aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.dir-locals.el6
-rw-r--r--.gitignore10
-rw-r--r--CREDITS83
-rw-r--r--HACKING18
-rw-r--r--LICENSE100
-rw-r--r--Makefile325
-rw-r--r--README132
-rw-r--r--build-targets.mk42
-rw-r--r--contrib/astylerc22
-rw-r--r--contrib/automake/Makefile.am138
-rw-r--r--contrib/automake/configure.ac8
-rw-r--r--contrib/openocd/debug_0.3.cfg75
-rw-r--r--contrib/openocd/debug_0.4.cfg75
-rw-r--r--contrib/openocd/flash_0.3.cfg89
-rw-r--r--contrib/openocd/flash_0.4.cfg95
-rwxr-xr-xcontrib/openocd/openocd-wrapper.sh16
-rw-r--r--docs/.gitignore2
-rw-r--r--docs/Makefile134
-rw-r--r--docs/README24
-rw-r--r--docs/README-building.txt (renamed from README-building.txt)0
-rw-r--r--docs/README-maintainers.txt (renamed from README-maintainers.txt)0
-rwxr-xr-xdocs/copy-to-ide (renamed from copy-to-ide)0
-rw-r--r--docs/make.bat (renamed from make.bat)0
-rw-r--r--docs/source/_static/.gitignore (renamed from source/_static/.gitignore)0
-rw-r--r--docs/source/_static/breathe.css (renamed from source/_static/breathe.css)0
-rw-r--r--docs/source/_static/img/blinky-to-flash.png (renamed from source/_static/img/blinky-to-flash.png)bin22657 -> 22657 bytes
-rw-r--r--docs/source/_static/img/blinky.png (renamed from source/_static/img/blinky.png)bin21042 -> 21042 bytes
-rw-r--r--docs/source/_static/img/button-new.png (renamed from source/_static/img/button-new.png)bin234 -> 234 bytes
-rw-r--r--docs/source/_static/img/button-open.png (renamed from source/_static/img/button-open.png)bin259 -> 259 bytes
-rw-r--r--docs/source/_static/img/button-save.png (renamed from source/_static/img/button-save.png)bin253 -> 253 bytes
-rw-r--r--docs/source/_static/img/button-serial-monitor.png (renamed from source/_static/img/button-serial-monitor.png)bin249 -> 249 bytes
-rw-r--r--docs/source/_static/img/button-stop.png (renamed from source/_static/img/button-stop.png)bin294 -> 294 bytes
-rw-r--r--docs/source/_static/img/button-upload.png (renamed from source/_static/img/button-upload.png)bin291 -> 291 bytes
-rw-r--r--docs/source/_static/img/button-verify.png (renamed from source/_static/img/button-verify.png)bin326 -> 326 bytes
-rw-r--r--docs/source/_static/img/codeblocks_build.png (renamed from source/_static/img/codeblocks_build.png)bin112088 -> 112088 bytes
-rw-r--r--docs/source/_static/img/codeblocks_makefile.png (renamed from source/_static/img/codeblocks_makefile.png)bin75653 -> 75653 bytes
-rw-r--r--docs/source/_static/img/codeblocks_maketargets.png (renamed from source/_static/img/codeblocks_maketargets.png)bin56250 -> 56250 bytes
-rw-r--r--docs/source/_static/img/codeblocks_newproject.png (renamed from source/_static/img/codeblocks_newproject.png)bin45930 -> 45930 bytes
-rw-r--r--docs/source/_static/img/github-clone-in-windows.png (renamed from source/_static/img/github-clone-in-windows.png)bin3899 -> 3899 bytes
-rw-r--r--docs/source/_static/img/ide-blinky.png (renamed from source/_static/img/ide-blinky.png)bin29213 -> 29213 bytes
-rw-r--r--docs/source/_static/img/jtag-wiring.png (renamed from source/_static/img/jtag-wiring.png)bin33637 -> 33637 bytes
-rw-r--r--docs/source/_static/img/osx-network-prefs-unconfigured.png (renamed from source/_static/img/osx-network-prefs-unconfigured.png)bin81770 -> 81770 bytes
-rw-r--r--docs/source/_static/img/osx-unconfigured-popup.png (renamed from source/_static/img/osx-unconfigured-popup.png)bin28359 -> 28359 bytes
-rw-r--r--docs/source/_static/img/round_logo_32x32.ico (renamed from source/_static/img/round_logo_32x32.ico)bin4286 -> 4286 bytes
-rw-r--r--docs/source/_static/img/round_logo_60x60.png (renamed from source/_static/img/round_logo_60x60.png)bin5552 -> 5552 bytes
-rw-r--r--docs/source/_static/img/serial-monitor.png (renamed from source/_static/img/serial-monitor.png)bin55975 -> 55975 bytes
-rw-r--r--docs/source/_static/img/serial-port-mac.png (renamed from source/_static/img/serial-port-mac.png)bin64284 -> 64284 bytes
-rw-r--r--docs/source/_static/img/serial-port-ubuntu.png (renamed from source/_static/img/serial-port-ubuntu.png)bin46629 -> 46629 bytes
-rw-r--r--docs/source/_static/img/serial-port-win.png (renamed from source/_static/img/serial-port-win.png)bin15183 -> 15183 bytes
-rw-r--r--docs/source/_static/img/upload-button.png (renamed from source/_static/img/upload-button.png)bin9993 -> 9993 bytes
-rw-r--r--docs/source/_static/img/verify-success.png (renamed from source/_static/img/verify-success.png)bin26460 -> 26460 bytes
-rw-r--r--docs/source/_static/img/verify_button.png (renamed from source/_static/img/verify_button.png)bin1800 -> 1800 bytes
-rw-r--r--docs/source/_static/img/win7-copy-arm-bin-address.png (renamed from source/_static/img/win7-copy-arm-bin-address.png)bin31648 -> 31648 bytes
-rw-r--r--docs/source/_static/img/win7-copy-python-address.png (renamed from source/_static/img/win7-copy-python-address.png)bin20500 -> 20500 bytes
-rw-r--r--docs/source/_static/img/win7-github-open-in-explorer.png (renamed from source/_static/img/win7-github-open-in-explorer.png)bin29280 -> 29280 bytes
-rw-r--r--docs/source/_static/img/win7-python-arm-bin-path.png (renamed from source/_static/img/win7-python-arm-bin-path.png)bin8196 -> 8196 bytes
-rw-r--r--docs/source/_static/img/win7-python-path.png (renamed from source/_static/img/win7-python-path.png)bin6912 -> 6912 bytes
-rw-r--r--docs/source/_static/img/win7-python-prompt.png (renamed from source/_static/img/win7-python-prompt.png)bin9796 -> 9796 bytes
-rw-r--r--docs/source/_static/index-style.css (renamed from source/_static/index-style.css)0
-rw-r--r--docs/source/_static/leaflabs-docs.css (renamed from source/_static/leaflabs-docs.css)0
-rw-r--r--docs/source/_templates/.gitignore (renamed from source/_templates/.gitignore)0
-rw-r--r--docs/source/_templates/indexcontent.html (renamed from source/_templates/indexcontent.html)0
-rw-r--r--docs/source/_templates/layout.html (renamed from source/_templates/layout.html)0
-rw-r--r--docs/source/adc.rst (renamed from source/adc.rst)0
-rw-r--r--docs/source/arduino-cc-attribution.txt (renamed from source/arduino-cc-attribution.txt)0
-rw-r--r--docs/source/arduino-compatibility.rst (renamed from source/arduino-compatibility.rst)0
-rw-r--r--docs/source/arm-gcc.rst (renamed from source/arm-gcc.rst)0
-rw-r--r--docs/source/bootloader.rst (renamed from source/bootloader.rst)0
-rw-r--r--docs/source/conf.py (renamed from source/conf.py)0
-rw-r--r--docs/source/contents.rst (renamed from source/contents.rst)0
-rw-r--r--docs/source/epilog.rst (renamed from source/epilog.rst)0
-rw-r--r--docs/source/external-interrupts.rst (renamed from source/external-interrupts.rst)0
-rw-r--r--docs/source/faq.rst (renamed from source/faq.rst)0
-rw-r--r--docs/source/fsmc.rst (renamed from source/fsmc.rst)0
-rw-r--r--docs/source/gpio.rst (renamed from source/gpio.rst)0
-rw-r--r--docs/source/hardware/maple-mini.rst (renamed from source/hardware/maple-mini.rst)0
-rw-r--r--docs/source/hardware/maple-native-beta.rst (renamed from source/hardware/maple-native-beta.rst)0
-rw-r--r--docs/source/hardware/maple-native.rst (renamed from source/hardware/maple-native.rst)0
-rw-r--r--docs/source/hardware/maple-ret6.rst (renamed from source/hardware/maple-ret6.rst)0
-rw-r--r--docs/source/hardware/maple.rst (renamed from source/hardware/maple.rst)0
-rw-r--r--docs/source/i2c.rst (renamed from source/i2c.rst)0
-rw-r--r--docs/source/ide.rst (renamed from source/ide.rst)0
-rw-r--r--docs/source/jtag.rst (renamed from source/jtag.rst)0
-rw-r--r--docs/source/lang/api/abs.rst (renamed from source/lang/api/abs.rst)0
-rw-r--r--docs/source/lang/api/analogread.rst (renamed from source/lang/api/analogread.rst)0
-rw-r--r--docs/source/lang/api/analogwrite.rst (renamed from source/lang/api/analogwrite.rst)0
-rw-r--r--docs/source/lang/api/assert.rst (renamed from source/lang/api/assert.rst)0
-rw-r--r--docs/source/lang/api/attachinterrupt.rst (renamed from source/lang/api/attachinterrupt.rst)0
-rw-r--r--docs/source/lang/api/bit.rst (renamed from source/lang/api/bit.rst)0
-rw-r--r--docs/source/lang/api/bitclear.rst (renamed from source/lang/api/bitclear.rst)0
-rw-r--r--docs/source/lang/api/bitread.rst (renamed from source/lang/api/bitread.rst)0
-rw-r--r--docs/source/lang/api/bitset.rst (renamed from source/lang/api/bitset.rst)0
-rw-r--r--docs/source/lang/api/bitwrite.rst (renamed from source/lang/api/bitwrite.rst)0
-rw-r--r--docs/source/lang/api/board-values.rst (renamed from source/lang/api/board-values.rst)0
-rw-r--r--docs/source/lang/api/boardusespin.rst (renamed from source/lang/api/boardusespin.rst)0
-rw-r--r--docs/source/lang/api/constants.rst (renamed from source/lang/api/constants.rst)0
-rw-r--r--docs/source/lang/api/constrain.rst (renamed from source/lang/api/constrain.rst)0
-rw-r--r--docs/source/lang/api/cos.rst (renamed from source/lang/api/cos.rst)0
-rw-r--r--docs/source/lang/api/delay.rst (renamed from source/lang/api/delay.rst)0
-rw-r--r--docs/source/lang/api/delaymicroseconds.rst (renamed from source/lang/api/delaymicroseconds.rst)0
-rw-r--r--docs/source/lang/api/detachinterrupt.rst (renamed from source/lang/api/detachinterrupt.rst)0
-rw-r--r--docs/source/lang/api/digitalread.rst (renamed from source/lang/api/digitalread.rst)0
-rw-r--r--docs/source/lang/api/digitalwrite.rst (renamed from source/lang/api/digitalwrite.rst)0
-rw-r--r--docs/source/lang/api/disabledebugports.rst (renamed from source/lang/api/disabledebugports.rst)0
-rw-r--r--docs/source/lang/api/enabledebugports.rst (renamed from source/lang/api/enabledebugports.rst)0
-rw-r--r--docs/source/lang/api/hardwarespi.rst (renamed from source/lang/api/hardwarespi.rst)0
-rw-r--r--docs/source/lang/api/hardwaretimer.rst (renamed from source/lang/api/hardwaretimer.rst)0
-rw-r--r--docs/source/lang/api/highbyte.rst (renamed from source/lang/api/highbyte.rst)0
-rw-r--r--docs/source/lang/api/interrupts.rst (renamed from source/lang/api/interrupts.rst)0
-rw-r--r--docs/source/lang/api/isbuttonpressed.rst (renamed from source/lang/api/isbuttonpressed.rst)0
-rw-r--r--docs/source/lang/api/loop.rst (renamed from source/lang/api/loop.rst)0
-rw-r--r--docs/source/lang/api/lowbyte.rst (renamed from source/lang/api/lowbyte.rst)0
-rw-r--r--docs/source/lang/api/map.rst (renamed from source/lang/api/map.rst)0
-rw-r--r--docs/source/lang/api/max.rst (renamed from source/lang/api/max.rst)0
-rw-r--r--docs/source/lang/api/micros.rst (renamed from source/lang/api/micros.rst)0
-rw-r--r--docs/source/lang/api/millis.rst (renamed from source/lang/api/millis.rst)0
-rw-r--r--docs/source/lang/api/min.rst (renamed from source/lang/api/min.rst)0
-rw-r--r--docs/source/lang/api/nointerrupts.rst (renamed from source/lang/api/nointerrupts.rst)0
-rw-r--r--docs/source/lang/api/pinmode.rst (renamed from source/lang/api/pinmode.rst)0
-rw-r--r--docs/source/lang/api/pow.rst (renamed from source/lang/api/pow.rst)0
-rw-r--r--docs/source/lang/api/pwmwrite.rst (renamed from source/lang/api/pwmwrite.rst)0
-rw-r--r--docs/source/lang/api/random.rst (renamed from source/lang/api/random.rst)0
-rw-r--r--docs/source/lang/api/randomseed.rst (renamed from source/lang/api/randomseed.rst)0
-rw-r--r--docs/source/lang/api/serial.rst (renamed from source/lang/api/serial.rst)0
-rw-r--r--docs/source/lang/api/serialusb.rst (renamed from source/lang/api/serialusb.rst)0
-rw-r--r--docs/source/lang/api/setup.rst (renamed from source/lang/api/setup.rst)0
-rw-r--r--docs/source/lang/api/shiftout.rst (renamed from source/lang/api/shiftout.rst)0
-rw-r--r--docs/source/lang/api/sin.rst (renamed from source/lang/api/sin.rst)0
-rw-r--r--docs/source/lang/api/sq.rst (renamed from source/lang/api/sq.rst)0
-rw-r--r--docs/source/lang/api/tan.rst (renamed from source/lang/api/tan.rst)0
-rw-r--r--docs/source/lang/api/toggleled.rst (renamed from source/lang/api/toggleled.rst)0
-rw-r--r--docs/source/lang/api/togglepin.rst (renamed from source/lang/api/togglepin.rst)0
-rw-r--r--docs/source/lang/api/volatile.rst (renamed from source/lang/api/volatile.rst)0
-rw-r--r--docs/source/lang/api/waitforbuttonpress.rst (renamed from source/lang/api/waitforbuttonpress.rst)0
-rw-r--r--docs/source/lang/cc-attribution.txt (renamed from source/lang/cc-attribution.txt)0
-rw-r--r--docs/source/lang/cpp/arithmetic.rst (renamed from source/lang/cpp/arithmetic.rst)0
-rw-r--r--docs/source/lang/cpp/array.rst (renamed from source/lang/cpp/array.rst)0
-rw-r--r--docs/source/lang/cpp/assignment.rst (renamed from source/lang/cpp/assignment.rst)0
-rw-r--r--docs/source/lang/cpp/bitshift.rst (renamed from source/lang/cpp/bitshift.rst)0
-rw-r--r--docs/source/lang/cpp/bitwisemath.rst (renamed from source/lang/cpp/bitwisemath.rst)0
-rw-r--r--docs/source/lang/cpp/boolean.rst (renamed from source/lang/cpp/boolean.rst)0
-rw-r--r--docs/source/lang/cpp/booleanvariables.rst (renamed from source/lang/cpp/booleanvariables.rst)0
-rw-r--r--docs/source/lang/cpp/break.rst (renamed from source/lang/cpp/break.rst)0
-rw-r--r--docs/source/lang/cpp/built-in-types.rst (renamed from source/lang/cpp/built-in-types.rst)0
-rw-r--r--docs/source/lang/cpp/byte.rst (renamed from source/lang/cpp/byte.rst)0
-rw-r--r--docs/source/lang/cpp/bytecast.rst (renamed from source/lang/cpp/bytecast.rst)0
-rw-r--r--docs/source/lang/cpp/cc-attribution.txt (renamed from source/lang/cpp/cc-attribution.txt)0
-rw-r--r--docs/source/lang/cpp/char.rst (renamed from source/lang/cpp/char.rst)0
-rw-r--r--docs/source/lang/cpp/charcast.rst (renamed from source/lang/cpp/charcast.rst)0
-rw-r--r--docs/source/lang/cpp/comments.rst (renamed from source/lang/cpp/comments.rst)0
-rw-r--r--docs/source/lang/cpp/comparison.rst (renamed from source/lang/cpp/comparison.rst)0
-rw-r--r--docs/source/lang/cpp/compoundarithmetic.rst (renamed from source/lang/cpp/compoundarithmetic.rst)0
-rw-r--r--docs/source/lang/cpp/compoundbitwise.rst (renamed from source/lang/cpp/compoundbitwise.rst)0
-rw-r--r--docs/source/lang/cpp/const.rst (renamed from source/lang/cpp/const.rst)0
-rw-r--r--docs/source/lang/cpp/continue.rst (renamed from source/lang/cpp/continue.rst)0
-rw-r--r--docs/source/lang/cpp/curly-braces.rst (renamed from source/lang/cpp/curly-braces.rst)0
-rw-r--r--docs/source/lang/cpp/define.rst (renamed from source/lang/cpp/define.rst)0
-rw-r--r--docs/source/lang/cpp/double.rst (renamed from source/lang/cpp/double.rst)0
-rw-r--r--docs/source/lang/cpp/doublecast.rst (renamed from source/lang/cpp/doublecast.rst)0
-rw-r--r--docs/source/lang/cpp/dowhile.rst (renamed from source/lang/cpp/dowhile.rst)0
-rw-r--r--docs/source/lang/cpp/enum.rst (renamed from source/lang/cpp/enum.rst)0
-rw-r--r--docs/source/lang/cpp/float.rst (renamed from source/lang/cpp/float.rst)0
-rw-r--r--docs/source/lang/cpp/floatcast.rst (renamed from source/lang/cpp/floatcast.rst)0
-rw-r--r--docs/source/lang/cpp/for.rst (renamed from source/lang/cpp/for.rst)0
-rw-r--r--docs/source/lang/cpp/goto.rst (renamed from source/lang/cpp/goto.rst)0
-rw-r--r--docs/source/lang/cpp/if.rst (renamed from source/lang/cpp/if.rst)0
-rw-r--r--docs/source/lang/cpp/include.rst (renamed from source/lang/cpp/include.rst)0
-rw-r--r--docs/source/lang/cpp/increment.rst (renamed from source/lang/cpp/increment.rst)0
-rw-r--r--docs/source/lang/cpp/int.rst (renamed from source/lang/cpp/int.rst)0
-rw-r--r--docs/source/lang/cpp/intcast.rst (renamed from source/lang/cpp/intcast.rst)0
-rw-r--r--docs/source/lang/cpp/keywords.rst (renamed from source/lang/cpp/keywords.rst)0
-rw-r--r--docs/source/lang/cpp/longcast.rst (renamed from source/lang/cpp/longcast.rst)0
-rw-r--r--docs/source/lang/cpp/longlong.rst (renamed from source/lang/cpp/longlong.rst)0
-rw-r--r--docs/source/lang/cpp/modulo.rst (renamed from source/lang/cpp/modulo.rst)0
-rw-r--r--docs/source/lang/cpp/pointer.rst (renamed from source/lang/cpp/pointer.rst)0
-rw-r--r--docs/source/lang/cpp/return.rst (renamed from source/lang/cpp/return.rst)0
-rw-r--r--docs/source/lang/cpp/scope.rst (renamed from source/lang/cpp/scope.rst)0
-rw-r--r--docs/source/lang/cpp/semicolon.rst (renamed from source/lang/cpp/semicolon.rst)0
-rw-r--r--docs/source/lang/cpp/sizeof.rst (renamed from source/lang/cpp/sizeof.rst)0
-rw-r--r--docs/source/lang/cpp/sqrt.rst (renamed from source/lang/cpp/sqrt.rst)0
-rw-r--r--docs/source/lang/cpp/static.rst (renamed from source/lang/cpp/static.rst)0
-rw-r--r--docs/source/lang/cpp/string.rst (renamed from source/lang/cpp/string.rst)0
-rw-r--r--docs/source/lang/cpp/switchcase.rst (renamed from source/lang/cpp/switchcase.rst)0
-rw-r--r--docs/source/lang/cpp/unsignedchar.rst (renamed from source/lang/cpp/unsignedchar.rst)0
-rw-r--r--docs/source/lang/cpp/unsignedint.rst (renamed from source/lang/cpp/unsignedint.rst)0
-rw-r--r--docs/source/lang/cpp/unsignedlonglong.rst (renamed from source/lang/cpp/unsignedlonglong.rst)0
-rw-r--r--docs/source/lang/cpp/variables.rst (renamed from source/lang/cpp/variables.rst)0
-rw-r--r--docs/source/lang/cpp/void.rst (renamed from source/lang/cpp/void.rst)0
-rw-r--r--docs/source/lang/cpp/while.rst (renamed from source/lang/cpp/while.rst)0
-rw-r--r--docs/source/lang/unimplemented/notone.rst (renamed from source/lang/unimplemented/notone.rst)0
-rw-r--r--docs/source/lang/unimplemented/pulsein.rst (renamed from source/lang/unimplemented/pulsein.rst)0
-rw-r--r--docs/source/lang/unimplemented/stringclass.rst (renamed from source/lang/unimplemented/stringclass.rst)0
-rw-r--r--docs/source/lang/unimplemented/stringobject.rst (renamed from source/lang/unimplemented/stringobject.rst)0
-rw-r--r--docs/source/lang/unimplemented/tone.rst (renamed from source/lang/unimplemented/tone.rst)0
-rw-r--r--docs/source/language-index.rst (renamed from source/language-index.rst)0
-rw-r--r--docs/source/language.rst (renamed from source/language.rst)0
-rw-r--r--docs/source/libmaple.rst (renamed from source/libmaple.rst)0
-rw-r--r--docs/source/libmaple/api/adc.rst (renamed from source/libmaple/api/adc.rst)0
-rw-r--r--docs/source/libmaple/api/bitband.rst (renamed from source/libmaple/api/bitband.rst)0
-rw-r--r--docs/source/libmaple/api/bkp.rst (renamed from source/libmaple/api/bkp.rst)0
-rw-r--r--docs/source/libmaple/api/dac.rst (renamed from source/libmaple/api/dac.rst)0
-rw-r--r--docs/source/libmaple/api/delay.rst (renamed from source/libmaple/api/delay.rst)0
-rw-r--r--docs/source/libmaple/api/dma.rst (renamed from source/libmaple/api/dma.rst)0
-rw-r--r--docs/source/libmaple/api/exti.rst (renamed from source/libmaple/api/exti.rst)0
-rw-r--r--docs/source/libmaple/api/flash.rst (renamed from source/libmaple/api/flash.rst)0
-rw-r--r--docs/source/libmaple/api/fsmc.rst (renamed from source/libmaple/api/fsmc.rst)0
-rw-r--r--docs/source/libmaple/api/gpio.rst (renamed from source/libmaple/api/gpio.rst)0
-rw-r--r--docs/source/libmaple/api/i2c.rst (renamed from source/libmaple/api/i2c.rst)0
-rw-r--r--docs/source/libmaple/api/iwdg.rst (renamed from source/libmaple/api/iwdg.rst)0
-rw-r--r--docs/source/libmaple/api/libmaple.rst (renamed from source/libmaple/api/libmaple.rst)0
-rw-r--r--docs/source/libmaple/api/libmaple_types.rst (renamed from source/libmaple/api/libmaple_types.rst)0
-rw-r--r--docs/source/libmaple/api/nvic.rst (renamed from source/libmaple/api/nvic.rst)0
-rw-r--r--docs/source/libmaple/api/pwr.rst (renamed from source/libmaple/api/pwr.rst)0
-rw-r--r--docs/source/libmaple/api/rcc-reg-bits.txt (renamed from source/libmaple/api/rcc-reg-bits.txt)0
-rw-r--r--docs/source/libmaple/api/rcc.rst (renamed from source/libmaple/api/rcc.rst)0
-rw-r--r--docs/source/libmaple/api/ring_buffer.rst (renamed from source/libmaple/api/ring_buffer.rst)0
-rw-r--r--docs/source/libmaple/api/scb.rst (renamed from source/libmaple/api/scb.rst)0
-rw-r--r--docs/source/libmaple/api/spi.rst (renamed from source/libmaple/api/spi.rst)0
-rw-r--r--docs/source/libmaple/api/stm32.rst (renamed from source/libmaple/api/stm32.rst)0
-rw-r--r--docs/source/libmaple/api/systick.rst (renamed from source/libmaple/api/systick.rst)0
-rw-r--r--docs/source/libmaple/api/timer.rst (renamed from source/libmaple/api/timer.rst)0
-rw-r--r--docs/source/libmaple/api/usart.rst (renamed from source/libmaple/api/usart.rst)0
-rw-r--r--docs/source/libmaple/api/util.rst (renamed from source/libmaple/api/util.rst)0
-rw-r--r--docs/source/libmaple/apis.rst (renamed from source/libmaple/apis.rst)0
-rw-r--r--docs/source/libmaple/coding-standard.rst (renamed from source/libmaple/coding-standard.rst)0
-rw-r--r--docs/source/libmaple/contributing.rst (renamed from source/libmaple/contributing.rst)0
-rw-r--r--docs/source/libmaple/overview.rst (renamed from source/libmaple/overview.rst)0
-rw-r--r--docs/source/libraries.rst (renamed from source/libraries.rst)0
-rw-r--r--docs/source/libs/servo.rst (renamed from source/libs/servo.rst)0
-rw-r--r--docs/source/libs/wire.rst (renamed from source/libs/wire.rst)0
-rw-r--r--docs/source/maple-ide-install.rst (renamed from source/maple-ide-install.rst)0
-rw-r--r--docs/source/maple-quickstart.rst (renamed from source/maple-quickstart.rst)0
-rw-r--r--docs/source/prolog.rst (renamed from source/prolog.rst)0
-rw-r--r--docs/source/pwm.rst (renamed from source/pwm.rst)0
-rw-r--r--docs/source/spi.rst (renamed from source/spi.rst)0
-rw-r--r--docs/source/stm32.rst (renamed from source/stm32.rst)0
-rw-r--r--docs/source/systick.rst (renamed from source/systick.rst)0
-rw-r--r--docs/source/timers.rst (renamed from source/timers.rst)0
-rw-r--r--docs/source/troubleshooting.rst (renamed from source/troubleshooting.rst)0
-rw-r--r--docs/source/unix-toolchain-linux-setup.rst (renamed from source/unix-toolchain-linux-setup.rst)0
-rw-r--r--docs/source/unix-toolchain-osx-setup.rst (renamed from source/unix-toolchain-osx-setup.rst)0
-rw-r--r--docs/source/unix-toolchain-win-setup.rst (renamed from source/unix-toolchain-win-setup.rst)0
-rw-r--r--docs/source/unix-toolchain.rst (renamed from source/unix-toolchain.rst)0
-rw-r--r--docs/source/usart.rst (renamed from source/usart.rst)0
-rw-r--r--docs/source/usb.rst (renamed from source/usb.rst)0
-rw-r--r--docs/source/whats-new.rst (renamed from source/whats-new.rst)0
-rw-r--r--docs/tmpl/libmaple-proper-page.rst.tmpl (renamed from tmpl/libmaple-proper-page.rst.tmpl)0
-rw-r--r--examples/blinky.cpp25
-rw-r--r--examples/debug-dtrrts.cpp38
-rw-r--r--examples/exti-interrupt-callback.cpp87
-rw-r--r--examples/exti-interrupt.cpp50
-rw-r--r--examples/freertos-blinky.cpp43
-rw-r--r--examples/fsmc-stress-test.cpp229
-rw-r--r--examples/i2c-mcp4725-dac.cpp145
-rw-r--r--examples/mini-exti-test.cpp251
-rw-r--r--examples/qa-slave-shield.cpp66
-rw-r--r--examples/serial-echo.cpp30
-rw-r--r--examples/spi_master.cpp77
-rw-r--r--examples/test-bkp.cpp80
-rw-r--r--examples/test-dac.cpp51
-rw-r--r--examples/test-fsmc.cpp122
-rw-r--r--examples/test-print.cpp184
-rw-r--r--examples/test-ring-buffer-insertion.cpp114
-rw-r--r--examples/test-serial-flush.cpp38
-rw-r--r--examples/test-serialusb.cpp126
-rw-r--r--examples/test-servo.cpp152
-rw-r--r--examples/test-session.cpp938
-rw-r--r--examples/test-spi-roundtrip.cpp192
-rw-r--r--examples/test-systick.cpp49
-rw-r--r--examples/test-timers.cpp537
-rw-r--r--examples/test-usart-dma.cpp211
-rw-r--r--examples/vga-leaf.cpp244
-rw-r--r--examples/vga-scope.cpp205
-rw-r--r--libmaple/adc.c109
-rw-r--r--libmaple/dac.c120
-rw-r--r--libmaple/dma.c82
-rw-r--r--libmaple/dma_private.h61
-rw-r--r--libmaple/exc.S101
-rw-r--r--libmaple/exti.c292
-rw-r--r--libmaple/exti_private.h34
-rw-r--r--libmaple/flash.c55
-rw-r--r--libmaple/gpio.c50
-rw-r--r--libmaple/i2c.c509
-rw-r--r--libmaple/i2c_private.h79
-rw-r--r--libmaple/include/libmaple/adc.h329
-rw-r--r--libmaple/include/libmaple/bitband.h128
-rw-r--r--libmaple/include/libmaple/bkp.h166
-rw-r--r--libmaple/include/libmaple/dac.h158
-rw-r--r--libmaple/include/libmaple/delay.h65
-rw-r--r--libmaple/include/libmaple/dma.h444
-rw-r--r--libmaple/include/libmaple/dma_common.h112
-rw-r--r--libmaple/include/libmaple/exti.h143
-rw-r--r--libmaple/include/libmaple/flash.h106
-rw-r--r--libmaple/include/libmaple/fsmc.h340
-rw-r--r--libmaple/include/libmaple/gpio.h121
-rw-r--r--libmaple/include/libmaple/i2c.h413
-rw-r--r--libmaple/include/libmaple/i2c_common.h93
-rw-r--r--libmaple/include/libmaple/iwdg.h115
-rw-r--r--libmaple/include/libmaple/libmaple.h48
-rw-r--r--libmaple/include/libmaple/libmaple_types.h73
-rw-r--r--libmaple/include/libmaple/nvic.h155
-rw-r--r--libmaple/include/libmaple/pwr.h115
-rw-r--r--libmaple/include/libmaple/rcc.h175
-rw-r--r--libmaple/include/libmaple/ring_buffer.h188
-rw-r--r--libmaple/include/libmaple/scb.h214
-rw-r--r--libmaple/include/libmaple/spi.h470
-rw-r--r--libmaple/include/libmaple/stm32.h237
-rw-r--r--libmaple/include/libmaple/syscfg.h151
-rw-r--r--libmaple/include/libmaple/systick.h115
-rw-r--r--libmaple/include/libmaple/timer.h1110
-rw-r--r--libmaple/include/libmaple/usart.h495
-rw-r--r--libmaple/include/libmaple/usb.h176
-rw-r--r--libmaple/include/libmaple/usb_cdcacm.h179
-rw-r--r--libmaple/include/libmaple/util.h111
-rw-r--r--libmaple/iwdg.c62
-rw-r--r--libmaple/nvic.c103
-rw-r--r--libmaple/pwr.c41
-rw-r--r--libmaple/rcc.c169
-rw-r--r--libmaple/rcc_private.h67
-rw-r--r--libmaple/rules.mk50
-rw-r--r--libmaple/spi.c164
-rw-r--r--libmaple/spi_private.h37
-rw-r--r--libmaple/stm32_private.h45
-rw-r--r--libmaple/stm32f1/adc.c115
-rw-r--r--libmaple/stm32f1/bkp.c129
-rw-r--r--libmaple/stm32f1/dma.c413
-rw-r--r--libmaple/stm32f1/exti.c32
-rw-r--r--libmaple/stm32f1/fsmc.c95
-rw-r--r--libmaple/stm32f1/gpio.c166
-rw-r--r--libmaple/stm32f1/i2c.c129
-rw-r--r--libmaple/stm32f1/include/series/adc.h253
-rw-r--r--libmaple/stm32f1/include/series/dac.h71
-rw-r--r--libmaple/stm32f1/include/series/dma.h575
-rw-r--r--libmaple/stm32f1/include/series/exti.h46
-rw-r--r--libmaple/stm32f1/include/series/flash.h149
-rw-r--r--libmaple/stm32f1/include/series/gpio.h493
-rw-r--r--libmaple/stm32f1/include/series/i2c.h85
-rw-r--r--libmaple/stm32f1/include/series/nvic.h173
-rw-r--r--libmaple/stm32f1/include/series/pwr.h52
-rw-r--r--libmaple/stm32f1/include/series/rcc.h599
-rw-r--r--libmaple/stm32f1/include/series/spi.h99
-rw-r--r--libmaple/stm32f1/include/series/stm32.h219
-rw-r--r--libmaple/stm32f1/include/series/timer.h128
-rw-r--r--libmaple/stm32f1/include/series/usart.h76
-rw-r--r--libmaple/stm32f1/performance/isrs.S263
-rw-r--r--libmaple/stm32f1/performance/vector_table.S118
-rw-r--r--libmaple/stm32f1/rcc.c164
-rw-r--r--libmaple/stm32f1/rules.mk45
-rw-r--r--libmaple/stm32f1/spi.c84
-rw-r--r--libmaple/stm32f1/timer.c124
-rw-r--r--libmaple/stm32f1/usart.c170
-rw-r--r--libmaple/stm32f1/value/isrs.S270
-rw-r--r--libmaple/stm32f1/value/vector_table.S116
-rw-r--r--libmaple/stm32f2/adc.c84
-rw-r--r--libmaple/stm32f2/dma.c504
-rw-r--r--libmaple/stm32f2/exti.c33
-rw-r--r--libmaple/stm32f2/fsmc.c90
-rw-r--r--libmaple/stm32f2/gpio.c194
-rw-r--r--libmaple/stm32f2/include/series/adc.h335
-rw-r--r--libmaple/stm32f2/include/series/dac.h94
-rw-r--r--libmaple/stm32f2/include/series/dma.h810
-rw-r--r--libmaple/stm32f2/include/series/exti.h46
-rw-r--r--libmaple/stm32f2/include/series/flash.h202
-rw-r--r--libmaple/stm32f2/include/series/gpio.h264
-rw-r--r--libmaple/stm32f2/include/series/nvic.h160
-rw-r--r--libmaple/stm32f2/include/series/pwr.h73
-rw-r--r--libmaple/stm32f2/include/series/rcc.h951
-rw-r--r--libmaple/stm32f2/include/series/spi.h88
-rw-r--r--libmaple/stm32f2/include/series/stm32.h77
-rw-r--r--libmaple/stm32f2/include/series/timer.h176
-rw-r--r--libmaple/stm32f2/include/series/usart.h111
-rw-r--r--libmaple/stm32f2/isrs.S322
-rw-r--r--libmaple/stm32f2/rcc.c175
-rw-r--r--libmaple/stm32f2/rules.mk40
-rw-r--r--libmaple/stm32f2/spi.c88
-rw-r--r--libmaple/stm32f2/syscfg.c78
-rw-r--r--libmaple/stm32f2/timer.c148
-rw-r--r--libmaple/stm32f2/usart.c204
-rw-r--r--libmaple/stm32f2/vector_table.S135
-rw-r--r--libmaple/systick.c88
-rw-r--r--libmaple/timer.c412
-rw-r--r--libmaple/timer_private.h235
-rw-r--r--libmaple/usart.c138
-rw-r--r--libmaple/usart_private.c41
-rw-r--r--libmaple/usart_private.h53
-rw-r--r--libmaple/usb/README63
-rw-r--r--libmaple/usb/rules.mk45
-rw-r--r--libmaple/usb/stm32f1/usb.c387
-rw-r--r--libmaple/usb/stm32f1/usb_cdcacm.c709
-rw-r--r--libmaple/usb/stm32f1/usb_lib_globals.h55
-rw-r--r--libmaple/usb/stm32f1/usb_reg_map.c88
-rw-r--r--libmaple/usb/stm32f1/usb_reg_map.h617
-rw-r--r--libmaple/usb/usb_lib/usb_core.c1013
-rw-r--r--libmaple/usb/usb_lib/usb_core.h251
-rw-r--r--libmaple/usb/usb_lib/usb_def.h88
-rw-r--r--libmaple/usb/usb_lib/usb_init.c64
-rw-r--r--libmaple/usb/usb_lib/usb_init.h57
-rw-r--r--libmaple/usb/usb_lib/usb_lib.h36
-rw-r--r--libmaple/usb/usb_lib/usb_mem.c73
-rw-r--r--libmaple/usb/usb_lib/usb_mem.h40
-rw-r--r--libmaple/usb/usb_lib/usb_regs.c748
-rw-r--r--libmaple/usb/usb_lib/usb_regs.h627
-rw-r--r--libmaple/usb/usb_lib/usb_type.h77
-rw-r--r--libmaple/util.c150
-rw-r--r--libraries/FreeRTOS/MapleFreeRTOS.cpp44
-rw-r--r--libraries/FreeRTOS/MapleFreeRTOS.h40
-rw-r--r--libraries/FreeRTOS/keywords.txt27
-rw-r--r--libraries/FreeRTOS/rules.mk38
-rwxr-xr-xlibraries/FreeRTOS/utility/FreeRTOS.h468
-rwxr-xr-xlibraries/FreeRTOS/utility/FreeRTOSConfig.h126
-rwxr-xr-xlibraries/FreeRTOS/utility/StackMacros.h174
-rwxr-xr-xlibraries/FreeRTOS/utility/croutine.c380
-rwxr-xr-xlibraries/FreeRTOS/utility/croutine.h752
-rwxr-xr-xlibraries/FreeRTOS/utility/heap_2.c278
-rwxr-xr-xlibraries/FreeRTOS/utility/list.c197
-rwxr-xr-xlibraries/FreeRTOS/utility/list.h314
-rwxr-xr-xlibraries/FreeRTOS/utility/mpu_wrappers.h141
-rwxr-xr-xlibraries/FreeRTOS/utility/port.c292
-rwxr-xr-xlibraries/FreeRTOS/utility/portable.h396
-rwxr-xr-xlibraries/FreeRTOS/utility/portmacro.h156
-rwxr-xr-xlibraries/FreeRTOS/utility/projdefs.h83
-rwxr-xr-xlibraries/FreeRTOS/utility/queue.c1539
-rwxr-xr-xlibraries/FreeRTOS/utility/queue.h1270
-rwxr-xr-xlibraries/FreeRTOS/utility/semphr.h717
-rwxr-xr-xlibraries/FreeRTOS/utility/task.h1307
-rwxr-xr-xlibraries/FreeRTOS/utility/tasks.c2522
-rwxr-xr-xlibraries/FreeRTOS/utility/timers.c649
-rwxr-xr-xlibraries/FreeRTOS/utility/timers.h936
-rw-r--r--libraries/LiquidCrystal/LiquidCrystal.cpp333
-rw-r--r--libraries/LiquidCrystal/LiquidCrystal.h105
-rw-r--r--libraries/LiquidCrystal/rules.mk29
-rw-r--r--libraries/Servo/Servo.cpp150
-rw-r--r--libraries/Servo/Servo.h196
-rw-r--r--libraries/Servo/rules.mk29
-rw-r--r--libraries/Wire/HardWire.cpp66
-rw-r--r--libraries/Wire/HardWire.h69
-rw-r--r--libraries/Wire/Wire.cpp182
-rw-r--r--libraries/Wire/Wire.h136
-rw-r--r--libraries/Wire/WireBase.cpp140
-rw-r--r--libraries/Wire/WireBase.h143
-rw-r--r--libraries/Wire/rules.mk29
-rw-r--r--main.cpp.example43
-rw-r--r--notes/dac.txt67
-rw-r--r--notes/dma-stm32f1.txt99
-rw-r--r--notes/exti.txt41
-rw-r--r--notes/fsmc.txt64
-rw-r--r--notes/interrupts.txt346
-rw-r--r--notes/pin-definitions.txt226
-rw-r--r--notes/portable.txt33
-rw-r--r--notes/stm32.txt63
-rw-r--r--notes/timers.txt96
-rw-r--r--notes/usb.txt72
-rw-r--r--notes/vga.txt35
-rw-r--r--support/doxygen/Doxyfile1648
-rwxr-xr-xsupport/doxygen/evil_mangler.awk38
-rw-r--r--support/gdb/gpio/gpio.gdb12
-rw-r--r--support/gdb/i2c/test.gdb112
-rw-r--r--support/ld/common.inc219
-rw-r--r--support/ld/flash.ld26
-rw-r--r--support/ld/jtag.ld31
-rw-r--r--support/ld/ram.ld25
-rw-r--r--support/ld/stm32/mem/maple_native/maple_native_heap.inc3
-rw-r--r--support/ld/stm32/mem/maple_native/mem-flash.inc7
-rw-r--r--support/ld/stm32/mem/maple_native/mem-jtag.inc7
-rw-r--r--support/ld/stm32/mem/maple_native/mem-ram.inc7
-rw-r--r--support/ld/stm32/mem/sram_112k_flash_1024k/mem-jtag.inc5
-rw-r--r--support/ld/stm32/mem/sram_112k_flash_1024k/mem-ram.inc5
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k/mem-flash.inc5
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k/mem-jtag.inc5
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k/mem-ram.inc5
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc5
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc5
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc5
-rw-r--r--support/ld/stm32/mem/sram_64k_flash_512k/mem-flash.inc5
-rw-r--r--support/ld/stm32/mem/sram_64k_flash_512k/mem-jtag.inc5
-rw-r--r--support/ld/stm32/mem/sram_64k_flash_512k/mem-ram.inc5
-rw-r--r--support/ld/stm32/mem/sram_8k_flash_128k/mem-flash.inc5
-rw-r--r--support/ld/stm32/mem/sram_8k_flash_128k/mem-jtag.inc5
-rw-r--r--support/ld/stm32/mem/sram_8k_flash_128k/mem-ram.inc5
-rw-r--r--support/ld/stm32/series/stm32f1/performance/vector_symbols.inc78
-rw-r--r--support/ld/stm32/series/stm32f1/value/vector_symbols.inc78
-rw-r--r--support/ld/stm32/series/stm32f2/vector_symbols.inc98
-rw-r--r--support/ld/toolchains/gcc-arm-embedded/extra_libs.inc7
-rw-r--r--support/ld/toolchains/generic/extra_libs.inc0
-rw-r--r--support/make/board-includes/VLDiscovery.mk7
-rw-r--r--support/make/board-includes/cm900.mk15
-rw-r--r--support/make/board-includes/maple.mk10
-rw-r--r--support/make/board-includes/maple_RET6.mk7
-rw-r--r--support/make/board-includes/maple_mini.mk7
-rw-r--r--support/make/board-includes/maple_native.mk7
-rw-r--r--support/make/board-includes/olimex_stm32_h103.mk7
-rw-r--r--support/make/board-includes/opencm904.mk15
-rw-r--r--support/make/board-includes/st_stm3220g_eval.mk5
-rw-r--r--support/make/build-rules.mk59
-rw-r--r--support/make/build-templates.mk5
-rw-r--r--support/make/footer.mk18
-rw-r--r--support/make/header.mk4
-rw-r--r--support/make/target-config.mk54
-rw-r--r--support/scripts/45-maple.rules5
-rwxr-xr-xsupport/scripts/copy-to-ide54
-rwxr-xr-xsupport/scripts/reset.py145
-rwxr-xr-xsupport/scripts/robotis-loader.py94
-rw-r--r--support/scripts/win-list-com-ports.py29
-rwxr-xr-xsupport/stm32loader.py532
-rw-r--r--wirish/HardwareSPI.cpp320
-rw-r--r--wirish/HardwareSerial.cpp137
-rw-r--r--wirish/HardwareTimer.cpp156
-rw-r--r--wirish/Print.cpp252
-rw-r--r--wirish/boards.cpp219
-rw-r--r--wirish/boards/VLDiscovery/board.cpp104
-rw-r--r--wirish/boards/VLDiscovery/include/board/board.h91
-rw-r--r--wirish/boards/cm900/board.cpp117
-rw-r--r--wirish/boards/cm900/include/board/board.h107
-rw-r--r--wirish/boards/maple/board.cpp143
-rw-r--r--wirish/boards/maple/include/board/board.h107
-rw-r--r--wirish/boards/maple_RET6/board.cpp115
-rw-r--r--wirish/boards/maple_RET6/include/board/board.h96
-rw-r--r--wirish/boards/maple_mini/board.cpp105
-rw-r--r--wirish/boards/maple_mini/include/board/board.h83
-rw-r--r--wirish/boards/maple_native/board.cpp197
-rw-r--r--wirish/boards/maple_native/include/board/board.h95
-rw-r--r--wirish/boards/olimex_stm32_h103/board.cpp119
-rw-r--r--wirish/boards/olimex_stm32_h103/include/board/board.h99
-rw-r--r--wirish/boards/opencm904/board.cpp112
-rw-r--r--wirish/boards/opencm904/include/board/board.h105
-rw-r--r--wirish/boards/st_stm3220g_eval/board.cpp60
-rw-r--r--wirish/boards/st_stm3220g_eval/include/board/board.h53
-rw-r--r--wirish/boards_private.h71
-rw-r--r--wirish/cxxabi-compat.cpp6
-rw-r--r--wirish/ext_interrupts.cpp90
-rw-r--r--wirish/include/wirish/HardwareSPI.h225
-rw-r--r--wirish/include/wirish/HardwareSerial.h102
-rw-r--r--wirish/include/wirish/HardwareTimer.h337
-rw-r--r--wirish/include/wirish/Print.h67
-rw-r--r--wirish/include/wirish/WProgram.h35
-rw-r--r--wirish/include/wirish/bit_constants.h579
-rw-r--r--wirish/include/wirish/bits.h35
-rw-r--r--wirish/include/wirish/boards.h173
-rw-r--r--wirish/include/wirish/ext_interrupts.h128
-rw-r--r--wirish/include/wirish/io.h222
-rw-r--r--wirish/include/wirish/pwm.h56
-rw-r--r--wirish/include/wirish/usb_serial.h67
-rw-r--r--wirish/include/wirish/wirish.h77
-rw-r--r--wirish/include/wirish/wirish_debug.h57
-rw-r--r--wirish/include/wirish/wirish_math.h151
-rw-r--r--wirish/include/wirish/wirish_time.h95
-rw-r--r--wirish/include/wirish/wirish_types.h68
-rw-r--r--wirish/main.cxx40
-rw-r--r--wirish/pwm.cpp48
-rw-r--r--wirish/rules.mk62
-rw-r--r--wirish/start.S57
-rw-r--r--wirish/start_c.c95
-rw-r--r--wirish/stm32f1/boards_setup.cpp89
-rw-r--r--wirish/stm32f1/util_hooks.c83
-rw-r--r--wirish/stm32f1/wirish_debug.cpp41
-rw-r--r--wirish/stm32f1/wirish_digital.cpp89
-rw-r--r--wirish/stm32f2/boards_setup.cpp120
-rw-r--r--wirish/stm32f2/util_hooks.c45
-rw-r--r--wirish/stm32f2/wirish_debug.cpp60
-rw-r--r--wirish/stm32f2/wirish_digital.cpp99
-rw-r--r--wirish/syscalls.c176
-rw-r--r--wirish/usb_serial.cpp286
-rw-r--r--wirish/wirish_analog.cpp47
-rw-r--r--wirish/wirish_digital.cpp94
-rw-r--r--wirish/wirish_math.cpp49
-rw-r--r--wirish/wirish_shift.cpp37
-rw-r--r--wirish/wirish_time.cpp45
567 files changed, 58076 insertions, 143 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..aed97bb
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,6 @@
+((c-mode . ((c-basic-offset . 4)
+ (indent-tabs-mode . nil)
+ (tab-width . 50))) ; display tabs badly on purpose
+ (c++-mode . ((c-basic-offset . 4)
+ (indent-tabs-mode . nil)
+ (tab-width . 50)))) ; display tabs badly on purpose \ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0187b3d..ec1e96b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,12 @@
build/
+doxygen/xml/
+doxygen/html/
+main.cpp
+libmaple.layout
+tags
+TAGS
*~
+*.swp
+arm
+cscope*
+.gdbinit
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 0000000..2b803b1
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,83 @@
+ This is at least a partial credits-file of people that have
+ contributed to libmaple (it was originally drawn from the
+ commit logs, so it e.g. leaves out contributions that didn't
+ come in the form of patches). It's formatted the same way as
+ the Linux kernel CREDITS: sorted by name and formatted for
+ easy processing.
+
+ The fields are: name (N), email (E), web-address (W),
+ description (D). Feel free to add any other fields present in
+ the Linux CREDITS file.
+
+ LeafLabs
+
+----------
+
+N: Marti Bolivar
+E: mbolivar@leaflabs.com
+D: Current libmaple maintainer
+D: Random libmaple hacks
+
+N: Anton Eltchaninov
+E: anton.eltchaninov@gmail.com
+D: STM32F1 value line support
+
+N: Victor G Estevez
+E: sphing@sphing.net
+D: Makefile tweak
+
+N: Gaute Hope
+E: eg@gaute.vetsj.com
+W: http://gaute.vetsj.com/
+D: Makefile fixes
+
+N: Michael Hope
+E: michaelh@juju.net.nz
+D: Documentation (!)
+D: IWDG support
+D: Original DMA support
+D: miscellaneous fixes and improvements
+
+N: Perry Hung
+E: iperry@alum.mit.edu
+D: Original libmaple hacker
+
+N: Trystan Jones ("crenn")
+E: crenn6977@gmail.com
+D: New Wire library
+
+N: David Kiliani
+E: mail@davidkiliani.de
+D: Olimex STM32-H103 support
+
+N: Andrew Meyer
+E: ajm@leaflabs.com
+D: USB stack and CDC ACM driver
+D: reset.py
+
+N: Bryan Newbold
+E: bnewbold@robocracy.org
+D: Original libmaple hacker
+W: robocracy.org
+
+N: Bruce Perens
+E: bruce@perens.com
+D: Makefile library target
+W: http://perens.com
+
+N: Hanspeter Portner
+E: agenthp@users.sf.net
+D: reset.py Python3 fixups
+
+N: RJ Ryan
+E: rryan@mit.edu
+D: USB fixups
+
+N: Nis Sarup
+E: nis@sarup.dk
+D: FreeRTOS support
+W: http://sarup.dk/index.html
+
+N: Andy Scott ("xttocs")
+E: andy.g.scott@gmail.com
+D: LiquidCrystal library
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..7fdec9a
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,18 @@
+Read this before submitting patches:
+
+ http://leaflabs.com/docs/libmaple/contributing.html
+
+In particular, patches without sign-off lines will not be accepted.
+
+If your patch is formatted very differently from the libmaple style,
+you may find the astyle options file in contrib/astylerc useful for
+auto-formatting it roughly in the libmaple style.
+
+LeafLabs is a small shop. Please help us merge your patches
+efficiently by getting formatting nits etc. out of the way before
+submitting.
+
+When writing your patch, feel free to add yourself to the CREDITS
+file. If you can't write your name in ASCII (or choose not to
+romanize it), then use UTF-8, and use your best judgement for how it
+should sort compared to the other names in the file.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2d4b51d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,100 @@
+-------------------------------------------------------------------------------
+All code in /libmaple/usb/usb_lib/ is from v2.0.2 of the standard peripheral
+library from STMicroelectronics, which is released with the following notice:
+
+THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+
+-------------------------------------------------------------------------------
+Unless otherwise noted in the header, all code in /libmaple/ and /wirish/ is
+copyright LeafLabs LLC and are released under the MIT License:
+
+Copyright (c) 2009-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.
+
+See http://creativecommons.org/licenses/MIT/ for more information.
+
+-------------------------------------------------------------------------------
+Some of files in /support/ld/ were written by 'lanchon' and posted in the
+STMicroelectronics forum at:
+
+https://my.st.com/public/STe2ecommunities/mcu/Lists/ARM%20CortexM3%20STM32/flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/ARM%20CortexM3%20STM32/STM32%20CC%2B%2B%20build%20environment%20using%20CodeSourcery%20Sourcery%20G%2B%2B&currentviews=18152
+
+These files are stated to be in the public domain. Other files in /stm32conf/
+are from CodeSourcery, Inc with the following notice:
+
+Copyright (c) 2006, 2007 CodeSourcery Inc
+
+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.
+
+-------------------------------------------------------------------------------
+The ./support/stm32loader.py python script is GPL (see
+http://www.gnu.org/licenses/ for a copy) and comes with the following info:
+
+ Author: Ivan A-R <ivan@tuxotronic.org>
+ Project page: http://tuxotronic.org/wiki/projects/stm32loader
+
+-------------------------------------------------------------------------------
+
+Note on contributing patches:
+
+If contributing patches, please add a Signed-off-by: line certifying
+your Developer Certificate of Origin (DCO). You should include this
+line at the bottom of any Git commits you want merged in, or along
+with any email you submit. By including this line, you are certifying
+the following:
+
+ Developer's Certificate of Origin 1.1
+
+ By making a contribution to this project, I certify that:
+
+ (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+ (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+ (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+ (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
diff --git a/Makefile b/Makefile
index 5255525..c632ee8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,134 +1,203 @@
-# Makefile for LeafLabs documentation (automatically generated by
-# Sphinx).
+# Try "make help" first
+
+.DEFAULT_GOAL := sketch
+
+##
+## Useful paths, constants, etc.
+##
+
+ifeq ($(LIB_MAPLE_HOME),)
+SRCROOT := .
+else
+SRCROOT := $(LIB_MAPLE_HOME)
+endif
+BUILD_PATH = build
+LIBMAPLE_PATH := $(SRCROOT)/libmaple
+WIRISH_PATH := $(SRCROOT)/wirish
+SUPPORT_PATH := $(SRCROOT)/support
+LIBRARIES_PATH := $(SRCROOT)/libraries
+# Support files for linker
+LDDIR := $(SUPPORT_PATH)/ld
+# Support files for this Makefile
+MAKEDIR := $(SUPPORT_PATH)/make
+BOARD_INCLUDE_DIR := $(MAKEDIR)/board-includes
+
+##
+## Target-specific configuration. This determines some compiler and
+## linker options/flags.
+##
+
+# Try "make help" for more information on BOARD and MEMORY_TARGET;
+# these default to a Maple Flash build.
+BOARD ?= maple
+MEMORY_TARGET ?= flash
+
+# Chooses the bootloader, available: maple and robotis
+BOOTLOADER ?= maple
+
+# This is the serial port used by robotis bootloader
+ROBOTIS_PORT ?= /dev/ttyACM0
+
+# $(BOARD)- and $(MEMORY_TARGET)-specific configuration
+include $(MAKEDIR)/target-config.mk
+
+##
+## Build rules and useful templates
+##
+
+include $(MAKEDIR)/build-rules.mk
+include $(MAKEDIR)/build-templates.mk
+
+##
+## Compilation flags
+##
+
+# FIXME: the following allows for deprecated include style, e.g.:
+# #include "libmaple.h"
+# or
+# #include "wirish.h"
+# It slows compilation noticeably; remove after 1 release.
+TARGET_FLAGS += -I$(LIBMAPLE_PATH)/include/libmaple \
+ -I$(WIRISH_PATH)/include/wirish
+TARGET_FLAGS += -I$(LIBRARIES_PATH) # for internal lib. includes, e.g. <Wire/WireBase.h>
+GLOBAL_CFLAGS := -Os -g3 -gdwarf-2 -nostdlib \
+ -ffunction-sections -fdata-sections \
+ -Wl,--gc-sections $(TARGET_FLAGS) \
+ -DBOOTLOADER_$(BOOTLOADER)
+GLOBAL_CXXFLAGS := -fno-rtti -fno-exceptions -Wall $(TARGET_FLAGS)
+GLOBAL_ASFLAGS := -x assembler-with-cpp $(TARGET_FLAGS)
+LDFLAGS = $(TARGET_LDFLAGS) $(TOOLCHAIN_LDFLAGS) -mcpu=cortex-m3 -mthumb \
+ -Xlinker --gc-sections \
+ -Xassembler --march=armv7-m -Wall
+# -Xlinker --print-gc-sections \
+
+##
+## Set all submodules here
+##
+
+LIBMAPLE_MODULES += $(SRCROOT)/libmaple
+LIBMAPLE_MODULES += $(SRCROOT)/libmaple/usb # The USB module is kept separate
+LIBMAPLE_MODULES += $(LIBMAPLE_MODULE_SERIES) # STM32 series submodule in libmaple
+LIBMAPLE_MODULES += $(SRCROOT)/wirish
+
+# Official libraries:
+LIBMAPLE_MODULES += $(SRCROOT)/libraries/Servo
+LIBMAPLE_MODULES += $(SRCROOT)/libraries/LiquidCrystal
+LIBMAPLE_MODULES += $(SRCROOT)/libraries/Wire
+# Experimental libraries:
+LIBMAPLE_MODULES += $(SRCROOT)/libraries/FreeRTOS
+
+# User modules:
+ifneq ($(USER_MODULES),)
+LIBMAPLE_MODULES += $(USER_MODULES)
+endif
+
+# Call each module's rules.mk:
+$(foreach m,$(LIBMAPLE_MODULES),$(eval $(call LIBMAPLE_MODULE_template,$(m))))
+
+##
+## Targets
+##
+
+# main target
+include $(SRCROOT)/build-targets.mk
+
+.PHONY: install sketch clean help cscope tags ctags ram flash jtag doxygen mrproper list-boards
+
+# Target upload commands
+# USB ID for DFU upload -- FIXME: do something smarter with this
+BOARD_USB_VENDOR_ID := 1EAF
+BOARD_USB_PRODUCT_ID := 0003
+
+ifeq ($(BOOTLOADER),maple)
+UPLOAD_ram := $(SUPPORT_PATH)/scripts/reset.py && \
+ sleep 1 && \
+ $(DFU) -a0 -d $(BOARD_USB_VENDOR_ID):$(BOARD_USB_PRODUCT_ID) -D $(BUILD_PATH)/$(BOARD).bin -R
+UPLOAD_flash := $(SUPPORT_PATH)/scripts/reset.py && \
+ sleep 1 && \
+ $(DFU) -a1 -d $(BOARD_USB_VENDOR_ID):$(BOARD_USB_PRODUCT_ID) -D $(BUILD_PATH)/$(BOARD).bin -R
+endif
+
+ifeq ($(BOOTLOADER),robotis)
+UPLOAD_flash := $(SUPPORT_PATH)/scripts/robotis-loader.py $(ROBOTIS_PORT) $(BUILD_PATH)/$(BOARD).bin
+endif
+
+# Conditionally upload to whatever the last build was
+install: INSTALL_TARGET = $(shell cat $(BUILD_PATH)/build-type 2>/dev/null)
+install: $(BUILD_PATH)/$(BOARD).bin
+ @echo "Install target:" $(INSTALL_TARGET)
+ $(UPLOAD_$(INSTALL_TARGET))
+
+# Force a rebuild if the target changed
+PREV_BUILD_TYPE = $(shell cat $(BUILD_PATH)/build-type 2>/dev/null)
+build-check:
+ifneq ($(PREV_BUILD_TYPE), $(MEMORY_TARGET))
+ $(shell rm -rf $(BUILD_PATH))
+endif
+
+sketch: build-check MSG_INFO $(BUILD_PATH)/$(BOARD).bin
-# 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
+clean:
+ rm -rf build
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+mrproper: clean
+ rm -rf 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:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-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."
-
-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.qhc"
-
-devhelp:
- $(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:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
- $(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:
- $(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:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-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."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
+ @echo ""
+ @echo "Basic usage (BOARD defaults to maple):"
+ @echo " $$ cp your-main.cpp main.cpp"
+ @echo " $$ make BOARD=your_board"
+ @echo " $$ make BOARD=your_board install"
+ @echo ""
+ @echo "(Multiple source files? Link with libmaple.a (\`$$ make library')"
+ @echo "or hack build-targets.mk appropriately.)"
+ @echo ""
+ @echo "Important targets:"
+ @echo " sketch: Compile for BOARD to MEMORY_TARGET (default)."
+ @echo " install: Compile and upload over USB using Maple bootloader"
+ @echo ""
+ @echo "You *must* set BOARD if not compiling for Maple (e.g."
+ @echo "use BOARD=maple_mini for mini, etc.), and MEMORY_TARGET"
+ @echo "if not compiling to Flash. Run \`$$ make list-boards' for"
+ @echo "a list of all boards."
+ @echo ""
+ @echo "Valid MEMORY_TARGETs (default=flash):"
+ @echo " ram: Compile to RAM (doesn't touch Flash)"
+ @echo " flash: Compile to Flash (for Maple bootloader)"
+ @echo " jtag: Compile for JTAG/SWD upload (overwrites bootloader)"
+ @echo ""
+ @echo "Other targets:"
+ @echo " clean: Remove all build and object files"
+ @echo " doxygen: Build Doxygen HTML and XML documentation"
+ @echo " help: Show this message"
+ @echo " mrproper: Remove all generated files"
+ @echo ""
+
+cscope:
+ rm -rf cscope.*
+ find . -name '*.[hcS]' -o -name '*.cpp' | xargs cscope -b
+
+tags:
+ etags `find . -name "*.c" -o -name "*.cpp" -o -name "*.h"`
+ @echo "Made TAGS file for EMACS code browsing"
+
+ctags:
+ ctags-exuberant -R .
+ @echo "Made tags file for VIM code browsing"
+
+ram:
+ @$(MAKE) MEMORY_TARGET=ram --no-print-directory sketch
+
+flash:
+ @$(MAKE) MEMORY_TARGET=flash --no-print-directory sketch
+
+jtag:
+ @$(MAKE) MEMORY_TARGET=jtag --no-print-directory sketch
doxygen:
- @echo "Wrong! You need to run this from within libmaple!"
- false
+ doxygen $(SUPPORT_PATH)/doxygen/Doxyfile
+
+# This output is kind of ugly, but I don't understand make very well.
+list-boards:
+ @echo " $(addsuffix "\\n",$(basename $(notdir $(wildcard $(BOARD_INCLUDE_DIR)/*.mk))))"
diff --git a/README b/README
index 60fb888..400e656 100644
--- a/README
+++ b/README
@@ -1,24 +1,126 @@
-This repository contains source files used to generate the
-documentation for LeafLabs' libmaple and Maple IDE projects [*]. The
-HTML documentation generated from these sources is available online:
+
+ _ _ _ _
+ | (_) |__ _ __ ___ __ _ _ __ | | ___
+ | | | '_ \| '_ ` _ \ / _` | '_ \| |/ _ \
+ | | | |_) | | | | | | (_| | |_) | | __/
+ |_|_|_.__/|_| |_| |_|\__,_| .__/|_|\___|
+ |_| by LeafLabs!
+ leaflabs.com
+
+
+The latest version of this repository can be found here:
+
+ https://github.com/leaflabs/libmaple
+
+IMPORTANT: read HACKING _before_ submitting patches.
+
+General information
+------------------------------------------------------------------------------
+
+libmaple is a library for programming ST's STM32 line of Cortex M3
+microcontrollers. It has a pure C layer, libmaple proper, which does
+most of the work, and a C++ layer, Wirish, which provides high-level
+convenience functions and a Wiring/Arduino-compatible interface.
+
+libmaple is designed for portability, and currently runs on a variety
+of STM32F1 performance and value line MCUs, with experimental support
+for STM32F2 MCUs.
+
+Using libmaple
+------------------------------------------------------------------------------
+
+The easiest way to use libmaple is in concert with the Maple IDE.
+Maple IDE, a sister project from LeafLabs, is an Arduino IDE fork
+usable for programming Maple boards, which includes libmaple and a
+compilation and upload toolchain:
+
+ http://leaflabs.com/docs/maple-ide-install.html
+
+Additionally, a HOWTO on setting up this library for use from the
+command line in a Unix environment is available here:
+
+ http://leaflabs.com/docs/unix-toolchain.html
+
+Documentation, Etc.
+------------------------------------------------------------------------------
+
+HTML documentation for the latest release of libmaple/Maple IDE is
+available here:
http://leaflabs.com/docs/
-The above URL is the recommended way for users to read the
-documentation. The docs for the latest release are always available
-there.
+libmaple is well documented via Doxygen comments. The HTML
+documentation referenced above (which also includes the Doxygen
+output) is automatically generated from the source files in the
+leaflabs-docs repository. In order to obtain the leaflabs-docs
+repository, visit:
-Older versions are here:
+ http://github.com/leaflabs/leaflabs-docs/
- http://static.leaflabs.com/pub/leaflabs/maple-docs/
+Repository Layout
+------------------------------------------------------------------------------
-The file README-building.txt explains how to build the HTML docs.
+/build/
-The file README-maintainers.txt contains important information for
-maintainers of the documentation (e.g. how to add docs for a new
-board, how to cut a release version of the docs, etc.).
+ Compiler output
-[*] libmaple and Maple IDE themselves are in separate repositories:
+/contrib/
- https://github.com/leaflabs/libmaple
- https://github.com/leaflabs/maple-ide
+ Community-contributed resources. LeafLabs doesn't maintain the
+ contents of this directory, so it may get stale.
+
+/examples/
+
+ Example code and test programs. Copy these to /main.cpp to compile them.
+
+/libmaple/
+
+ This is the meat of the library. C only, no C++. The
+ Arduino-like compatibility layer (in C++) is in /wirish/.
+
+/libraries/
+
+ Special-purpose libraries that don't merit inclusion in the
+ /libmaple/ and /wirish/ directories, which are intended for
+ general use. Arduino-compatible libraries go here.
+
+/LICENSE
+
+ Licensing and copyright information.
+
+/main.cpp.example
+
+ main.cpp is required for a successful build but is non-existent by
+ default; use this file as a template for building your program. By
+ default, just blinks an LED.
+
+/Makefile
+
+ libmaple build instructions for GNU Make. (This is supplemented by
+ build-targets.mk, the rules.mk files throughout the tree, and the
+ files in support/make/).
+
+/notes/
+
+ Unstructured text notes that may be useful.
+
+/README
+
+ This file ;).
+
+/support/
+
+ Support files and scripts for various purposes.
+
+ gdb/ GDB scripts.
+ ld/ Linker scripts.
+ make/ Additional files used by the top-level Makefile.
+ scripts/ Miscellany.
+ doxygen/ Doxygen configuration.
+ stm32loader.py Upload script for the STM32's built-in USART bootloader.
+
+/wirish/
+
+ Extra wrappers and functionality around the lower level code in
+ /libmaple/. These files implement an Arduino "Wiring"-like
+ library.
diff --git a/build-targets.mk b/build-targets.mk
new file mode 100644
index 0000000..aaff2d0
--- /dev/null
+++ b/build-targets.mk
@@ -0,0 +1,42 @@
+# main project target
+$(BUILD_PATH)/main.o: $(SRCROOT)/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 -Wl,-Map,$(BUILD_PATH)/$(BOARD).map
+
+$(BUILD_PATH)/$(BOARD).bin: $(BUILD_PATH)/$(BOARD).elf
+ $(SILENT_OBJCOPY) $(OBJCOPY) -v -Obinary $(BUILD_PATH)/$(BOARD).elf $@ 1>/dev/null
+ $(SILENT_DISAS) $(DISAS) -d $(BUILD_PATH)/$(BOARD).elf > $(BUILD_PATH)/$(BOARD).disas
+ @echo " "
+ @echo "Object file sizes:"
+ @find $(BUILD_PATH) -iname *.o | xargs $(SIZE) -t > $(BUILD_PATH)/$(BOARD).sizes
+ @cat $(BUILD_PATH)/$(BOARD).sizes
+ @echo " "
+ @echo "Final Size:"
+ @$(SIZE) $<
+ @echo $(MEMORY_TARGET) > $(BUILD_PATH)/build-type
+
+$(BUILDDIRS):
+ @mkdir -p $@
+
+MSG_INFO:
+ @echo "================================================================================"
+ @echo ""
+ @echo " Build info:"
+ @echo " BOARD: " $(BOARD)
+ @echo " MCU: " $(MCU)
+ @echo " MEMORY_TARGET: " $(MEMORY_TARGET)
+ @echo ""
+ @echo " See 'make help' for all possible targets"
+ @echo ""
+ @echo "================================================================================"
+ @echo ""
diff --git a/contrib/astylerc b/contrib/astylerc
new file mode 100644
index 0000000..211b008
--- /dev/null
+++ b/contrib/astylerc
@@ -0,0 +1,22 @@
+# This is an astyle (http://astyle.sourceforge.net/) options file you
+# can use to autoformat code roughly along the lines of libmaple's
+# style guidelines. "Roughly" in the sense that if you use it on code
+# that wildly differs from the libmaple style, the patch stands a much
+# better chance of not getting held up for trivial reasons.
+#
+# Use it like this:
+#
+# $ astyle --options=contrib/astylerc <your_source_file>
+#
+# It needs astyle version 2; versions 1.x are missing some of these
+# options.
+
+--indent=spaces=4
+--style=attach
+--indent-namespaces
+--pad-oper
+--pad-header
+--unpad-paren
+--align-pointer=name
+--indent-preprocessor
+--lineend=linux
diff --git a/contrib/automake/Makefile.am b/contrib/automake/Makefile.am
new file mode 100644
index 0000000..58275cf
--- /dev/null
+++ b/contrib/automake/Makefile.am
@@ -0,0 +1,138 @@
+# Top level Makefile for libmaple
+
+CROSS_COMPILE = arm-none-eabi-
+CC = $(CROSS_COMPILE)gcc
+CXX = $(CROSS_COMPILE)g++
+LD = $(CROSS_COMPILE)ld
+
+# The main library
+lib_LIBRARIES = \
+ libmaple.a \
+ libmapleusb.a
+
+# libwirish.a
+
+# noinst_PROGRAMS = \
+# main
+
+# main_SOURCES = \
+# startup2.c \
+# main.cpp
+
+main_LDFLAGS = \
+ --gc-sections \
+ -Map=main.map
+
+main_LDADD = libmaple.a
+
+# Main library
+libmaple_a_SOURCES = \
+ libmaple/adc.c \
+ libmaple/bkp.c \
+ libmaple/dac.c \
+ libmaple/dma.c \
+ libmaple/exti.c \
+ libmaple/flash.c \
+ libmaple/fsmc.c \
+ libmaple/gpio.c \
+ libmaple/iwdg.c \
+ libmaple/nvic.c \
+ libmaple/pwr.c \
+ libmaple/i2c.c \
+ libmaple/rcc.c \
+ libmaple/spi.c \
+ libmaple/syscalls.c \
+ libmaple/systick.c \
+ libmaple/timer.c \
+ libmaple/usart.c \
+ libmaple/util.c
+
+nobase_include_HEADERS = \
+ libmaple/adc.h \
+ libmaple/bitband.h \
+ libmaple/bkp.h \
+ libmaple/dac.h \
+ libmaple/delay.h \
+ libmaple/dma.h \
+ libmaple/exti.h \
+ libmaple/flash.h \
+ libmaple/fsmc.h \
+ libmaple/gpio.h \
+ libmaple/i2c.h \
+ libmaple/iwdg.h \
+ libmaple/libmaple.h \
+ libmaple/libmaple_types.h \
+ libmaple/nvic.h \
+ libmaple/pwr.h \
+ libmaple/rcc.h \
+ libmaple/ring_buffer.h \
+ libmaple/scb.h \
+ libmaple/spi.h \
+ libmaple/stm32.h \
+ libmaple/systick.h \
+ libmaple/timer.h \
+ libmaple/usart.h \
+ libmaple/util.h \
+ libmaple/usb/descriptors.h \
+ libmaple/usb/usb.h \
+ libmaple/usb/usb_callbacks.h \
+ libmaple/usb/usb_config.h \
+ libmaple/usb/usb_hardware.h \
+ libmaple/usb/usb_lib/usb_core.h \
+ libmaple/usb/usb_lib/usb_def.h \
+ libmaple/usb/usb_lib/usb_init.h \
+ libmaple/usb/usb_lib/usb_int.h \
+ libmaple/usb/usb_lib/usb_lib.h \
+ libmaple/usb/usb_lib/usb_mem.h \
+ libmaple/usb/usb_lib/usb_regs.h \
+ libmaple/usb/usb_lib/usb_type.h
+
+libmapleusb_a_SOURCES = \
+ libmaple/usb/descriptors.c \
+ libmaple/usb/usb.c \
+ libmaple/usb/usb_callbacks.c \
+ libmaple/usb/usb_hardware.c \
+ libmaple/usb/usb_lib/usb_core.c \
+ libmaple/usb/usb_lib/usb_init.c \
+ libmaple/usb/usb_lib/usb_int.c \
+ libmaple/usb/usb_lib/usb_mem.c \
+ libmaple/usb/usb_lib/usb_regs.c
+
+libwirish_a_SOURCES = \
+ wirish/wirish_math.cpp \
+ wirish/Print.cpp \
+ wirish/boards.cpp \
+ wirish/boards/maple.cpp \
+ wirish/boards/maple_mini.cpp \
+ wirish/boards/maple_native.cpp \
+ wirish/boards/maple_RET6.cpp \
+ wirish/comm/HardwareSerial.cpp \
+ wirish/comm/HardwareSPI.cpp \
+ wirish/HardwareTimer.cpp \
+ wirish/usb_serial.cpp \
+ wirish/cxxabi-compat.cpp \
+ wirish/wirish_shift.cpp \
+ wirish/wirish_analog.cpp \
+ wirish/wirish_time.cpp \
+ wirish/pwm.cpp \
+ wirish/ext_interrupts.cpp \
+ wirish/wirish_digital.cpp
+
+MCU := STM32F103RB
+BOARD ?= maple
+DENSITY = STM32_MEDIUM_DENSITY
+
+FLAGS = \
+ -Os -ggdb -nostdlib -Wall \
+ -ffunction-sections -fdata-sections -Wl,--gc-sections \
+ -mcpu=cortex-m3 -mthumb -fshort-enums -mfloat-abi=soft \
+ -DBOARD_$(BOARD) -DMCU_$(MCU) -D$(DENSITY) -DVECT_TAB_BASE \
+ -I$(srcdir)/libmaple \
+ -I$(srcdir)/libmaple/usb \
+ -I$(srcdir)/libmaple/usb/usb_lib
+
+AM_CFLAGS = $(FLAGS) -std=gnu99
+
+AM_CXXFLAGS = $(FLAGS) \
+ -I$(srcdir)/wirish -I$(srcdir)/wirish/comm -I$(srcdir)/wirish/boards \
+ -fno-rtti -fno-exceptions
diff --git a/contrib/automake/configure.ac b/contrib/automake/configure.ac
new file mode 100644
index 0000000..9f072db
--- /dev/null
+++ b/contrib/automake/configure.ac
@@ -0,0 +1,8 @@
+AC_INIT(libmaple, 0.11+git)
+AM_INIT_AUTOMAKE(foreign subdir-objects color-tests)
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_FILES(Makefile)
+AM_PROG_AS
+AC_PROG_CXX
+AM_PROG_LIBTOOL
+AC_OUTPUT
diff --git a/contrib/openocd/debug_0.3.cfg b/contrib/openocd/debug_0.3.cfg
new file mode 100644
index 0000000..87d33ae
--- /dev/null
+++ b/contrib/openocd/debug_0.3.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 stm32x 0x08000000 0x00020000 0 0 $_TARGETNAME
+
+proc nopforever {} {
+ puts "Resetting the chip..."
+ reset run
+}
+
+init
+nopforever
diff --git a/contrib/openocd/debug_0.4.cfg b/contrib/openocd/debug_0.4.cfg
new file mode 100644
index 0000000..7d6982a
--- /dev/null
+++ b/contrib/openocd/debug_0.4.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 srst_only
+
+#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... Halting for debugger."
+ reset halt
+}
+
+init
+nopforever
diff --git a/contrib/openocd/flash_0.3.cfg b/contrib/openocd/flash_0.3.cfg
new file mode 100644
index 0000000..41c6532
--- /dev/null
+++ b/contrib/openocd/flash_0.3.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 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/contrib/openocd/flash_0.4.cfg b/contrib/openocd/flash_0.4.cfg
new file mode 100644
index 0000000..32c06c6
--- /dev/null
+++ b/contrib/openocd/flash_0.4.cfg
@@ -0,0 +1,95 @@
+# 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 srst_only
+
+#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..."
+ reset halt
+
+ echo "Unlocking flash..."
+ flash protect 0 0 last off
+
+ echo "Erasing..."
+ flash erase_address 0x08000000 0x20000
+
+ 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/contrib/openocd/openocd-wrapper.sh b/contrib/openocd/openocd-wrapper.sh
new file mode 100755
index 0000000..73be92e
--- /dev/null
+++ b/contrib/openocd/openocd-wrapper.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+# Helper to decide which openocd script to use. We only support 0.3.x and 0.4.x.
+
+if [ $# -ne 1 ]
+then
+ echo "Usage: `basename $0` {flash|debug}"
+ exit 1
+fi
+
+OPENOCD_VERSION=`openocd -v 2>&1 | head -n1 | \
+ awk '{print $4}' | sed 's/\([0-9]*\.[0-9]*\)\.[0-9]*/\1/'`
+
+CFG_FILE=$1_${OPENOCD_VERSION}.cfg
+
+openocd -f support/openocd/$CFG_FILE
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000..0187b3d
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,2 @@
+build/
+*~
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..5255525
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,134 @@
+# Makefile for LeafLabs documentation (automatically generated by
+# Sphinx).
+
+# 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
+
+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:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+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."
+
+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.qhc"
+
+devhelp:
+ $(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:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(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:
+ $(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:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+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."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+doxygen:
+ @echo "Wrong! You need to run this from within libmaple!"
+ false
diff --git a/docs/README b/docs/README
new file mode 100644
index 0000000..60fb888
--- /dev/null
+++ b/docs/README
@@ -0,0 +1,24 @@
+This repository contains source files used to generate the
+documentation for LeafLabs' libmaple and Maple IDE projects [*]. The
+HTML documentation generated from these sources is available online:
+
+ http://leaflabs.com/docs/
+
+The above URL is the recommended way for users to read the
+documentation. The docs for the latest release are always available
+there.
+
+Older versions are here:
+
+ http://static.leaflabs.com/pub/leaflabs/maple-docs/
+
+The file README-building.txt explains how to build the HTML docs.
+
+The file README-maintainers.txt contains important information for
+maintainers of the documentation (e.g. how to add docs for a new
+board, how to cut a release version of the docs, etc.).
+
+[*] libmaple and Maple IDE themselves are in separate repositories:
+
+ https://github.com/leaflabs/libmaple
+ https://github.com/leaflabs/maple-ide
diff --git a/README-building.txt b/docs/README-building.txt
index de4a7f7..de4a7f7 100644
--- a/README-building.txt
+++ b/docs/README-building.txt
diff --git a/README-maintainers.txt b/docs/README-maintainers.txt
index 48e8e5c..48e8e5c 100644
--- a/README-maintainers.txt
+++ b/docs/README-maintainers.txt
diff --git a/copy-to-ide b/docs/copy-to-ide
index 6cd4bdd..6cd4bdd 100755
--- a/copy-to-ide
+++ b/docs/copy-to-ide
diff --git a/make.bat b/docs/make.bat
index 1833a4b..1833a4b 100644
--- a/make.bat
+++ b/docs/make.bat
diff --git a/source/_static/.gitignore b/docs/source/_static/.gitignore
index e69de29..e69de29 100644
--- a/source/_static/.gitignore
+++ b/docs/source/_static/.gitignore
diff --git a/source/_static/breathe.css b/docs/source/_static/breathe.css
index d86028c..d86028c 100644
--- a/source/_static/breathe.css
+++ b/docs/source/_static/breathe.css
diff --git a/source/_static/img/blinky-to-flash.png b/docs/source/_static/img/blinky-to-flash.png
index 0320c5b..0320c5b 100644
--- a/source/_static/img/blinky-to-flash.png
+++ b/docs/source/_static/img/blinky-to-flash.png
Binary files differ
diff --git a/source/_static/img/blinky.png b/docs/source/_static/img/blinky.png
index bda4cee..bda4cee 100644
--- a/source/_static/img/blinky.png
+++ b/docs/source/_static/img/blinky.png
Binary files differ
diff --git a/source/_static/img/button-new.png b/docs/source/_static/img/button-new.png
index 3fd98be..3fd98be 100644
--- a/source/_static/img/button-new.png
+++ b/docs/source/_static/img/button-new.png
Binary files differ
diff --git a/source/_static/img/button-open.png b/docs/source/_static/img/button-open.png
index 466fc10..466fc10 100644
--- a/source/_static/img/button-open.png
+++ b/docs/source/_static/img/button-open.png
Binary files differ
diff --git a/source/_static/img/button-save.png b/docs/source/_static/img/button-save.png
index 7eba286..7eba286 100644
--- a/source/_static/img/button-save.png
+++ b/docs/source/_static/img/button-save.png
Binary files differ
diff --git a/source/_static/img/button-serial-monitor.png b/docs/source/_static/img/button-serial-monitor.png
index aec9741..aec9741 100644
--- a/source/_static/img/button-serial-monitor.png
+++ b/docs/source/_static/img/button-serial-monitor.png
Binary files differ
diff --git a/source/_static/img/button-stop.png b/docs/source/_static/img/button-stop.png
index 4812ae9..4812ae9 100644
--- a/source/_static/img/button-stop.png
+++ b/docs/source/_static/img/button-stop.png
Binary files differ
diff --git a/source/_static/img/button-upload.png b/docs/source/_static/img/button-upload.png
index 0f41eeb..0f41eeb 100644
--- a/source/_static/img/button-upload.png
+++ b/docs/source/_static/img/button-upload.png
Binary files differ
diff --git a/source/_static/img/button-verify.png b/docs/source/_static/img/button-verify.png
index 95abeb8..95abeb8 100644
--- a/source/_static/img/button-verify.png
+++ b/docs/source/_static/img/button-verify.png
Binary files differ
diff --git a/source/_static/img/codeblocks_build.png b/docs/source/_static/img/codeblocks_build.png
index c98bcdc..c98bcdc 100644
--- a/source/_static/img/codeblocks_build.png
+++ b/docs/source/_static/img/codeblocks_build.png
Binary files differ
diff --git a/source/_static/img/codeblocks_makefile.png b/docs/source/_static/img/codeblocks_makefile.png
index a0ef21f..a0ef21f 100644
--- a/source/_static/img/codeblocks_makefile.png
+++ b/docs/source/_static/img/codeblocks_makefile.png
Binary files differ
diff --git a/source/_static/img/codeblocks_maketargets.png b/docs/source/_static/img/codeblocks_maketargets.png
index bbb68cb..bbb68cb 100644
--- a/source/_static/img/codeblocks_maketargets.png
+++ b/docs/source/_static/img/codeblocks_maketargets.png
Binary files differ
diff --git a/source/_static/img/codeblocks_newproject.png b/docs/source/_static/img/codeblocks_newproject.png
index 8d08d1f..8d08d1f 100644
--- a/source/_static/img/codeblocks_newproject.png
+++ b/docs/source/_static/img/codeblocks_newproject.png
Binary files differ
diff --git a/source/_static/img/github-clone-in-windows.png b/docs/source/_static/img/github-clone-in-windows.png
index 41d76d1..41d76d1 100644
--- a/source/_static/img/github-clone-in-windows.png
+++ b/docs/source/_static/img/github-clone-in-windows.png
Binary files differ
diff --git a/source/_static/img/ide-blinky.png b/docs/source/_static/img/ide-blinky.png
index 3cccdb4..3cccdb4 100644
--- a/source/_static/img/ide-blinky.png
+++ b/docs/source/_static/img/ide-blinky.png
Binary files differ
diff --git a/source/_static/img/jtag-wiring.png b/docs/source/_static/img/jtag-wiring.png
index 8f31f99..8f31f99 100644
--- a/source/_static/img/jtag-wiring.png
+++ b/docs/source/_static/img/jtag-wiring.png
Binary files differ
diff --git a/source/_static/img/osx-network-prefs-unconfigured.png b/docs/source/_static/img/osx-network-prefs-unconfigured.png
index 70d2fa0..70d2fa0 100644
--- a/source/_static/img/osx-network-prefs-unconfigured.png
+++ b/docs/source/_static/img/osx-network-prefs-unconfigured.png
Binary files differ
diff --git a/source/_static/img/osx-unconfigured-popup.png b/docs/source/_static/img/osx-unconfigured-popup.png
index a43ad57..a43ad57 100644
--- a/source/_static/img/osx-unconfigured-popup.png
+++ b/docs/source/_static/img/osx-unconfigured-popup.png
Binary files differ
diff --git a/source/_static/img/round_logo_32x32.ico b/docs/source/_static/img/round_logo_32x32.ico
index 29fb2bf..29fb2bf 100644
--- a/source/_static/img/round_logo_32x32.ico
+++ b/docs/source/_static/img/round_logo_32x32.ico
Binary files differ
diff --git a/source/_static/img/round_logo_60x60.png b/docs/source/_static/img/round_logo_60x60.png
index dacd36a..dacd36a 100644
--- a/source/_static/img/round_logo_60x60.png
+++ b/docs/source/_static/img/round_logo_60x60.png
Binary files differ
diff --git a/source/_static/img/serial-monitor.png b/docs/source/_static/img/serial-monitor.png
index 6162dab..6162dab 100644
--- a/source/_static/img/serial-monitor.png
+++ b/docs/source/_static/img/serial-monitor.png
Binary files differ
diff --git a/source/_static/img/serial-port-mac.png b/docs/source/_static/img/serial-port-mac.png
index b3a1989..b3a1989 100644
--- a/source/_static/img/serial-port-mac.png
+++ b/docs/source/_static/img/serial-port-mac.png
Binary files differ
diff --git a/source/_static/img/serial-port-ubuntu.png b/docs/source/_static/img/serial-port-ubuntu.png
index 8038e41..8038e41 100644
--- a/source/_static/img/serial-port-ubuntu.png
+++ b/docs/source/_static/img/serial-port-ubuntu.png
Binary files differ
diff --git a/source/_static/img/serial-port-win.png b/docs/source/_static/img/serial-port-win.png
index 90dc1c4..90dc1c4 100644
--- a/source/_static/img/serial-port-win.png
+++ b/docs/source/_static/img/serial-port-win.png
Binary files differ
diff --git a/source/_static/img/upload-button.png b/docs/source/_static/img/upload-button.png
index 20a663f..20a663f 100644
--- a/source/_static/img/upload-button.png
+++ b/docs/source/_static/img/upload-button.png
Binary files differ
diff --git a/source/_static/img/verify-success.png b/docs/source/_static/img/verify-success.png
index 6928674..6928674 100644
--- a/source/_static/img/verify-success.png
+++ b/docs/source/_static/img/verify-success.png
Binary files differ
diff --git a/source/_static/img/verify_button.png b/docs/source/_static/img/verify_button.png
index 37100db..37100db 100644
--- a/source/_static/img/verify_button.png
+++ b/docs/source/_static/img/verify_button.png
Binary files differ
diff --git a/source/_static/img/win7-copy-arm-bin-address.png b/docs/source/_static/img/win7-copy-arm-bin-address.png
index a3886d1..a3886d1 100644
--- a/source/_static/img/win7-copy-arm-bin-address.png
+++ b/docs/source/_static/img/win7-copy-arm-bin-address.png
Binary files differ
diff --git a/source/_static/img/win7-copy-python-address.png b/docs/source/_static/img/win7-copy-python-address.png
index 34d3022..34d3022 100644
--- a/source/_static/img/win7-copy-python-address.png
+++ b/docs/source/_static/img/win7-copy-python-address.png
Binary files differ
diff --git a/source/_static/img/win7-github-open-in-explorer.png b/docs/source/_static/img/win7-github-open-in-explorer.png
index 8320a90..8320a90 100644
--- a/source/_static/img/win7-github-open-in-explorer.png
+++ b/docs/source/_static/img/win7-github-open-in-explorer.png
Binary files differ
diff --git a/source/_static/img/win7-python-arm-bin-path.png b/docs/source/_static/img/win7-python-arm-bin-path.png
index 8dcc8ed..8dcc8ed 100644
--- a/source/_static/img/win7-python-arm-bin-path.png
+++ b/docs/source/_static/img/win7-python-arm-bin-path.png
Binary files differ
diff --git a/source/_static/img/win7-python-path.png b/docs/source/_static/img/win7-python-path.png
index 8898a9e..8898a9e 100644
--- a/source/_static/img/win7-python-path.png
+++ b/docs/source/_static/img/win7-python-path.png
Binary files differ
diff --git a/source/_static/img/win7-python-prompt.png b/docs/source/_static/img/win7-python-prompt.png
index 27ae62a..27ae62a 100644
--- a/source/_static/img/win7-python-prompt.png
+++ b/docs/source/_static/img/win7-python-prompt.png
Binary files differ
diff --git a/source/_static/index-style.css b/docs/source/_static/index-style.css
index d7c42b3..d7c42b3 100644
--- a/source/_static/index-style.css
+++ b/docs/source/_static/index-style.css
diff --git a/source/_static/leaflabs-docs.css b/docs/source/_static/leaflabs-docs.css
index 18f5bcc..18f5bcc 100644
--- a/source/_static/leaflabs-docs.css
+++ b/docs/source/_static/leaflabs-docs.css
diff --git a/source/_templates/.gitignore b/docs/source/_templates/.gitignore
index e69de29..e69de29 100644
--- a/source/_templates/.gitignore
+++ b/docs/source/_templates/.gitignore
diff --git a/source/_templates/indexcontent.html b/docs/source/_templates/indexcontent.html
index a043f8a..a043f8a 100644
--- a/source/_templates/indexcontent.html
+++ b/docs/source/_templates/indexcontent.html
diff --git a/source/_templates/layout.html b/docs/source/_templates/layout.html
index 2fd81ce..2fd81ce 100644
--- a/source/_templates/layout.html
+++ b/docs/source/_templates/layout.html
diff --git a/source/adc.rst b/docs/source/adc.rst
index 937b178..937b178 100644
--- a/source/adc.rst
+++ b/docs/source/adc.rst
diff --git a/source/arduino-cc-attribution.txt b/docs/source/arduino-cc-attribution.txt
index ad1c1e0..ad1c1e0 100644
--- a/source/arduino-cc-attribution.txt
+++ b/docs/source/arduino-cc-attribution.txt
diff --git a/source/arduino-compatibility.rst b/docs/source/arduino-compatibility.rst
index f7d3210..f7d3210 100644
--- a/source/arduino-compatibility.rst
+++ b/docs/source/arduino-compatibility.rst
diff --git a/source/arm-gcc.rst b/docs/source/arm-gcc.rst
index 30667a2..30667a2 100644
--- a/source/arm-gcc.rst
+++ b/docs/source/arm-gcc.rst
diff --git a/source/bootloader.rst b/docs/source/bootloader.rst
index 23b0448..23b0448 100644
--- a/source/bootloader.rst
+++ b/docs/source/bootloader.rst
diff --git a/source/conf.py b/docs/source/conf.py
index f4a9bbb..f4a9bbb 100644
--- a/source/conf.py
+++ b/docs/source/conf.py
diff --git a/source/contents.rst b/docs/source/contents.rst
index 7be7aec..7be7aec 100644
--- a/source/contents.rst
+++ b/docs/source/contents.rst
diff --git a/source/epilog.rst b/docs/source/epilog.rst
index b548001..b548001 100644
--- a/source/epilog.rst
+++ b/docs/source/epilog.rst
diff --git a/source/external-interrupts.rst b/docs/source/external-interrupts.rst
index 209d5af..209d5af 100644
--- a/source/external-interrupts.rst
+++ b/docs/source/external-interrupts.rst
diff --git a/source/faq.rst b/docs/source/faq.rst
index bd155ae..bd155ae 100644
--- a/source/faq.rst
+++ b/docs/source/faq.rst
diff --git a/source/fsmc.rst b/docs/source/fsmc.rst
index c8f0125..c8f0125 100644
--- a/source/fsmc.rst
+++ b/docs/source/fsmc.rst
diff --git a/source/gpio.rst b/docs/source/gpio.rst
index caaae3d..caaae3d 100644
--- a/source/gpio.rst
+++ b/docs/source/gpio.rst
diff --git a/source/hardware/maple-mini.rst b/docs/source/hardware/maple-mini.rst
index c28211d..c28211d 100644
--- a/source/hardware/maple-mini.rst
+++ b/docs/source/hardware/maple-mini.rst
diff --git a/source/hardware/maple-native-beta.rst b/docs/source/hardware/maple-native-beta.rst
index bdfd216..bdfd216 100644
--- a/source/hardware/maple-native-beta.rst
+++ b/docs/source/hardware/maple-native-beta.rst
diff --git a/source/hardware/maple-native.rst b/docs/source/hardware/maple-native.rst
index 79115fc..79115fc 100644
--- a/source/hardware/maple-native.rst
+++ b/docs/source/hardware/maple-native.rst
diff --git a/source/hardware/maple-ret6.rst b/docs/source/hardware/maple-ret6.rst
index 3d2d037..3d2d037 100644
--- a/source/hardware/maple-ret6.rst
+++ b/docs/source/hardware/maple-ret6.rst
diff --git a/source/hardware/maple.rst b/docs/source/hardware/maple.rst
index b187115..b187115 100644
--- a/source/hardware/maple.rst
+++ b/docs/source/hardware/maple.rst
diff --git a/source/i2c.rst b/docs/source/i2c.rst
index a206ed4..a206ed4 100644
--- a/source/i2c.rst
+++ b/docs/source/i2c.rst
diff --git a/source/ide.rst b/docs/source/ide.rst
index e6d49fc..e6d49fc 100644
--- a/source/ide.rst
+++ b/docs/source/ide.rst
diff --git a/source/jtag.rst b/docs/source/jtag.rst
index caba223..caba223 100644
--- a/source/jtag.rst
+++ b/docs/source/jtag.rst
diff --git a/source/lang/api/abs.rst b/docs/source/lang/api/abs.rst
index d9f1ca3..d9f1ca3 100644
--- a/source/lang/api/abs.rst
+++ b/docs/source/lang/api/abs.rst
diff --git a/source/lang/api/analogread.rst b/docs/source/lang/api/analogread.rst
index 6665a94..6665a94 100644
--- a/source/lang/api/analogread.rst
+++ b/docs/source/lang/api/analogread.rst
diff --git a/source/lang/api/analogwrite.rst b/docs/source/lang/api/analogwrite.rst
index 0169976..0169976 100644
--- a/source/lang/api/analogwrite.rst
+++ b/docs/source/lang/api/analogwrite.rst
diff --git a/source/lang/api/assert.rst b/docs/source/lang/api/assert.rst
index 76330b6..76330b6 100644
--- a/source/lang/api/assert.rst
+++ b/docs/source/lang/api/assert.rst
diff --git a/source/lang/api/attachinterrupt.rst b/docs/source/lang/api/attachinterrupt.rst
index 58e4764..58e4764 100644
--- a/source/lang/api/attachinterrupt.rst
+++ b/docs/source/lang/api/attachinterrupt.rst
diff --git a/source/lang/api/bit.rst b/docs/source/lang/api/bit.rst
index 3df042c..3df042c 100644
--- a/source/lang/api/bit.rst
+++ b/docs/source/lang/api/bit.rst
diff --git a/source/lang/api/bitclear.rst b/docs/source/lang/api/bitclear.rst
index f487059..f487059 100644
--- a/source/lang/api/bitclear.rst
+++ b/docs/source/lang/api/bitclear.rst
diff --git a/source/lang/api/bitread.rst b/docs/source/lang/api/bitread.rst
index fd9fbbe..fd9fbbe 100644
--- a/source/lang/api/bitread.rst
+++ b/docs/source/lang/api/bitread.rst
diff --git a/source/lang/api/bitset.rst b/docs/source/lang/api/bitset.rst
index 83ab5f8..83ab5f8 100644
--- a/source/lang/api/bitset.rst
+++ b/docs/source/lang/api/bitset.rst
diff --git a/source/lang/api/bitwrite.rst b/docs/source/lang/api/bitwrite.rst
index 6106545..6106545 100644
--- a/source/lang/api/bitwrite.rst
+++ b/docs/source/lang/api/bitwrite.rst
diff --git a/source/lang/api/board-values.rst b/docs/source/lang/api/board-values.rst
index d944c8d..d944c8d 100644
--- a/source/lang/api/board-values.rst
+++ b/docs/source/lang/api/board-values.rst
diff --git a/source/lang/api/boardusespin.rst b/docs/source/lang/api/boardusespin.rst
index 126c4a0..126c4a0 100644
--- a/source/lang/api/boardusespin.rst
+++ b/docs/source/lang/api/boardusespin.rst
diff --git a/source/lang/api/constants.rst b/docs/source/lang/api/constants.rst
index 6f69dfe..6f69dfe 100644
--- a/source/lang/api/constants.rst
+++ b/docs/source/lang/api/constants.rst
diff --git a/source/lang/api/constrain.rst b/docs/source/lang/api/constrain.rst
index 28af1e3..28af1e3 100644
--- a/source/lang/api/constrain.rst
+++ b/docs/source/lang/api/constrain.rst
diff --git a/source/lang/api/cos.rst b/docs/source/lang/api/cos.rst
index c340f09..c340f09 100644
--- a/source/lang/api/cos.rst
+++ b/docs/source/lang/api/cos.rst
diff --git a/source/lang/api/delay.rst b/docs/source/lang/api/delay.rst
index 30bd436..30bd436 100644
--- a/source/lang/api/delay.rst
+++ b/docs/source/lang/api/delay.rst
diff --git a/source/lang/api/delaymicroseconds.rst b/docs/source/lang/api/delaymicroseconds.rst
index 7078660..7078660 100644
--- a/source/lang/api/delaymicroseconds.rst
+++ b/docs/source/lang/api/delaymicroseconds.rst
diff --git a/source/lang/api/detachinterrupt.rst b/docs/source/lang/api/detachinterrupt.rst
index 6eb8e53..6eb8e53 100644
--- a/source/lang/api/detachinterrupt.rst
+++ b/docs/source/lang/api/detachinterrupt.rst
diff --git a/source/lang/api/digitalread.rst b/docs/source/lang/api/digitalread.rst
index 03ccd7f..03ccd7f 100644
--- a/source/lang/api/digitalread.rst
+++ b/docs/source/lang/api/digitalread.rst
diff --git a/source/lang/api/digitalwrite.rst b/docs/source/lang/api/digitalwrite.rst
index bae8db9..bae8db9 100644
--- a/source/lang/api/digitalwrite.rst
+++ b/docs/source/lang/api/digitalwrite.rst
diff --git a/source/lang/api/disabledebugports.rst b/docs/source/lang/api/disabledebugports.rst
index 283cdbf..283cdbf 100644
--- a/source/lang/api/disabledebugports.rst
+++ b/docs/source/lang/api/disabledebugports.rst
diff --git a/source/lang/api/enabledebugports.rst b/docs/source/lang/api/enabledebugports.rst
index bee2b0a..bee2b0a 100644
--- a/source/lang/api/enabledebugports.rst
+++ b/docs/source/lang/api/enabledebugports.rst
diff --git a/source/lang/api/hardwarespi.rst b/docs/source/lang/api/hardwarespi.rst
index a44a65f..a44a65f 100644
--- a/source/lang/api/hardwarespi.rst
+++ b/docs/source/lang/api/hardwarespi.rst
diff --git a/source/lang/api/hardwaretimer.rst b/docs/source/lang/api/hardwaretimer.rst
index b919e52..b919e52 100644
--- a/source/lang/api/hardwaretimer.rst
+++ b/docs/source/lang/api/hardwaretimer.rst
diff --git a/source/lang/api/highbyte.rst b/docs/source/lang/api/highbyte.rst
index 4cb6f9b..4cb6f9b 100644
--- a/source/lang/api/highbyte.rst
+++ b/docs/source/lang/api/highbyte.rst
diff --git a/source/lang/api/interrupts.rst b/docs/source/lang/api/interrupts.rst
index 58fd2cc..58fd2cc 100644
--- a/source/lang/api/interrupts.rst
+++ b/docs/source/lang/api/interrupts.rst
diff --git a/source/lang/api/isbuttonpressed.rst b/docs/source/lang/api/isbuttonpressed.rst
index 8c350b9..8c350b9 100644
--- a/source/lang/api/isbuttonpressed.rst
+++ b/docs/source/lang/api/isbuttonpressed.rst
diff --git a/source/lang/api/loop.rst b/docs/source/lang/api/loop.rst
index c2a5097..c2a5097 100644
--- a/source/lang/api/loop.rst
+++ b/docs/source/lang/api/loop.rst
diff --git a/source/lang/api/lowbyte.rst b/docs/source/lang/api/lowbyte.rst
index c513711..c513711 100644
--- a/source/lang/api/lowbyte.rst
+++ b/docs/source/lang/api/lowbyte.rst
diff --git a/source/lang/api/map.rst b/docs/source/lang/api/map.rst
index 69661a0..69661a0 100644
--- a/source/lang/api/map.rst
+++ b/docs/source/lang/api/map.rst
diff --git a/source/lang/api/max.rst b/docs/source/lang/api/max.rst
index d356f08..d356f08 100644
--- a/source/lang/api/max.rst
+++ b/docs/source/lang/api/max.rst
diff --git a/source/lang/api/micros.rst b/docs/source/lang/api/micros.rst
index de85303..de85303 100644
--- a/source/lang/api/micros.rst
+++ b/docs/source/lang/api/micros.rst
diff --git a/source/lang/api/millis.rst b/docs/source/lang/api/millis.rst
index b6fbf55..b6fbf55 100644
--- a/source/lang/api/millis.rst
+++ b/docs/source/lang/api/millis.rst
diff --git a/source/lang/api/min.rst b/docs/source/lang/api/min.rst
index 3307105..3307105 100644
--- a/source/lang/api/min.rst
+++ b/docs/source/lang/api/min.rst
diff --git a/source/lang/api/nointerrupts.rst b/docs/source/lang/api/nointerrupts.rst
index 68f0498..68f0498 100644
--- a/source/lang/api/nointerrupts.rst
+++ b/docs/source/lang/api/nointerrupts.rst
diff --git a/source/lang/api/pinmode.rst b/docs/source/lang/api/pinmode.rst
index 643e26e..643e26e 100644
--- a/source/lang/api/pinmode.rst
+++ b/docs/source/lang/api/pinmode.rst
diff --git a/source/lang/api/pow.rst b/docs/source/lang/api/pow.rst
index 219a866..219a866 100644
--- a/source/lang/api/pow.rst
+++ b/docs/source/lang/api/pow.rst
diff --git a/source/lang/api/pwmwrite.rst b/docs/source/lang/api/pwmwrite.rst
index 5cc112e..5cc112e 100644
--- a/source/lang/api/pwmwrite.rst
+++ b/docs/source/lang/api/pwmwrite.rst
diff --git a/source/lang/api/random.rst b/docs/source/lang/api/random.rst
index 9875ee6..9875ee6 100644
--- a/source/lang/api/random.rst
+++ b/docs/source/lang/api/random.rst
diff --git a/source/lang/api/randomseed.rst b/docs/source/lang/api/randomseed.rst
index ca7b75f..ca7b75f 100644
--- a/source/lang/api/randomseed.rst
+++ b/docs/source/lang/api/randomseed.rst
diff --git a/source/lang/api/serial.rst b/docs/source/lang/api/serial.rst
index e287015..e287015 100644
--- a/source/lang/api/serial.rst
+++ b/docs/source/lang/api/serial.rst
diff --git a/source/lang/api/serialusb.rst b/docs/source/lang/api/serialusb.rst
index ed466f2..ed466f2 100644
--- a/source/lang/api/serialusb.rst
+++ b/docs/source/lang/api/serialusb.rst
diff --git a/source/lang/api/setup.rst b/docs/source/lang/api/setup.rst
index 1e8e3b8..1e8e3b8 100644
--- a/source/lang/api/setup.rst
+++ b/docs/source/lang/api/setup.rst
diff --git a/source/lang/api/shiftout.rst b/docs/source/lang/api/shiftout.rst
index 1d9ba12..1d9ba12 100644
--- a/source/lang/api/shiftout.rst
+++ b/docs/source/lang/api/shiftout.rst
diff --git a/source/lang/api/sin.rst b/docs/source/lang/api/sin.rst
index 3e28c0b..3e28c0b 100644
--- a/source/lang/api/sin.rst
+++ b/docs/source/lang/api/sin.rst
diff --git a/source/lang/api/sq.rst b/docs/source/lang/api/sq.rst
index 96724d3..96724d3 100644
--- a/source/lang/api/sq.rst
+++ b/docs/source/lang/api/sq.rst
diff --git a/source/lang/api/tan.rst b/docs/source/lang/api/tan.rst
index b1aed31..b1aed31 100644
--- a/source/lang/api/tan.rst
+++ b/docs/source/lang/api/tan.rst
diff --git a/source/lang/api/toggleled.rst b/docs/source/lang/api/toggleled.rst
index cad347f..cad347f 100644
--- a/source/lang/api/toggleled.rst
+++ b/docs/source/lang/api/toggleled.rst
diff --git a/source/lang/api/togglepin.rst b/docs/source/lang/api/togglepin.rst
index 290718d..290718d 100644
--- a/source/lang/api/togglepin.rst
+++ b/docs/source/lang/api/togglepin.rst
diff --git a/source/lang/api/volatile.rst b/docs/source/lang/api/volatile.rst
index 1b72897..1b72897 100644
--- a/source/lang/api/volatile.rst
+++ b/docs/source/lang/api/volatile.rst
diff --git a/source/lang/api/waitforbuttonpress.rst b/docs/source/lang/api/waitforbuttonpress.rst
index 0e0fbaf..0e0fbaf 100644
--- a/source/lang/api/waitforbuttonpress.rst
+++ b/docs/source/lang/api/waitforbuttonpress.rst
diff --git a/source/lang/cc-attribution.txt b/docs/source/lang/cc-attribution.txt
index 11302b2..11302b2 100644
--- a/source/lang/cc-attribution.txt
+++ b/docs/source/lang/cc-attribution.txt
diff --git a/source/lang/cpp/arithmetic.rst b/docs/source/lang/cpp/arithmetic.rst
index cef3954..cef3954 100644
--- a/source/lang/cpp/arithmetic.rst
+++ b/docs/source/lang/cpp/arithmetic.rst
diff --git a/source/lang/cpp/array.rst b/docs/source/lang/cpp/array.rst
index 39d4d91..39d4d91 100644
--- a/source/lang/cpp/array.rst
+++ b/docs/source/lang/cpp/array.rst
diff --git a/source/lang/cpp/assignment.rst b/docs/source/lang/cpp/assignment.rst
index 6379298..6379298 100644
--- a/source/lang/cpp/assignment.rst
+++ b/docs/source/lang/cpp/assignment.rst
diff --git a/source/lang/cpp/bitshift.rst b/docs/source/lang/cpp/bitshift.rst
index 47413f2..47413f2 100644
--- a/source/lang/cpp/bitshift.rst
+++ b/docs/source/lang/cpp/bitshift.rst
diff --git a/source/lang/cpp/bitwisemath.rst b/docs/source/lang/cpp/bitwisemath.rst
index cfe34f2..cfe34f2 100644
--- a/source/lang/cpp/bitwisemath.rst
+++ b/docs/source/lang/cpp/bitwisemath.rst
diff --git a/source/lang/cpp/boolean.rst b/docs/source/lang/cpp/boolean.rst
index f09345e..f09345e 100644
--- a/source/lang/cpp/boolean.rst
+++ b/docs/source/lang/cpp/boolean.rst
diff --git a/source/lang/cpp/booleanvariables.rst b/docs/source/lang/cpp/booleanvariables.rst
index e032c74..e032c74 100644
--- a/source/lang/cpp/booleanvariables.rst
+++ b/docs/source/lang/cpp/booleanvariables.rst
diff --git a/source/lang/cpp/break.rst b/docs/source/lang/cpp/break.rst
index f367b99..f367b99 100644
--- a/source/lang/cpp/break.rst
+++ b/docs/source/lang/cpp/break.rst
diff --git a/source/lang/cpp/built-in-types.rst b/docs/source/lang/cpp/built-in-types.rst
index f14dce5..f14dce5 100644
--- a/source/lang/cpp/built-in-types.rst
+++ b/docs/source/lang/cpp/built-in-types.rst
diff --git a/source/lang/cpp/byte.rst b/docs/source/lang/cpp/byte.rst
index 4634594..4634594 100644
--- a/source/lang/cpp/byte.rst
+++ b/docs/source/lang/cpp/byte.rst
diff --git a/source/lang/cpp/bytecast.rst b/docs/source/lang/cpp/bytecast.rst
index 24c3b9e..24c3b9e 100644
--- a/source/lang/cpp/bytecast.rst
+++ b/docs/source/lang/cpp/bytecast.rst
diff --git a/source/lang/cpp/cc-attribution.txt b/docs/source/lang/cpp/cc-attribution.txt
index e100140..e100140 100644
--- a/source/lang/cpp/cc-attribution.txt
+++ b/docs/source/lang/cpp/cc-attribution.txt
diff --git a/source/lang/cpp/char.rst b/docs/source/lang/cpp/char.rst
index 686c0d1..686c0d1 100644
--- a/source/lang/cpp/char.rst
+++ b/docs/source/lang/cpp/char.rst
diff --git a/source/lang/cpp/charcast.rst b/docs/source/lang/cpp/charcast.rst
index 640ad85..640ad85 100644
--- a/source/lang/cpp/charcast.rst
+++ b/docs/source/lang/cpp/charcast.rst
diff --git a/source/lang/cpp/comments.rst b/docs/source/lang/cpp/comments.rst
index 1428dc3..1428dc3 100644
--- a/source/lang/cpp/comments.rst
+++ b/docs/source/lang/cpp/comments.rst
diff --git a/source/lang/cpp/comparison.rst b/docs/source/lang/cpp/comparison.rst
index 9cd0a9f..9cd0a9f 100644
--- a/source/lang/cpp/comparison.rst
+++ b/docs/source/lang/cpp/comparison.rst
diff --git a/source/lang/cpp/compoundarithmetic.rst b/docs/source/lang/cpp/compoundarithmetic.rst
index d70a43c..d70a43c 100644
--- a/source/lang/cpp/compoundarithmetic.rst
+++ b/docs/source/lang/cpp/compoundarithmetic.rst
diff --git a/source/lang/cpp/compoundbitwise.rst b/docs/source/lang/cpp/compoundbitwise.rst
index 4efe5df..4efe5df 100644
--- a/source/lang/cpp/compoundbitwise.rst
+++ b/docs/source/lang/cpp/compoundbitwise.rst
diff --git a/source/lang/cpp/const.rst b/docs/source/lang/cpp/const.rst
index ad0c580..ad0c580 100644
--- a/source/lang/cpp/const.rst
+++ b/docs/source/lang/cpp/const.rst
diff --git a/source/lang/cpp/continue.rst b/docs/source/lang/cpp/continue.rst
index 2a694f6..2a694f6 100644
--- a/source/lang/cpp/continue.rst
+++ b/docs/source/lang/cpp/continue.rst
diff --git a/source/lang/cpp/curly-braces.rst b/docs/source/lang/cpp/curly-braces.rst
index df2fe2a..df2fe2a 100644
--- a/source/lang/cpp/curly-braces.rst
+++ b/docs/source/lang/cpp/curly-braces.rst
diff --git a/source/lang/cpp/define.rst b/docs/source/lang/cpp/define.rst
index b22085f..b22085f 100644
--- a/source/lang/cpp/define.rst
+++ b/docs/source/lang/cpp/define.rst
diff --git a/source/lang/cpp/double.rst b/docs/source/lang/cpp/double.rst
index 59422eb..59422eb 100644
--- a/source/lang/cpp/double.rst
+++ b/docs/source/lang/cpp/double.rst
diff --git a/source/lang/cpp/doublecast.rst b/docs/source/lang/cpp/doublecast.rst
index d3f32ce..d3f32ce 100644
--- a/source/lang/cpp/doublecast.rst
+++ b/docs/source/lang/cpp/doublecast.rst
diff --git a/source/lang/cpp/dowhile.rst b/docs/source/lang/cpp/dowhile.rst
index d229122..d229122 100644
--- a/source/lang/cpp/dowhile.rst
+++ b/docs/source/lang/cpp/dowhile.rst
diff --git a/source/lang/cpp/enum.rst b/docs/source/lang/cpp/enum.rst
index b6409eb..b6409eb 100644
--- a/source/lang/cpp/enum.rst
+++ b/docs/source/lang/cpp/enum.rst
diff --git a/source/lang/cpp/float.rst b/docs/source/lang/cpp/float.rst
index 5195fac..5195fac 100644
--- a/source/lang/cpp/float.rst
+++ b/docs/source/lang/cpp/float.rst
diff --git a/source/lang/cpp/floatcast.rst b/docs/source/lang/cpp/floatcast.rst
index af92543..af92543 100644
--- a/source/lang/cpp/floatcast.rst
+++ b/docs/source/lang/cpp/floatcast.rst
diff --git a/source/lang/cpp/for.rst b/docs/source/lang/cpp/for.rst
index 78ea562..78ea562 100644
--- a/source/lang/cpp/for.rst
+++ b/docs/source/lang/cpp/for.rst
diff --git a/source/lang/cpp/goto.rst b/docs/source/lang/cpp/goto.rst
index 2c0b3b0..2c0b3b0 100644
--- a/source/lang/cpp/goto.rst
+++ b/docs/source/lang/cpp/goto.rst
diff --git a/source/lang/cpp/if.rst b/docs/source/lang/cpp/if.rst
index f248b05..f248b05 100644
--- a/source/lang/cpp/if.rst
+++ b/docs/source/lang/cpp/if.rst
diff --git a/source/lang/cpp/include.rst b/docs/source/lang/cpp/include.rst
index 163509d..163509d 100644
--- a/source/lang/cpp/include.rst
+++ b/docs/source/lang/cpp/include.rst
diff --git a/source/lang/cpp/increment.rst b/docs/source/lang/cpp/increment.rst
index c423d1a..c423d1a 100644
--- a/source/lang/cpp/increment.rst
+++ b/docs/source/lang/cpp/increment.rst
diff --git a/source/lang/cpp/int.rst b/docs/source/lang/cpp/int.rst
index fa63946..fa63946 100644
--- a/source/lang/cpp/int.rst
+++ b/docs/source/lang/cpp/int.rst
diff --git a/source/lang/cpp/intcast.rst b/docs/source/lang/cpp/intcast.rst
index da838c7..da838c7 100644
--- a/source/lang/cpp/intcast.rst
+++ b/docs/source/lang/cpp/intcast.rst
diff --git a/source/lang/cpp/keywords.rst b/docs/source/lang/cpp/keywords.rst
index f21cd0d..f21cd0d 100644
--- a/source/lang/cpp/keywords.rst
+++ b/docs/source/lang/cpp/keywords.rst
diff --git a/source/lang/cpp/longcast.rst b/docs/source/lang/cpp/longcast.rst
index 493ad67..493ad67 100644
--- a/source/lang/cpp/longcast.rst
+++ b/docs/source/lang/cpp/longcast.rst
diff --git a/source/lang/cpp/longlong.rst b/docs/source/lang/cpp/longlong.rst
index d942cb4..d942cb4 100644
--- a/source/lang/cpp/longlong.rst
+++ b/docs/source/lang/cpp/longlong.rst
diff --git a/source/lang/cpp/modulo.rst b/docs/source/lang/cpp/modulo.rst
index 013d07e..013d07e 100644
--- a/source/lang/cpp/modulo.rst
+++ b/docs/source/lang/cpp/modulo.rst
diff --git a/source/lang/cpp/pointer.rst b/docs/source/lang/cpp/pointer.rst
index ff4ec32..ff4ec32 100644
--- a/source/lang/cpp/pointer.rst
+++ b/docs/source/lang/cpp/pointer.rst
diff --git a/source/lang/cpp/return.rst b/docs/source/lang/cpp/return.rst
index d9aecbe..d9aecbe 100644
--- a/source/lang/cpp/return.rst
+++ b/docs/source/lang/cpp/return.rst
diff --git a/source/lang/cpp/scope.rst b/docs/source/lang/cpp/scope.rst
index a270428..a270428 100644
--- a/source/lang/cpp/scope.rst
+++ b/docs/source/lang/cpp/scope.rst
diff --git a/source/lang/cpp/semicolon.rst b/docs/source/lang/cpp/semicolon.rst
index 05e6218..05e6218 100644
--- a/source/lang/cpp/semicolon.rst
+++ b/docs/source/lang/cpp/semicolon.rst
diff --git a/source/lang/cpp/sizeof.rst b/docs/source/lang/cpp/sizeof.rst
index ec2dea6..ec2dea6 100644
--- a/source/lang/cpp/sizeof.rst
+++ b/docs/source/lang/cpp/sizeof.rst
diff --git a/source/lang/cpp/sqrt.rst b/docs/source/lang/cpp/sqrt.rst
index fbabf82..fbabf82 100644
--- a/source/lang/cpp/sqrt.rst
+++ b/docs/source/lang/cpp/sqrt.rst
diff --git a/source/lang/cpp/static.rst b/docs/source/lang/cpp/static.rst
index 8c52ba0..8c52ba0 100644
--- a/source/lang/cpp/static.rst
+++ b/docs/source/lang/cpp/static.rst
diff --git a/source/lang/cpp/string.rst b/docs/source/lang/cpp/string.rst
index 3497484..3497484 100644
--- a/source/lang/cpp/string.rst
+++ b/docs/source/lang/cpp/string.rst
diff --git a/source/lang/cpp/switchcase.rst b/docs/source/lang/cpp/switchcase.rst
index e31ccf3..e31ccf3 100644
--- a/source/lang/cpp/switchcase.rst
+++ b/docs/source/lang/cpp/switchcase.rst
diff --git a/source/lang/cpp/unsignedchar.rst b/docs/source/lang/cpp/unsignedchar.rst
index 45fedeb..45fedeb 100644
--- a/source/lang/cpp/unsignedchar.rst
+++ b/docs/source/lang/cpp/unsignedchar.rst
diff --git a/source/lang/cpp/unsignedint.rst b/docs/source/lang/cpp/unsignedint.rst
index f8ea473..f8ea473 100644
--- a/source/lang/cpp/unsignedint.rst
+++ b/docs/source/lang/cpp/unsignedint.rst
diff --git a/source/lang/cpp/unsignedlonglong.rst b/docs/source/lang/cpp/unsignedlonglong.rst
index a1143f0..a1143f0 100644
--- a/source/lang/cpp/unsignedlonglong.rst
+++ b/docs/source/lang/cpp/unsignedlonglong.rst
diff --git a/source/lang/cpp/variables.rst b/docs/source/lang/cpp/variables.rst
index 9ffdd1d..9ffdd1d 100644
--- a/source/lang/cpp/variables.rst
+++ b/docs/source/lang/cpp/variables.rst
diff --git a/source/lang/cpp/void.rst b/docs/source/lang/cpp/void.rst
index 7af0acd..7af0acd 100644
--- a/source/lang/cpp/void.rst
+++ b/docs/source/lang/cpp/void.rst
diff --git a/source/lang/cpp/while.rst b/docs/source/lang/cpp/while.rst
index e66e0aa..e66e0aa 100644
--- a/source/lang/cpp/while.rst
+++ b/docs/source/lang/cpp/while.rst
diff --git a/source/lang/unimplemented/notone.rst b/docs/source/lang/unimplemented/notone.rst
index 8af878b..8af878b 100644
--- a/source/lang/unimplemented/notone.rst
+++ b/docs/source/lang/unimplemented/notone.rst
diff --git a/source/lang/unimplemented/pulsein.rst b/docs/source/lang/unimplemented/pulsein.rst
index 2b52428..2b52428 100644
--- a/source/lang/unimplemented/pulsein.rst
+++ b/docs/source/lang/unimplemented/pulsein.rst
diff --git a/source/lang/unimplemented/stringclass.rst b/docs/source/lang/unimplemented/stringclass.rst
index b893e83..b893e83 100644
--- a/source/lang/unimplemented/stringclass.rst
+++ b/docs/source/lang/unimplemented/stringclass.rst
diff --git a/source/lang/unimplemented/stringobject.rst b/docs/source/lang/unimplemented/stringobject.rst
index e47ed7e..e47ed7e 100644
--- a/source/lang/unimplemented/stringobject.rst
+++ b/docs/source/lang/unimplemented/stringobject.rst
diff --git a/source/lang/unimplemented/tone.rst b/docs/source/lang/unimplemented/tone.rst
index 13d581e..13d581e 100644
--- a/source/lang/unimplemented/tone.rst
+++ b/docs/source/lang/unimplemented/tone.rst
diff --git a/source/language-index.rst b/docs/source/language-index.rst
index 5e4c609..5e4c609 100644
--- a/source/language-index.rst
+++ b/docs/source/language-index.rst
diff --git a/source/language.rst b/docs/source/language.rst
index a24bb5f..a24bb5f 100644
--- a/source/language.rst
+++ b/docs/source/language.rst
diff --git a/source/libmaple.rst b/docs/source/libmaple.rst
index 458241e..458241e 100644
--- a/source/libmaple.rst
+++ b/docs/source/libmaple.rst
diff --git a/source/libmaple/api/adc.rst b/docs/source/libmaple/api/adc.rst
index 2f06926..2f06926 100644
--- a/source/libmaple/api/adc.rst
+++ b/docs/source/libmaple/api/adc.rst
diff --git a/source/libmaple/api/bitband.rst b/docs/source/libmaple/api/bitband.rst
index 768f678..768f678 100644
--- a/source/libmaple/api/bitband.rst
+++ b/docs/source/libmaple/api/bitband.rst
diff --git a/source/libmaple/api/bkp.rst b/docs/source/libmaple/api/bkp.rst
index 4f0115b..4f0115b 100644
--- a/source/libmaple/api/bkp.rst
+++ b/docs/source/libmaple/api/bkp.rst
diff --git a/source/libmaple/api/dac.rst b/docs/source/libmaple/api/dac.rst
index 55c8faf..55c8faf 100644
--- a/source/libmaple/api/dac.rst
+++ b/docs/source/libmaple/api/dac.rst
diff --git a/source/libmaple/api/delay.rst b/docs/source/libmaple/api/delay.rst
index d11496b..d11496b 100644
--- a/source/libmaple/api/delay.rst
+++ b/docs/source/libmaple/api/delay.rst
diff --git a/source/libmaple/api/dma.rst b/docs/source/libmaple/api/dma.rst
index a9893e2..a9893e2 100644
--- a/source/libmaple/api/dma.rst
+++ b/docs/source/libmaple/api/dma.rst
diff --git a/source/libmaple/api/exti.rst b/docs/source/libmaple/api/exti.rst
index 1038fbf..1038fbf 100644
--- a/source/libmaple/api/exti.rst
+++ b/docs/source/libmaple/api/exti.rst
diff --git a/source/libmaple/api/flash.rst b/docs/source/libmaple/api/flash.rst
index 52ff4d2..52ff4d2 100644
--- a/source/libmaple/api/flash.rst
+++ b/docs/source/libmaple/api/flash.rst
diff --git a/source/libmaple/api/fsmc.rst b/docs/source/libmaple/api/fsmc.rst
index e2bf87a..e2bf87a 100644
--- a/source/libmaple/api/fsmc.rst
+++ b/docs/source/libmaple/api/fsmc.rst
diff --git a/source/libmaple/api/gpio.rst b/docs/source/libmaple/api/gpio.rst
index faf0ad2..faf0ad2 100644
--- a/source/libmaple/api/gpio.rst
+++ b/docs/source/libmaple/api/gpio.rst
diff --git a/source/libmaple/api/i2c.rst b/docs/source/libmaple/api/i2c.rst
index ff380cc..ff380cc 100644
--- a/source/libmaple/api/i2c.rst
+++ b/docs/source/libmaple/api/i2c.rst
diff --git a/source/libmaple/api/iwdg.rst b/docs/source/libmaple/api/iwdg.rst
index 65f9f7b..65f9f7b 100644
--- a/source/libmaple/api/iwdg.rst
+++ b/docs/source/libmaple/api/iwdg.rst
diff --git a/source/libmaple/api/libmaple.rst b/docs/source/libmaple/api/libmaple.rst
index 7deb659..7deb659 100644
--- a/source/libmaple/api/libmaple.rst
+++ b/docs/source/libmaple/api/libmaple.rst
diff --git a/source/libmaple/api/libmaple_types.rst b/docs/source/libmaple/api/libmaple_types.rst
index 5ca446e..5ca446e 100644
--- a/source/libmaple/api/libmaple_types.rst
+++ b/docs/source/libmaple/api/libmaple_types.rst
diff --git a/source/libmaple/api/nvic.rst b/docs/source/libmaple/api/nvic.rst
index 505e36e..505e36e 100644
--- a/source/libmaple/api/nvic.rst
+++ b/docs/source/libmaple/api/nvic.rst
diff --git a/source/libmaple/api/pwr.rst b/docs/source/libmaple/api/pwr.rst
index 6a2cf22..6a2cf22 100644
--- a/source/libmaple/api/pwr.rst
+++ b/docs/source/libmaple/api/pwr.rst
diff --git a/source/libmaple/api/rcc-reg-bits.txt b/docs/source/libmaple/api/rcc-reg-bits.txt
index 6b1133d..6b1133d 100644
--- a/source/libmaple/api/rcc-reg-bits.txt
+++ b/docs/source/libmaple/api/rcc-reg-bits.txt
diff --git a/source/libmaple/api/rcc.rst b/docs/source/libmaple/api/rcc.rst
index ce58ec8..ce58ec8 100644
--- a/source/libmaple/api/rcc.rst
+++ b/docs/source/libmaple/api/rcc.rst
diff --git a/source/libmaple/api/ring_buffer.rst b/docs/source/libmaple/api/ring_buffer.rst
index ef082dd..ef082dd 100644
--- a/source/libmaple/api/ring_buffer.rst
+++ b/docs/source/libmaple/api/ring_buffer.rst
diff --git a/source/libmaple/api/scb.rst b/docs/source/libmaple/api/scb.rst
index 96d464f..96d464f 100644
--- a/source/libmaple/api/scb.rst
+++ b/docs/source/libmaple/api/scb.rst
diff --git a/source/libmaple/api/spi.rst b/docs/source/libmaple/api/spi.rst
index e72696b..e72696b 100644
--- a/source/libmaple/api/spi.rst
+++ b/docs/source/libmaple/api/spi.rst
diff --git a/source/libmaple/api/stm32.rst b/docs/source/libmaple/api/stm32.rst
index 335bda4..335bda4 100644
--- a/source/libmaple/api/stm32.rst
+++ b/docs/source/libmaple/api/stm32.rst
diff --git a/source/libmaple/api/systick.rst b/docs/source/libmaple/api/systick.rst
index 45b6d63..45b6d63 100644
--- a/source/libmaple/api/systick.rst
+++ b/docs/source/libmaple/api/systick.rst
diff --git a/source/libmaple/api/timer.rst b/docs/source/libmaple/api/timer.rst
index f315cb0..f315cb0 100644
--- a/source/libmaple/api/timer.rst
+++ b/docs/source/libmaple/api/timer.rst
diff --git a/source/libmaple/api/usart.rst b/docs/source/libmaple/api/usart.rst
index 68f2c37..68f2c37 100644
--- a/source/libmaple/api/usart.rst
+++ b/docs/source/libmaple/api/usart.rst
diff --git a/source/libmaple/api/util.rst b/docs/source/libmaple/api/util.rst
index 54377c0..54377c0 100644
--- a/source/libmaple/api/util.rst
+++ b/docs/source/libmaple/api/util.rst
diff --git a/source/libmaple/apis.rst b/docs/source/libmaple/apis.rst
index 31f4902..31f4902 100644
--- a/source/libmaple/apis.rst
+++ b/docs/source/libmaple/apis.rst
diff --git a/source/libmaple/coding-standard.rst b/docs/source/libmaple/coding-standard.rst
index 9ed56cc..9ed56cc 100644
--- a/source/libmaple/coding-standard.rst
+++ b/docs/source/libmaple/coding-standard.rst
diff --git a/source/libmaple/contributing.rst b/docs/source/libmaple/contributing.rst
index 25c6c17..25c6c17 100644
--- a/source/libmaple/contributing.rst
+++ b/docs/source/libmaple/contributing.rst
diff --git a/source/libmaple/overview.rst b/docs/source/libmaple/overview.rst
index 006f1d8..006f1d8 100644
--- a/source/libmaple/overview.rst
+++ b/docs/source/libmaple/overview.rst
diff --git a/source/libraries.rst b/docs/source/libraries.rst
index 1ae0e87..1ae0e87 100644
--- a/source/libraries.rst
+++ b/docs/source/libraries.rst
diff --git a/source/libs/servo.rst b/docs/source/libs/servo.rst
index 80288c6..80288c6 100644
--- a/source/libs/servo.rst
+++ b/docs/source/libs/servo.rst
diff --git a/source/libs/wire.rst b/docs/source/libs/wire.rst
index 2c5bed9..2c5bed9 100644
--- a/source/libs/wire.rst
+++ b/docs/source/libs/wire.rst
diff --git a/source/maple-ide-install.rst b/docs/source/maple-ide-install.rst
index 7e9bfa2..7e9bfa2 100644
--- a/source/maple-ide-install.rst
+++ b/docs/source/maple-ide-install.rst
diff --git a/source/maple-quickstart.rst b/docs/source/maple-quickstart.rst
index a4bc55a..a4bc55a 100644
--- a/source/maple-quickstart.rst
+++ b/docs/source/maple-quickstart.rst
diff --git a/source/prolog.rst b/docs/source/prolog.rst
index 8606555..8606555 100644
--- a/source/prolog.rst
+++ b/docs/source/prolog.rst
diff --git a/source/pwm.rst b/docs/source/pwm.rst
index 421229d..421229d 100644
--- a/source/pwm.rst
+++ b/docs/source/pwm.rst
diff --git a/source/spi.rst b/docs/source/spi.rst
index 13c4c59..13c4c59 100644
--- a/source/spi.rst
+++ b/docs/source/spi.rst
diff --git a/source/stm32.rst b/docs/source/stm32.rst
index d918655..d918655 100644
--- a/source/stm32.rst
+++ b/docs/source/stm32.rst
diff --git a/source/systick.rst b/docs/source/systick.rst
index afc8d09..afc8d09 100644
--- a/source/systick.rst
+++ b/docs/source/systick.rst
diff --git a/source/timers.rst b/docs/source/timers.rst
index 0fa0976..0fa0976 100644
--- a/source/timers.rst
+++ b/docs/source/timers.rst
diff --git a/source/troubleshooting.rst b/docs/source/troubleshooting.rst
index 4d7cbb0..4d7cbb0 100644
--- a/source/troubleshooting.rst
+++ b/docs/source/troubleshooting.rst
diff --git a/source/unix-toolchain-linux-setup.rst b/docs/source/unix-toolchain-linux-setup.rst
index c1333e1..c1333e1 100644
--- a/source/unix-toolchain-linux-setup.rst
+++ b/docs/source/unix-toolchain-linux-setup.rst
diff --git a/source/unix-toolchain-osx-setup.rst b/docs/source/unix-toolchain-osx-setup.rst
index 01b9e2c..01b9e2c 100644
--- a/source/unix-toolchain-osx-setup.rst
+++ b/docs/source/unix-toolchain-osx-setup.rst
diff --git a/source/unix-toolchain-win-setup.rst b/docs/source/unix-toolchain-win-setup.rst
index 099e7fe..099e7fe 100644
--- a/source/unix-toolchain-win-setup.rst
+++ b/docs/source/unix-toolchain-win-setup.rst
diff --git a/source/unix-toolchain.rst b/docs/source/unix-toolchain.rst
index 769b8ec..769b8ec 100644
--- a/source/unix-toolchain.rst
+++ b/docs/source/unix-toolchain.rst
diff --git a/source/usart.rst b/docs/source/usart.rst
index dbbc81c..dbbc81c 100644
--- a/source/usart.rst
+++ b/docs/source/usart.rst
diff --git a/source/usb.rst b/docs/source/usb.rst
index 80c40ca..80c40ca 100644
--- a/source/usb.rst
+++ b/docs/source/usb.rst
diff --git a/source/whats-new.rst b/docs/source/whats-new.rst
index c7d10c5..c7d10c5 100644
--- a/source/whats-new.rst
+++ b/docs/source/whats-new.rst
diff --git a/tmpl/libmaple-proper-page.rst.tmpl b/docs/tmpl/libmaple-proper-page.rst.tmpl
index c00dd63..c00dd63 100644
--- a/tmpl/libmaple-proper-page.rst.tmpl
+++ b/docs/tmpl/libmaple-proper-page.rst.tmpl
diff --git a/examples/blinky.cpp b/examples/blinky.cpp
new file mode 100644
index 0000000..751475e
--- /dev/null
+++ b/examples/blinky.cpp
@@ -0,0 +1,25 @@
+// Blinks the built-in LED
+
+#include <wirish/wirish.h>
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+}
+
+void loop() {
+ togglePin(BOARD_LED_PIN);
+ delay(100);
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/debug-dtrrts.cpp b/examples/debug-dtrrts.cpp
new file mode 100644
index 0000000..75eceef
--- /dev/null
+++ b/examples/debug-dtrrts.cpp
@@ -0,0 +1,38 @@
+// Test sketch for figuring out DTR/RTS behavior on different platforms.
+
+#include <wirish/wirish.h>
+#include "usb_cdcacm.h"
+
+void setup() {
+ /* Set up the LED to blink */
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ /* Send a message out USART2 */
+ Serial2.begin(9600);
+ Serial2.println("Debugging DTR/RTS...");
+}
+
+void loop() {
+ toggleLED();
+ delay(100);
+
+ Serial2.print("DTR: ");
+ Serial2.print(usb_cdcacm_get_dtr(), DEC);
+ Serial2.print("\tRTS: ");
+ Serial2.println(usb_cdcacm_get_rts(), DEC);
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/exti-interrupt-callback.cpp b/examples/exti-interrupt-callback.cpp
new file mode 100644
index 0000000..c87c064
--- /dev/null
+++ b/examples/exti-interrupt-callback.cpp
@@ -0,0 +1,87 @@
+// Toggles the built-in LED when the built in button
+// on the Maple is pushed in. This uses the attachInterrupt function to
+// setup the interrupt handler for the button being pressed.
+//
+// This is similar to the exti-interrupt example, but shows the use of a class
+// method to handle interrupts.
+//
+// More about attachInterrupt:
+// http://leaflabs.com/docs/lang/api/attachinterrupt.html
+//
+
+
+#include <wirish/wirish.h>
+
+class MyAwesomeClass {
+public:
+ // Setup the interrupt handler
+ void initialize() {
+ // LED is off by default
+ this->isLEDOn = false;
+
+ // Attach interrupt to class method handler
+ attachInterrupt(BOARD_BUTTON_PIN, buttonInterruptHandler, this, RISING);
+ }
+
+private:
+
+ bool isLEDOn;
+
+ // Static event handler takes a void * argument that was originally
+ // passed to the attachInterrupt call. If the argument in question is an
+ // instance of the class (MyAwesomeClass in this case), the static function
+ // get access to that instance's data (even private data).
+ //
+ // In other words, this setup allows the Maple to have class method
+ // interrupt handlers (albeit with a work around).
+ //
+ // However, as you might imagine, this argument can be anything (if you
+ // don't need instance data access).
+ //
+ static void buttonInterruptHandler(void *arg) {
+ // Cast the "generic" void argument to the class instance.
+ MyAwesomeClass *instance = (MyAwesomeClass *)arg;
+
+ // Accessing private instance data
+ instance->isLEDOn = !(instance->isLEDOn);
+
+ // Set LED
+ digitalWrite(BOARD_LED_PIN, instance->isLEDOn);
+
+ // Delay slightly for switch de-bouncing
+ delay(20);
+ }
+};
+
+MyAwesomeClass myClass;
+
+// Setup pin modes and the interrupt handler class
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ // The initialize method sets up the event handler to the private method
+ // in MyAwesomeClass. There is however, nothing stopping you from setting
+ // up event handlers which are public methods in classes.
+ myClass.initialize();
+}
+
+// Loop. Does nothing in this example.
+void loop() {
+
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/exti-interrupt.cpp b/examples/exti-interrupt.cpp
new file mode 100644
index 0000000..89382d7
--- /dev/null
+++ b/examples/exti-interrupt.cpp
@@ -0,0 +1,50 @@
+// Toggles the built-in LED when the built in button
+// on the Maple is pushed in. This uses the attachInterrupt function to
+// setup the interrupt handler for the button being pressed.
+//
+// More about attachInterrupt:
+// http://leaflabs.com/docs/lang/api/attachinterrupt.html
+//
+
+#include <wirish/wirish.h>
+
+// LED is off by default
+bool isLEDOn = false;
+
+// Interrupt handler takes in nothing and returns nothing.
+void interruptHandler() {
+ // Set LED
+ isLEDOn = !isLEDOn;
+ digitalWrite(BOARD_LED_PIN, isLEDOn);
+
+ // Delay slightly for switch debouncing.
+ delay(20);
+}
+
+// Setup pin modes and the interrupt handler
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ attachInterrupt(BOARD_BUTTON_PIN, interruptHandler, RISING);
+}
+
+// Loop. Does nothing in this example.
+void loop() {
+
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/freertos-blinky.cpp b/examples/freertos-blinky.cpp
new file mode 100644
index 0000000..2e7c7f7
--- /dev/null
+++ b/examples/freertos-blinky.cpp
@@ -0,0 +1,43 @@
+#include <wirish/wirish.h>
+#include "libraries/FreeRTOS/MapleFreeRTOS.h"
+
+static void vLEDFlashTask(void *pvParameters) {
+ for (;;) {
+ vTaskDelay(1000);
+ digitalWrite(BOARD_LED_PIN, HIGH);
+ vTaskDelay(50);
+ digitalWrite(BOARD_LED_PIN, LOW);
+ }
+}
+
+void setup() {
+ // initialize the digital pin as an output:
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ xTaskCreate(vLEDFlashTask,
+ (signed portCHAR *)"Task1",
+ configMINIMAL_STACK_SIZE,
+ NULL,
+ tskIDLE_PRIORITY + 2,
+ NULL);
+ vTaskStartScheduler();
+}
+
+void loop() {
+ // Insert background code here
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/fsmc-stress-test.cpp b/examples/fsmc-stress-test.cpp
new file mode 100644
index 0000000..20d3fa7
--- /dev/null
+++ b/examples/fsmc-stress-test.cpp
@@ -0,0 +1,229 @@
+/*
+
+ A low-level stress test of SRAM functionality. Uses slow-ish timing
+ by default (DATAST = ADDSET = 0xF).
+
+ Copyright 2011 LeafLabs, LLC.
+
+ This code is released into the public domain.
+
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+
+#include <wirish/wirish.h>
+#include <libmaple/rcc.h>
+#include <libmaple/fsmc.h>
+
+// -- SRAM config -------------------------------------------------------------
+
+// Timing configuration
+#define DATAST 0xF
+#define ADDSET 0xF
+
+// Number of SRAM chips to test
+#define N 1
+
+// How much of each to test
+#define MEM_SIZE 0x3FFF
+
+// Their start addresses in FSMC bank 1
+__io uint16 *const starts[N] = {
+ // (__io uint16 *const)FSMC_NOR_PSRAM_REGION1,
+ // (__io uint16 *const)FSMC_NOR_PSRAM_REGION2,
+ (__io uint16 *const)FSMC_NOR_PSRAM_REGION3,
+ // (__io uint16 *const)FSMC_NOR_PSRAM_REGION4,
+};
+
+// Corresponding FSMC configuration registers
+__io uint32 *const bcrs[N] = {
+ // &FSMC_NOR_PSRAM1_BASE->BCR,
+ // &FSMC_NOR_PSRAM2_BASE->BCR,
+ &FSMC_NOR_PSRAM3_BASE->BCR,
+ // &FSMC_NOR_PSRAM4_BASE->BCR,
+};
+
+// Corresponding FSMC timing registers
+__io uint32 *const btrs[N] = {
+ // &FSMC_NOR_PSRAM1_BASE->BTR,
+ // &FSMC_NOR_PSRAM2_BASE->BTR,
+ &FSMC_NOR_PSRAM3_BASE->BTR,
+ // &FSMC_NOR_PSRAM4_BASE->BTR,
+};
+
+// -- Pseudorandom number generation -----------------------------------------
+
+const uint32 seed = 0xDEADBEEF;
+
+uint32 num_rand_calls = 0;
+
+uint32 rand(long n) {
+ num_rand_calls++;
+ return random(n);
+}
+
+// -- Printing ----------------------------------------------------------------
+
+// For snprintf()
+char snprintf_buf[200];
+
+#define ERR(fmt, ...) do { \
+ snprintf(snprintf_buf, sizeof snprintf_buf, \
+ "ERROR: " fmt " (seed %d, ncalls %d, line %d)", \
+ __VA_ARGS__, seed, num_rand_calls, __LINE__); \
+ SerialUSB.println(snprintf_buf); \
+ } while (0)
+
+// Set to 1 for more output
+#define VERBOSE 0
+
+// -- setup()/loop() ----------------------------------------------------------
+
+void setup() {
+ fsmc_sram_init_gpios();
+ rcc_clk_enable(RCC_FSMC);
+
+ for (int i = 0; i < N; i++) {
+ *bcrs[i] = (FSMC_BCR_WREN |
+ FSMC_BCR_MTYP_SRAM |
+ FSMC_BCR_MWID_16BITS |
+ FSMC_BCR_MBKEN);
+ *btrs[i] = (DATAST << 8) | ADDSET;
+ }
+
+ randomSeed(seed);
+
+ SerialUSB.read();
+ SerialUSB.println("Starting test");
+}
+
+// stress_test() and simple_roundtrip() are the available test routines
+bool stress_test(void);
+bool simple_roundtrip(void);
+
+void loop() {
+ uint32 last;
+
+ last = millis();
+ while (true) {
+ if (!stress_test()) {
+ SerialUSB.println("Halting due to error.");
+ throb();
+ } else {
+ uint32 now = millis();
+ if (now - last > 500) {
+ snprintf(snprintf_buf, sizeof snprintf_buf,
+ "everything ok so far, timestamp %d ms", now);
+ SerialUSB.println(snprintf_buf);
+ last = now;
+ }
+ }
+ }
+}
+
+// -- Test routines -----------------------------------------------------------
+
+bool random_trips();
+bool sequential_trips();
+
+bool stress_test(void) {
+ static int i = 0;
+ i = !i;
+
+ switch (i) {
+ case 0:
+ return random_trips();
+ default:
+ return sequential_trips();
+ }
+}
+
+bool simple_roundtrip(void) {
+ uint16 wval = 0xAB;
+
+ for (int i = 0; i < N; i++) {
+ __io uint16 *addr = starts[i] + 4;
+ snprintf(snprintf_buf, sizeof snprintf_buf, "round-trip 0x%x at %p",
+ wval, addr);
+ SerialUSB.println(snprintf_buf);
+
+ *addr = wval;
+ uint16 rval = *addr;
+
+ if (rval != wval) {
+ ERR("wrote 0x%x, read 0x%x, timestamp %d", wval, rval, millis());
+ return false;
+ } else {
+ snprintf(snprintf_buf, sizeof snprintf_buf, "got back 0x%x", rval);
+ SerialUSB.println(snprintf_buf);
+ }
+ }
+
+ return true;
+}
+
+bool random_trips(void) {
+#if VERBOSE
+ SerialUSB.println("[random]");
+#endif
+ for (int n = 0; n < N; n++) {
+ __io uint16 *const start = starts[n];
+
+ for (int i = 0; i < 1000; i++) {
+ uint32 offset = rand(MEM_SIZE);
+ uint32 wval = rand(0xFFFF);
+
+ *(start + offset) = wval;
+ uint32 rval = *(start + offset);
+
+ if (rval != wval) {
+ ERR("wrote 0x%x to 0x%x, read 0x%x", wval, offset, rval);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool sequential_trips(void) {
+ static const uint32 seq_length = 300;
+#if VERBOSE
+ SerialUSB.println("[seq]");
+#endif
+ for (int n = 0; n < N; n++) {
+ __io uint16 *const start = starts[n];
+
+ for (int i = 0; i < 100; i++) {
+ uint32 start_offset = rand(MEM_SIZE - seq_length);
+
+ for (uint32 w = 0; w < seq_length; w++) {
+ uint32 offset = start_offset + w;
+
+ *(start + offset) = w;
+ uint32 r = *(start + offset);
+
+ if (w != r) {
+ ERR("wrote 0x%x to 0x%x, read 0x%x", w, offset, r);
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+ while (true) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/examples/i2c-mcp4725-dac.cpp b/examples/i2c-mcp4725-dac.cpp
new file mode 100644
index 0000000..da9a34e
--- /dev/null
+++ b/examples/i2c-mcp4725-dac.cpp
@@ -0,0 +1,145 @@
+// i2c-mcp4725-dac.cpp
+//
+// Written by Andrew Meyer <ajm@leaflabs.com>
+// Modified by Marti Bolivar <mbolivar@leaflabs.com>
+//
+// Simple program showing how to control an MCP4725 DAC using the
+// libmaple I2C interface. There's an MCP4725 breakout board available
+// on SparkFun:
+//
+// http://www.sparkfun.com/products/8736
+//
+// How to use:
+//
+// 1. Connect the DAC SDA and SCL pins to I2C2, with a pullup
+// resistor (1 KOhm should work) to VCC.
+// 2. Load the sketch and connect to SerialUSB.
+// 3. Press the button.
+//
+// The program then makes sure the DAC is connected properly (during
+// setup()), then has the DAC output a sawtooth wave (with loop()).
+
+#include <wirish/wirish.h>
+#include <libmaple/i2c.h>
+
+#define MCP_ADDR 0x60
+#define MCP_WRITE_DAC 0b01000000
+#define MCP_WRITE_EEPROM 0b01100000
+#define MCP_PD_NORMAL 0b00000000
+#define MCP_PD_1K 0b00000010
+#define MCP_PD_100K 0b00000100
+#define MCP_PD_500K 0b00000110
+
+static uint8 write_msg_data[3];
+static i2c_msg write_msg;
+
+static uint8 read_msg_data[5];
+static i2c_msg read_msg;
+
+/*
+ * DAC control routines
+ */
+
+void mcp_i2c_setup(void) {
+ write_msg.addr = MCP_ADDR;
+ write_msg.flags = 0; // write, 7 bit address
+ write_msg.length = sizeof(write_msg_data);
+ write_msg.xferred = 0;
+ write_msg.data = write_msg_data;
+
+ read_msg.addr = MCP_ADDR;
+ read_msg.flags = I2C_MSG_READ;
+ read_msg.length = sizeof(read_msg_data);
+ read_msg.xferred = 0;
+ read_msg.data = read_msg_data;
+}
+
+void mcp_write_val(uint16 val) {
+ write_msg_data[0] = MCP_WRITE_DAC | MCP_PD_NORMAL;
+ uint16 tmp = val >> 4;
+ write_msg_data[1] = tmp;
+ tmp = (val << 4) & 0x00FF;
+ write_msg_data[2] = tmp;
+
+ i2c_master_xfer(I2C2, &write_msg, 1, 0);
+}
+
+uint16 mcp_read_val() {
+ uint16 tmp = 0;
+
+ i2c_master_xfer(I2C2, &read_msg, 1, 2);
+
+ /* We don't care about the status and EEPROM bytes (0, 3, and 4). */
+ tmp = (read_msg_data[1] << 4);
+ tmp += (read_msg_data[2] >> 4);
+ return tmp;
+}
+
+int mcp_test() {
+ uint16 val;
+ uint16 test_val = 0x0101;
+
+ SerialUSB.println("Testing the MCP4725...");
+ /* Read the value of the register (should be 0x0800 if factory fresh) */
+ val = mcp_read_val();
+ SerialUSB.print("DAC Register = 0x");
+ SerialUSB.println(val, HEX);
+
+ mcp_write_val(test_val);
+ SerialUSB.print("Wrote 0x");
+ SerialUSB.print(test_val, HEX);
+ SerialUSB.println(" to the DAC");
+
+ val = mcp_read_val();
+ SerialUSB.print("DAC Register = 0x");
+ SerialUSB.println(val, HEX);
+
+ if (val != test_val) {
+ SerialUSB.println("ERROR: MCP4725 not responding correctly");
+ return 0;
+ }
+
+ SerialUSB.println("MCP4725 seems to be working");
+ return 1;
+}
+
+/*
+ * setup() and loop()
+ */
+
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ i2c_master_enable(I2C2, 0);
+ mcp_i2c_setup();
+
+ waitForButtonPress();
+ ASSERT(mcp_test());
+
+ SerialUSB.println("Starting sawtooth wave");
+}
+
+void loop() {
+ static uint16 dout = 0;
+
+ mcp_write_val(dout);
+
+ dout += 50;
+ if (dout >= 32768) {
+ dout = 0;
+ }
+}
+
+// -- init() and main() -------------------------------------------------------
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/mini-exti-test.cpp b/examples/mini-exti-test.cpp
new file mode 100644
index 0000000..54a4dd0
--- /dev/null
+++ b/examples/mini-exti-test.cpp
@@ -0,0 +1,251 @@
+/*
+ * EXTI test (Maple Mini only).
+ *
+ * Setup: For i from 0 to N_EXTI-1 (see below), connect exti_pins[i]
+ * to src_pins[i]. Connect via SerialUSB and press a key to perform a
+ * test run. In the printed results For each EXTI within a test run,
+ * the number triggered should match the number handled.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <wirish/wirish.h>
+
+// test routines
+void run_exti_test(void);
+void print_test_results(void);
+
+// -- State -------------------------------------------------------------------
+
+// Test using EXTI lines 0 -- (N_EXTI - 1).
+#define N_EXTI 6
+
+// src_pins[i] determines the line level for EXTI i. these *must* be
+// in GPIOA. if you want to change them, make sure they don't
+// conflict with exti_pins[].
+//
+// src_pins[0] = D5 = PA6
+// src_pins[1] = D4 = PA7
+// src_pins[2] = D27 = PA8
+// src_pins[3] = D26 = PA9
+// src_pins[4] = D25 = PA10
+// src_pins[5] = D22 = PA13
+#define SRC0 5
+#define SRC0_BIT BIT(6)
+#define SRC1 4
+#define SRC1_BIT BIT(7)
+#define SRC2 27
+#define SRC2_BIT BIT(8)
+#define SRC3 26
+#define SRC3_BIT BIT(9)
+#define SRC4 25
+#define SRC4_BIT BIT(10)
+#define SRC5 22
+#define SRC5_BIT BIT(13)
+// Setting a bit in GPIOA_SRC_MSK means that the given src pin will
+// actually trigger interrupts. Useful for experimenting.
+#define GPIOA_SRC_MSK \
+ (SRC0_BIT | SRC1_BIT | SRC2_BIT | SRC3_BIT | SRC4_BIT | SRC5_BIT)
+const int src_pins[N_EXTI] = {
+ SRC0,
+ SRC1,
+ SRC2,
+ SRC3,
+ SRC4,
+ SRC5,
+};
+const int src_gpioa_msks[N_EXTI] = {
+ SRC0_BIT,
+ SRC1_BIT,
+ SRC2_BIT,
+ SRC3_BIT,
+ SRC4_BIT,
+ SRC5_BIT,
+};
+
+// exti_pins[i] <-> EXTI line i. make sure these don't conflict with
+// src_pins.
+const int exti_pins[N_EXTI] = {
+ D3, // PB0
+ D10, // PA1
+ D2, // PB2
+ D19, // PB3
+ D7, // PA4
+ D6, // PA5
+};
+
+// EXTI handlers
+void exti_0_handler(void);
+void exti_1_handler(void);
+void exti_2_handler(void);
+void exti_3_handler(void);
+void exti_4_handler(void);
+void exti_5_handler(void);
+voidFuncPtr exti_handlers[N_EXTI] = {
+ exti_0_handler,
+ exti_1_handler,
+ exti_2_handler,
+ exti_3_handler,
+ exti_4_handler,
+ exti_5_handler,
+};
+
+// index i = number of times we've triggered EXTI line n
+static uint32 n_triggered[N_EXTI];
+
+// index i = number of times we've handled EXTI line n
+volatile static uint32 n_handled[N_EXTI];
+
+// -- setup() -----------------------------------------------------------------
+
+void setup(void) {
+ // Set up pin modes and get line levels stable
+ for (int i = 0; i < N_EXTI; i++) {
+ pinMode(src_pins[i], OUTPUT);
+ digitalWrite(src_pins[i], LOW);
+ pinMode(exti_pins[i], INPUT);
+ }
+
+ // Delay to ensure src_pins are all LOW before proceeding
+ delay(1);
+
+ // Attach interrupts
+ for (int i = 0; i < N_EXTI; i++) {
+ attachInterrupt(exti_pins[i], exti_handlers[i], RISING);
+ }
+}
+
+// -- loop() ------------------------------------------------------------------
+
+void loop(void) {
+ // Wait for user to send a byte before starting
+ while (!SerialUSB.available())
+ ;
+ while (SerialUSB.available()) {
+ SerialUSB.read();
+ }
+
+ // Run the test, print the results
+ run_exti_test();
+ print_test_results();
+
+ // Clear out the triggered/handled state
+ for (int i = 0; i < N_EXTI; i++) {
+ n_triggered[i] = 0;
+ n_handled[i] = 0;
+ }
+
+ SerialUSB.println();
+ SerialUSB.println();
+ SerialUSB.println();
+}
+
+// -- Test routines -----------------------------------------------------------
+
+#define N_RUNS 100
+void run_exti_test(void) {
+ for (int run = 0; run < N_RUNS; run++) {
+ // Trigger EXTIs simultaneously
+ GPIOA_BASE->BSRR = GPIOA_SRC_MSK;
+
+ // Reset line levels
+ GPIOA_BASE->BSRR = GPIOA_SRC_MSK << 16;
+
+ // Update number of times triggered
+ for (int i = 0; i < N_EXTI; i++) {
+ if (GPIOA_SRC_MSK & src_gpioa_msks[i]) {
+ n_triggered[i]++;
+ }
+ }
+ }
+}
+
+// string handling boilerplate
+void resetl(void);
+void appendl(const char str[]);
+void appendl(uint32 n);
+void printl(void);
+
+void print_test_results(void) {
+ SerialUSB.println("Results:");
+
+ resetl();
+ appendl("EXTI");
+ appendl("# Triggered");
+ appendl("# Handled");
+ printl();
+ resetl();
+
+ for (uint32 i = 0; i < N_EXTI; i++) {
+ appendl(i);
+ appendl(n_triggered[i]);
+ appendl(n_handled[i]);
+ printl();
+ resetl();
+ }
+}
+
+// -- EXTI handlers -----------------------------------------------------------
+
+void exti_0_handler(void) {
+ n_handled[0]++;
+}
+
+void exti_1_handler(void) {
+ n_handled[1]++;
+}
+
+void exti_2_handler(void) {
+ n_handled[2]++;
+}
+
+void exti_3_handler(void) {
+ n_handled[3]++;
+}
+
+void exti_4_handler(void) {
+ n_handled[4]++;
+}
+
+void exti_5_handler(void) {
+ n_handled[5]++;
+}
+
+// -- String handling ---------------------------------------------------------
+
+#define C_SIZ 20
+#define LIN_SIZ 80
+char l[LIN_SIZ + 1];
+char tmp[C_SIZ + 1];
+
+void resetl(void) {
+ l[0] = '\0';
+}
+
+void appendl(const char str[]) {
+ snprintf(tmp, C_SIZ, "%-*s", C_SIZ, str);
+ strncat(l, tmp, LIN_SIZ - strlen(tmp));
+}
+
+void appendl(uint32 n) {
+ snprintf(tmp, C_SIZ, "%-*u", C_SIZ, n);
+ strncat(l, tmp, LIN_SIZ - strlen(tmp));
+}
+
+void printl(void) {
+ SerialUSB.println(l);
+}
+
+// -- init()/main() -----------------------------------------------------------
+
+__attribute__((constructor)) void premain() { init(); }
+
+int main(void) {
+ setup();
+
+ while (true)
+ loop();
+
+ return 0;
+}
diff --git a/examples/qa-slave-shield.cpp b/examples/qa-slave-shield.cpp
new file mode 100644
index 0000000..ec25e49
--- /dev/null
+++ b/examples/qa-slave-shield.cpp
@@ -0,0 +1,66 @@
+// Slave mode for Quality Assurance test
+
+#include <wirish/wirish.h>
+
+#define INTER_TOGGLE_DELAY_NORMAL 5
+#define INTER_TOGGLE_DELAY_SLOW 80
+
+void interToggleDelay(void);
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+
+ // All unused pins start out low.
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pinMode(i, OUTPUT);
+ digitalWrite(i, LOW);
+ }
+ SerialUSB.println("OK, starting...");
+}
+
+void loop() {
+ toggleLED();
+ delay(100);
+ toggleLED();
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+
+ // Bring just this pin high.
+ digitalWrite(i, HIGH);
+ // Give the master time to detect if any other pins also went high.
+ interToggleDelay();
+ // Bring this pin back low again; all pins should now be low.
+ digitalWrite(i, LOW);
+ // Give the master time to detect if any pins are still high.
+ interToggleDelay();
+ }
+}
+
+void interToggleDelay(void) {
+ if (digitalRead(BOARD_BUTTON_PIN)) { // don't pay the debouncing time
+ delay(INTER_TOGGLE_DELAY_SLOW);
+ } else {
+ delay(INTER_TOGGLE_DELAY_NORMAL);
+ }
+ }
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/examples/serial-echo.cpp b/examples/serial-echo.cpp
new file mode 100644
index 0000000..204f011
--- /dev/null
+++ b/examples/serial-echo.cpp
@@ -0,0 +1,30 @@
+// Simple serial port "echo". Send back any received data.
+
+#include <wirish/wirish.h>
+
+// Note: you can change "Serial1" to any other serial port you have on
+// your board.
+
+void setup() {
+ Serial1.begin(115200);
+}
+
+void loop() {
+ while (Serial1.available()) {
+ Serial1.write(Serial1.read());
+ }
+}
+
+// Force init() to be called before anything else.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/spi_master.cpp b/examples/spi_master.cpp
new file mode 100644
index 0000000..ea6c990
--- /dev/null
+++ b/examples/spi_master.cpp
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * 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 Sample main.cpp file. Sends "Hello world!" out SPI1.
+ *
+ * SPI1 is set up to be a master transmitter at 4.5MHz, little
+ * endianness, and SPI mode 0.
+ *
+ * Pin 10 is used as slave select.
+ */
+
+#include <wirish/wirish.h>
+
+#define NSS 10
+
+byte buf[] = "Hello world!";
+
+HardwareSPI spi1(1);
+
+void setup() {
+ /* Set up chip select as output */
+ pinMode(NSS, OUTPUT);
+
+ /* NSS is usually active LOW, so initialize it HIGH */
+ digitalWrite(NSS, HIGH);
+
+ /* Initialize SPI */
+ spi1.begin(SPI_4_5MHZ, LSBFIRST, 0);
+}
+
+void loop() {
+ /* Send message */
+ digitalWrite(NSS, LOW);
+ spi1.write(buf, sizeof buf);
+ digitalWrite(NSS, HIGH);
+ delay(1000);
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/examples/test-bkp.cpp b/examples/test-bkp.cpp
new file mode 100644
index 0000000..719cac7
--- /dev/null
+++ b/examples/test-bkp.cpp
@@ -0,0 +1,80 @@
+#include <stdio.h> // for snprintf()
+
+#include <wirish/wirish.h>
+#include <libmaple/bkp.h>
+#include <libmaple/iwdg.h>
+
+void print_bkp_contents();
+void write_to_bkp(uint16 val);
+
+#define comm Serial2
+
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+
+ comm.begin(9600);
+ comm.println("*** Beginning BKP test");
+
+ comm.println("Init...");
+ bkp_init();
+ comm.println("Done.");
+
+ print_bkp_contents();
+ write_to_bkp(10);
+ print_bkp_contents();
+
+ comm.println("Enabling backup writes.");
+ bkp_enable_writes();
+ write_to_bkp(20);
+ print_bkp_contents();
+
+ comm.println("Disabling backup writes.");
+ bkp_disable_writes();
+ write_to_bkp(30);
+ print_bkp_contents();
+
+ comm.println("Done testing backup registers; press button to enable "
+ "independent watchdog (in order to cause a reset).");
+ waitForButtonPress(0);
+ iwdg_init(IWDG_PRE_4, 1);
+ comm.println();
+}
+
+void loop() {
+}
+
+void print_bkp_contents() {
+ comm.println("Backup data register contents:");
+ char buf[100];
+ for (int i = 1; i <= BKP_NR_DATA_REGS; i++) {
+ snprintf(buf, sizeof buf, "DR%d: %d ", i, bkp_read(i));
+ comm.print(buf);
+ if (i % 5 == 0) comm.println();
+ }
+ comm.println();
+}
+
+void write_to_bkp(uint16 val) {
+ comm.print("Attempting to write ");
+ comm.print(val);
+ comm.println(" to backup registers...");
+ for (int i = 1; i <= BKP_NR_DATA_REGS; i++) {
+ bkp_write(i, val);
+ }
+ comm.println("Done.");
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ init();
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/examples/test-dac.cpp b/examples/test-dac.cpp
new file mode 100644
index 0000000..af188cc
--- /dev/null
+++ b/examples/test-dac.cpp
@@ -0,0 +1,51 @@
+/*
+ * Simple DAC test.
+ *
+ * Author: Marti Bolivar <mbolivar@leaflabs.com>
+ *
+ * This file is released into the public domain.
+ */
+
+#include <wirish/wirish.h>
+#include <libmaple/dac.h>
+
+uint16 count = 0;
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ digitalWrite(BOARD_LED_PIN, HIGH);
+
+ Serial1.begin(9600);
+ Serial1.println("**** Beginning DAC test");
+
+ Serial1.print("Init... ");
+ dac_init(DAC, DAC_CH1 | DAC_CH2);
+ Serial1.println("Done.");
+}
+
+void loop() {
+ toggleLED();
+ delay(100);
+
+ count += 100;
+ if (count > 4095) {
+ count = 0;
+ }
+
+ dac_write_channel(DAC, 1, 4095 - count);
+ dac_write_channel(DAC, 2, count);
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/examples/test-fsmc.cpp b/examples/test-fsmc.cpp
new file mode 100644
index 0000000..1621317
--- /dev/null
+++ b/examples/test-fsmc.cpp
@@ -0,0 +1,122 @@
+#include <stddef.h> // for ptrdiff_t
+
+#include <wirish/wirish.h>
+#include <libmaple/fsmc.h>
+
+#ifndef BOARD_maple_native
+#error "Sorry, this example only works on Maple Native."
+#endif
+
+// Start of FSMC SRAM bank 1
+static uint16 *const sram_start = (uint16*)0x60000000;
+// End of Maple Native SRAM chip address space (512K 16-bit words)
+static uint16 *const sram_end = (uint16*)0x60100000;
+
+void test_single_write(void);
+void test_all_addresses(void);
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ digitalWrite(BOARD_LED_PIN, HIGH);
+
+ SerialUSB.read();
+ SerialUSB.println("*** Beginning RAM chip test");
+
+ test_single_write();
+ test_all_addresses();
+
+ SerialUSB.println("Tests pass, finished.");
+ SerialUSB.println("***\n");
+}
+
+void loop() {
+}
+
+void test_single_write() {
+ uint16 *ptr = sram_start;
+ uint16 tmp;
+
+ SerialUSB.print("Writing 0x1234... ");
+ *ptr = 0x1234;
+ SerialUSB.println("Done.");
+
+ SerialUSB.print("Reading... ");
+ tmp = *ptr;
+ SerialUSB.print("Done: 0x");
+ SerialUSB.println(tmp, HEX);
+
+ if (tmp != 0x1234) {
+ SerialUSB.println("Mismatch; abort.");
+ ASSERT(0);
+ }
+}
+
+void test_all_addresses() {
+ uint32 start, end;
+ uint16 count = 0;
+ uint16 *ptr;
+
+ SerialUSB.println("Now writing all memory addresses (unrolled loop)");
+ start = micros();
+ for (ptr = sram_start; ptr < sram_end;) {
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ }
+ end = micros();
+ SerialUSB.print("Done. Elapsed time (us): ");
+ SerialUSB.println(end - start);
+
+ SerialUSB.println("Validating writes.");
+ for (ptr = sram_start, count = 0; ptr < sram_end; ptr++, count++) {
+ uint16 value = *ptr;
+ if (value != count) {
+ SerialUSB.print("mismatch: 0x");
+ SerialUSB.print((uint32)ptr);
+ SerialUSB.print(" = 0x");
+ SerialUSB.print(value, HEX);
+ SerialUSB.print(", should be 0x");
+ SerialUSB.print(count, HEX);
+ SerialUSB.println(".");
+ ASSERT(0);
+ }
+ }
+ SerialUSB.println("Done; all writes seem valid.");
+
+ ptrdiff_t nwrites = sram_end - sram_start;
+ double us_per_write = double(end-start) / double(nwrites);
+ SerialUSB.print("Number of writes = ");
+ SerialUSB.print(nwrites);
+ SerialUSB.print("; avg. time per write = ");
+ SerialUSB.print(us_per_write);
+ SerialUSB.print(" us (");
+ SerialUSB.print(1 / us_per_write);
+ SerialUSB.println(" MHz)");
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+
+ return 0;
+}
diff --git a/examples/test-print.cpp b/examples/test-print.cpp
new file mode 100644
index 0000000..bdc1894
--- /dev/null
+++ b/examples/test-print.cpp
@@ -0,0 +1,184 @@
+/*
+ * print-test.cpp
+ *
+ * Tests the various Print methods. (For USBSerial; assuming that
+ * writing a single character works, this should generalize to
+ * HardwareSerial).
+ *
+ * This file is released into the public domain.
+ */
+
+#include <wirish/wirish.h>
+#undef min
+#undef max
+
+// For snprintf()
+#include <stdio.h>
+// The <limits.h> that comes with newlib is missing LLONG_MAX, etc.
+#include <limits>
+
+using namespace std;
+
+#define BUF_SIZE 100
+char buf[BUF_SIZE];
+
+void test_numbers(void);
+void test_base_arithmetic(void);
+void test_floating_point(void);
+
+void print_separator(void);
+
+void setup() {
+ while (!SerialUSB.available())
+ continue;
+ SerialUSB.read();
+}
+
+void loop() {
+ SerialUSB.println("Testing Print methods.");
+ print_separator();
+
+ test_numbers();
+ print_separator();
+
+ test_base_arithmetic();
+ print_separator();
+
+ test_floating_point();
+ print_separator();
+
+ SerialUSB.println("Test finished.");
+ while (true) {
+ continue;
+ }
+}
+
+void test_numbers(void) {
+ SerialUSB.println("Numeric types:");
+
+ SerialUSB.print("unsigned char: ");
+ // prevent Print from treating it as an (extended) ASCII character:
+ SerialUSB.println((uint32)numeric_limits<unsigned char>::max());
+
+ SerialUSB.print("int: ");
+ SerialUSB.print(numeric_limits<int>::min());
+ SerialUSB.print(" -- ");
+ SerialUSB.println(numeric_limits<int>::max());
+
+ SerialUSB.print("unsigned int: ");
+ SerialUSB.print(numeric_limits<unsigned int>::max());
+ SerialUSB.println();
+
+ SerialUSB.print("long: ");
+ SerialUSB.print(numeric_limits<long>::min());
+ SerialUSB.print(" -- ");
+ SerialUSB.println(numeric_limits<long>::max());
+
+ SerialUSB.print("long long: ");
+ SerialUSB.print(numeric_limits<long long>::min());
+ SerialUSB.print(" -- ");
+ SerialUSB.println(numeric_limits<long long>::max());
+
+ SerialUSB.print("unsigned long long: ");
+ SerialUSB.println(numeric_limits<unsigned long long>::max());
+}
+
+void base_test(int base) {
+ SerialUSB.print("\tuint8: ");
+ SerialUSB.println(numeric_limits<uint8>::max(), base);
+ SerialUSB.print("\tint: ");
+ SerialUSB.print(numeric_limits<int>::max(), base);
+ SerialUSB.print(", unsigned int: ");
+ SerialUSB.println(numeric_limits<unsigned int>::max(), base);
+ SerialUSB.print("\tlong: ");
+ SerialUSB.print(numeric_limits<long>::max(), base);
+ SerialUSB.print(", unsigned long: ");
+ SerialUSB.println(numeric_limits<unsigned long>::max(), base);
+ SerialUSB.print("\tlong long: ");
+ SerialUSB.print(numeric_limits<long long>::max(), base);
+ SerialUSB.print(", unsigned long long: ");
+ SerialUSB.println(numeric_limits<unsigned long long>::max(), base);
+}
+
+void test_base_arithmetic(void) {
+ SerialUSB.println("Base arithmetic:");
+
+ SerialUSB.println("Binary:");
+ base_test(BIN);
+
+ SerialUSB.println("Octal:");
+ base_test(OCT);
+
+ SerialUSB.println("Decimal:");
+ base_test(DEC);
+
+ SerialUSB.println("Hexadecimal:");
+ base_test(HEX);
+}
+
+void test_floating_point(void) {
+ double dmax = numeric_limits<double>::max();
+
+ SerialUSB.println("Floating point:");
+
+ SerialUSB.print("println(-5.67): ");
+ SerialUSB.print(-5.67);
+ SerialUSB.print(". println(5.67, 5): ");
+ SerialUSB.println(5.67, 5);
+ SerialUSB.print("println((double)(LLONG_MAX - 10)): ");
+ SerialUSB.print((double)(numeric_limits<long long>::max() - 10));
+ SerialUSB.print("; from snprintf(): ");
+ snprintf(buf, BUF_SIZE, "%.2f",
+ (double)(numeric_limits<long long>::max() - 10));
+ SerialUSB.println(buf);
+ SerialUSB.print("println((double)LLONG_MAX / 2): ");
+ SerialUSB.print((double)(numeric_limits<long long>::max()) / 2);
+ SerialUSB.print("; from snprintf(): ");
+ snprintf(buf, BUF_SIZE, "%.2f",
+ (double)(numeric_limits<long long>::max()) / 2);
+ SerialUSB.println(buf);
+ SerialUSB.print("DBL_MAX: ");
+ SerialUSB.print(dmax);
+ SerialUSB.print("; from snprintf(): ");
+ snprintf(buf, BUF_SIZE, "%g", dmax);
+ SerialUSB.println(buf);
+ SerialUSB.print("-DBL_MAX / 2: ");
+ SerialUSB.print(-dmax / 2.0);
+ SerialUSB.print("; from snprintf(): ");
+ snprintf(buf, BUF_SIZE, "%g", -dmax / 2.0);
+ SerialUSB.println(buf);
+ SerialUSB.print("Double epsilon, round error: ");
+ SerialUSB.print(numeric_limits<double>::epsilon());
+ SerialUSB.print(", ");
+ SerialUSB.println(numeric_limits<double>::round_error());
+
+ SerialUSB.println();
+
+ float fmax = numeric_limits<float>::max();
+
+ SerialUSB.print("println(-5.67f): ");
+ SerialUSB.println(-5.67f);
+ SerialUSB.print("Float max: ");
+ SerialUSB.println(fmax);
+}
+
+void print_separator(void) {
+ SerialUSB.println();
+ SerialUSB.println(" ** ");
+ SerialUSB.println();
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-ring-buffer-insertion.cpp b/examples/test-ring-buffer-insertion.cpp
new file mode 100644
index 0000000..2188b03
--- /dev/null
+++ b/examples/test-ring-buffer-insertion.cpp
@@ -0,0 +1,114 @@
+/*
+ * Simple ring_buffer test.
+ *
+ * Does a basic test of functionality on rb_full_count(), rb_reset(),
+ * rb_push_insert(), and rb_safe_insert().
+ *
+ * To test:
+ *
+ * - Connect a serial monitor to SerialUSB
+ * - Press any key
+ *
+ * This file is released into the public domain.
+ */
+
+#include <wirish/wirish.h>
+
+#include <libmaple/ring_buffer.h>
+
+#define BUF_SIZE 64
+ring_buffer ring_buf;
+ring_buffer *rb;
+uint8 rb_buffer[BUF_SIZE];
+
+void test_rb_push_insert(int num_bytes_to_insert);
+void test_rb_safe_insert(int num_bytes_to_insert);
+void test_rb_insertion_function(int num_bytes_to_insert,
+ int (*insertion_fn)(ring_buffer*, uint8),
+ const char insertion_fn_name[]);
+void print_rb_contents(void);
+
+void setup() {
+ rb = &ring_buf;
+ rb_init(rb, BUF_SIZE, rb_buffer);
+
+ while (!SerialUSB.available())
+ ;
+
+ SerialUSB.println("Beginning test.");
+ SerialUSB.println();
+}
+
+void loop() {
+ test_rb_push_insert(63);
+ SerialUSB.println("------------------------------");
+ test_rb_push_insert(64);
+ SerialUSB.println("------------------------------");
+ test_rb_safe_insert(63);
+ SerialUSB.println("------------------------------");
+ test_rb_safe_insert(64);
+ SerialUSB.println("------------------------------");
+
+ SerialUSB.println();
+ SerialUSB.println("Test finished.");
+ while (true)
+ ;
+}
+
+void test_rb_push_insert(int num_bytes_to_insert) {
+ test_rb_insertion_function(num_bytes_to_insert,
+ rb_push_insert,
+ "rb_push_insert()");
+}
+
+void test_rb_safe_insert(int num_bytes_to_insert) {
+ test_rb_insertion_function(num_bytes_to_insert,
+ rb_safe_insert,
+ "rb_safe_insert()");
+}
+
+void test_rb_insertion_function(int num_bytes_to_insert,
+ int (*insertion_fn)(ring_buffer *, uint8),
+ const char insertion_fn_name[]) {
+ SerialUSB.println("resetting ring buffer.");
+ rb_reset(rb);
+ print_rb_contents();
+
+ SerialUSB.print(insertion_fn_name);
+ SerialUSB.print("-ing ");
+ SerialUSB.print(num_bytes_to_insert);
+ SerialUSB.println(" bytes.");
+ for (uint8 i = 1; i <= num_bytes_to_insert; i++)
+ insertion_fn(rb, i);
+
+ uint16 count = rb_full_count(rb);
+ SerialUSB.print("rb_full_count(rb) = ");
+ SerialUSB.println(count);
+
+ print_rb_contents();
+}
+
+void print_rb_contents() {
+ uint16 count = rb_full_count(rb);
+ SerialUSB.print("ring buffer contents: ");
+ for (uint16 i = 0; i < count; i++) {
+ SerialUSB.print((int)rb_remove(rb));
+ if (i < count - 1) SerialUSB.print(", ");
+ }
+ SerialUSB.println();
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-serial-flush.cpp b/examples/test-serial-flush.cpp
new file mode 100644
index 0000000..409d1f9
--- /dev/null
+++ b/examples/test-serial-flush.cpp
@@ -0,0 +1,38 @@
+/*
+ * Tests the "flush" Serial function.
+ */
+
+#include <wirish/wirish.h>
+
+void setup() {
+ Serial1.begin(9600);
+ Serial1.println("Hello world!");
+}
+
+void loop() {
+ Serial1.println("Waiting for multiple input...");
+ while (Serial1.available() < 5)
+ ;
+ Serial1.println(Serial1.read());
+ Serial1.println(Serial1.read());
+ Serial1.flush();
+
+ if (Serial1.available()) {
+ Serial1.println("FAIL! Still had junk in the buffer...");
+ }
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-serialusb.cpp b/examples/test-serialusb.cpp
new file mode 100644
index 0000000..098e445
--- /dev/null
+++ b/examples/test-serialusb.cpp
@@ -0,0 +1,126 @@
+// Tests SerialUSB functionality.
+
+#include <wirish/wirish.h>
+#include "usb_cdcacm.h"
+
+#define QUICKPRINT 0
+#define BIGSTUFF 1
+#define NUMBERS 2
+#define SIMPLE 3
+#define ONOFF 4
+
+uint32 state = 0;
+
+void setup() {
+ /* Set up the LED to blink */
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ /* Set up Serial2 for use as a debug channel */
+ Serial2.begin(9600);
+ Serial2.println("This is the debug channel. Press any key.");
+ while (!Serial2.available())
+ ;
+ Serial2.read();
+}
+
+uint8 c1 = '-';
+
+void loop() {
+ toggleLED();
+ delay(1000);
+
+ if (Serial2.available()) {
+ Serial2.read();
+ state++;
+ }
+
+ switch (state) {
+ case QUICKPRINT:
+ for (int i = 0; i < 30; i++) {
+ usb_cdcacm_putc((char)c1, 1);
+ SerialUSB.print('.');
+ SerialUSB.print('|');
+ }
+ Serial2.println(SerialUSB.pending(), DEC);
+ SerialUSB.println();
+ break;
+ case BIGSTUFF:
+ SerialUSB.println("0123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789"
+ "012345678901234567890");
+ SerialUSB.println((int64)123456789, DEC);
+ SerialUSB.println(3.1415926535);
+ Serial2.println(SerialUSB.pending(), DEC);
+ break;
+ case NUMBERS:
+ SerialUSB.println("Numbers! -----------------------------");
+ Serial2.println("Numbers! -----------------------------");
+ SerialUSB.println('1');
+ Serial2.println('1');
+ SerialUSB.println(1, DEC);
+ Serial2.println(1, DEC);
+ SerialUSB.println(-1, DEC);
+ Serial2.println(-1, DEC);
+ SerialUSB.println(3.14159265);
+ Serial2.println(3.14159265);
+ SerialUSB.println(123456789, DEC);
+ Serial2.println(123456789, DEC);
+ SerialUSB.println(-123456789, DEC);
+ Serial2.println(-123456789, DEC);
+ SerialUSB.println(65535, HEX);
+ Serial2.println(65535, HEX);
+ break;
+ case SIMPLE:
+ Serial2.println("Trying write('a')");
+ SerialUSB.write('a');
+ Serial2.println("Trying write(\"b\")");
+ SerialUSB.write("b");
+ Serial2.println("Trying print('c')");
+ SerialUSB.print('c');
+ Serial2.println("Trying print(\"d\")");
+ SerialUSB.print("d");
+ Serial2.println("Trying print(\"efg\")");
+ SerialUSB.print("efg");
+ Serial2.println("Trying println(\"hij\\n\\r\")");
+ SerialUSB.print("hij\n\r");
+ SerialUSB.write(' ');
+ SerialUSB.println();
+ Serial2.println("Trying println(123456789, DEC)");
+ SerialUSB.println(123456789, DEC);
+ Serial2.println("Trying println(3.141592)");
+ SerialUSB.println(3.141592);
+ Serial2.println("Trying println(\"DONE\")");
+ SerialUSB.println("DONE");
+ break;
+ case ONOFF:
+ Serial2.println("Shutting down...");
+ SerialUSB.println("Shutting down...");
+ SerialUSB.end();
+ Serial2.println("Waiting 4 seconds...");
+ delay(4000);
+ Serial2.println("Starting up...");
+ SerialUSB.begin();
+ SerialUSB.println("Hello World!");
+ Serial2.println("Waiting 4 seconds...");
+ delay(4000);
+ state++;
+ break;
+ default:
+ state = 0;
+ }
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-servo.cpp b/examples/test-servo.cpp
new file mode 100644
index 0000000..6f6e3ba
--- /dev/null
+++ b/examples/test-servo.cpp
@@ -0,0 +1,152 @@
+/*
+ * Basic Servo library test program.
+ *
+ * Setup:
+ *
+ * - Connect a potentiometer to POT_PIN (default pin 15)
+ * - Connect an oscilloscope to SERVO_PIN1 (default pin 5) and
+ * SERVO_PIN2 (default pin 6).
+ * - Connect a serial monitor to SerialUSB
+ *
+ * The potentiometer controls the target angle for each of two Servo
+ * objects, one with angles in [-90, 90], and another in [0, 180].
+ * Servo pulse width range is [1000, 2000].
+ *
+ * Serial2 will tell you what inputs it's giving to each servo object,
+ * and some information it gets back. Pressing the button
+ * detaches/reattaches the Servo objects.
+ *
+ * Tests you should perform:
+ *
+ * - Check calculated pulse widths for each servo's target angle
+ * - Check that calculated pulse widths match actual pulse widths
+ * - Check that the period of the pulse train is roughly 20 ms
+ * - Check that the pulses stop when detached, and resume when reattached
+ * - Check that Servo::write() and Servo::read() round-trip properly
+ *
+ * This file is released into the public domain.
+ */
+
+#include <stdio.h>
+
+#include <wirish/wirish.h>
+
+#include "libraries/Servo/Servo.h"
+
+#define POT_PIN 15
+
+#define MIN_PW 1000
+#define MAX_PW 2000
+
+#define SERVO_PIN1 5
+#define MIN_ANGLE1 0
+#define MAX_ANGLE1 180
+
+#define SERVO_PIN2 6
+#define MIN_ANGLE2 (-90)
+#define MAX_ANGLE2 90
+
+Servo servo1;
+Servo servo2;
+
+#define BUF_SIZE 100
+char buf[BUF_SIZE];
+
+#define print_buf(fmt, ...) do { \
+ snprintf(buf, BUF_SIZE, fmt, __VA_ARGS__); \
+ Serial2.println(buf); } while (0)
+
+int averageAnalogReads(int);
+void attach();
+void detach();
+
+void setup() {
+ pinMode(POT_PIN, INPUT_ANALOG);
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ Serial2.begin(9600);
+
+ servo1.attach(SERVO_PIN1, MIN_PW, MAX_PW, MIN_ANGLE1, MAX_ANGLE1);
+ servo2.attach(SERVO_PIN2, MIN_PW, MAX_PW, MIN_ANGLE2, MAX_ANGLE2);
+
+ ASSERT(servo1.attachedPin() == SERVO_PIN1);
+ ASSERT(servo2.attachedPin() == SERVO_PIN2);
+}
+
+void loop() {
+ delay(250);
+ toggleLED();
+
+ if (isButtonPressed()) {
+ if (servo1.attached()) detach();
+ else attach();
+ }
+
+ if (!servo1.attached()) return;
+
+ int32 average = averageAnalogReads(250);
+ int16 angle1 = (int16)map(average, 0, 4095, MIN_ANGLE1, MAX_ANGLE1);
+ int16 angle2 = (int16)map(average, 0, 4095, MIN_ANGLE2, MAX_ANGLE2);
+
+ print_buf("pot reading = %d, angle 1 = %d, angle 2 = %d.",
+ average, angle1, angle2);
+
+ servo1.write(angle1);
+ servo2.write(angle2);
+
+ int16 read1 = servo1.read();
+ int16 read2 = servo2.read();
+
+ print_buf("write/read angle 1: %d/%d, angle 2: %d/%d",
+ angle1, read1, angle2, read2);
+
+ ASSERT(abs(angle1 - read1) <= 1);
+ ASSERT(abs(angle2 - read2) <= 1);
+
+ print_buf("pulse width 1: %d, pulse width 2: %d",
+ servo1.readMicroseconds(), servo2.readMicroseconds());
+
+ Serial2.println("\n--------------------------\n");
+}
+
+int32 averageAnalogReads(int n) {
+ uint64 total = 0;
+
+ for (int i = 0; i < n; i++) {
+ total += analogRead(POT_PIN);
+ }
+
+ return (int32)(total / n);
+}
+
+void attach() {
+ Serial2.println("attaching");
+ servo1.attach(SERVO_PIN1);
+ servo2.attach(SERVO_PIN2);
+ ASSERT(servo1.attachedPin() == SERVO_PIN1);
+ ASSERT(servo2.attachedPin() == SERVO_PIN2);
+}
+
+void detach() {
+ Serial2.println("detaching");
+ servo1.detach();
+ servo2.detach();
+ ASSERT(!servo1.attached());
+ ASSERT(!servo2.attached());
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-session.cpp b/examples/test-session.cpp
new file mode 100644
index 0000000..284b4b0
--- /dev/null
+++ b/examples/test-session.cpp
@@ -0,0 +1,938 @@
+// Interactive Test Session for LeafLabs Maple
+// Copyright (c) 2010 LeafLabs LLC.
+//
+// Useful for testing Maple features and troubleshooting.
+// Communicates over SerialUSB.
+
+#include <string.h>
+
+#include <wirish/wirish.h>
+
+// ASCII escape character
+#define ESC ((uint8)27)
+
+// Default USART baud rate
+#define BAUD 9600
+
+// Number of times to sample a pin per ADC noise measurement
+#define N_ADC_NOISE_MEASUREMENTS 40
+
+uint8 gpio_state[BOARD_NR_GPIO_PINS];
+
+const char* dummy_data = ("123456789012345678901234567890\r\n"
+ "123456789012345678901234567890\r\n");
+
+// Commands
+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_serial1_echo(void);
+void cmd_gpio_monitoring(void);
+void cmd_sequential_adc_reads(void);
+void cmd_gpio_qa(void);
+void cmd_sequential_gpio_toggling(void);
+void cmd_gpio_toggling(void);
+void cmd_sequential_debug_gpio_toggling(void);
+void cmd_debug_gpio_toggling(void);
+void cmd_but_test(void);
+void cmd_sequential_pwm_test(void);
+void cmd_servo_sweep(void);
+void cmd_board_info(void);
+
+// Helper functions
+void measure_adc_noise(uint8 pin);
+void fast_gpio(int pin);
+void serial_baud_test(HardwareSerial **serials, int n, unsigned baud);
+void serial_echo_test(HardwareSerial *serial, unsigned baud);
+void init_all_timers(uint16 prescale);
+void enable_usarts(void);
+void disable_usarts(void);
+void print_board_array(const char* msg, const uint8 arr[], int len);
+
+// -- setup() and loop() ------------------------------------------------------
+
+void setup() {
+ // Set up the LED to blink
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ // Start up the serial ports
+ Serial1.begin(BAUD);
+ Serial2.begin(BAUD);
+ Serial3.begin(BAUD);
+
+ // Send a message out over SerialUSB interface
+ SerialUSB.println(" ");
+ SerialUSB.println(" __ __ _ _");
+ SerialUSB.println(" | \\/ | __ _ _ __ | | ___| |");
+ SerialUSB.println(" | |\\/| |/ _` | '_ \\| |/ _ \\ |");
+ SerialUSB.println(" | | | | (_| | |_) | | __/_|");
+ SerialUSB.println(" |_| |_|\\__,_| .__/|_|\\___(_)");
+ SerialUSB.println(" |_|");
+ SerialUSB.println(" by leaflabs");
+ SerialUSB.println("");
+ SerialUSB.println("");
+ SerialUSB.println("Maple interactive test program (type '?' for help)");
+ SerialUSB.println("-------------------------------------------------------"
+ "---");
+ SerialUSB.print("> ");
+
+}
+
+void loop () {
+ toggleLED();
+ delay(250);
+
+ while (SerialUSB.available()) {
+ uint8 input = SerialUSB.read();
+ SerialUSB.println((char)input);
+
+ switch(input) {
+ case '\r':
+ break;
+
+ case ' ':
+ SerialUSB.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 'E':
+ cmd_serial1_echo();
+ break;
+
+ case '.':
+ while (!SerialUSB.available()) {
+ Serial1.print(".");
+ Serial2.print(".");
+ Serial3.print(".");
+ SerialUSB.print(".");
+ }
+ break;
+
+ case 'd':
+ SerialUSB.println("Disabling USB. Press BUT to re-enable.");
+ SerialUSB.end();
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ while (!isButtonPressed())
+ ;
+ SerialUSB.begin();
+ break;
+
+ case 'n':
+ cmd_adc_stats();
+ break;
+
+ case 'N':
+ cmd_stressful_adc_stats();
+ break;
+
+ case 'e':
+ cmd_everything();
+ break;
+
+ case 'W':
+ while (!SerialUSB.available()) {
+ Serial1.print(dummy_data);
+ Serial2.print(dummy_data);
+ Serial3.print(dummy_data);
+ }
+ break;
+
+ case 'U': {
+ SerialUSB.println("Dumping data to USB. Press any key.");
+ int nprints = 0;
+ int start = millis();
+ while (!SerialUSB.available()) {
+ SerialUSB.print(dummy_data);
+ nprints++;
+ }
+ int elapsed = millis() - start;
+ SerialUSB.read(); // consume available character
+ size_t nbytes = nprints * strlen(dummy_data);
+ SerialUSB.println();
+ SerialUSB.print("Sent ");
+ SerialUSB.print(nbytes);
+ SerialUSB.print(" bytes (");
+ SerialUSB.print((nbytes / (double)elapsed) * (1000.0 / 1024.0));
+ SerialUSB.println(" kB/sec)");
+ }
+ break;
+
+ case 'g':
+ cmd_sequential_gpio_toggling();
+ break;
+
+ case 'G':
+ cmd_gpio_toggling();
+ break;
+
+ case 'j':
+ cmd_sequential_debug_gpio_toggling();
+ break;
+
+ case 'J':
+ cmd_debug_gpio_toggling();
+ break;
+
+ case 'B':
+ cmd_but_test();
+ break;
+
+ case 'f':
+ SerialUSB.println("Wiggling D4 as fast as possible in bursts. "
+ "Press any key.");
+ pinMode(4, OUTPUT);
+ while (!SerialUSB.available()) {
+ fast_gpio(4);
+ delay(1);
+ }
+ break;
+
+ case 'p':
+ cmd_sequential_pwm_test();
+ break;
+
+ case '_':
+ SerialUSB.println("Delaying for 5 seconds...");
+ delay(5000);
+ break;
+
+ // Be sure to update cmd_print_help() if you implement these:
+
+ case 't': // TODO
+ SerialUSB.println("Unimplemented.");
+ break;
+
+ case 'T': // TODO
+ SerialUSB.println("Unimplemented.");
+ break;
+
+ case 's':
+ cmd_servo_sweep();
+ break;
+
+ // Be sure to update cmd_print_help() if you implement these:
+
+ case 'i': // TODO
+ SerialUSB.println("Unimplemented.");
+ break;
+
+ case 'I': // TODO
+ SerialUSB.println("Unimplemented.");
+ break;
+
+ case 'r':
+ cmd_gpio_monitoring();
+ break;
+
+ case 'a':
+ cmd_sequential_adc_reads();
+ break;
+
+ case 'b':
+ cmd_board_info();
+ break;
+
+ case '+':
+ cmd_gpio_qa();
+ break;
+
+ default: // -------------------------------
+ SerialUSB.print("Unexpected byte: 0x");
+ SerialUSB.print((int)input, HEX);
+ SerialUSB.println(", press h for help.");
+ }
+
+ SerialUSB.print("> ");
+ }
+}
+
+// -- Commands ----------------------------------------------------------------
+
+void cmd_print_help(void) {
+ SerialUSB.println("");
+ SerialUSB.println("Command Listing");
+ SerialUSB.println("\t?: print this menu");
+ SerialUSB.println("\td: Disable SerialUSB (press button to re-enable)");
+ SerialUSB.println("\th: print this menu");
+ SerialUSB.println("\tw: print Hello World on all 3 USARTS");
+ SerialUSB.println("\tn: measure noise and do statistics");
+ SerialUSB.println("\tN: measure noise and do statistics with background "
+ "stuff");
+ SerialUSB.println("\ta: show realtime ADC info");
+ SerialUSB.println("\t.: echo '.' until new input");
+ SerialUSB.println("\tu: print Hello World on USB");
+ SerialUSB.println("\t_: do as little as possible for a couple seconds "
+ "(delay)");
+ SerialUSB.println("\tp: test all PWM channels sequentially");
+ SerialUSB.println("\tW: dump data as fast as possible on all 3 USARTS");
+ SerialUSB.println("\tU: dump data as fast as possible over USB"
+ " and measure data rate");
+ SerialUSB.println("\tg: toggle GPIOs sequentially");
+ SerialUSB.println("\tG: toggle GPIOs at the same time");
+ SerialUSB.println("\tj: toggle debug port GPIOs sequentially");
+ SerialUSB.println("\tJ: toggle debug port GPIOs simultaneously");
+ SerialUSB.println("\tB: test the built-in button");
+ SerialUSB.println("\tf: toggle pin 4 as fast as possible in bursts");
+ SerialUSB.println("\tr: monitor and print GPIO status changes");
+ SerialUSB.println("\ts: output a sweeping servo PWM on all PWM channels");
+ SerialUSB.println("\tm: output data on USART1 and USART3 at various "
+ "baud rates");
+ SerialUSB.println("\tE: echo data on USART1 at various baud rates");
+ SerialUSB.println("\tb: print information about the board.");
+ SerialUSB.println("\t+: test shield mode (for quality assurance testing)");
+
+ SerialUSB.println("Unimplemented:");
+ SerialUSB.println("\te: do everything all at once until new input");
+ SerialUSB.println("\tt: output a 1khz squarewave on all GPIOs");
+ SerialUSB.println("\tT: output a 1hz squarewave on all GPIOs");
+ SerialUSB.println("\ti: print out a bunch of info about system state");
+ SerialUSB.println("\tI: print out status of all headers");
+}
+
+void cmd_adc_stats(void) {
+ SerialUSB.println("Taking ADC noise stats. Press ESC to stop, "
+ "'R' to repeat same pin, anything else for next pin.");
+
+ uint32 i = 0;
+ while (i < BOARD_NR_ADC_PINS) {
+ measure_adc_noise(boardADCPins[i]);
+
+ SerialUSB.println("----------");
+ uint8 c = SerialUSB.read();
+ if (c == ESC) {
+ break;
+ } else if (c != 'r' && c != 'R') {
+ i++;
+ }
+ }
+}
+
+void cmd_stressful_adc_stats(void) {
+ SerialUSB.println("Taking ADC noise stats under duress. Press ESC to "
+ "stop, 'R' to repeat same pin, anything else for next "
+ "pin.");
+
+ uint32 i = 0;
+ while (i < BOARD_NR_ADC_PINS) {
+ // use PWM to create digital noise
+ for (uint32 j = 0; j < BOARD_NR_PWM_PINS; j++) {
+ if (boardADCPins[i] != boardPWMPins[j]) {
+ pinMode(boardPWMPins[j], PWM);
+ pwmWrite(boardPWMPins[j], 1000 + i);
+ }
+ }
+
+ measure_adc_noise(boardADCPins[i]);
+
+ // turn off the noise
+ for (uint32 j = 0; j < BOARD_NR_PWM_PINS; j++) {
+ if (boardADCPins[i] != boardPWMPins[j]) {
+ pinMode(boardPWMPins[j], OUTPUT);
+ digitalWrite(boardPWMPins[j], LOW);
+ }
+ }
+
+ SerialUSB.println("----------");
+ uint8 c = SerialUSB.read();
+ if (c == ESC) {
+ break;
+ } else if (c != 'r' && c != 'R') {
+ i++;
+ }
+ }
+}
+
+void cmd_everything(void) { // TODO
+ // Be sure to update cmd_print_help() if you implement this.
+
+ // print to usart
+ // print to usb
+ // toggle gpios
+ // enable pwm
+ SerialUSB.println("Unimplemented.");
+}
+
+void cmd_serial1_serial3(void) {
+ HardwareSerial *serial_1_and_3[] = {&Serial1, &Serial3};
+
+ SerialUSB.println("Testing 57600 baud on USART1 and USART3. "
+ "Press any key to stop.");
+ serial_baud_test(serial_1_and_3, 2, 57600);
+ SerialUSB.read();
+
+ SerialUSB.println("Testing 115200 baud on USART1 and USART3. "
+ "Press any key to stop.");
+ serial_baud_test(serial_1_and_3, 2, 115200);
+ SerialUSB.read();
+
+ SerialUSB.println("Testing 9600 baud on USART1 and USART3. "
+ "Press any key to stop.");
+ serial_baud_test(serial_1_and_3, 2, 9600);
+ SerialUSB.read();
+
+ SerialUSB.println("Resetting USART1 and USART3...");
+ Serial1.begin(BAUD);
+ Serial3.begin(BAUD);
+}
+
+void cmd_serial1_echo(void) {
+ SerialUSB.println("Testing serial echo at various baud rates. "
+ "Press any key for next baud rate, or ESC to quit "
+ "early.");
+ while (!SerialUSB.available())
+ ;
+
+ if (SerialUSB.read() == ESC) return;
+ SerialUSB.println("Testing 115200 baud on USART1.");
+ serial_echo_test(&Serial1, 115200);
+
+ if (SerialUSB.read() == ESC) return;
+ SerialUSB.println("Testing 57600 baud on USART1.");
+ serial_echo_test(&Serial1, 57600);
+
+ if (SerialUSB.read() == ESC) return;
+ SerialUSB.println("Testing 9600 baud on USART1.");
+ serial_echo_test(&Serial1, 9600);
+}
+
+void cmd_gpio_monitoring(void) {
+ SerialUSB.println("Monitoring pin state changes. Press any key to stop.");
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pinMode(i, INPUT_PULLDOWN);
+ gpio_state[i] = (uint8)digitalRead(i);
+ }
+
+ while (!SerialUSB.available()) {
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+
+ uint8 current_state = (uint8)digitalRead(i);
+ if (current_state != gpio_state[i]) {
+ SerialUSB.print("State change on pin ");
+ SerialUSB.print(i, DEC);
+ if (current_state) {
+ SerialUSB.println(":\tHIGH");
+ } else {
+ SerialUSB.println(":\tLOW");
+ }
+ gpio_state[i] = current_state;
+ }
+ }
+ }
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pinMode(i, OUTPUT);
+ }
+}
+
+void cmd_sequential_adc_reads(void) {
+ SerialUSB.print("Sequentially reading most ADC ports.");
+ SerialUSB.println("Press any key for next port, or ESC to stop.");
+
+ for (uint32 i = 0; i < BOARD_NR_ADC_PINS; i++) {
+ if (boardUsesPin(boardADCPins[i]))
+ continue;
+
+ SerialUSB.print("Reading pin ");
+ SerialUSB.print(boardADCPins[i], DEC);
+ SerialUSB.println("...");
+ pinMode(boardADCPins[i], INPUT_ANALOG);
+ while (!SerialUSB.available()) {
+ int sample = analogRead(boardADCPins[i]);
+ SerialUSB.print(boardADCPins[i], DEC);
+ SerialUSB.print("\t");
+ SerialUSB.print(sample, DEC);
+ SerialUSB.print("\t");
+ SerialUSB.print("|");
+ for (int j = 0; j < 4096; j += 100) {
+ if (sample >= j) {
+ SerialUSB.print("#");
+ } else {
+ SerialUSB.print(" ");
+ }
+ }
+ SerialUSB.print("| ");
+ for (int j = 0; j < 12; j++) {
+ if (sample & (1 << (11 - j))) {
+ SerialUSB.print("1");
+ } else {
+ SerialUSB.print("0");
+ }
+ }
+ SerialUSB.println();
+ }
+ pinMode(boardADCPins[i], OUTPUT);
+ digitalWrite(boardADCPins[i], 0);
+ if (SerialUSB.read() == ESC)
+ break;
+ }
+}
+
+bool test_single_pin_is_high(int high_pin, const char* err_msg) {
+ bool ok = true;
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i)) continue;
+
+ if (digitalRead(i) == HIGH && i != high_pin) {
+ SerialUSB.println();
+ SerialUSB.print("\t*** FAILURE! pin ");
+ SerialUSB.print(i, DEC);
+ SerialUSB.print(' ');
+ SerialUSB.println(err_msg);
+ ok = false;
+ }
+ }
+ return ok;
+}
+
+bool wait_for_low_transition(uint8 pin) {
+ uint32 start = millis();
+ while (millis() - start < 2000) {
+ if (digitalRead(pin) == LOW) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmd_gpio_qa(void) {
+ bool all_pins_ok = true;
+ const int not_a_pin = -1;
+ SerialUSB.println("Doing QA testing for unused GPIO pins.");
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i)) continue;
+
+ pinMode(i, INPUT);
+ }
+
+ SerialUSB.println("Waiting to start.");
+ ASSERT(!boardUsesPin(0));
+ while (digitalRead(0) == LOW) continue;
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i)) {
+ SerialUSB.print("Skipping pin ");
+ SerialUSB.println(i, DEC);
+ continue;
+ }
+ bool pin_ok = true;
+ SerialUSB.print("Checking pin ");
+ SerialUSB.print(i, DEC);
+ while (digitalRead(i) == LOW) continue;
+
+ pin_ok = pin_ok && test_single_pin_is_high(i, "is also HIGH");
+
+ if (!wait_for_low_transition(i)) {
+ SerialUSB.println("Transition to low timed out; something is "
+ "very wrong. Aborting test.");
+ return;
+ }
+
+ pin_ok = pin_ok && test_single_pin_is_high(not_a_pin, "is still HIGH");
+
+ if (pin_ok) {
+ SerialUSB.println(": ok");
+ }
+
+ all_pins_ok = all_pins_ok && pin_ok;
+ }
+
+ if (all_pins_ok) {
+ SerialUSB.println("Finished; test passes.");
+ } else {
+ SerialUSB.println("**** TEST FAILS *****");
+ }
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i)) continue;
+
+ pinMode(i, OUTPUT);
+ digitalWrite(i, LOW);
+ gpio_state[i] = 0;
+ }
+}
+
+void cmd_sequential_gpio_toggling(void) {
+ SerialUSB.println("Sequentially toggling all unused pins. "
+ "Press any key for next pin, ESC to stop.");
+
+ for (uint32 i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+
+ SerialUSB.print("Toggling pin ");
+ SerialUSB.print((int)i, DEC);
+ SerialUSB.println("...");
+
+ pinMode(i, OUTPUT);
+ do {
+ togglePin(i);
+ } while (!SerialUSB.available());
+
+ digitalWrite(i, LOW);
+ if (SerialUSB.read() == ESC)
+ break;
+ }
+}
+
+void cmd_gpio_toggling(void) {
+ SerialUSB.println("Toggling all unused pins simultaneously. "
+ "Press any key to stop.");
+
+ for (uint32 i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pinMode(i, OUTPUT);
+ }
+
+ while (!SerialUSB.available()) {
+ for (uint32 i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ togglePin(i);
+ }
+ }
+
+ for (uint32 i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ digitalWrite(i, LOW);
+ }
+}
+
+uint8 debugGPIOPins[] = {BOARD_JTMS_SWDIO_PIN,
+ BOARD_JTCK_SWCLK_PIN,
+ BOARD_JTDI_PIN,
+ BOARD_JTDO_PIN,
+ BOARD_NJTRST_PIN};
+
+#define N_DEBUG_PINS 5
+
+void cmd_sequential_debug_gpio_toggling(void) {
+ SerialUSB.println("Toggling all debug (JTAG/SWD) pins sequentially. "
+ "This will permanently disable debug port "
+ "functionality.");
+ disableDebugPorts();
+
+ for (int i = 0; i < N_DEBUG_PINS; i++) {
+ pinMode(debugGPIOPins[i], OUTPUT);
+ }
+
+ for (int i = 0; i < N_DEBUG_PINS; i++) {
+ int pin = debugGPIOPins[i];
+ SerialUSB.print("Toggling pin ");
+ SerialUSB.print(pin, DEC);
+ SerialUSB.println("...");
+
+ pinMode(pin, OUTPUT);
+ do {
+ togglePin(pin);
+ } while (!SerialUSB.available());
+
+ digitalWrite(pin, LOW);
+ if (SerialUSB.read() == ESC)
+ break;
+ }
+
+ for (int i = 0; i < N_DEBUG_PINS; i++) {
+ digitalWrite(debugGPIOPins[i], 0);
+ }
+}
+
+void cmd_debug_gpio_toggling(void) {
+ SerialUSB.println("Toggling debug GPIO simultaneously. "
+ "This will permanently disable JTAG and Serial Wire "
+ "debug port functionality. "
+ "Press any key to stop.");
+ disableDebugPorts();
+
+ for (uint32 i = 0; i < N_DEBUG_PINS; i++) {
+ pinMode(debugGPIOPins[i], OUTPUT);
+ }
+
+ while (!SerialUSB.available()) {
+ for (uint32 i = 0; i < N_DEBUG_PINS; i++) {
+ togglePin(debugGPIOPins[i]);
+ }
+ }
+
+ for (uint32 i = 0; i < N_DEBUG_PINS; i++) {
+ digitalWrite(debugGPIOPins[i], LOW);
+ }
+}
+
+void cmd_but_test(void) {
+ SerialUSB.println("Press the button to test. Press any key to stop.");
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+
+ while (!SerialUSB.available()) {
+ if (isButtonPressed()) {
+ uint32 tstamp = millis();
+ SerialUSB.print("Button press detected, timestamp: ");
+ SerialUSB.println(tstamp);
+ }
+ }
+ SerialUSB.read();
+}
+
+void cmd_sequential_pwm_test(void) {
+ SerialUSB.println("Sequentially testing PWM on all unused pins. "
+ "Press any key for next pin, ESC to stop.");
+
+ for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+
+ SerialUSB.print("PWM out on header D");
+ SerialUSB.print(boardPWMPins[i], DEC);
+ SerialUSB.println("...");
+ pinMode(boardPWMPins[i], PWM);
+ pwmWrite(boardPWMPins[i], 16000);
+
+ while (!SerialUSB.available()) {
+ delay(10);
+ }
+
+ pinMode(boardPWMPins[i], OUTPUT);
+ digitalWrite(boardPWMPins[i], 0);
+ if (SerialUSB.read() == ESC)
+ break;
+ }
+}
+
+void cmd_servo_sweep(void) {
+ SerialUSB.println("Testing all PWM headers with a servo sweep. "
+ "Press any key to stop.");
+ SerialUSB.println();
+
+ disable_usarts();
+ init_all_timers(21);
+
+ for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pinMode(boardPWMPins[i], PWM);
+ pwmWrite(boardPWMPins[i], 4000);
+ }
+
+ // 1.25ms = 4096counts = 0deg
+ // 1.50ms = 4915counts = 90deg
+ // 1.75ms = 5734counts = 180deg
+ int rate = 4096;
+ while (!SerialUSB.available()) {
+ rate += 20;
+ if (rate > 5734)
+ rate = 4096;
+ for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pwmWrite(boardPWMPins[i], rate);
+ }
+ delay(20);
+ }
+
+ for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pinMode(boardPWMPins[i], OUTPUT);
+ }
+ init_all_timers(1);
+ enable_usarts();
+}
+
+void cmd_board_info(void) { // TODO print more information
+ SerialUSB.println("Board information");
+ SerialUSB.println("=================");
+
+ SerialUSB.print("* Clock speed (MHz): ");
+ SerialUSB.println(CYCLES_PER_MICROSECOND);
+
+ SerialUSB.print("* BOARD_LED_PIN: ");
+ SerialUSB.println(BOARD_LED_PIN);
+
+ SerialUSB.print("* BOARD_BUTTON_PIN: ");
+ SerialUSB.println(BOARD_BUTTON_PIN);
+
+ SerialUSB.print("* GPIO information (BOARD_NR_GPIO_PINS = ");
+ SerialUSB.print(BOARD_NR_GPIO_PINS);
+ SerialUSB.println("):");
+ print_board_array("ADC pins", boardADCPins, BOARD_NR_ADC_PINS);
+ print_board_array("PWM pins", boardPWMPins, BOARD_NR_PWM_PINS);
+ print_board_array("Used pins", boardUsedPins, BOARD_NR_USED_PINS);
+}
+
+// -- Helper functions --------------------------------------------------------
+
+void measure_adc_noise(uint8 pin) {
+ const int N = 1000;
+ uint16 x;
+ float mean = 0;
+ float delta = 0;
+ float M2 = 0;
+ pinMode(pin, INPUT_ANALOG);
+
+ // Variance algorithm from Welford, via Knuth, by way of Wikipedia:
+ // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm
+ for (int sample = 0; sample < N_ADC_NOISE_MEASUREMENTS; sample++) {
+ for (int i = 1; i <= N; i++) {
+ x = analogRead(pin);
+ delta = x - mean;
+ mean += delta / i;
+ M2 = M2 + delta * (x - mean);
+ }
+ SerialUSB.print("header: D");
+ SerialUSB.print(pin, DEC);
+ SerialUSB.print("\tn: ");
+ SerialUSB.print(N, DEC);
+ SerialUSB.print("\tmean: ");
+ SerialUSB.print(mean);
+ SerialUSB.print("\tvariance: ");
+ SerialUSB.println(M2 / (float)(N-1));
+ }
+
+ pinMode(pin, OUTPUT);
+}
+
+void fast_gpio(int maple_pin) {
+ gpio_dev *dev = PIN_MAP[maple_pin].gpio_device;
+ uint32 bit = PIN_MAP[maple_pin].gpio_bit;
+
+ gpio_write_bit(dev, bit, 1);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+}
+
+void serial_baud_test(HardwareSerial **serials, int n, unsigned baud) {
+ for (int i = 0; i < n; i++) {
+ serials[i]->begin(baud);
+ }
+ while (!SerialUSB.available()) {
+ for (int i = 0; i < n; i++) {
+ serials[i]->println(dummy_data);
+ if (serials[i]->available()) {
+ serials[i]->println(serials[i]->read());
+ delay(1000);
+ }
+ }
+ }
+}
+
+void serial_echo_test(HardwareSerial *serial, unsigned baud) {
+ serial->begin(baud);
+ while (!SerialUSB.available()) {
+ if (!serial->available())
+ continue;
+ serial->print(serial->read());
+ }
+}
+
+static uint16 init_all_timers_prescale = 0;
+
+static void set_prescale(timer_dev *dev) {
+ timer_set_prescaler(dev, init_all_timers_prescale);
+}
+
+void init_all_timers(uint16 prescale) {
+ init_all_timers_prescale = prescale;
+ timer_foreach(set_prescale);
+}
+
+void enable_usarts(void) {
+ Serial1.begin(BAUD);
+ Serial2.begin(BAUD);
+ Serial3.begin(BAUD);
+#if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6)
+ Serial4.begin(BAUD);
+ Serial5.begin(BAUD);
+#endif
+}
+
+void disable_usarts(void) {
+ Serial1.end();
+ Serial2.end();
+ Serial3.end();
+#if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6)
+ Serial4.end();
+ Serial5.end();
+#endif
+}
+
+void print_board_array(const char* msg, const uint8 arr[], int len) {
+ SerialUSB.print("\t");
+ SerialUSB.print(msg);
+ SerialUSB.print(" (");
+ SerialUSB.print(len);
+ SerialUSB.print("): ");
+ for (int i = 0; i < len; i++) {
+ SerialUSB.print(arr[i], DEC);
+ if (i < len - 1) SerialUSB.print(", ");
+ }
+ SerialUSB.println();
+}
+
+// -- premain() and main() ----------------------------------------------------
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-spi-roundtrip.cpp b/examples/test-spi-roundtrip.cpp
new file mode 100644
index 0000000..ddc9875
--- /dev/null
+++ b/examples/test-spi-roundtrip.cpp
@@ -0,0 +1,192 @@
+/*
+ * Polling SPI loopback test.
+ *
+ * Bob is nowhere to be found, so Alice decides to talk to herself.
+ *
+ * Instructions: Connect SPI2 (Alice) to herself (i.e., MISO to MOSI).
+ * Connect to Alice via SerialUSB. Press any key to start.
+ *
+ * Alice will talk to herself for a little while. The sketch will
+ * report if Alice can't hear anything she says. She'll then start
+ * talking forever at various frequencies, bit orders, and modes. Use
+ * an oscilloscope to make sure she's not trying to lie about any of
+ * those things.
+ *
+ * This file is released into the public domain.
+ *
+ * Author: Marti Bolivar <mbolivar@leaflabs.com>
+ */
+
+#include <wirish/wirish.h>
+
+HardwareSPI alice(2);
+
+#define NFREQS 8
+const SPIFrequency spi_freqs[] = {
+ SPI_140_625KHZ,
+ SPI_281_250KHZ,
+ SPI_562_500KHZ,
+ SPI_1_125MHZ,
+ SPI_2_25MHZ,
+ SPI_4_5MHZ,
+ SPI_9MHZ,
+ SPI_18MHZ,
+};
+
+#define TEST_BUF_SIZE 10
+uint8 test_buf[TEST_BUF_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+void bad_assert(const char* file, int line, const char* exp) {
+ SerialUSB.println();
+ SerialUSB.print("ERROR: FAILED ASSERT(");
+ SerialUSB.print(exp);
+ SerialUSB.print("): ");
+ SerialUSB.print(file);
+ SerialUSB.print(": ");
+ SerialUSB.println(line);
+ throb();
+}
+
+#undef ASSERT
+#define ASSERT(exp) \
+ if (exp) { \
+ } else { \
+ bad_assert(__FILE__, __LINE__, #exp); \
+ }
+
+void haveConversation(uint32 bitOrder);
+void soliloquies(uint32 bitOrder);
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ SerialUSB.read();
+}
+
+void loop() {
+ SerialUSB.println("** Having a conversation, MSB first");
+ haveConversation(MSBFIRST);
+
+ SerialUSB.println("** Having a conversation, LSB first");
+ haveConversation(LSBFIRST);
+
+ SerialUSB.println();
+ SerialUSB.println("*** All done! It looks like everything worked.");
+ SerialUSB.println();
+
+ SerialUSB.println("** Alice will now wax eloquent in various styles. "
+ "Press any key for the next configuration.");
+ soliloquies(MSBFIRST);
+ soliloquies(LSBFIRST);
+
+ while (true)
+ ;
+}
+
+void printFrequencyString(SPIFrequency frequency);
+void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode);
+
+void haveConversation(uint32 bitOrder) {
+ for (int f = 0; f < NFREQS; f++) {
+ for (int mode = 0; mode < 4; mode++) {
+ chat(spi_freqs[f], bitOrder, mode);
+ delay(10);
+ }
+ }
+}
+
+void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode) {
+ SerialUSB.print("Having a chat.\tFrequency: ");
+ printFrequencyString(frequency);
+ SerialUSB.print(",\tbitOrder: ");
+ SerialUSB.print(bitOrder == MSBFIRST ? "MSB" : "LSB");
+ SerialUSB.print(",\tmode: ");
+ SerialUSB.print(mode);
+ SerialUSB.print(".");
+
+ SerialUSB.print(" [1] ");
+ alice.begin(frequency, bitOrder, mode);
+
+ SerialUSB.print(" [2] ");
+ uint32 txed = 0;
+ while (txed < TEST_BUF_SIZE) {
+ ASSERT(alice.transfer(test_buf[txed]) == test_buf[txed]);
+ txed++;
+ }
+
+ SerialUSB.print(" [3] ");
+ alice.end();
+
+ SerialUSB.println(" ok.");
+}
+
+void soliloquy(SPIFrequency freq, uint32 bitOrder, uint32 mode);
+
+void soliloquies(uint32 bitOrder) {
+ for (int f = 0; f < NFREQS; f++) {
+ for (int mode = 0; mode < 4; mode++) {
+ soliloquy(spi_freqs[f], bitOrder, mode);
+ }
+ }
+}
+
+void soliloquy(SPIFrequency frequency, uint32 bitOrder, uint32 mode) {
+ const uint8 repeat = 0xAE;
+ SerialUSB.print("Alice is giving a soliloquy (repeating 0x");
+ SerialUSB.print(repeat, HEX);
+ SerialUSB.print("). Frequency: ");
+ printFrequencyString(frequency);
+ SerialUSB.print(", bitOrder: ");
+ SerialUSB.print(bitOrder == MSBFIRST ? "big-endian" : "little-endian");
+ SerialUSB.print(", SPI mode: ");
+ SerialUSB.println(mode);
+
+ alice.begin(frequency, bitOrder, mode);
+ while (!SerialUSB.available()) {
+ alice.write(repeat);
+ delayMicroseconds(200);
+ }
+ SerialUSB.read();
+}
+
+void printFrequencyString(SPIFrequency frequency) {
+ switch (frequency) {
+ case SPI_18MHZ:
+ SerialUSB.print("18 MHz");
+ break;
+ case SPI_9MHZ:
+ SerialUSB.print("9 MHz");
+ break;
+ case SPI_4_5MHZ:
+ SerialUSB.print("4.5 MHz");
+ break;
+ case SPI_2_25MHZ:
+ SerialUSB.print("2.25 MHZ");
+ break;
+ case SPI_1_125MHZ:
+ SerialUSB.print("1.125 MHz");
+ break;
+ case SPI_562_500KHZ:
+ SerialUSB.print("562.500 KHz");
+ break;
+ case SPI_281_250KHZ:
+ SerialUSB.print("281.250 KHz");
+ break;
+ case SPI_140_625KHZ:
+ SerialUSB.print("140.625 KHz");
+ break;
+ }
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-systick.cpp b/examples/test-systick.cpp
new file mode 100644
index 0000000..356f302
--- /dev/null
+++ b/examples/test-systick.cpp
@@ -0,0 +1,49 @@
+// Tests the SysTick enable/disable functions
+
+#include <wirish/wirish.h>
+#include <libmaple/systick.h>
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+}
+
+bool disable = true;
+long time = 0;
+
+void loop() {
+ volatile int i = 0;
+ toggleLED();
+
+ // An artificial delay
+ for(i = 0; i < 150000; i++)
+ ;
+
+ if (isButtonPressed()) {
+ if (disable) {
+ systick_disable();
+ SerialUSB.println("Disabling SysTick");
+ } else {
+ SerialUSB.println("Re-enabling SysTick");
+ systick_enable();
+ }
+ disable = !disable;
+ }
+
+ SerialUSB.println(millis());
+}
+
+// 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() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp
new file mode 100644
index 0000000..e646916
--- /dev/null
+++ b/examples/test-timers.cpp
@@ -0,0 +1,537 @@
+//
+// This is a mostly Wirish-free timer test. Wirish usage is minimized
+// because this is a test of the C timer interface in
+// <libmaple/timer.h>, so it's good if it can be made to work even
+// when most or all of Wirish is missing. Because of that, you may
+// need to customize the following output configuration:
+//
+// Output is printed:
+// - on COMM_USART,
+// - via TX pin on port COMM_USART_PORT, bit COMM_USART_TX_BIT
+// - via RX pin on port COMM_USART_PORT, bit COMM_USART_RX_BIT
+// - at COMM_USART_BAUD baud.
+#define COMM_USART USART6
+#define COMM_USART_BAUD 115200
+#define COMM_USART_PORT GPIOG
+#define COMM_USART_TX_BIT 14
+#define COMM_USART_RX_BIT 9
+// Other optional configuration below.
+
+#include <libmaple/libmaple.h>
+#include <libmaple/gpio.h>
+#include <libmaple/usart.h>
+#include <libmaple/systick.h>
+#include <libmaple/timer.h>
+#include <wirish/boards.h>
+
+//
+// Configuration
+//
+
+// More output if true
+static bool verbose = true;
+
+// Timers to test
+// FIXME use feature test macros for smaller MCUs
+static timer_dev *timers[] = {
+ // Available on all currently supported MCUs
+ TIMER1, TIMER2, TIMER3, TIMER4,
+ // Available on F1 (HD and up), F2
+ TIMER5, TIMER6, TIMER7, TIMER8,
+ // Available on F1 (XL), F2
+ TIMER9, TIMER10, TIMER11, TIMER12, TIMER13, TIMER14,
+};
+
+//
+// Test routines
+//
+
+typedef void (*timer_test_t)(timer_dev *);
+
+static void runTest(const char description[], timer_test_t test);
+static void runTests(void);
+
+static void testGetAndSetCount(timer_dev*);
+static void testPauseAndResume(timer_dev*);
+static void testTimerChannels(timer_dev*);
+
+//
+// Helpers
+//
+
+static void initTimer(timer_dev *dev);
+static int timerNumber(timer_dev *dev);
+// Hack: a systick-based delay, useful until delay_us() is fixed
+static void _delay(uint32 msec);
+// Wirish-less USART initialization routine
+static void init_usart(usart_dev *dev, gpio_dev *gdev, uint8 tx, uint8 rx);
+// Return whether or not the timer has capture/compare channel `ch'.
+// TODO: does something like this belong in the standard timer library?
+static bool timer_has_cc_ch(timer_dev *dev, int ch);
+
+// Printing routines and variants for verbose mode
+static void putstr(const char str[]);
+static void println(void);
+static void putstrln(const char str[]);
+static void putudec(uint32 val);
+static void puttimn(timer_dev *dev);
+static void v_putstr(const char str[]);
+static void v_println();
+static void v_putstrln(const char str[]);
+static void v_putudec(uint32 val);
+static void v_puttimn(timer_dev *dev);
+// Used to visually separate output from different tests
+static void printBanner(void);
+
+//
+// Handler state
+//
+
+static int count1 = 0;
+static int count2 = 0;
+static int count3 = 0;
+static int count4 = 0;
+static int timer_num; // Current timer we're considering
+
+//
+// Timer capture/compare interrupt handlers
+//
+// These are shared between timers. The global variable timer_num
+// controls which timer they affect.
+//
+
+static void handler1(void);
+static void handler2(void);
+static void handler3(void);
+static void handler4(void);
+static voidFuncPtr handlers[] = {handler1, handler2, handler3, handler4};
+
+//
+// setup() and loop()
+//
+
+void setup() {
+ init_usart(COMM_USART, COMM_USART_PORT,
+ COMM_USART_TX_BIT, COMM_USART_RX_BIT);
+ _delay(5);
+ println();
+ printBanner();
+ putstr("Initializing timers...\r\n");
+ timer_foreach(initTimer);
+ putstr("Done. Running tests.\r\n");
+ runTests();
+ printBanner();
+ putstr("Done testing timers.\r\n");
+}
+
+void loop() {
+}
+
+//
+// Test routine implementations
+//
+
+static void runTests(void) {
+ runTest("timer_get_count()/timer_set_count()", testGetAndSetCount);
+ runTest("timer_pause()/timer_resume()", testPauseAndResume);
+ runTest("capture/compare channels and interrupts",
+ testTimerChannels);
+}
+
+static void runTest(const char description[], timer_test_t test) {
+ printBanner();
+ putstr("Testing ");
+ putstr(description);
+ putstrln(".");
+ timer_foreach(test);
+}
+
+static void testGetAndSetCount(timer_dev *dev) {
+ unsigned before, after;
+ unsigned val_to_set = 1234;
+
+ timer_pause(dev);
+ before = timer_get_count(dev);
+ timer_set_count(dev, val_to_set);
+ after = timer_get_count(dev);
+ timer_resume(dev);
+
+ if (after != val_to_set) {
+ puttimn(dev);
+ putstr(": ");
+ putstr("*** FAIL: get/set count for ");
+ puttimn(dev);
+ putstr(".");
+ putstr("Start count = ");
+ putudec(before);
+ putstr(". Count set to ");
+ putudec(val_to_set);
+ putstr(", and now count is = ");
+ putudec(after);
+ println();
+ } else if (verbose) {
+ puttimn(dev);
+ putstr(": ");
+ putstrln("[ok]");
+ }
+}
+
+// This hack works on all currently supported STM32 series, but you
+// may need to do something smarter in the future. The assertions
+// ensure that our assumptions hold for your target.
+static timer_dev *getDifferentTimerOnSameBusAs(timer_dev *dev) {
+ rcc_clk_domain dev_domain = rcc_dev_clk(dev->clk_id);
+ ASSERT(RCC_APB1 == dev_domain || RCC_APB2 == dev_domain);
+ ASSERT(rcc_dev_clk(TIMER1->clk_id) == RCC_APB2);
+ ASSERT(rcc_dev_clk(TIMER2->clk_id) == RCC_APB1);
+ ASSERT(rcc_dev_clk(TIMER8->clk_id) == RCC_APB2);
+ ASSERT(rcc_dev_clk(TIMER3->clk_id) == RCC_APB1);
+
+ if (dev->clk_id == RCC_TIMER1) {
+ return TIMER8;
+ }
+ if (dev->clk_id == RCC_TIMER2) {
+ return TIMER3;
+ }
+ return dev_domain == RCC_APB2 ? TIMER1 : TIMER2;
+}
+
+// Rough test of pause and resume.
+//
+// Approximately half the time, dev is in the "pause" state and the
+// timer doesn't increment, while another timer (`base_dev') on the
+// same bus continues. dev and base_dev have identical start counts
+// and prescalers.
+//
+// Since dev and base_dev share a bus (and thus a base clock), and we
+// configure them to have the same prescaler and start count, the
+// ratio of their end counts should be approximately 1 : 2. We check
+// to make sure this is true, up to tolerance `epsilon'.
+static void testPauseAndResume(timer_dev *dev) {
+ timer_dev *base_dev = getDifferentTimerOnSameBusAs(dev);
+ unsigned start_count = 0, reload = 65535;
+ // This prescaler should be enough to ensure that we don't
+ // overflow, while still giving us a reasonably large number of
+ // timer ticks.
+ uint16 prescaler = CYCLES_PER_MICROSECOND * 50;
+ double epsilon = .02;
+
+ if (rcc_dev_clk(base_dev->clk_id) != rcc_dev_clk(dev->clk_id)) {
+ putstrln("*** ERROR: cannot run test. Bus info is messed up.");
+ return;
+ }
+
+ // Pause and set up timers
+ timer_pause(base_dev);
+ timer_pause(dev);
+ timer_set_count(base_dev, start_count);
+ timer_set_count(dev, start_count);
+ timer_set_reload(base_dev, reload);
+ timer_set_reload(dev, reload);
+ timer_set_prescaler(base_dev, prescaler);
+ timer_set_prescaler(dev, prescaler);
+ timer_generate_update(base_dev);
+ timer_generate_update(dev);
+
+ // Resume the timers and run the test
+ ASSERT(timer_get_count(base_dev) == start_count);
+ ASSERT(timer_get_count(dev) == start_count);
+ timer_resume(base_dev);
+ timer_resume(dev);
+ _delay(1000);
+ timer_pause(dev);
+ _delay(1000);
+ timer_pause(base_dev);
+
+ // Check the results
+ unsigned dev_count = timer_get_count(dev);
+ unsigned base_count = timer_get_count(base_dev);
+ double count_ratio = ((double)dev_count / base_count);
+ bool fail = false;
+ if (count_ratio > 0.5 + epsilon || count_ratio < 0.5 - epsilon) {
+ fail = true;
+ }
+ if (fail || verbose) {
+ puttimn(dev);
+ putstr(" vs. ");
+ puttimn(base_dev);
+ putstr(": ");
+ if (fail) putstr("*** FAIL: ");
+ else putstr("[ok] ");
+ putstr("(dev = ");
+ putudec(dev_count);
+ putstr(") / (base = ");
+ putudec(base_count);
+ putstr(") = ");
+ // hack hack hack
+ putudec((int)count_ratio);
+ count_ratio -= (int)count_ratio;
+ putstr(".");
+ int cr_x_100 = (int)(count_ratio * 100);
+ int hundredths = cr_x_100 % 10;
+ cr_x_100 /= 10;
+ int tenths = cr_x_100 % 10;
+ putudec(tenths);
+ putudec(hundredths);
+ println();
+ }
+}
+
+// This function touches every capture/compare channel of a given
+// timer. The channel counts should be equal within a timer
+// regardless of other interrupts on the system (note that this
+// doesn't really test timers with only a single capture/compare
+// channel; for that, you'll want to do visual inspection of timers
+// that share a bus, in verbose mode).
+static void testTimerChannels(timer_dev *dev) {
+ switch (dev->type) {
+ case TIMER_BASIC:
+ v_putstr("Skipping basic timer ");
+ v_puttimn(dev);
+ v_println();
+ return;
+ case TIMER_ADVANCED:
+ case TIMER_GENERAL:
+ // Set up
+ v_puttimn(dev);
+ v_println();
+ v_putstr("\tchannels: ");
+
+ timer_num = timerNumber(dev);
+ timer_pause(dev);
+ count1 = 0;
+ count2 = 0;
+ count3 = 0;
+ count4 = 0;
+ timer_set_reload(dev, 0xFFFF);
+ timer_set_prescaler(dev, 1);
+ for (int c = 1; c <= 4; c++) {
+ if (timer_has_cc_ch(dev, c)) {
+ v_putudec(c);
+ v_putstr("\t");
+ timer_set_compare(dev, c, 0xFFFF);
+ timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE);
+ timer_attach_interrupt(dev, c, handlers[c - 1]);
+ }
+ }
+ v_println();
+
+ // Run test
+ timer_generate_update(dev);
+ timer_resume(dev);
+ _delay(250);
+ timer_pause(dev);
+
+ // Print results
+ v_putstr("\tcounts: ");
+ bool fail = false;
+ bool mismatched[4] = {false, false, false, false};
+ int counts[4];
+ counts[0] = count1;
+ counts[1] = count2;
+ counts[2] = count3;
+ counts[3] = count4;
+ bool first = true;
+ int first_count = -1;
+ for (int c = 1; c <= 4; c++) {
+ if (timer_has_cc_ch(dev, c)) {
+ if (first) {
+ first_count = counts[c - 1];
+ first = false;
+ }
+ if (!first && (counts[c - 1] != first_count)) {
+ mismatched[c - 1] = true;
+ fail = true;
+ }
+ v_putudec(counts[c - 1]);
+ v_putstr("\t");
+ }
+ }
+ v_println();
+ if (fail) {
+ for (int i = 0; i < 4; i++) {
+ if (mismatched[i]) {
+ putstr("*** FAIL: mismatch on ");
+ puttimn(dev);
+ putstr(", channel ");
+ putudec(i + 1);
+ putstr(": expected ");
+ putudec(first_count);
+ putstr(", got ");
+ putudec(counts[i]);
+ println();
+ }
+ }
+ } else {
+ puttimn(dev);
+ putstrln(" [ok]");
+ }
+ v_println();
+
+ // Clean up
+ for (int c = 1; c <= 4; c++) {
+ if (timer_has_cc_ch(dev, c)) {
+ timer_set_mode(dev, c, TIMER_DISABLED);
+ }
+ }
+ break;
+ }
+}
+
+//
+// Helper implementations
+//
+
+static void _delay(uint32 msec) {
+ uint32 end = systick_uptime() + msec;
+ while (systick_uptime() < end)
+ ;
+}
+
+static void init_usart(usart_dev *dev, gpio_dev *gdev, uint8 tx, uint8 rx) {
+ usart_config_gpios_async(dev, gdev, rx, gdev, tx, 0);
+ usart_init(dev);
+ usart_set_baud_rate(dev, USART_USE_PCLK, COMM_USART_BAUD);
+ usart_enable(dev);
+}
+
+static bool timer_has_cc_ch(timer_dev *dev, int ch) {
+ ASSERT(1 <= ch && ch <= 4);
+ if (dev->type == TIMER_BASIC)
+ return false;
+ int tn = timerNumber(dev);
+ return (// TIM1-5 and 8 have all four channels
+ (tn <= 5 || tn == 8) ||
+ // TIM9 and 12 only have channels 1 and 2
+ ((tn == 9 || tn == 12) && ch <= 2) ||
+ // All other general purpose timers only have channel 1
+ (ch == 1));
+}
+
+static void putstr(const char str[]) {
+ usart_putstr(COMM_USART, str);
+}
+
+static void println(void) {
+ putstr("\r\n");
+}
+
+static void putstrln(const char str[]) {
+ putstr(str);
+ println();
+}
+
+static void putudec(uint32 val) {
+ usart_putudec(COMM_USART, val);
+}
+
+static void puttimn(timer_dev *dev) {
+ putstr("TIM");
+ putudec(timerNumber(dev));
+}
+
+static void v_putstr(const char str[]) {
+ if (verbose) putstr(str);
+}
+
+static void v_println() {
+ if (verbose) println();
+}
+
+__attribute__((unused)) /* (shut up, gcc) */
+static void v_putstrln(const char str[]) {
+ if (verbose) putstrln(str);
+}
+
+static void v_putudec(uint32 val) {
+ if (verbose) putudec(val);
+}
+
+static void v_puttimn(timer_dev *dev) {
+ if (verbose) puttimn(dev);
+}
+
+// Used to visually separate output from different tests
+static void printBanner(void) {
+ putstrln("-----------------------------------------------------");
+}
+
+static void initTimer(timer_dev *dev) {
+ v_puttimn(dev);
+ timer_init(dev);
+ switch (dev->type) {
+ case TIMER_ADVANCED:
+ case TIMER_GENERAL:
+ v_putstr(" channels ");
+ for (int c = 1; c <= 4; c++) {
+ if (timer_has_cc_ch(dev, c)) {
+ v_putudec(c);
+ v_putstr(" ");
+ timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE);
+ }
+ }
+ break;
+ case TIMER_BASIC:
+ break;
+ }
+ v_println();
+}
+
+static int timerNumber(timer_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_TIMER1: return 1;
+ case RCC_TIMER2: return 2;
+ case RCC_TIMER3: return 3;
+ case RCC_TIMER4: return 4;
+ case RCC_TIMER5: return 5;
+ case RCC_TIMER6: return 6;
+ case RCC_TIMER7: return 7;
+ case RCC_TIMER8: return 8;
+ case RCC_TIMER9: return 9;
+ case RCC_TIMER10: return 10;
+ case RCC_TIMER11: return 11;
+ case RCC_TIMER12: return 12;
+ case RCC_TIMER13: return 13;
+ case RCC_TIMER14: return 14;
+ default:
+ ASSERT(0);
+ return 0;
+ }
+}
+
+//
+// IRQ Handlers
+//
+
+static void handler1(void) {
+ count1++;
+}
+
+static void handler2(void) {
+ count2++;
+}
+
+static void handler3(void) {
+ count3++;
+}
+
+static void handler4(void) {
+ count4++;
+}
+
+//
+// init() and main()
+//
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-usart-dma.cpp b/examples/test-usart-dma.cpp
new file mode 100644
index 0000000..d10dc68
--- /dev/null
+++ b/examples/test-usart-dma.cpp
@@ -0,0 +1,211 @@
+/**
+ * @file examples/test-usart-dma.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ *
+ * Simple test of DMA used with a USART receiver.
+ *
+ * Configures a USART receiver for use with DMA. Received bytes are
+ * placed into a buffer, with an interrupt firing when the buffer is
+ * full. At that point, the USART transmitter will print the contents
+ * of the byte buffer. The buffer is continually filled and refilled
+ * in this manner.
+ *
+ * This example isn't very robust; don't use it in production. In
+ * particular, since the buffer keeps filling (DMA_CIRC_MODE is set),
+ * if you keep sending characters after filling the buffer, you'll
+ * overwrite earlier bytes; this may happen before those earlier bytes
+ * are done printing. (Typing quickly and seeing how it affects the
+ * output is a fun way to make sense of how the interrupts and the
+ * main thread of execution interleave.)
+ *
+ * This code is released into the public domain.
+ */
+
+#include <libmaple/dma.h>
+#include <libmaple/usart.h>
+#include <libmaple/gpio.h>
+
+#include <wirish/wirish.h>
+
+/*
+ * Configuration and state
+ */
+
+// Serial port and DMA configuration. You can change these to suit
+// your purposes.
+HardwareSerial *serial = &Serial2;
+#define USART_DMA_DEV DMA1
+#if STM32_MCU_SERIES == STM32_SERIES_F1
+// On STM32F1 microcontrollers (like what's on Maple and Maple Mini),
+// dma tubes are channels.
+#define USART_RX_DMA_TUBE DMA_CH6
+#elif (STM32_MCU_SERIES == STM32_SERIES_F2 || \
+ STM32_MCU_SERIES == STM32_SERIES_F4)
+// On STM32F2 and STM32F4 microcontrollers (Maple 2 will have an F4),
+// dma tubes are streams.
+#define USART_RX_DMA_TUBE DMA_S5
+#else
+#error "unsupported stm32 series"
+#endif
+// The serial port will make a DMA request each time it receives data.
+// This is the dma_request_src we use to tell the DMA tube to handle
+// that DMA request.
+#define USART_DMA_REQ_SRC DMA_REQ_SRC_USART2_RX
+#define BAUD 9600
+
+// This will store the DMA configuration for USART RX.
+dma_tube_config tube_config;
+
+// This will store received USART characters.
+#define BUF_SIZE 20
+char rx_buf[BUF_SIZE];
+
+// The interrupt handler, rx_dma_irq(), sets this to 1.
+volatile uint32 irq_fired = 0;
+// Used to store DMA interrupt status register (ISR) bits inside
+// rx_dma_irq(). This helps explain what's going on inside loop(); see
+// comments below.
+volatile uint32 isr = 0;
+
+/*
+ * Helper functions
+ */
+
+// This is our DMA interrupt handler.
+void rx_dma_irq(void) {
+ irq_fired = 1;
+ isr = dma_get_isr_bits(USART_DMA_DEV, USART_RX_DMA_TUBE);
+}
+
+// Configure the USART receiver for use with DMA:
+// 1. Turn it on.
+// 2. Set the "DMA request on RX" bit in USART_CR3 (USART_CR3_DMAR).
+void setup_usart(void) {
+ serial->begin(BAUD);
+ usart_dev *serial_dev = serial->c_dev();
+ serial_dev->regs->CR3 = USART_CR3_DMAR;
+}
+
+// Set up our dma_tube_config structure. (We could have done this
+// above, when we declared tube_config, but having this function makes
+// it easier to explain what's going on).
+void setup_tube_config(void) {
+ // We're receiving from the USART data register. serial->c_dev()
+ // returns a pointer to the libmaple usart_dev for that serial
+ // port, so this is a pointer to its data register.
+ tube_config.tube_src = &serial->c_dev()->regs->DR;
+ // We're only interested in the bottom 8 bits of that data register.
+ tube_config.tube_src_size = DMA_SIZE_8BITS;
+ // We're storing to rx_buf.
+ tube_config.tube_dst = rx_buf;
+ // rx_buf is a char array, and a "char" takes up 8 bits on STM32.
+ tube_config.tube_dst_size = DMA_SIZE_8BITS;
+ // Only fill BUF_SIZE - 1 characters, to leave a null byte at the end.
+ tube_config.tube_nr_xfers = BUF_SIZE - 1;
+ // Flags:
+ // - DMA_CFG_DST_INC so we start at the beginning of rx_buf and
+ // fill towards the end.
+ // - DMA_CFG_CIRC so we go back to the beginning and start over when
+ // rx_buf fills up.
+ // - DMA_CFG_CMPLT_IE to turn on interrupts on transfer completion.
+ tube_config.tube_flags = DMA_CFG_DST_INC | DMA_CFG_CIRC | DMA_CFG_CMPLT_IE;
+ // Target data: none. It's important to set this to NULL if you
+ // don't have any special (microcontroller-specific) configuration
+ // in mind, which we don't.
+ tube_config.target_data = NULL;
+ // DMA request source.
+ tube_config.tube_req_src = USART_DMA_REQ_SRC;
+}
+
+// Configure the DMA controller to serve DMA requests from the USART.
+void setup_dma_xfer(void) {
+ // First, turn it on.
+ dma_init(USART_DMA_DEV);
+ // Next, configure it by calling dma_tube_cfg(), and check to make
+ // sure it succeeded. DMA tubes have many restrictions on their
+ // configuration, and there are configurations which work on some
+ // types of STM32 but not others. libmaple tries hard to make
+ // things just work, but checking the return status is important!
+ int status = dma_tube_cfg(USART_DMA_DEV, USART_RX_DMA_TUBE, &tube_config);
+ ASSERT(status == DMA_TUBE_CFG_SUCCESS);
+ // Now we'll perform any other configuration we want. For this
+ // example, we attach an interrupt handler.
+ dma_attach_interrupt(USART_DMA_DEV, USART_RX_DMA_TUBE, rx_dma_irq);
+ // Turn on the DMA tube. It will now begin serving requests.
+ dma_enable(USART_DMA_DEV, USART_RX_DMA_TUBE);
+}
+
+/*
+ * setup() and loop()
+ */
+
+void setup(void) {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ setup_tube_config();
+ setup_dma_xfer();
+ setup_usart();
+}
+
+void loop(void) {
+ toggleLED();
+ delay(100);
+
+ // See if the interrupt handler got called since the last time we
+ // checked.
+ if (irq_fired) {
+ serial->println("** IRQ **");
+ // Notice how the interrupt status register (ISR) bits show
+ // transfer complete _and_ half-complete here, but the ISR
+ // bits we print next will be zero. That's because the
+ // variable "isr" gets set _inside_ rx_dma_irq(). After it
+ // exits, libmaple cleans up by clearing the tube's ISR
+ // bits. (If it didn't, and we forgot to, the interrupt would
+ // repeatedly fire forever.)
+ serial->print("ISR bits: 0x");
+ serial->println(isr, HEX);
+ irq_fired = 0;
+ }
+
+ // Print the ISR bits.
+ //
+ // Notice that the "transfer half-complete" ISR flag gets set when
+ // we reach the rx_buf half-way point. This is true even though we
+ // don't tell the DMA controller to interrupt us on a
+ // half-complete transfer. That is, the ISR bits get set at the
+ // right times no matter what; we just don't get interrupted
+ // unless we asked. (If an error or other problem occurs, the
+ // relevant ISR bits will get set in the same way).
+ serial->print("[");
+ serial->print(millis());
+ serial->print("]\tISR bits: 0x");
+ uint8 isr_bits = dma_get_isr_bits(USART_DMA_DEV, USART_RX_DMA_TUBE);
+ serial->print(isr_bits, HEX);
+
+ // Print the contents of rx_buf. If you keep typing after it fills
+ // up, the new characters will overwrite the old ones, thanks to
+ // DMA_CIRC_MODE.
+ serial->print("\tCharacter buffer contents: '");
+ serial->print(rx_buf);
+ serial->println("'");
+ if (isr_bits == 0x7) {
+ serial->println("** Clearing ISR bits.");
+ dma_clear_isr_bits(USART_DMA_DEV, USART_RX_DMA_TUBE);
+ }
+}
+
+// ------- init() and main() --------------------------------------------------
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/vga-leaf.cpp b/examples/vga-leaf.cpp
new file mode 100644
index 0000000..5159956
--- /dev/null
+++ b/examples/vga-leaf.cpp
@@ -0,0 +1,244 @@
+/*
+ VGA Output
+
+ Outputs a red and white leaf to VGA. It should run most VGA monitors
+ at 640x480, though it does not follow the timing spec very
+ carefully. Real twisted or shielded wires, proper grounding, and not
+ doing this on a breadboard are recommended (but it seems to work ok
+ without).
+
+ SerialUSB and SysTick are disabled to get rid of the most frequently
+ occurring interrupts (which mess with timing). This means that you
+ have to use perpetual bootloader mode or the reset button to flash
+ new programs.
+
+ How to wire this to a VGA port:
+ D6 via ~200ohms to VGA Red (1)
+ D7 via ~200ohms to VGA Green (2)
+ D8 via ~200ohms to VGA Blue (3)
+ D11 to VGA VSync (14) (swapped?)
+ D12 to VGA HSync (13) (swapped?)
+ GND to VGA Ground (5)
+ GND to VGA Sync Ground (10)
+
+ See also:
+ - http://pinouts.ru/Video/VGA15_pinout.shtml
+ - http://www.epanorama.net/documents/pc/vga_timing.html
+
+ Created 20 July 2010
+ By Bryan Newbold for LeafLabs
+ This code is released with no strings attached.
+ */
+
+// FIXME: generalize for Native and Mini
+
+#include <wirish/wirish.h>
+
+// Pinouts -- you also must change the GPIO macros below if you change
+// these
+#define VGA_R 6 // STM32: A8
+#define VGA_G 7 // STM32: A9
+#define VGA_B 8 // STM32: A10
+#define VGA_V 11 // STM32: A6
+#define VGA_H 12 // STM32: A7
+
+// These low level (and STM32 specific) macros make GPIO writes much
+// faster
+#define ABSRR ((volatile uint32*)0x40010810)
+#define ABRR ((volatile uint32*)0x40010814)
+
+#define RBIT 8 // (see pinouts)
+#define GBIT 9
+#define BBIT 10
+
+#define VGA_R_HIGH *ABSRR = BIT(RBIT)
+#define VGA_R_LOW *ABRR = BIT(RBIT)
+#define VGA_G_HIGH *ABSRR = BIT(GBIT)
+#define VGA_G_LOW *ABRR = BIT(GBIT)
+#define VGA_B_HIGH *ABSRR = BIT(BBIT)
+#define VGA_B_LOW *ABRR = BIT(BBIT)
+
+#define ON_COLOR BIT(RBIT)
+#define OFF_COLOR (BIT(RBIT) | BIT(GBIT) | BIT(BBIT))
+
+// set has priority, so clear every bit and set some given bits:
+#define VGA_COLOR(c) (*ABSRR = c | \
+ BIT(RBIT+16) | BIT(GBIT+16) | BIT(BBIT+16))
+
+#define VGA_V_HIGH *ABSRR = BIT(6)
+#define VGA_V_LOW *ABRR = BIT(6)
+#define VGA_H_HIGH *ABSRR = BIT(7)
+#define VGA_H_LOW *ABRR = BIT(7)
+
+void isr_porch(void);
+void isr_start(void);
+void isr_stop(void);
+void isr_update(void);
+
+uint16 x = 0; // X coordinate
+uint16 y = 0; // Y coordinate
+uint16 logo_y = 0; // Y coordinate, mapped into valid logo index (for speed)
+bool v_active = true; // Are we in the image?
+
+const uint8 x_max = 16;
+const uint8 y_max = 18;
+uint32 logo[y_max][x_max] = {
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+ {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,},
+ {0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,},
+ {0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,},
+ {0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,},
+ {0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,},
+ {0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,0,},
+ {0,1,0,0,0,0,1,1,1,0,0,0,0,1,0,0,},
+ {0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,},
+ {1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,},
+ {1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,},
+ {1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,},
+ {0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,},
+ {0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0,},
+ {0,0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,},
+ {0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,},
+ {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, };
+
+HardwareTimer timer(4);
+
+void setup() {
+ // Setup our pins
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ pinMode(VGA_R, OUTPUT);
+ pinMode(VGA_G, OUTPUT);
+ pinMode(VGA_B, OUTPUT);
+ pinMode(VGA_V, OUTPUT);
+ pinMode(VGA_H, OUTPUT);
+ digitalWrite(VGA_R, LOW);
+ digitalWrite(VGA_G, LOW);
+ digitalWrite(VGA_B, LOW);
+ digitalWrite(VGA_H, HIGH);
+ digitalWrite(VGA_V, HIGH);
+
+ // Fill the logo array with color patterns corresponding to its
+ // truth value. Note that we could get more tricky here, since
+ // there are 3 bits of color.
+ for (int y = 0; y < y_max; y++) {
+ for (int x = 0; x < x_max; x++) {
+ logo[y][x] = logo[y][x] ? ON_COLOR : OFF_COLOR;
+ }
+ }
+
+ // This gets rid of the majority of the interrupt artifacts;
+ // there's still a glitch for low values of y, but let's not worry
+ // about that. (Probably due to the hackish way vsync is done).
+ SerialUSB.end();
+ systick_disable();
+
+ // Configure
+ timer.pause(); // while we configure
+ timer.setPrescaleFactor(1); // Full speed
+ timer.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
+ timer.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE);
+ timer.setMode(TIMER_CH3, TIMER_OUTPUT_COMPARE);
+ timer.setMode(TIMER_CH4, TIMER_OUTPUT_COMPARE);
+ timer.setOverflow(2287); // Total line time
+
+ timer.setCompare(TIMER_CH1, 200);
+ timer.attachInterrupt(TIMER_CH1, isr_porch);
+ timer.setCompare(TIMER_CH2, 300);
+ timer.attachInterrupt(TIMER_CH2, isr_start);
+ timer.setCompare(TIMER_CH3, 2170);
+ timer.attachInterrupt(TIMER_CH3, isr_stop);
+ timer.setCompare(TIMER_CH4, 1); // Could be zero, I guess
+ timer.attachInterrupt(TIMER_CH4, isr_update);
+
+ timer.setCount(0); // Ready...
+ timer.resume(); // Go!
+}
+
+void loop() {
+ toggleLED();
+ delay(100);
+
+ // Everything happens in the interrupts!
+}
+
+// This ISR will end horizontal sync for most of the image and
+// setup the vertical sync for higher line counts
+void isr_porch(void) {
+ VGA_H_HIGH;
+ y++;
+ logo_y = map(y, 0, 478, 0, y_max);
+ // Back to the top
+ if (y >= 523) {
+ y = 1;
+ logo_y = 0;
+ v_active = true;
+ return;
+ }
+ // Other vsync stuff below the image
+ if (y >= 492) {
+ VGA_V_HIGH;
+ return;
+ }
+ if (y >= 490) {
+ VGA_V_LOW;
+ return;
+ }
+ if (y >= 479) {
+ v_active = false;
+ return;
+ }
+}
+
+// This is the main horizontal sweep
+void isr_start(void) {
+ // Skip if we're not in the image at all
+ if (!v_active) {
+ return;
+ }
+
+ // Start Red
+ VGA_R_LOW;
+ VGA_R_HIGH;
+
+ // For each "pixel", go ON_COLOR or OFF_COLOR
+ for (x = 0; x < 16; x++) {
+ // setting the color several times is just an easy way to
+ // delay, so the image is wider. if you only do the following
+ // once, you'll be able to make the logo array bigger:
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ }
+}
+
+// End of the horizontal line
+void isr_stop(void) {
+ if (!v_active) {
+ return;
+ }
+ VGA_R_LOW;
+ VGA_G_LOW;
+ VGA_B_LOW;
+}
+
+// Setup horizonal sync
+void isr_update(void) {
+ VGA_H_LOW;
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp
new file mode 100644
index 0000000..8730cf0
--- /dev/null
+++ b/examples/vga-scope.cpp
@@ -0,0 +1,205 @@
+/*
+ VGA Oscilloscope demo.
+
+ Connect a microphone or something like it to ANALOG_PIN (0V -- 3.3V
+ only; 0.2V -- 3.1V will probably look nicer); an attached VGA
+ monitor will display the signal roughly in real-time.
+
+ The thick blue line corresponds roughly to 0V.
+
+ This is a fairy crude hack, but it's fun to watch/toy around with.
+
+ SerialUSB and SysTick are disabled to get rid of the most frequently
+ occurring interrupts (which mess with timing). This means that you
+ have to use perpetual bootloader mode or the reset button to flash
+ new programs.
+
+ How to wire this to a VGA port:
+ D6 via ~200ohms to VGA Red (1)
+ D7 via ~200ohms to VGA Green (2)
+ D8 via ~200ohms to VGA Blue (3)
+ D11 to VGA VSync (14) (swapped?)
+ D12 to VGA HSync (13) (swapped?)
+ GND to VGA Ground (5)
+ GND to VGA Sync Ground (10)
+
+ See also:
+ - http://pinouts.ru/Video/VGA15_pinout.shtml
+ - http://www.epanorama.net/documents/pc/vga_timing.html
+
+ This code is released into the public domain.
+
+ Authors:
+
+ Bryan Newbold <bnewbold@leaflabs.com>
+ Marti Bolivar <mbolivar@leaflabs.com>
+ */
+
+#include <wirish/wirish.h>
+#include <libmaple/systick.h>
+
+// FIXME: generalize for Native and Mini
+
+#define ANALOG_PIN 18
+
+// Pinouts -- you also must change the GPIO macros below if you change
+// these
+#define VGA_R 6 // STM32: A8
+#define VGA_G 7 // STM32: A9
+#define VGA_B 8 // STM32: A10
+#define VGA_V 11 // STM32: A6
+#define VGA_H 12 // STM32: A7
+
+// These low level (and STM32 specific) macros make GPIO writes much
+// faster
+#define ABSRR ((volatile uint32*)0x40010810)
+#define ABRR ((volatile uint32*)0x40010814)
+
+#define RBIT 8 // (see pinouts)
+#define GBIT 9
+#define BBIT 10
+
+#define VGA_R_HIGH *ABSRR = BIT(RBIT)
+#define VGA_R_LOW *ABRR = BIT(RBIT)
+#define VGA_G_HIGH *ABSRR = BIT(GBIT)
+#define VGA_G_LOW *ABRR = BIT(GBIT)
+#define VGA_B_HIGH *ABSRR = BIT(BBIT)
+#define VGA_B_LOW *ABRR = BIT(BBIT)
+
+#define COLOR_WHITE (BIT(RBIT) | BIT(GBIT) | BIT(BBIT))
+#define COLOR_BLACK 0
+#define COLOR_RED BIT(RBIT)
+#define COLOR_GREEN BIT(GBIT)
+#define COLOR_BLUE BIT(BBIT)
+
+#define BORDER_COLOR COLOR_BLUE
+
+// set has priority, so clear every bit and set some given bits:
+#define VGA_COLOR(c) (*ABSRR = c | \
+ BIT(RBIT + 16) | BIT(GBIT + 16) | BIT(BBIT + 16))
+
+#define VGA_V_HIGH *ABSRR = BIT(6)
+#define VGA_V_LOW *ABRR = BIT(6)
+#define VGA_H_HIGH *ABSRR = BIT(7)
+#define VGA_H_LOW *ABRR = BIT(7)
+
+void isr_porch(void);
+void isr_start(void);
+void isr_stop(void);
+void isr_update(void);
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ pinMode(ANALOG_PIN, INPUT_ANALOG);
+ digitalWrite(BOARD_LED_PIN, 1);
+ pinMode(VGA_R, OUTPUT);
+ pinMode(VGA_G, OUTPUT);
+ pinMode(VGA_B, OUTPUT);
+ pinMode(VGA_V, OUTPUT);
+ pinMode(VGA_H, OUTPUT);
+
+ // Send a message out USART2
+ Serial2.begin(9600);
+ Serial2.println("Time to kill the radio star...");
+
+ // This gets rid of the majority of the interrupt artifacts;
+ // there's still a glitch for low values of y, but let's not worry
+ // about that. (Probably due to the hackish way vsync is done).
+ SerialUSB.end();
+ systick_disable();
+
+ digitalWrite(VGA_R, 0);
+ digitalWrite(VGA_G, 0);
+ digitalWrite(VGA_B, 0);
+ digitalWrite(VGA_H, 1);
+ digitalWrite(VGA_V, 1);
+
+ timer_pause(TIMER4);
+ timer_set_prescaler(TIMER4, 0);
+ timer_set_mode(TIMER4, 1, TIMER_OUTPUT_COMPARE);
+ timer_set_mode(TIMER4, 2, TIMER_OUTPUT_COMPARE);
+ timer_set_mode(TIMER4, 3, TIMER_OUTPUT_COMPARE);
+ timer_set_mode(TIMER4, 4, TIMER_OUTPUT_COMPARE);
+ timer_set_reload(TIMER4, 2287);
+ timer_set_compare(TIMER4, 1, 200);
+ timer_set_compare(TIMER4, 2, 250);
+ timer_set_compare(TIMER4, 3, 2170); // 2219 max...
+ timer_set_compare(TIMER4, 4, 1);
+ timer_attach_interrupt(TIMER4, 1, isr_porch);
+ timer_attach_interrupt(TIMER4, 2, isr_start);
+ timer_attach_interrupt(TIMER4, 3, isr_stop);
+ timer_attach_interrupt(TIMER4, 4, isr_update);
+
+ timer_set_count(TIMER4, 0);
+ timer_resume(TIMER4);
+}
+
+uint16 y = 0;
+uint16 val = 0;
+bool v_active = true;
+const uint16 x_max = 60; // empirically (and sloppily) determined
+
+void isr_porch(void) {
+ VGA_H_HIGH;
+ y++;
+ val = map(analogRead(ANALOG_PIN), 0, 4095, 0, x_max);
+ if (y >= 523) {
+ y = 1;
+ v_active = true;
+ return;
+ }
+ if (y >= 492) {
+ VGA_V_HIGH;
+ return;
+ }
+ if (y >= 490) {
+ VGA_V_LOW;
+ return;
+ }
+ if (y >= 479) {
+ v_active = false;
+ return;
+ }
+
+}
+
+void isr_start(void) {
+ if (!v_active) {
+ return;
+ }
+ VGA_COLOR(BORDER_COLOR);
+ for (int x = 0; x < val; x++) {
+ VGA_COLOR(COLOR_BLACK);
+ }
+ VGA_COLOR(COLOR_WHITE);
+ VGA_COLOR(COLOR_BLACK);
+}
+
+void isr_stop(void) {
+ if (!v_active) {
+ return;
+ }
+ VGA_COLOR(COLOR_BLACK);
+}
+
+void isr_update(void) {
+ VGA_H_LOW;
+}
+
+void loop() {
+ toggleLED();
+ delay(100);
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/libmaple/adc.c b/libmaple/adc.c
new file mode 100644
index 0000000..7ea85dd
--- /dev/null
+++ b/libmaple/adc.c
@@ -0,0 +1,109 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/adc.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief Analog to digital converter routines
+ */
+
+#include <libmaple/adc.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
+
+/**
+ * @brief Initialize an ADC peripheral.
+ *
+ * Initializes the RCC clock line for the given peripheral. Resets
+ * ADC device registers.
+ *
+ * @param dev ADC peripheral to initialize
+ */
+void adc_init(const adc_dev *dev) {
+ rcc_clk_enable(dev->clk_id);
+ rcc_reset_dev(dev->clk_id);
+}
+
+/**
+ * @brief Set external event select for regular group
+ * @param dev ADC device
+ * @param event Event used to trigger the start of conversion.
+ * @see adc_extsel_event
+ */
+void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) {
+ uint32 cr2 = dev->regs->CR2;
+ cr2 &= ~ADC_CR2_EXTSEL;
+ cr2 |= event;
+ dev->regs->CR2 = cr2;
+}
+
+/**
+ * @brief Set the sample rate for all channels on an ADC device.
+ *
+ * Don't call this during conversion.
+ *
+ * @param dev adc device
+ * @param smp_rate sample rate to set
+ * @see adc_smp_rate
+ */
+void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) {
+ uint32 adc_smpr1_val = 0, adc_smpr2_val = 0;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ if (i < 8) {
+ /* ADC_SMPR1 determines sample time for channels [10,17] */
+ adc_smpr1_val |= smp_rate << (i * 3);
+ }
+ /* ADC_SMPR2 determines sample time for channels [0,9] */
+ adc_smpr2_val |= smp_rate << (i * 3);
+ }
+
+ dev->regs->SMPR1 = adc_smpr1_val;
+ dev->regs->SMPR2 = adc_smpr2_val;
+}
+
+/**
+ * @brief Perform a single synchronous software triggered conversion on a
+ * channel.
+ * @param dev ADC device to use for reading.
+ * @param channel channel to convert
+ * @return conversion result
+ */
+uint16 adc_read(const adc_dev *dev, uint8 channel) {
+ adc_reg_map *regs = dev->regs;
+
+ adc_set_reg_seqlen(dev, 1);
+
+ regs->SQR3 = channel;
+ regs->CR2 |= ADC_CR2_SWSTART;
+ while (!(regs->SR & ADC_SR_EOC))
+ ;
+
+ return (uint16)(regs->DR & ADC_DR_DATA);
+}
diff --git a/libmaple/dac.c b/libmaple/dac.c
new file mode 100644
index 0000000..d802d2b
--- /dev/null
+++ b/libmaple/dac.c
@@ -0,0 +1,120 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Bryan Newbold.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/dac.c
+ * @brief Digital to analog converter support.
+ */
+
+#include <libmaple/dac.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/gpio.h>
+
+#if STM32_HAVE_DAC
+dac_dev dac = {
+ .regs = DAC_BASE,
+};
+const dac_dev *DAC = &dac;
+#endif
+
+/**
+ * @brief Initialize the digital to analog converter
+ * @param dev DAC device
+ * @param flags Flags:
+ * DAC_CH1: Enable channel 1
+ * DAC_CH2: Enable channel 2
+ * @sideeffect May set PA4 or PA5 to INPUT_ANALOG
+ */
+void dac_init(const dac_dev *dev, uint32 flags) {
+ /* First turn on the clock */
+ rcc_clk_enable(RCC_DAC);
+ rcc_reset_dev(RCC_DAC);
+
+ if (flags & DAC_CH1) {
+ dac_enable_channel(dev, 1);
+ }
+
+ if (flags & DAC_CH2) {
+ dac_enable_channel(dev, 2);
+ }
+}
+
+/**
+ * @brief Write a 12-bit value to the DAC to output
+ * @param dev DAC device
+ * @param channel channel to select (1 or 2)
+ * @param val value to write
+ */
+void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val) {
+ switch(channel) {
+ case 1:
+ dev->regs->DHR12R1 = DAC_DHR12R1_DACC1DHR & val;
+ break;
+ case 2:
+ dev->regs->DHR12R2 = DAC_DHR12R2_DACC2DHR & val;
+ break;
+ }
+}
+
+/**
+ * @brief Enable a DAC channel
+ * @param dev DAC device
+ * @param channel channel to enable, either 1 or 2
+ * @sideeffect May change pin mode of PA4 or PA5
+ */
+void dac_enable_channel(const dac_dev *dev, uint8 channel) {
+ /*
+ * Setup ANALOG mode on PA4 and PA5. This mapping is consistent
+ * across all supported STM32s with a DAC.
+ */
+ switch (channel) {
+ case 1:
+ gpio_set_mode(GPIOA, 4, GPIO_MODE_ANALOG);
+ dev->regs->CR |= DAC_CR_EN1;
+ break;
+ case 2:
+ gpio_set_mode(GPIOA, 5, GPIO_MODE_ANALOG);
+ dev->regs->CR |= DAC_CR_EN2;
+ break;
+ }
+}
+
+/**
+ * @brief Disable a DAC channel
+ * @param dev DAC device
+ * @param channel channel to disable, either 1 or 2
+ */
+void dac_disable_channel(const dac_dev *dev, uint8 channel) {
+ switch (channel) {
+ case 1:
+ dev->regs->CR &= ~DAC_CR_EN1;
+ break;
+ case 2:
+ dev->regs->CR &= ~DAC_CR_EN2;
+ break;
+ }
+}
diff --git a/libmaple/dma.c b/libmaple/dma.c
new file mode 100644
index 0000000..d13de10
--- /dev/null
+++ b/libmaple/dma.c
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/dma.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>;
+ * Original implementation by Michael Hope
+ * @brief Portable DMA routines.
+ */
+
+#include <libmaple/dma.h>
+#include "dma_private.h"
+#include "stm32_private.h"
+
+/*
+ * Convenience routines
+ */
+
+/**
+ * @brief Initialize a DMA device.
+ * @param dev Device to initialize.
+ */
+void dma_init(dma_dev *dev) {
+ rcc_clk_enable(dev->clk_id);
+}
+
+/*
+ * Private API
+ */
+
+enum dma_atype _dma_addr_type(__io void *addr) {
+ switch (stm32_block_purpose((void*)addr)) {
+ /* Notice we're treating the code block as memory here. That's
+ * correct for addresses in Flash and in [0x0, 0x7FFFFFF]
+ * (provided that those addresses are aliased to Flash, SRAM, or
+ * FSMC, depending on BOOT[01] and possibly SYSCFG_MEMRMP). It's
+ * not correct for other addresses in the code block, but those
+ * will (hopefully) just fail-fast with transfer or bus errors. If
+ * lots of people get confused, it might be worth being more
+ * careful here. */
+ case STM32_BLOCK_CODE: /* Fall through */
+ case STM32_BLOCK_SRAM: /* ... */
+ case STM32_BLOCK_FSMC_1_2: /* ... */
+ case STM32_BLOCK_FSMC_3_4:
+ return DMA_ATYPE_MEM;
+ case STM32_BLOCK_PERIPH:
+ return DMA_ATYPE_PER;
+ case STM32_BLOCK_FSMC_REG: /* Fall through */
+ /* Is this right? I can't think of a reason to DMA into or out
+ * of the FSMC registers. [mbolivar] */
+ case STM32_BLOCK_UNUSED: /* ... */
+ case STM32_BLOCK_CORTEX_INTERNAL: /* ... */
+ return DMA_ATYPE_OTHER;
+ default:
+ ASSERT(0); /* Can't happen */
+ return DMA_ATYPE_OTHER;
+ }
+}
diff --git a/libmaple/dma_private.h b/libmaple/dma_private.h
new file mode 100644
index 0000000..82f5fc1
--- /dev/null
+++ b/libmaple/dma_private.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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 _LIBMAPLE_DMA_PRIVATE_H_
+#define _LIBMAPLE_DMA_PRIVATE_H_
+
+#include <libmaple/dma.h>
+#include <libmaple/libmaple_types.h>
+
+/*
+ * IRQ handling
+ */
+
+/* Wrap this in an ifdef to shut up GCC. (We provide DMA_GET_HANDLER
+ * in the series support files, which need dma_irq_handler().) */
+#ifdef DMA_GET_HANDLER
+static __always_inline void dma_irq_handler(dma_dev *dev, dma_tube tube) {
+ dma_clear_isr_bits(dev, tube); /* in case handler doesn't */
+ void (*handler)(void) = DMA_GET_HANDLER(dev, tube);
+ if (handler) {
+ handler();
+ }
+}
+#endif
+
+/*
+ * Conveniences for dealing with tube sources/destinations
+ */
+
+enum dma_atype {
+ DMA_ATYPE_MEM,
+ DMA_ATYPE_PER,
+ DMA_ATYPE_OTHER,
+};
+
+enum dma_atype _dma_addr_type(__io void *addr);
+
+#endif
diff --git a/libmaple/exc.S b/libmaple/exc.S
new file mode 100644
index 0000000..7631e48
--- /dev/null
+++ b/libmaple/exc.S
@@ -0,0 +1,101 @@
+/* *****************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ * ****************************************************************************/
+
+# On an exception, push a fake stack thread mode stack frame and redirect
+# thread execution to a thread mode error handler
+
+# From RM008:
+# The SP is decremented by eight words by the completion of the stack push.
+# Figure 5-1 shows the contents of the stack after an exception pre-empts the
+# current program flow.
+#
+# Old SP--> <previous>
+# xPSR
+# PC
+# LR
+# r12
+# r3
+# r2
+# r1
+# SP--> r0
+
+.text
+.globl __exc_hardfault
+.globl __exc_nmi
+.globl __exc_hardfault
+.globl __exc_memmanage
+.globl __exc_busfault
+.globl __exc_usagefault
+
+.code 16
+.thumb_func
+__exc_nmi:
+ mov r0, #1
+ b __default_exc
+
+.thumb_func
+__exc_hardfault:
+ mov r0, #2
+ b __default_exc
+
+.thumb_func
+__exc_memmanage:
+ mov r0, #3
+ b __default_exc
+
+.thumb_func
+__exc_busfault:
+ mov r0, #4
+ b __default_exc
+
+.thumb_func
+__exc_usagefault:
+ mov r0, #5
+ b __default_exc
+
+.thumb_func
+__default_exc:
+ ldr r2, NVIC_CCR @ Enable returning to thread mode even if there are
+ mov r1 ,#1 @ pending exceptions. See flag NONEBASETHRDENA.
+ str r1, [r2]
+ cpsid i @ Disable global interrupts
+ ldr r2, SYSTICK_CSR @ Disable systick handler
+ mov r1, #0
+ str r1, [r2]
+ ldr r1, CPSR_MASK @ Set default CPSR
+ push {r1}
+ ldr r1, TARGET_PC @ Set target pc
+ push {r1}
+ sub sp, sp, #24 @ Don't care
+ ldr r1, EXC_RETURN @ Return to thread mode
+ mov lr, r1
+ bx lr @ Exception exit
+
+.align 4
+CPSR_MASK: .word 0x61000000
+EXC_RETURN: .word 0xFFFFFFF9
+TARGET_PC: .word __error
+NVIC_CCR: .word 0xE000ED14 @ NVIC configuration control register
+SYSTICK_CSR: .word 0xE000E010 @ Systick control register
+
diff --git a/libmaple/exti.c b/libmaple/exti.c
new file mode 100644
index 0000000..f8ee8c3
--- /dev/null
+++ b/libmaple/exti.c
@@ -0,0 +1,292 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/exti.c
+ * @brief External interrupt control routines
+ */
+
+#include <libmaple/exti.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/nvic.h>
+#include <libmaple/bitband.h>
+
+static inline void dispatch_single_exti(uint32 exti_num);
+static inline void dispatch_extis(uint32 start, uint32 stop);
+
+/*
+ * Internal state
+ */
+
+typedef struct exti_channel {
+ void (*handler)(void *);
+ void *arg;
+} exti_channel;
+
+static exti_channel exti_channels[] = {
+ { .handler = NULL, .arg = NULL }, // EXTI0
+ { .handler = NULL, .arg = NULL }, // EXTI1
+ { .handler = NULL, .arg = NULL }, // EXTI2
+ { .handler = NULL, .arg = NULL }, // EXTI3
+ { .handler = NULL, .arg = NULL }, // EXTI4
+ { .handler = NULL, .arg = NULL }, // EXTI5
+ { .handler = NULL, .arg = NULL }, // EXTI6
+ { .handler = NULL, .arg = NULL }, // EXTI7
+ { .handler = NULL, .arg = NULL }, // EXTI8
+ { .handler = NULL, .arg = NULL }, // EXTI9
+ { .handler = NULL, .arg = NULL }, // EXTI10
+ { .handler = NULL, .arg = NULL }, // EXTI11
+ { .handler = NULL, .arg = NULL }, // EXTI12
+ { .handler = NULL, .arg = NULL }, // EXTI13
+ { .handler = NULL, .arg = NULL }, // EXTI14
+ { .handler = NULL, .arg = NULL }, // EXTI15
+};
+
+/*
+ * Portable routines
+ */
+
+/**
+ * @brief Register a handler to run upon external interrupt.
+ *
+ * This function assumes that the interrupt request corresponding to
+ * the given external interrupt is masked.
+ *
+ * @param num External interrupt line number.
+ * @param port Port to use as source input for external interrupt.
+ * @param handler Function handler to execute when interrupt is triggered.
+ * @param mode Type of transition to trigger on, one of:
+ * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING.
+ * @see exti_num
+ * @see exti_cfg
+ * @see voidFuncPtr
+ * @see exti_trigger_mode
+ */
+void exti_attach_interrupt(exti_num num,
+ exti_cfg port,
+ voidFuncPtr handler,
+ exti_trigger_mode mode) {
+ // Call callback version with arg being null
+ exti_attach_callback(num, port, (voidArgumentFuncPtr)handler, NULL, mode);
+}
+
+/**
+ * @brief Register a handler with an argument to run upon external interrupt.
+ *
+ * This function assumes that the interrupt request corresponding to
+ * the given external interrupt is masked.
+ *
+ * @param num External interrupt line number.
+ * @param port Port to use as source input for external interrupt.
+ * @param handler Function handler to execute when interrupt is triggered.
+ * @param arg Argument to pass to the interrupt handler.
+ * @param mode Type of transition to trigger on, one of:
+ * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING.
+ * @see exti_num
+ * @see exti_cfg
+ * @see voidFuncPtr
+ * @see exti_trigger_mode
+ */
+void exti_attach_callback(exti_num num,
+ exti_cfg port,
+ voidArgumentFuncPtr handler,
+ void *arg,
+ exti_trigger_mode mode) {
+ ASSERT(handler);
+
+ /* Register the handler */
+ exti_channels[num].handler = handler;
+ exti_channels[num].arg = arg;
+
+ /* Set trigger mode */
+ switch (mode) {
+ case EXTI_RISING:
+ bb_peri_set_bit(&EXTI_BASE->RTSR, num, 1);
+ break;
+ case EXTI_FALLING:
+ bb_peri_set_bit(&EXTI_BASE->FTSR, num, 1);
+ break;
+ case EXTI_RISING_FALLING:
+ bb_peri_set_bit(&EXTI_BASE->RTSR, num, 1);
+ bb_peri_set_bit(&EXTI_BASE->FTSR, num, 1);
+ break;
+ }
+
+ /* Use the chip-specific exti_select() to map num to port */
+ exti_select(num, port);
+
+ /* Unmask external interrupt request */
+ bb_peri_set_bit(&EXTI_BASE->IMR, num, 1);
+
+ /* Enable the interrupt line */
+ switch(num)
+ {
+ case EXTI0:
+ nvic_irq_enable(NVIC_EXTI0);
+ break;
+ case EXTI1:
+ nvic_irq_enable(NVIC_EXTI1);
+ break;
+ case EXTI2:
+ nvic_irq_enable(NVIC_EXTI2);
+ break;
+ case EXTI3:
+ nvic_irq_enable(NVIC_EXTI3);
+ break;
+ case EXTI4:
+ nvic_irq_enable(NVIC_EXTI4);
+ break;
+ case EXTI5:
+ case EXTI6:
+ case EXTI7:
+ case EXTI8:
+ case EXTI9:
+ nvic_irq_enable(NVIC_EXTI_9_5);
+ break;
+ case EXTI10:
+ case EXTI11:
+ case EXTI12:
+ case EXTI13:
+ case EXTI14:
+ case EXTI15:
+ nvic_irq_enable(NVIC_EXTI_15_10);
+ break;
+ }
+}
+
+/**
+ * @brief Unregister an external interrupt handler
+ * @param num External interrupt line to disable.
+ * @see exti_num
+ */
+void exti_detach_interrupt(exti_num num) {
+ /* First, mask the interrupt request */
+ bb_peri_set_bit(&EXTI_BASE->IMR, num, 0);
+
+ /* Then, clear the trigger selection registers */
+ bb_peri_set_bit(&EXTI_BASE->FTSR, num, 0);
+ bb_peri_set_bit(&EXTI_BASE->RTSR, num, 0);
+
+ /* Finally, unregister the user's handler */
+ exti_channels[num].handler = NULL;
+ exti_channels[num].arg = NULL;
+}
+
+/*
+ * Private routines
+ */
+
+void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port) {
+ uint32 shift = 4 * (num % 4);
+ uint32 cr = *exti_cr;
+ cr &= ~(0xF << shift);
+ cr |= port << shift;
+ *exti_cr = cr;
+}
+
+/*
+ * Interrupt handlers
+ */
+
+void __irq_exti0(void) {
+ dispatch_single_exti(EXTI0);
+}
+
+void __irq_exti1(void) {
+ dispatch_single_exti(EXTI1);
+}
+
+void __irq_exti2(void) {
+ dispatch_single_exti(EXTI2);
+}
+
+void __irq_exti3(void) {
+ dispatch_single_exti(EXTI3);
+}
+
+void __irq_exti4(void) {
+ dispatch_single_exti(EXTI4);
+}
+
+void __irq_exti9_5(void) {
+ dispatch_extis(5, 9);
+}
+
+void __irq_exti15_10(void) {
+ dispatch_extis(10, 15);
+}
+
+/*
+ * Auxiliary functions
+ */
+
+/* Clear the pending bits for EXTIs whose bits are set in exti_msk.
+ *
+ * If a pending bit is cleared as the last instruction in an ISR, it
+ * won't actually be cleared in time and the ISR will fire again. To
+ * compensate, this function NOPs for 2 cycles after clearing the
+ * pending bits to ensure it takes effect. */
+static __always_inline void clear_pending_msk(uint32 exti_msk) {
+ EXTI_BASE->PR = exti_msk;
+ asm volatile("nop");
+ asm volatile("nop");
+}
+
+/* This dispatch routine is for non-multiplexed EXTI lines only; i.e.,
+ * it doesn't check EXTI_PR. */
+static __always_inline void dispatch_single_exti(uint32 exti) {
+ voidArgumentFuncPtr handler = exti_channels[exti].handler;
+
+ if (!handler) {
+ return;
+ }
+
+ handler(exti_channels[exti].arg);
+ clear_pending_msk(1U << exti);
+}
+
+/* Dispatch routine for EXTIs which share an IRQ. */
+static __always_inline void dispatch_extis(uint32 start, uint32 stop) {
+ uint32 pr = EXTI_BASE->PR;
+ uint32 handled_msk = 0;
+ uint32 exti;
+
+ /* Dispatch user handlers for pending EXTIs. */
+ for (exti = start; exti <= stop; exti++) {
+ uint32 eb = (1U << exti);
+ if (pr & eb) {
+ voidArgumentFuncPtr handler = exti_channels[exti].handler;
+ if (handler) {
+ handler(exti_channels[exti].arg);
+ handled_msk |= eb;
+ }
+ }
+ }
+
+ /* Clear the pending bits for handled EXTIs. */
+ clear_pending_msk(handled_msk);
+}
diff --git a/libmaple/exti_private.h b/libmaple/exti_private.h
new file mode 100644
index 0000000..4f0a4cf
--- /dev/null
+++ b/libmaple/exti_private.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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 _LIBMAPLE_EXTI_PRIVATE_H_
+#define _LIBMAPLE_EXTI_PRIVATE_H_
+
+#include <libmaple/exti.h>
+
+void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port);
+
+#endif
diff --git a/libmaple/flash.c b/libmaple/flash.c
new file mode 100644
index 0000000..c57bbbf
--- /dev/null
+++ b/libmaple/flash.c
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/flash.c
+ * @brief Flash management functions
+ */
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/flash.h>
+
+/**
+ * @brief Set flash wait states
+ *
+ * Note that not all wait states are available on every MCU. See the
+ * Flash programming manual for your MCU for restrictions on the
+ * allowed value of wait_states for a given system clock (SYSCLK)
+ * frequency.
+ *
+ * @param wait_states number of wait states (one of
+ * FLASH_WAIT_STATE_0, FLASH_WAIT_STATE_1,
+ * ..., FLASH_WAIT_STATE_7).
+ */
+void flash_set_latency(uint32 wait_states) {
+ uint32 val = FLASH_BASE->ACR;
+
+ val &= ~FLASH_ACR_LATENCY;
+ val |= wait_states;
+
+ FLASH_BASE->ACR = val;
+}
diff --git a/libmaple/gpio.c b/libmaple/gpio.c
new file mode 100644
index 0000000..6e63d2f
--- /dev/null
+++ b/libmaple/gpio.c
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/gpio.c
+ * @brief Generic STM32 GPIO support.
+ */
+
+#include <libmaple/gpio.h>
+#include <libmaple/rcc.h>
+
+/*
+ * GPIO routines
+ */
+
+/**
+ * Initialize a GPIO device.
+ *
+ * Enables the clock for and resets the given device.
+ *
+ * @param dev GPIO device to initialize.
+ */
+void gpio_init(gpio_dev *dev) {
+ rcc_clk_enable(dev->clk_id);
+ rcc_reset_dev(dev->clk_id);
+}
diff --git a/libmaple/i2c.c b/libmaple/i2c.c
new file mode 100644
index 0000000..9c93d3f
--- /dev/null
+++ b/libmaple/i2c.c
@@ -0,0 +1,509 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/i2c.c
+ * @author Perry Hung <perry@leaflabs.com>
+ * @brief Inter-Integrated Circuit (I2C) support.
+ *
+ * Currently, only master mode is supported.
+ */
+
+#include "i2c_private.h"
+
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
+#include <libmaple/gpio.h>
+#include <libmaple/nvic.h>
+#include <libmaple/i2c.h>
+#include <libmaple/systick.h>
+
+#include <string.h>
+
+static inline int32 wait_for_state_change(i2c_dev *dev,
+ i2c_state state,
+ uint32 timeout);
+static void set_ccr_trise(i2c_dev *dev, uint32 flags);
+
+/**
+ * @brief Fill data register with slave address
+ * @param dev I2C device
+ * @param addr Slave address
+ * @param rw Read/write bit
+ */
+static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) {
+ dev->regs->DR = (addr << 1) | rw;
+}
+
+/*
+ * Simple debugging trail. Define I2C_DEBUG to turn on.
+ */
+#ifdef I2C_DEBUG
+
+#define NR_CRUMBS 128
+static struct crumb crumbs[NR_CRUMBS];
+static uint32 cur_crumb = 0;
+
+static inline void i2c_drop_crumb(uint32 event, uint32 arg0, uint32 arg1) {
+ if (cur_crumb < NR_CRUMBS) {
+ struct crumb *crumb = &crumbs[cur_crumb++];
+ crumb->event = event;
+ crumb->arg0 = arg0;
+ crumb->arg1 = arg1;
+ }
+}
+#define I2C_CRUMB(event, arg0, arg1) i2c_drop_crumb(event, arg0, arg1)
+
+#else
+#define I2C_CRUMB(event, arg0, arg1)
+#endif
+
+struct crumb {
+ uint32 event;
+ uint32 arg0;
+ uint32 arg1;
+};
+
+enum {
+ IRQ_ENTRY = 1,
+ TXE_ONLY = 2,
+ TXE_BTF = 3,
+ STOP_SENT = 4,
+ TEST = 5,
+ RX_ADDR_START = 6,
+ RX_ADDR_STOP = 7,
+ RXNE_ONLY = 8,
+ RXNE_SENDING = 9,
+ RXNE_START_SENT = 10,
+ RXNE_STOP_SENT = 11,
+ RXNE_DONE = 12,
+ ERROR_ENTRY = 13,
+};
+
+/**
+ * @brief Reset an I2C bus.
+ *
+ * Reset is accomplished by clocking out pulses until any hung slaves
+ * release SDA and SCL, then generating a START condition, then a STOP
+ * condition.
+ *
+ * @param dev I2C device
+ */
+void i2c_bus_reset(const i2c_dev *dev) {
+ /* Release both lines */
+ i2c_master_release_bus(dev);
+
+ /*
+ * Make sure the bus is free by clocking it until any slaves release the
+ * bus.
+ */
+ while (!gpio_read_bit(sda_port(dev), dev->sda_pin)) {
+ /* Wait for any clock stretching to finish */
+ while (!gpio_read_bit(scl_port(dev), dev->scl_pin))
+ ;
+ delay_us(10);
+
+ /* Pull low */
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 0);
+ delay_us(10);
+
+ /* Release high again */
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
+ delay_us(10);
+ }
+
+ /* Generate start then stop condition */
+ gpio_write_bit(sda_port(dev), dev->sda_pin, 0);
+ delay_us(10);
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 0);
+ delay_us(10);
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
+ delay_us(10);
+ gpio_write_bit(sda_port(dev), dev->sda_pin, 1);
+}
+
+/**
+ * @brief Initialize an I2C device and reset its registers to their
+ * default values.
+ * @param dev Device to initialize.
+ */
+void i2c_init(i2c_dev *dev) {
+ rcc_reset_dev(dev->clk_id);
+ rcc_clk_enable(dev->clk_id);
+}
+
+/* Hack for deprecated bit of STM32F1 functionality */
+#ifndef _I2C_HAVE_DEPRECATED_I2C_REMAP
+#define _i2c_handle_remap(dev, flags) ((void)0)
+#endif
+
+/**
+ * @brief Initialize an I2C device as bus master
+ * @param dev Device to enable
+ * @param flags Bitwise or of the following I2C options:
+ * I2C_FAST_MODE: 400 khz operation,
+ * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for
+ * fast mode),
+ * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on
+ * initialization,
+ * I2C_10BIT_ADDRESSING: Enable 10-bit addressing,
+ * I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8
+ * SDA/PB9.
+ */
+void i2c_master_enable(i2c_dev *dev, uint32 flags) {
+ /* PE must be disabled to configure the device */
+ ASSERT(!(dev->regs->CR1 & I2C_CR1_PE));
+
+ /* Ugh */
+ _i2c_handle_remap(dev, flags);
+
+ /* Reset the bus. Clock out any hung slaves. */
+ if (flags & I2C_BUS_RESET) {
+ i2c_bus_reset(dev);
+ }
+
+ /* Turn on clock and set GPIO modes */
+ i2c_init(dev);
+ i2c_config_gpios(dev);
+
+ /* Configure clock and rise time */
+ set_ccr_trise(dev, flags);
+
+ /* Enable event and buffer interrupts */
+ nvic_irq_enable(dev->ev_nvic_line);
+ nvic_irq_enable(dev->er_nvic_line);
+ i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR);
+
+ /* Make it go! */
+ i2c_peripheral_enable(dev);
+
+ dev->state = I2C_STATE_IDLE;
+}
+
+/**
+ * @brief Process an i2c transaction.
+ *
+ * Transactions are composed of one or more i2c_msg's, and may be read
+ * or write tranfers. Multiple i2c_msg's will generate a repeated
+ * start in between messages.
+ *
+ * @param dev I2C device
+ * @param msgs Messages to send/receive
+ * @param num Number of messages to send/receive
+ * @param timeout Bus idle timeout in milliseconds before aborting the
+ * transfer. 0 denotes no timeout.
+ * @return 0 on success,
+ * I2C_ERROR_PROTOCOL if there was a protocol error,
+ * I2C_ERROR_TIMEOUT if the transfer timed out.
+ */
+int32 i2c_master_xfer(i2c_dev *dev,
+ i2c_msg *msgs,
+ uint16 num,
+ uint32 timeout) {
+ int32 rc;
+
+ ASSERT(dev->state == I2C_STATE_IDLE);
+
+ dev->msg = msgs;
+ dev->msgs_left = num;
+ dev->timestamp = systick_uptime();
+ dev->state = I2C_STATE_BUSY;
+
+ i2c_enable_irq(dev, I2C_IRQ_EVENT);
+ i2c_start_condition(dev);
+
+ rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE, timeout);
+ if (rc < 0) {
+ goto out;
+ }
+
+ dev->state = I2C_STATE_IDLE;
+out:
+ return rc;
+}
+
+/**
+ * @brief Wait for an I2C event, or time out in case of error.
+ * @param dev I2C device
+ * @param state I2C_state state to wait for
+ * @param timeout Timeout, in milliseconds
+ * @return 0 if target state is reached, a negative value on error.
+ */
+static inline int32 wait_for_state_change(i2c_dev *dev,
+ i2c_state state,
+ uint32 timeout) {
+ i2c_state tmp;
+
+ while (1) {
+ tmp = dev->state;
+
+ if (tmp == I2C_STATE_ERROR) {
+ return I2C_STATE_ERROR;
+ }
+
+ if (tmp == state) {
+ return 0;
+ }
+
+ if (timeout) {
+ if (systick_uptime() > (dev->timestamp + timeout)) {
+ /* TODO: overflow? */
+ /* TODO: racy? */
+ return I2C_ERROR_TIMEOUT;
+ }
+ }
+ }
+}
+
+/*
+ * Private API
+ */
+
+/*
+ * IRQ handler for I2C master. Handles transmission/reception.
+ */
+void _i2c_irq_handler(i2c_dev *dev) {
+ /* WTFs:
+ * - Where is I2C_MSG_10BIT_ADDR handled?
+ */
+ i2c_msg *msg = dev->msg;
+
+ uint8 read = msg->flags & I2C_MSG_READ;
+
+ uint32 sr1 = dev->regs->SR1;
+ uint32 sr2 = dev->regs->SR2;
+ I2C_CRUMB(IRQ_ENTRY, sr1, sr2);
+
+ /*
+ * Reset timeout counter
+ */
+ dev->timestamp = systick_uptime();
+
+ /*
+ * EV5: Start condition sent
+ */
+ if (sr1 & I2C_SR1_SB) {
+ msg->xferred = 0;
+ i2c_enable_irq(dev, I2C_IRQ_BUFFER);
+
+ /*
+ * Master receiver
+ */
+ if (read) {
+ i2c_enable_ack(dev);
+ }
+
+ i2c_send_slave_addr(dev, msg->addr, read);
+ sr1 = sr2 = 0;
+ }
+
+ /*
+ * EV6: Slave address sent
+ */
+ if (sr1 & I2C_SR1_ADDR) {
+ /*
+ * Special case event EV6_1 for master receiver.
+ * Generate NACK and restart/stop condition after ADDR
+ * is cleared.
+ */
+ if (read) {
+ if (msg->length == 1) {
+ i2c_disable_ack(dev);
+ if (dev->msgs_left > 1) {
+ i2c_start_condition(dev);
+ I2C_CRUMB(RX_ADDR_START, 0, 0);
+ } else {
+ i2c_stop_condition(dev);
+ I2C_CRUMB(RX_ADDR_STOP, 0, 0);
+ }
+ }
+ } else {
+ /*
+ * Master transmitter: write first byte to fill shift
+ * register. We should get another TXE interrupt
+ * immediately to fill DR again.
+ */
+ if (msg->length != 1) {
+ i2c_write(dev, msg->data[msg->xferred++]);
+ }
+ }
+ sr1 = sr2 = 0;
+ }
+
+ /*
+ * EV8: Master transmitter
+ * Transmit buffer empty, but we haven't finished transmitting the last
+ * byte written.
+ */
+ if ((sr1 & I2C_SR1_TXE) && !(sr1 & I2C_SR1_BTF)) {
+ I2C_CRUMB(TXE_ONLY, 0, 0);
+ if (dev->msgs_left) {
+ i2c_write(dev, msg->data[msg->xferred++]);
+ if (msg->xferred == msg->length) {
+ /*
+ * End of this message. Turn off TXE/RXNE and wait for
+ * BTF to send repeated start or stop condition.
+ */
+ i2c_disable_irq(dev, I2C_IRQ_BUFFER);
+ dev->msgs_left--;
+ }
+ } else {
+ /*
+ * This should be impossible...
+ */
+ ASSERT(0);
+ }
+ sr1 = sr2 = 0;
+ }
+
+ /*
+ * EV8_2: Master transmitter
+ * Last byte sent, program repeated start/stop
+ */
+ if ((sr1 & I2C_SR1_TXE) && (sr1 & I2C_SR1_BTF)) {
+ I2C_CRUMB(TXE_BTF, 0, 0);
+ if (dev->msgs_left) {
+ I2C_CRUMB(TEST, 0, 0);
+ /*
+ * Repeated start insanity: We can't disable ITEVTEN or else SB
+ * won't interrupt, but if we don't disable ITEVTEN, BTF will
+ * continually interrupt us. What the fuck ST?
+ */
+ i2c_start_condition(dev);
+ while (!(dev->regs->SR1 & I2C_SR1_SB))
+ ;
+ dev->msg++;
+ } else {
+ i2c_stop_condition(dev);
+
+ /*
+ * Turn off event interrupts to keep BTF from firing until
+ * the end of the stop condition. Why on earth they didn't
+ * have a start/stop condition request clear BTF is beyond
+ * me.
+ */
+ i2c_disable_irq(dev, I2C_IRQ_EVENT);
+ I2C_CRUMB(STOP_SENT, 0, 0);
+ dev->state = I2C_STATE_XFER_DONE;
+ }
+ sr1 = sr2 = 0;
+ }
+
+ /*
+ * EV7: Master Receiver
+ */
+ if (sr1 & I2C_SR1_RXNE) {
+ I2C_CRUMB(RXNE_ONLY, 0, 0);
+ msg->data[msg->xferred++] = dev->regs->DR;
+
+ /*
+ * EV7_1: Second to last byte in the reception? Set NACK and generate
+ * stop/restart condition in time for the last byte. We'll get one more
+ * RXNE interrupt before shutting things down.
+ */
+ if (msg->xferred == (msg->length - 1)) {
+ i2c_disable_ack(dev);
+ if (dev->msgs_left > 2) {
+ i2c_start_condition(dev);
+ I2C_CRUMB(RXNE_START_SENT, 0, 0);
+ } else {
+ i2c_stop_condition(dev);
+ I2C_CRUMB(RXNE_STOP_SENT, 0, 0);
+ }
+ } else if (msg->xferred == msg->length) {
+ dev->msgs_left--;
+ if (dev->msgs_left == 0) {
+ /*
+ * We're done.
+ */
+ I2C_CRUMB(RXNE_DONE, 0, 0);
+ dev->state = I2C_STATE_XFER_DONE;
+ } else {
+ dev->msg++;
+ }
+ }
+ }
+}
+
+/*
+ * Interrupt handler for I2C error conditions. Aborts any pending I2C
+ * transactions.
+ */
+void _i2c_irq_error_handler(i2c_dev *dev) {
+ I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2);
+
+ dev->error_flags = dev->regs->SR2 & (I2C_SR1_BERR |
+ I2C_SR1_ARLO |
+ I2C_SR1_AF |
+ I2C_SR1_OVR);
+ /* Clear flags */
+ dev->regs->SR1 = 0;
+ dev->regs->SR2 = 0;
+
+ i2c_stop_condition(dev);
+ i2c_disable_irq(dev, I2C_IRQ_BUFFER | I2C_IRQ_EVENT | I2C_IRQ_ERROR);
+ dev->state = I2C_STATE_ERROR;
+}
+
+/*
+ * CCR/TRISE configuration helper
+ */
+static void set_ccr_trise(i2c_dev *dev, uint32 flags) {
+ uint32 ccr = 0;
+ uint32 trise = 0;
+ uint32 clk_mhz = _i2c_bus_clk(dev);
+ uint32 clk_hz = clk_mhz * (1000 * 1000);
+
+ i2c_set_input_clk(dev, clk_mhz);
+
+ if (flags & I2C_FAST_MODE) {
+ ccr |= I2C_CCR_FS;
+
+ if (flags & I2C_DUTY_16_9) {
+ /* Tlow/Thigh = 16/9 */
+ ccr |= I2C_CCR_DUTY_16_9;
+ ccr |= clk_hz / (400000 * 25);
+ } else {
+ /* Tlow/Thigh = 2 */
+ ccr |= clk_hz / (400000 * 3);
+ }
+
+ trise = (300 * clk_mhz / 1000) + 1;
+ } else {
+ /* Tlow/Thigh = 1 */
+ ccr = clk_hz / (100000 * 2);
+ trise = clk_mhz + 1;
+ }
+
+ /* Set minimum required value if CCR < 1*/
+ if ((ccr & I2C_CCR_CCR) == 0) {
+ ccr |= 0x1;
+ }
+
+ i2c_set_clk_control(dev, ccr);
+ i2c_set_trise(dev, trise);
+}
diff --git a/libmaple/i2c_private.h b/libmaple/i2c_private.h
new file mode 100644
index 0000000..5b79516
--- /dev/null
+++ b/libmaple/i2c_private.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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 _LIBMAPLE_I2C_PRIVATE_H_
+#define _LIBMAPLE_I2C_PRIVATE_H_
+
+#include <libmaple/i2c_common.h>
+
+/* For old-style definitions (SDA/SCL on same GPIO device) */
+#define I2C_DEV_OLD(num, port, sda, scl) \
+ { \
+ .regs = I2C##num##_BASE, \
+ .gpio_port = port, \
+ .scl_port = NULL, \
+ .sda_port = NULL, \
+ .sda_pin = sda, \
+ .scl_pin = scl, \
+ .clk_id = RCC_I2C##num, \
+ .ev_nvic_line = NVIC_I2C##num##_EV, \
+ .er_nvic_line = NVIC_I2C##num##_ER, \
+ .state = I2C_STATE_DISABLED, \
+ }
+
+/* For new-style definitions (SDA/SCL may be on different GPIO devices) */
+#define I2C_DEV_NEW(num, sdaport, sdabit, sclport, sclbit) \
+ { \
+ .regs = I2C##num##_BASE, \
+ .gpio_port = NULL, \
+ .scl_port = sclport, \
+ .scl_pin = sclbit, \
+ .sda_port = sdaport, \
+ .sda_pin = sdabit, \
+ .clk_id = RCC_I2C##num, \
+ .ev_nvic_line = NVIC_I2C##num##_EV, \
+ .er_nvic_line = NVIC_I2C##num##_ER, \
+ .state = I2C_STATE_DISABLED, \
+ }
+
+void _i2c_irq_handler(i2c_dev *dev);
+void _i2c_irq_error_handler(i2c_dev *dev);
+
+struct gpio_dev;
+
+static inline struct gpio_dev* scl_port(const i2c_dev *dev) {
+ return (dev->gpio_port == NULL) ? dev->scl_port : dev->gpio_port;
+}
+
+static inline struct gpio_dev* sda_port(const i2c_dev *dev) {
+ return (dev->gpio_port == NULL) ? dev->sda_port : dev->gpio_port;
+}
+
+/* Auxiliary procedure for enabling an I2C peripheral; `flags' as for
+ * i2c_master_enable(). */
+void _i2c_set_ccr_trise(i2c_dev *dev, uint32 flags);
+
+#endif /* _LIBMAPLE_I2C_PRIVATE_H_ */
diff --git a/libmaple/include/libmaple/adc.h b/libmaple/include/libmaple/adc.h
new file mode 100644
index 0000000..a500af7
--- /dev/null
+++ b/libmaple/include/libmaple/adc.h
@@ -0,0 +1,329 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/adc.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief Analog-to-Digital Conversion (ADC) header.
+ */
+
+#ifndef _LIBMAPLE_ADC_H_
+#define _LIBMAPLE_ADC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple.h>
+#include <libmaple/bitband.h>
+#include <libmaple/rcc.h>
+/* We include the series header below, after defining the register map
+ * and device structs. */
+
+/*
+ * Register map
+ */
+
+/** ADC register map type. */
+typedef struct adc_reg_map {
+ __io uint32 SR; ///< Status register
+ __io uint32 CR1; ///< Control register 1
+ __io uint32 CR2; ///< Control register 2
+ __io uint32 SMPR1; ///< Sample time register 1
+ __io uint32 SMPR2; ///< Sample time register 2
+ __io uint32 JOFR1; ///< Injected channel data offset register 1
+ __io uint32 JOFR2; ///< Injected channel data offset register 2
+ __io uint32 JOFR3; ///< Injected channel data offset register 3
+ __io uint32 JOFR4; ///< Injected channel data offset register 4
+ __io uint32 HTR; ///< Watchdog high threshold register
+ __io uint32 LTR; ///< Watchdog low threshold register
+ __io uint32 SQR1; ///< Regular sequence register 1
+ __io uint32 SQR2; ///< Regular sequence register 2
+ __io uint32 SQR3; ///< Regular sequence register 3
+ __io uint32 JSQR; ///< Injected sequence register
+ __io uint32 JDR1; ///< Injected data register 1
+ __io uint32 JDR2; ///< Injected data register 2
+ __io uint32 JDR3; ///< Injected data register 3
+ __io uint32 JDR4; ///< Injected data register 4
+ __io uint32 DR; ///< Regular data register
+} adc_reg_map;
+
+/** ADC device type. */
+typedef struct adc_dev {
+ adc_reg_map *regs; /**< Register map */
+ rcc_clk_id clk_id; /**< RCC clock information */
+} adc_dev;
+
+/* Pull in the series header (which may need the above struct
+ * definitions).
+ *
+ * IMPORTANT: The series header must define the following:
+ *
+ * - enum adc_extsel_event (and typedef to adc_extsel_event): One per
+ * external event used to trigger start of conversion of a regular
+ * group. If two different series support the same event as a
+ * trigger, they must use the same token for the enumerator for that
+ * event. (The value of the enumerator is of course allowed to be
+ * different).
+ *
+ * - enum adc_smp_rate (and typedef to adc_smp_rate): One per
+ * available sampling time. These must be in the form ADC_SMPR_X_Y
+ * for X.Y cycles (e.g. ADC_SMPR_1_5 means 1.5 cycles), or
+ * ADC_SMPR_X for X cycles (e.g. ADC_SMPR_3 means 3 cycles).
+ *
+ * - enum adc_prescaler (and typedef): One per available prescaler,
+ * suitable for adc_set_prescaler. Series which have the same
+ * prescaler dividers (e.g. STM32F1 and STM32F2 both divide PCLK2 by
+ * 2, 4, 6, or 8) must provide the same tokens as enumerators, for
+ * portability.
+ */
+#include <series/adc.h>
+
+/*
+ * Register bit definitions
+ */
+
+/* Status register */
+
+#define ADC_SR_AWD_BIT 0
+#define ADC_SR_EOC_BIT 1
+#define ADC_SR_JEOC_BIT 2
+#define ADC_SR_JSTRT_BIT 3
+#define ADC_SR_STRT_BIT 4
+
+#define ADC_SR_AWD BIT(ADC_SR_AWD_BIT)
+#define ADC_SR_EOC BIT(ADC_SR_EOC_BIT)
+#define ADC_SR_JEOC BIT(ADC_SR_JEOC_BIT)
+#define ADC_SR_JSTRT BIT(ADC_SR_JSTRT_BIT)
+#define ADC_SR_STRT BIT(ADC_SR_STRT_BIT)
+
+/* Control register 1 */
+
+#define ADC_CR1_EOCIE_BIT 5
+#define ADC_CR1_AWDIE_BIT 6
+#define ADC_CR1_JEOCIE_BIT 7
+#define ADC_CR1_SCAN_BIT 8
+#define ADC_CR1_AWDSGL_BIT 9
+#define ADC_CR1_JAUTO_BIT 10
+#define ADC_CR1_DISCEN_BIT 11
+#define ADC_CR1_JDISCEN_BIT 12
+#define ADC_CR1_JAWDEN_BIT 22
+#define ADC_CR1_AWDEN_BIT 23
+
+#define ADC_CR1_AWDCH (0x1F)
+#define ADC_CR1_EOCIE BIT(ADC_CR1_EOCIE_BIT)
+#define ADC_CR1_AWDIE BIT(ADC_CR1_AWDIE_BIT)
+#define ADC_CR1_JEOCIE BIT(ADC_CR1_JEOCIE_BIT)
+#define ADC_CR1_SCAN BIT(ADC_CR1_SCAN_BIT)
+#define ADC_CR1_AWDSGL BIT(ADC_CR1_AWDSGL_BIT)
+#define ADC_CR1_JAUTO BIT(ADC_CR1_JAUTO_BIT)
+#define ADC_CR1_DISCEN BIT(ADC_CR1_DISCEN_BIT)
+#define ADC_CR1_JDISCEN BIT(ADC_CR1_JDISCEN_BIT)
+#define ADC_CR1_DISCNUM (0xE000)
+#define ADC_CR1_JAWDEN BIT(ADC_CR1_JAWDEN_BIT)
+#define ADC_CR1_AWDEN BIT(ADC_CR1_AWDEN_BIT)
+
+/* Control register 2 */
+
+/* Because this register varies significantly by series (e.g. some
+ * bits moved and others disappeared in the F1->F2 transition), its
+ * definitions are in the series headers. */
+
+/* Sample time register 1 */
+
+#define ADC_SMPR1_SMP17 (0x7 << 21)
+#define ADC_SMPR1_SMP16 (0x7 << 18)
+#define ADC_SMPR1_SMP15 (0x7 << 15)
+#define ADC_SMPR1_SMP14 (0x7 << 12)
+#define ADC_SMPR1_SMP13 (0x7 << 9)
+#define ADC_SMPR1_SMP12 (0x7 << 6)
+#define ADC_SMPR1_SMP11 (0x7 << 3)
+#define ADC_SMPR1_SMP10 0x7
+
+/* Sample time register 2 */
+
+#define ADC_SMPR2_SMP9 (0x7 << 27)
+#define ADC_SMPR2_SMP8 (0x7 << 24)
+#define ADC_SMPR2_SMP7 (0x7 << 21)
+#define ADC_SMPR2_SMP6 (0x7 << 18)
+#define ADC_SMPR2_SMP5 (0x7 << 15)
+#define ADC_SMPR2_SMP4 (0x7 << 12)
+#define ADC_SMPR2_SMP3 (0x7 << 9)
+#define ADC_SMPR2_SMP2 (0x7 << 6)
+#define ADC_SMPR2_SMP1 (0x7 << 3)
+#define ADC_SMPR2_SMP0 0x7
+
+/* Injected channel data offset register */
+
+#define ADC_JOFR_JOFFSET 0x3FF
+
+/* Watchdog high threshold register */
+
+#define ADC_HTR_HT 0x3FF
+
+/* Watchdog low threshold register */
+
+#define ADC_LTR_LT 0x3FF
+
+/* Regular sequence register 1 */
+
+#define ADC_SQR1_L (0x1F << 20)
+#define ADC_SQR1_SQ16 (0x1F << 15)
+#define ADC_SQR1_SQ15 (0x1F << 10)
+#define ADC_SQR1_SQ14 (0x1F << 5)
+#define ADC_SQR1_SQ13 0x1F
+
+/* Regular sequence register 2 */
+
+#define ADC_SQR2_SQ12 (0x1F << 25)
+#define ADC_SQR2_SQ11 (0x1F << 20)
+#define ADC_SQR2_SQ10 (0x1F << 16)
+#define ADC_SQR2_SQ9 (0x1F << 10)
+#define ADC_SQR2_SQ8 (0x1F << 5)
+#define ADC_SQR2_SQ7 0x1F
+
+/* Regular sequence register 3 */
+
+#define ADC_SQR3_SQ6 (0x1F << 25)
+#define ADC_SQR3_SQ5 (0x1F << 20)
+#define ADC_SQR3_SQ4 (0x1F << 16)
+#define ADC_SQR3_SQ3 (0x1F << 10)
+#define ADC_SQR3_SQ2 (0x1F << 5)
+#define ADC_SQR3_SQ1 0x1F
+
+/* Injected sequence register */
+
+#define ADC_JSQR_JL (0x3 << 20)
+#define ADC_JSQR_JL_1CONV (0x0 << 20)
+#define ADC_JSQR_JL_2CONV (0x1 << 20)
+#define ADC_JSQR_JL_3CONV (0x2 << 20)
+#define ADC_JSQR_JL_4CONV (0x3 << 20)
+#define ADC_JSQR_JSQ4 (0x1F << 15)
+#define ADC_JSQR_JSQ3 (0x1F << 10)
+#define ADC_JSQR_JSQ2 (0x1F << 5)
+#define ADC_JSQR_JSQ1 0x1F
+
+/* Injected data registers */
+
+#define ADC_JDR_JDATA 0xFFFF
+
+/* Regular data register */
+
+#define ADC_DR_ADC2DATA (0xFFFF << 16)
+#define ADC_DR_DATA 0xFFFF
+
+/*
+ * Routines
+ */
+
+void adc_init(const adc_dev *dev);
+void adc_set_extsel(const adc_dev *dev, adc_extsel_event event);
+void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate);
+uint16 adc_read(const adc_dev *dev, uint8 channel);
+
+/**
+ * @brief Set the ADC prescaler.
+ *
+ * This determines the ADC clock for all devices.
+ */
+extern void adc_set_prescaler(adc_prescaler pre);
+
+/**
+ * @brief Call a function on all ADC devices.
+ * @param fn Function to call on each ADC device.
+ */
+extern void adc_foreach(void (*fn)(const adc_dev*));
+
+struct gpio_dev;
+/**
+ * @brief Configure a GPIO pin for ADC conversion.
+ * @param dev ADC device to use for conversion (currently ignored on
+ * all targets).
+ * @param gdev GPIO device to configure.
+ * @param bit Bit on gdev to configure for ADC conversion.
+ */
+extern void adc_config_gpio(const struct adc_dev *dev,
+ struct gpio_dev *gdev,
+ uint8 bit);
+
+/**
+ * @brief Enable an ADC and configure it for single conversion mode.
+ *
+ * This function performs any initialization necessary to allow the
+ * ADC device to perform a single synchronous regular software
+ * triggered conversion, using adc_read().
+ *
+ * @param dev Device to enable.
+ * @see adc_read()
+ */
+extern void adc_enable_single_swstart(const adc_dev* dev);
+
+/**
+ * @brief Set the regular channel sequence length.
+ *
+ * Defines the total number of conversions in the regular channel
+ * conversion sequence.
+ *
+ * @param dev ADC device.
+ * @param length Regular channel sequence length, from 1 to 16.
+ */
+static inline void adc_set_reg_seqlen(const adc_dev *dev, uint8 length) {
+ uint32 tmp = dev->regs->SQR1;
+ tmp &= ~ADC_SQR1_L;
+ tmp |= (length - 1) << 20;
+ dev->regs->SQR1 = tmp;
+}
+
+/**
+ * @brief Enable an adc peripheral
+ * @param dev ADC device to enable
+ */
+static inline void adc_enable(const adc_dev *dev) {
+ *bb_perip(&dev->regs->CR2, ADC_CR2_ADON_BIT) = 1;
+}
+
+/**
+ * @brief Disable an ADC peripheral
+ * @param dev ADC device to disable
+ */
+static inline void adc_disable(const adc_dev *dev) {
+ *bb_perip(&dev->regs->CR2, ADC_CR2_ADON_BIT) = 0;
+}
+
+/**
+ * @brief Disable all ADC peripherals.
+ */
+static inline void adc_disable_all(void) {
+ adc_foreach(adc_disable);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/bitband.h b/libmaple/include/libmaple/bitband.h
new file mode 100644
index 0000000..6e77991
--- /dev/null
+++ b/libmaple/include/libmaple/bitband.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/bitband.h
+ *
+ * @brief Bit-banding utility functions
+ */
+
+#ifndef _LIBMAPLE_BITBAND_H_
+#define _LIBMAPLE_BITBAND_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+#define BB_SRAM_REF 0x20000000
+#define BB_SRAM_BASE 0x22000000
+#define BB_PERI_REF 0x40000000
+#define BB_PERI_BASE 0x42000000
+
+static inline volatile uint32* __bb_addr(volatile void*,
+ uint32,
+ uint32,
+ uint32);
+
+/**
+ * @brief Obtain a pointer to the bit-band address corresponding to a
+ * bit in a volatile SRAM address.
+ * @param address Address in the bit-banded SRAM region
+ * @param bit Bit in address to bit-band
+ */
+static inline volatile uint32* bb_sramp(volatile void *address, uint32 bit) {
+ return __bb_addr(address, bit, BB_SRAM_BASE, BB_SRAM_REF);
+}
+
+/**
+ * @brief Get a bit from an address in the SRAM bit-band region.
+ * @param address Address in the SRAM bit-band region to read from
+ * @param bit Bit in address to read
+ * @return bit's value in address.
+ */
+static inline uint8 bb_sram_get_bit(volatile void *address, uint32 bit) {
+ return *bb_sramp(address, bit);
+}
+
+/**
+ * @brief Set a bit in an address in the SRAM bit-band region.
+ * @param address Address in the SRAM bit-band region to write to
+ * @param bit Bit in address to write to
+ * @param val Value to write for bit, either 0 or 1.
+ */
+static inline void bb_sram_set_bit(volatile void *address,
+ uint32 bit,
+ uint8 val) {
+ *bb_sramp(address, bit) = val;
+}
+
+/**
+ * @brief Obtain a pointer to the bit-band address corresponding to a
+ * bit in a peripheral address.
+ * @param address Address in the bit-banded peripheral region
+ * @param bit Bit in address to bit-band
+ */
+static inline volatile uint32* bb_perip(volatile void *address, uint32 bit) {
+ return __bb_addr(address, bit, BB_PERI_BASE, BB_PERI_REF);
+}
+
+/**
+ * @brief Get a bit from an address in the peripheral bit-band region.
+ * @param address Address in the peripheral bit-band region to read from
+ * @param bit Bit in address to read
+ * @return bit's value in address.
+ */
+static inline uint8 bb_peri_get_bit(volatile void *address, uint32 bit) {
+ return *bb_perip(address, bit);
+}
+
+/**
+ * @brief Set a bit in an address in the peripheral bit-band region.
+ * @param address Address in the peripheral bit-band region to write to
+ * @param bit Bit in address to write to
+ * @param val Value to write for bit, either 0 or 1.
+ */
+static inline void bb_peri_set_bit(volatile void *address,
+ uint32 bit,
+ uint8 val) {
+ *bb_perip(address, bit) = val;
+}
+
+static inline volatile uint32* __bb_addr(volatile void *address,
+ uint32 bit,
+ uint32 bb_base,
+ uint32 bb_ref) {
+ return (volatile uint32*)(bb_base + ((uint32)address - bb_ref) * 32 +
+ bit * 4);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/bkp.h b/libmaple/include/libmaple/bkp.h
new file mode 100644
index 0000000..bb63a2f
--- /dev/null
+++ b/libmaple/include/libmaple/bkp.h
@@ -0,0 +1,166 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/bkp.h
+ * @brief Backup register support (STM32F1 only).
+ */
+
+#ifndef _LIBMAPLE_BKP_H_
+#define _LIBMAPLE_BKP_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple.h>
+
+#if defined(STM32_MEDIUM_DENSITY)
+#define BKP_NR_DATA_REGS 10
+#elif defined(STM32_HIGH_DENSITY)
+#define BKP_NR_DATA_REGS 42
+#endif
+
+/** Backup peripheral register map type. */
+typedef struct bkp_reg_map {
+ const uint32 RESERVED1; ///< Reserved
+ __io uint32 DR1; ///< Data register 1
+ __io uint32 DR2; ///< Data register 2
+ __io uint32 DR3; ///< Data register 3
+ __io uint32 DR4; ///< Data register 4
+ __io uint32 DR5; ///< Data register 5
+ __io uint32 DR6; ///< Data register 6
+ __io uint32 DR7; ///< Data register 7
+ __io uint32 DR8; ///< Data register 8
+ __io uint32 DR9; ///< Data register 9
+ __io uint32 DR10; ///< Data register 10
+ __io uint32 RTCCR; ///< RTC control register
+ __io uint32 CR; ///< Control register
+ __io uint32 CSR; ///< Control and status register
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ const uint32 RESERVED2; ///< Reserved
+ const uint32 RESERVED3; ///< Reserved
+ __io uint32 DR11; ///< Data register 11
+ __io uint32 DR12; ///< Data register 12
+ __io uint32 DR13; ///< Data register 13
+ __io uint32 DR14; ///< Data register 14
+ __io uint32 DR15; ///< Data register 15
+ __io uint32 DR16; ///< Data register 16
+ __io uint32 DR17; ///< Data register 17
+ __io uint32 DR18; ///< Data register 18
+ __io uint32 DR19; ///< Data register 19
+ __io uint32 DR20; ///< Data register 20
+ __io uint32 DR21; ///< Data register 21
+ __io uint32 DR22; ///< Data register 22
+ __io uint32 DR23; ///< Data register 23
+ __io uint32 DR24; ///< Data register 24
+ __io uint32 DR25; ///< Data register 25
+ __io uint32 DR26; ///< Data register 26
+ __io uint32 DR27; ///< Data register 27
+ __io uint32 DR28; ///< Data register 28
+ __io uint32 DR29; ///< Data register 29
+ __io uint32 DR30; ///< Data register 30
+ __io uint32 DR31; ///< Data register 31
+ __io uint32 DR32; ///< Data register 32
+ __io uint32 DR33; ///< Data register 33
+ __io uint32 DR34; ///< Data register 34
+ __io uint32 DR35; ///< Data register 35
+ __io uint32 DR36; ///< Data register 36
+ __io uint32 DR37; ///< Data register 37
+ __io uint32 DR38; ///< Data register 38
+ __io uint32 DR39; ///< Data register 39
+ __io uint32 DR40; ///< Data register 40
+ __io uint32 DR41; ///< Data register 41
+ __io uint32 DR42; ///< Data register 42
+#endif
+} bkp_reg_map;
+
+/** Backup peripheral register map base pointer. */
+#define BKP_BASE ((struct bkp_reg_map*)0x40006C00)
+
+/** Backup peripheral device type. */
+typedef struct bkp_dev {
+ bkp_reg_map *regs; /**< Register map */
+} bkp_dev;
+
+extern const bkp_dev *BKP;
+
+/*
+ * Register bit definitions
+ */
+
+/* Data Registers */
+
+#define BKP_DR_D 0xFFFF
+
+/* RTC Clock Calibration Register */
+
+#define BKP_RTCCR_ASOS_BIT 9
+#define BKP_RTCCR_ASOE_BIT 8
+#define BKP_RTCCR_CCO_BIT 7
+
+#define BKP_RTCCR_ASOS BIT(BKP_RTCCR_ASOS_BIT)
+#define BKP_RTCCR_ASOE BIT(BKP_RTCCR_ASOE_BIT)
+#define BKP_RTCCR_CCO BIT(BKP_RTCCR_CCO_BIT)
+#define BKP_RTCCR_CAL 0x7F
+
+/* Backup control register */
+
+#define BKP_CR_TPAL_BIT 1
+#define BKP_CR_TPE_BIT 0
+
+#define BKP_CR_TPAL BIT(BKP_CR_TPAL_BIT)
+#define BKP_CR_TPE BIT(BKP_CR_TPE_BIT)
+
+/* Backup control/status register */
+
+#define BKP_CSR_TIF_BIT 9
+#define BKP_CSR_TEF_BIT 8
+#define BKP_CSR_TPIE_BIT 2
+#define BKP_CSR_CTI_BIT 1
+#define BKP_CSR_CTE_BIT 0
+
+#define BKP_CSR_TIF BIT(BKP_CSR_TIF_BIT)
+#define BKP_CSR_TEF BIT(BKP_CSR_TEF_BIT)
+#define BKP_CSR_TPIE BIT(BKP_CSR_TPIE_BIT)
+#define BKP_CSR_CTI BIT(BKP_CSR_CTI_BIT)
+#define BKP_CSR_CTE BIT(BKP_CSR_CTE_BIT)
+
+/*
+ * Convenience functions
+ */
+
+void bkp_init(void);
+void bkp_enable_writes(void);
+void bkp_disable_writes(void);
+uint16 bkp_read(uint8 reg);
+void bkp_write(uint8 reg, uint16 val);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/dac.h b/libmaple/include/libmaple/dac.h
new file mode 100644
index 0000000..56bfdc4
--- /dev/null
+++ b/libmaple/include/libmaple/dac.h
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Bryan Newbold.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/dac.h
+ * @brief Digital to analog converter support.
+ */
+
+/* See notes/dac.txt for more info */
+
+#ifndef _LIBMAPLE_DAC_H_
+#define _LIBMAPLE_DAC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <series/dac.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+#include <libmaple/stm32.h>
+
+/*
+ * Register map base and device pointers.
+ *
+ * The DACs are the same on all supported targets, so it's not worth
+ * repeating these in the series headers.
+ */
+
+#define DAC_BASE ((struct dac_reg_map*)0x40007400)
+
+/** DAC device type. */
+typedef struct dac_dev {
+ dac_reg_map *regs; /**< Register map */
+} dac_dev;
+
+#if STM32_HAVE_DAC
+extern const dac_dev *DAC;
+#endif
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+
+/* Channel 1 control */
+#define DAC_CR_EN1 (1U << 0) /* Enable */
+#define DAC_CR_BOFF1 (1U << 1) /* Output buffer disable */
+#define DAC_CR_TEN1 (1U << 2) /* Trigger enable */
+#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */
+#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave */
+#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */
+#define DAC_CR_DMAEN1 (1U << 12) /* DMA enable */
+/* Channel 2 control */
+#define DAC_CR_EN2 (1U << 16) /* Enable */
+#define DAC_CR_BOFF2 (1U << 17) /* Output buffer disable */
+#define DAC_CR_TEN2 (1U << 18) /* Trigger enable */
+#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */
+#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave */
+#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */
+#define DAC_CR_DMAEN2 (1U << 28) /* DMA enable */
+
+/* Software trigger register */
+
+#define DAC_SWTRIGR_SWTRIG1 (1U << 0) /* Channel 1 software trigger */
+#define DAC_SWTRIGR_SWTRIG2 (1U << 1) /* Channel 2 software trigger */
+
+/* Channel 1 12-bit right-aligned data holding register */
+
+#define DAC_DHR12R1_DACC1DHR 0x00000FFF
+
+/* Channel 1 12-bit left-aligned data holding register */
+
+#define DAC_DHR12L1_DACC1DHR 0x0000FFF0
+
+/* Channel 1 8-bit left-aligned data holding register */
+
+#define DAC_DHR8R1_DACC1DHR 0x000000FF
+
+/* Channel 2 12-bit right-aligned data holding register */
+
+#define DAC_DHR12R2_DACC2DHR 0x00000FFF
+
+/* Channel 2 12-bit left-aligned data holding register */
+
+#define DAC_DHR12L2_DACC2DHR 0x0000FFF0
+
+/* Channel 2 8-bit left-aligned data holding register */
+
+#define DAC_DHR8R2_DACC2DHR 0x000000FF
+
+/* Dual DAC 12-bit right-aligned data holding register */
+
+#define DAC_DHR12RD_DACC1DHR 0x00000FFF
+#define DAC_DHR12RD_DACC2DHR 0x0FFF0000
+
+/* Dual DAC 12-bit left-aligned data holding register */
+
+#define DAC_DHR12LD_DACC1DHR 0x0000FFF0
+#define DAC_DHR12LD_DACC2DHR 0xFFF00000
+
+/* Dual DAC 8-bit left-aligned data holding register */
+
+#define DAC_DHR8RD_DACC1DHR 0x000000FF
+#define DAC_DHR8RD_DACC2DHR 0x0000FF00
+
+/* Channel 1 data output register */
+
+#define DAC_DOR1_DACC1DOR 0x00000FFF
+
+/* Channel 1 data output register */
+
+#define DAC_DOR2_DACC2DOR 0x00000FFF
+
+/*
+ * Routines
+ */
+
+/* We take the dev argument in these for future-proofing */
+
+#define DAC_CH1 0x1
+#define DAC_CH2 0x2
+void dac_init(const dac_dev *dev, uint32 flags);
+
+void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val);
+void dac_enable_channel(const dac_dev *dev, uint8 channel);
+void dac_disable_channel(const dac_dev *dev, uint8 channel);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/delay.h b/libmaple/include/libmaple/delay.h
new file mode 100644
index 0000000..472a208
--- /dev/null
+++ b/libmaple/include/libmaple/delay.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/delay.h
+ * @brief Delay implementation
+ */
+
+#ifndef _LIBMAPLE_DELAY_H_
+#define _LIBMAPLE_DELAY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.h>
+
+/**
+ * @brief Delay the given number of microseconds.
+ *
+ * @param us Number of microseconds to delay.
+ */
+static inline void delay_us(uint32 us) {
+ us *= STM32_DELAY_US_MULT;
+
+ /* fudge for function call overhead */
+ us--;
+ asm volatile(" mov r0, %[us] \n\t"
+ "1: subs r0, #1 \n\t"
+ " bhi 1b \n\t"
+ :
+ : [us] "r" (us)
+ : "r0");
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/dma.h b/libmaple/include/libmaple/dma.h
new file mode 100644
index 0000000..e22cdaf
--- /dev/null
+++ b/libmaple/include/libmaple/dma.h
@@ -0,0 +1,444 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/dma.h
+ *
+ * @author Marti Bolivar <mbolivar@leaflabs.com>;
+ * Original implementation by Michael Hope
+ *
+ * @brief Direct Memory Access peripheral support
+ */
+
+#ifndef _LIBMAPLE_DMA_H_
+#define _LIBMAPLE_DMA_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* <series/dma.h> provides:
+ *
+ * - An opaque dma_tube type, and predefined rvalues for each tube
+ * supported by the series.
+ *
+ * A "DMA tube" is a series-specific (hopefully integer) datatype
+ * that abstracts the conduit through which DMA-ed data flow.
+ *
+ * Examples: On STM32F1, dma_tube is just an alias for dma_channel,
+ * and the tube values are just DMA_CH1 (=1), DMA_CH2 (=2), etc.
+ *
+ * Note that a dma_tube doesn't have to be an enum, and its values
+ * don't have to be integral. They _do_ need to be cheap to pass as
+ * arguments, though.
+ *
+ * - struct dma_tube_reg_map (and typedef to dma_tube_reg_map). DMA
+ * register maps tend to be split into global registers and per-tube
+ * registers. It's convenient to pass around pointers to a tube's
+ * registers, since that makes it possible to configure or otherwise
+ * mess with a tube without knowing which one you're dealing with.
+ *
+ * - Base pointers to the various dma_tube_reg_maps.
+ *
+ * Examples: On STM32F1, these are DMAxCHy_BASE. You can access
+ * registers like DMAxCHy_BASE->CPAR, etc.
+ *
+ * - enum dma_request_src (and typedef to dma_request_src). This
+ * specifies the peripheral DMA request sources (e.g. USART TX DMA
+ * requests, etc.).
+ *
+ * - enum dma_mode_flags (and typedef to dma_mode_flags). Used in
+ * dma_tube_config. If two series both support the same mode flags,
+ * they must use the same enumerator names for those flags (the
+ * values of those enumerators are of course allowed to differ).
+ *
+ * - Normal stuff: dma_reg_map and base pointers, register bit
+ * definitions, dma_dev pointer declarations, and any other
+ * convenience functions useful for the series. */
+#include <series/dma.h>
+/* <libmaple/dma_common.h> buys us dma_dev and other necessities. */
+#include <libmaple/dma_common.h>
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Declarations/documentation for some of the series-provided types.
+ */
+
+/**
+ * @brief (Series-dependent) DMA request sources.
+ *
+ * These specify the various pieces of peripheral functionality which
+ * may make DMA requests. Use them to set up a DMA transfer (see
+ * struct dma_tube_config, dma_tube_cfg()).
+ */
+enum dma_request_src;
+
+/**
+ * @brief (Series-dependent) DMA tube configuration flags.
+ * These specify miscellaneous bits of configuration for a DMA tube.
+ * @see struct dma_mode_config
+ */
+enum dma_cfg_flags;
+
+/**
+ * @brief (Series-dependent) DMA tube register map type.
+ * This allows you to access a tube's registers as a group.
+ * @see dma_tube_regs()
+ */
+struct dma_tube_reg_map;
+
+/*
+ * Convenience functions
+ */
+
+/* Initialization */
+
+void dma_init(dma_dev *dev);
+
+/* dma_tube configuration
+ *
+ * Use these types and functions to set up DMA transfers, handle
+ * interrupts, etc. The main function of interest is dma_tube_cfg(),
+ * which the various series implement separately. */
+
+/**
+ * @brief Specifies a DMA tube configuration.
+ *
+ * Use one of these to set up a DMA transfer by passing it to
+ * dma_tube_cfg().
+ *
+ * @see dma_tube_cfg()
+ * @see dma_xfer_size
+ */
+typedef struct dma_tube_config {
+ /** Source of data */
+ __io void *tube_src;
+ /** Source transfer size */
+ dma_xfer_size tube_src_size;
+
+ /** Destination of data */
+ __io void *tube_dst;
+ /** Destination transfer size */
+ dma_xfer_size tube_dst_size;
+
+ /**
+ * Number of data to transfer (0 to 65,535).
+ *
+ * Note that this is NOT measured in bytes; it's measured in
+ * number of data, which occur in multiples of tube_src_size. For
+ * example, if tube_src_size is DMA_SIZE_32BITS and tube_nr_xfers
+ * is 2, then 8 total bytes will be transferred.
+ */
+ unsigned tube_nr_xfers;
+
+ /**
+ * Target-specific configuration flags.
+ *
+ * These are an OR of series-specific enum dma_mode_flags values.
+ * Consult the documentation for your target for what flags you
+ * can use here.
+ *
+ * Typical flag examples: DMA_CFG_SRC_INC, DMA_CFG_DST_INC,
+ * DMA_CFG_CIRC, DMA_CFG_CMPLT_IE, etc.
+ */
+ unsigned tube_flags;
+
+ /**
+ * Currently unused. You must set this to 0 or something valid for
+ * your target. */
+ void *target_data;
+
+ /**
+ * Hardware DMA request source.
+ *
+ * This is ignored for memory-to-memory transfers.
+ */
+ enum dma_request_src tube_req_src;
+} dma_tube_config;
+
+#define DMA_TUBE_CFG_SUCCESS 0
+#define DMA_TUBE_CFG_EREQ 1
+#define DMA_TUBE_CFG_ENDATA 2
+#define DMA_TUBE_CFG_EDEV 3
+#define DMA_TUBE_CFG_ESRC 4
+#define DMA_TUBE_CFG_EDST 5
+#define DMA_TUBE_CFG_EDIR 6
+#define DMA_TUBE_CFG_ESIZE 7
+#define DMA_TUBE_CFG_ECFG 0xFF
+/**
+ * @brief Configure a DMA tube.
+ *
+ * Use this function to set up a DMA transfer. The tube will be
+ * disabled before being reconfigured. The transfer will have low
+ * priority by default. You can choose another priority before the
+ * transfer begins using dma_set_priority(). You can manage your
+ * interrupt handlers for the tube using dma_attach_interrupt() and
+ * dma_detach_interrupt().
+ *
+ * After calling dma_tube_cfg() and performing any other desired
+ * configuration, start the transfer using dma_enable().
+ *
+ * @param dev DMA device.
+ * @param tube DMA tube to configure.
+ * @param cfg Configuration to apply to tube.
+ *
+ * @return DMA_TUBE_CFG_SUCCESS (0) on success, <0 on failure. On
+ * failure, returned value will be the opposite (-) of one of:
+ *
+ * - DMA_TUBE_CFG_EREQ: tube doesn't work with cfg->tube_req_src
+ * - DMA_TUBE_CFG_ENDATA: cfg->tube_[src,dst]_size are
+ * incompatible with cfg->tube_nr_xfers, or cfg->tube_nr_xfers
+ * is out of bounds.
+ * - DMA_TUBE_CFG_EDEV: dev does not support cfg
+ * - DMA_TUBE_CFG_ESRC: bad cfg->tube_src
+ * - DMA_TUBE_CFG_EDST: bad cfg->tube_dst
+ * - DMA_TUBE_CFG_EDIR: dev can't transfer from cfg->tube_src to
+ * cfg->tube_dst
+ * - DMA_TUBE_CFG_ESIZE: something ended up wrong due to MSIZE/PSIZE
+ * - DMA_TUBE_CFG_ECFG: generic "something's wrong"
+ *
+ * @sideeffect Disables tube. May alter tube's registers even when an
+ * error occurs.
+ * @see struct dma_tube_config
+ * @see dma_attach_interrupt()
+ * @see dma_detach_interrupt()
+ * @see dma_enable()
+ */
+extern int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg);
+
+/* Other tube configuration functions. You can use these if
+ * dma_tube_cfg() isn't enough, or to adjust parts of an existing tube
+ * configuration. */
+
+/** DMA transfer priority. */
+typedef enum dma_priority {
+ DMA_PRIORITY_LOW = 0, /**< Low priority */
+ DMA_PRIORITY_MEDIUM = 1, /**< Medium priority */
+ DMA_PRIORITY_HIGH = 2, /**< High priority */
+ DMA_PRIORITY_VERY_HIGH = 3, /**< Very high priority */
+} dma_priority;
+
+/**
+ * @brief Set the priority of a DMA transfer.
+ *
+ * You may not call this function while the tube is enabled.
+ *
+ * @param dev DMA device
+ * @param tube DMA tube
+ * @param priority priority to set.
+ */
+extern void dma_set_priority(dma_dev *dev, dma_tube tube,
+ dma_priority priority);
+
+/**
+ * @brief Set the number of data transfers on a DMA tube.
+ *
+ * You may not call this function while the tube is enabled.
+ *
+ * @param dev DMA device
+ * @param tube Tube through which the transfer will occur.
+ * @param num_transfers Number of DMA transactions to set.
+ */
+extern void dma_set_num_transfers(dma_dev *dev, dma_tube tube,
+ uint16 num_transfers);
+
+/**
+ * @brief Set the base memory address where data will be read from or
+ * written to.
+ *
+ * You must not call this function while the tube is enabled.
+ *
+ * If the DMA memory size is 16 bits, the address is automatically
+ * aligned to a half-word. If the DMA memory size is 32 bits, the
+ * address is aligned to a word.
+ *
+ * @param dev DMA Device
+ * @param tube Tube whose base memory address to set.
+ * @param address Memory base address to use.
+ */
+extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address);
+
+/**
+ * @brief Set the base peripheral address where data will be read from
+ * or written to.
+ *
+ * You must not call this function while the channel is enabled.
+ *
+ * If the DMA peripheral size is 16 bits, the address is automatically
+ * aligned to a half-word. If the DMA peripheral size is 32 bits, the
+ * address is aligned to a word.
+ *
+ * @param dev DMA Device
+ * @param tube Tube whose peripheral data register base address to set.
+ * @param address Peripheral memory base address to use.
+ */
+extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address);
+
+/* Interrupt handling */
+
+/**
+ * @brief Attach an interrupt to a DMA transfer.
+ *
+ * Interrupts are enabled using series-specific mode flags in
+ * dma_tube_cfg().
+ *
+ * @param dev DMA device
+ * @param tube Tube to attach handler to
+ * @param handler Interrupt handler to call when tube interrupt fires.
+ * @see dma_tube_cfg()
+ * @see dma_get_irq_cause()
+ * @see dma_detach_interrupt()
+ */
+extern void dma_attach_interrupt(dma_dev *dev, dma_tube tube,
+ void (*handler)(void));
+
+
+/**
+ * @brief Detach a DMA transfer interrupt handler.
+ *
+ * After calling this function, the given tube's interrupts will be
+ * disabled.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose handler to detach
+ * @sideeffect Clears the tube's interrupt enable bits.
+ * @see dma_attach_interrupt()
+ */
+extern void dma_detach_interrupt(dma_dev *dev, dma_tube tube);
+
+/* Tube enable/disable */
+
+/**
+ * @brief Enable a DMA tube.
+ *
+ * If the tube has been properly configured, calling this function
+ * allows it to start serving DMA requests.
+ *
+ * @param dev DMA device
+ * @param tube Tube to enable
+ * @see dma_tube_cfg()
+ */
+extern void dma_enable(dma_dev *dev, dma_tube tube);
+
+/**
+ * @brief Disable a DMA channel.
+ *
+ * Calling this function makes the tube stop serving DMA requests.
+ *
+ * @param dev DMA device
+ * @param tube Tube to disable
+ */
+extern void dma_disable(dma_dev *dev, dma_tube tube);
+
+/**
+ * @brief Check if a DMA tube is enabled.
+ * @param dev DMA device.
+ * @param tube Tube to check.
+ * @return 0 if the tube is disabled, >0 if it is enabled.
+ */
+static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube);
+
+/* Other conveniences */
+
+/**
+ * @brief Obtain a pointer to an individual DMA tube's registers.
+ *
+ * Examples:
+ *
+ * - On STM32F1, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1.
+ *
+ * @param dev DMA device.
+ * @param tube DMA tube whose register map to obtain.
+ * @return (Series-specific) tube register map.
+ */
+static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube);
+
+/**
+ * Encodes the reason why a DMA interrupt was called.
+ * @see dma_get_irq_cause()
+ */
+typedef enum dma_irq_cause {
+ DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */
+ DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */
+ DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */
+ DMA_TRANSFER_DME_ERROR, /**<
+ * @brief Direct mode error occurred during
+ * transfer. */
+ DMA_TRANSFER_FIFO_ERROR, /**< FIFO error occurred during transfer. */
+} dma_irq_cause;
+
+/**
+ * @brief Discover the reason why a DMA interrupt was called.
+ *
+ * You may only call this function within an attached interrupt
+ * handler for the given channel.
+ *
+ * This function resets the internal DMA register state which encodes
+ * the cause of the interrupt; consequently, it can only be called
+ * once per interrupt handler invocation.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose interrupt is being handled.
+ * @return Reason why the interrupt fired.
+ * @sideeffect Clears flags in dev's interrupt status registers.
+ * @see dma_attach_interrupt()
+ * @see dma_irq_cause
+ */
+extern dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube);
+
+/**
+ * @brief Get the ISR status bits for a DMA channel.
+ *
+ * The bits are returned right-aligned, in the order they appear in
+ * the corresponding ISR register.
+ *
+ * If you're trying to figure out why a DMA interrupt fired, you may
+ * find dma_get_irq_cause() more convenient.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose ISR bits to return.
+ * @see dma_get_irq_cause().
+ */
+static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube);
+
+/**
+ * @brief Clear the ISR status bits for a given DMA tube.
+ *
+ * If you're trying to clean up after yourself in a DMA interrupt, you
+ * may find dma_get_irq_cause() more convenient.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose ISR bits to clear.
+ * @see dma_get_irq_cause()
+ */
+static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/dma_common.h b/libmaple/include/libmaple/dma_common.h
new file mode 100644
index 0000000..3765cd5
--- /dev/null
+++ b/libmaple/include/libmaple/dma_common.h
@@ -0,0 +1,112 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/dma_common.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Common DMA sub-header for <series/dma.h> and <libmaple/dma.h>.
+ *
+ * CONTENTS UNSTABLE. The existence of this file is an implementation
+ * detail. Never include it directly. If you need something from
+ * here, include <libmaple/dma.h> instead.
+ */
+
+/*
+ * There's a fair amount of common DMA functionality needed by each
+ * <series/dma.h> and <libmaple/dma.h>. This header exists in order
+ * to provide it to both, avoiding some hacks and circular
+ * dependencies.
+ */
+
+#ifndef _LIBMAPLE_DMA_COMMON_H_
+#define _LIBMAPLE_DMA_COMMON_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/nvic.h>
+#include <libmaple/rcc.h>
+
+/*
+ * Devices
+ */
+
+struct dma_reg_map;
+
+/* Encapsulates state related to user interrupt handlers. You
+ * shouldn't touch these directly; use dma_attach_interrupt() and
+ * dma_detach_interupt() instead. */
+typedef struct dma_handler_config {
+ void (*handler)(void); /* User handler */
+ nvic_irq_num irq_line; /* IRQ line for interrupt */
+} dma_handler_config;
+
+/** DMA device type */
+typedef struct dma_dev {
+ struct dma_reg_map *regs; /**< Register map */
+ rcc_clk_id clk_id; /**< Clock ID */
+ struct dma_handler_config handlers[]; /**< For internal use */
+} dma_dev;
+
+/**
+ * @brief DMA channels
+ *
+ * Notes:
+ * - This is also the dma_tube type for STM32F1.
+ * - Channel 0 is not available on all STM32 series.
+ *
+ * @see dma_tube
+ */
+typedef enum dma_channel {
+ DMA_CH0 = 0, /**< Channel 0 */
+ DMA_CH1 = 1, /**< Channel 1 */
+ DMA_CH2 = 2, /**< Channel 2 */
+ DMA_CH3 = 3, /**< Channel 3 */
+ DMA_CH4 = 4, /**< Channel 4 */
+ DMA_CH5 = 5, /**< Channel 5 */
+ DMA_CH6 = 6, /**< Channel 6 */
+ DMA_CH7 = 7, /**< Channel 7 */
+} dma_channel;
+
+/**
+ * @brief Source and destination transfer sizes.
+ * Use these when initializing a struct dma_tube_config.
+ * @see struct dma_tube_config
+ * @see dma_tube_cfg
+ */
+typedef enum dma_xfer_size {
+ DMA_SIZE_8BITS = 0, /**< 8-bit transfers */
+ DMA_SIZE_16BITS = 1, /**< 16-bit transfers */
+ DMA_SIZE_32BITS = 2, /**< 32-bit transfers */
+} dma_xfer_size;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/exti.h b/libmaple/include/libmaple/exti.h
new file mode 100644
index 0000000..1d201ac
--- /dev/null
+++ b/libmaple/include/libmaple/exti.h
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/exti.h
+ * @brief External interrupt control
+ */
+
+/* See notes/exti.txt for more info */
+
+#ifndef _LIBMAPLE_EXTI_H_
+#define _LIBMAPLE_EXTI_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <series/exti.h> /* provides EXTI_BASE */
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map and base pointer.
+ */
+
+/** EXTI register map type */
+typedef struct exti_reg_map {
+ __io uint32 IMR; /**< Interrupt mask register */
+ __io uint32 EMR; /**< Event mask register */
+ __io uint32 RTSR; /**< Rising trigger selection register */
+ __io uint32 FTSR; /**< Falling trigger selection register */
+ __io uint32 SWIER; /**< Software interrupt event register */
+ __io uint32 PR; /**< Pending register */
+} exti_reg_map;
+
+/*
+ * Types: exti_num, exti_cfg, exti_trigger_mode.
+ *
+ * A combination of these three specifies an external interrupt
+ * configuration (see exti_attach_interrupt()).
+ */
+
+/** EXTI line. */
+typedef enum exti_num {
+ EXTI0, /**< EXTI line 0 */
+ EXTI1, /**< EXTI line 1 */
+ EXTI2, /**< EXTI line 2 */
+ EXTI3, /**< EXTI line 3 */
+ EXTI4, /**< EXTI line 4 */
+ EXTI5, /**< EXTI line 5 */
+ EXTI6, /**< EXTI line 6 */
+ EXTI7, /**< EXTI line 7 */
+ EXTI8, /**< EXTI line 8 */
+ EXTI9, /**< EXTI line 9 */
+ EXTI10, /**< EXTI line 10 */
+ EXTI11, /**< EXTI line 11 */
+ EXTI12, /**< EXTI line 12 */
+ EXTI13, /**< EXTI line 13 */
+ EXTI14, /**< EXTI line 14 */
+ EXTI15, /**< EXTI line 15 */
+} exti_num;
+
+/**
+ * @brief EXTI port configuration
+ *
+ * These specify which GPIO port an external interrupt line should be
+ * connected to.
+ */
+typedef enum exti_cfg {
+ EXTI_PA, /**< Use PAx pin */
+ EXTI_PB, /**< Use PBx pin */
+ EXTI_PC, /**< Use PCx pin */
+ EXTI_PD, /**< Use PDx pin */
+ EXTI_PE, /**< Use PEx pin */
+ EXTI_PF, /**< Use PFx pin */
+ EXTI_PG, /**< Use PGx pin */
+ EXTI_PH, /**< Use PHx pin */
+ EXTI_PI, /**< Use PIx pin */
+} exti_cfg;
+
+/** External interrupt trigger mode */
+typedef enum exti_trigger_mode {
+ EXTI_RISING, /**< Trigger on the rising edge */
+ EXTI_FALLING, /**< Trigger on the falling edge */
+ EXTI_RISING_FALLING /**< Trigger on both the rising and falling edges */
+} exti_trigger_mode;
+
+/*
+ * Routines
+ */
+
+void exti_attach_interrupt(exti_num num,
+ exti_cfg port,
+ voidFuncPtr handler,
+ exti_trigger_mode mode);
+void exti_attach_callback(exti_num num,
+ exti_cfg port,
+ voidArgumentFuncPtr handler,
+ void *arg,
+ exti_trigger_mode mode);
+void exti_detach_interrupt(exti_num num);
+
+/**
+ * @brief Set the GPIO port for an EXTI line.
+ *
+ * This is a low-level routine that most users will not
+ * need. exti_attach_interrupt() handles calling this function
+ * appropriately.
+ *
+ * @param num EXTI line
+ * @param port EXTI configuration for GPIO port to connect to num.
+ * @see exti_num
+ * @see exti_cfg
+ */
+extern void exti_select(exti_num num, exti_cfg port);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/flash.h b/libmaple/include/libmaple/flash.h
new file mode 100644
index 0000000..943e466
--- /dev/null
+++ b/libmaple/include/libmaple/flash.h
@@ -0,0 +1,106 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/flash.h
+ * @brief Flash support.
+ */
+
+#ifndef _LIBMAPLE_FLASH_H_
+#define _LIBMAPLE_FLASH_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+#define FLASH_WAIT_STATE_0 0x0
+#define FLASH_WAIT_STATE_1 0x1
+#define FLASH_WAIT_STATE_2 0x2
+#define FLASH_WAIT_STATE_3 0x3
+#define FLASH_WAIT_STATE_4 0x4
+#define FLASH_WAIT_STATE_5 0x5
+#define FLASH_WAIT_STATE_6 0x6
+#define FLASH_WAIT_STATE_7 0x7
+
+/* The series header must define:
+ *
+ * - FLASH_SAFE_WAIT_STATES, the smallest number of wait states that
+ * it is safe to use when SYSCLK is at its fastest documented rate
+ * and the MCU is powered at 3.3V (i.e. this doesn't consider
+ * overclocking or low voltage operation).
+ *
+ * - The following bit flags, for flash_enable_features():
+ *
+ * -- FLASH_PREFETCH: prefetcher
+ * -- FLASH_ICACHE: instruction cache
+ * -- FLASH_DCACHE: data cache
+ *
+ * See that function's Doxygen for more restrictions.
+ */
+#include <series/flash.h>
+
+#ifdef __DOXYGEN__
+/** Flash register map base pointer. */
+#define FLASH_BASE
+#endif
+
+/*
+ * Flash routines
+ */
+
+void flash_set_latency(uint32 wait_states);
+
+/**
+ * @brief Enable Flash memory features
+ *
+ * If the target MCU doesn't provide a feature (e.g. instruction and
+ * data caches on the STM32F1), the flag will be ignored. This allows
+ * using these flags unconditionally, with the desired effect taking
+ * place on targets that support them.
+ *
+ * @param feature_flags Bitwise OR of the following:
+ * FLASH_PREFETCH (turns on prefetcher),
+ * FLASH_ICACHE (turns on instruction cache),
+ * FLASH_DCACHE (turns on data cache).
+ */
+static inline void flash_enable_features(uint32 feature_flags) {
+ FLASH_BASE->ACR |= feature_flags;
+}
+
+/**
+ * @brief Deprecated. Use flash_enable_features(FLASH_PREFETCH) instead.
+ */
+static inline void flash_enable_prefetch(void) {
+ flash_enable_features(FLASH_PREFETCH);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/fsmc.h b/libmaple/include/libmaple/fsmc.h
new file mode 100644
index 0000000..6225fee
--- /dev/null
+++ b/libmaple/include/libmaple/fsmc.h
@@ -0,0 +1,340 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Bryan Newbold.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/fsmc.h
+ * @brief Flexible static memory controller support.
+ */
+
+/*
+ * See ../notes/fsmc.txt for more info
+ */
+
+#ifndef _LIBMAPLE_FSMC_H_
+#define _LIBMAPLE_FSMC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.h>
+
+#if !STM32_HAVE_FSMC
+#error "FSMC is unavailable on your MCU"
+#endif
+
+/*
+ * Register maps and devices
+ */
+
+/** FSMC register map type */
+typedef struct fsmc_reg_map {
+ __io uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */
+ __io uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */
+ __io uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */
+ __io uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */
+ __io uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */
+ __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */
+ __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */
+ __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */
+ const uint8 RESERVED1[64]; /**< Reserved */
+ __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */
+ __io uint32 SR2; /**< FIFO status and interrupt register 2 */
+ __io uint32 PMEM2; /**< Common memory space timing register 2 */
+ __io uint32 PATT2; /**< Attribute memory space timing register 2 */
+ const uint8 RESERVED2[4]; /**< Reserved */
+ __io uint32 ECCR2; /**< ECC result register 2 */
+ const uint8 RESERVED3[2];
+ __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */
+ __io uint32 SR3; /**< FIFO status and interrupt register 3 */
+ __io uint32 PMEM3; /**< Common memory space timing register 3 */
+ __io uint32 PATT3; /**< Attribute memory space timing register 3 */
+ const uint32 RESERVED4; /**< Reserved */
+ __io uint32 ECCR3; /**< ECC result register 3 */
+ const uint8 RESERVED5[8]; /**< Reserved */
+ __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */
+ __io uint32 SR4; /**< FIFO status and interrupt register 4 */
+ __io uint32 PMEM4; /**< Common memory space timing register 4 */
+ __io uint32 PATT4; /**< Attribute memory space timing register 4 */
+ __io uint32 PIO4; /**< I/O space timing register 4 */
+ const uint8 RESERVED6[80]; /**< Reserved */
+ __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */
+ const uint32 RESERVED7; /**< Reserved */
+ __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */
+ const uint32 RESERVED8; /**< Reserved */
+ __io uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */
+ const uint32 RESERVED9; /**< Reserved */
+ __io uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */
+} __attribute__((packed)) fsmc_reg_map;
+
+#define __FSMCB 0xA0000000
+
+/** FSMC register map base pointer */
+#define FSMC_BASE ((struct fsmc_reg_map*)__FSMCB)
+
+/** FSMC NOR/PSRAM register map type */
+typedef struct fsmc_nor_psram_reg_map {
+ __io uint32 BCR; /**< Chip-select control register */
+ __io uint32 BTR; /**< Chip-select timing register */
+ const uint8 RESERVED[252]; /**< Reserved */
+ __io uint32 BWTR; /**< Write timing register */
+} fsmc_nor_psram_reg_map;
+
+/** FSMC NOR/PSRAM base pointer 1 */
+#define FSMC_NOR_PSRAM1_BASE ((struct fsmc_nor_psram_reg_map*)__FSMCB)
+
+/** FSMC NOR/PSRAM base pointer 2 */
+#define FSMC_NOR_PSRAM2_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x8))
+
+/** FSMC NOR/PSRAM base pointer 3 */
+#define FSMC_NOR_PSRAM3_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x10))
+
+/** FSMC NOR/PSRAM base pointer 4 */
+#define FSMC_NOR_PSRAM4_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x18))
+
+/*
+ * Register bit definitions
+ */
+
+/* NOR/PSRAM chip-select control registers */
+
+#define FSMC_BCR_CBURSTRW_BIT 19
+#define FSMC_BCR_ASYNCWAIT_BIT 15
+#define FSMC_BCR_EXTMOD_BIT 14
+#define FSMC_BCR_WAITEN_BIT 13
+#define FSMC_BCR_WREN_BIT 12
+#define FSMC_BCR_WAITCFG_BIT 11
+#define FSMC_BCR_WRAPMOD_BIT 10
+#define FSMC_BCR_WAITPOL_BIT 9
+#define FSMC_BCR_BURSTEN_BIT 8
+#define FSMC_BCR_FACCEN_BIT 6
+#define FSMC_BCR_MUXEN_BIT 1
+#define FSMC_BCR_MBKEN_BIT 0
+
+#define FSMC_BCR_CBURSTRW (1U << FSMC_BCR_CBURSTRW_BIT)
+#define FSMC_BCR_ASYNCWAIT (1U << FSMC_BCR_ASYNCWAIT_BIT)
+#define FSMC_BCR_EXTMOD (1U << FSMC_BCR_EXTMOD_BIT)
+#define FSMC_BCR_WAITEN (1U << FSMC_BCR_WAITEN_BIT)
+#define FSMC_BCR_WREN (1U << FSMC_BCR_WREN_BIT)
+#define FSMC_BCR_WAITCFG (1U << FSMC_BCR_WAITCFG_BIT)
+#define FSMC_BCR_WRAPMOD (1U << FSMC_BCR_WRAPMOD_BIT)
+#define FSMC_BCR_WAITPOL (1U << FSMC_BCR_WAITPOL_BIT)
+#define FSMC_BCR_BURSTEN (1U << FSMC_BCR_BURSTEN_BIT)
+#define FSMC_BCR_FACCEN (1U << FSMC_BCR_FACCEN_BIT)
+#define FSMC_BCR_MWID (0x3 << 4)
+#define FSMC_BCR_MWID_8BITS (0x0 << 4)
+#define FSMC_BCR_MWID_16BITS (0x1 << 4)
+#define FSMC_BCR_MTYP (0x3 << 2)
+#define FSMC_BCR_MTYP_SRAM (0x0 << 2)
+#define FSMC_BCR_MTYP_PSRAM (0x1 << 2)
+#define FSMC_BCR_MTYP_NOR_FLASH (0x2 << 2)
+#define FSMC_BCR_MUXEN (1U << FSMC_BCR_MUXEN_BIT)
+#define FSMC_BCR_MBKEN (1U << FSMC_BCR_MBKEN_BIT)
+
+/* SRAM/NOR-Flash chip-select timing registers */
+
+#define FSMC_BTR_ACCMOD (0x3 << 28)
+#define FSMC_BTR_ACCMOD_A (0x0 << 28)
+#define FSMC_BTR_ACCMOD_B (0x1 << 28)
+#define FSMC_BTR_ACCMOD_C (0x2 << 28)
+#define FSMC_BTR_ACCMOD_D (0x3 << 28)
+#define FSMC_BTR_DATLAT (0xF << 24)
+#define FSMC_BTR_CLKDIV (0xF << 20)
+#define FSMC_BTR_BUSTURN (0xF << 16)
+#define FSMC_BTR_DATAST (0xFF << 8)
+#define FSMC_BTR_ADDHLD (0xF << 4)
+#define FSMC_BTR_ADDSET 0xF
+
+/* SRAM/NOR-Flash write timing registers */
+
+#define FSMC_BWTR_ACCMOD (0x3 << 28)
+#define FSMC_BWTR_ACCMOD_A (0x0 << 28)
+#define FSMC_BWTR_ACCMOD_B (0x1 << 28)
+#define FSMC_BWTR_ACCMOD_C (0x2 << 28)
+#define FSMC_BWTR_ACCMOD_D (0x3 << 28)
+#define FSMC_BWTR_DATLAT (0xF << 24)
+#define FSMC_BWTR_CLKDIV (0xF << 20)
+#define FSMC_BWTR_DATAST (0xFF << 8)
+#define FSMC_BWTR_ADDHLD (0xF << 4)
+#define FSMC_BWTR_ADDSET 0xF
+
+/* NAND Flash/PC Card controller registers */
+
+#define FSMC_PCR_ECCEN_BIT 6
+#define FSMC_PCR_PTYP_BIT 3
+#define FSMC_PCR_PBKEN_BIT 2
+#define FSMC_PCR_PWAITEN_BIT 1
+
+#define FSMC_PCR_ECCPS (0x7 << 17)
+#define FSMC_PCR_ECCPS_256B (0x0 << 17)
+#define FSMC_PCR_ECCPS_512B (0x1 << 17)
+#define FSMC_PCR_ECCPS_1024B (0x2 << 17)
+#define FSMC_PCR_ECCPS_2048B (0x3 << 17)
+#define FSMC_PCR_ECCPS_4096B (0x4 << 17)
+#define FSMC_PCR_ECCPS_8192B (0x5 << 17)
+#define FSMC_PCR_TAR (0xF << 13)
+#define FSMC_PCR_TCLR (0xF << 9)
+#define FSMC_PCR_ECCEN (1U << FSMC_PCR_ECCEN_BIT)
+#define FSMC_PCR_PWID (0x3 << 4)
+#define FSMC_PCR_PWID_8BITS (0x0 << 4)
+#define FSMC_PCR_PWID_16BITS (0x1 << 4)
+#define FSMC_PCR_PTYP (1U << FSMC_PCR_PTYP_BIT)
+#define FSMC_PCR_PTYP_PC_CF_PCMCIA (0x0 << FSMC_PCR_PTYP_BIT)
+#define FSMC_PCR_PTYP_NAND (0x1 << FSMC_PCR_PTYP_BIT)
+#define FSMC_PCR_PBKEN (1U << FSMC_PCR_PBKEN_BIT)
+#define FSMC_PCR_PWAITEN (1U << FSMC_PCR_PWAITEN_BIT)
+
+/* FIFO status and interrupt registers */
+
+#define FSMC_SR_FEMPT_BIT 6
+#define FSMC_SR_IFEN_BIT 5
+#define FSMC_SR_ILEN_BIT 4
+#define FSMC_SR_IREN_BIT 3
+#define FSMC_SR_IFS_BIT 2
+#define FSMC_SR_ILS_BIT 1
+#define FSMC_SR_IRS_BIT 0
+
+#define FSMC_SR_FEMPT (1U << FSMC_SR_FEMPT_BIT)
+#define FSMC_SR_IFEN (1U << FSMC_SR_IFEN_BIT)
+#define FSMC_SR_ILEN (1U << FSMC_SR_ILEN_BIT)
+#define FSMC_SR_IREN (1U << FSMC_SR_IREN_BIT)
+#define FSMC_SR_IFS (1U << FSMC_SR_IFS_BIT)
+#define FSMC_SR_ILS (1U << FSMC_SR_ILS_BIT)
+#define FSMC_SR_IRS (1U << FSMC_SR_IRS_BIT)
+
+/* Common memory space timing registers */
+
+#define FSMC_PMEM_MEMHIZ (0xFF << 24)
+#define FSMC_PMEM_MEMHOLD (0xFF << 16)
+#define FSMC_PMEM_MEMWAIT (0xFF << 8)
+#define FSMC_PMEM_MEMSET 0xFF
+
+/* Attribute memory space timing registers */
+
+#define FSMC_PATT_ATTHIZ (0xFF << 24)
+#define FSMC_PATT_ATTHOLD (0xFF << 16)
+#define FSMC_PATT_ATTWAIT (0xFF << 8)
+#define FSMC_PATT_ATTSET 0xFF
+
+/* I/O space timing register 4 */
+
+#define FSMC_PIO_IOHIZ (0xFF << 24)
+#define FSMC_PIO_IOHOLD (0xFF << 16)
+#define FSMC_PIO_IOWAIT (0xFF << 8)
+#define FSMC_PIO_IOSET 0xFF
+
+/*
+ * Memory bank boundary addresses
+ */
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1 (NOR/PSRAM).
+ *
+ * This bank is split into 4 regions. Each region supports interfacing
+ * with 1 NOR Flash, SRAM, or PSRAM chip. The base addresses of these
+ * regions are FSMC_NOR_PSRAM_REGIONx, for x = 1, 2, 3, 4.
+ */
+#define FSMC_BANK1 ((void*)0x60000000)
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 1
+ * (NOR/PSRAM).
+ */
+#define FSMC_NOR_PSRAM_REGION1 FSMC_BANK1
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 2
+ * (NOR/PSRAM).
+ */
+#define FSMC_NOR_PSRAM_REGION2 ((void*)0x64000000)
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 3
+ * (NOR/PSRAM).
+ */
+#define FSMC_NOR_PSRAM_REGION3 ((void*)0x68000000)
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 4
+ * (NOR/PSRAM).
+ */
+#define FSMC_NOR_PSRAM_REGION4 ((void*)0x6C000000)
+
+/** Void pointer to base address of FSMC memory bank 2 (NAND Flash). */
+#define FSMC_BANK2 ((void*)0x70000000)
+
+/** Void pointer to base address of FSMC memory bank 3 (NAND Flash). */
+#define FSMC_BANK3 ((void*)0x80000000)
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 4 (PC card
+ * devices).
+ */
+#define FSMC_BANK4 ((void*)0x90000000)
+
+/*
+ * SRAM/NOR Flash routines
+ */
+
+/**
+ * @brief Configure FSMC GPIOs for use with SRAM.
+ */
+void fsmc_sram_init_gpios(void);
+
+/**
+ * Set the DATAST bits in the given NOR/PSRAM register map's
+ * chip-select timing register (FSMC_BTR).
+ *
+ * @param regs NOR Flash/PSRAM register map whose chip-select timing
+ * register to set.
+ * @param datast Value to use for DATAST bits.
+ */
+static inline void fsmc_nor_psram_set_datast(fsmc_nor_psram_reg_map *regs,
+ uint8 datast) {
+ regs->BTR &= ~FSMC_BTR_DATAST;
+ regs->BTR |= datast << 8;
+}
+
+/**
+ * Set the ADDHLD bits in the given NOR/PSRAM register map's chip
+ * select timing register (FSMC_BTRx).
+ *
+ * @param regs NOR Flash/PSRAM register map whose chip-select timing
+ * register to set.
+ * @param addset Value to use for ADDSET bits.
+ */
+static inline void fsmc_nor_psram_set_addset(fsmc_nor_psram_reg_map *regs,
+ uint8 addset) {
+ regs->BTR &= ~FSMC_BTR_ADDSET;
+ regs->BTR |= addset & 0xF;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/gpio.h b/libmaple/include/libmaple/gpio.h
new file mode 100644
index 0000000..0cc3746
--- /dev/null
+++ b/libmaple/include/libmaple/gpio.h
@@ -0,0 +1,121 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+*****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/gpio.h
+ * @brief General Purpose I/O (GPIO) interace.
+ */
+
+#ifndef _LIBMAPLE_GPIO_H_
+#define _LIBMAPLE_GPIO_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/*
+ * Note: Series header must define:
+ * - enum gpio_pin_mode (TODO think harder about portability here)
+ */
+#include <series/gpio.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+#include <libmaple/exti.h>
+
+/*
+ * Device type
+ */
+
+/** GPIO device type */
+typedef struct gpio_dev {
+ gpio_reg_map *regs; /**< Register map */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ /**
+ * @brief (Deprecated) External interrupt port.
+ * Instead of dev->exti_port, use gpio_exti_port(dev).
+ */
+ exti_cfg exti_port;
+} gpio_dev;
+
+/*
+ * Portable routines
+ */
+
+void gpio_init(gpio_dev *dev);
+void gpio_init_all(void);
+/* TODO flags argument version? */
+void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode);
+
+/**
+ * @brief Get a GPIO port's corresponding EXTI port configuration.
+ * @param dev GPIO port whose exti_cfg to return.
+ */
+static inline exti_cfg gpio_exti_port(gpio_dev *dev) {
+ return (exti_cfg)(EXTI_PA + (dev->clk_id - RCC_GPIOA));
+}
+
+/**
+ * Set or reset a GPIO pin.
+ *
+ * Pin must have previously been configured to output mode.
+ *
+ * @param dev GPIO device whose pin to set.
+ * @param pin Pin on to set or reset
+ * @param val If true, set the pin. If false, reset the pin.
+ */
+static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) {
+ val = !val; /* "set" bits are lower than "reset" bits */
+ dev->regs->BSRR = (1U << pin) << (16 * val);
+}
+
+/**
+ * Determine whether or not a GPIO pin is set.
+ *
+ * Pin must have previously been configured to input mode.
+ *
+ * @param dev GPIO device whose pin to test.
+ * @param pin Pin on dev to test.
+ * @return True if the pin is set, false otherwise.
+ */
+static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) {
+ return dev->regs->IDR & (1U << pin);
+}
+
+/**
+ * Toggle a pin configured as output push-pull.
+ * @param dev GPIO device.
+ * @param pin Pin on dev to toggle.
+ */
+static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) {
+ dev->regs->ODR = dev->regs->ODR ^ (1U << pin);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/i2c.h b/libmaple/include/libmaple/i2c.h
new file mode 100644
index 0000000..ff1c313
--- /dev/null
+++ b/libmaple/include/libmaple/i2c.h
@@ -0,0 +1,413 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/i2c.h
+ * @brief Inter-Integrated Circuit (I2C) peripheral support
+ *
+ * Currently master-only. Usage notes:
+ *
+ * - Enable an I2C device with i2c_master_enable().
+ * - Initialize an array of struct i2c_msg to suit the bus
+ * transactions (reads/writes) you wish to perform.
+ * - Call i2c_master_xfer() to do the work.
+ */
+
+#ifndef _LIBMAPLE_I2C_H_
+#define _LIBMAPLE_I2C_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Series header must provide:
+ *
+ * - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in
+ * MHz. (This is for internal use only).
+ *
+ * - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1.
+ * This is for internal use only. It's a hack to work around a
+ * silicon bug related to I2C IRQ pre-emption on some targets. If 1,
+ * the series header must also declare and implement a routine with
+ * this signature (it may also be provided as a macro):
+ *
+ * void _i2c_irq_priority_fixup(i2c_dev*)
+ *
+ * This will be called by i2c_enable_irq() before actually enabling
+ * I2C interrupts.
+ *
+ * - Reg. map base pointers, device pointer declarations.
+ */
+
+#include <series/i2c.h>
+#include <libmaple/i2c_common.h>
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+#include <libmaple/nvic.h>
+#include <libmaple/gpio.h>
+
+/** I2C register map type */
+typedef struct i2c_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 OAR1; /**< Own address register 1 */
+ __io uint32 OAR2; /**< Own address register 2 */
+ __io uint32 DR; /**< Data register */
+ __io uint32 SR1; /**< Status register 1 */
+ __io uint32 SR2; /**< Status register 2 */
+ __io uint32 CCR; /**< Clock control register */
+ __io uint32 TRISE; /**< TRISE (rise time) register */
+} i2c_reg_map;
+
+/**
+ * @brief I2C message type
+ */
+typedef struct i2c_msg {
+ uint16 addr; /**< Address */
+
+#define I2C_MSG_READ 0x1
+#define I2C_MSG_10BIT_ADDR 0x2
+ /**
+ * Bitwise OR of:
+ * - I2C_MSG_READ (write is default)
+ * - I2C_MSG_10BIT_ADDR (7-bit is default) */
+ uint16 flags;
+
+ uint16 length; /**< Message length */
+ uint16 xferred; /**< Messages transferred */
+ uint8 *data; /**< Data */
+} i2c_msg;
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 1 */
+
+#define I2C_CR1_SWRST (1U << 15) // Software reset
+#define I2C_CR1_ALERT (1U << 13) // SMBus alert
+#define I2C_CR1_PEC (1U << 12) // Packet error checking
+#define I2C_CR1_POS (1U << 11) // Acknowledge/PEC position
+#define I2C_CR1_ACK (1U << 10) // Acknowledge enable
+#define I2C_CR1_STOP (1U << 9) // Stop generation
+#define I2C_CR1_START (1U << 8) // Start generation
+#define I2C_CR1_NOSTRETCH (1U << 7) // Clock stretching disable
+#define I2C_CR1_ENGC (1U << 6) // General call enable
+#define I2C_CR1_ENPEC (1U << 5) // PEC enable
+#define I2C_CR1_ENARP (1U << 4) // ARP enable
+#define I2C_CR1_SMBTYPE (1U << 3) // SMBus type
+#define I2C_CR1_SMBTYPE_DEVICE (0U << 3) // SMBus type: device
+#define I2C_CR1_SMBTYPE_HOST (1U << 3) // SMBus type: host
+#define I2C_CR1_SMBUS (1U << 1) // SMBus mode
+#define I2C_CR1_SMBUS_I2C (0U << 1) // SMBus mode: I2C
+#define I2C_CR1_SMBUS_SMBUS (1U << 1) // SMBus mode: SMBus
+#define I2C_CR1_PE (1U << 0) // Peripheral Enable
+
+/* Control register 2 */
+
+#define I2C_CR2_LAST (1U << 12) // DMA last transfer
+#define I2C_CR2_DMAEN (1U << 11) // DMA requests enable
+#define I2C_CR2_ITBUFEN (1U << 10) // Buffer interrupt enable
+#define I2C_CR2_ITEVTEN (1U << 9) // Event interupt enable
+#define I2C_CR2_ITERREN (1U << 8) // Error interupt enable
+#define I2C_CR2_FREQ 0x3F // Peripheral input frequency
+
+/* Own address register 1 */
+
+#define I2C_OAR1_ADDMODE (1U << 15) // Addressing mode
+#define I2C_OAR1_ADDMODE_7_BIT (0U << 15) // Addressing mode: 7-bit
+#define I2C_OAR1_ADDMODE_10_BIT (1U << 15) // Addressing mode: 10-bit
+#define I2C_OAR1_ADD 0x3FF // Interface address
+
+/* Own address register 2 */
+
+#define I2C_OAR2_ADD2 0xFE // Interface address
+#define I2C_OAR2_ENDUAL 1U // Dual addressing mode enable
+
+/* Status register 1 */
+
+#define I2C_SR1_SMBALERT (1U << 15) // SMBus alert
+#define I2C_SR1_TIMEOUT (1U << 14) // Timeout or Tlow error
+#define I2C_SR1_PECERR (1U << 12) // PEC Error in reception
+#define I2C_SR1_OVR (1U << 11) // Overrun/underrun
+#define I2C_SR1_AF (1U << 10) // Acknowledge failure
+#define I2C_SR1_ARLO (1U << 9) // Arbitration lost
+#define I2C_SR1_BERR (1U << 8) // Bus error
+#define I2C_SR1_TXE (1U << 7) // Data register empty
+#define I2C_SR1_RXNE (1U << 6) // Data register not empty
+#define I2C_SR1_STOPF (1U << 4) // Stop detection
+#define I2C_SR1_ADD10 (1U << 3) // 10-bit header sent
+#define I2C_SR1_BTF (1U << 2) // Byte transfer finished
+#define I2C_SR1_ADDR (1U << 1) // Address sent/matched
+#define I2C_SR1_SB (1U << 0) // Start bit
+
+/* Status register 2 */
+
+#define I2C_SR2_PEC 0xFF00 // Packet error checking register
+#define I2C_SR2_DUALF (1U << 7) // Dual flag
+#define I2C_SR2_SMBHOST (1U << 6) // SMBus host header
+#define I2C_SR2_SMBDEFAULT (1U << 5) // SMBus device default address
+#define I2C_SR2_GENCALL (1U << 4) // General call address
+#define I2C_SR2_TRA (1U << 2) // Transmitter/receiver
+#define I2C_SR2_BUSY (1U << 1) // Bus busy
+#define I2C_SR2_MSL (1U << 0) // Master/slave
+
+/* Clock control register */
+
+#define I2C_CCR_FS (1U << 15) // Fast mode selection
+#define I2C_CCR_DUTY (1U << 14) // Fast mode duty cycle
+#define I2C_CCR_DUTY_2_1 (0U << 14) // Fast mode duty: 2/1
+#define I2C_CCR_DUTY_16_9 (1U << 14) // Fast mode duty: 16/9
+#define I2C_CCR_CCR 0xFFF // Clock control bits
+
+/*
+ * Convenience routines
+ */
+
+/* Main I2C API */
+
+/* I2C enable options */
+#define I2C_FAST_MODE 0x1 // 400 khz
+#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio
+/* Flag 0x4 is reserved; DO NOT USE. */
+#define I2C_BUS_RESET 0x8 // Perform a bus reset
+void i2c_master_enable(i2c_dev *dev, uint32 flags);
+
+#define I2C_ERROR_PROTOCOL (-1)
+#define I2C_ERROR_TIMEOUT (-2)
+int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout);
+
+void i2c_bus_reset(const i2c_dev *dev);
+
+/**
+ * @brief Disable an I2C device
+ *
+ * This function disables the corresponding peripheral and marks dev's
+ * state as I2C_STATE_DISABLED.
+ *
+ * @param dev Device to disable.
+ */
+static inline void i2c_disable(i2c_dev *dev) {
+ dev->regs->CR1 &= ~I2C_CR1_PE;
+ dev->state = I2C_STATE_DISABLED;
+}
+
+/* Start/stop conditions */
+
+/**
+ * @brief Generate a start condition on the bus.
+ * @param dev I2C device
+ */
+static inline void i2c_start_condition(i2c_dev *dev) {
+ uint32 cr1;
+ while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
+ I2C_CR1_STOP |
+ I2C_CR1_PEC)) {
+ ;
+ }
+ dev->regs->CR1 |= I2C_CR1_START;
+}
+
+/**
+ * @brief Generate a stop condition on the bus
+ * @param dev I2C device
+ */
+static inline void i2c_stop_condition(i2c_dev *dev) {
+ uint32 cr1;
+ while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
+ I2C_CR1_STOP |
+ I2C_CR1_PEC)) {
+ ;
+ }
+ dev->regs->CR1 |= I2C_CR1_STOP;
+ while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
+ I2C_CR1_STOP |
+ I2C_CR1_PEC)) {
+ ;
+ }
+
+}
+
+/* IRQ enable/disable */
+
+#ifndef _I2C_HAVE_IRQ_FIXUP
+/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined,
+ * but we need it either way. */
+#define _i2c_irq_priority_fixup(dev) ((void)0)
+#endif
+
+#define I2C_IRQ_ERROR I2C_CR2_ITERREN
+#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN
+#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN
+/**
+ * @brief Enable one or more I2C interrupts
+ * @param dev I2C device
+ * @param irqs Bitwise or of:
+ * I2C_IRQ_ERROR (error interrupt),
+ * I2C_IRQ_EVENT (event interrupt), and
+ * I2C_IRQ_BUFFER (buffer interrupt).
+ */
+static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) {
+ _i2c_irq_priority_fixup(dev);
+ dev->regs->CR2 |= irqs;
+}
+
+/**
+ * @brief Disable one or more I2C interrupts
+ * @param dev I2C device
+ * @param irqs Bitwise or of:
+ * I2C_IRQ_ERROR (error interrupt),
+ * I2C_IRQ_EVENT (event interrupt), and
+ * I2C_IRQ_BUFFER (buffer interrupt).
+ */
+static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) {
+ dev->regs->CR2 &= ~irqs;
+}
+
+/* ACK/NACK */
+
+/**
+ * @brief Enable I2C acknowledgment
+ * @param dev I2C device
+ */
+static inline void i2c_enable_ack(i2c_dev *dev) {
+ dev->regs->CR1 |= I2C_CR1_ACK;
+}
+
+/**
+ * @brief Disable I2C acknowledgment
+ * @param dev I2C device
+ */
+static inline void i2c_disable_ack(i2c_dev *dev) {
+ dev->regs->CR1 &= ~I2C_CR1_ACK;
+}
+
+/* GPIO control */
+
+/**
+ * @brief Configure device GPIOs.
+ *
+ * Configure GPIO bits dev->sda_pin and dev->scl_pin on GPIO device
+ * dev->gpio_port for use with I2C device dev.
+ *
+ * @param dev I2C Device
+ * @see i2c_release_gpios()
+ */
+extern void i2c_config_gpios(const i2c_dev *dev);
+
+/**
+ * @brief Release GPIOs controlling an I2C bus
+ *
+ * Releases the I2C bus controlled by dev as master, and disconnects
+ * GPIO bits dev->sda_pin and dev->scl_pin on GPIO device
+ * dev->gpio_port from I2C device dev.
+ *
+ * @param dev I2C device
+ * @see i2c_config_gpios()
+ */
+extern void i2c_master_release_bus(const i2c_dev *dev);
+
+/* Miscellaneous low-level routines */
+
+void i2c_init(i2c_dev *dev);
+
+/**
+ * @brief Turn on an I2C peripheral
+ * @param dev Device to enable
+ */
+static inline void i2c_peripheral_enable(i2c_dev *dev) {
+ dev->regs->CR1 |= I2C_CR1_PE;
+}
+
+/**
+ * @brief Turn off an I2C peripheral
+ * @param dev Device to turn off
+ */
+static inline void i2c_peripheral_disable(i2c_dev *dev) {
+ dev->regs->CR1 &= ~I2C_CR1_PE;
+}
+
+/**
+ * @brief Fill transmit register
+ * @param dev I2C device
+ * @param byte Byte to write
+ */
+static inline void i2c_write(i2c_dev *dev, uint8 byte) {
+ dev->regs->DR = byte;
+}
+
+/**
+ * @brief Set input clock frequency, in MHz
+ * @param dev I2C device
+ * @param freq Frequency, in MHz. This must be at least 2, and at most
+ * the APB frequency of dev's bus. (For example, if
+ * rcc_dev_clk(dev) == RCC_APB1, freq must be at most
+ * PCLK1, in MHz). There is an additional limit of 46 MHz.
+ */
+static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) {
+#define I2C_MAX_FREQ_MHZ 46
+ ASSERT(2 <= freq && freq <= _i2c_bus_clk(dev) && freq <= I2C_MAX_FREQ_MHZ);
+ uint32 cr2 = dev->regs->CR2;
+ cr2 &= ~I2C_CR2_FREQ;
+ cr2 |= freq;
+ dev->regs->CR2 = freq;
+#undef I2C_MAX_FREQ_MHZ
+}
+
+/**
+ * @brief Set I2C clock control register.
+ *
+ * See the chip reference manual for the details.
+ *
+ * @param dev I2C device
+ * @param val Value to use for clock control register (in
+ * Fast/Standard mode)
+ */
+static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) {
+ uint32 ccr = dev->regs->CCR;
+ ccr &= ~I2C_CCR_CCR;
+ ccr |= val;
+ dev->regs->CCR = ccr;
+}
+
+/**
+ * @brief Set SCL rise time
+ * @param dev I2C device
+ * @param trise Maximum rise time in fast/standard mode (see chip
+ * reference manual for the relevant formulas).
+ */
+static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) {
+ dev->regs->TRISE = trise;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/i2c_common.h b/libmaple/include/libmaple/i2c_common.h
new file mode 100644
index 0000000..17cabe3
--- /dev/null
+++ b/libmaple/include/libmaple/i2c_common.h
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung (from <libmaple/i2c.h>).
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/i2c_common.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief This file is an implementation detail
+ *
+ * CONTENTS UNSTABLE. The existence of this file is an implementation
+ * detail. Never include it directly. If you need something from
+ * here, include <libmaple/i2c.h> instead.
+ */
+
+#ifndef _LIBMAPLE_I2C_COMMON_H_
+#define _LIBMAPLE_I2C_COMMON_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/nvic.h>
+#include <libmaple/rcc.h>
+
+struct gpio_dev;
+struct i2c_reg_map;
+struct i2c_msg;
+
+/** I2C device states */
+typedef enum i2c_state {
+ I2C_STATE_DISABLED = 0, /**< Disabled */
+ I2C_STATE_IDLE = 1, /**< Idle */
+ I2C_STATE_XFER_DONE = 2, /**< Done with transfer */
+ I2C_STATE_BUSY = 3, /**< Busy */
+ I2C_STATE_ERROR = -1 /**< Error occurred */
+} i2c_state;
+
+/**
+ * @brief I2C device type.
+ */
+typedef struct i2c_dev {
+ struct i2c_reg_map *regs; /**< Register map */
+ struct i2c_msg *msg; /**< Messages */
+ uint32 error_flags; /**< Error flags, set on I2C error condition */
+ volatile uint32 timestamp; /**< For internal use */
+
+ /**
+ * @brief Deprecated. Use .scl_port or .sda_port instead.
+ * If non-null, this will be used as SDA, SCL pins' GPIO port. If
+ * null, then .sda_port will be used for SDA, and .sda_port for
+ * SDA. */
+ struct gpio_dev *gpio_port;
+
+ /**
+ * @brief SDA GPIO device (but see .gpio_port).
+ */
+ struct gpio_dev *sda_port;
+
+ /**
+ * @brief SCL GPIO device (but see .gpio_port).
+ */
+ struct gpio_dev *scl_port;
+
+ uint16 msgs_left; /**< Messages left */
+ uint8 sda_pin; /**< SDA bit on gpio_port */
+ uint8 scl_pin; /**< SCL bit on gpio_port */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ nvic_irq_num ev_nvic_line; /**< Event IRQ number */
+ nvic_irq_num er_nvic_line; /**< Error IRQ number */
+ volatile i2c_state state; /**< Device state */
+} i2c_dev;
+
+#endif
diff --git a/libmaple/include/libmaple/iwdg.h b/libmaple/include/libmaple/iwdg.h
new file mode 100644
index 0000000..3a16c55
--- /dev/null
+++ b/libmaple/include/libmaple/iwdg.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/iwdg.h
+ * @author Michael Hope, Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Independent watchdog support.
+ *
+ * To use the independent watchdog, first call iwdg_init() with the
+ * appropriate prescaler and IWDG counter reload values for your
+ * application. Afterwards, you must periodically call iwdg_feed()
+ * before the IWDG counter reaches 0 to reset the counter to its
+ * reload value. If you do not, the chip will reset.
+ *
+ * Once started, the independent watchdog cannot be turned off.
+ */
+
+#ifndef _LIBMAPLE_IWDG_H_
+#define _LIBMAPLE_IWDG_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** Independent watchdog register map type. */
+typedef struct iwdg_reg_map {
+ __io uint32 KR; /**< Key register. */
+ __io uint32 PR; /**< Prescaler register. */
+ __io uint32 RLR; /**< Reload register. */
+ __io uint32 SR; /**< Status register */
+} iwdg_reg_map;
+
+/** Independent watchdog base pointer */
+#define IWDG_BASE ((struct iwdg_reg_map*)0x40003000)
+
+/*
+ * Register bit definitions
+ */
+
+/* Key register */
+
+#define IWDG_KR_UNLOCK 0x5555
+#define IWDG_KR_FEED 0xAAAA
+#define IWDG_KR_START 0xCCCC
+
+/* Prescaler register */
+
+#define IWDG_PR_DIV_4 0x0
+#define IWDG_PR_DIV_8 0x1
+#define IWDG_PR_DIV_16 0x2
+#define IWDG_PR_DIV_32 0x3
+#define IWDG_PR_DIV_64 0x4
+#define IWDG_PR_DIV_128 0x5
+#define IWDG_PR_DIV_256 0x6
+
+/* Status register */
+
+#define IWDG_SR_RVU_BIT 1
+#define IWDG_SR_PVU_BIT 0
+
+#define IWDG_SR_RVU (1U << IWDG_SR_RVU_BIT)
+#define IWDG_SR_PVU (1U << IWDG_SR_PVU_BIT)
+
+/**
+ * @brief Independent watchdog prescalers.
+ *
+ * These divide the 40 kHz IWDG clock.
+ */
+typedef enum iwdg_prescaler {
+ IWDG_PRE_4 = IWDG_PR_DIV_4, /**< Divide by 4 */
+ IWDG_PRE_8 = IWDG_PR_DIV_8, /**< Divide by 8 */
+ IWDG_PRE_16 = IWDG_PR_DIV_16, /**< Divide by 16 */
+ IWDG_PRE_32 = IWDG_PR_DIV_32, /**< Divide by 32 */
+ IWDG_PRE_64 = IWDG_PR_DIV_64, /**< Divide by 64 */
+ IWDG_PRE_128 = IWDG_PR_DIV_128, /**< Divide by 128 */
+ IWDG_PRE_256 = IWDG_PR_DIV_256 /**< Divide by 256 */
+} iwdg_prescaler;
+
+void iwdg_init(iwdg_prescaler prescaler, uint16 reload);
+void iwdg_feed(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/libmaple.h b/libmaple/include/libmaple/libmaple.h
new file mode 100644
index 0000000..c9034d7
--- /dev/null
+++ b/libmaple/include/libmaple/libmaple.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/libmaple.h
+ * @brief General include file for libmaple
+ */
+
+#ifndef _LIBMAPLE_LIBMAPLE_H_
+#define _LIBMAPLE_LIBMAPLE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.h>
+#include <libmaple/util.h>
+#include <libmaple/delay.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/libmaple_types.h b/libmaple/include/libmaple/libmaple_types.h
new file mode 100644
index 0000000..60dd2ff
--- /dev/null
+++ b/libmaple/include/libmaple/libmaple_types.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/libmaple_types.h
+ *
+ * @brief libmaple's types, and operations on types.
+ */
+
+#ifndef _LIBMAPLE_LIBMAPLE_TYPES_H_
+#define _LIBMAPLE_LIBMAPLE_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef unsigned long long uint64;
+
+typedef signed char int8;
+typedef short int16;
+typedef int int32;
+typedef long long int64;
+
+typedef void (*voidFuncPtr)(void);
+typedef void (*voidArgumentFuncPtr)(void *);
+
+#define __io volatile
+#define __attr_flash __attribute__((section (".USER_FLASH")))
+#define __packed __attribute__((__packed__))
+#define __deprecated __attribute__((__deprecated__))
+#define __weak __attribute__((weak))
+#define __always_inline inline __attribute__((always_inline))
+#define __unused __attribute__((unused))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef offsetof
+#define offsetof(type, member) __builtin_offsetof(type, member)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/nvic.h b/libmaple/include/libmaple/nvic.h
new file mode 100644
index 0000000..ffe385d
--- /dev/null
+++ b/libmaple/include/libmaple/nvic.h
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/nvic.h
+ * @brief Nested vectored interrupt controller support.
+ *
+ * Basic usage:
+ *
+ * @code
+ * // Initialise the interrupt controller and point to the vector
+ * // table at the start of flash.
+ * nvic_init(0x08000000, 0);
+ * // Bind in a timer interrupt handler
+ * timer_attach_interrupt(TIMER_CC1_INTERRUPT, handler);
+ * // Optionally set the priority
+ * nvic_irq_set_priority(NVIC_TIMER1_CC, 5);
+ * // All done, enable all interrupts
+ * nvic_globalirq_enable();
+ * @endcode
+ */
+
+#ifndef _LIBMAPLE_NVIC_H_
+#define _LIBMAPLE_NVIC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
+
+/** NVIC register map type. */
+typedef struct nvic_reg_map {
+ __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */
+ /** Reserved */
+ uint32 RESERVED0[24];
+
+ __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */
+ /** Reserved */
+ uint32 RESERVED1[24];
+
+ __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */
+ /** Reserved */
+ uint32 RESERVED2[24];
+
+ __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */
+ /** Reserved */
+ uint32 RESERVED3[24];
+
+ __io uint32 IABR[8]; /**< Interrupt Active bit Registers */
+ /** Reserved */
+ uint32 RESERVED4[56];
+
+ __io uint8 IP[240]; /**< Interrupt Priority Registers */
+ /** Reserved */
+ uint32 RESERVED5[644];
+
+ __io uint32 STIR; /**< Software Trigger Interrupt Registers */
+} nvic_reg_map;
+
+/** NVIC register map base pointer. */
+#define NVIC_BASE ((struct nvic_reg_map*)0xE000E100)
+
+/*
+ * Note: The series header must define enum nvic_irq_num, which gives
+ * descriptive names to the interrupts and exceptions from NMI (-14)
+ * to the largest interrupt available in the series, where the value
+ * for nonnegative enumerators corresponds to its position in the
+ * vector table.
+ *
+ * It also must define a static inline nvic_irq_disable_all(), which
+ * writes 0xFFFFFFFF to all ICE registers available in the series. (We
+ * place the include here to give the series header access to
+ * NVIC_BASE, in order to let it do so).
+ */
+#include <series/nvic.h>
+
+void nvic_init(uint32 address, uint32 offset);
+void nvic_set_vector_table(uint32 address, uint32 offset);
+void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority);
+void nvic_sys_reset();
+
+/**
+ * Enables interrupts and configurable fault handlers (clear PRIMASK).
+ */
+static __always_inline void nvic_globalirq_enable() {
+ asm volatile("cpsie i");
+}
+
+/**
+ * Disable interrupts and configurable fault handlers (set PRIMASK).
+ */
+static __always_inline void nvic_globalirq_disable() {
+ asm volatile("cpsid i");
+}
+
+/**
+ * @brief Enable interrupt irq_num
+ * @param irq_num Interrupt to enable
+ */
+static inline void nvic_irq_enable(nvic_irq_num irq_num) {
+ if (irq_num < 0) {
+ return;
+ }
+ NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32);
+}
+
+/**
+ * @brief Disable interrupt irq_num
+ * @param irq_num Interrupt to disable
+ */
+static inline void nvic_irq_disable(nvic_irq_num irq_num) {
+ if (irq_num < 0) {
+ return;
+ }
+ NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32);
+}
+
+/**
+ * @brief Quickly disable all interrupts.
+ *
+ * Calling this function is significantly faster than calling
+ * nvic_irq_disable() in a loop.
+ */
+static inline void nvic_irq_disable_all(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/pwr.h b/libmaple/include/libmaple/pwr.h
new file mode 100644
index 0000000..e4b5b0d
--- /dev/null
+++ b/libmaple/include/libmaple/pwr.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/pwr.h
+ * @brief Power control (PWR).
+ */
+
+#ifndef _LIBMAPLE_PWR_H_
+#define _LIBMAPLE_PWR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple.h>
+#include <series/pwr.h>
+
+/** Power interface register map. */
+typedef struct pwr_reg_map {
+ __io uint32 CR; /**< Control register */
+ __io uint32 CSR; /**< Control and status register */
+} pwr_reg_map;
+
+/** Power peripheral register map base pointer. */
+#define PWR_BASE ((struct pwr_reg_map*)0x40007000)
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+
+/** Disable backup domain write protection bit */
+#define PWR_CR_DBP_BIT 8
+/** Power voltage detector enable bit */
+#define PWR_CR_PVDE_BIT 4
+/** Clear standby flag bit */
+#define PWR_CR_CSBF_BIT 3
+/** Clear wakeup flag bit */
+#define PWR_CR_CWUF_BIT 2
+/** Power down deepsleep bit */
+#define PWR_CR_PDDS_BIT 1
+/** Low-power deepsleep bit */
+#define PWR_CR_LPDS_BIT 0
+
+/** Disable backup domain write protection */
+#define PWR_CR_DBP (1U << PWR_CR_DBP_BIT)
+/** Power voltage detector (PVD) level selection */
+#define PWR_CR_PLS (0x7 << 5)
+/** Power voltage detector enable */
+#define PWR_CR_PVDE (1U << PWR_CR_PVDE_BIT)
+/** Clear standby flag */
+#define PWR_CR_CSBF (1U << PWR_CR_CSBF_BIT)
+/** Clear wakeup flag */
+#define PWR_CR_CWUF (1U << PWR_CR_CWUF_BIT)
+/** Power down deepsleep */
+#define PWR_CR_PDDS (1U << PWR_CR_PDDS_BIT)
+/** Low-power deepsleep */
+#define PWR_CR_LPDS (1U << PWR_CR_LPDS_BIT)
+
+/* Control and status register */
+
+/** Enable wakeup pin bit */
+#define PWR_CSR_EWUP_BIT 8
+/** PVD output bit */
+#define PWR_CSR_PVDO_BIT 2
+/** Standby flag bit */
+#define PWR_CSR_SBF_BIT 1
+/** Wakeup flag bit */
+#define PWR_CSR_WUF_BIT 0
+
+/** Enable wakeup pin */
+#define PWR_CSR_EWUP (1U << PWR_CSR_EWUP_BIT)
+/** PVD output */
+#define PWR_CSR_PVDO (1U << PWR_CSR_PVDO_BIT)
+/** Standby flag */
+#define PWR_CSR_SBF (1U << PWR_CSR_SBF_BIT)
+/** Wakeup flag */
+#define PWR_CSR_WUF (1U << PWR_CSR_WUF_BIT)
+
+/*
+ * Convenience functions
+ */
+
+void pwr_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/rcc.h b/libmaple/include/libmaple/rcc.h
new file mode 100644
index 0000000..ea16803
--- /dev/null
+++ b/libmaple/include/libmaple/rcc.h
@@ -0,0 +1,175 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/rcc.h
+ * @brief Reset and Clock Control (RCC) interface.
+ */
+
+#ifndef _LIBMAPLE_RCC_H_
+#define _LIBMAPLE_RCC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/* Put the SYSCLK sources before the series header is included, as it
+ * might need them. */
+/**
+ * @brief SYSCLK sources
+ * @see rcc_switch_sysclk()
+ */
+typedef enum rcc_sysclk_src {
+ RCC_CLKSRC_HSI = 0x0,
+ RCC_CLKSRC_HSE = 0x1,
+ RCC_CLKSRC_PLL = 0x2,
+} rcc_sysclk_src;
+
+#include <series/rcc.h>
+
+/* Note: Beyond the usual (registers, etc.), it's up to the series
+ * header to define the following types:
+ *
+ * - enum rcc_clk: Available system and secondary clock sources,
+ * e.g. RCC_CLK_HSE, RCC_CLK_PLL, RCC_CLK_LSE.
+ *
+ * Note that the inclusion of secondary clock sources (like LSI and
+ * LSE) makes enum rcc_clk different from the SYSCLK sources, which
+ * are defined in this header as enum rcc_sysclk_src.
+ *
+ * IMPORTANT NOTE TO IMPLEMENTORS: If you are adding support for a
+ * new STM32 series, see the comment near rcc_clk_reg() in
+ * libmaple/rcc.c for information on how to choose these values so
+ * that rcc_turn_on_clk() etc. will work on your series.
+ *
+ * - enum rcc_clk_id: For each available peripheral. These are widely used
+ * as unique IDs (TODO extricate from RCC?). Peripherals which are
+ * common across STM32 series should use the same token for their
+ * rcc_clk_id in each series header.
+ *
+ * - enum rcc_clk_domain: For each clock domain. This is returned by
+ * rcc_dev_clk(). For instance, each AHB and APB is a clock domain.
+ *
+ * - enum rcc_prescaler: And a suitable set of dividers for
+ * rcc_set_prescaler().
+ *
+ * - enum rcc_pllsrc: For each PLL source. Same source, same token.
+ *
+ * - A target-dependent type to be pointed to by the data field in a
+ * struct rcc_pll_cfg.
+ */
+
+#ifdef __DOXYGEN__
+/** RCC register map base pointer */
+#define RCC_BASE
+#endif
+
+/* Clock prescaler management. */
+
+/**
+ * @brief Set the divider on a peripheral prescaler
+ * @param prescaler prescaler to set
+ * @param divider prescaler divider
+ */
+extern void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider);
+
+/* SYSCLK. */
+
+void rcc_switch_sysclk(rcc_sysclk_src sysclk_src);
+
+/* PLL configuration */
+
+/**
+ * @brief Specifies a configuration for the main PLL.
+ */
+typedef struct rcc_pll_cfg {
+ rcc_pllsrc pllsrc; /**< PLL source */
+
+ /** Series-specific configuration data. */
+ void *data;
+} rcc_pll_cfg;
+
+/**
+ * @brief Configure the main PLL.
+ *
+ * You may only call this function while the PLL is disabled.
+ *
+ * @param pll_cfg Desired PLL configuration. The contents of this
+ * struct depend entirely on the target.
+ */
+extern void rcc_configure_pll(rcc_pll_cfg *pll_cfg);
+
+/* System and secondary clock sources. */
+
+void rcc_turn_on_clk(rcc_clk clock);
+void rcc_turn_off_clk(rcc_clk clock);
+int rcc_is_clk_on(rcc_clk clock);
+int rcc_is_clk_ready(rcc_clk clock);
+
+/* Peripheral clock lines and clock domains. */
+
+/**
+ * @brief Turn on the clock line on a peripheral
+ * @param id Clock ID of the peripheral to turn on.
+ */
+extern void rcc_clk_enable(rcc_clk_id id);
+
+/**
+ * @brief Reset a peripheral.
+ *
+ * Caution: not all rcc_clk_id values refer to a peripheral which can
+ * be reset. (Only rcc_clk_ids for peripherals with bits in an RCC
+ * reset register can be used here.)
+ *
+ * @param id Clock ID of the peripheral to reset.
+ */
+extern void rcc_reset_dev(rcc_clk_id id);
+
+rcc_clk_domain rcc_dev_clk(rcc_clk_id id);
+
+/* Clock security system */
+
+/**
+ * @brief Enable the clock security system (CSS).
+ */
+static inline void rcc_enable_css() {
+ RCC_BASE->CR |= RCC_CR_CSSON;
+}
+
+/**
+ * @brief Disable the clock security system (CSS).
+ */
+static inline void rcc_disable_css() {
+ RCC_BASE->CR &= ~RCC_CR_CSSON;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/ring_buffer.h b/libmaple/include/libmaple/ring_buffer.h
new file mode 100644
index 0000000..e02e6e7
--- /dev/null
+++ b/libmaple/include/libmaple/ring_buffer.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/ring_buffer.h
+ * @brief Simple circular buffer
+ *
+ * This implementation is not thread-safe. In particular, none of
+ * these functions is guaranteed re-entrant.
+ */
+
+#ifndef _LIBMAPLE_RING_BUFFER_H_
+#define _LIBMAPLE_RING_BUFFER_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/**
+ * Ring buffer type.
+ *
+ * The buffer is empty when head == tail.
+ *
+ * The buffer is full when the head is one byte in front of the tail,
+ * modulo buffer length.
+ *
+ * One byte is left free to distinguish empty from full. */
+typedef struct ring_buffer {
+ volatile uint8 *buf; /**< Buffer items are stored into */
+ uint16 head; /**< Index of the next item to remove */
+ uint16 tail; /**< Index where the next item will get inserted */
+ uint16 size; /**< Buffer capacity minus one */
+} ring_buffer;
+
+/**
+ * Initialise a ring buffer.
+ *
+ * @param rb Instance to initialise
+ *
+ * @param size Number of items in buf. The ring buffer will always
+ * leave one element unoccupied, so the maximum number of
+ * elements it can store will be size - 1. Thus, size
+ * must be at least 2.
+ *
+ * @param buf Buffer to store items into
+ */
+static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) {
+ rb->head = 0;
+ rb->tail = 0;
+ rb->size = size - 1;
+ rb->buf = buf;
+}
+
+/**
+ * @brief Return the number of elements stored in the ring buffer.
+ * @param rb Buffer whose elements to count.
+ */
+static inline uint16 rb_full_count(ring_buffer *rb) {
+ __io ring_buffer *arb = rb;
+ int32 size = arb->tail - arb->head;
+ if (arb->tail < arb->head) {
+ size += arb->size + 1;
+ }
+ return (uint16)size;
+}
+
+/**
+ * @brief Returns true if and only if the ring buffer is full.
+ * @param rb Buffer to test.
+ */
+static inline int rb_is_full(ring_buffer *rb) {
+ return (rb->tail + 1 == rb->head) ||
+ (rb->tail == rb->size && rb->head == 0);
+}
+
+/**
+ * @brief Returns true if and only if the ring buffer is empty.
+ * @param rb Buffer to test.
+ */
+static inline int rb_is_empty(ring_buffer *rb) {
+ return rb->head == rb->tail;
+}
+
+/**
+ * Append element onto the end of a ring buffer.
+ * @param rb Buffer to append onto.
+ * @param element Value to append.
+ */
+static inline void rb_insert(ring_buffer *rb, uint8 element) {
+ rb->buf[rb->tail] = element;
+ rb->tail = (rb->tail == rb->size) ? 0 : rb->tail + 1;
+}
+
+/**
+ * @brief Remove and return the first item from a ring buffer.
+ * @param rb Buffer to remove from, must contain at least one element.
+ */
+static inline uint8 rb_remove(ring_buffer *rb) {
+ uint8 ch = rb->buf[rb->head];
+ rb->head = (rb->head == rb->size) ? 0 : rb->head + 1;
+ return ch;
+}
+
+/**
+ * @brief Attempt to remove the first item from a ring buffer.
+ *
+ * If the ring buffer is nonempty, removes and returns its first item.
+ * If it is empty, does nothing and returns a negative value.
+ *
+ * @param rb Buffer to attempt to remove from.
+ */
+static inline int16 rb_safe_remove(ring_buffer *rb) {
+ return rb_is_empty(rb) ? -1 : rb_remove(rb);
+}
+
+/**
+ * @brief Attempt to insert an element into a ring buffer.
+ *
+ * @param rb Buffer to insert into.
+ * @param element Value to insert into rb.
+ * @sideeffect If rb is not full, appends element onto buffer.
+ * @return If element was appended, then true; otherwise, false. */
+static inline int rb_safe_insert(ring_buffer *rb, uint8 element) {
+ if (rb_is_full(rb)) {
+ return 0;
+ }
+ rb_insert(rb, element);
+ return 1;
+}
+
+/**
+ * @brief Append an item onto the end of a non-full ring buffer.
+ *
+ * If the buffer is full, removes its first item, then inserts the new
+ * element at the end.
+ *
+ * @param rb Ring buffer to insert into.
+ * @param element Value to insert into ring buffer.
+ * @return On success, returns -1. If an element was popped, returns
+ * the popped value.
+ */
+static inline int rb_push_insert(ring_buffer *rb, uint8 element) {
+ int ret = -1;
+ if (rb_is_full(rb)) {
+ ret = rb_remove(rb);
+ }
+ rb_insert(rb, element);
+ return ret;
+}
+
+/**
+ * @brief Discard all items from a ring buffer.
+ * @param rb Ring buffer to discard all items from.
+ */
+static inline void rb_reset(ring_buffer *rb) {
+ rb->tail = rb->head;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/scb.h b/libmaple/include/libmaple/scb.h
new file mode 100644
index 0000000..c42a0f2
--- /dev/null
+++ b/libmaple/include/libmaple/scb.h
@@ -0,0 +1,214 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011-2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/scb.h
+ * @brief System control block header
+ */
+
+/*
+ * FIXME: STM32F2?
+ */
+
+#ifndef _LIBMAPLE_SCB_H_
+#define _LIBMAPLE_SCB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map and base pointer
+ */
+
+/** System control block register map type */
+typedef struct scb_reg_map {
+ __io uint32 CPUID; /**< CPU ID Base Register */
+ __io uint32 ICSR; /**< Interrupt Control State Register */
+ __io uint32 VTOR; /**< Vector Table Offset Register */
+ __io uint32 AIRCR; /**< Application Interrupt / Reset Control Register */
+ __io uint32 SCR; /**< System Control Register */
+ __io uint32 CCR; /**< Configuration and Control Register */
+ __io uint8 SHP[12]; /**< System Handler Priority Registers
+ (4-7, 8-11, 12-15) */
+ __io uint32 SHCSR; /**< System Handler Control and State Register */
+ __io uint32 CFSR; /**< Configurable Fault Status Register */
+ __io uint32 HFSR; /**< Hard Fault Status Register */
+ /* DFSR is not documented by ST in PM0056 (as of Revision 4), but
+ * there's a 4 byte hole in the SCB register map docs right where
+ * it belongs. Since it's specified as "always implemented" in
+ * the ARM v7-M ARM, I'm assuming its absence is a bug in the ST
+ * doc, but I haven't proven it. [mbolivar] */
+ __io uint32 DFSR; /**< Debug Fault Status Register */
+ __io uint32 MMFAR; /**< Mem Manage Address Register */
+ __io uint32 BFAR; /**< Bus Fault Address Register */
+#if 0
+ /* The following registers are implementation-defined according to
+ * ARM v7-M, and I can't find evidence of their existence in ST's
+ * docs. I'm removing them. Feel free to yell at me if they do
+ * exist. [mbolivar]
+ */
+ __io uint32 AFSR; /**< Auxiliary Fault Status Register */
+ __io uint32 PFR[2]; /**< Processor Feature Register */
+ __io uint32 DFR; /**< Debug Feature Register */
+ __io uint32 AFR; /**< Auxiliary Feature Register */
+ __io uint32 MMFR[4]; /**< Memory Model Feature Register */
+ __io uint32 ISAR[5]; /**< ISA Feature Register */
+#endif
+} scb_reg_map;
+
+/** System control block register map base pointer */
+#define SCB_BASE ((struct scb_reg_map*)0xE000ED00)
+
+/*
+ * Register bit definitions
+ */
+
+/* No SCB_REG_FIELD_BIT macros as the relevant addresses are not in a
+ * bit-band region. */
+
+/* CPUID base register (SCB_CPUID) */
+
+#define SCB_CPUID_IMPLEMENTER (0xFF << 24)
+#define SCB_CPUID_VARIANT (0xF << 20)
+#define SCB_CPUID_CONSTANT (0xF << 16)
+#define SCB_CPUID_PARTNO (0xFFF << 4)
+#define SCB_CPUID_REVISION 0xF
+
+/* Interrupt control state register (SCB_ICSR) */
+
+#define SCB_ICSR_NMIPENDSET (1U << 31)
+#define SCB_ICSR_PENDSVSET (1U << 28)
+#define SCB_ICSR_PENDSVCLR (1U << 27)
+#define SCB_ICSR_PENDSTSET (1U << 26)
+#define SCB_ICSR_PENDSTCLR (1U << 25)
+#define SCB_ICSR_ISRPENDING (1U << 22)
+#define SCB_ICSR_VECTPENDING (0x3FF << 12)
+#define SCB_ICSR_RETOBASE (1U << 11)
+#define SCB_ICSR_VECTACTIVE 0xFF
+
+/* Vector table offset register (SCB_VTOR) */
+
+#define SCB_VTOR_TBLOFF (0x1FFFFF << 9)
+
+/* Application interrupt and reset control register (SCB_AIRCR) */
+
+#define SCB_AIRCR_VECTKEYSTAT (0x5FA << 16)
+#define SCB_AIRCR_VECTKEY (0x5FA << 16)
+#define SCB_AIRCR_ENDIANNESS (1U << 15)
+#define SCB_AIRCR_PRIGROUP (0x3 << 8)
+#define SCB_AIRCR_SYSRESETREQ (1U << 2)
+#define SCB_AIRCR_VECTCLRACTIVE (1U << 1)
+#define SCB_AIRCR_VECTRESET (1U << 0)
+
+/* System control register (SCB_SCR) */
+
+#define SCB_SCR_SEVONPEND (1U << 4)
+#define SCB_SCR_SLEEPDEEP (1U << 2)
+#define SCB_SCR_SLEEPONEXIT (1U << 1)
+
+/* Configuration and Control Register (SCB_CCR) */
+
+#define SCB_CCR_STKALIGN (1U << 9)
+#define SCB_CCR_BFHFNMIGN (1U << 8)
+#define SCB_CCR_DIV_0_TRP (1U << 4)
+#define SCB_CCR_UNALIGN_TRP (1U << 3)
+#define SCB_CCR_USERSETMPEND (1U << 1)
+#define SCB_CCR_NONBASETHRDENA (1U << 0)
+
+/* System handler priority registers (SCB_SHPRx) */
+
+#define SCB_SHPR1_PRI6 (0xFF << 16)
+#define SCB_SHPR1_PRI5 (0xFF << 8)
+#define SCB_SHPR1_PRI4 0xFF
+
+#define SCB_SHPR2_PRI11 (0xFF << 24)
+
+#define SCB_SHPR3_PRI15 (0xFF << 24)
+#define SCB_SHPR3_PRI14 (0xFF << 16)
+
+/* System Handler Control and state register (SCB_SHCSR) */
+
+#define SCB_SHCSR_USGFAULTENA (1U << 18)
+#define SCB_SHCSR_BUSFAULTENA (1U << 17)
+#define SCB_SHCSR_MEMFAULTENA (1U << 16)
+#define SCB_SHCSR_SVCALLPENDED (1U << 15)
+#define SCB_SHCSR_BUSFAULTPENDED (1U << 14)
+#define SCB_SHCSR_MEMFAULTPENDED (1U << 13)
+#define SCB_SHCSR_USGFAULTPENDED (1U << 12)
+#define SCB_SHCSR_SYSTICKACT (1U << 11)
+#define SCB_SHCSR_PENDSVACT (1U << 10)
+#define SCB_SHCSR_MONITORACT (1U << 8)
+#define SCB_SHCSR_SVCALLACT (1U << 7)
+#define SCB_SHCSR_USGFAULTACT (1U << 3)
+#define SCB_SHCSR_BUSFAULTACT (1U << 1)
+#define SCB_SHCSR_MEMFAULTACT (1U << 0)
+
+/* Configurable fault status register (SCB_CFSR) */
+
+#define SCB_CFSR_DIVBYZERO (1U << 25)
+#define SCB_CFSR_UNALIGNED (1U << 24)
+#define SCB_CFSR_NOCP (1U << 19)
+#define SCB_CFSR_INVPC (1U << 18)
+#define SCB_CFSR_INVSTATE (1U << 17)
+#define SCB_CFSR_UNDEFINSTR (1U << 16)
+#define SCB_CFSR_BFARVALID (1U << 15)
+#define SCB_CFSR_STKERR (1U << 12)
+#define SCB_CFSR_UNSTKERR (1U << 11)
+#define SCB_CFSR_IMPRECISERR (1U << 10)
+#define SCB_CFSR_PRECISERR (1U << 9)
+#define SCB_CFSR_IBUSERR (1U << 8)
+#define SCB_CFSR_MMARVALID (1U << 7)
+#define SCB_CFSR_MSTKERR (1U << 4)
+#define SCB_CFSR_MUNSTKERR (1U << 3)
+#define SCB_CFSR_DACCVIOL (1U << 1)
+#define SCB_CFSR_IACCVIOL (1U << 0)
+
+/* Hard Fault Status Register (SCB_HFSR) */
+
+#define SCB_HFSR_DEBUG_VT (1U << 31)
+#define SCB_CFSR_FORCED (1U << 30)
+#define SCB_CFSR_VECTTBL (1U << 1)
+
+/* Debug Fault Status Register */
+
+/* Not specified by PM0056, but required by ARM. The bit definitions
+ * here are based on the names given in the ARM v7-M ARM. */
+
+#define SCB_DFSR_EXTERNAL (1U << 4)
+#define SCB_DFSR_VCATCH (1U << 3)
+#define SCB_DFSR_DWTTRAP (1U << 2)
+#define SCB_DFSR_BKPT (1U << 1)
+#define SCB_DFSR_HALTED (1U << 0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/spi.h b/libmaple/include/libmaple/spi.h
new file mode 100644
index 0000000..4acd230
--- /dev/null
+++ b/libmaple/include/libmaple/spi.h
@@ -0,0 +1,470 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/spi.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Serial Peripheral Interface (SPI) and Integrated
+ * Interchip Sound (I2S) peripheral support.
+ *
+ * I2S support is currently limited to register maps and bit definitions.
+ */
+
+#ifndef _LIBMAPLE_SPI_H_
+#define _LIBMAPLE_SPI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+#include <libmaple/nvic.h>
+#include <series/spi.h>
+
+/*
+ * Register maps
+ */
+
+/** SPI register map type. */
+typedef struct spi_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SR; /**< Status register */
+ __io uint32 DR; /**< Data register */
+ __io uint32 CRCPR; /**< CRC polynomial register */
+ __io uint32 RXCRCR; /**< RX CRC register */
+ __io uint32 TXCRCR; /**< TX CRC register */
+ __io uint32 I2SCFGR; /**< I2S configuration register */
+ __io uint32 I2SPR; /**< I2S prescaler register */
+} spi_reg_map;
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 1 */
+
+#define SPI_CR1_BIDIMODE_BIT 15
+#define SPI_CR1_BIDIOE_BIT 14
+#define SPI_CR1_CRCEN_BIT 13
+#define SPI_CR1_CRCNEXT_BIT 12
+#define SPI_CR1_DFF_BIT 11
+#define SPI_CR1_RXONLY_BIT 10
+#define SPI_CR1_SSM_BIT 9
+#define SPI_CR1_SSI_BIT 8
+#define SPI_CR1_LSBFIRST_BIT 7
+#define SPI_CR1_SPE_BIT 6
+#define SPI_CR1_MSTR_BIT 2
+#define SPI_CR1_CPOL_BIT 1
+#define SPI_CR1_CPHA_BIT 0
+
+#define SPI_CR1_BIDIMODE (1U << SPI_CR1_BIDIMODE_BIT)
+#define SPI_CR1_BIDIMODE_2_LINE (0x0 << SPI_CR1_BIDIMODE_BIT)
+#define SPI_CR1_BIDIMODE_1_LINE (0x1 << SPI_CR1_BIDIMODE_BIT)
+#define SPI_CR1_BIDIOE (1U << SPI_CR1_BIDIOE_BIT)
+#define SPI_CR1_CRCEN (1U << SPI_CR1_CRCEN_BIT)
+#define SPI_CR1_CRCNEXT (1U << SPI_CR1_CRCNEXT_BIT)
+#define SPI_CR1_DFF (1U << SPI_CR1_DFF_BIT)
+#define SPI_CR1_DFF_8_BIT (0x0 << SPI_CR1_DFF_BIT)
+#define SPI_CR1_DFF_16_BIT (0x1 << SPI_CR1_DFF_BIT)
+#define SPI_CR1_RXONLY (1U << SPI_CR1_RXONLY_BIT)
+#define SPI_CR1_SSM (1U << SPI_CR1_SSM_BIT)
+#define SPI_CR1_SSI (1U << SPI_CR1_SSI_BIT)
+#define SPI_CR1_LSBFIRST (1U << SPI_CR1_LSBFIRST_BIT)
+#define SPI_CR1_SPE (1U << SPI_CR1_SPE_BIT)
+#define SPI_CR1_BR (0x7 << 3)
+#define SPI_CR1_BR_PCLK_DIV_2 (0x0 << 3)
+#define SPI_CR1_BR_PCLK_DIV_4 (0x1 << 3)
+#define SPI_CR1_BR_PCLK_DIV_8 (0x2 << 3)
+#define SPI_CR1_BR_PCLK_DIV_16 (0x3 << 3)
+#define SPI_CR1_BR_PCLK_DIV_32 (0x4 << 3)
+#define SPI_CR1_BR_PCLK_DIV_64 (0x5 << 3)
+#define SPI_CR1_BR_PCLK_DIV_128 (0x6 << 3)
+#define SPI_CR1_BR_PCLK_DIV_256 (0x7 << 3)
+#define SPI_CR1_MSTR (1U << SPI_CR1_MSTR_BIT)
+#define SPI_CR1_CPOL (1U << SPI_CR1_CPOL_BIT)
+#define SPI_CR1_CPOL_LOW (0x0 << SPI_CR1_CPOL_BIT)
+#define SPI_CR1_CPOL_HIGH (0x1 << SPI_CR1_CPOL_BIT)
+#define SPI_CR1_CPHA (1U << SPI_CR1_CPHA_BIT)
+
+/* Control register 2 */
+
+#define SPI_CR2_TXEIE_BIT 7
+#define SPI_CR2_RXNEIE_BIT 6
+#define SPI_CR2_ERRIE_BIT 5
+#define SPI_CR2_SSOE_BIT 2
+#define SPI_CR2_TXDMAEN_BIT 1
+#define SPI_CR2_RXDMAEN_BIT 0
+
+#define SPI_CR2_TXEIE (1U << SPI_CR2_TXEIE_BIT)
+#define SPI_CR2_RXNEIE (1U << SPI_CR2_RXNEIE_BIT)
+#define SPI_CR2_ERRIE (1U << SPI_CR2_ERRIE_BIT)
+#define SPI_CR2_SSOE (1U << SPI_CR2_SSOE_BIT)
+#define SPI_CR2_TXDMAEN (1U << SPI_CR2_TXDMAEN_BIT)
+#define SPI_CR2_RXDMAEN (1U << SPI_CR2_RXDMAEN_BIT)
+
+/* Status register */
+
+#define SPI_SR_BSY_BIT 7
+#define SPI_SR_OVR_BIT 6
+#define SPI_SR_MODF_BIT 5
+#define SPI_SR_CRCERR_BIT 4
+#define SPI_SR_UDR_BIT 3
+#define SPI_SR_CHSIDE_BIT 2
+#define SPI_SR_TXE_BIT 1
+#define SPI_SR_RXNE_BIT 0
+
+#define SPI_SR_BSY (1U << SPI_SR_BSY_BIT)
+#define SPI_SR_OVR (1U << SPI_SR_OVR_BIT)
+#define SPI_SR_MODF (1U << SPI_SR_MODF_BIT)
+#define SPI_SR_CRCERR (1U << SPI_SR_CRCERR_BIT)
+#define SPI_SR_UDR (1U << SPI_SR_UDR_BIT)
+#define SPI_SR_CHSIDE (1U << SPI_SR_CHSIDE_BIT)
+#define SPI_SR_CHSIDE_LEFT (0x0 << SPI_SR_CHSIDE_BIT)
+#define SPI_SR_CHSIDE_RIGHT (0x1 << SPI_SR_CHSIDE_BIT)
+#define SPI_SR_TXE (1U << SPI_SR_TXE_BIT)
+#define SPI_SR_RXNE (1U << SPI_SR_RXNE_BIT)
+
+/* I2S configuration register */
+
+#define SPI_I2SCFGR_I2SMOD_BIT 11
+#define SPI_I2SCFGR_I2SE_BIT 10
+#define SPI_I2SCFGR_PCMSYNC_BIT 7
+#define SPI_I2SCFGR_CKPOL_BIT 3
+#define SPI_I2SCFGR_CHLEN_BIT 0
+
+#define SPI_I2SCFGR_I2SMOD (1U << SPI_I2SCFGR_I2SMOD_BIT)
+#define SPI_I2SCFGR_I2SMOD_SPI (0x0 << SPI_I2SCFGR_I2SMOD_BIT)
+#define SPI_I2SCFGR_I2SMOD_I2S (0x1 << SPI_I2SCFGR_I2SMOD_BIT)
+#define SPI_I2SCFGR_I2SE (1U << SPI_I2SCFGR_I2SE_BIT)
+#define SPI_I2SCFGR_I2SCFG (0x3 << 8)
+#define SPI_I2SCFGR_I2SCFG_SLAVE_TX (0x0 << 8)
+#define SPI_I2SCFGR_I2SCFG_SLAVE_RX (0x1 << 8)
+#define SPI_I2SCFGR_I2SCFG_MASTER_TX (0x2 << 8)
+#define SPI_I2SCFGR_I2SCFG_MASTER_RX (0x3 << 8)
+#define SPI_I2SCFGR_PCMSYNC (1U << SPI_I2SCFGR_PCMSYNC_BIT)
+#define SPI_I2SCFGR_PCMSYNC_SHORT (0x0 << SPI_I2SCFGR_PCMSYNC_BIT)
+#define SPI_I2SCFGR_PCMSYNC_LONG (0x1 << SPI_I2SCFGR_PCMSYNC_BIT)
+#define SPI_I2SCFGR_I2SSTD (0x3 << 4)
+#define SPI_I2SCFGR_I2SSTD_PHILLIPS (0x0 << 4)
+#define SPI_I2SCFGR_I2SSTD_MSB (0x1 << 4)
+#define SPI_I2SCFGR_I2SSTD_LSB (0x2 << 4)
+#define SPI_I2SCFGR_I2SSTD_PCM (0x3 << 4)
+#define SPI_I2SCFGR_CKPOL (1U << SPI_I2SCFGR_CKPOL_BIT)
+#define SPI_I2SCFGR_CKPOL_LOW (0x0 << SPI_I2SCFGR_CKPOL_BIT)
+#define SPI_I2SCFGR_CKPOL_HIGH (0x1 << SPI_I2SCFGR_CKPOL_BIT)
+#define SPI_I2SCFGR_DATLEN (0x3 << 1)
+#define SPI_I2SCFGR_DATLEN_16_BIT (0x0 << 1)
+#define SPI_I2SCFGR_DATLEN_24_BIT (0x1 << 1)
+#define SPI_I2SCFGR_DATLEN_32_BIT (0x2 << 1)
+#define SPI_I2SCFGR_CHLEN (1U << SPI_I2SCFGR_CHLEN_BIT)
+#define SPI_I2SCFGR_CHLEN_16_BIT (0x0 << SPI_I2SCFGR_CHLEN_BIT)
+#define SPI_I2SCFGR_CHLEN_32_BIT (0x1 << SPI_I2SCFGR_CHLEN_BIT)
+
+/* I2S prescaler register */
+
+#define SPI_I2SPR_MCKOE_BIT 9
+#define SPI_I2SPR_ODD_BIT 8
+
+#define SPI_I2SPR_MCKOE (1U << SPI_I2SPR_MCKOE_BIT)
+#define SPI_I2SPR_ODD (1U << SPI_I2SPR_ODD_BIT)
+#define SPI_I2SPR_I2SDIV 0xFF
+
+/*
+ * Devices
+ */
+
+/** SPI device type */
+typedef struct spi_dev {
+ spi_reg_map *regs; /**< Register map */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ nvic_irq_num irq_num; /**< NVIC interrupt number */
+} spi_dev;
+
+/*
+ * SPI Convenience functions
+ */
+
+void spi_init(spi_dev *dev);
+
+struct gpio_dev;
+/**
+ * @brief Configure GPIO bit modes for use as a SPI port's pins.
+ *
+ * @param dev SPI device
+ * @param as_master If true, configure as bus master; otherwise, as slave.
+ * @param nss_dev NSS pin's GPIO device
+ * @param nss_bit NSS pin's GPIO bit on nss_dev
+ * @param comm_dev SCK, MISO, MOSI pins' GPIO device
+ * @param sck_bit SCK pin's GPIO bit on comm_dev
+ * @param miso_bit MISO pin's GPIO bit on comm_dev
+ * @param mosi_bit MOSI pin's GPIO bit on comm_dev
+ */
+extern void spi_config_gpios(spi_dev *dev,
+ uint8 as_master,
+ struct gpio_dev *nss_dev,
+ uint8 nss_bit,
+ struct gpio_dev *comm_dev,
+ uint8 sck_bit,
+ uint8 miso_bit,
+ uint8 mosi_bit);
+
+/**
+ * @brief SPI mode configuration.
+ *
+ * A SPI mode determines a combination of the idle state of the clock
+ * line (the clock polarity, or "CPOL"), and which clock edge triggers
+ * data capture (the clock phase, or "CPHA").
+ */
+typedef enum spi_mode {
+ /** Clock idles low, data captured on rising edge (first transition) */
+ SPI_MODE_LOW_RISING = 0,
+ /** Clock idles low, data captured on falling edge (second transition) */
+ SPI_MODE_LOW_FALLING = 1,
+ /** Clock idles high, data captured on falling edge (first transition) */
+ SPI_MODE_HIGH_FALLING = 2,
+ /** Clock idles high, data captured on rising edge (second transition) */
+ SPI_MODE_HIGH_RISING = 3,
+
+ SPI_MODE_0 = SPI_MODE_LOW_RISING, /**< Same as SPI_MODE_LOW_RISING */
+ SPI_MODE_1 = SPI_MODE_LOW_FALLING, /**< Same as SPI_MODE_LOW_FALLING */
+ SPI_MODE_2 = SPI_MODE_HIGH_FALLING, /**< Same as SPI_MODE_HIGH_FALLING */
+ SPI_MODE_3 = SPI_MODE_HIGH_RISING, /**< Same as SPI_MODE_HIGH_RISING */
+} spi_mode;
+
+/**
+ * @brief SPI baud rate configuration, as a divisor of f_PCLK, the
+ * PCLK clock frequency.
+ */
+typedef enum spi_baud_rate {
+ SPI_BAUD_PCLK_DIV_2 = SPI_CR1_BR_PCLK_DIV_2, /**< f_PCLK/2 */
+ SPI_BAUD_PCLK_DIV_4 = SPI_CR1_BR_PCLK_DIV_4, /**< f_PCLK/4 */
+ SPI_BAUD_PCLK_DIV_8 = SPI_CR1_BR_PCLK_DIV_8, /**< f_PCLK/8 */
+ SPI_BAUD_PCLK_DIV_16 = SPI_CR1_BR_PCLK_DIV_16, /**< f_PCLK/16 */
+ SPI_BAUD_PCLK_DIV_32 = SPI_CR1_BR_PCLK_DIV_32, /**< f_PCLK/32 */
+ SPI_BAUD_PCLK_DIV_64 = SPI_CR1_BR_PCLK_DIV_64, /**< f_PCLK/64 */
+ SPI_BAUD_PCLK_DIV_128 = SPI_CR1_BR_PCLK_DIV_128, /**< f_PCLK/128 */
+ SPI_BAUD_PCLK_DIV_256 = SPI_CR1_BR_PCLK_DIV_256, /**< f_PCLK/256 */
+} spi_baud_rate;
+
+/**
+ * @brief SPI initialization flags.
+ * @see spi_master_enable()
+ * @see spi_slave_enable()
+ */
+typedef enum spi_cfg_flag {
+ SPI_BIDIMODE = SPI_CR1_BIDIMODE, /**< Bidirectional mode enable */
+ SPI_BIDIOE = SPI_CR1_BIDIOE, /**< Output enable in bidirectional
+ mode */
+ SPI_CRCEN = SPI_CR1_CRCEN, /**< Cyclic redundancy check (CRC)
+ enable */
+ SPI_DFF_8_BIT = SPI_CR1_DFF_8_BIT, /**< 8-bit data frame format (this is
+ the default) */
+ SPI_DFF_16_BIT = SPI_CR1_DFF_16_BIT, /**< 16-bit data frame format */
+ SPI_RX_ONLY = SPI_CR1_RXONLY, /**< Receive only */
+ SPI_SW_SLAVE = SPI_CR1_SSM, /**< Software slave management */
+ SPI_SOFT_SS = SPI_CR1_SSI, /**< Software (internal) slave
+ select. This flag only has an
+ effect when used in combination
+ with SPI_SW_SLAVE. */
+ SPI_FRAME_LSB = SPI_CR1_LSBFIRST, /**< LSB-first (little-endian) frame
+ format */
+ SPI_FRAME_MSB = 0, /**< MSB-first (big-endian) frame
+ format (this is the default) */
+} spi_cfg_flag;
+
+void spi_master_enable(spi_dev *dev,
+ spi_baud_rate baud,
+ spi_mode mode,
+ uint32 flags);
+
+void spi_slave_enable(spi_dev *dev,
+ spi_mode mode,
+ uint32 flags);
+
+uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len);
+
+/**
+ * @brief Call a function on each SPI port
+ * @param fn Function to call.
+ */
+extern void spi_foreach(void (*fn)(spi_dev*));
+
+void spi_peripheral_enable(spi_dev *dev);
+void spi_peripheral_disable(spi_dev *dev);
+
+void spi_tx_dma_enable(spi_dev *dev);
+void spi_tx_dma_disable(spi_dev *dev);
+
+void spi_rx_dma_enable(spi_dev *dev);
+void spi_rx_dma_disable(spi_dev *dev);
+
+/**
+ * @brief Determine if a SPI peripheral is enabled.
+ * @param dev SPI device
+ * @return True, if and only if dev's peripheral is enabled.
+ */
+static inline uint8 spi_is_enabled(spi_dev *dev) {
+ return dev->regs->CR1 & SPI_CR1_SPE_BIT;
+}
+
+/**
+ * @brief Disable all SPI peripherals
+ */
+static inline void spi_peripheral_disable_all(void) {
+ spi_foreach(spi_peripheral_disable);
+}
+
+/** Available SPI interrupts */
+typedef enum spi_interrupt {
+ SPI_TXE_INTERRUPT = SPI_CR2_TXEIE, /**< TX buffer empty interrupt */
+ SPI_RXNE_INTERRUPT = SPI_CR2_RXNEIE, /**< RX buffer not empty interrupt */
+ SPI_ERR_INTERRUPT = SPI_CR2_ERRIE /**<
+ * Error interrupt (CRC, overrun,
+ * and mode fault errors for SPI;
+ * underrun, overrun errors for I2S)
+ */
+} spi_interrupt;
+
+/**
+ * @brief Mask for all spi_interrupt values
+ * @see spi_interrupt
+ */
+#define SPI_INTERRUPTS_ALL (SPI_TXE_INTERRUPT | \
+ SPI_RXNE_INTERRUPT | \
+ SPI_ERR_INTERRUPT)
+
+/**
+ * @brief Enable SPI interrupt requests
+ * @param dev SPI device
+ * @param interrupt_flags Bitwise OR of spi_interrupt values to enable
+ * @see spi_interrupt
+ */
+static inline void spi_irq_enable(spi_dev *dev, uint32 interrupt_flags) {
+ dev->regs->CR2 |= interrupt_flags;
+ nvic_irq_enable(dev->irq_num);
+}
+
+/**
+ * @brief Disable SPI interrupt requests
+ * @param dev SPI device
+ * @param interrupt_flags Bitwise OR of spi_interrupt values to disable
+ * @see spi_interrupt
+ */
+static inline void spi_irq_disable(spi_dev *dev, uint32 interrupt_flags) {
+ dev->regs->CR2 &= ~interrupt_flags;
+}
+
+/**
+ * @brief Get the data frame format flags with which a SPI port is
+ * configured.
+ * @param dev SPI device whose data frame format to get.
+ * @return SPI_DFF_8_BIT, if dev has an 8-bit data frame format.
+ * Otherwise, SPI_DFF_16_BIT.
+ */
+static inline spi_cfg_flag spi_dff(spi_dev *dev) {
+ return ((dev->regs->CR1 & SPI_CR1_DFF) == SPI_CR1_DFF_8_BIT ?
+ SPI_DFF_8_BIT :
+ SPI_DFF_16_BIT);
+}
+
+/**
+ * @brief Determine whether the device's peripheral receive (RX)
+ * register is empty.
+ * @param dev SPI device
+ * @return true, iff dev's RX register is empty.
+ */
+static inline uint8 spi_is_rx_nonempty(spi_dev *dev) {
+ return dev->regs->SR & SPI_SR_RXNE;
+}
+
+/**
+ * @brief Retrieve the contents of the device's peripheral receive
+ * (RX) register.
+ *
+ * You may only call this function when the RX register is nonempty.
+ * Calling this function clears the contents of the RX register.
+ *
+ * @param dev SPI device
+ * @return Contents of dev's peripheral RX register
+ * @see spi_is_rx_reg_nonempty()
+ */
+static inline uint16 spi_rx_reg(spi_dev *dev) {
+ return (uint16)dev->regs->DR;
+}
+
+/**
+ * @brief Determine whether the device's peripheral transmit (TX)
+ * register is empty.
+ * @param dev SPI device
+ * @return true, iff dev's TX register is empty.
+ */
+static inline uint8 spi_is_tx_empty(spi_dev *dev) {
+ return dev->regs->SR & SPI_SR_TXE;
+}
+
+/**
+ * @brief Load a value into the device's peripheral transmit (TX) register.
+ *
+ * You may only call this function when the TX register is empty.
+ * Calling this function loads val into the peripheral's TX register.
+ * If the device is properly configured, this will initiate a
+ * transmission, the completion of which will cause the TX register to
+ * be empty again.
+ *
+ * @param dev SPI device
+ * @param val Value to load into the TX register. If the SPI data
+ * frame format is 8 bit, the value must be right-aligned.
+ * @see spi_is_tx_reg_empty()
+ * @see spi_init()
+ * @see spi_master_enable()
+ * @see spi_slave_enable()
+ */
+static inline void spi_tx_reg(spi_dev *dev, uint16 val) {
+ dev->regs->DR = val;
+}
+
+/**
+ * @brief Determine whether the device's peripheral busy (SPI_SR_BSY)
+ * flag is set.
+ * @param dev SPI device
+ * @return true, iff dev's BSY flag is set.
+ */
+static inline uint8 spi_is_busy(spi_dev *dev) {
+ return dev->regs->SR & SPI_SR_BSY;
+}
+
+/*
+ * I2S convenience functions (TODO)
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/stm32.h b/libmaple/include/libmaple/stm32.h
new file mode 100644
index 0000000..3845cab
--- /dev/null
+++ b/libmaple/include/libmaple/stm32.h
@@ -0,0 +1,237 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/stm32.h
+ * @brief STM32 chip header
+ *
+ * This header supplies various chip-specific values for the current
+ * build target. It's useful both to abstract away hardware details
+ * (e.g. through use of STM32_NR_INTERRUPTS) and to decide what to do
+ * when you want something nonportable (e.g. by checking
+ * STM32_MCU_SERIES).
+ */
+
+#ifndef _LIBMAPLE_STM32_H_
+#define _LIBMAPLE_STM32_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * STM32 series identifiers.
+ *
+ * Don't make these into an enum; the preprocessor needs them.
+ */
+
+/** STM32F1 series. */
+#define STM32_SERIES_F1 0
+/** STM32F2 series. */
+#define STM32_SERIES_F2 1
+/** STM32L1 series. */
+#define STM32_SERIES_L1 2
+/** STM32F4 series. */
+#define STM32_SERIES_F4 3
+
+/* The series header is responsible for defining:
+ *
+ * - Everything in the following __DOXYGEN__ conditional block.
+ *
+ * - STM32_HAVE_FSMC: 1 if the MCU has the FSMC peripheral, and 0
+ * otherwise.
+ *
+ * - STM32_HAVE_USB: 1 if the MCU has a USB peripheral, and 0
+ * otherwise.
+ */
+#include <series/stm32.h>
+
+/* Ensure the series header isn't broken. */
+#if (!defined(STM32_PCLK1) || \
+ !defined(STM32_PCLK2) || \
+ !defined(STM32_MCU_SERIES) || \
+ !defined(STM32_NR_INTERRUPTS) || \
+ !defined(STM32_NR_GPIO_PORTS) || \
+ !defined(STM32_TIMER_MASK) || \
+ !defined(STM32_DELAY_US_MULT) || \
+ !defined(STM32_SRAM_END) || \
+ !defined(STM32_HAVE_DAC) || \
+ !defined(STM32_HAVE_FSMC) || \
+ !defined(STM32_HAVE_USB))
+#error "Bad STM32F1 configuration. Check <series/stm32.h> header for your MCU."
+#endif
+
+/*
+ * Derived macros
+ */
+
+/* FIXME [0.0.13] add this to ReST API page */
+/**
+ * @brief Statically determine whether a timer is present.
+ *
+ * Given a constant timer number n (starting from 1), this macro has a
+ * nonzero value exactly when TIMERn is available.
+ */
+#define STM32_HAVE_TIMER(n) (STM32_TIMER_MASK & (1 << (n)))
+
+/*
+ * Doxygen for functionality provided by series header.
+ */
+
+#ifdef __DOXYGEN__
+
+/*
+ * Clock configuration.
+ *
+ * These defines depend upon how the MCU is configured. Because of
+ * the potential for a mismatch between them and the actual clock
+ * configuration, keep their number to a minimum.
+ */
+
+/**
+ * @brief APB1 clock speed, in Hz.
+ */
+#define STM32_PCLK1
+
+/**
+ * @brief APB2 clock speed, in Hz.
+ */
+#define STM32_PCLK2
+
+/** @brief Deprecated. Use STM32_PCLK1 instead. */
+#define PCLK1
+/** @brief Deprecated. Use STM32_PCLK2 instead. */
+#define PCLK2
+
+/*
+ * Series- and MCU-specific values.
+ */
+
+/**
+ * @brief STM32 series value for the MCU being targeted.
+ *
+ * At time of writing, allowed values are: STM32_SERIES_F1,
+ * STM32_SERIES_F2. This set of values will expand as libmaple adds
+ * support for more STM32 series MCUs.
+ */
+#define STM32_MCU_SERIES
+
+/**
+ * @brief Number of interrupts in the vector table.
+ *
+ * This does not include Cortex-M interrupts (NMI, HardFault, etc.).
+ */
+#define STM32_NR_INTERRUPTS
+
+/**
+ * Number of GPIO ports.
+ */
+#define STM32_NR_GPIO_PORTS
+
+/* FIXME [0.0.13] add this to ReST API page */
+/**
+ * @brief Bitmask of timers available on the MCU.
+ *
+ * That is, if TIMERn is available, then STM32_TIMER_MASK & (1 << n)
+ * will be nonzero. For example, a nonzero value of "STM32_TIMER_MASK
+ * & 0x2" means TIMER1 is available.
+ *
+ * A bitmask is necessary as some STM32 MCUs have "holes" in the range
+ * of available timers.
+ */
+#define STM32_TIMER_MASK
+
+/**
+ * @brief Multiplier to convert microseconds into loop iterations
+ * in delay_us().
+ *
+ * @see delay_us()
+ */
+#define STM32_DELAY_US_MULT
+
+/**
+ * @brief Pointer to end of built-in SRAM.
+ *
+ * Points to the address which is 1 byte past the last valid
+ * SRAM address.
+ */
+#define STM32_SRAM_END
+
+/**
+ * @brief 1 if the target MCU has a DAC, and 0 otherwise.
+ */
+#define STM32_HAVE_DAC
+
+/**
+ * @brief 1 if the target MCU has the FSMC peripheral, and 0 otherwise.
+ *
+ * Note that the feature set of the FSMC peripheral is restricted on
+ * some MCUs.
+ */
+#define STM32_HAVE_FSMC
+
+/**
+ * @brief 1 if the target MCU has a USB peripheral, and 0 otherwise.
+ *
+ * Note that a variety of USB peripherals are available across the
+ * different series, with widely varying feature sets and programming
+ * interfaces. This macro will be 1 if any such peripheral is present.
+ */
+#define STM32_HAVE_USB
+
+#endif /* __DOXYGEN__ */
+
+/*
+ * The following are for backwards compatibility only.
+ */
+
+/* PCLK1 and PCLK2 are for backwards compatibility only; don't use in
+ * new code. */
+#ifndef PCLK1
+#define PCLK1 STM32_PCLK1
+#endif
+#if PCLK1 != STM32_PCLK1
+#error "PCLK1 (which is deprecated) differs from STM32_PCLK1."
+#endif
+#ifndef PCLK2
+#define PCLK2 STM32_PCLK2
+#endif
+#if PCLK2 != STM32_PCLK2
+#error "PCLK2 (which is deprecated) differs from STM32_PCLK2."
+#endif
+
+/** @brief Deprecated. Use STM32_NR_INTERRUPTS instead. */
+#define NR_INTERRUPTS STM32_NR_INTERRUPTS
+/** @brief Deprecated. Use STM32_NR_GPIO_PORTS instead. */
+#define NR_GPIO_PORTS STM32_NR_GPIO_PORTS
+/** @brief Deprecated. Use STM32_DELAY_US_MULT instead. */
+#define DELAY_US_MULT STM32_DELAY_US_MULT
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/syscfg.h b/libmaple/include/libmaple/syscfg.h
new file mode 100644
index 0000000..6b375d3
--- /dev/null
+++ b/libmaple/include/libmaple/syscfg.h
@@ -0,0 +1,151 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/syscfg.h
+ * @brief System configuration controller (SYSCFG)
+ *
+ * Availability: STM32F2, STM32F4.
+ */
+
+#ifndef _LIBMAPLE_SYSCFG_H_
+#define _LIBMAPLE_SYSCFG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map and base pointer
+ */
+
+/**
+ * @brief SYSCFG register map type.
+ */
+typedef struct syscfg_reg_map {
+ __io uint32 MEMRMP; /**< Memory remap register */
+ __io uint32 PMC; /**< Peripheral mode configuration */
+ __io uint32 EXTICR[4]; /**< External interrupt configuration registers */
+ const uint32 RESERVED1;
+ const uint32 RESERVED2;
+ __io uint32 CMPCR; /**< Compensation cell control register */
+} syscfg_reg_map;
+
+/** SYSCFG register map base pointer */
+#define SYSCFG_BASE ((struct syscfg_reg_map*)0x40013800)
+
+/*
+ * Register bit definitions
+ */
+
+/* Memory remap register */
+
+#define SYSCFG_MEMRMP_MEM_MODE 0x3
+#define SYSCFG_MEMRMP_MEM_MODE_FLASH 0x0
+#define SYSCFG_MEMRMP_MEM_MODE_SYS_FLASH 0x1
+#define SYSCFG_MEMRMP_MEM_MODE_FSMC_1 0x2
+#define SYSCFG_MEMRMP_MEM_MODE_EMB_SRAM 0x3
+
+/* Peripheral mode configuration register */
+
+#define SYSCFG_PMC_MII_RMII_SEL_BIT 23
+
+#define SYSCFG_PMC_MII_RMII_SEL (1U << SYSCFG_PMC_MII_RMII_SEL_BIT)
+#define SYSCFG_PMC_MII_RMII_SEL_MII (0U << SYSCFG_PMC_MII_RMII_SEL_BIT)
+#define SYSCFG_PMC_MII_RMII_SEL_RMII (1U << SYSCFG_PMC_MII_RMII_SEL_BIT)
+
+/* External interrupt configuration register 1 */
+
+#define SYSCFG_EXTICR1_EXTI0 0xF
+#define SYSCFG_EXTICR1_EXTI1 0xF0
+#define SYSCFG_EXTICR1_EXTI2 0xF00
+#define SYSCFG_EXTICR1_EXTI3 0xF000
+
+/* External interrupt configuration register 2 */
+
+#define SYSCFG_EXTICR2_EXTI4 0xF
+#define SYSCFG_EXTICR2_EXTI5 0xF0
+#define SYSCFG_EXTICR2_EXTI6 0xF00
+#define SYSCFG_EXTICR2_EXTI7 0xF000
+
+/* External interrupt configuration register 3 */
+
+#define SYSCFG_EXTICR3_EXTI8 0xF
+#define SYSCFG_EXTICR3_EXTI9 0xF0
+#define SYSCFG_EXTICR3_EXTI10 0xF00
+#define SYSCFG_EXTICR3_EXTI11 0xF000
+
+/* External interrupt configuration register 4 */
+
+#define SYSCFG_EXTICR4_EXTI12 0xF
+#define SYSCFG_EXTICR4_EXTI13 0xF0
+#define SYSCFG_EXTICR4_EXTI14 0xF00
+#define SYSCFG_EXTICR4_EXTI15 0xF000
+
+/* Compensation cell control register */
+
+#define SYSCFG_CMPCR_READY_BIT 8
+#define SYSCFG_CMPCR_CMP_PD_BIT 0
+
+#define SYSCFG_CMPCR_READY (1U << SYSCFG_CMPCR_READY_BIT)
+#define SYSCFG_CMPCR_CMP_PD (1U << SYSCFG_CMPCR_CMP_PD_BIT)
+#define SYSCFG_CMPCR_CMP_PD_PDWN (0U << SYSCFG_CMPCR_CMP_PD_BIT)
+#define SYSCFG_CMPCR_CMP_PD_ENABLE (1U << SYSCFG_CMPCR_CMP_PD_BIT)
+
+/*
+ * Routines
+ */
+
+void syscfg_init(void);
+
+void syscfg_enable_io_compensation(void);
+void syscfg_disable_io_compensation(void);
+
+/**
+ * @brief System memory mode
+ * These values specify what memory to map to address 0x00000000.
+ * @see syscfg_set_mem_mode
+ */
+typedef enum syscfg_mem_mode {
+ /** Main flash memory is mapped at 0x0. */
+ SYCFG_MEM_MODE_FLASH = SYSCFG_MEMRMP_MEM_MODE_FLASH,
+ /** System flash (i.e. ST's baked-in bootloader) is mapped at 0x0. */
+ SYCFG_MEM_MODE_SYSTEM_FLASH = SYSCFG_MEMRMP_MEM_MODE_SYS_FLASH,
+ /** FSMC bank 1 (NOR/PSRAM 1 and 2) is mapped at 0x0. */
+ SYCFG_MEM_MODE_FSMC_BANK_1 = SYSCFG_MEMRMP_MEM_MODE_FSMC_1,
+ /** Embedded SRAM (i.e., not backup SRAM) is mapped at 0x0. */
+ SYCFG_MEM_MODE_SRAM = SYSCFG_MEMRMP_MEM_MODE_EMB_SRAM,
+} syscfg_mem_mode;
+
+void syscfg_set_mem_mode(syscfg_mem_mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/systick.h b/libmaple/include/libmaple/systick.h
new file mode 100644
index 0000000..551f800
--- /dev/null
+++ b/libmaple/include/libmaple/systick.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/systick.h
+ * @brief System timer definitions
+ */
+
+#ifndef _LIBMAPLE_SYSTICK_H_
+#define _LIBMAPLE_SYSTICK_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
+
+/** SysTick register map type */
+typedef struct systick_reg_map {
+ __io uint32 CSR; /**< Control and status register */
+ __io uint32 RVR; /**< Reload value register */
+ __io uint32 CNT; /**< Current value register ("count") */
+ __io uint32 CVR; /**< Calibration value register */
+} systick_reg_map;
+
+/** SysTick register map base pointer */
+#define SYSTICK_BASE ((struct systick_reg_map*)0xE000E010)
+
+/*
+ * Register bit definitions.
+ */
+
+/* Control and status register */
+
+#define SYSTICK_CSR_COUNTFLAG BIT(16)
+#define SYSTICK_CSR_CLKSOURCE BIT(2)
+#define SYSTICK_CSR_CLKSOURCE_EXTERNAL 0
+#define SYSTICK_CSR_CLKSOURCE_CORE BIT(2)
+#define SYSTICK_CSR_TICKINT BIT(1)
+#define SYSTICK_CSR_TICKINT_PEND BIT(1)
+#define SYSTICK_CSR_TICKINT_NO_PEND 0
+#define SYSTICK_CSR_ENABLE BIT(0)
+#define SYSTICK_CSR_ENABLE_MULTISHOT BIT(0)
+#define SYSTICK_CSR_ENABLE_DISABLED 0
+
+/* Calibration value register */
+
+#define SYSTICK_CVR_NOREF BIT(31)
+#define SYSTICK_CVR_SKEW BIT(30)
+#define SYSTICK_CVR_TENMS 0xFFFFFF
+
+/** System elapsed time, in milliseconds */
+extern volatile uint32 systick_uptime_millis;
+
+/**
+ * @brief Returns the system uptime, in milliseconds.
+ */
+static inline uint32 systick_uptime(void) {
+ return systick_uptime_millis;
+}
+
+
+void systick_init(uint32 reload_val);
+void systick_disable();
+void systick_enable();
+
+/**
+ * @brief Returns the current value of the SysTick counter.
+ */
+static inline uint32 systick_get_count(void) {
+ return SYSTICK_BASE->CNT;
+}
+
+/**
+ * @brief Check for underflow.
+ *
+ * This function returns 1 if the SysTick timer has counted to 0 since
+ * the last time it was called. However, any reads of any part of the
+ * SysTick Control and Status Register SYSTICK_BASE->CSR will
+ * interfere with this functionality. See the ARM Cortex M3 Technical
+ * Reference Manual for more details (e.g. Table 8-3 in revision r1p1).
+ */
+static inline uint32 systick_check_underflow(void) {
+ return SYSTICK_BASE->CSR & SYSTICK_CSR_COUNTFLAG;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/timer.h b/libmaple/include/libmaple/timer.h
new file mode 100644
index 0000000..995f868
--- /dev/null
+++ b/libmaple/include/libmaple/timer.h
@@ -0,0 +1,1110 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/timer.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Timer interface.
+ */
+
+#ifndef _LIBMAPLE_TIMER_H_
+#define _LIBMAPLE_TIMER_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <series/timer.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
+#include <libmaple/nvic.h>
+#include <libmaple/bitband.h>
+
+/*
+ * Register maps
+ */
+
+/** Advanced control timer register map type */
+typedef struct timer_adv_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SMCR; /**< Slave mode control register */
+ __io uint32 DIER; /**< DMA/interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ __io uint32 CCMR1; /**< Capture/compare mode register 1 */
+ __io uint32 CCMR2; /**< Capture/compare mode register 2 */
+ __io uint32 CCER; /**< Capture/compare enable register */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+ __io uint32 RCR; /**< Repetition counter register */
+ __io uint32 CCR1; /**< Capture/compare register 1 */
+ __io uint32 CCR2; /**< Capture/compare register 2 */
+ __io uint32 CCR3; /**< Capture/compare register 3 */
+ __io uint32 CCR4; /**< Capture/compare register 4 */
+ __io uint32 BDTR; /**< Break and dead-time register */
+ __io uint32 DCR; /**< DMA control register */
+ __io uint32 DMAR; /**< DMA address for full transfer */
+} timer_adv_reg_map;
+
+/* General purpose timer register map type: intentionally omitted.
+ *
+ * General purpose timers differ slightly across series, so leave it
+ * up to the series header to define struct timer_gen_reg_map. */
+
+/** Basic timer register map type */
+typedef struct timer_bas_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 DIER; /**< DMA/interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ const uint32 RESERVED2; /**< Reserved */
+ const uint32 RESERVED3; /**< Reserved */
+ const uint32 RESERVED4; /**< Reserved */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+} timer_bas_reg_map;
+
+/*
+ * Timer devices
+ */
+
+/**
+ * @brief Timer register map type.
+ *
+ * Just holds a pointer to the correct type of register map, based on
+ * the timer's type.
+ */
+typedef union timer_reg_map {
+ timer_adv_reg_map *adv; /**< Advanced register map */
+ timer_gen_reg_map *gen; /**< General purpose register map */
+ timer_bas_reg_map *bas; /**< Basic register map */
+} timer_reg_map;
+
+/**
+ * @brief Timer type
+ *
+ * Type marker for timer_dev.
+ *
+ * @see timer_dev
+ */
+typedef enum timer_type {
+ TIMER_ADVANCED, /**< Advanced type */
+ TIMER_GENERAL, /**< General purpose type */
+ TIMER_BASIC, /**< Basic type */
+} timer_type;
+
+/** Timer device type */
+typedef struct timer_dev {
+ timer_reg_map regs; /**< Register map */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ timer_type type; /**< Timer's type */
+ voidFuncPtr handlers[]; /**<
+ * Don't touch these. Use these instead:
+ * @see timer_attach_interrupt()
+ * @see timer_detach_interrupt() */
+} timer_dev;
+
+#if STM32_HAVE_TIMER(1)
+extern timer_dev *TIMER1;
+#endif
+#if STM32_HAVE_TIMER(2)
+extern timer_dev *TIMER2;
+#endif
+#if STM32_HAVE_TIMER(3)
+extern timer_dev *TIMER3;
+#endif
+#if STM32_HAVE_TIMER(4)
+extern timer_dev *TIMER4;
+#endif
+#if STM32_HAVE_TIMER(5)
+extern timer_dev *TIMER5;
+#endif
+#if STM32_HAVE_TIMER(6)
+extern timer_dev *TIMER6;
+#endif
+#if STM32_HAVE_TIMER(7)
+extern timer_dev *TIMER7;
+#endif
+#if STM32_HAVE_TIMER(8)
+extern timer_dev *TIMER8;
+#endif
+#if STM32_HAVE_TIMER(9)
+extern timer_dev *TIMER9;
+#endif
+#if STM32_HAVE_TIMER(10)
+extern timer_dev *TIMER10;
+#endif
+#if STM32_HAVE_TIMER(11)
+extern timer_dev *TIMER11;
+#endif
+#if STM32_HAVE_TIMER(12)
+extern timer_dev *TIMER12;
+#endif
+#if STM32_HAVE_TIMER(13)
+extern timer_dev *TIMER13;
+#endif
+#if STM32_HAVE_TIMER(14)
+extern timer_dev *TIMER14;
+#endif
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 1 (CR1) */
+
+#define TIMER_CR1_ARPE_BIT 7
+#define TIMER_CR1_DIR_BIT 4
+#define TIMER_CR1_OPM_BIT 3
+#define TIMER_CR1_URS_BIT 2
+#define TIMER_CR1_UDIS_BIT 1
+#define TIMER_CR1_CEN_BIT 0
+
+#define TIMER_CR1_CKD (0x3 << 8)
+#define TIMER_CR1_CKD_1TCKINT (0x0 << 8)
+#define TIMER_CR1_CKD_2TCKINT (0x1 << 8)
+#define TIMER_CR1_CKD_4TICKINT (0x2 << 8)
+#define TIMER_CR1_ARPE (1U << TIMER_CR1_ARPE_BIT)
+#define TIMER_CR1_CKD_CMS (0x3 << 5)
+#define TIMER_CR1_CKD_CMS_EDGE (0x0 << 5)
+#define TIMER_CR1_CKD_CMS_CENTER1 (0x1 << 5)
+#define TIMER_CR1_CKD_CMS_CENTER2 (0x2 << 5)
+#define TIMER_CR1_CKD_CMS_CENTER3 (0x3 << 5)
+#define TIMER_CR1_DIR (1U << TIMER_CR1_DIR_BIT)
+#define TIMER_CR1_OPM (1U << TIMER_CR1_OPM_BIT)
+#define TIMER_CR1_URS (1U << TIMER_CR1_URS_BIT)
+#define TIMER_CR1_UDIS (1U << TIMER_CR1_UDIS_BIT)
+#define TIMER_CR1_CEN (1U << TIMER_CR1_CEN_BIT)
+
+/* Control register 2 (CR2) */
+
+#define TIMER_CR2_OIS4_BIT 14
+#define TIMER_CR2_OIS3N_BIT 13
+#define TIMER_CR2_OIS3_BIT 12
+#define TIMER_CR2_OIS2N_BIT 11
+#define TIMER_CR2_OIS2_BIT 10
+#define TIMER_CR2_OIS1N_BIT 9
+#define TIMER_CR2_OIS1_BIT 8
+#define TIMER_CR2_TI1S_BIT 7
+#define TIMER_CR2_CCDS_BIT 3
+#define TIMER_CR2_CCUS_BIT 2
+#define TIMER_CR2_CCPC_BIT 0
+
+#define TIMER_CR2_OIS4 (1U << TIMER_CR2_OIS4_BIT)
+#define TIMER_CR2_OIS3N (1U << TIMER_CR2_OIS3N_BIT)
+#define TIMER_CR2_OIS3 (1U << TIMER_CR2_OIS3_BIT)
+#define TIMER_CR2_OIS2N (1U << TIMER_CR2_OIS2N_BIT)
+#define TIMER_CR2_OIS2 (1U << TIMER_CR2_OIS2_BIT)
+#define TIMER_CR2_OIS1N (1U << TIMER_CR2_OIS1N_BIT)
+#define TIMER_CR2_OIS1 (1U << TIMER_CR2_OIS1_BIT)
+#define TIMER_CR2_TI1S (1U << TIMER_CR2_TI1S_BIT)
+#define TIMER_CR2_MMS (0x7 << 4)
+#define TIMER_CR2_MMS_RESET (0x0 << 4)
+#define TIMER_CR2_MMS_ENABLE (0x1 << 4)
+#define TIMER_CR2_MMS_UPDATE (0x2 << 4)
+#define TIMER_CR2_MMS_COMPARE_PULSE (0x3 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC1REF (0x4 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC2REF (0x5 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC3REF (0x6 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC4REF (0x7 << 4)
+#define TIMER_CR2_CCDS (1U << TIMER_CR2_CCDS_BIT)
+#define TIMER_CR2_CCUS (1U << TIMER_CR2_CCUS_BIT)
+#define TIMER_CR2_CCPC (1U << TIMER_CR2_CCPC_BIT)
+
+/* Slave mode control register (SMCR) */
+
+#define TIMER_SMCR_ETP_BIT 15
+#define TIMER_SMCR_ECE_BIT 14
+#define TIMER_SMCR_MSM_BIT 7
+
+#define TIMER_SMCR_ETP (1U << TIMER_SMCR_ETP_BIT)
+#define TIMER_SMCR_ECE (1U << TIMER_SMCR_ECE_BIT)
+#define TIMER_SMCR_ETPS (0x3 << 12)
+#define TIMER_SMCR_ETPS_OFF (0x0 << 12)
+#define TIMER_SMCR_ETPS_DIV2 (0x1 << 12)
+#define TIMER_SMCR_ETPS_DIV4 (0x2 << 12)
+#define TIMER_SMCR_ETPS_DIV8 (0x3 << 12)
+#define TIMER_SMCR_ETF (0xF << 12)
+#define TIMER_SMCR_MSM (1U << TIMER_SMCR_MSM_BIT)
+#define TIMER_SMCR_TS (0x3 << 4)
+#define TIMER_SMCR_TS_ITR0 (0x0 << 4)
+#define TIMER_SMCR_TS_ITR1 (0x1 << 4)
+#define TIMER_SMCR_TS_ITR2 (0x2 << 4)
+#define TIMER_SMCR_TS_ITR3 (0x3 << 4)
+#define TIMER_SMCR_TS_TI1F_ED (0x4 << 4)
+#define TIMER_SMCR_TS_TI1FP1 (0x5 << 4)
+#define TIMER_SMCR_TS_TI2FP2 (0x6 << 4)
+#define TIMER_SMCR_TS_ETRF (0x7 << 4)
+#define TIMER_SMCR_SMS 0x3
+#define TIMER_SMCR_SMS_DISABLED 0x0
+#define TIMER_SMCR_SMS_ENCODER1 0x1
+#define TIMER_SMCR_SMS_ENCODER2 0x2
+#define TIMER_SMCR_SMS_ENCODER3 0x3
+#define TIMER_SMCR_SMS_RESET 0x4
+#define TIMER_SMCR_SMS_GATED 0x5
+#define TIMER_SMCR_SMS_TRIGGER 0x6
+#define TIMER_SMCR_SMS_EXTERNAL 0x7
+
+/* DMA/Interrupt enable register (DIER) */
+
+#define TIMER_DIER_TDE_BIT 14
+#define TIMER_DIER_COMDE_BIT 13
+#define TIMER_DIER_CC4DE_BIT 12
+#define TIMER_DIER_CC3DE_BIT 11
+#define TIMER_DIER_CC2DE_BIT 10
+#define TIMER_DIER_CC1DE_BIT 9
+#define TIMER_DIER_UDE_BIT 8
+#define TIMER_DIER_BIE_BIT 7
+#define TIMER_DIER_TIE_BIT 6
+#define TIMER_DIER_COMIE_BIT 5
+#define TIMER_DIER_CC4IE_BIT 4
+#define TIMER_DIER_CC3IE_BIT 3
+#define TIMER_DIER_CC2IE_BIT 2
+#define TIMER_DIER_CC1IE_BIT 1
+#define TIMER_DIER_UIE_BIT 0
+
+#define TIMER_DIER_TDE (1U << TIMER_DIER_TDE_BIT)
+#define TIMER_DIER_COMDE (1U << TIMER_DIER_COMDE_BIT)
+#define TIMER_DIER_CC4DE (1U << TIMER_DIER_CC4DE_BIT)
+#define TIMER_DIER_CC3DE (1U << TIMER_DIER_CC3DE_BIT)
+#define TIMER_DIER_CC2DE (1U << TIMER_DIER_CC2DE_BIT)
+#define TIMER_DIER_CC1DE (1U << TIMER_DIER_CC1DE_BIT)
+#define TIMER_DIER_UDE (1U << TIMER_DIER_UDE_BIT)
+#define TIMER_DIER_BIE (1U << TIMER_DIER_BIE_BIT)
+#define TIMER_DIER_TIE (1U << TIMER_DIER_TIE_BIT)
+#define TIMER_DIER_COMIE (1U << TIMER_DIER_COMIE_BIT)
+#define TIMER_DIER_CC4IE (1U << TIMER_DIER_CC4IE_BIT)
+#define TIMER_DIER_CC3IE (1U << TIMER_DIER_CC3IE_BIT)
+#define TIMER_DIER_CC2IE (1U << TIMER_DIER_CC2IE_BIT)
+#define TIMER_DIER_CC1IE (1U << TIMER_DIER_CC1IE_BIT)
+#define TIMER_DIER_UIE (1U << TIMER_DIER_UIE_BIT)
+
+/* Status register (SR) */
+
+#define TIMER_SR_CC4OF_BIT 12
+#define TIMER_SR_CC3OF_BIT 11
+#define TIMER_SR_CC2OF_BIT 10
+#define TIMER_SR_CC1OF_BIT 9
+#define TIMER_SR_BIF_BIT 7
+#define TIMER_SR_TIF_BIT 6
+#define TIMER_SR_COMIF_BIT 5
+#define TIMER_SR_CC4IF_BIT 4
+#define TIMER_SR_CC3IF_BIT 3
+#define TIMER_SR_CC2IF_BIT 2
+#define TIMER_SR_CC1IF_BIT 1
+#define TIMER_SR_UIF_BIT 0
+
+#define TIMER_SR_CC4OF (1U << TIMER_SR_CC4OF_BIT)
+#define TIMER_SR_CC3OF (1U << TIMER_SR_CC3OF_BIT)
+#define TIMER_SR_CC2OF (1U << TIMER_SR_CC2OF_BIT)
+#define TIMER_SR_CC1OF (1U << TIMER_SR_CC1OF_BIT)
+#define TIMER_SR_BIF (1U << TIMER_SR_BIF_BIT)
+#define TIMER_SR_TIF (1U << TIMER_SR_TIF_BIT)
+#define TIMER_SR_COMIF (1U << TIMER_SR_COMIF_BIT)
+#define TIMER_SR_CC4IF (1U << TIMER_SR_CC4IF_BIT)
+#define TIMER_SR_CC3IF (1U << TIMER_SR_CC3IF_BIT)
+#define TIMER_SR_CC2IF (1U << TIMER_SR_CC2IF_BIT)
+#define TIMER_SR_CC1IF (1U << TIMER_SR_CC1IF_BIT)
+#define TIMER_SR_UIF (1U << TIMER_SR_UIF_BIT)
+
+/* Event generation register (EGR) */
+
+#define TIMER_EGR_BG_BIT 7
+#define TIMER_EGR_TG_BIT 6
+#define TIMER_EGR_COMG_BIT 5
+#define TIMER_EGR_CC4G_BIT 4
+#define TIMER_EGR_CC3G_BIT 3
+#define TIMER_EGR_CC2G_BIT 2
+#define TIMER_EGR_CC1G_BIT 1
+#define TIMER_EGR_UG_BIT 0
+
+#define TIMER_EGR_BG (1U << TIMER_EGR_BG_BIT)
+#define TIMER_EGR_TG (1U << TIMER_EGR_TG_BIT)
+#define TIMER_EGR_COMG (1U << TIMER_EGR_COMG_BIT)
+#define TIMER_EGR_CC4G (1U << TIMER_EGR_CC4G_BIT)
+#define TIMER_EGR_CC3G (1U << TIMER_EGR_CC3G_BIT)
+#define TIMER_EGR_CC2G (1U << TIMER_EGR_CC2G_BIT)
+#define TIMER_EGR_CC1G (1U << TIMER_EGR_CC1G_BIT)
+#define TIMER_EGR_UG (1U << TIMER_EGR_UG_BIT)
+
+/* Capture/compare mode registers, common values */
+
+#define TIMER_CCMR_CCS_OUTPUT 0x0
+#define TIMER_CCMR_CCS_INPUT_TI1 0x1
+#define TIMER_CCMR_CCS_INPUT_TI2 0x2
+#define TIMER_CCMR_CCS_INPUT_TRC 0x3
+
+/* Capture/compare mode register 1 (CCMR1) */
+
+#define TIMER_CCMR1_OC2CE_BIT 15
+#define TIMER_CCMR1_OC2PE_BIT 11
+#define TIMER_CCMR1_OC2FE_BIT 10
+#define TIMER_CCMR1_OC1CE_BIT 7
+#define TIMER_CCMR1_OC1PE_BIT 3
+#define TIMER_CCMR1_OC1FE_BIT 2
+
+#define TIMER_CCMR1_OC2CE (1U << TIMER_CCMR1_OC2CE_BIT)
+#define TIMER_CCMR1_OC2M (0x3 << 12)
+#define TIMER_CCMR1_IC2F (0xF << 12)
+#define TIMER_CCMR1_OC2PE (1U << TIMER_CCMR1_OC2PE_BIT)
+#define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT)
+#define TIMER_CCMR1_IC2PSC (0x3 << 10)
+#define TIMER_CCMR1_CC2S (0x3 << 8)
+#define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8)
+#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8)
+#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8)
+#define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8)
+#define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT)
+#define TIMER_CCMR1_OC1M (0x3 << 4)
+#define TIMER_CCMR1_IC1F (0xF << 4)
+#define TIMER_CCMR1_OC1PE (1U << TIMER_CCMR1_OC1PE_BIT)
+#define TIMER_CCMR1_OC1FE (1U << TIMER_CCMR1_OC1FE_BIT)
+#define TIMER_CCMR1_IC1PSC (0x3 << 2)
+#define TIMER_CCMR1_CC1S 0x3
+#define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT
+#define TIMER_CCMR1_CC1S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
+#define TIMER_CCMR1_CC1S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
+#define TIMER_CCMR1_CC1S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
+
+/* Capture/compare mode register 2 (CCMR2) */
+
+#define TIMER_CCMR2_OC4CE_BIT 15
+#define TIMER_CCMR2_OC4PE_BIT 11
+#define TIMER_CCMR2_OC4FE_BIT 10
+#define TIMER_CCMR2_OC3CE_BIT 7
+#define TIMER_CCMR2_OC3PE_BIT 3
+#define TIMER_CCMR2_OC3FE_BIT 2
+
+#define TIMER_CCMR2_OC4CE (1U << TIMER_CCMR2_OC4CE_BIT)
+#define TIMER_CCMR2_OC4M (0x3 << 12)
+#define TIMER_CCMR2_IC4F (0xF << 12)
+#define TIMER_CCMR2_OC4PE (1U << TIMER_CCMR2_OC4PE_BIT)
+#define TIMER_CCMR2_OC4FE (1U << TIMER_CCMR2_OC4FE_BIT)
+#define TIMER_CCMR2_IC4PSC (0x3 << 10)
+#define TIMER_CCMR2_CC4S (0x3 << 8)
+#define TIMER_CCMR2_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8)
+#define TIMER_CCMR2_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8)
+#define TIMER_CCMR2_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8)
+#define TIMER_CCMR2_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8)
+#define TIMER_CCMR2_OC3CE (1U << TIMER_CCMR2_OC3CE_BIT)
+#define TIMER_CCMR2_OC3M (0x3 << 4)
+#define TIMER_CCMR2_IC3F (0xF << 4)
+#define TIMER_CCMR2_OC3PE (1U << TIMER_CCMR2_OC3PE_BIT)
+#define TIMER_CCMR2_OC3FE (1U << TIMER_CCMR2_OC3FE_BIT)
+#define TIMER_CCMR2_IC3PSC (0x3 << 2)
+#define TIMER_CCMR2_CC3S 0x3
+#define TIMER_CCMR2_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT
+#define TIMER_CCMR2_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
+#define TIMER_CCMR2_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
+#define TIMER_CCMR2_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
+
+/* Capture/compare enable register (CCER) */
+
+#define TIMER_CCER_CC4P_BIT 13
+#define TIMER_CCER_CC4E_BIT 12
+#define TIMER_CCER_CC3NP_BIT 11
+#define TIMER_CCER_CC3NE_BIT 10
+#define TIMER_CCER_CC3P_BIT 9
+#define TIMER_CCER_CC3E_BIT 8
+#define TIMER_CCER_CC2NP_BIT 7
+#define TIMER_CCER_CC2NE_BIT 6
+#define TIMER_CCER_CC2P_BIT 5
+#define TIMER_CCER_CC2E_BIT 4
+#define TIMER_CCER_CC1NP_BIT 3
+#define TIMER_CCER_CC1NE_BIT 2
+#define TIMER_CCER_CC1P_BIT 1
+#define TIMER_CCER_CC1E_BIT 0
+
+#define TIMER_CCER_CC4P (1U << TIMER_CCER_CC4P_BIT)
+#define TIMER_CCER_CC4E (1U << TIMER_CCER_CC4E_BIT)
+#define TIMER_CCER_CC3NP (1U << TIMER_CCER_CC3NP_BIT)
+#define TIMER_CCER_CC3NE (1U << TIMER_CCER_CC3NE_BIT)
+#define TIMER_CCER_CC3P (1U << TIMER_CCER_CC3P_BIT)
+#define TIMER_CCER_CC3E (1U << TIMER_CCER_CC3E_BIT)
+#define TIMER_CCER_CC2NP (1U << TIMER_CCER_CC2NP_BIT)
+#define TIMER_CCER_CC2NE (1U << TIMER_CCER_CC2NE_BIT)
+#define TIMER_CCER_CC2P (1U << TIMER_CCER_CC2P_BIT)
+#define TIMER_CCER_CC2E (1U << TIMER_CCER_CC2E_BIT)
+#define TIMER_CCER_CC1NP (1U << TIMER_CCER_CC1NP_BIT)
+#define TIMER_CCER_CC1NE (1U << TIMER_CCER_CC1NE_BIT)
+#define TIMER_CCER_CC1P (1U << TIMER_CCER_CC1P_BIT)
+#define TIMER_CCER_CC1E (1U << TIMER_CCER_CC1E_BIT)
+
+/* Break and dead-time register (BDTR) */
+
+#define TIMER_BDTR_MOE_BIT 15
+#define TIMER_BDTR_AOE_BIT 14
+#define TIMER_BDTR_BKP_BIT 13
+#define TIMER_BDTR_BKE_BIT 12
+#define TIMER_BDTR_OSSR_BIT 11
+#define TIMER_BDTR_OSSI_BIT 10
+
+#define TIMER_BDTR_MOE (1U << TIMER_BDTR_MOE_BIT)
+#define TIMER_BDTR_AOE (1U << TIMER_BDTR_AOE_BIT)
+#define TIMER_BDTR_BKP (1U << TIMER_BDTR_BKP_BIT)
+#define TIMER_BDTR_BKE (1U << TIMER_BDTR_BKE_BIT)
+#define TIMER_BDTR_OSSR (1U << TIMER_BDTR_OSSR_BIT)
+#define TIMER_BDTR_OSSI (1U << TIMER_BDTR_OSSI_BIT)
+#define TIMER_BDTR_LOCK (0x3 << 8)
+#define TIMER_BDTR_LOCK_OFF (0x0 << 8)
+#define TIMER_BDTR_LOCK_LEVEL1 (0x1 << 8)
+#define TIMER_BDTR_LOCK_LEVEL2 (0x2 << 8)
+#define TIMER_BDTR_LOCK_LEVEL3 (0x3 << 8)
+#define TIMER_BDTR_DTG 0xFF
+
+/* DMA control register (DCR) */
+
+#define TIMER_DCR_DBL (0x1F << 8)
+#define TIMER_DCR_DBL_1_XFER (0x0 << 8)
+#define TIMER_DCR_DBL_2_XFER (0x1 << 8)
+#define TIMER_DCR_DBL_3_XFER (0x2 << 8)
+#define TIMER_DCR_DBL_4_XFER (0x3 << 8)
+#define TIMER_DCR_DBL_5_XFER (0x4 << 8)
+#define TIMER_DCR_DBL_6_XFER (0x5 << 8)
+#define TIMER_DCR_DBL_7_XFER (0x6 << 8)
+#define TIMER_DCR_DBL_8_XFER (0x7 << 8)
+#define TIMER_DCR_DBL_9_XFER (0x8 << 8)
+#define TIMER_DCR_DBL_10_XFER (0x9 << 8)
+#define TIMER_DCR_DBL_11_XFER (0xA << 8)
+#define TIMER_DCR_DBL_12_XFER (0xB << 8)
+#define TIMER_DCR_DBL_13_XFER (0xC << 8)
+#define TIMER_DCR_DBL_14_XFER (0xD << 8)
+#define TIMER_DCR_DBL_15_XFER (0xE << 8)
+#define TIMER_DCR_DBL_16_XFER (0xF << 8)
+#define TIMER_DCR_DBL_17_XFER (0x10 << 8)
+#define TIMER_DCR_DBL_18_XFER (0x11 << 8)
+#define TIMER_DCR_DBA 0x1F
+#define TIMER_DCR_DBA_CR1 0x0
+#define TIMER_DCR_DBA_CR2 0x1
+#define TIMER_DCR_DBA_SMCR 0x2
+#define TIMER_DCR_DBA_DIER 0x3
+#define TIMER_DCR_DBA_SR 0x4
+#define TIMER_DCR_DBA_EGR 0x5
+#define TIMER_DCR_DBA_CCMR1 0x6
+#define TIMER_DCR_DBA_CCMR2 0x7
+#define TIMER_DCR_DBA_CCER 0x8
+#define TIMER_DCR_DBA_CNT 0x9
+#define TIMER_DCR_DBA_PSC 0xA
+#define TIMER_DCR_DBA_ARR 0xB
+#define TIMER_DCR_DBA_RCR 0xC
+#define TIMER_DCR_DBA_CCR1 0xD
+#define TIMER_DCR_DBA_CCR2 0xE
+#define TIMER_DCR_DBA_CCR3 0xF
+#define TIMER_DCR_DBA_CCR4 0x10
+#define TIMER_DCR_DBA_BDTR 0x11
+#define TIMER_DCR_DBA_DCR 0x12
+#define TIMER_DCR_DBA_DMAR 0x13
+
+/*
+ * Convenience routines
+ */
+
+/**
+ * @brief Used to configure the behavior of a timer channel.
+ *
+ * Be careful: not all timers can be configured in every mode.
+ */
+typedef enum timer_mode {
+ /**
+ * The timer stops counting, channel interrupts are detached, and
+ * no state changes are output. */
+ TIMER_DISABLED,
+
+ /** PWM output. */
+ TIMER_PWM,
+
+ /* TIMER_PWM_CENTER_ALIGNED, TODO: Center-aligned PWM output 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. */
+ TIMER_OUTPUT_COMPARE,
+
+ /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the
+ * pulse lengths of input signals */
+ /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single
+ * pulse on a GPIO pin for a specified amount of
+ * time. */
+} timer_mode;
+
+/** Timer channel numbers */
+typedef enum timer_channel {
+ TIMER_CH1 = 1, /**< Channel 1 */
+ TIMER_CH2 = 2, /**< Channel 2 */
+ TIMER_CH3 = 3, /**< Channel 3 */
+ TIMER_CH4 = 4 /**< Channel 4 */
+} timer_channel;
+
+/*
+ * Note: Don't require timer_channel arguments! We want to be able to say
+ *
+ * for (int channel = 1; channel <= 4; channel++) {
+ * ...
+ * }
+ *
+ * without the compiler yelling at us.
+ */
+
+void timer_init(timer_dev *dev);
+void timer_disable(timer_dev *dev);
+void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode);
+void timer_foreach(void (*fn)(timer_dev*));
+int timer_has_cc_channel(timer_dev *dev, uint8 channel);
+
+/**
+ * @brief Timer interrupt number.
+ *
+ * Not all timers support all of these values. All timers support
+ * TIMER_UPDATE_INTERRUPT. "General purpose" timers can be a special
+ * nuisance in this regard, as they individually support different
+ * subsets of the available interupts. Consult your target's reference
+ * manual for the details.
+ */
+typedef enum timer_interrupt_id {
+ TIMER_UPDATE_INTERRUPT, /**< Update interrupt. */
+ TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt. */
+ TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt. */
+ TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt. */
+ TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt. */
+ TIMER_COM_INTERRUPT, /**< COM interrupt. */
+ TIMER_TRG_INTERRUPT, /**< Trigger interrupt. */
+ TIMER_BREAK_INTERRUPT, /**< Break interrupt. */
+} timer_interrupt_id;
+
+void timer_attach_interrupt(timer_dev *dev,
+ uint8 interrupt,
+ voidFuncPtr handler);
+void timer_detach_interrupt(timer_dev *dev, uint8 interrupt);
+
+/**
+ * Initialize all timer devices on the chip.
+ */
+static inline void timer_init_all(void) {
+ timer_foreach(timer_init);
+}
+
+/**
+ * Disables all timers on the device.
+ */
+static inline void timer_disable_all(void) {
+ timer_foreach(timer_disable);
+}
+
+/**
+ * @brief Stop a timer's counter from changing.
+ *
+ * Does not affect the timer's mode or other settings.
+ *
+ * @param dev Device whose counter to pause.
+ */
+static inline void timer_pause(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 0;
+}
+
+/**
+ * @brief Start a timer's counter.
+ *
+ * Does not affect the timer's mode or other settings.
+ *
+ * @param dev Device whose counter to resume
+ */
+static inline void timer_resume(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1;
+}
+
+/**
+ * @brief Returns the timer's counter value.
+ *
+ * This value is likely to be inaccurate if the counter is running
+ * with a low prescaler.
+ *
+ * @param dev Timer whose counter to return
+ */
+static inline uint16 timer_get_count(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->CNT;
+}
+
+/**
+ * @brief Sets the counter value for the given timer.
+ * @param dev Timer whose counter to set
+ * @param value New counter value
+ */
+static inline void timer_set_count(timer_dev *dev, uint16 value) {
+ (dev->regs).bas->CNT = value;
+}
+
+/**
+ * @brief Returns the given timer's prescaler.
+ *
+ * Note that if the timer's prescaler is set (e.g. via
+ * timer_set_prescaler() or accessing a TIMx_PSC register), the value
+ * returned by this function will reflect the new setting, but the
+ * timer's counter will only reflect the new prescaler at the next
+ * update event.
+ *
+ * @param dev Timer whose prescaler to return
+ * @see timer_generate_update()
+ */
+static inline uint16 timer_get_prescaler(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->PSC;
+}
+
+/**
+ * @brief Set a timer's prescale value.
+ *
+ * Divides the input clock by (PSC+1). The new value will not take
+ * effect until the next update event.
+ *
+ * @param dev Timer whose prescaler to set
+ * @param psc New prescaler value
+ * @see timer_generate_update()
+ */
+static inline void timer_set_prescaler(timer_dev *dev, uint16 psc) {
+ (dev->regs).bas->PSC = psc;
+}
+
+/**
+ * @brief Returns a timer's reload value.
+ * @param dev Timer whose reload value to return
+ */
+static inline uint16 timer_get_reload(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->ARR;
+}
+
+/**
+ * @brief Set a timer's reload value.
+ * @param dev Timer whose reload value to set
+ * @param arr New reload value to use. Takes effect at next update event.
+ * @see timer_generate_update()
+ */
+static inline void timer_set_reload(timer_dev *dev, uint16 arr) {
+ (dev->regs).bas->ARR = arr;
+}
+
+/**
+ * @brief Get the compare value for the given timer channel.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose compare value to get.
+ */
+static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) {
+ __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
+ return *ccr;
+}
+
+/**
+ * @brief Set the compare value for the given timer channel.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose compare value to set.
+ * @param value New compare value.
+ */
+static inline void timer_set_compare(timer_dev *dev,
+ uint8 channel,
+ uint16 value) {
+ __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
+ *ccr = value;
+}
+
+/**
+ * @brief Generate an update event for the given timer.
+ *
+ * Normally, this will cause the prescaler and auto-reload values in
+ * the PSC and ARR registers to take immediate effect. However, this
+ * function will do nothing if the UDIS bit is set in the timer's CR1
+ * register (UDIS is cleared by default).
+ *
+ * @param dev Timer device to generate an update for.
+ */
+static inline void timer_generate_update(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->EGR, TIMER_EGR_UG_BIT) = 1;
+}
+
+/**
+ * @brief Enable a timer's trigger DMA request
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ */
+static inline void timer_dma_enable_trg_req(timer_dev *dev) {
+ *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 1;
+}
+
+/**
+ * @brief Disable a timer's trigger DMA request
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ */
+static inline void timer_dma_disable_trg_req(timer_dev *dev) {
+ *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 0;
+}
+
+/**
+ * @brief Enable a timer channel's DMA request.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ * @param channel Channel whose DMA request to enable.
+ */
+static inline void timer_dma_enable_req(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 1;
+}
+
+/**
+ * @brief Disable a timer channel's DMA request.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose DMA request to disable.
+ */
+static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 0;
+}
+
+/**
+ * @brief Enable a timer interrupt.
+ * @param dev Timer device.
+ * @param interrupt Interrupt number to enable; this may be any
+ * timer_interrupt_id value appropriate for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) {
+ *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1;
+}
+
+/**
+ * @brief Disable a timer interrupt.
+ * @param dev Timer device.
+ * @param interrupt Interrupt number to disable; this may be any
+ * timer_interrupt_id value appropriate for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+static inline void timer_disable_irq(timer_dev *dev, uint8 interrupt) {
+ *bb_perip(&(dev->regs).adv->DIER, interrupt) = 0;
+}
+
+/**
+ * @brief Enable a timer channel's capture/compare signal.
+ *
+ * If the channel is configured as output, the corresponding output
+ * compare signal will be output on the corresponding output pin. If
+ * the channel is configured as input, enables capture of the counter
+ * value into the input capture/compare register.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to enable, from 1 to 4.
+ */
+static inline void timer_cc_enable(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 1;
+}
+
+/**
+ * @brief Disable a timer channel's output compare or input capture signal.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to disable, from 1 to 4.
+ * @see timer_cc_enable()
+ */
+static inline void timer_cc_disable(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 0;
+}
+
+/**
+ * @brief Get a channel's capture/compare output polarity
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose capture/compare output polarity to get.
+ * @return Polarity, either 0 or 1.
+ * @see timer_cc_set_polarity()
+ */
+static inline uint8 timer_cc_get_pol(timer_dev *dev, uint8 channel) {
+ return *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1);
+}
+
+/**
+ * @brief Set a timer channel's capture/compare output polarity.
+ *
+ * If the timer channel is configured as output: polarity == 0 means
+ * the output channel will be active high; polarity == 1 means active
+ * low.
+ *
+ * If the timer channel is configured as input: polarity == 0 means
+ * capture is done on the rising edge of ICn; when used as an external
+ * trigger, ICn is non-inverted. polarity == 1 means capture is done
+ * on the falling edge of ICn; when used as an external trigger, ICn
+ * is inverted.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose capture/compare output polarity to set.
+ * @param pol New polarity, 0 or 1.
+ */
+static inline void timer_cc_set_pol(timer_dev *dev, uint8 channel, uint8 pol) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1) = pol;
+}
+
+/**
+ * @brief Get a timer's DMA burst length.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @return Number of transfers per read or write to timer DMA register,
+ * from 1 to 18.
+ */
+static inline uint8 timer_dma_get_burst_len(timer_dev *dev) {
+ uint32 dbl = ((dev->regs).gen->DCR & TIMER_DCR_DBL) >> 8;
+ return dbl + 1; /* 0 means 1 transfer, etc. */
+}
+
+/**
+ * @brief Set a timer's DMA burst length.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param length DMA burst length; i.e., number of DMA transfers per
+ * read/write to timer DMA register, from 1 to 18.
+ */
+static inline void timer_dma_set_burst_len(timer_dev *dev, uint8 length) {
+ uint32 tmp = (dev->regs).gen->DCR;
+ tmp &= ~TIMER_DCR_DBL;
+ tmp |= (length - 1) << 8;
+ (dev->regs).gen->DCR = tmp;
+}
+
+/**
+ * @brief Timer DMA base address.
+ *
+ * Defines the base address for DMA transfers.
+ */
+typedef enum timer_dma_base_addr {
+ /** Base is control register 1 */
+ TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1,
+ /** Base is control register 2 */
+ TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2,
+ /** Base is slave mode control register */
+ TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR,
+ /** Base is DMA interrupt enable register */
+ TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER,
+ /** Base is status register */
+ TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR,
+ /** Base is event generation register */
+ TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR,
+ /** Base is capture/compare mode register 1 */
+ TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1,
+ /** Base is capture/compare mode register 2 */
+ TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2,
+ /** Base is capture/compare enable register */
+ TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER,
+ /** Base is counter */
+ TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT,
+ /** Base is prescaler */
+ TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC,
+ /** Base is auto-reload register */
+ TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR,
+ /** Base is repetition counter register */
+ TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR,
+ /** Base is capture/compare register 1 */
+ TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1,
+ /** Base is capture/compare register 2 */
+ TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2,
+ /** Base is capture/compare register 3 */
+ TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3,
+ /** Base is capture/compare register 4 */
+ TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4,
+ /** Base is break and dead-time register */
+ TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR,
+ /** Base is DMA control register */
+ TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR,
+ /** Base is DMA address for full transfer */
+ TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR,
+} timer_dma_base_addr;
+
+/**
+ * @brief Get the timer's DMA base address.
+ *
+ * Some restrictions apply; see the reference manual for your chip.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @return DMA base address
+ */
+static inline timer_dma_base_addr timer_dma_get_base_addr(timer_dev *dev) {
+ uint32 dcr = (dev->regs).gen->DCR;
+ return (timer_dma_base_addr)(dcr & TIMER_DCR_DBA);
+}
+
+/**
+ * @brief Set the timer's DMA base address.
+ *
+ * Some restrictions apply; see the reference manual for your chip.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param dma_base DMA base address.
+ */
+static inline void timer_dma_set_base_addr(timer_dev *dev,
+ timer_dma_base_addr dma_base) {
+ uint32 tmp = (dev->regs).gen->DCR;
+ tmp &= ~TIMER_DCR_DBA;
+ tmp |= dma_base;
+ (dev->regs).gen->DCR = tmp;
+}
+
+/**
+ * Timer output compare modes.
+ */
+typedef enum timer_oc_mode {
+ /**
+ * Frozen: comparison between output compare register and counter
+ * has no effect on the outputs. */
+ TIMER_OC_MODE_FROZEN = 0 << 4,
+ /**
+ * OCxREF signal is forced high when the count matches the channel
+ * capture/compare register. */
+ TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4,
+ /**
+ * OCxREF signal is forced low when the counter matches the
+ * channel capture/compare register. */
+ TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4,
+ /**
+ * OCxREF toggles when counter matches the channel capture/compare
+ * register. */
+ TIMER_OC_MODE_TOGGLE = 3 << 4,
+ /** OCxREF is forced low. */
+ TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4,
+ /** OCxREF is forced high. */
+ TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4,
+ /**
+ * PWM mode 1. In upcounting, channel is active as long as count
+ * is less than channel capture/compare register, else inactive.
+ * In downcounting, channel is inactive as long as count exceeds
+ * capture/compare register, else active. */
+ TIMER_OC_MODE_PWM_1 = 6 << 4,
+ /**
+ * PWM mode 2. In upcounting, channel is inactive as long as count
+ * is less than capture/compare register, else active. In
+ * downcounting, channel is active as long as count exceeds
+ * capture/compare register, else inactive. */
+ TIMER_OC_MODE_PWM_2 = 7 << 4,
+} timer_oc_mode;
+
+/**
+ * Timer output compare mode flags.
+ * @see timer_oc_set_mode()
+ */
+typedef enum timer_oc_mode_flags {
+ TIMER_OC_CE = 1U << 7, /**< Output compare clear enable. */
+ TIMER_OC_PE = 1U << 3, /**< Output compare preload enable. */
+ TIMER_OC_FE = 1U << 2, /**< Output compare fast enable. */
+} timer_oc_mode_flags;
+
+/**
+ * @brief Configure a channel's output compare mode.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to configure in output compare mode.
+ * @param mode Timer mode to set.
+ * @param flags OR of timer_oc_mode_flags.
+ * @see timer_oc_mode
+ * @see timer_oc_mode_flags
+ */
+static inline void timer_oc_set_mode(timer_dev *dev,
+ uint8 channel,
+ timer_oc_mode mode,
+ uint8 flags) {
+ /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */
+ __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1);
+ /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */
+ uint8 shift = 8 * (1 - (channel & 1));
+
+ uint32 tmp = *ccmr;
+ tmp &= ~(0xFF << shift);
+ tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift;
+ *ccmr = tmp;
+}
+
+/*
+ * Old, erroneous bit definitions from previous releases, kept for
+ * backwards compatibility:
+ */
+
+/** Deprecated. Use TIMER_CCMR1_CC4S_OUTPUT instead. */
+#define TIMER_CCMR1_CC4S_OUTPUT TIMER_CCMR2_CC4S_OUTPUT
+/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI1 instead. */
+#define TIMER_CCMR1_CC4S_INPUT_TI1 TIMER_CCMR2_CC4S_INPUT_TI1
+/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI2 instead. */
+#define TIMER_CCMR1_CC4S_INPUT_TI2 TIMER_CCMR2_CC4S_INPUT_TI2
+/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TRC instead. */
+#define TIMER_CCMR1_CC4S_INPUT_TRC TIMER_CCMR2_CC4S_INPUT_TRC
+/** Deprecated. Use TIMER_CCMR2_IC4F instead. */
+#define TIMER_CCMR2_IC2F TIMER_CCMR2_IC4F
+/** Deprecated. Use TIMER_CCMR2_IC4PSC instead. */
+#define TIMER_CCMR2_IC2PSC TIMER_CCMR2_IC4PSC
+/** Deprecated. Use TIMER_CCMR2_IC3F instead. */
+#define TIMER_CCMR2_IC1F TIMER_CCMR2_IC3F
+/** Deprecated. Use TIMER_CCMR2_IC3PSC instead. */
+#define TIMER_CCMR2_IC1PSC TIMER_CCMR2_IC3PSC
+/** Deprecated. Use TIMER_CCMR1_CC3S_OUTPUT instead. */
+#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR2_CC3S_OUTPUT
+/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI1 instead. */
+#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR2_CC3S_INPUT_TI1
+/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI2 instead. */
+#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR2_CC3S_INPUT_TI2
+/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TRC instead. */
+#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR2_CC3S_INPUT_TRC
+
+/** Deprecated. Use TIMER_DCR_DBL_1_XFER instead. */
+#define TIMER_DCR_DBL_1BYTE TIMER_DCR_DBL_1_XFER
+/** Deprecated. Use TIMER_DCR_DBL_2_XFER instead. */
+#define TIMER_DCR_DBL_2BYTE TIMER_DCR_DBL_2_XFER
+/** Deprecated. Use TIMER_DCR_DBL_3_XFER instead. */
+#define TIMER_DCR_DBL_3BYTE TIMER_DCR_DBL_3_XFER
+/** Deprecated. Use TIMER_DCR_DBL_4_XFER instead. */
+#define TIMER_DCR_DBL_4BYTE TIMER_DCR_DBL_4_XFER
+/** Deprecated. Use TIMER_DCR_DBL_5_XFER instead. */
+#define TIMER_DCR_DBL_5BYTE TIMER_DCR_DBL_5_XFER
+/** Deprecated. Use TIMER_DCR_DBL_6_XFER instead. */
+#define TIMER_DCR_DBL_6BYTE TIMER_DCR_DBL_6_XFER
+/** Deprecated. Use TIMER_DCR_DBL_7_XFER instead. */
+#define TIMER_DCR_DBL_7BYTE TIMER_DCR_DBL_7_XFER
+/** Deprecated. Use TIMER_DCR_DBL_8_XFER instead. */
+#define TIMER_DCR_DBL_8BYTE TIMER_DCR_DBL_8_XFER
+/** Deprecated. Use TIMER_DCR_DBL_9_XFER instead. */
+#define TIMER_DCR_DBL_9BYTE TIMER_DCR_DBL_9_XFER
+/** Deprecated. Use TIMER_DCR_DBL_10_XFER instead. */
+#define TIMER_DCR_DBL_10BYTE TIMER_DCR_DBL_10_XFER
+/** Deprecated. Use TIMER_DCR_DBL_11_XFER instead. */
+#define TIMER_DCR_DBL_11BYTE TIMER_DCR_DBL_11_XFER
+/** Deprecated. Use TIMER_DCR_DBL_12_XFER instead. */
+#define TIMER_DCR_DBL_12BYTE TIMER_DCR_DBL_12_XFER
+/** Deprecated. Use TIMER_DCR_DBL_13_XFER instead. */
+#define TIMER_DCR_DBL_13BYTE TIMER_DCR_DBL_13_XFER
+/** Deprecated. Use TIMER_DCR_DBL_14_XFER instead. */
+#define TIMER_DCR_DBL_14BYTE TIMER_DCR_DBL_14_XFER
+/** Deprecated. Use TIMER_DCR_DBL_15_XFER instead. */
+#define TIMER_DCR_DBL_15BYTE TIMER_DCR_DBL_15_XFER
+/** Deprecated. Use TIMER_DCR_DBL_16_XFER instead. */
+#define TIMER_DCR_DBL_16BYTE TIMER_DCR_DBL_16_XFER
+/** Deprecated. Use TIMER_DCR_DBL_17_XFER instead. */
+#define TIMER_DCR_DBL_17BYTE TIMER_DCR_DBL_17_XFER
+/** Deprecated. Use TIMER_DCR_DBL_18_XFER instead. */
+#define TIMER_DCR_DBL_18BYTE TIMER_DCR_DBL_18_XFER
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/usart.h b/libmaple/include/libmaple/usart.h
new file mode 100644
index 0000000..26a64d3
--- /dev/null
+++ b/libmaple/include/libmaple/usart.h
@@ -0,0 +1,495 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/usart.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief USART definitions and prototypes
+ */
+
+#ifndef _LIBMAPLE_USART_H_
+#define _LIBMAPLE_USART_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
+#include <libmaple/rcc.h>
+#include <libmaple/nvic.h>
+#include <libmaple/ring_buffer.h>
+#include <series/usart.h>
+
+/*
+ * Register map (common across supported STM32 series).
+ */
+
+/** USART register map type */
+typedef struct usart_reg_map {
+ __io uint32 SR; /**< Status register */
+ __io uint32 DR; /**< Data register */
+ __io uint32 BRR; /**< Baud rate register */
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 CR3; /**< Control register 3 */
+ __io uint32 GTPR; /**< Guard time and prescaler register */
+} usart_reg_map;
+
+/*
+ * Register bit definitions
+ */
+
+/* Status register */
+
+/** Clear to send bit */
+#define USART_SR_CTS_BIT 9
+/** Line break detection bit */
+#define USART_SR_LBD_BIT 8
+/** Transmit data register empty bit */
+#define USART_SR_TXE_BIT 7
+/** Transmission complete bit */
+#define USART_SR_TC_BIT 6
+/** Read data register not empty bit */
+#define USART_SR_RXNE_BIT 5
+/** IDLE line detected bit */
+#define USART_SR_IDLE_BIT 4
+/** Overrun error bit */
+#define USART_SR_ORE_BIT 3
+/** Noise error bit */
+#define USART_SR_NE_BIT 2
+/**
+ * @brief Synonym for USART_SR_NE_BIT.
+ *
+ * Some series (e.g. STM32F2) use "NF" for "noise flag" instead of the
+ * original "NE" for "noise error". The meaning of the bit is
+ * unchanged, but the NF flag can be disabled when the line is
+ * noise-free.
+ *
+ * @see USART_SR_NE_BIT
+ */
+#define USART_SR_NF_BIT USART_SR_NE_BIT
+/** Framing error bit */
+#define USART_SR_FE_BIT 1
+/** Parity error bit */
+#define USART_SR_PE_BIT 0
+
+/** Clear to send mask */
+#define USART_SR_CTS BIT(USART_SR_CTS_BIT)
+/** Line break detected mask */
+#define USART_SR_LBD BIT(USART_SR_LBD_BIT)
+/** Transmit data register empty mask */
+#define USART_SR_TXE BIT(USART_SR_TXE_BIT)
+/** Transmission complete mask */
+#define USART_SR_TC BIT(USART_SR_TC_BIT)
+/** Read data register not empty mask */
+#define USART_SR_RXNE BIT(USART_SR_RXNE_BIT)
+/** IDLE line detected mask */
+#define USART_SR_IDLE BIT(USART_SR_IDLE_BIT)
+/** Overrun error mask */
+#define USART_SR_ORE BIT(USART_SR_ORE_BIT)
+/** Noise error mask */
+#define USART_SR_NE BIT(USART_SR_NE_BIT)
+/**
+ * @brief Synonym for USART_SR_NE.
+ * @see USART_SR_NF_BIT
+ */
+#define USART_SR_NF USART_SR_NE
+/** Framing error mask */
+#define USART_SR_FE BIT(USART_SR_FE_BIT)
+/** Parity error mask */
+#define USART_SR_PE BIT(USART_SR_PE_BIT)
+
+/* Data register */
+
+/** Data register data value mask */
+#define USART_DR_DR 0xFF
+
+/* Baud rate register */
+
+/** Mantissa of USARTDIV mask */
+#define USART_BRR_DIV_MANTISSA (0xFFF << 4)
+/** Fraction of USARTDIV mask */
+#define USART_BRR_DIV_FRACTION 0xF
+
+/* Control register 1 */
+
+/** USART enable bit */
+#define USART_CR1_UE_BIT 13
+/** Word length bit */
+#define USART_CR1_M_BIT 12
+/** Wakeup method bit */
+#define USART_CR1_WAKE_BIT 11
+/** Parity control enable bit */
+#define USART_CR1_PCE_BIT 10
+/** Parity selection bit */
+#define USART_CR1_PS_BIT 9
+/** Parity error interrupt enable bit */
+#define USART_CR1_PEIE_BIT 8
+/** Transmit data regsiter not empty interrupt enable bit */
+#define USART_CR1_TXEIE_BIT 7
+/** Transmission complete interrupt enable bit */
+#define USART_CR1_TCIE_BIT 6
+/** RXNE interrupt enable bit */
+#define USART_CR1_RXNEIE_BIT 5
+/** IDLE interrupt enable bit */
+#define USART_CR1_IDLEIE_BIT 4
+/** Transmitter enable bit */
+#define USART_CR1_TE_BIT 3
+/** Receiver enable bit */
+#define USART_CR1_RE_BIT 2
+/** Receiver wakeup bit */
+#define USART_CR1_RWU_BIT 1
+/** Send break bit */
+#define USART_CR1_SBK_BIT 0
+
+/** USART enable mask */
+#define USART_CR1_UE BIT(USART_CR1_UE_BIT)
+/** Word length mask */
+#define USART_CR1_M BIT(USART_CR1_M_BIT)
+/** Word length: 1 start bit, 8 data bits, n stop bit */
+#define USART_CR1_M_8N1 (0 << USART_CR1_M_BIT)
+/** Word length: 1 start bit, 9 data bits, n stop bit */
+#define USART_CR1_M_9N1 (1 << USART_CR1_M_BIT)
+/** Wakeup method mask */
+#define USART_CR1_WAKE BIT(USART_CR1_WAKE_BIT)
+/** Wakeup on idle line */
+#define USART_CR1_WAKE_IDLE (0 << USART_CR1_WAKE_BIT)
+/** Wakeup on address mark */
+#define USART_CR1_WAKE_ADDR (1 << USART_CR1_WAKE_BIT)
+/** Parity control enable mask */
+#define USART_CR1_PCE BIT(USART_CR1_PCE_BIT)
+/** Parity selection mask */
+#define USART_CR1_PS BIT(USART_CR1_PS_BIT)
+/** Parity selection: even parity */
+#define USART_CR1_PS_EVEN (0 << USART_CR1_PS_BIT)
+/** Parity selection: odd parity */
+#define USART_CR1_PS_ODD (1 << USART_CR1_PS_BIT)
+/** Parity error interrupt enable mask */
+#define USART_CR1_PEIE BIT(USART_CR1_PEIE_BIT)
+/** Transmit data register empty interrupt enable mask */
+#define USART_CR1_TXEIE BIT(USART_CR1_TXEIE_BIT)
+/** Transmission complete interrupt enable mask */
+#define USART_CR1_TCIE BIT(USART_CR1_TCIE_BIT)
+/** RXNE interrupt enable mask */
+#define USART_CR1_RXNEIE BIT(USART_CR1_RXNEIE_BIT)
+/** IDLE line interrupt enable mask */
+#define USART_CR1_IDLEIE BIT(USART_CR1_IDLEIE_BIT)
+/** Transmitter enable mask */
+#define USART_CR1_TE BIT(USART_CR1_TE_BIT)
+/** Receiver enable mask */
+#define USART_CR1_RE BIT(USART_CR1_RE_BIT)
+/** Receiver wakeup mask */
+#define USART_CR1_RWU BIT(USART_CR1_RWU_BIT)
+/** Receiver wakeup: receiver in active mode */
+#define USART_CR1_RWU_ACTIVE (0 << USART_CR1_RWU_BIT)
+/** Receiver wakeup: receiver in mute mode */
+#define USART_CR1_RWU_MUTE (1 << USART_CR1_RWU_BIT)
+/** Send break */
+#define USART_CR1_SBK BIT(USART_CR1_SBK_BIT)
+
+/* Control register 2 */
+
+/** LIN mode enable bit */
+#define USART_CR2_LINEN_BIT 14
+/** Clock enable bit */
+#define USART_CR2_CLKEN_BIT 11
+/** Clock polarity bit */
+#define USART_CR2_CPOL_BIT 10
+/** Clock phase bit */
+#define USART_CR2_CPHA_BIT 9
+/** Last bit clock pulse bit */
+#define USART_CR2_LBCL_BIT 8
+/** LIN break detection interrupt enable bit */
+#define USART_CR2_LBDIE_BIT 6
+/** LIN break detection length bit */
+#define USART_CR2_LBDL_BIT 5
+
+/** LIN mode enable mask */
+#define USART_CR2_LINEN BIT(USART_CR2_LINEN_BIT)
+/** STOP bits mask */
+#define USART_CR2_STOP (0x3 << 12)
+/** STOP bits: 1 stop bit */
+#define USART_CR2_STOP_BITS_1 (0x0 << 12)
+/**
+ * @brief STOP bits: 0.5 stop bits
+ * Not available on UART4, UART5. */
+#define USART_CR2_STOP_BITS_POINT_5 (0x1 << 12)
+/** STOP bits: 2 stop bits */
+#define USART_CR2_STOP_BITS_2 (0x2 << 12)
+/**
+ * @brief STOP bits: 1.5 stop bits
+ * Not available on UART4, UART5. */
+#define USART_CR2_STOP_BITS_1_POINT_5 (0x3 << 12)
+/**
+ * @brief Clock enable.
+ * Not available on UART4, UART5 */
+#define USART_CR2_CLKEN BIT(USART_CR2_CLKEN_BIT)
+/**
+ * @brief Clock polarity mask.
+ * Not available on UART4, UART5 */
+#define USART_CR2_CPOL BIT(USART_CR2_CPOL_BIT)
+/** Clock polarity: low */
+#define USART_CR2_CPOL_LOW (0x0 << USART_CR2_CLKEN_BIT)
+/** Clock polarity: high */
+#define USART_CR2_CPOL_HIGH (0x1 << USART_CR2_CLKEN_BIT)
+/**
+ * @brief Clock phase mask.
+ * Not available on UART4, UART5 */
+#define USART_CR2_CPHA BIT(USART_CR2_CPHA_BIT)
+/**
+ * @brief Clock phase: first
+ * First clock transition is the first data capture edge. */
+#define USART_CR2_CPHA_FIRST (0x0 << USART_CR2_CPHA_BIT)
+/**
+ * @brief Clock phase: second
+ * Second clock transition is the first data capture edge. */
+#define USART_CR2_CPHA_SECOND (0x1 << USART_CR2_CPHA_BIT)
+/**
+ * @brief Last bit clock pulse mask.
+ *
+ * When set, the last bit transmitted causes a clock pulse in
+ * synchronous mode.
+ *
+ * Not available on UART4, UART5 */
+#define USART_CR2_LBCL BIT(USART_CR2_LBCL_BIT)
+/** LIN break detection interrupt enable mask. */
+#define USART_CR2_LBDIE BIT(USART_CR2_LBDIE_BIT)
+/** LIN break detection length. */
+#define USART_CR2_LBDL BIT(USART_CR2_LBDL_BIT)
+/** LIN break detection length: 10 bits */
+#define USART_CR2_LBDL_10_BIT (0 << USART_CR2_LBDL_BIT)
+/** LIN break detection length: 11 bits */
+#define USART_CR2_LBDL_11_BIT (1 << USART_CR2_LBDL_BIT)
+/**
+ * @brief Address of the USART node
+ * This is useful during multiprocessor communication. */
+#define USART_CR2_ADD 0xF
+
+/* Control register 3 */
+
+/** Clear to send interrupt enable bit */
+#define USART_CR3_CTSIE_BIT 10
+/** Clear to send enable bit */
+#define USART_CR3_CTSE_BIT 9
+/** Ready to send enable bit */
+#define USART_CR3_RTSE_BIT 8
+/** DMA enable transmitter bit */
+#define USART_CR3_DMAT_BIT 7
+/** DMA enable receiver bit */
+#define USART_CR3_DMAR_BIT 6
+/** Smartcard mode enable bit */
+#define USART_CR3_SCEN_BIT 5
+/** Smartcard NACK enable bit */
+#define USART_CR3_NACK_BIT 4
+/** Half-duplex selection bit */
+#define USART_CR3_HDSEL_BIT 3
+/** IrDA low power bit */
+#define USART_CR3_IRLP_BIT 2
+/** IrDA mode enable bit */
+#define USART_CR3_IREN_BIT 1
+/** Error interrupt enable bit */
+#define USART_CR3_EIE_BIT 0
+
+/**
+ * @brief Clear to send interrupt enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_CTSIE BIT(USART_CR3_CTSIE_BIT)
+/**
+ * @brief Clear to send enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_CTSE BIT(USART_CR3_CTSE_BIT)
+/**
+ * @brief Ready to send enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_RTSE BIT(USART_CR3_RTSE_BIT)
+/**
+ * @brief DMA enable transmitter
+ * Not available on UART5. */
+#define USART_CR3_DMAT BIT(USART_CR3_DMAT_BIT)
+/**
+ * @brief DMA enable receiver
+ * Not available on UART5. */
+#define USART_CR3_DMAR BIT(USART_CR3_DMAR_BIT)
+/**
+ * @brief Smartcard mode enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_SCEN BIT(USART_CR3_SCEN_BIT)
+/**
+ * @brief Smartcard NACK enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_NACK BIT(USART_CR3_NACK_BIT)
+/**
+ * @brief Half-duplex selection
+ * When set, single-wire half duplex mode is selected.
+ */
+#define USART_CR3_HDSEL BIT(USART_CR3_HDSEL_BIT)
+/** IrDA low power mode */
+#define USART_CR3_IRLP BIT(USART_CR3_IRLP_BIT)
+/** IrDA mode: normal */
+#define USART_CR3_IRLP_NORMAL (0U << USART_CR3_IRLP_BIT)
+/** IrDA mode: low power */
+#define USART_CR3_IRLP_LOW_POWER (1U << USART_CR3_IRLP_BIT)
+/** IrDA mode enable */
+#define USART_CR3_IREN BIT(USART_CR3_IREN_BIT)
+/** Error interrupt enable */
+#define USART_CR3_EIE BIT(USART_CR3_EIE_BIT)
+
+/* Guard time and prescaler register */
+
+/**
+ * @brief Guard time value mask
+ * Used in Smartcard mode. Not available on UART4, UART5. */
+#define USART_GTPR_GT (0xFF << 8)
+/**
+ * @brief Prescaler value mask
+ * Restrictions on this value apply, depending on the USART mode. Not
+ * available on UART4, UART5. */
+#define USART_GTPR_PSC 0xFF
+
+/*
+ * Devices
+ */
+
+#ifndef USART_RX_BUF_SIZE
+#define USART_RX_BUF_SIZE 64
+#endif
+
+/** USART device type */
+typedef struct usart_dev {
+ usart_reg_map *regs; /**< Register map */
+ ring_buffer *rb; /**< RX ring buffer */
+ uint32 max_baud; /**< @brief Deprecated.
+ * Maximum baud rate. */
+ uint8 rx_buf[USART_RX_BUF_SIZE]; /**< @brief Deprecated.
+ * Actual RX buffer used by rb.
+ * This field will be removed in
+ * a future release. */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ nvic_irq_num irq_num; /**< USART NVIC interrupt */
+} usart_dev;
+
+void usart_init(usart_dev *dev);
+
+struct gpio_dev; /* forward declaration */
+/* FIXME [PRE 0.0.13] decide if flags are necessary */
+/**
+ * @brief Configure GPIOs for use as USART TX/RX.
+ * @param udev USART device to use
+ * @param rx_dev RX pin gpio_dev
+ * @param rx RX pin bit on rx_dev
+ * @param tx_dev TX pin gpio_dev
+ * @param tx TX pin bit on tx_dev
+ * @param flags Currently ignored
+ */
+extern void usart_config_gpios_async(usart_dev *udev,
+ struct gpio_dev *rx_dev, uint8 rx,
+ struct gpio_dev *tx_dev, uint8 tx,
+ unsigned flags);
+
+#define USART_USE_PCLK 0
+void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud);
+
+void usart_enable(usart_dev *dev);
+void usart_disable(usart_dev *dev);
+void usart_foreach(void (*fn)(usart_dev *dev));
+uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len);
+uint32 usart_rx(usart_dev *dev, uint8 *buf, uint32 len);
+void usart_putudec(usart_dev *dev, uint32 val);
+
+/**
+ * @brief Disable all serial ports.
+ */
+static inline void usart_disable_all(void) {
+ usart_foreach(usart_disable);
+}
+
+/**
+ * @brief Transmit one character on a serial port.
+ *
+ * This function blocks until the character has been successfully
+ * transmitted.
+ *
+ * @param dev Serial port to send on.
+ * @param byte Byte to transmit.
+ */
+static inline void usart_putc(usart_dev* dev, uint8 byte) {
+ while (!usart_tx(dev, &byte, 1))
+ ;
+}
+
+/**
+ * @brief Transmit a character string on a serial port.
+ *
+ * This function blocks until str is completely transmitted.
+ *
+ * @param dev Serial port to send on
+ * @param str String to send
+ */
+static inline void usart_putstr(usart_dev *dev, const char* str) {
+ uint32 i = 0;
+ while (str[i] != '\0') {
+ usart_putc(dev, str[i++]);
+ }
+}
+
+/**
+ * @brief Read one character from a serial port.
+ *
+ * It's not safe to call this function if the serial port has no data
+ * available.
+ *
+ * @param dev Serial port to read from
+ * @return byte read
+ * @see usart_data_available()
+ */
+static inline uint8 usart_getc(usart_dev *dev) {
+ return rb_remove(dev->rb);
+}
+
+/**
+ * @brief Return the amount of data available in a serial port's RX buffer.
+ * @param dev Serial port to check
+ * @return Number of bytes in dev's RX buffer.
+ */
+static inline uint32 usart_data_available(usart_dev *dev) {
+ return rb_full_count(dev->rb);
+}
+
+/**
+ * @brief Discard the contents of a serial port's RX buffer.
+ * @param dev Serial port whose buffer to empty.
+ */
+static inline void usart_reset_rx(usart_dev *dev) {
+ rb_reset(dev->rb);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/usb.h b/libmaple/include/libmaple/usb.h
new file mode 100644
index 0000000..ea24030
--- /dev/null
+++ b/libmaple/include/libmaple/usb.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, 2011, 2012 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.
+ *****************************************************************************/
+
+/*
+ * NOTE: This API is _unstable_ and will change drastically over time.
+ */
+
+#ifndef _LIBMAPLE_USB_H_
+#define _LIBMAPLE_USB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+
+/*
+ * Descriptors and other paraphernalia
+ */
+
+/* Descriptor types */
+
+#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
+#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
+#define USB_DESCRIPTOR_TYPE_STRING 0x03
+#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
+#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
+
+/* Descriptor structs and declaration helpers */
+
+#define USB_DESCRIPTOR_STRING_LEN(x) (2 + (x << 1))
+
+#define USB_DESCRIPTOR_STRING(len) \
+ struct { \
+ uint8 bLength; \
+ uint8 bDescriptorType; \
+ uint16 bString[len]; \
+ } __packed
+
+typedef struct usb_descriptor_device {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint16 bcdUSB;
+ uint8 bDeviceClass;
+ uint8 bDeviceSubClass;
+ uint8 bDeviceProtocol;
+ uint8 bMaxPacketSize0;
+ uint16 idVendor;
+ uint16 idProduct;
+ uint16 bcdDevice;
+ uint8 iManufacturer;
+ uint8 iProduct;
+ uint8 iSerialNumber;
+ uint8 bNumConfigurations;
+} __packed usb_descriptor_device;
+
+typedef struct usb_descriptor_config_header {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint16 wTotalLength;
+ uint8 bNumInterfaces;
+ uint8 bConfigurationValue;
+ uint8 iConfiguration;
+ uint8 bmAttributes;
+ uint8 bMaxPower;
+} __packed usb_descriptor_config_header;
+
+typedef struct usb_descriptor_interface {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint8 bInterfaceNumber;
+ uint8 bAlternateSetting;
+ uint8 bNumEndpoints;
+ uint8 bInterfaceClass;
+ uint8 bInterfaceSubClass;
+ uint8 bInterfaceProtocol;
+ uint8 iInterface;
+} __packed usb_descriptor_interface;
+
+typedef struct usb_descriptor_endpoint {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint8 bEndpointAddress;
+ uint8 bmAttributes;
+ uint16 wMaxPacketSize;
+ uint8 bInterval;
+} __packed usb_descriptor_endpoint;
+
+typedef struct usb_descriptor_string {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint8 bString[];
+} usb_descriptor_string;
+
+/* Common values that go inside descriptors */
+
+#define USB_CONFIG_ATTR_BUSPOWERED 0b10000000
+#define USB_CONFIG_ATTR_SELF_POWERED 0b11000000
+
+#define USB_EP_TYPE_INTERRUPT 0x03
+#define USB_EP_TYPE_BULK 0x02
+
+#define USB_DESCRIPTOR_ENDPOINT_IN 0x80
+#define USB_DESCRIPTOR_ENDPOINT_OUT 0x00
+
+/*
+ * USB module core
+ */
+
+#ifndef USB_ISR_MSK
+/* Handle CTRM, WKUPM, SUSPM, ERRM, SOFM, ESOFM, RESETM */
+#define USB_ISR_MSK 0xBF00
+#endif
+
+typedef enum usb_dev_state {
+ USB_UNCONNECTED,
+ USB_ATTACHED,
+ USB_POWERED,
+ USB_SUSPENDED,
+ USB_ADDRESSED,
+ USB_CONFIGURED
+} usb_dev_state;
+
+/* Encapsulates global state formerly handled by usb_lib/ */
+typedef struct usblib_dev {
+ uint32 irq_mask;
+ void (**ep_int_in)(void);
+ void (**ep_int_out)(void);
+ usb_dev_state state;
+ usb_dev_state prevState;
+ rcc_clk_id clk_id;
+} usblib_dev;
+
+extern usblib_dev *USBLIB;
+
+void usb_init_usblib(usblib_dev *dev,
+ void (**ep_int_in)(void),
+ void (**ep_int_out)(void));
+
+static inline uint8 usb_is_connected(usblib_dev *dev) {
+ return dev->state != USB_UNCONNECTED;
+}
+
+static inline uint8 usb_is_configured(usblib_dev *dev) {
+ return dev->state == USB_CONFIGURED;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/usb_cdcacm.h b/libmaple/include/libmaple/usb_cdcacm.h
new file mode 100644
index 0000000..5fe832c
--- /dev/null
+++ b/libmaple/include/libmaple/usb_cdcacm.h
@@ -0,0 +1,179 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/usb_cdcacm.h
+ * @brief USB CDC ACM (virtual serial terminal) support
+ *
+ * IMPORTANT: this API is unstable, and may change without notice.
+ */
+
+#ifndef _LIBMAPLE_USB_CDCACM_H_
+#define _LIBMAPLE_USB_CDCACM_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/gpio.h>
+#include <libmaple/usb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * CDC ACM Requests
+ */
+
+#define USB_CDCACM_SET_LINE_CODING 0x20
+#define USB_CDCACM_GET_LINE_CODING 0x21
+#define USB_CDCACM_SET_COMM_FEATURE 0x02
+#define USB_CDCACM_SET_CONTROL_LINE_STATE 0x22
+#define USB_CDCACM_CONTROL_LINE_DTR (0x01)
+#define USB_CDCACM_CONTROL_LINE_RTS (0x02)
+
+/*
+ * Descriptors, etc.
+ */
+
+#define CDC_FUNCTIONAL_DESCRIPTOR_SIZE(DataSize) (3 + DataSize)
+#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \
+ struct { \
+ uint8 bLength; \
+ uint8 bDescriptorType; \
+ uint8 SubType; \
+ uint8 Data[DataSize]; \
+ } __packed
+
+#define USB_DEVICE_CLASS_CDC 0x02
+#define USB_DEVICE_SUBCLASS_CDC 0x00
+#define USB_INTERFACE_CLASS_CDC 0x02
+#define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02
+#define USB_INTERFACE_CLASS_DIC 0x0A
+
+/*
+ * Endpoint configuration
+ */
+
+#define USB_CDCACM_CTRL_ENDP 0
+#define USB_CDCACM_CTRL_RX_ADDR 0x40
+#define USB_CDCACM_CTRL_TX_ADDR 0x80
+#define USB_CDCACM_CTRL_EPSIZE 0x40
+
+#define USB_CDCACM_TX_ENDP 1
+#define USB_CDCACM_TX_ADDR 0xC0
+#define USB_CDCACM_TX_EPSIZE 0x40
+
+#define USB_CDCACM_MANAGEMENT_ENDP 2
+#define USB_CDCACM_MANAGEMENT_ADDR 0x100
+#define USB_CDCACM_MANAGEMENT_EPSIZE 0x40
+
+#define USB_CDCACM_RX_ENDP 3
+#define USB_CDCACM_RX_ADDR 0x110
+#define USB_CDCACM_RX_EPSIZE 0x40
+
+#ifndef __cplusplus
+#define USB_CDCACM_DECLARE_DEV_DESC(vid, pid) \
+ { \
+ .bLength = sizeof(usb_descriptor_device), \
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, \
+ .bcdUSB = 0x0200, \
+ .bDeviceClass = USB_DEVICE_CLASS_CDC, \
+ .bDeviceSubClass = USB_DEVICE_SUBCLASS_CDC, \
+ .bDeviceProtocol = 0x00, \
+ .bMaxPacketSize0 = 0x40, \
+ .idVendor = vid, \
+ .idProduct = pid, \
+ .bcdDevice = 0x0200, \
+ .iManufacturer = 0x01, \
+ .iProduct = 0x02, \
+ .iSerialNumber = 0x00, \
+ .bNumConfigurations = 0x01, \
+ }
+#endif
+
+/*
+ * CDC ACM interface
+ */
+
+void usb_cdcacm_enable(gpio_dev*, uint8);
+void usb_cdcacm_disable(gpio_dev*, uint8);
+
+void usb_cdcacm_putc(char ch);
+uint32 usb_cdcacm_tx(const uint8* buf, uint32 len);
+uint32 usb_cdcacm_rx(uint8* buf, uint32 len);
+uint32 usb_cdcacm_peek(uint8* buf, uint32 len);
+
+uint32 usb_cdcacm_data_available(void); /* in RX buffer */
+uint16 usb_cdcacm_get_pending(void);
+uint8 usb_cdcacm_is_transmitting(void);
+
+uint8 usb_cdcacm_get_dtr(void);
+uint8 usb_cdcacm_get_rts(void);
+
+typedef struct usb_cdcacm_line_coding {
+ uint32 dwDTERate; /* Baud rate */
+
+#define USB_CDCACM_STOP_BITS_1 0
+#define USB_CDCACM_STOP_BITS_1_5 1
+#define USB_CDCACM_STOP_BITS_2 2
+ uint8 bCharFormat; /* Stop bits */
+
+#define USB_CDCACM_PARITY_NONE 0
+#define USB_CDCACM_PARITY_ODD 1
+#define USB_CDCACM_PARITY_EVEN 2
+#define USB_CDCACM_PARITY_MARK 3
+#define USB_CDCACM_PARITY_SPACE 4
+ uint8 bParityType; /* Parity type */
+
+ uint8 bDataBits; /* Data bits: 5, 6, 7, 8, or 16 */
+} __packed usb_cdcacm_line_coding;
+
+/* Retrieve a copy of the current line coding structure. */
+void usb_cdcacm_get_line_coding(usb_cdcacm_line_coding*);
+
+/* Line coding conveniences. */
+int usb_cdcacm_get_baud(void); /* dwDTERate */
+int usb_cdcacm_get_stop_bits(void); /* bCharFormat */
+int usb_cdcacm_get_parity(void); /* bParityType */
+int usb_cdcacm_get_n_data_bits(void); /* bDataBits */
+
+/*
+ * Hack: hooks for bootloader reset signalling
+ */
+
+#define USB_CDCACM_HOOK_RX 0x1
+#define USB_CDCACM_HOOK_IFACE_SETUP 0x2
+
+void usb_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*));
+
+static __always_inline void usb_cdcacm_remove_hooks(unsigned hook_flags) {
+ usb_cdcacm_set_hooks(hook_flags, 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/util.h b/libmaple/include/libmaple/util.h
new file mode 100644
index 0000000..5a70348
--- /dev/null
+++ b/libmaple/include/libmaple/util.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/include/libmaple/util.h
+ * @brief Miscellaneous utility macros and procedures.
+ */
+
+#ifndef _LIBMAPLE_UTIL_H_
+#define _LIBMAPLE_UTIL_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Bit manipulation
+ */
+
+/** 1UL shifted left by 'shift' */
+#define BIT(shift) (1UL << (shift))
+/** 'Mask' shifted left by 'shift' */
+#define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift))
+/** Bits m to n of x */
+#define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m)))
+/** True iff v is a power of two (1, 2, 4, 8, ...) */
+#define IS_POWER_OF_TWO(v) ((v) && !((v) & ((v) - 1)))
+
+/*
+ * Failure routines
+ */
+
+void __error(void);
+void _fail(const char*, int, const char*);
+void throb(void);
+
+/*
+ * Asserts and debug levels
+ */
+
+#define DEBUG_NONE 0
+#define DEBUG_FAULT 1
+#define DEBUG_ALL 2
+
+/**
+ * \def DEBUG_LEVEL
+ *
+ * Controls the level of assertion checking.
+ *
+ * The higher the debug level, the more assertions will be compiled
+ * in. This increases the amount of debugging information, but slows
+ * down (and increases the size of) the binary.
+ *
+ * The debug levels, from lowest to highest, are DEBUG_NONE,
+ * DEBUG_FAULT, and DEBUG_ALL. The default level is DEBUG_ALL.
+ */
+
+#ifndef DEBUG_LEVEL
+#define DEBUG_LEVEL DEBUG_ALL
+#endif
+
+#if DEBUG_LEVEL >= DEBUG_ALL
+#define ASSERT(exp) \
+ if (exp) { \
+ } else { \
+ _fail(__FILE__, __LINE__, #exp); \
+ }
+#else
+#define ASSERT(exp) (void)((0))
+#endif
+
+#if DEBUG_LEVEL >= DEBUG_FAULT
+#define ASSERT_FAULT(exp) \
+ if (exp) { \
+ } else { \
+ _fail(__FILE__, __LINE__, #exp); \
+ }
+#else
+#define ASSERT_FAULT(exp) (void)((0))
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/iwdg.c b/libmaple/iwdg.c
new file mode 100644
index 0000000..2456235
--- /dev/null
+++ b/libmaple/iwdg.c
@@ -0,0 +1,62 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/iwdg.c
+ * @brief Independent watchdog (IWDG) support
+ */
+
+#include <libmaple/iwdg.h>
+
+/**
+ * @brief Initialise and start the watchdog
+ *
+ * The prescaler and reload set the timeout. For example, a prescaler
+ * of IWDG_PRE_32 divides the 40 kHz clock by 32 and gives roughly 1
+ * ms per reload.
+ *
+ * @param prescaler Prescaler for the 40 kHz IWDG clock.
+ * @param reload Independent watchdog counter reload value.
+ */
+void iwdg_init(iwdg_prescaler prescaler, uint16 reload) {
+ IWDG_BASE->KR = IWDG_KR_UNLOCK;
+ IWDG_BASE->PR = prescaler;
+ IWDG_BASE->RLR = reload;
+
+ /* Start things off */
+ IWDG_BASE->KR = IWDG_KR_START;
+ iwdg_feed();
+}
+
+/**
+ * @brief Reset the IWDG counter.
+ *
+ * Calling this function will cause the IWDG counter to be reset to
+ * its reload value.
+ */
+void iwdg_feed(void) {
+ IWDG_BASE->KR = IWDG_KR_FEED;
+}
diff --git a/libmaple/nvic.c b/libmaple/nvic.c
new file mode 100644
index 0000000..149e780
--- /dev/null
+++ b/libmaple/nvic.c
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/nvic.c
+ * @brief Nested vector interrupt controller support.
+ */
+
+#include <libmaple/nvic.h>
+#include <libmaple/scb.h>
+#include <libmaple/stm32.h>
+
+/**
+ * @brief Set interrupt priority for an interrupt line
+ *
+ * Note: The STM32 only implements 4 bits of priority, ignoring the
+ * lower 4 bits. This means there are only 16 levels of priority.
+ * Bits[3:0] read as zero and ignore writes.
+ *
+ * @param irqn device to set
+ * @param priority Priority to set, 0 being highest priority and 15
+ * being lowest.
+ */
+void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) {
+ if (irqn < 0) {
+ /* This interrupt is in the system handler block */
+ SCB_BASE->SHP[((uint32)irqn & 0xF) - 4] = (priority & 0xF) << 4;
+ } else {
+ NVIC_BASE->IP[irqn] = (priority & 0xF) << 4;
+ }
+}
+
+/**
+ * @brief Initialize the NVIC, setting interrupts to a default priority.
+ */
+void nvic_init(uint32 address, uint32 offset) {
+ uint32 i;
+
+ nvic_set_vector_table(address, offset);
+
+ /*
+ * Lower priority level for all peripheral interrupts to lowest
+ * possible.
+ */
+ for (i = 0; i < STM32_NR_INTERRUPTS; i++) {
+ nvic_irq_set_priority((nvic_irq_num)i, 0xF);
+ }
+
+ /* Lower systick interrupt priority to lowest level */
+ nvic_irq_set_priority(NVIC_SYSTICK, 0xF);
+}
+
+/**
+ * @brief Set the vector table base address.
+ *
+ * For stand-alone products, the vector table base address is normally
+ * the start of Flash (0x08000000).
+ *
+ * @param address Vector table base address.
+ * @param offset Offset from address. Some restrictions apply to the
+ * use of nonzero offsets; see the ARM Cortex M3
+ * Technical Reference Manual.
+ */
+void nvic_set_vector_table(uint32 address, uint32 offset) {
+ SCB_BASE->VTOR = address | (offset & 0x1FFFFF80);
+}
+
+/**
+ * @brief Force a system reset.
+ *
+ * Resets all major system components, excluding debug.
+ */
+void nvic_sys_reset() {
+ uint32 prigroup = SCB_BASE->AIRCR & SCB_AIRCR_PRIGROUP;
+ SCB_BASE->AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ | prigroup;
+ asm volatile("dsb");
+ while (1)
+ ;
+}
diff --git a/libmaple/pwr.c b/libmaple/pwr.c
new file mode 100644
index 0000000..3cf170f
--- /dev/null
+++ b/libmaple/pwr.c
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/pwr.c
+ * @brief Power control (PWR) support.
+ */
+
+#include <libmaple/pwr.h>
+#include <libmaple/rcc.h>
+
+/**
+ * Enables the power interface clock, and resets the power device.
+ */
+void pwr_init(void) {
+ rcc_clk_enable(RCC_PWR);
+ rcc_reset_dev(RCC_PWR);
+}
diff --git a/libmaple/rcc.c b/libmaple/rcc.c
new file mode 100644
index 0000000..8e7d1ea
--- /dev/null
+++ b/libmaple/rcc.c
@@ -0,0 +1,169 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/rcc.c
+ * @brief Portable RCC routines.
+ */
+
+#include <libmaple/rcc.h>
+
+#include "rcc_private.h"
+
+/**
+ * @brief Get a peripheral's clock domain
+ * @param id Clock ID of the peripheral whose clock domain to return
+ * @return Clock source for the given clock ID
+ */
+rcc_clk_domain rcc_dev_clk(rcc_clk_id id) {
+ return rcc_dev_table[id].clk_domain;
+}
+
+/**
+ * @brief Switch the clock used as the source of the system clock.
+ *
+ * After switching the source, this function blocks until the new
+ * clock source is in use.
+ *
+ * @param sysclk_src New system clock source.
+ * @see rcc_sysclk_src
+ */
+void rcc_switch_sysclk(rcc_sysclk_src sysclk_src) {
+ uint32 cfgr = RCC_BASE->CFGR;
+ cfgr &= ~RCC_CFGR_SW;
+ cfgr |= sysclk_src;
+
+ /* Switch SYSCLK source. */
+ RCC_BASE->CFGR = cfgr;
+
+ /* Wait for new source to come into use. */
+ while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != (sysclk_src << 2))
+ ;
+}
+
+/*
+ * Turning clocks off and on, querying their status.
+ */
+
+/* IMPORTANT NOTE FOR IMPLEMENTORS:
+ *
+ * libmaple assumes that enum rcc_clk enumerators are two-byte
+ * values, stored in a uint16, in the following way:
+ *
+ * - The high-order byte is the byte offset (from RCC_BASE) of the register
+ * to touch when turning on or off the given clock.
+ *
+ * - The low-order byte is the bit in that register that turns the
+ * clock on or off.
+ *
+ * Example for STM32F1: Turning on the high-speed external clock (HSE)
+ * involves setting HSEON, bit 16, of RCC_CR. The high-order byte is
+ * then offsetof(struct rcc_reg_map, CR) = 0, and the low-order byte
+ * is 16.
+ *
+ * The corresponding value of RCC_CLK_HSE is thus (0 << 8) | 16 = 16.
+ *
+ * On all known STM32 series, this encoding has the property that
+ * adding one to the low byte also gives the bit to check to determine
+ * if the clock is ready. For example, on STM32F1, RCC_CR_HSERDY is
+ * bit 17. If that's not the case on your series, rcc_is_clk_ready()
+ * won't work for you. */
+
+/* Returns the RCC register which controls the clock source. */
+static inline __io uint32* rcc_clk_reg(rcc_clk clock) {
+ return (__io uint32*)((__io uint8*)RCC_BASE + (clock >> 8));
+}
+
+/* Returns a mask in rcc_clk_reg(clock) to be used for turning the
+ * clock on and off */
+static inline uint32 rcc_clk_on_mask(rcc_clk clock) {
+ return 1 << (clock & 0xFF);
+}
+
+/* Returns a mask in rcc_clk_reg(clock) to be used when checking the
+ * readiness of the clock. */
+static inline uint32 rcc_clk_ready_mask(rcc_clk clock) {
+ return rcc_clk_on_mask(clock) << 1;
+}
+
+/**
+ * @brief Turn on a clock source.
+ *
+ * After this routine exits, callers should ensure that the clock
+ * source is ready by waiting until rcc_is_clk_ready(clock) returns
+ * true.
+ *
+ * @param clock Clock to turn on.
+ * @see rcc_turn_off_clk()
+ * @see rcc_is_clk_ready()
+ */
+void rcc_turn_on_clk(rcc_clk clock) {
+ *rcc_clk_reg(clock) |= rcc_clk_on_mask(clock);
+}
+
+/**
+ * @brief Turn off a clock source.
+ *
+ * In certain configurations, certain clock sources cannot be safely
+ * turned off. (For example, the main PLL on STM32F1 devices cannot be
+ * turned off if it has been selected as the SYSCLK source). Consult
+ * the reference material for your MCU to ensure it is safe to call
+ * this function.
+ *
+ * @param clock Clock to turn off.
+ * @see rcc_turn_on_clk()
+ * @see rcc_is_clk_ready()
+ */
+void rcc_turn_off_clk(rcc_clk clock) {
+ *rcc_clk_reg(clock) &= ~rcc_clk_on_mask(clock);
+}
+
+/**
+ * @brief Check if a clock is on.
+ * @param clock Clock to check.
+ * @return 1 if the clock is on, 0 if the clock is off.
+ */
+int rcc_is_clk_on(rcc_clk clock) {
+ return !!(*rcc_clk_reg(clock) & rcc_clk_on_mask(clock));
+}
+
+/**
+ * @brief Check if a clock source is ready.
+ *
+ * In general, it is not safe to rely on a clock source unless this
+ * function returns nonzero. Also note that this function may return
+ * nonzero for a short period of time after a clock has been turned
+ * off. Consult the reference material for your MCU for more details.
+ *
+ * @param clock Clock whose readiness to check for.
+ * @return Nonzero if the clock is ready, zero otherwise.
+ * @see rcc_turn_on_clk()
+ * @see rcc_turn_off_clk()
+ */
+int rcc_is_clk_ready(rcc_clk clock) {
+ return (int)(*rcc_clk_reg(clock) & rcc_clk_ready_mask(clock));
+}
diff --git a/libmaple/rcc_private.h b/libmaple/rcc_private.h
new file mode 100644
index 0000000..66eaf00
--- /dev/null
+++ b/libmaple/rcc_private.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/*
+ * RCC private header.
+ */
+
+#ifndef _LIBMAPLE_PRIVATE_RCC_H_
+#define _LIBMAPLE_PRIVATE_RCC_H_
+
+#include <libmaple/bitband.h>
+
+struct rcc_dev_info {
+ const rcc_clk_domain clk_domain;
+ const uint8 line_num;
+};
+
+extern const struct rcc_dev_info rcc_dev_table[];
+
+static inline void rcc_do_clk_enable(__io uint32** enable_regs,
+ rcc_clk_id id) {
+ __io uint32 *enable_reg = enable_regs[rcc_dev_clk(id)];
+ uint8 line_num = rcc_dev_table[id].line_num;
+ bb_peri_set_bit(enable_reg, line_num, 1);
+}
+
+static inline void rcc_do_reset_dev(__io uint32** reset_regs,
+ rcc_clk_id id) {
+ __io uint32 *reset_reg = reset_regs[rcc_dev_clk(id)];
+ uint8 line_num = rcc_dev_table[id].line_num;
+ bb_peri_set_bit(reset_reg, line_num, 1);
+ bb_peri_set_bit(reset_reg, line_num, 0);
+}
+
+static inline void rcc_do_set_prescaler(const uint32 *masks,
+ rcc_prescaler prescaler,
+ uint32 divider) {
+ uint32 cfgr = RCC_BASE->CFGR;
+ cfgr &= ~masks[prescaler];
+ cfgr |= divider;
+ RCC_BASE->CFGR = cfgr;
+}
+
+#endif
diff --git a/libmaple/rules.mk b/libmaple/rules.mk
new file mode 100644
index 0000000..71979f0
--- /dev/null
+++ b/libmaple/rules.mk
@@ -0,0 +1,50 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH)/include -I$(LIBMAPLE_MODULE_SERIES)/include
+LIBMAPLE_PRIVATE_INCLUDES := -I$(LIBMAPLE_PATH)
+
+# Local flags
+CFLAGS_$(d) = $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror
+
+# Local rules and targets
+cSRCS_$(d) := adc.c
+cSRCS_$(d) += dac.c
+cSRCS_$(d) += dma.c
+cSRCS_$(d) += exti.c
+cSRCS_$(d) += flash.c
+cSRCS_$(d) += gpio.c
+cSRCS_$(d) += iwdg.c
+cSRCS_$(d) += nvic.c
+cSRCS_$(d) += pwr.c
+cSRCS_$(d) += rcc.c
+cSRCS_$(d) += spi.c
+cSRCS_$(d) += systick.c
+cSRCS_$(d) += timer.c
+cSRCS_$(d) += usart.c
+cSRCS_$(d) += usart_private.c
+cSRCS_$(d) += util.c
+sSRCS_$(d) := exc.S
+# I2C support must be ported to F2:
+ifeq ($(MCU_SERIES),stm32f1)
+cSRCS_$(d) += i2c.c
+endif
+
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+$(OBJS_$(d)): TGT_ASFLAGS :=
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp))
diff --git a/libmaple/spi.c b/libmaple/spi.c
new file mode 100644
index 0000000..194a82e
--- /dev/null
+++ b/libmaple/spi.c
@@ -0,0 +1,164 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/spi.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Serial Peripheral Interface (SPI) support.
+ * Currently, there is no Integrated Interchip Sound (I2S) support.
+ */
+
+#include <libmaple/spi.h>
+#include <libmaple/bitband.h>
+
+static void spi_reconfigure(spi_dev *dev, uint32 cr1_config);
+
+/*
+ * SPI convenience routines
+ */
+
+/**
+ * @brief Initialize and reset a SPI device.
+ * @param dev Device to initialize and reset.
+ */
+void spi_init(spi_dev *dev) {
+ rcc_clk_enable(dev->clk_id);
+ rcc_reset_dev(dev->clk_id);
+}
+
+/**
+ * @brief Configure and enable a SPI device as bus master.
+ *
+ * The device's peripheral will be disabled before being reconfigured.
+ *
+ * @param dev Device to configure as bus master
+ * @param baud Bus baud rate
+ * @param mode SPI mode
+ * @param flags Logical OR of spi_cfg_flag values.
+ * @see spi_cfg_flag
+ */
+void spi_master_enable(spi_dev *dev,
+ spi_baud_rate baud,
+ spi_mode mode,
+ uint32 flags) {
+ spi_reconfigure(dev, baud | flags | SPI_CR1_MSTR | mode);
+}
+
+/**
+ * @brief Configure and enable a SPI device as a bus slave.
+ *
+ * The device's peripheral will be disabled before being reconfigured.
+ *
+ * @param dev Device to configure as a bus slave
+ * @param mode SPI mode
+ * @param flags Logical OR of spi_cfg_flag values.
+ * @see spi_cfg_flag
+ */
+void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) {
+ spi_reconfigure(dev, flags | mode);
+}
+
+/**
+ * @brief Nonblocking SPI transmit.
+ * @param dev SPI port to use for transmission
+ * @param buf Buffer to transmit. The sizeof buf's elements are
+ * inferred from dev's data frame format (i.e., are
+ * correctly treated as 8-bit or 16-bit quantities).
+ * @param len Maximum number of elements to transmit.
+ * @return Number of elements transmitted.
+ */
+uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) {
+ uint32 txed = 0;
+ uint8 byte_frame = spi_dff(dev) == SPI_DFF_8_BIT;
+ while (spi_is_tx_empty(dev) && (txed < len)) {
+ if (byte_frame) {
+ dev->regs->DR = ((const uint8*)buf)[txed++];
+ } else {
+ dev->regs->DR = ((const uint16*)buf)[txed++];
+ }
+ }
+ return txed;
+}
+
+/**
+ * @brief Enable a SPI peripheral
+ * @param dev Device to enable
+ */
+void spi_peripheral_enable(spi_dev *dev) {
+ bb_peri_set_bit(&dev->regs->CR1, SPI_CR1_SPE_BIT, 1);
+}
+
+/**
+ * @brief Disable a SPI peripheral
+ * @param dev Device to disable
+ */
+void spi_peripheral_disable(spi_dev *dev) {
+ bb_peri_set_bit(&dev->regs->CR1, SPI_CR1_SPE_BIT, 0);
+}
+
+/**
+ * @brief Enable DMA requests whenever the transmit buffer is empty
+ * @param dev SPI device on which to enable TX DMA requests
+ */
+void spi_tx_dma_enable(spi_dev *dev) {
+ bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_TXDMAEN_BIT, 1);
+}
+
+/**
+ * @brief Disable DMA requests whenever the transmit buffer is empty
+ * @param dev SPI device on which to disable TX DMA requests
+ */
+void spi_tx_dma_disable(spi_dev *dev) {
+ bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_TXDMAEN_BIT, 0);
+}
+
+/**
+ * @brief Enable DMA requests whenever the receive buffer is empty
+ * @param dev SPI device on which to enable RX DMA requests
+ */
+void spi_rx_dma_enable(spi_dev *dev) {
+ bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_RXDMAEN_BIT, 1);
+}
+
+/**
+ * @brief Disable DMA requests whenever the receive buffer is empty
+ * @param dev SPI device on which to disable RX DMA requests
+ */
+void spi_rx_dma_disable(spi_dev *dev) {
+ bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_RXDMAEN_BIT, 0);
+}
+
+/*
+ * SPI auxiliary routines
+ */
+
+static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) {
+ spi_irq_disable(dev, SPI_INTERRUPTS_ALL);
+ spi_peripheral_disable(dev);
+ dev->regs->CR1 = cr1_config;
+ spi_peripheral_enable(dev);
+}
diff --git a/libmaple/spi_private.h b/libmaple/spi_private.h
new file mode 100644
index 0000000..f0e0bd1
--- /dev/null
+++ b/libmaple/spi_private.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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 _LIBMAPLE_SPI_PRIVATE_H_
+#define _LIBMAPLE_SPI_PRIVATE_H_
+
+#define SPI_DEV(num) \
+ { \
+ .regs = SPI##num##_BASE, \
+ .clk_id = RCC_SPI##num, \
+ .irq_num = NVIC_SPI##num, \
+ }
+
+#endif
diff --git a/libmaple/stm32_private.h b/libmaple/stm32_private.h
new file mode 100644
index 0000000..427417a
--- /dev/null
+++ b/libmaple/stm32_private.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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 _LIBMAPLE_STM32_PRIVATE_H_
+#define _LIBMAPLE_STM32_PRIVATE_H_
+
+typedef enum stm32_mem_block_purpose {
+ STM32_BLOCK_CODE,
+ STM32_BLOCK_SRAM,
+ STM32_BLOCK_PERIPH,
+ STM32_BLOCK_FSMC_1_2,
+ STM32_BLOCK_FSMC_3_4,
+ STM32_BLOCK_FSMC_REG,
+ STM32_BLOCK_UNUSED,
+ STM32_BLOCK_CORTEX_INTERNAL,
+} stm32_mem_block_purpose;
+
+static inline stm32_mem_block_purpose stm32_block_purpose(void *addr) {
+ return (stm32_mem_block_purpose)((unsigned)addr >> 29);
+}
+
+#endif
diff --git a/libmaple/stm32f1/adc.c b/libmaple/stm32f1/adc.c
new file mode 100644
index 0000000..6409c37
--- /dev/null
+++ b/libmaple/stm32f1/adc.c
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/adc.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief STM32F1 ADC support.
+ */
+
+#include <libmaple/adc.h>
+#include <libmaple/gpio.h>
+
+/*
+ * Devices
+ */
+
+static adc_dev adc1 = {
+ .regs = ADC1_BASE,
+ .clk_id = RCC_ADC1,
+};
+/** ADC1 device. */
+const adc_dev *ADC1 = &adc1;
+
+static adc_dev adc2 = {
+ .regs = ADC2_BASE,
+ .clk_id = RCC_ADC2,
+};
+/** ADC2 device. */
+const adc_dev *ADC2 = &adc2;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static adc_dev adc3 = {
+ .regs = ADC3_BASE,
+ .clk_id = RCC_ADC3,
+};
+/** ADC3 device. */
+const adc_dev *ADC3 = &adc3;
+#endif
+
+/*
+ * STM32F1 routines
+ */
+
+/**
+ * @brief Calibrate an ADC peripheral
+ *
+ * Availability: STM32F1.
+ *
+ * @param dev adc device
+ */
+void adc_calibrate(const adc_dev *dev) {
+ __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3);
+ __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2);
+
+ *rstcal_bit = 1;
+ while (*rstcal_bit)
+ ;
+
+ *cal_bit = 1;
+ while (*cal_bit)
+ ;
+}
+
+/*
+ * Common routines
+ */
+
+void adc_set_prescaler(adc_prescaler pre) {
+ rcc_set_prescaler(RCC_PRESCALER_ADC, (uint32)pre);
+}
+
+void adc_foreach(void (*fn)(const adc_dev*)) {
+ fn(ADC1);
+ fn(ADC2);
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ fn(ADC3);
+#endif
+}
+
+void adc_config_gpio(const adc_dev *ignored, gpio_dev *gdev, uint8 bit) {
+ gpio_set_mode(gdev, bit, GPIO_INPUT_ANALOG);
+}
+
+void adc_enable_single_swstart(const adc_dev *dev) {
+ adc_init(dev);
+ adc_set_extsel(dev, ADC_SWSTART);
+ adc_set_exttrig(dev, 1);
+ adc_enable(dev);
+ adc_calibrate(dev);
+}
diff --git a/libmaple/stm32f1/bkp.c b/libmaple/stm32f1/bkp.c
new file mode 100644
index 0000000..01ad419
--- /dev/null
+++ b/libmaple/stm32f1/bkp.c
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/bkp.c
+ * @brief STM32F1 Backup register support.
+ */
+
+#include <libmaple/bkp.h>
+#include <libmaple/pwr.h>
+#include <libmaple/rcc.h>
+#include <libmaple/bitband.h>
+
+static inline __io uint32* data_register(uint8 reg);
+
+bkp_dev bkp = {
+ .regs = BKP_BASE,
+};
+/** Backup device. */
+const bkp_dev *BKP = &bkp;
+
+/**
+ * @brief Initialize backup interface.
+ *
+ * Enables the power and backup interface clocks, and resets the
+ * backup device.
+ */
+void bkp_init(void) {
+ /* Don't call pwr_init(), or you'll reset the device. We just
+ * need the clock. */
+ rcc_clk_enable(RCC_PWR);
+ rcc_clk_enable(RCC_BKP);
+ rcc_reset_dev(RCC_BKP);
+}
+
+/**
+ * Enable write access to the backup registers. Backup interface must
+ * be initialized for subsequent register writes to work.
+ * @see bkp_init()
+ */
+void bkp_enable_writes(void) {
+ *bb_perip(&PWR_BASE->CR, PWR_CR_DBP_BIT) = 1;
+}
+
+/**
+ * Disable write access to the backup registers.
+ */
+void bkp_disable_writes(void) {
+ *bb_perip(&PWR_BASE->CR, PWR_CR_DBP_BIT) = 0;
+}
+
+/**
+ * Read a value from given backup data register.
+ * @param reg Data register to read, from 1 to BKP_NR_DATA_REGS (10 on
+ * medium-density devices, 42 on high-density devices).
+ */
+uint16 bkp_read(uint8 reg) {
+ __io uint32* dr = data_register(reg);
+ if (!dr) {
+ ASSERT(0); /* nonexistent register */
+ return 0;
+ }
+ return (uint16)*dr;
+}
+
+/**
+ * @brief Write a value to given data register.
+ *
+ * Write access to backup registers must be enabled.
+ *
+ * @param reg Data register to write, from 1 to BKP_NR_DATA_REGS (10
+ * on medium-density devices, 42 on high-density devices).
+ * @param val Value to write into the register.
+ * @see bkp_enable_writes()
+ */
+void bkp_write(uint8 reg, uint16 val) {
+ __io uint32* dr = data_register(reg);
+ if (!dr) {
+ ASSERT(0); /* nonexistent register */
+ return;
+ }
+ *dr = (uint32)val;
+}
+
+/*
+ * Data register memory layout is not contiguous. It's split up from
+ * 1--NR_LOW_DRS, beginning at BKP_BASE->DR1, through to
+ * (NR_LOW_DRS+1)--BKP_NR_DATA_REGS, beginning at BKP_BASE->DR11.
+ */
+#define NR_LOW_DRS 10
+
+static inline __io uint32* data_register(uint8 reg) {
+ if (reg < 1 || reg > BKP_NR_DATA_REGS) {
+ return 0;
+ }
+
+#if BKP_NR_DATA_REGS == NR_LOW_DRS
+ return (uint32*)BKP_BASE + reg;
+#else
+ if (reg <= NR_LOW_DRS) {
+ return (uint32*)BKP_BASE + reg;
+ } else {
+ return (uint32*)&(BKP_BASE->DR11) + (reg - NR_LOW_DRS - 1);
+ }
+#endif
+}
diff --git a/libmaple/stm32f1/dma.c b/libmaple/stm32f1/dma.c
new file mode 100644
index 0000000..6400d15
--- /dev/null
+++ b/libmaple/stm32f1/dma.c
@@ -0,0 +1,413 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/dma.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>;
+ * Original implementation by Michael Hope
+ * @brief STM32F1 DMA support.
+ */
+
+#include <libmaple/dma.h>
+#include <libmaple/bitband.h>
+
+/* Hack to ensure inlining in dma_irq_handler() */
+#define DMA_GET_HANDLER(dev, tube) (dev->handlers[tube - 1].handler)
+#include "dma_private.h"
+
+/*
+ * Devices
+ */
+
+static dma_dev dma1 = {
+ .regs = DMA1_BASE,
+ .clk_id = RCC_DMA1,
+ .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH2 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH3 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH4 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH5 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH6 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH7 }},
+};
+/** STM32F1 DMA1 device */
+dma_dev *DMA1 = &dma1;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static dma_dev dma2 = {
+ .regs = DMA2_BASE,
+ .clk_id = RCC_DMA2,
+ .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_CH2 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_CH3 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }}, /* !@#$ */
+};
+/** STM32F1 DMA2 device */
+dma_dev *DMA2 = &dma2;
+#endif
+
+/*
+ * Auxiliary routines
+ */
+
+/* Can channel serve cfg->tube_req_src? */
+static int cfg_req_ok(dma_channel channel, dma_tube_config *cfg) {
+ return (cfg->tube_req_src & 0x7) == channel;
+}
+
+/* Can dev serve cfg->tube_req_src? */
+static int cfg_dev_ok(dma_dev *dev, dma_tube_config *cfg) {
+ return (rcc_clk_id)(cfg->tube_req_src >> 3) == dev->clk_id;
+}
+
+/* Is addr acceptable for use as DMA src/dst? */
+static int cfg_mem_ok(__io void *addr) {
+ enum dma_atype atype = _dma_addr_type(addr);
+ return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER;
+}
+
+/* Is the direction implied by src->dst supported? */
+static int cfg_dir_ok(dma_tube_config *cfg) {
+ /* We can't do peripheral->peripheral transfers. */
+ return ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) ||
+ (_dma_addr_type(cfg->tube_dst) == DMA_ATYPE_MEM));
+}
+
+static int preconfig_check(dma_dev *dev, dma_channel channel,
+ dma_tube_config *cfg) {
+ if (!cfg_req_ok(channel, cfg)) {
+ return -DMA_TUBE_CFG_EREQ;
+ }
+ if (cfg->tube_nr_xfers > 65535) {
+ return -DMA_TUBE_CFG_ENDATA;
+ }
+ if (!cfg_dev_ok(dev, cfg)) {
+ return -DMA_TUBE_CFG_EDEV;
+ }
+ if (!cfg_mem_ok(cfg->tube_src)) {
+ return -DMA_TUBE_CFG_ESRC;
+ }
+ if (!cfg_mem_ok(cfg->tube_dst)) {
+ return -DMA_TUBE_CFG_EDST;
+ }
+ if (!cfg_dir_ok(cfg)) {
+ return -DMA_TUBE_CFG_EDIR;
+ }
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+static inline void set_ccr(dma_tube_reg_map *chregs,
+ dma_xfer_size msize, int minc,
+ dma_xfer_size psize, int pinc,
+ uint32 other_flags) {
+ chregs->CCR = ((msize << 10) | (psize << 8) |
+ (minc ? DMA_CCR_MINC : 0) | (pinc ? DMA_CCR_PINC : 0) |
+ other_flags);
+}
+
+static inline uint32 cfg_ccr_flags(unsigned tube_flags) {
+ /* DMA_CFG_SRC_INC and DMA_CFG_DST_INC are special */
+ return tube_flags & ~(DMA_CFG_SRC_INC | DMA_CFG_DST_INC);
+}
+
+/* Configure chregs according to cfg, where cfg->tube_dst is peripheral. */
+static int config_to_per(dma_tube_reg_map *chregs, dma_tube_config *cfg) {
+ /* Check that ->tube_src is memory (if it's anything else, we
+ * shouldn't have been called). */
+ ASSERT(_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM);
+
+ set_ccr(chregs,
+ cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC,
+ cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC,
+ (cfg_ccr_flags(cfg->tube_flags) | DMA_CCR_DIR_FROM_MEM));
+ chregs->CNDTR = cfg->tube_nr_xfers;
+ chregs->CMAR = (uint32)cfg->tube_src;
+ chregs->CPAR = (uint32)cfg->tube_dst;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Configure chregs according to cfg, where cfg->tube_dst is memory. */
+static int config_to_mem(dma_tube_reg_map *chregs, dma_tube_config *cfg) {
+ uint32 mem2mem;
+
+ if ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) &&
+ (cfg->tube_flags & DMA_CFG_CIRC)) {
+ /* Can't do mem-to-mem and circular mode */
+ return -DMA_TUBE_CFG_ECFG;
+ }
+
+ mem2mem = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ?
+ DMA_CCR_MEM2MEM : 0);
+ set_ccr(chregs,
+ cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC,
+ cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC,
+ (cfg_ccr_flags(cfg->tube_flags) |
+ DMA_CCR_DIR_FROM_PER |
+ mem2mem));
+ chregs->CNDTR = cfg->tube_nr_xfers;
+ chregs->CMAR = (uint32)cfg->tube_dst;
+ chregs->CPAR = (uint32)cfg->tube_src;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/*
+ * Routines
+ */
+
+int dma_tube_cfg(dma_dev *dev, dma_channel channel, dma_tube_config *cfg) {
+ dma_tube_reg_map *chregs;
+ int ret = preconfig_check(dev, channel, cfg);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ dma_disable(dev, channel); /* Must disable before reconfiguring */
+ dma_clear_isr_bits(dev, channel); /* For sanity and consistency
+ * with STM32F2. */
+
+ chregs = dma_tube_regs(dev, channel);
+ switch (_dma_addr_type(cfg->tube_dst)) {
+ case DMA_ATYPE_PER:
+ ret = config_to_per(chregs, cfg);
+ break;
+ case DMA_ATYPE_MEM:
+ ret = config_to_mem(chregs, cfg);
+ break;
+ default:
+ /* Can't happen */
+ ASSERT(0);
+ return -DMA_TUBE_CFG_ECFG;
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ chregs->CNDTR = cfg->tube_nr_xfers;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+void dma_set_priority(dma_dev *dev,
+ dma_channel channel,
+ dma_priority priority) {
+ dma_channel_reg_map *channel_regs;
+ uint32 ccr;
+
+ ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
+
+ channel_regs = dma_channel_regs(dev, channel);
+ ccr = channel_regs->CCR;
+ ccr &= ~DMA_CCR_PL;
+ ccr |= (priority << 12);
+ channel_regs->CCR = ccr;
+}
+
+void dma_set_num_transfers(dma_dev *dev,
+ dma_channel channel,
+ uint16 num_transfers) {
+ dma_channel_reg_map *channel_regs;
+
+ ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
+
+ channel_regs = dma_channel_regs(dev, channel);
+ channel_regs->CNDTR = num_transfers;
+}
+
+void dma_attach_interrupt(dma_dev *dev, dma_channel channel,
+ void (*handler)(void)) {
+ DMA_GET_HANDLER(dev, channel) = handler;
+ nvic_irq_enable(dev->handlers[channel - 1].irq_line);
+}
+
+void dma_detach_interrupt(dma_dev *dev, dma_channel channel) {
+ /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */
+ dma_channel_regs(dev, channel)->CCR &= ~0xF;
+ DMA_GET_HANDLER(dev, channel) = NULL;
+}
+
+void dma_enable(dma_dev *dev, dma_channel channel) {
+ dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel);
+ bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1);
+}
+
+void dma_disable(dma_dev *dev, dma_channel channel) {
+ dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel);
+ bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0);
+}
+
+dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) {
+ /* Grab and clear the ISR bits. */
+ uint8 status_bits = dma_get_isr_bits(dev, channel);
+ dma_clear_isr_bits(dev, channel);
+
+ /* If the channel global interrupt flag is cleared, then
+ * something's very wrong. */
+ ASSERT(status_bits & 0x1);
+ /* If GIF is set, then some other flag should be set, barring
+ * something unexpected (e.g. the user making an unforeseen IFCR
+ * write). */
+ ASSERT(status_bits != 0x1);
+
+ /* ISR flags get set even if the corresponding interrupt enable
+ * bits in the channel's configuration register are cleared, so we
+ * can't use a switch here.
+ *
+ * Don't change the order of these if statements. */
+ if (status_bits & 0x8) {
+ return DMA_TRANSFER_ERROR;
+ } else if (status_bits & 0x2) {
+ return DMA_TRANSFER_COMPLETE;
+ } else if (status_bits & 0x4) {
+ return DMA_TRANSFER_HALF_COMPLETE;
+ }
+
+ /* If we get here, one of our assumptions has been violated, but
+ * the debug level is too low for the above ASSERTs() to have had
+ * any effect. In order to fail fast, mimic the DMA controller's
+ * behavior when an error occurs. */
+ dma_disable(dev, channel);
+ return DMA_TRANSFER_ERROR;
+}
+
+void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) {
+ dma_channel_reg_map *chan_regs;
+
+ ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
+
+ chan_regs = dma_channel_regs(dev, channel);
+ chan_regs->CMAR = (uint32)addr;
+}
+
+void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) {
+ dma_channel_reg_map *chan_regs;
+
+ ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
+
+ chan_regs = dma_channel_regs(dev, channel);
+ chan_regs->CPAR = (uint32)addr;
+}
+
+/**
+ * @brief Deprecated. Use dma_tube_cfg() instead.
+ *
+ * Set up a DMA transfer.
+ *
+ * The channel will be disabled before being reconfigured. The
+ * transfer will have low priority by default. You may choose another
+ * priority before the transfer begins using dma_set_priority(), as
+ * well as performing any other configuration you desire. When the
+ * channel is configured to your liking, enable it using dma_enable().
+ *
+ * @param dev DMA device.
+ * @param channel DMA channel.
+ * @param peripheral_address Base address of peripheral data register
+ * involved in the transfer.
+ * @param peripheral_size Peripheral data transfer size.
+ * @param memory_address Base memory address involved in the transfer.
+ * @param memory_size Memory data transfer size.
+ * @param mode Logical OR of dma_mode_flags
+ *
+ * @see dma_tube_cfg()
+ *
+ * @sideeffect Disables the given DMA channel.
+ * @see dma_xfer_size
+ * @see dma_mode_flags
+ * @see dma_set_num_transfers()
+ * @see dma_set_priority()
+ * @see dma_attach_interrupt()
+ * @see dma_enable()
+ */
+__deprecated
+void dma_setup_transfer(dma_dev *dev,
+ dma_channel channel,
+ __io void *peripheral_address,
+ dma_xfer_size peripheral_size,
+ __io void *memory_address,
+ dma_xfer_size memory_size,
+ uint32 mode) {
+ dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel);
+
+ dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */
+ channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode;
+ channel_regs->CMAR = (uint32)memory_address;
+ channel_regs->CPAR = (uint32)peripheral_address;
+}
+
+/*
+ * IRQ handlers
+ */
+
+void __irq_dma1_channel1(void) {
+ dma_irq_handler(DMA1, DMA_CH1);
+}
+
+void __irq_dma1_channel2(void) {
+ dma_irq_handler(DMA1, DMA_CH2);
+}
+
+void __irq_dma1_channel3(void) {
+ dma_irq_handler(DMA1, DMA_CH3);
+}
+
+void __irq_dma1_channel4(void) {
+ dma_irq_handler(DMA1, DMA_CH4);
+}
+
+void __irq_dma1_channel5(void) {
+ dma_irq_handler(DMA1, DMA_CH5);
+}
+
+void __irq_dma1_channel6(void) {
+ dma_irq_handler(DMA1, DMA_CH6);
+}
+
+void __irq_dma1_channel7(void) {
+ dma_irq_handler(DMA1, DMA_CH7);
+}
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+void __irq_dma2_channel1(void) {
+ dma_irq_handler(DMA2, DMA_CH1);
+}
+
+void __irq_dma2_channel2(void) {
+ dma_irq_handler(DMA2, DMA_CH2);
+}
+
+void __irq_dma2_channel3(void) {
+ dma_irq_handler(DMA2, DMA_CH3);
+}
+
+void __irq_dma2_channel4_5(void) {
+ if ((DMA2_BASE->CCR4 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF4)) {
+ dma_irq_handler(DMA2, DMA_CH4);
+ }
+ if ((DMA2_BASE->CCR5 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF5)) {
+ dma_irq_handler(DMA2, DMA_CH5);
+ }
+}
+#endif
diff --git a/libmaple/stm32f1/exti.c b/libmaple/stm32f1/exti.c
new file mode 100644
index 0000000..b9ff401
--- /dev/null
+++ b/libmaple/stm32f1/exti.c
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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 <libmaple/gpio.h>
+#include "exti_private.h"
+
+void exti_select(exti_num num, exti_cfg port) {
+ exti_do_select(&AFIO_BASE->EXTICR1 + num / 4, num, port);
+}
diff --git a/libmaple/stm32f1/fsmc.c b/libmaple/stm32f1/fsmc.c
new file mode 100644
index 0000000..210f0be
--- /dev/null
+++ b/libmaple/stm32f1/fsmc.c
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Bryan Newbold.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/fsmc.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Bryan Newbold <bnewbold@robocracy.org>
+ * @brief STM32F1 FSMC support.
+ */
+
+#include <libmaple/stm32.h>
+
+#if STM32_HAVE_FSMC /* Don't try building the rest for MCUs without FSMC */
+
+#include <libmaple/fsmc.h>
+#include <libmaple/gpio.h>
+
+void fsmc_sram_init_gpios(void) {
+ /* Data lines... */
+ gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOD, 8, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOD, 9, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOD, 10, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOD, 14, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOD, 15, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 7, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 8, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 9, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 10, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 11, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 12, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 13, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 14, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOE, 15, GPIO_AF_OUTPUT_PP);
+
+ /* Address lines... */
+ gpio_set_mode(GPIOD, 11, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOD, 12, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOD, 13, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 0, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 1, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 2, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 3, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 4, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 5, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 12, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 13, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 14, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOF, 15, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOG, 0, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOG, 1, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOG, 2, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOG, 3, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOG, 4, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(GPIOG, 5, GPIO_AF_OUTPUT_PP);
+
+ /* And control lines... */
+ gpio_set_mode(GPIOD, 4, GPIO_AF_OUTPUT_PP); // NOE
+ gpio_set_mode(GPIOD, 5, GPIO_AF_OUTPUT_PP); // NWE
+
+ gpio_set_mode(GPIOD, 7, GPIO_AF_OUTPUT_PP); // NE1
+ gpio_set_mode(GPIOG, 9, GPIO_AF_OUTPUT_PP); // NE2
+ gpio_set_mode(GPIOG, 10, GPIO_AF_OUTPUT_PP); // NE3
+ gpio_set_mode(GPIOG, 12, GPIO_AF_OUTPUT_PP); // NE4
+
+ gpio_set_mode(GPIOE, 0, GPIO_AF_OUTPUT_PP); // NBL0
+ gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1
+}
+
+#endif /* STM32_HAVE_FSMC */
diff --git a/libmaple/stm32f1/gpio.c b/libmaple/stm32f1/gpio.c
new file mode 100644
index 0000000..4b596e9
--- /dev/null
+++ b/libmaple/stm32f1/gpio.c
@@ -0,0 +1,166 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/gpio.c
+ * @brief STM32F1 GPIO support.
+ */
+
+#include <libmaple/gpio.h>
+#include <libmaple/rcc.h>
+
+/*
+ * GPIO devices
+ */
+
+gpio_dev gpioa = {
+ .regs = GPIOA_BASE,
+ .clk_id = RCC_GPIOA,
+ .exti_port = EXTI_PA,
+};
+/** GPIO port A device. */
+gpio_dev* const GPIOA = &gpioa;
+
+gpio_dev gpiob = {
+ .regs = GPIOB_BASE,
+ .clk_id = RCC_GPIOB,
+ .exti_port = EXTI_PB,
+};
+/** GPIO port B device. */
+gpio_dev* const GPIOB = &gpiob;
+
+gpio_dev gpioc = {
+ .regs = GPIOC_BASE,
+ .clk_id = RCC_GPIOC,
+ .exti_port = EXTI_PC,
+};
+/** GPIO port C device. */
+gpio_dev* const GPIOC = &gpioc;
+
+gpio_dev gpiod = {
+ .regs = GPIOD_BASE,
+ .clk_id = RCC_GPIOD,
+ .exti_port = EXTI_PD,
+};
+/** GPIO port D device. */
+gpio_dev* const GPIOD = &gpiod;
+
+#ifdef STM32_HIGH_DENSITY
+gpio_dev gpioe = {
+ .regs = GPIOE_BASE,
+ .clk_id = RCC_GPIOE,
+ .exti_port = EXTI_PE,
+};
+/** GPIO port E device. */
+gpio_dev* const GPIOE = &gpioe;
+
+gpio_dev gpiof = {
+ .regs = GPIOF_BASE,
+ .clk_id = RCC_GPIOF,
+ .exti_port = EXTI_PF,
+};
+/** GPIO port F device. */
+gpio_dev* const GPIOF = &gpiof;
+
+gpio_dev gpiog = {
+ .regs = GPIOG_BASE,
+ .clk_id = RCC_GPIOG,
+ .exti_port = EXTI_PG,
+};
+/** GPIO port G device. */
+gpio_dev* const GPIOG = &gpiog;
+#endif
+
+/*
+ * GPIO routines
+ */
+
+/**
+ * Initialize and reset all available GPIO devices.
+ */
+void gpio_init_all(void) {
+ gpio_init(GPIOA);
+ gpio_init(GPIOB);
+ gpio_init(GPIOC);
+ gpio_init(GPIOD);
+#ifdef STM32_HIGH_DENSITY
+ gpio_init(GPIOE);
+ gpio_init(GPIOF);
+ gpio_init(GPIOG);
+#endif
+}
+
+/**
+ * Set the mode of a GPIO pin.
+ *
+ * @param dev GPIO device.
+ * @param pin Pin on the device whose mode to set, 0--15.
+ * @param mode General purpose or alternate function mode to set the pin to.
+ * @see gpio_pin_mode
+ */
+void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) {
+ gpio_reg_map *regs = dev->regs;
+ __io uint32 *cr = &regs->CRL + (pin >> 3);
+ uint32 shift = (pin & 0x7) * 4;
+ uint32 tmp = *cr;
+
+ tmp &= ~(0xF << shift);
+ tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift;
+ *cr = tmp;
+
+ if (mode == GPIO_INPUT_PD) {
+ regs->ODR &= ~(1U << pin);
+ } else if (mode == GPIO_INPUT_PU) {
+ regs->ODR |= (1U << pin);
+ }
+}
+
+/*
+ * AFIO
+ */
+
+/**
+ * @brief Initialize the AFIO clock, and reset the AFIO registers.
+ */
+void afio_init(void) {
+ rcc_clk_enable(RCC_AFIO);
+ rcc_reset_dev(RCC_AFIO);
+}
+
+#define AFIO_EXTI_SEL_MASK 0xF
+
+/**
+ * @brief Perform an alternate function remap.
+ * @param remapping Remapping to perform.
+ */
+void afio_remap(afio_remap_peripheral remapping) {
+ if (remapping & AFIO_REMAP_USE_MAPR2) {
+ remapping &= ~AFIO_REMAP_USE_MAPR2;
+ AFIO_BASE->MAPR2 |= remapping;
+ } else {
+ AFIO_BASE->MAPR |= remapping;
+ }
+}
diff --git a/libmaple/stm32f1/i2c.c b/libmaple/stm32f1/i2c.c
new file mode 100644
index 0000000..8439793
--- /dev/null
+++ b/libmaple/stm32f1/i2c.c
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/i2c.c
+ * @brief STM32F1 I2C support
+ */
+
+#include "i2c_private.h"
+#include <libmaple/i2c.h>
+
+/*
+ * Devices
+ */
+
+static i2c_dev i2c1 = I2C_DEV_OLD(1, &gpiob, 7, 6);
+static i2c_dev i2c2 = I2C_DEV_OLD(2, &gpiob, 11, 10);
+
+/** STM32F1 I2C device 1 */
+i2c_dev* const I2C1 = &i2c1;
+/** STM32F1 I2C device 2 */
+i2c_dev* const I2C2 = &i2c2;
+
+/*
+ * Routines
+ */
+
+static int i2c1_wants_remap(const i2c_dev *dev) {
+ /* Check if we've got I2C1 configured for SDA/SCL remap on PB9/PB8 */
+ return (dev->clk_id == RCC_I2C1) &&
+ (scl_port(dev)->clk_id == RCC_GPIOB) &&
+ (sda_port(dev)->clk_id == RCC_GPIOB) &&
+ (dev->sda_pin == 9) &&
+ (dev->scl_pin == 8);
+}
+
+void i2c_config_gpios(const i2c_dev *dev) {
+ if (i2c1_wants_remap(dev)) {
+ afio_remap(AFIO_REMAP_I2C1);
+ }
+ gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_AF_OUTPUT_OD);
+ gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_AF_OUTPUT_OD);
+}
+
+void i2c_master_release_bus(const i2c_dev *dev) {
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
+ gpio_write_bit(sda_port(dev), dev->sda_pin, 1);
+ gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_OUTPUT_OD);
+ gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_OUTPUT_OD);
+}
+
+/*
+ * IRQ handlers
+ */
+
+void __irq_i2c1_ev(void) {
+ _i2c_irq_handler(I2C1);
+}
+
+void __irq_i2c2_ev(void) {
+ _i2c_irq_handler(I2C2);
+}
+
+void __irq_i2c1_er(void) {
+ _i2c_irq_error_handler(I2C1);
+}
+
+void __irq_i2c2_er(void) {
+ _i2c_irq_error_handler(I2C2);
+}
+
+/*
+ * Internal APIs
+ */
+
+void _i2c_irq_priority_fixup(i2c_dev *dev) {
+ /*
+ * Important STM32 Errata:
+ *
+ * See STM32F10xx8 and STM32F10xxB Errata sheet (Doc ID 14574 Rev 8),
+ * Section 2.11.1, 2.11.2.
+ *
+ * 2.11.1:
+ * When the EV7, EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events are not
+ * managed before the current byte is being transferred, problems may be
+ * encountered such as receiving an extra byte, reading the same data twice
+ * or missing data.
+ *
+ * 2.11.2:
+ * In Master Receiver mode, when closing the communication using
+ * method 2, the content of the last read data can be corrupted.
+ *
+ * If the user software is not able to read the data N-1 before the STOP
+ * condition is generated on the bus, the content of the shift register
+ * (data N) will be corrupted. (data N is shifted 1-bit to the left).
+ *
+ * ----------------------------------------------------------------------
+ *
+ * In order to ensure that events are not missed, the i2c interrupt must
+ * not be preempted. We set the i2c interrupt priority to be the highest
+ * interrupt in the system (priority level 0). All other interrupts have
+ * been initialized to priority level 16. See nvic_init().
+ */
+ nvic_irq_set_priority(dev->ev_nvic_line, 0);
+ nvic_irq_set_priority(dev->er_nvic_line, 0);
+}
diff --git a/libmaple/stm32f1/include/series/adc.h b/libmaple/stm32f1/include/series/adc.h
new file mode 100644
index 0000000..79d8107
--- /dev/null
+++ b/libmaple/stm32f1/include/series/adc.h
@@ -0,0 +1,253 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/adc.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief STM32F1 ADC header.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_ADC_H_
+#define _LIBMAPLE_STM32F1_ADC_H_
+
+#include <libmaple/bitband.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h> /* For the prescalers */
+
+/*
+ * Devices
+ */
+
+extern const struct adc_dev *ADC1;
+extern const struct adc_dev *ADC2;
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+extern const struct adc_dev *ADC3;
+#endif
+
+/*
+ * Register map base pointers
+ */
+
+/** STM32F1 ADC1 register map base pointer. */
+#define ADC1_BASE ((struct adc_reg_map*)0x40012400)
+/** STM32F1 ADC2 register map base pointer. */
+#define ADC2_BASE ((struct adc_reg_map*)0x40012800)
+/** STM32F1 ADC3 register map base pointer. */
+#define ADC3_BASE ((struct adc_reg_map*)0x40013C00)
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 2 */
+
+#define ADC_CR2_ADON_BIT 0
+#define ADC_CR2_CONT_BIT 1
+#define ADC_CR2_CAL_BIT 2
+#define ADC_CR2_RSTCAL_BIT 3
+#define ADC_CR2_DMA_BIT 8
+#define ADC_CR2_ALIGN_BIT 11
+#define ADC_CR2_JEXTTRIG_BIT 15
+#define ADC_CR2_EXTTRIG_BIT 20
+#define ADC_CR2_JSWSTART_BIT 21
+#define ADC_CR2_SWSTART_BIT 22
+#define ADC_CR2_TSEREFE_BIT 23
+
+#define ADC_CR2_ADON (1U << ADC_CR2_ADON_BIT)
+#define ADC_CR2_CONT (1U << ADC_CR2_CONT_BIT)
+#define ADC_CR2_CAL (1U << ADC_CR2_CAL_BIT)
+#define ADC_CR2_RSTCAL (1U << ADC_CR2_RSTCAL_BIT)
+#define ADC_CR2_DMA (1U << ADC_CR2_DMA_BIT)
+#define ADC_CR2_ALIGN (1U << ADC_CR2_ALIGN_BIT)
+#define ADC_CR2_JEXTSEL 0x7000
+#define ADC_CR2_JEXTTRIG (1U << ADC_CR2_JEXTTRIG_BIT)
+#define ADC_CR2_EXTSEL 0xE0000
+#define ADC_CR2_EXTTRIG (1U << ADC_CR2_EXTTRIG_BIT)
+#define ADC_CR2_JSWSTART (1U << ADC_CR2_JSWSTART_BIT)
+#define ADC_CR2_SWSTART (1U << ADC_CR2_SWSTART_BIT)
+#define ADC_CR2_TSEREFE (1U << ADC_CR2_TSEREFE_BIT)
+
+/*
+ * Other types
+ */
+
+/**
+ * @brief STM32F1 external event selectors for regular group
+ * conversion.
+ *
+ * Some external events are only available on ADCs 1 and 2, others
+ * only on ADC3, while others are available on all three ADCs.
+ * Additionally, some events are only available on high- and
+ * XL-density STM32F1 MCUs, as they use peripherals only available on
+ * those MCU densities.
+ *
+ * For ease of use, each event selector is given along with the ADCs
+ * it's available on, along with any other availability restrictions.
+ *
+ * @see adc_set_extsel()
+ */
+typedef enum adc_extsel_event {
+ /* TODO: Smarten this up a bit, as follows.
+ *
+ * The EXTSEL bits on F1 are a little brain-damaged in that the
+ * TIM8 TRGO event has different bits depending on whether you're
+ * using ADC1/2 or ADC3. We route around this by declaring two
+ * enumerators, ADC_EXT_EV_ADC12_TIM8_TRGO and
+ * ADC_EXT_EV_ADC3_TIM8_TRGO.
+ *
+ * The right thing to do is to provide a single
+ * ADC_EXT_EV_TIM8_TRGO enumerator and override adc_set_extsel on
+ * STM32F1 to handle this situation correctly. We can do that
+ * later, though, and change the per-ADC enumerator values to
+ * ADC_EXT_EV_TIM8_TRGO to preserve compatibility. */
+
+ /* ADC1 and ADC2 only: */
+ ADC_EXT_EV_TIM1_CC1 = 0x00000, /**< ADC1, ADC2: Timer 1 CC1 event */
+ ADC_EXT_EV_TIM1_CC2 = 0x20000, /**< ADC1, ADC2: Timer 1 CC2 event */
+ ADC_EXT_EV_TIM2_CC2 = 0x60000, /**< ADC1, ADC2: Timer 2 CC2 event */
+ ADC_EXT_EV_TIM3_TRGO = 0x80000, /**< ADC1, ADC2: Timer 3 TRGO event */
+ ADC_EXT_EV_TIM4_CC4 = 0xA0000, /**< ADC1, ADC2: Timer 4 CC4 event */
+ ADC_EXT_EV_EXTI11 = 0xC0000, /**< ADC1, ADC2: EXTI11 event */
+
+ /* Common: */
+ ADC_EXT_EV_TIM1_CC3 = 0x40000, /**< ADC1, ADC2, ADC3: Timer 1 CC3 event */
+ ADC_EXT_EV_SWSTART = 0xE0000, /**< ADC1, ADC2, ADC3: Software start */
+
+ /* HD only: */
+ ADC_EXT_EV_TIM3_CC1 = 0x00000, /**<
+ * ADC3: Timer 3 CC1 event
+ * Availability: high- and XL-density. */
+ ADC_EXT_EV_TIM2_CC3 = 0x20000, /**<
+ * ADC3: Timer 2 CC3 event
+ * Availability: high- and XL-density. */
+ ADC_EXT_EV_TIM8_CC1 = 0x60000, /**<
+ * ADC3: Timer 8 CC1 event
+ * Availability: high- and XL-density. */
+ ADC_EXT_EV_ADC3_TIM8_TRGO = 0x80000, /**<
+ * ADC3: Timer 8 TRGO event
+ * Availability: high- and XL-density. */
+ ADC_EXT_EV_TIM5_CC1 = 0xA0000, /**<
+ * ADC3: Timer 5 CC1 event
+ * Availability: high- and XL-density. */
+ ADC_EXT_EV_ADC12_TIM8_TRGO = 0xC0000, /**<
+ * ADC1, ADC2: Timer 8 TRGO event
+ * Availability: high- and XL-density. */
+ ADC_EXT_EV_TIM5_CC3 = 0xC0000, /**<
+ * ADC3: Timer 5 CC3 event
+ * Availability: high- and XL-density. */
+} adc_extsel_event;
+
+/* We'll keep these old adc_extsel_event enumerators around for a
+ * while, for backwards compatibility: */
+/** Deprecated. Use ADC_EXT_EV_TIM1_CC1 instead. */
+#define ADC_ADC12_TIM1_CC1 ADC_EXT_EV_TIM1_CC1
+/** Deprecated. Use ADC_EXT_EV_TIM1_CC2 instead. */
+#define ADC_ADC12_TIM1_CC2 ADC_EXT_EV_TIM1_CC2
+/** Deprecated. Use ADC_EXT_EV_TIM1_CC3 instead. */
+#define ADC_ADC12_TIM1_CC3 ADC_EXT_EV_TIM1_CC3
+/** Deprecated. Use ADC_EXT_EV_TIM2_CC2 instead. */
+#define ADC_ADC12_TIM2_CC2 ADC_EXT_EV_TIM2_CC2
+/** Deprecated. Use ADC_EXT_EV_TIM3_TRGO instead. */
+#define ADC_ADC12_TIM3_TRGO ADC_EXT_EV_TIM3_TRGO
+/** Deprecated. Use ADC_EXT_EV_TIM4_CC4 instead. */
+#define ADC_ADC12_TIM4_CC4 ADC_EXT_EV_TIM4_CC4
+/** Deprecated. Use ADC_EXT_EV_EXTI11 instead. */
+#define ADC_ADC12_EXTI11 ADC_EXT_EV_EXTI11
+/** Deprecated. Use ADC_EXT_EV_ADC12_TIM8_TRGO instead. */
+#define ADC_ADC12_TIM8_TRGO ADC_EXT_EV_ADC12_TIM8_TRGO
+/** Deprecated. Use ADC_EXT_EV_SWSTART instead. */
+#define ADC_ADC12_SWSTART ADC_EXT_EV_SWSTART
+/** Deprecated. Use ADC_EXT_EV_TIM1_CC1 instead. */
+#define ADC_ADC3_TIM3_CC1 ADC_EXT_EV_TIM1_CC1
+/** Deprecated. Use ADC_EXT_EV_TIM1_CC2 instead. */
+#define ADC_ADC3_TIM2_CC3 ADC_EXT_EV_TIM1_CC2
+/** Deprecated. Use ADC_EXT_EV_TIM1_CC3 instead. */
+#define ADC_ADC3_TIM1_CC3 ADC_EXT_EV_TIM1_CC3
+/** Deprecated. Use ADC_EXT_EV_TIM2_CC2 instead. */
+#define ADC_ADC3_TIM8_CC1 ADC_EXT_EV_TIM2_CC2
+/** Deprecated. Use ADC_EXT_EV_TIM3_TRGO instead. */
+#define ADC_ADC3_TIM8_TRGO ADC_EXT_EV_TIM3_TRGO
+/** Deprecated. Use ADC_EXT_EV_TIM4_CC4 instead. */
+#define ADC_ADC3_TIM5_CC1 ADC_EXT_EV_TIM4_CC4
+/** Deprecated. Use ADC_EXT_EV_EXTI11 instead. */
+#define ADC_ADC3_TIM5_CC3 ADC_EXT_EV_EXTI11
+/** Deprecated. Use ADC_EXT_EV_TIM8_TRGO instead. */
+#define ADC_ADC3_SWSTART ADC_EXT_EV_TIM8_TRGO
+/** Deprecated. Use ADC_EXT_EV_SWSTART instead. */
+#define ADC_SWSTART ADC_EXT_EV_SWSTART
+
+/**
+ * @brief STM32F1 sample times, in ADC clock cycles.
+ *
+ * These control the amount of time spent sampling the input voltage.
+ */
+typedef enum adc_smp_rate {
+ ADC_SMPR_1_5, /**< 1.5 ADC cycles */
+ ADC_SMPR_7_5, /**< 7.5 ADC cycles */
+ ADC_SMPR_13_5, /**< 13.5 ADC cycles */
+ ADC_SMPR_28_5, /**< 28.5 ADC cycles */
+ ADC_SMPR_41_5, /**< 41.5 ADC cycles */
+ ADC_SMPR_55_5, /**< 55.5 ADC cycles */
+ ADC_SMPR_71_5, /**< 71.5 ADC cycles */
+ ADC_SMPR_239_5, /**< 239.5 ADC cycles */
+} adc_smp_rate;
+
+/**
+ * @brief STM32F1 ADC prescalers, as divisors of PCLK2.
+ */
+typedef enum adc_prescaler {
+ /** PCLK2 divided by 2 */
+ ADC_PRE_PCLK2_DIV_2 = RCC_ADCPRE_PCLK_DIV_2,
+ /** PCLK2 divided by 4 */
+ ADC_PRE_PCLK2_DIV_4 = RCC_ADCPRE_PCLK_DIV_4,
+ /** PCLK2 divided by 6 */
+ ADC_PRE_PCLK2_DIV_6 = RCC_ADCPRE_PCLK_DIV_6,
+ /** PCLK2 divided by 8 */
+ ADC_PRE_PCLK2_DIV_8 = RCC_ADCPRE_PCLK_DIV_8,
+} adc_prescaler;
+
+/*
+ * Routines
+ */
+
+void adc_calibrate(const adc_dev *dev);
+
+/**
+ * @brief Set external trigger conversion mode event for regular channels
+ *
+ * Availability: STM32F1.
+ *
+ * @param dev ADC device
+ * @param enable If 1, conversion on external events is enabled; if 0,
+ * disabled.
+ */
+static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) {
+ *bb_perip(&dev->regs->CR2, ADC_CR2_EXTTRIG_BIT) = !!enable;
+}
+
+#endif
diff --git a/libmaple/stm32f1/include/series/dac.h b/libmaple/stm32f1/include/series/dac.h
new file mode 100644
index 0000000..c0d026b
--- /dev/null
+++ b/libmaple/stm32f1/include/series/dac.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/dac.h
+ * @brief STM32F1 DAC support
+ */
+
+#ifndef _LIBMAPLE_STM32F1_DAC_H_
+#define _LIBMAPLE_STM32F1_DAC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/** STM32F1 DAC register map type. */
+typedef struct dac_reg_map {
+ __io uint32 CR; /**< Control register */
+ __io uint32 SWTRIGR; /**< Software trigger register */
+ __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding
+ register */
+ __io uint32 DOR1; /**< Channel 1 data output register */
+ __io uint32 DOR2; /**< Channel 2 data output register */
+} dac_reg_map;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/dma.h b/libmaple/stm32f1/include/series/dma.h
new file mode 100644
index 0000000..bedb602
--- /dev/null
+++ b/libmaple/stm32f1/include/series/dma.h
@@ -0,0 +1,575 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/dma.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>;
+ * Original implementation by Michael Hope
+ * @brief STM32F1 DMA series header.
+ */
+
+/*
+ * See /notes/dma-stm32f1.txt for more information.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_DMA_H_
+#define _LIBMAPLE_STM32F1_DMA_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/dma_common.h>
+
+/*
+ * Register maps and base pointers
+ */
+
+/**
+ * @brief STM32F1 DMA register map type.
+ *
+ * Note that DMA controller 2 (register map base pointer DMA2_BASE)
+ * only supports channels 1--5.
+ */
+typedef struct dma_reg_map {
+ __io uint32 ISR; /**< Interrupt status register */
+ __io uint32 IFCR; /**< Interrupt flag clear register */
+ __io uint32 CCR1; /**< Channel 1 configuration register */
+ __io uint32 CNDTR1; /**< Channel 1 number of data register */
+ __io uint32 CPAR1; /**< Channel 1 peripheral address register */
+ __io uint32 CMAR1; /**< Channel 1 memory address register */
+ const uint32 RESERVED1; /**< Reserved. */
+ __io uint32 CCR2; /**< Channel 2 configuration register */
+ __io uint32 CNDTR2; /**< Channel 2 number of data register */
+ __io uint32 CPAR2; /**< Channel 2 peripheral address register */
+ __io uint32 CMAR2; /**< Channel 2 memory address register */
+ const uint32 RESERVED2; /**< Reserved. */
+ __io uint32 CCR3; /**< Channel 3 configuration register */
+ __io uint32 CNDTR3; /**< Channel 3 number of data register */
+ __io uint32 CPAR3; /**< Channel 3 peripheral address register */
+ __io uint32 CMAR3; /**< Channel 3 memory address register */
+ const uint32 RESERVED3; /**< Reserved. */
+ __io uint32 CCR4; /**< Channel 4 configuration register */
+ __io uint32 CNDTR4; /**< Channel 4 number of data register */
+ __io uint32 CPAR4; /**< Channel 4 peripheral address register */
+ __io uint32 CMAR4; /**< Channel 4 memory address register */
+ const uint32 RESERVED4; /**< Reserved. */
+ __io uint32 CCR5; /**< Channel 5 configuration register */
+ __io uint32 CNDTR5; /**< Channel 5 number of data register */
+ __io uint32 CPAR5; /**< Channel 5 peripheral address register */
+ __io uint32 CMAR5; /**< Channel 5 memory address register */
+ const uint32 RESERVED5; /**< Reserved. */
+ __io uint32 CCR6; /**< Channel 6 configuration register */
+ __io uint32 CNDTR6; /**< Channel 6 number of data register */
+ __io uint32 CPAR6; /**< Channel 6 peripheral address register */
+ __io uint32 CMAR6; /**< Channel 6 memory address register */
+ const uint32 RESERVED6; /**< Reserved. */
+ __io uint32 CCR7; /**< Channel 7 configuration register */
+ __io uint32 CNDTR7; /**< Channel 7 number of data register */
+ __io uint32 CPAR7; /**< Channel 7 peripheral address register */
+ __io uint32 CMAR7; /**< Channel 7 memory address register */
+ const uint32 RESERVED7; /**< Reserved. */
+} dma_reg_map;
+
+/** DMA controller 1 register map base pointer */
+#define DMA1_BASE ((struct dma_reg_map*)0x40020000)
+/** DMA controller 2 register map base pointer */
+#define DMA2_BASE ((struct dma_reg_map*)0x40020400)
+
+/**
+ * @brief STM32F1 DMA channel (i.e. tube) register map type.
+ * Provides access to an individual channel's registers.
+ * @see dma_tube_regs()
+ */
+typedef struct dma_tube_reg_map {
+ __io uint32 CCR; /**< Channel configuration register */
+ __io uint32 CNDTR; /**< Channel number of data register */
+ __io uint32 CPAR; /**< Channel peripheral address register */
+ __io uint32 CMAR; /**< Channel memory address register */
+} dma_tube_reg_map;
+
+/** DMA1 channel 1 register map base pointer */
+#define DMA1CH1_BASE ((struct dma_tube_reg_map*)0x40020008)
+/** DMA1 channel 2 register map base pointer */
+#define DMA1CH2_BASE ((struct dma_tube_reg_map*)0x4002001C)
+/** DMA1 channel 3 register map base pointer */
+#define DMA1CH3_BASE ((struct dma_tube_reg_map*)0x40020030)
+/** DMA1 channel 4 register map base pointer */
+#define DMA1CH4_BASE ((struct dma_tube_reg_map*)0x40020044)
+/** DMA1 channel 5 register map base pointer */
+#define DMA1CH5_BASE ((struct dma_tube_reg_map*)0x40020058)
+/** DMA1 channel 6 register map base pointer */
+#define DMA1CH6_BASE ((struct dma_tube_reg_map*)0x4002006C)
+/** DMA1 channel 7 register map base pointer */
+#define DMA1CH7_BASE ((struct dma_tube_reg_map*)0x40020080)
+
+/** DMA2 channel 1 register map base pointer */
+#define DMA2CH1_BASE ((struct dma_tube_reg_map*)0x40020408)
+/** DMA2 channel 2 register map base pointer */
+#define DMA2CH2_BASE ((struct dma_tube_reg_map*)0x4002041C)
+/** DMA2 channel 3 register map base pointer */
+#define DMA2CH3_BASE ((struct dma_tube_reg_map*)0x40020430)
+/** DMA2 channel 4 register map base pointer */
+#define DMA2CH4_BASE ((struct dma_tube_reg_map*)0x40020444)
+/** DMA2 channel 5 register map base pointer */
+#define DMA2CH5_BASE ((struct dma_tube_reg_map*)0x40020458)
+
+/*
+ * Register bit definitions
+ */
+
+/* Interrupt status register */
+
+#define DMA_ISR_TEIF_BIT 3
+#define DMA_ISR_HTIF_BIT 2
+#define DMA_ISR_TCIF_BIT 1
+#define DMA_ISR_GIF_BIT 0
+
+#define DMA_ISR_TEIF (1 << DMA_ISR_TEIF_BIT)
+#define DMA_ISR_HTIF (1 << DMA_ISR_HTIF_BIT)
+#define DMA_ISR_TCID (1 << DMA_ISR_TCIF_BIT)
+#define DMA_ISR_GIF (1 << DMA_ISR_GIF_BIT)
+
+#define DMA_ISR_TEIF7_BIT 27
+#define DMA_ISR_HTIF7_BIT 26
+#define DMA_ISR_TCIF7_BIT 25
+#define DMA_ISR_GIF7_BIT 24
+#define DMA_ISR_TEIF6_BIT 23
+#define DMA_ISR_HTIF6_BIT 22
+#define DMA_ISR_TCIF6_BIT 21
+#define DMA_ISR_GIF6_BIT 20
+#define DMA_ISR_TEIF5_BIT 19
+#define DMA_ISR_HTIF5_BIT 18
+#define DMA_ISR_TCIF5_BIT 17
+#define DMA_ISR_GIF5_BIT 16
+#define DMA_ISR_TEIF4_BIT 15
+#define DMA_ISR_HTIF4_BIT 14
+#define DMA_ISR_TCIF4_BIT 13
+#define DMA_ISR_GIF4_BIT 12
+#define DMA_ISR_TEIF3_BIT 11
+#define DMA_ISR_HTIF3_BIT 10
+#define DMA_ISR_TCIF3_BIT 9
+#define DMA_ISR_GIF3_BIT 8
+#define DMA_ISR_TEIF2_BIT 7
+#define DMA_ISR_HTIF2_BIT 6
+#define DMA_ISR_TCIF2_BIT 5
+#define DMA_ISR_GIF2_BIT 4
+#define DMA_ISR_TEIF1_BIT 3
+#define DMA_ISR_HTIF1_BIT 2
+#define DMA_ISR_TCIF1_BIT 1
+#define DMA_ISR_GIF1_BIT 0
+
+#define DMA_ISR_TEIF7 (1U << DMA_ISR_TEIF7_BIT)
+#define DMA_ISR_HTIF7 (1U << DMA_ISR_HTIF7_BIT)
+#define DMA_ISR_TCIF7 (1U << DMA_ISR_TCIF7_BIT)
+#define DMA_ISR_GIF7 (1U << DMA_ISR_GIF7_BIT)
+#define DMA_ISR_TEIF6 (1U << DMA_ISR_TEIF6_BIT)
+#define DMA_ISR_HTIF6 (1U << DMA_ISR_HTIF6_BIT)
+#define DMA_ISR_TCIF6 (1U << DMA_ISR_TCIF6_BIT)
+#define DMA_ISR_GIF6 (1U << DMA_ISR_GIF6_BIT)
+#define DMA_ISR_TEIF5 (1U << DMA_ISR_TEIF5_BIT)
+#define DMA_ISR_HTIF5 (1U << DMA_ISR_HTIF5_BIT)
+#define DMA_ISR_TCIF5 (1U << DMA_ISR_TCIF5_BIT)
+#define DMA_ISR_GIF5 (1U << DMA_ISR_GIF5_BIT)
+#define DMA_ISR_TEIF4 (1U << DMA_ISR_TEIF4_BIT)
+#define DMA_ISR_HTIF4 (1U << DMA_ISR_HTIF4_BIT)
+#define DMA_ISR_TCIF4 (1U << DMA_ISR_TCIF4_BIT)
+#define DMA_ISR_GIF4 (1U << DMA_ISR_GIF4_BIT)
+#define DMA_ISR_TEIF3 (1U << DMA_ISR_TEIF3_BIT)
+#define DMA_ISR_HTIF3 (1U << DMA_ISR_HTIF3_BIT)
+#define DMA_ISR_TCIF3 (1U << DMA_ISR_TCIF3_BIT)
+#define DMA_ISR_GIF3 (1U << DMA_ISR_GIF3_BIT)
+#define DMA_ISR_TEIF2 (1U << DMA_ISR_TEIF2_BIT)
+#define DMA_ISR_HTIF2 (1U << DMA_ISR_HTIF2_BIT)
+#define DMA_ISR_TCIF2 (1U << DMA_ISR_TCIF2_BIT)
+#define DMA_ISR_GIF2 (1U << DMA_ISR_GIF2_BIT)
+#define DMA_ISR_TEIF1 (1U << DMA_ISR_TEIF1_BIT)
+#define DMA_ISR_HTIF1 (1U << DMA_ISR_HTIF1_BIT)
+#define DMA_ISR_TCIF1 (1U << DMA_ISR_TCIF1_BIT)
+#define DMA_ISR_GIF1 (1U << DMA_ISR_GIF1_BIT)
+
+/* Interrupt flag clear register */
+
+#define DMA_IFCR_CTEIF7_BIT 27
+#define DMA_IFCR_CHTIF7_BIT 26
+#define DMA_IFCR_CTCIF7_BIT 25
+#define DMA_IFCR_CGIF7_BIT 24
+#define DMA_IFCR_CTEIF6_BIT 23
+#define DMA_IFCR_CHTIF6_BIT 22
+#define DMA_IFCR_CTCIF6_BIT 21
+#define DMA_IFCR_CGIF6_BIT 20
+#define DMA_IFCR_CTEIF5_BIT 19
+#define DMA_IFCR_CHTIF5_BIT 18
+#define DMA_IFCR_CTCIF5_BIT 17
+#define DMA_IFCR_CGIF5_BIT 16
+#define DMA_IFCR_CTEIF4_BIT 15
+#define DMA_IFCR_CHTIF4_BIT 14
+#define DMA_IFCR_CTCIF4_BIT 13
+#define DMA_IFCR_CGIF4_BIT 12
+#define DMA_IFCR_CTEIF3_BIT 11
+#define DMA_IFCR_CHTIF3_BIT 10
+#define DMA_IFCR_CTCIF3_BIT 9
+#define DMA_IFCR_CGIF3_BIT 8
+#define DMA_IFCR_CTEIF2_BIT 7
+#define DMA_IFCR_CHTIF2_BIT 6
+#define DMA_IFCR_CTCIF2_BIT 5
+#define DMA_IFCR_CGIF2_BIT 4
+#define DMA_IFCR_CTEIF1_BIT 3
+#define DMA_IFCR_CHTIF1_BIT 2
+#define DMA_IFCR_CTCIF1_BIT 1
+#define DMA_IFCR_CGIF1_BIT 0
+
+#define DMA_IFCR_CTEIF7 (1U << DMA_IFCR_CTEIF7_BIT)
+#define DMA_IFCR_CHTIF7 (1U << DMA_IFCR_CHTIF7_BIT)
+#define DMA_IFCR_CTCIF7 (1U << DMA_IFCR_CTCIF7_BIT)
+#define DMA_IFCR_CGIF7 (1U << DMA_IFCR_CGIF7_BIT)
+#define DMA_IFCR_CTEIF6 (1U << DMA_IFCR_CTEIF6_BIT)
+#define DMA_IFCR_CHTIF6 (1U << DMA_IFCR_CHTIF6_BIT)
+#define DMA_IFCR_CTCIF6 (1U << DMA_IFCR_CTCIF6_BIT)
+#define DMA_IFCR_CGIF6 (1U << DMA_IFCR_CGIF6_BIT)
+#define DMA_IFCR_CTEIF5 (1U << DMA_IFCR_CTEIF5_BIT)
+#define DMA_IFCR_CHTIF5 (1U << DMA_IFCR_CHTIF5_BIT)
+#define DMA_IFCR_CTCIF5 (1U << DMA_IFCR_CTCIF5_BIT)
+#define DMA_IFCR_CGIF5 (1U << DMA_IFCR_CGIF5_BIT)
+#define DMA_IFCR_CTEIF4 (1U << DMA_IFCR_CTEIF4_BIT)
+#define DMA_IFCR_CHTIF4 (1U << DMA_IFCR_CHTIF4_BIT)
+#define DMA_IFCR_CTCIF4 (1U << DMA_IFCR_CTCIF4_BIT)
+#define DMA_IFCR_CGIF4 (1U << DMA_IFCR_CGIF4_BIT)
+#define DMA_IFCR_CTEIF3 (1U << DMA_IFCR_CTEIF3_BIT)
+#define DMA_IFCR_CHTIF3 (1U << DMA_IFCR_CHTIF3_BIT)
+#define DMA_IFCR_CTCIF3 (1U << DMA_IFCR_CTCIF3_BIT)
+#define DMA_IFCR_CGIF3 (1U << DMA_IFCR_CGIF3_BIT)
+#define DMA_IFCR_CTEIF2 (1U << DMA_IFCR_CTEIF2_BIT)
+#define DMA_IFCR_CHTIF2 (1U << DMA_IFCR_CHTIF2_BIT)
+#define DMA_IFCR_CTCIF2 (1U << DMA_IFCR_CTCIF2_BIT)
+#define DMA_IFCR_CGIF2 (1U << DMA_IFCR_CGIF2_BIT)
+#define DMA_IFCR_CTEIF1 (1U << DMA_IFCR_CTEIF1_BIT)
+#define DMA_IFCR_CHTIF1 (1U << DMA_IFCR_CHTIF1_BIT)
+#define DMA_IFCR_CTCIF1 (1U << DMA_IFCR_CTCIF1_BIT)
+#define DMA_IFCR_CGIF1 (1U << DMA_IFCR_CGIF1_BIT)
+
+/* Channel configuration register */
+
+#define DMA_CCR_MEM2MEM_BIT 14
+#define DMA_CCR_MINC_BIT 7
+#define DMA_CCR_PINC_BIT 6
+#define DMA_CCR_CIRC_BIT 5
+#define DMA_CCR_DIR_BIT 4
+#define DMA_CCR_TEIE_BIT 3
+#define DMA_CCR_HTIE_BIT 2
+#define DMA_CCR_TCIE_BIT 1
+#define DMA_CCR_EN_BIT 0
+
+#define DMA_CCR_MEM2MEM (1U << DMA_CCR_MEM2MEM_BIT)
+#define DMA_CCR_PL (0x3 << 12)
+#define DMA_CCR_PL_LOW (0x0 << 12)
+#define DMA_CCR_PL_MEDIUM (0x1 << 12)
+#define DMA_CCR_PL_HIGH (0x2 << 12)
+#define DMA_CCR_PL_VERY_HIGH (0x3 << 12)
+#define DMA_CCR_MSIZE (0x3 << 10)
+#define DMA_CCR_MSIZE_8BITS (0x0 << 10)
+#define DMA_CCR_MSIZE_16BITS (0x1 << 10)
+#define DMA_CCR_MSIZE_32BITS (0x2 << 10)
+#define DMA_CCR_PSIZE (0x3 << 8)
+#define DMA_CCR_PSIZE_8BITS (0x0 << 8)
+#define DMA_CCR_PSIZE_16BITS (0x1 << 8)
+#define DMA_CCR_PSIZE_32BITS (0x2 << 8)
+#define DMA_CCR_MINC (1U << DMA_CCR_MINC_BIT)
+#define DMA_CCR_PINC (1U << DMA_CCR_PINC_BIT)
+#define DMA_CCR_CIRC (1U << DMA_CCR_CIRC_BIT)
+#define DMA_CCR_DIR (1U << DMA_CCR_DIR_BIT)
+#define DMA_CCR_DIR_FROM_PER (0U << DMA_CCR_DIR_BIT)
+#define DMA_CCR_DIR_FROM_MEM (1U << DMA_CCR_DIR_BIT)
+#define DMA_CCR_TEIE (1U << DMA_CCR_TEIE_BIT)
+#define DMA_CCR_HTIE (1U << DMA_CCR_HTIE_BIT)
+#define DMA_CCR_TCIE (1U << DMA_CCR_TCIE_BIT)
+#define DMA_CCR_EN (1U << DMA_CCR_EN_BIT)
+
+/*
+ * Devices
+ */
+
+extern dma_dev *DMA1;
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+extern dma_dev *DMA2;
+#endif
+
+/*
+ * Other types needed by, or useful for, <libmaple/dma.h>.
+ */
+
+/**
+ * @brief STM32F1 dma_tube.
+ * On STM32F1, DMA tubes are just channels.
+ */
+#define dma_tube dma_channel
+
+/**
+ * @brief On STM32F1, dma_channel_reg_map is an alias for dma_tube_reg_map.
+ * This is for backwards compatibility. */
+#define dma_channel_reg_map dma_tube_reg_map
+
+/**
+ * @brief STM32F1 configuration flags for dma_tube_config
+ * @see struct dma_tube_config
+ */
+typedef enum dma_cfg_flags {
+ /**
+ * Source address increment mode
+ *
+ * If this flag is set, the source address is incremented (by the
+ * source size) after each DMA transfer.
+ */
+ DMA_CFG_SRC_INC = 1U << 31,
+
+ /**
+ * Destination address increment mode
+ *
+ * If this flag is set, the destination address is incremented (by
+ * the destination size) after each DMA transfer.
+ */
+ DMA_CFG_DST_INC = 1U << 30,
+
+ /**
+ * Circular mode
+ *
+ * This mode is not available for memory-to-memory transfers.
+ */
+ DMA_CFG_CIRC = DMA_CCR_CIRC,
+
+ /** Transfer complete interrupt enable */
+ DMA_CFG_CMPLT_IE = DMA_CCR_TCIE,
+ /** Transfer half-complete interrupt enable */
+ DMA_CFG_HALF_CMPLT_IE = DMA_CCR_HTIE,
+ /** Transfer error interrupt enable */
+ DMA_CFG_ERR_IE = DMA_CCR_TEIE,
+} dma_cfg_flags;
+
+/**
+ * @brief STM32F1 DMA request sources.
+ *
+ * IMPORTANT:
+ *
+ * 1. On STM32F1, each dma_request_src can only be used by a
+ * particular tube on a particular DMA controller. For example,
+ * DMA_REQ_SRC_ADC1 belongs to DMA1, tube 1. DMA2 cannot serve
+ * requests from ADC1, nor can DMA1 tube 2, etc. If you try to use a
+ * request source with the wrong DMA controller or tube on STM32F1,
+ * dma_tube_cfg() will fail.
+ *
+ * 2. In general, a DMA tube can only serve a single request source at
+ * a time, and on STM32F1, Terrible Super-Bad Things will happen if
+ * two request sources are active for a single tube.
+ *
+ * To make all this easier to sort out, these dma_request_src
+ * enumerators are grouped by DMA controller and tube.
+ *
+ * @see struct dma_tube_config
+ * @see dma_tube_cfg()
+ */
+typedef enum dma_request_src {
+ /* Each request source encodes the DMA controller and channel it
+ * belongs to, for error checking in dma_tube_cfg(). */
+
+ /* DMA1 request sources */
+
+ /**@{*/
+ /** (DMA1, tube 1) */
+ DMA_REQ_SRC_ADC1 = (RCC_DMA1 << 3) | 1,
+ DMA_REQ_SRC_TIM2_CH3 = (RCC_DMA1 << 3) | 1,
+ DMA_REQ_SRC_TIM4_CH1 = (RCC_DMA1 << 3) | 1,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 2)*/
+ DMA_REQ_SRC_SPI1_RX = (RCC_DMA1 << 3) | 2,
+ DMA_REQ_SRC_USART3_TX = (RCC_DMA1 << 3) | 2,
+ DMA_REQ_SRC_TIM1_CH1 = (RCC_DMA1 << 3) | 2,
+ DMA_REQ_SRC_TIM2_UP = (RCC_DMA1 << 3) | 2,
+ DMA_REQ_SRC_TIM3_CH3 = (RCC_DMA1 << 3) | 2,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 3)*/
+ DMA_REQ_SRC_SPI1_TX = (RCC_DMA1 << 3) | 3,
+ DMA_REQ_SRC_USART3_RX = (RCC_DMA1 << 3) | 3,
+ DMA_REQ_SRC_TIM1_CH2 = (RCC_DMA1 << 3) | 3,
+ DMA_REQ_SRC_TIM3_CH4 = (RCC_DMA1 << 3) | 3,
+ DMA_REQ_SRC_TIM3_UP = (RCC_DMA1 << 3) | 3,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 4)*/
+ DMA_REQ_SRC_SPI2_RX = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_I2S2_RX = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_USART1_TX = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_I2C2_TX = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_TIM1_CH4 = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_TIM1_TRIG = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_TIM1_COM = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_TIM4_CH2 = (RCC_DMA1 << 3) | 4,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 5)*/
+ DMA_REQ_SRC_SPI2_TX = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_I2S2_TX = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_USART1_RX = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_I2C2_RX = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_TIM1_UP = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_TIM2_CH1 = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_TIM4_CH3 = (RCC_DMA1 << 3) | 5,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 6)*/
+ DMA_REQ_SRC_USART2_RX = (RCC_DMA1 << 3) | 6,
+ DMA_REQ_SRC_I2C1_TX = (RCC_DMA1 << 3) | 6,
+ DMA_REQ_SRC_TIM1_CH3 = (RCC_DMA1 << 3) | 6,
+ DMA_REQ_SRC_TIM3_CH1 = (RCC_DMA1 << 3) | 6,
+ DMA_REQ_SRC_TIM3_TRIG = (RCC_DMA1 << 3) | 6,
+ /**@}*/
+
+ /**@{*/
+ /* Tube 7 */
+ DMA_REQ_SRC_USART2_TX = (RCC_DMA1 << 3) | 7,
+ DMA_REQ_SRC_I2C1_RX = (RCC_DMA1 << 3) | 7,
+ DMA_REQ_SRC_TIM2_CH2 = (RCC_DMA1 << 3) | 7,
+ DMA_REQ_SRC_TIM2_CH4 = (RCC_DMA1 << 3) | 7,
+ DMA_REQ_SRC_TIM4_UP = (RCC_DMA1 << 3) | 7,
+ /**@}*/
+
+ /* DMA2 request sources */
+
+ /**@{*/
+ /** (DMA2, tube 1)*/
+ DMA_REQ_SRC_SPI3_RX = (RCC_DMA2 << 3) | 1,
+ DMA_REQ_SRC_I2S3_RX = (RCC_DMA2 << 3) | 1,
+ DMA_REQ_SRC_TIM5_CH4 = (RCC_DMA2 << 3) | 1,
+ DMA_REQ_SRC_TIM5_TRIG = (RCC_DMA2 << 3) | 1,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA2, tube 2)*/
+ DMA_REQ_SRC_SPI3_TX = (RCC_DMA2 << 3) | 2,
+ DMA_REQ_SRC_I2S3_TX = (RCC_DMA2 << 3) | 2,
+ DMA_REQ_SRC_TIM5_CH3 = (RCC_DMA2 << 3) | 2,
+ DMA_REQ_SRC_TIM5_UP = (RCC_DMA2 << 3) | 2,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA2, tube 3)*/
+ DMA_REQ_SRC_UART4_RX = (RCC_DMA2 << 3) | 3,
+ DMA_REQ_SRC_TIM6_UP = (RCC_DMA2 << 3) | 3,
+ DMA_REQ_SRC_DAC_CH1 = (RCC_DMA2 << 3) | 3,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA2, tube 4)*/
+ DMA_REQ_SRC_SDIO = (RCC_DMA2 << 3) | 4,
+ DMA_REQ_SRC_TIM5_CH2 = (RCC_DMA2 << 3) | 4,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA2, tube 5)*/
+ DMA_REQ_SRC_ADC3 = (RCC_DMA2 << 3) | 5,
+ DMA_REQ_SRC_UART4_TX = (RCC_DMA2 << 3) | 5,
+ DMA_REQ_SRC_TIM5_CH1 = (RCC_DMA2 << 3) | 5,
+ /**@}*/
+} dma_request_src;
+
+/*
+ * Convenience routines.
+ */
+
+/**
+ * @brief On STM32F1, dma_is_channel_enabled() is an alias for
+ * dma_is_enabled().
+ * This is for backwards compatibility.
+ */
+#define dma_is_channel_enabled dma_is_enabled
+
+#define DMA_CHANNEL_NREGS 5 /* accounts for reserved word */
+static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube) {
+ __io uint32 *ccr1 = &dev->regs->CCR1;
+ return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (tube - 1));
+}
+
+/**
+ * @brief On STM32F1, dma_channel_regs() is an alias for dma_tube_regs().
+ * This is for backwards compatibility. */
+#define dma_channel_regs(dev, ch) dma_tube_regs(dev, ch)
+
+static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube) {
+ return (uint8)(dma_tube_regs(dev, tube)->CCR & DMA_CCR_EN);
+}
+
+static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube) {
+ uint8 shift = (tube - 1) * 4;
+ return (dev->regs->ISR >> shift) & 0xF;
+}
+
+static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) {
+ dev->regs->IFCR = (1U << (4 * (tube - 1)));
+}
+
+/**
+ * @brief Deprecated
+ * STM32F1 mode flags for dma_setup_xfer(). Use dma_tube_cfg() instead.
+ * @see dma_tube_cfg()
+ */
+typedef enum dma_mode_flags {
+ DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */
+ DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */
+ DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */
+ DMA_CIRC_MODE = 1 << 5, /**< Circular mode */
+ DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */
+ DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */
+ DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */
+ DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */
+} dma_mode_flags;
+
+/* Keep this around for backwards compatibility, but it's deprecated.
+ * New code should use dma_tube_cfg() instead.
+ *
+ * (It's not possible to fully configure a DMA stream on F2 with just
+ * this information, so this interface is too tied to the F1.) */
+__deprecated
+void dma_setup_transfer(dma_dev *dev,
+ dma_channel channel,
+ __io void *peripheral_address,
+ dma_xfer_size peripheral_size,
+ __io void *memory_address,
+ dma_xfer_size memory_size,
+ uint32 mode);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/exti.h b/libmaple/stm32f1/include/series/exti.h
new file mode 100644
index 0000000..1ece664
--- /dev/null
+++ b/libmaple/stm32f1/include/series/exti.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/exti.h
+ * @brief STM32F1 external interrupts
+ */
+
+#ifndef _LIBMAPLE_STM32F1_EXTI_H_
+#define _LIBMAPLE_STM32F1_EXTI_H_
+
+#ifdef __cpluspus
+extern "C" {
+#endif
+
+struct exti_reg_map;
+#define EXTI_BASE ((struct exti_reg_map*)0x40010400)
+
+#ifdef __cpluspus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/flash.h b/libmaple/stm32f1/include/series/flash.h
new file mode 100644
index 0000000..24efb0b
--- /dev/null
+++ b/libmaple/stm32f1/include/series/flash.h
@@ -0,0 +1,149 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/flash.h
+ * @brief STM32F1 Flash header.
+ *
+ * Provides register map, base pointer, and register bit definitions
+ * for the Flash controller on the STM32F1 line, along with
+ * series-specific configuration values.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_FLASH_H_
+#define _LIBMAPLE_STM32F1_FLASH_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** @brief STM32F1 Flash register map type */
+typedef struct flash_reg_map {
+ __io uint32 ACR; /**< Access control register */
+ __io uint32 KEYR; /**< Key register */
+ __io uint32 OPTKEYR; /**< OPTKEY register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 CR; /**< Control register */
+ __io uint32 AR; /**< Address register */
+ __io uint32 OBR; /**< Option byte register */
+ __io uint32 WRPR; /**< Write protection register */
+} flash_reg_map;
+
+#define FLASH_BASE ((struct flash_reg_map*)0x40022000)
+
+/*
+ * Register bit definitions
+ */
+
+/* Access control register */
+
+#define FLASH_ACR_PRFTBS_BIT 5
+#define FLASH_ACR_PRFTBE_BIT 4
+#define FLASH_ACR_HLFCYA_BIT 3
+
+#define FLASH_ACR_PRFTBS (1U << FLASH_ACR_PRFTBS_BIT)
+#define FLASH_ACR_PRFTBE (1U << FLASH_ACR_PRFTBE_BIT)
+#define FLASH_ACR_HLFCYA (1U << FLASH_ACR_HLFCYA_BIT)
+#define FLASH_ACR_LATENCY 0x7
+
+/* Status register */
+
+#define FLASH_SR_EOP_BIT 5
+#define FLASH_SR_WRPRTERR_BIT 4
+#define FLASH_SR_PGERR_BIT 2
+#define FLASH_SR_BSY_BIT 0
+
+#define FLASH_SR_EOP (1U << FLASH_SR_EOP_BIT)
+#define FLASH_SR_WRPRTERR (1U << FLASH_SR_WRPRTERR_BIT)
+#define FLASH_SR_PGERR (1U << FLASH_SR_PGERR_BIT)
+#define FLASH_SR_BSY (1U << FLASH_SR_BSY_BIT)
+
+/* Control register */
+
+#define FLASH_CR_EOPIE_BIT 12
+#define FLASH_CR_ERRIE_BIT 10
+#define FLASH_CR_OPTWRE_BIT 9
+#define FLASH_CR_LOCK_BIT 7
+#define FLASH_CR_STRT_BIT 6
+#define FLASH_CR_OPTER_BIT 5
+#define FLASH_CR_OPTPG_BIT 4
+#define FLASH_CR_MER_BIT 2
+#define FLASH_CR_PER_BIT 1
+#define FLASH_CR_PG_BIT 0
+
+#define FLASH_CR_EOPIE (1U << FLASH_CR_EOPIE_BIT)
+#define FLASH_CR_ERRIE (1U << FLASH_CR_ERRIE_BIT)
+#define FLASH_CR_OPTWRE (1U << FLASH_CR_OPTWRE_BIT)
+#define FLASH_CR_LOCK (1U << FLASH_CR_LOCK_BIT)
+#define FLASH_CR_STRT (1U << FLASH_CR_STRT_BIT)
+#define FLASH_CR_OPTER (1U << FLASH_CR_OPTER_BIT)
+#define FLASH_CR_OPTPG (1U << FLASH_CR_OPTPG_BIT)
+#define FLASH_CR_MER (1U << FLASH_CR_MER_BIT)
+#define FLASH_CR_PER (1U << FLASH_CR_PER_BIT)
+#define FLASH_CR_PG (1U << FLASH_CR_PG_BIT)
+
+/* Option byte register */
+
+#define FLASH_OBR_nRST_STDBY_BIT 4
+#define FLASH_OBR_nRST_STOP_BIT 3
+#define FLASH_OBR_WDG_SW_BIT 2
+#define FLASH_OBR_RDPRT_BIT 1
+#define FLASH_OBR_OPTERR_BIT 0
+
+#define FLASH_OBR_DATA1 (0xFF << 18)
+#define FLASH_OBR_DATA0 (0xFF << 10)
+#define FLASH_OBR_USER 0x3FF
+#define FLASH_OBR_nRST_STDBY (1U << FLASH_OBR_nRST_STDBY_BIT)
+#define FLASH_OBR_nRST_STOP (1U << FLASH_OBR_nRST_STOP_BIT)
+#define FLASH_OBR_WDG_SW (1U << FLASH_OBR_WDG_SW_BIT)
+#define FLASH_OBR_RDPRT (1U << FLASH_OBR_RDPRT_BIT)
+#define FLASH_OBR_OPTERR (1U << FLASH_OBR_OPTERR_BIT)
+
+/*
+ * Series-specific configuration values.
+ */
+
+#define FLASH_SAFE_WAIT_STATES FLASH_WAIT_STATE_2
+
+/* Flash memory features available via ACR */
+enum {
+ FLASH_PREFETCH = 0x10,
+ FLASH_HALF_CYCLE = 0x8,
+ FLASH_ICACHE = 0x0, /* Not available on STM32F1 */
+ FLASH_DCACHE = 0x0, /* Not available on STM32F1 */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/gpio.h b/libmaple/stm32f1/include/series/gpio.h
new file mode 100644
index 0000000..aecf911
--- /dev/null
+++ b/libmaple/stm32f1/include/series/gpio.h
@@ -0,0 +1,493 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+*****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/gpio.h
+ * @brief STM32F1 GPIO and AFIO support.
+ * General purpose I/O (GPIO) and Alternate Function I/O (AFIO).
+ */
+
+#ifndef _LIBMAPLE_STM32F1_GPIO_H_
+#define _LIBMAPLE_STM32F1_GPIO_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/stm32.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/exti.h>
+
+/*
+ * GPIO register maps and devices
+ */
+
+/** GPIO register map type */
+typedef struct gpio_reg_map {
+ __io uint32 CRL; /**< Port configuration register low */
+ __io uint32 CRH; /**< Port configuration register high */
+ __io uint32 IDR; /**< Port input data register */
+ __io uint32 ODR; /**< Port output data register */
+ __io uint32 BSRR; /**< Port bit set/reset register */
+ __io uint32 BRR; /**< Port bit reset register */
+ __io uint32 LCKR; /**< Port configuration lock register */
+} gpio_reg_map;
+
+struct gpio_dev;
+extern struct gpio_dev gpioa;
+extern struct gpio_dev* const GPIOA;
+extern struct gpio_dev gpiob;
+extern struct gpio_dev* const GPIOB;
+extern struct gpio_dev gpioc;
+extern struct gpio_dev* const GPIOC;
+extern struct gpio_dev gpiod;
+extern struct gpio_dev* const GPIOD;
+#ifdef STM32_HIGH_DENSITY
+extern struct gpio_dev gpioe;
+extern struct gpio_dev* const GPIOE;
+extern struct gpio_dev gpiof;
+extern struct gpio_dev* const GPIOF;
+extern struct gpio_dev gpiog;
+extern struct gpio_dev* const GPIOG;
+#endif
+
+/** GPIO port A register map base pointer */
+#define GPIOA_BASE ((struct gpio_reg_map*)0x40010800)
+/** GPIO port B register map base pointer */
+#define GPIOB_BASE ((struct gpio_reg_map*)0x40010C00)
+/** GPIO port C register map base pointer */
+#define GPIOC_BASE ((struct gpio_reg_map*)0x40011000)
+/** GPIO port D register map base pointer */
+#define GPIOD_BASE ((struct gpio_reg_map*)0x40011400)
+/** GPIO port E register map base pointer */
+#define GPIOE_BASE ((struct gpio_reg_map*)0x40011800)
+/** GPIO port F register map base pointer */
+#define GPIOF_BASE ((struct gpio_reg_map*)0x40011C00)
+/** GPIO port G register map base pointer */
+#define GPIOG_BASE ((struct gpio_reg_map*)0x40012000)
+
+/*
+ * GPIO register bit definitions
+ */
+
+/* Control registers, low and high */
+
+#define GPIO_CR_CNF (0x3 << 2)
+#define GPIO_CR_CNF_INPUT_ANALOG (0x0 << 2)
+#define GPIO_CR_CNF_INPUT_FLOATING (0x1 << 2)
+#define GPIO_CR_CNF_INPUT_PU_PD (0x2 << 2)
+#define GPIO_CR_CNF_OUTPUT_PP (0x0 << 2)
+#define GPIO_CR_CNF_OUTPUT_OD (0x1 << 2)
+#define GPIO_CR_CNF_AF_OUTPUT_PP (0x2 << 2)
+#define GPIO_CR_CNF_AF_OUTPUT_OD (0x3 << 2)
+#define GPIO_CR_MODE 0x3
+#define GPIO_CR_MODE_INPUT 0x0
+#define GPIO_CR_MODE_OUTPUT_10MHZ 0x1
+#define GPIO_CR_MODE_OUTPUT_2MHZ 0x2
+#define GPIO_CR_MODE_OUTPUT_50MHZ 0x3
+
+/**
+ * @brief GPIO pin modes.
+ *
+ * These only allow for 50MHZ max output speeds; if you want slower,
+ * use direct register access.
+ */
+typedef enum gpio_pin_mode {
+ /** Output push-pull. */
+ GPIO_OUTPUT_PP = GPIO_CR_CNF_OUTPUT_PP | GPIO_CR_MODE_OUTPUT_50MHZ,
+ /** Output open-drain. */
+ GPIO_OUTPUT_OD = GPIO_CR_CNF_OUTPUT_OD | GPIO_CR_MODE_OUTPUT_50MHZ,
+ /** Alternate function output push-pull. */
+ GPIO_AF_OUTPUT_PP = GPIO_CR_CNF_AF_OUTPUT_PP | GPIO_CR_MODE_OUTPUT_50MHZ,
+ /** Alternate function output open drain. */
+ GPIO_AF_OUTPUT_OD = GPIO_CR_CNF_AF_OUTPUT_OD | GPIO_CR_MODE_OUTPUT_50MHZ,
+ /** Analog input. */
+ GPIO_INPUT_ANALOG = GPIO_CR_CNF_INPUT_ANALOG | GPIO_CR_MODE_INPUT,
+ /** Input floating. */
+ GPIO_INPUT_FLOATING = GPIO_CR_CNF_INPUT_FLOATING | GPIO_CR_MODE_INPUT,
+ /** Input pull-down. */
+ GPIO_INPUT_PD = GPIO_CR_CNF_INPUT_PU_PD | GPIO_CR_MODE_INPUT,
+ /** Input pull-up. */
+ GPIO_INPUT_PU, /* (treated a special case, for ODR twiddling) */
+} gpio_pin_mode;
+
+/* Hacks for F2: */
+#define GPIO_MODE_ANALOG GPIO_INPUT_ANALOG
+#define GPIO_MODE_OUTPUT GPIO_OUTPUT_PP
+
+/*
+ * AFIO register map
+ */
+
+/** AFIO register map */
+typedef struct afio_reg_map {
+ __io uint32 EVCR; /**< Event control register. */
+ __io uint32 MAPR; /**< AF remap and debug I/O configuration register. */
+ __io uint32 EXTICR1; /**< External interrupt configuration register 1. */
+ __io uint32 EXTICR2; /**< External interrupt configuration register 2. */
+ __io uint32 EXTICR3; /**< External interrupt configuration register 3. */
+ __io uint32 EXTICR4; /**< External interrupt configuration register 4. */
+ __io uint32 MAPR2; /**<
+ * AF remap and debug I/O configuration register 2. */
+} afio_reg_map;
+
+/** AFIO register map base pointer. */
+#define AFIO_BASE ((struct afio_reg_map *)0x40010000)
+
+/*
+ * AFIO register bit definitions
+ */
+
+/* Event control register */
+
+#define AFIO_EVCR_EVOE (0x1 << 7)
+#define AFIO_EVCR_PORT_PA (0x0 << 4)
+#define AFIO_EVCR_PORT_PB (0x1 << 4)
+#define AFIO_EVCR_PORT_PC (0x2 << 4)
+#define AFIO_EVCR_PORT_PD (0x3 << 4)
+#define AFIO_EVCR_PORT_PE (0x4 << 4)
+#define AFIO_EVCR_PIN_0 0x0
+#define AFIO_EVCR_PIN_1 0x1
+#define AFIO_EVCR_PIN_2 0x2
+#define AFIO_EVCR_PIN_3 0x3
+#define AFIO_EVCR_PIN_4 0x4
+#define AFIO_EVCR_PIN_5 0x5
+#define AFIO_EVCR_PIN_6 0x6
+#define AFIO_EVCR_PIN_7 0x7
+#define AFIO_EVCR_PIN_8 0x8
+#define AFIO_EVCR_PIN_9 0x9
+#define AFIO_EVCR_PIN_10 0xA
+#define AFIO_EVCR_PIN_11 0xB
+#define AFIO_EVCR_PIN_12 0xC
+#define AFIO_EVCR_PIN_13 0xD
+#define AFIO_EVCR_PIN_14 0xE
+#define AFIO_EVCR_PIN_15 0xF
+
+/* AF remap and debug I/O configuration register */
+
+#define AFIO_MAPR_SWJ_CFG (0x7 << 24)
+#define AFIO_MAPR_SWJ_CFG_FULL_SWJ (0x0 << 24)
+#define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24)
+#define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24)
+#define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24)
+#define AFIO_MAPR_ADC2_ETRGREG_REMAP (1U << 20)
+#define AFIO_MAPR_ADC2_ETRGINJ_REMAP (1U << 19)
+#define AFIO_MAPR_ADC1_ETRGREG_REMAP (1U << 18)
+#define AFIO_MAPR_ADC1_ETRGINJ_REMAP (1U << 17)
+#define AFIO_MAPR_TIM5CH4_IREMAP (1U << 16)
+#define AFIO_MAPR_PD01_REMAP (1U << 15)
+#define AFIO_MAPR_CAN_REMAP (0x3 << 13)
+#define AFIO_MAPR_CAN_REMAP_NONE (0x0 << 13)
+#define AFIO_MAPR_CAN_REMAP_PB8_PB9 (0x2 << 13)
+#define AFIO_MAPR_CAN_REMAP_PD0_PD1 (0x3 << 13)
+#define AFIO_MAPR_TIM4_REMAP (1U << 12)
+#define AFIO_MAPR_TIM3_REMAP (0x3 << 10)
+#define AFIO_MAPR_TIM3_REMAP_NONE (0x0 << 10)
+#define AFIO_MAPR_TIM3_REMAP_PARTIAL (0x2 << 10)
+#define AFIO_MAPR_TIM3_REMAP_FULL (0x3 << 10)
+#define AFIO_MAPR_TIM2_REMAP (0x3 << 8)
+#define AFIO_MAPR_TIM2_REMAP_NONE (0x0 << 8)
+#define AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3 (0x1 << 8)
+#define AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11 (0x2 << 8)
+#define AFIO_MAPR_TIM2_REMAP_FULL (0x3 << 8)
+#define AFIO_MAPR_TIM1_REMAP (0x3 << 6)
+#define AFIO_MAPR_TIM1_REMAP_NONE (0x0 << 6)
+#define AFIO_MAPR_TIM1_REMAP_PARTIAL (0x1 << 6)
+#define AFIO_MAPR_TIM1_REMAP_FULL (0x3 << 6)
+#define AFIO_MAPR_USART3_REMAP (0x3 << 4)
+#define AFIO_MAPR_USART3_REMAP_NONE (0x0 << 4)
+#define AFIO_MAPR_USART3_REMAP_PARTIAL (0x1 << 4)
+#define AFIO_MAPR_USART3_REMAP_FULL (0x3 << 4)
+#define AFIO_MAPR_USART2_REMAP (1U << 3)
+#define AFIO_MAPR_USART1_REMAP (1U << 2)
+#define AFIO_MAPR_I2C1_REMAP (1U << 1)
+#define AFIO_MAPR_SPI1_REMAP (1U << 0)
+
+/* External interrupt configuration register 1 */
+
+#define AFIO_EXTICR1_EXTI3 (0xF << 12)
+#define AFIO_EXTICR1_EXTI3_PA (0x0 << 12)
+#define AFIO_EXTICR1_EXTI3_PB (0x1 << 12)
+#define AFIO_EXTICR1_EXTI3_PC (0x2 << 12)
+#define AFIO_EXTICR1_EXTI3_PD (0x3 << 12)
+#define AFIO_EXTICR1_EXTI3_PE (0x4 << 12)
+#define AFIO_EXTICR1_EXTI3_PF (0x5 << 12)
+#define AFIO_EXTICR1_EXTI3_PG (0x6 << 12)
+#define AFIO_EXTICR1_EXTI2 (0xF << 8)
+#define AFIO_EXTICR1_EXTI2_PA (0x0 << 8)
+#define AFIO_EXTICR1_EXTI2_PB (0x1 << 8)
+#define AFIO_EXTICR1_EXTI2_PC (0x2 << 8)
+#define AFIO_EXTICR1_EXTI2_PD (0x3 << 8)
+#define AFIO_EXTICR1_EXTI2_PE (0x4 << 8)
+#define AFIO_EXTICR1_EXTI2_PF (0x5 << 8)
+#define AFIO_EXTICR1_EXTI2_PG (0x6 << 8)
+#define AFIO_EXTICR1_EXTI1 (0xF << 4)
+#define AFIO_EXTICR1_EXTI1_PA (0x0 << 4)
+#define AFIO_EXTICR1_EXTI1_PB (0x1 << 4)
+#define AFIO_EXTICR1_EXTI1_PC (0x2 << 4)
+#define AFIO_EXTICR1_EXTI1_PD (0x3 << 4)
+#define AFIO_EXTICR1_EXTI1_PE (0x4 << 4)
+#define AFIO_EXTICR1_EXTI1_PF (0x5 << 4)
+#define AFIO_EXTICR1_EXTI1_PG (0x6 << 4)
+#define AFIO_EXTICR1_EXTI0 0xF
+#define AFIO_EXTICR1_EXTI0_PA 0x0
+#define AFIO_EXTICR1_EXTI0_PB 0x1
+#define AFIO_EXTICR1_EXTI0_PC 0x2
+#define AFIO_EXTICR1_EXTI0_PD 0x3
+#define AFIO_EXTICR1_EXTI0_PE 0x4
+#define AFIO_EXTICR1_EXTI0_PF 0x5
+#define AFIO_EXTICR1_EXTI0_PG 0x6
+
+/* External interrupt configuration register 2 */
+
+#define AFIO_EXTICR2_EXTI7 (0xF << 12)
+#define AFIO_EXTICR2_EXTI7_PA (0x0 << 12)
+#define AFIO_EXTICR2_EXTI7_PB (0x1 << 12)
+#define AFIO_EXTICR2_EXTI7_PC (0x2 << 12)
+#define AFIO_EXTICR2_EXTI7_PD (0x3 << 12)
+#define AFIO_EXTICR2_EXTI7_PE (0x4 << 12)
+#define AFIO_EXTICR2_EXTI7_PF (0x5 << 12)
+#define AFIO_EXTICR2_EXTI7_PG (0x6 << 12)
+#define AFIO_EXTICR2_EXTI6 (0xF << 8)
+#define AFIO_EXTICR2_EXTI6_PA (0x0 << 8)
+#define AFIO_EXTICR2_EXTI6_PB (0x1 << 8)
+#define AFIO_EXTICR2_EXTI6_PC (0x2 << 8)
+#define AFIO_EXTICR2_EXTI6_PD (0x3 << 8)
+#define AFIO_EXTICR2_EXTI6_PE (0x4 << 8)
+#define AFIO_EXTICR2_EXTI6_PF (0x5 << 8)
+#define AFIO_EXTICR2_EXTI6_PG (0x6 << 8)
+#define AFIO_EXTICR2_EXTI5 (0xF << 4)
+#define AFIO_EXTICR2_EXTI5_PA (0x0 << 4)
+#define AFIO_EXTICR2_EXTI5_PB (0x1 << 4)
+#define AFIO_EXTICR2_EXTI5_PC (0x2 << 4)
+#define AFIO_EXTICR2_EXTI5_PD (0x3 << 4)
+#define AFIO_EXTICR2_EXTI5_PE (0x4 << 4)
+#define AFIO_EXTICR2_EXTI5_PF (0x5 << 4)
+#define AFIO_EXTICR2_EXTI5_PG (0x6 << 4)
+#define AFIO_EXTICR2_EXTI4 0xF
+#define AFIO_EXTICR2_EXTI4_PA 0x0
+#define AFIO_EXTICR2_EXTI4_PB 0x1
+#define AFIO_EXTICR2_EXTI4_PC 0x2
+#define AFIO_EXTICR2_EXTI4_PD 0x3
+#define AFIO_EXTICR2_EXTI4_PE 0x4
+#define AFIO_EXTICR2_EXTI4_PF 0x5
+#define AFIO_EXTICR2_EXTI4_PG 0x6
+
+/* AF remap and debug I/O configuration register 2 */
+
+#define AFIO_MAPR2_FSMC_NADV (1U << 10)
+#define AFIO_MAPR2_TIM14_REMAP (1U << 9)
+#define AFIO_MAPR2_TIM13_REMAP (1U << 8)
+#define AFIO_MAPR2_TIM11_REMAP (1U << 7)
+#define AFIO_MAPR2_TIM10_REMAP (1U << 6)
+#define AFIO_MAPR2_TIM9_REMAP (1U << 5)
+
+/*
+ * AFIO convenience routines
+ */
+
+void afio_init(void);
+
+/* HACK: Use upper bit to denote MAPR2, Bit 31 is reserved and
+ * not used in either MAPR or MAPR2 */
+#define AFIO_REMAP_USE_MAPR2 (1U << 31)
+
+/**
+ * @brief Available peripheral remaps.
+ * @see afio_remap()
+ */
+typedef enum afio_remap_peripheral {
+ /** ADC 2 external trigger regular conversion remapping */
+ AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP,
+ /** ADC 2 external trigger injected conversion remapping */
+ AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP,
+ /** ADC 1 external trigger regular conversion remapping */
+ AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP,
+ /** ADC 1 external trigger injected conversion remapping */
+ AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP,
+ /** Timer 5 channel 4 internal remapping */
+ AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP,
+ /** Port D0/Port D1 mapping on OSC_IN/OSC_OUT */
+ AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP,
+ /** CAN alternate function remapping 1 (RX on PB8, TX on PB9) */
+ AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9,
+ /** CAN alternate function remapping 2 (RX on PD0, TX on PD1) */
+ AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1,
+ /** Timer 4 remapping */
+ AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP,
+ /** Timer 3 partial remapping */
+ AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL,
+ /** Timer 3 full remapping */
+ AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL,
+ /**
+ * Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3,
+ * CH3 on PA2, CH4 on PA3) */
+ AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3,
+ /**
+ * Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1,
+ * CH3 on PB10, CH4 on PB11) */
+ AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11,
+ /** Timer 2 full remapping */
+ AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL,
+ /** USART 2 remapping */
+ AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP,
+ /** USART 1 remapping */
+ AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP,
+ /** I2C 1 remapping */
+ AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP,
+ /** SPI 1 remapping */
+ AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP,
+ /** NADV signal not connected */
+ AFIO_REMAP_FSMC_NADV = AFIO_MAPR2_FSMC_NADV | AFIO_REMAP_USE_MAPR2,
+ /** Timer 14 remapping */
+ AFIO_REMAP_TIM14 = AFIO_MAPR2_TIM14_REMAP | AFIO_REMAP_USE_MAPR2,
+ /** Timer 13 remapping */
+ AFIO_REMAP_TIM13 = AFIO_MAPR2_TIM13_REMAP | AFIO_REMAP_USE_MAPR2,
+ /** Timer 11 remapping */
+ AFIO_REMAP_TIM11 = AFIO_MAPR2_TIM11_REMAP | AFIO_REMAP_USE_MAPR2,
+ /** Timer 10 remapping */
+ AFIO_REMAP_TIM10 = AFIO_MAPR2_TIM10_REMAP | AFIO_REMAP_USE_MAPR2,
+ /** Timer 9 remapping */
+ AFIO_REMAP_TIM9 = AFIO_MAPR2_TIM9_REMAP | AFIO_REMAP_USE_MAPR2,
+} afio_remap_peripheral;
+
+void afio_remap(afio_remap_peripheral p);
+
+/**
+ * @brief Debug port configuration
+ *
+ * Used to configure the behavior of JTAG and Serial Wire (SW) debug
+ * ports and their associated GPIO pins.
+ *
+ * @see afio_cfg_debug_ports()
+ */
+typedef enum afio_debug_cfg {
+ /** Full Serial Wire and JTAG debug */
+ AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ,
+ /** Full Serial Wire and JTAG, but no NJTRST. */
+ AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST,
+ /** Serial Wire debug only (JTAG-DP disabled, SW-DP enabled) */
+ AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW,
+ /** No debug; all JTAG and SW pins are free for use as GPIOs. */
+ AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW,
+} afio_debug_cfg;
+
+/**
+ * @brief Enable or disable the JTAG and SW debug ports.
+ * @param config Desired debug port configuration
+ * @see afio_debug_cfg
+ */
+static inline void afio_cfg_debug_ports(afio_debug_cfg config) {
+ __io uint32 *mapr = &AFIO_BASE->MAPR;
+ *mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config;
+}
+
+/*
+ * Deprecated bits
+ */
+
+/**
+ * @brief Deprecated. Use exti_cfg instead.
+ *
+ * In previous versions of libmaple, exti_attach_interrupt() took an
+ * afio_exti_port argument; afio_exti_port was also a member of struct
+ * gpio_dev. This isn't portable, so we now use exti_cfg
+ * instead. This typedef (and the macros AFIO_EXTI_PA, ...,
+ * AFIO_EXTI_PG) exist to preserve backwards compatibility.
+ */
+typedef exti_cfg afio_exti_port;
+
+/** Deprecated. Use EXTI_PA instead. */
+#define AFIO_EXTI_PA EXTI_PA
+/** Deprecated. Use EXTI_PB instead. */
+#define AFIO_EXTI_PB EXTI_PB
+/** Deprecated. Use EXTI_PC instead. */
+#define AFIO_EXTI_PC EXTI_PC
+/** Deprecated. Use EXTI_PD instead. */
+#define AFIO_EXTI_PD EXTI_PD
+/** Deprecated. Use EXTI_PE instead. */
+#define AFIO_EXTI_PE EXTI_PE
+/** Deprecated. Use EXTI_PF instead. */
+#define AFIO_EXTI_PF EXTI_PF
+/** Deprecated. Use EXTI_PG instead. */
+#define AFIO_EXTI_PG EXTI_PG
+
+/**
+ * @brief Deprecated. Use exti_num instead.
+ *
+ * In previous versions of libmaple, exti_attach_interrupt() took an
+ * afio_exti_num argument. This isn't portable, so we use exti_num
+ * instead. This typedef (and the macros AFIO_EXTI_0, ...,
+ * AFIO_EXTI_15) exist to preserve backwards compatibility.
+ */
+typedef exti_num afio_exti_num;
+
+/** Deprecated. Use EXTI0 instead. */
+#define AFIO_EXTI_0 EXTI0
+/** Deprecated. Use EXTI1 instead. */
+#define AFIO_EXTI_1 EXTI1
+/** Deprecated. Use EXTI2 instead. */
+#define AFIO_EXTI_2 EXTI2
+/** Deprecated. Use EXTI3 instead. */
+#define AFIO_EXTI_3 EXTI3
+/** Deprecated. Use EXTI4 instead. */
+#define AFIO_EXTI_4 EXTI4
+/** Deprecated. Use EXTI5 instead. */
+#define AFIO_EXTI_5 EXTI5
+/** Deprecated. Use EXTI6 instead. */
+#define AFIO_EXTI_6 EXTI6
+/** Deprecated. Use EXTI7 instead. */
+#define AFIO_EXTI_7 EXTI7
+/** Deprecated. Use EXTI8 instead. */
+#define AFIO_EXTI_8 EXTI8
+/** Deprecated. Use EXTI9 instead. */
+#define AFIO_EXTI_9 EXTI9
+/** Deprecated. Use EXTI10 instead. */
+#define AFIO_EXTI_10 EXTI10
+/** Deprecated. Use EXTI11 instead. */
+#define AFIO_EXTI_11 EXTI11
+/** Deprecated. Use EXTI12 instead. */
+#define AFIO_EXTI_12 EXTI12
+/** Deprecated. Use EXTI13 instead. */
+#define AFIO_EXTI_13 EXTI13
+/** Deprecated. Use EXTI14 instead. */
+#define AFIO_EXTI_14 EXTI14
+/** Deprecated. Use EXTI15 instead. */
+#define AFIO_EXTI_15 EXTI15
+
+/**
+ * @brief Deprecated. Use exti_select(exti, port) instead.
+ */
+static __always_inline void afio_exti_select(exti_num exti, exti_cfg port) {
+ exti_select(exti, port);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/i2c.h b/libmaple/stm32f1/include/series/i2c.h
new file mode 100644
index 0000000..f407955
--- /dev/null
+++ b/libmaple/stm32f1/include/series/i2c.h
@@ -0,0 +1,85 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung (from <libmaple/i2c.h>).
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/i2c.h
+ * @brief STM32F1 I2C
+ */
+
+#ifndef _LIBMAPLE_STM32F1_I2C_H_
+#define _LIBMAPLE_STM32F1_I2C_H_
+
+#include <libmaple/i2c_common.h>
+#include <libmaple/gpio.h>
+#include <libmaple/stm32.h>
+
+/*
+ * Register maps
+ */
+
+struct i2c_reg_map;
+
+/** STM32F1 I2C1 register map base pointer */
+#define I2C1_BASE ((struct i2c_reg_map*)0x40005400)
+/** STM32F1 I2C2 register map base pointer */
+#define I2C2_BASE ((struct i2c_reg_map*)0x40005800)
+
+/*
+ * Devices
+ */
+
+extern i2c_dev* const I2C1;
+extern i2c_dev* const I2C2;
+
+/*
+ * For internal use
+ */
+
+static inline uint32 _i2c_bus_clk(i2c_dev *dev) {
+ /* Both I2C peripherals are on APB1 */
+ return STM32_PCLK1 / (1000 * 1000);
+}
+
+#define _I2C_HAVE_IRQ_FIXUP 1
+void _i2c_irq_priority_fixup(i2c_dev *dev);
+
+/*
+ * Deprecated functionality
+ */
+
+/* Flag to use alternate pin mapping in i2c_master_enable(). */
+#define _I2C_HAVE_DEPRECATED_I2C_REMAP 1
+#define I2C_REMAP 0x4
+static inline void _i2c_handle_remap(i2c_dev *dev, uint32 flags) {
+ if ((dev == I2C1) && (flags & I2C_REMAP)) {
+ afio_remap(AFIO_REMAP_I2C1);
+ I2C1->sda_pin = 9;
+ I2C1->scl_pin = 8;
+ }
+}
+
+#endif /* _LIBMAPLE_STM32F1_I2C_H_ */
diff --git a/libmaple/stm32f1/include/series/nvic.h b/libmaple/stm32f1/include/series/nvic.h
new file mode 100644
index 0000000..cdac737
--- /dev/null
+++ b/libmaple/stm32f1/include/series/nvic.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/nvic.h
+ * @brief STM32F1 Nested Vectored Interrupt Controller (NVIC) support.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_NVIC_H_
+#define _LIBMAPLE_STM32F1_NVIC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.h>
+
+/**
+ * @brief STM32F1 interrupt vector table interrupt numbers.
+ * @see <libmaple/scb.h>
+ */
+typedef enum nvic_irq_num {
+ NVIC_NMI = -14, /**< Non-maskable interrupt */
+ NVIC_HARDFAULT = -13, /**< Hard fault (all class of fault) */
+ NVIC_MEM_MANAGE = -12, /**< Memory management */
+ NVIC_BUS_FAULT = -11, /**< Bus fault: prefetch fault, memory
+ access fault. */
+ NVIC_USAGE_FAULT = -10, /**< Usage fault: Undefined instruction or
+ illegal state. */
+ NVIC_SVC = -5, /**< System service call via SWI insruction */
+ NVIC_DEBUG_MON = -4, /**< Debug monitor */
+ NVIC_PEND_SVC = -2, /**< Pendable request for system service */
+ NVIC_SYSTICK = -1, /**< System tick timer */
+ NVIC_WWDG = 0, /**< Window watchdog interrupt */
+ NVIC_PVD = 1, /**< PVD through EXTI line detection */
+ NVIC_TAMPER = 2, /**< Tamper */
+ NVIC_RTC = 3, /**< Real-time clock */
+ NVIC_FLASH = 4, /**< Flash */
+ NVIC_RCC = 5, /**< Reset and clock control */
+ NVIC_EXTI0 = 6, /**< EXTI line 0 */
+ NVIC_EXTI1 = 7, /**< EXTI line 1 */
+ NVIC_EXTI2 = 8, /**< EXTI line 2 */
+ NVIC_EXTI3 = 9, /**< EXTI line 3 */
+ NVIC_EXTI4 = 10, /**< EXTI line 4 */
+ NVIC_DMA_CH1 = 11, /**< DMA1 channel 1 */
+ NVIC_DMA_CH2 = 12, /**< DMA1 channel 2 */
+ NVIC_DMA_CH3 = 13, /**< DMA1 channel 3 */
+ NVIC_DMA_CH4 = 14, /**< DMA1 channel 4 */
+ NVIC_DMA_CH5 = 15, /**< DMA1 channel 5 */
+ NVIC_DMA_CH6 = 16, /**< DMA1 channel 6 */
+ NVIC_DMA_CH7 = 17, /**< DMA1 channel 7 */
+ NVIC_ADC_1_2 = 18, /**< ADC1 and ADC2 */
+ NVIC_USB_HP_CAN_TX = 19, /**< USB high priority or CAN TX */
+ NVIC_USB_LP_CAN_RX0 = 20, /**< USB low priority or CAN RX0 */
+ NVIC_CAN_RX1 = 21, /**< CAN RX1 */
+ NVIC_CAN_SCE = 22, /**< CAN SCE */
+ NVIC_EXTI_9_5 = 23, /**< EXTI line [9:5] */
+ NVIC_TIMER1_BRK_TIMER9 = 24, /**< Timer 1 break, Timer 9. */
+ NVIC_TIMER1_UP_TIMER10 = 25, /**< Timer 1 update, Timer 10. */
+ NVIC_TIMER1_TRG_COM_TIMER11 = 26, /**<
+ * Timer 1 trigger and commutation,
+ * Timer 11. */
+ NVIC_TIMER1_CC = 27, /**< Timer 1 capture/compare */
+ NVIC_TIMER2 = 28, /**< Timer 2 */
+ NVIC_TIMER3 = 29, /**< Timer 3 */
+ NVIC_TIMER4 = 30, /**< Timer 4 */
+ NVIC_I2C1_EV = 31, /**< I2C1 event */
+ NVIC_I2C1_ER = 32, /**< I2C1 error */
+ NVIC_I2C2_EV = 33, /**< I2C2 event */
+ NVIC_I2C2_ER = 34, /**< I2C2 error */
+ NVIC_SPI1 = 35, /**< SPI1 */
+ NVIC_SPI2 = 36, /**< SPI2 */
+ NVIC_USART1 = 37, /**< USART1 */
+ NVIC_USART2 = 38, /**< USART2 */
+ NVIC_USART3 = 39, /**< USART3 */
+ NVIC_EXTI_15_10 = 40, /**< EXTI line [15:10] */
+ NVIC_RTCALARM = 41, /**< RTC alarm through EXTI line */
+ NVIC_USBWAKEUP = 42, /**< USB wakeup from suspend through
+ EXTI line */
+ NVIC_TIMER8_BRK_TIMER12 = 43, /**< Timer 8 break, timer 12 */
+ NVIC_TIMER8_UP_TIMER13 = 44, /**< Timer 8 update, timer 13 */
+ NVIC_TIMER8_TRG_COM_TIMER14 = 45, /**<
+ * Timer 8 trigger and commutation,
+ * Timer 14. */
+ NVIC_TIMER8_CC = 46, /**< Timer 8 capture/compare */
+ NVIC_ADC3 = 47, /**< ADC3 */
+ NVIC_FSMC = 48, /**< FSMC */
+ NVIC_SDIO = 49, /**< SDIO */
+ NVIC_TIMER5 = 50, /**< Timer 5 */
+ NVIC_SPI3 = 51, /**< SPI3 */
+ NVIC_UART4 = 52, /**< UART4 */
+ NVIC_UART5 = 53, /**< UART5 */
+ NVIC_TIMER6 = 54, /**< Timer 6 */
+ NVIC_TIMER7 = 55, /**< Timer 7 */
+ NVIC_DMA2_CH1 = 56, /**< DMA2 channel 1 */
+ NVIC_DMA2_CH2 = 57, /**< DMA2 channel 2 */
+ NVIC_DMA2_CH3 = 58, /**< DMA2 channel 3 */
+ NVIC_DMA2_CH_4_5 = 59, /**< DMA2 channels 4 and 5 */
+
+ /* Old enumerators kept around for backwards compatibility: */
+ NVIC_TIMER1_BRK =
+ NVIC_TIMER1_BRK_TIMER9, /**< @brief (Deprecated) Timer 1 break
+ *
+ * For backwards compatibility only.
+ * Use NVIC_TIMER1_BRK_TIMER9 instead. */
+ NVIC_TIMER1_UP =
+ NVIC_TIMER1_UP_TIMER10, /**< @brief (Deprecated) Timer 1 update.
+ *
+ * For backwards compatibility only.
+ * Use NVIC_TIMER1_UP_TIMER10 instead. */
+ NVIC_TIMER1_TRG_COM =
+ NVIC_TIMER1_TRG_COM_TIMER11, /**< @brief (deprecated) Timer 1 trigger
+ * and commutation.
+ *
+ * For backwards compatibility only.
+ * Use NVIC_TIMER1_TRG_COM_TIMER11
+ * instead. */
+ NVIC_TIMER8_BRK =
+ NVIC_TIMER8_BRK_TIMER12, /**< @brief (deprecated) Timer 8 break
+ *
+ * For backwards compatibility only.
+ * Use NVIC_TIMER8_BRK_TIMER12 instead. */
+ NVIC_TIMER8_UP =
+ NVIC_TIMER8_UP_TIMER13, /**< @brief (deprecated) Timer 8 update
+ * For backwards compatibility only.
+ * Use NVIC_TIMER8_UP_TIMER13 instead. */
+ NVIC_TIMER8_TRG_COM =
+ NVIC_TIMER8_TRG_COM_TIMER14, /**< @brief (deprecated) Timer 8 trigger
+ * and commutation.
+ * For backwards compatibility only.
+ * Use NVIC_TIMER8_TRG_COM_TIMER14
+ * instead. */
+} nvic_irq_num;
+
+static inline void nvic_irq_disable_all(void) {
+ /* Even low-density devices have over 32 interrupt lines. */
+ NVIC_BASE->ICER[0] = 0xFFFFFFFF;
+ NVIC_BASE->ICER[1] = 0xFFFFFFFF;
+#if STM32_NR_INTERRUPTS > 64
+ /* Only some have over 64; e.g. connectivity line MCUs. */
+ NVIC_BASE->ICER[2] = 0xFFFFFFFF;
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/pwr.h b/libmaple/stm32f1/include/series/pwr.h
new file mode 100644
index 0000000..e143a8c
--- /dev/null
+++ b/libmaple/stm32f1/include/series/pwr.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/pwr.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 Power control (PWR) support.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_PWR_H_
+#define _LIBMAPLE_STM32F1_PWR_H_
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+
+/* PVD level selection */
+#define PWR_CR_PLS_2_2V (0x0 << 5)
+#define PWR_CR_PLS_2_3V (0x1 << 5)
+#define PWR_CR_PLS_2_4V (0x2 << 5)
+#define PWR_CR_PLS_2_5V (0x3 << 5)
+#define PWR_CR_PLS_2_6V (0x4 << 5)
+#define PWR_CR_PLS_2_7V (0x5 << 5)
+#define PWR_CR_PLS_2_8V (0x6 << 5)
+#define PWR_CR_PLS_2_9V (0x7 << 5)
+
+#endif
diff --git a/libmaple/stm32f1/include/series/rcc.h b/libmaple/stm32f1/include/series/rcc.h
new file mode 100644
index 0000000..225ca49
--- /dev/null
+++ b/libmaple/stm32f1/include/series/rcc.h
@@ -0,0 +1,599 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/rcc.h
+ * @brief STM32F1 reset and clock control (RCC) support.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_RCC_H_
+#define _LIBMAPLE_STM32F1_RCC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** STM32F1 RCC register map type */
+typedef struct rcc_reg_map {
+ __io uint32 CR; /**< Clock control register */
+ __io uint32 CFGR; /**< Clock configuration register */
+ __io uint32 CIR; /**< Clock interrupt register */
+ __io uint32 APB2RSTR; /**< APB2 peripheral reset register */
+ __io uint32 APB1RSTR; /**< APB1 peripheral reset register */
+ __io uint32 AHBENR; /**< AHB peripheral clock enable register */
+ __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */
+ __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */
+ __io uint32 BDCR; /**< Backup domain control register */
+ __io uint32 CSR; /**< Control/status register */
+} rcc_reg_map;
+
+#define RCC_BASE ((struct rcc_reg_map*)0x40021000)
+
+/*
+ * Register bit definitions
+ */
+
+/* Clock control register */
+
+#define RCC_CR_PLLRDY_BIT 25
+#define RCC_CR_PLLON_BIT 24
+#define RCC_CR_CSSON_BIT 19
+#define RCC_CR_HSEBYP_BIT 18
+#define RCC_CR_HSERDY_BIT 17
+#define RCC_CR_HSEON_BIT 16
+#define RCC_CR_HSIRDY_BIT 1
+#define RCC_CR_HSION_BIT 0
+
+#define RCC_CR_PLLRDY (1U << RCC_CR_PLLRDY_BIT)
+#define RCC_CR_PLLON (1U << RCC_CR_PLLON_BIT)
+#define RCC_CR_CSSON (1U << RCC_CR_CSSON_BIT)
+#define RCC_CR_HSEBYP (1U << RCC_CR_HSEBYP_BIT)
+#define RCC_CR_HSERDY (1U << RCC_CR_HSERDY_BIT)
+#define RCC_CR_HSEON (1U << RCC_CR_HSEON_BIT)
+#define RCC_CR_HSICAL (0xFF << 8)
+#define RCC_CR_HSITRIM (0x1F << 3)
+#define RCC_CR_HSIRDY (1U << RCC_CR_HSIRDY_BIT)
+#define RCC_CR_HSION (1U << RCC_CR_HSION_BIT)
+
+/* Clock configuration register */
+
+#define RCC_CFGR_USBPRE_BIT 22
+#define RCC_CFGR_PLLXTPRE_BIT 17
+#define RCC_CFGR_PLLSRC_BIT 16
+
+#define RCC_CFGR_MCO (0x3 << 24)
+#define RCC_CFGR_USBPRE (1U << RCC_CFGR_USBPRE_BIT)
+#define RCC_CFGR_PLLMUL (0xF << 18)
+#define RCC_CFGR_PLLXTPRE (1U << RCC_CFGR_PLLXTPRE_BIT)
+#define RCC_CFGR_PLLSRC (1U << RCC_CFGR_PLLSRC_BIT)
+#define RCC_CFGR_ADCPRE (0x3 << 14)
+#define RCC_CFGR_PPRE2 (0x7 << 11)
+#define RCC_CFGR_PPRE1 (0x7 << 8)
+#define RCC_CFGR_HPRE (0xF << 4)
+#define RCC_CFGR_SWS (0x3 << 2)
+#define RCC_CFGR_SWS_PLL (0x2 << 2)
+#define RCC_CFGR_SWS_HSE (0x1 << 2)
+#define RCC_CFGR_SW 0x3
+#define RCC_CFGR_SW_PLL 0x2
+#define RCC_CFGR_SW_HSE 0x1
+
+/* Clock interrupt register */
+
+#define RCC_CIR_CSSC_BIT 23
+#define RCC_CIR_PLLRDYC_BIT 20
+#define RCC_CIR_HSERDYC_BIT 19
+#define RCC_CIR_HSIRDYC_BIT 18
+#define RCC_CIR_LSERDYC_BIT 17
+#define RCC_CIR_LSIRDYC_BIT 16
+#define RCC_CIR_PLLRDYIE_BIT 12
+#define RCC_CIR_HSERDYIE_BIT 11
+#define RCC_CIR_HSIRDYIE_BIT 10
+#define RCC_CIR_LSERDYIE_BIT 9
+#define RCC_CIR_LSIRDYIE_BIT 8
+#define RCC_CIR_CSSF_BIT 7
+#define RCC_CIR_PLLRDYF_BIT 4
+#define RCC_CIR_HSERDYF_BIT 3
+#define RCC_CIR_HSIRDYF_BIT 2
+#define RCC_CIR_LSERDYF_BIT 1
+#define RCC_CIR_LSIRDYF_BIT 0
+
+#define RCC_CIR_CSSC (1U << RCC_CIR_CSSC_BIT)
+#define RCC_CIR_PLLRDYC (1U << RCC_CIR_PLLRDYC_BIT)
+#define RCC_CIR_HSERDYC (1U << RCC_CIR_HSERDYC_BIT)
+#define RCC_CIR_HSIRDYC (1U << RCC_CIR_HSIRDYC_BIT)
+#define RCC_CIR_LSERDYC (1U << RCC_CIR_LSERDYC_BIT)
+#define RCC_CIR_LSIRDYC (1U << RCC_CIR_LSIRDYC_BIT)
+#define RCC_CIR_PLLRDYIE (1U << RCC_CIR_PLLRDYIE_BIT)
+#define RCC_CIR_HSERDYIE (1U << RCC_CIR_HSERDYIE_BIT)
+#define RCC_CIR_HSIRDYIE (1U << RCC_CIR_HSIRDYIE_BIT)
+#define RCC_CIR_LSERDYIE (1U << RCC_CIR_LSERDYIE_BIT)
+#define RCC_CIR_LSIRDYIE (1U << RCC_CIR_LSIRDYIE_BIT)
+#define RCC_CIR_CSSF (1U << RCC_CIR_CSSF_BIT)
+#define RCC_CIR_PLLRDYF (1U << RCC_CIR_PLLRDYF_BIT)
+#define RCC_CIR_HSERDYF (1U << RCC_CIR_HSERDYF_BIT)
+#define RCC_CIR_HSIRDYF (1U << RCC_CIR_HSIRDYF_BIT)
+#define RCC_CIR_LSERDYF (1U << RCC_CIR_LSERDYF_BIT)
+#define RCC_CIR_LSIRDYF (1U << RCC_CIR_LSIRDYF_BIT)
+
+/* APB2 peripheral reset register */
+
+#define RCC_APB2RSTR_TIM11RST_BIT 21
+#define RCC_APB2RSTR_TIM10RST_BIT 20
+#define RCC_APB2RSTR_TIM9RST_BIT 19
+#define RCC_APB2RSTR_ADC3RST_BIT 15
+#define RCC_APB2RSTR_USART1RST_BIT 14
+#define RCC_APB2RSTR_TIM8RST_BIT 13
+#define RCC_APB2RSTR_SPI1RST_BIT 12
+#define RCC_APB2RSTR_TIM1RST_BIT 11
+#define RCC_APB2RSTR_ADC2RST_BIT 10
+#define RCC_APB2RSTR_ADC1RST_BIT 9
+#define RCC_APB2RSTR_IOPGRST_BIT 8
+#define RCC_APB2RSTR_IOPFRST_BIT 7
+#define RCC_APB2RSTR_IOPERST_BIT 6
+#define RCC_APB2RSTR_IOPDRST_BIT 5
+#define RCC_APB2RSTR_IOPCRST_BIT 4
+#define RCC_APB2RSTR_IOPBRST_BIT 3
+#define RCC_APB2RSTR_IOPARST_BIT 2
+#define RCC_APB2RSTR_AFIORST_BIT 0
+
+#define RCC_APB2RSTR_TIM11RST (1U << RCC_APB2RSTR_TIM11RST_BIT)
+#define RCC_APB2RSTR_TIM10RST (1U << RCC_APB2RSTR_TIM10RST_BIT)
+#define RCC_APB2RSTR_TIM9RST (1U << RCC_APB2RSTR_TIM9RST_BIT)
+#define RCC_APB2RSTR_ADC3RST (1U << RCC_APB2RSTR_ADC3RST_BIT)
+#define RCC_APB2RSTR_USART1RST (1U << RCC_APB2RSTR_USART1RST_BIT)
+#define RCC_APB2RSTR_TIM8RST (1U << RCC_APB2RSTR_TIM8RST_BIT)
+#define RCC_APB2RSTR_SPI1RST (1U << RCC_APB2RSTR_SPI1RST_BIT)
+#define RCC_APB2RSTR_TIM1RST (1U << RCC_APB2RSTR_TIM1RST_BIT)
+#define RCC_APB2RSTR_ADC2RST (1U << RCC_APB2RSTR_ADC2RST_BIT)
+#define RCC_APB2RSTR_ADC1RST (1U << RCC_APB2RSTR_ADC1RST_BIT)
+#define RCC_APB2RSTR_IOPGRST (1U << RCC_APB2RSTR_IOPGRST_BIT)
+#define RCC_APB2RSTR_IOPFRST (1U << RCC_APB2RSTR_IOPFRST_BIT)
+#define RCC_APB2RSTR_IOPERST (1U << RCC_APB2RSTR_IOPERST_BIT)
+#define RCC_APB2RSTR_IOPDRST (1U << RCC_APB2RSTR_IOPDRST_BIT)
+#define RCC_APB2RSTR_IOPCRST (1U << RCC_APB2RSTR_IOPCRST_BIT)
+#define RCC_APB2RSTR_IOPBRST (1U << RCC_APB2RSTR_IOPBRST_BIT)
+#define RCC_APB2RSTR_IOPARST (1U << RCC_APB2RSTR_IOPARST_BIT)
+#define RCC_APB2RSTR_AFIORST (1U << RCC_APB2RSTR_AFIORST_BIT)
+
+/* APB1 peripheral reset register */
+
+#define RCC_APB1RSTR_DACRST_BIT 29
+#define RCC_APB1RSTR_PWRRST_BIT 28
+#define RCC_APB1RSTR_BKPRST_BIT 27
+#define RCC_APB1RSTR_CANRST_BIT 25
+#define RCC_APB1RSTR_USBRST_BIT 23
+#define RCC_APB1RSTR_I2C2RST_BIT 22
+#define RCC_APB1RSTR_I2C1RST_BIT 21
+#define RCC_APB1RSTR_UART5RST_BIT 20
+#define RCC_APB1RSTR_UART4RST_BIT 19
+#define RCC_APB1RSTR_USART3RST_BIT 18
+#define RCC_APB1RSTR_USART2RST_BIT 17
+#define RCC_APB1RSTR_SPI3RST_BIT 15
+#define RCC_APB1RSTR_SPI2RST_BIT 14
+#define RCC_APB1RSTR_WWDRST_BIT 11
+#define RCC_APB1RSTR_TIM14RST_BIT 8
+#define RCC_APB1RSTR_TIM13RST_BIT 7
+#define RCC_APB1RSTR_TIM12RST_BIT 6
+#define RCC_APB1RSTR_TIM7RST_BIT 5
+#define RCC_APB1RSTR_TIM6RST_BIT 4
+#define RCC_APB1RSTR_TIM5RST_BIT 3
+#define RCC_APB1RSTR_TIM4RST_BIT 2
+#define RCC_APB1RSTR_TIM3RST_BIT 1
+#define RCC_APB1RSTR_TIM2RST_BIT 0
+
+#define RCC_APB1RSTR_DACRST (1U << RCC_APB1RSTR_DACRST_BIT)
+#define RCC_APB1RSTR_PWRRST (1U << RCC_APB1RSTR_PWRRST_BIT)
+#define RCC_APB1RSTR_BKPRST (1U << RCC_APB1RSTR_BKPRST_BIT)
+#define RCC_APB1RSTR_CANRST (1U << RCC_APB1RSTR_CANRST_BIT)
+#define RCC_APB1RSTR_USBRST (1U << RCC_APB1RSTR_USBRST_BIT)
+#define RCC_APB1RSTR_I2C2RST (1U << RCC_APB1RSTR_I2C2RST_BIT)
+#define RCC_APB1RSTR_I2C1RST (1U << RCC_APB1RSTR_I2C1RST_BIT)
+#define RCC_APB1RSTR_UART5RST (1U << RCC_APB1RSTR_UART5RST_BIT)
+#define RCC_APB1RSTR_UART4RST (1U << RCC_APB1RSTR_UART4RST_BIT)
+#define RCC_APB1RSTR_USART3RST (1U << RCC_APB1RSTR_USART3RST_BIT)
+#define RCC_APB1RSTR_USART2RST (1U << RCC_APB1RSTR_USART2RST_BIT)
+#define RCC_APB1RSTR_SPI3RST (1U << RCC_APB1RSTR_SPI3RST_BIT)
+#define RCC_APB1RSTR_SPI2RST (1U << RCC_APB1RSTR_SPI2RST_BIT)
+#define RCC_APB1RSTR_WWDRST (1U << RCC_APB1RSTR_WWDRST_BIT)
+#define RCC_APB1RSTR_TIM14RST (1U << RCC_APB1RSTR_TIM14RST_BIT)
+#define RCC_APB1RSTR_TIM13RST (1U << RCC_APB1RSTR_TIM13RST_BIT)
+#define RCC_APB1RSTR_TIM12RST (1U << RCC_APB1RSTR_TIM12RST_BIT)
+#define RCC_APB1RSTR_TIM7RST (1U << RCC_APB1RSTR_TIM7RST_BIT)
+#define RCC_APB1RSTR_TIM6RST (1U << RCC_APB1RSTR_TIM6RST_BIT)
+#define RCC_APB1RSTR_TIM5RST (1U << RCC_APB1RSTR_TIM5RST_BIT)
+#define RCC_APB1RSTR_TIM4RST (1U << RCC_APB1RSTR_TIM4RST_BIT)
+#define RCC_APB1RSTR_TIM3RST (1U << RCC_APB1RSTR_TIM3RST_BIT)
+#define RCC_APB1RSTR_TIM2RST (1U << RCC_APB1RSTR_TIM2RST_BIT)
+
+/* AHB peripheral clock enable register */
+
+#define RCC_AHBENR_SDIOEN_BIT 10
+#define RCC_AHBENR_FSMCEN_BIT 8
+#define RCC_AHBENR_CRCEN_BIT 7
+#define RCC_AHBENR_FLITFEN_BIT 4
+#define RCC_AHBENR_SRAMEN_BIT 2
+#define RCC_AHBENR_DMA2EN_BIT 1
+#define RCC_AHBENR_DMA1EN_BIT 0
+
+#define RCC_AHBENR_SDIOEN (1U << RCC_AHBENR_SDIOEN_BIT)
+#define RCC_AHBENR_FSMCEN (1U << RCC_AHBENR_FSMCEN_BIT)
+#define RCC_AHBENR_CRCEN (1U << RCC_AHBENR_CRCEN_BIT)
+#define RCC_AHBENR_FLITFEN (1U << RCC_AHBENR_FLITFEN_BIT)
+#define RCC_AHBENR_SRAMEN (1U << RCC_AHBENR_SRAMEN_BIT)
+#define RCC_AHBENR_DMA2EN (1U << RCC_AHBENR_DMA2EN_BIT)
+#define RCC_AHBENR_DMA1EN (1U << RCC_AHBENR_DMA1EN_BIT)
+
+/* APB2 peripheral clock enable register */
+
+#define RCC_APB2ENR_TIM11EN_BIT 21
+#define RCC_APB2ENR_TIM10EN_BIT 20
+#define RCC_APB2ENR_TIM9EN_BIT 19
+#define RCC_APB2ENR_ADC3EN_BIT 15
+#define RCC_APB2ENR_USART1EN_BIT 14
+#define RCC_APB2ENR_TIM8EN_BIT 13
+#define RCC_APB2ENR_SPI1EN_BIT 12
+#define RCC_APB2ENR_TIM1EN_BIT 11
+#define RCC_APB2ENR_ADC2EN_BIT 10
+#define RCC_APB2ENR_ADC1EN_BIT 9
+#define RCC_APB2ENR_IOPGEN_BIT 8
+#define RCC_APB2ENR_IOPFEN_BIT 7
+#define RCC_APB2ENR_IOPEEN_BIT 6
+#define RCC_APB2ENR_IOPDEN_BIT 5
+#define RCC_APB2ENR_IOPCEN_BIT 4
+#define RCC_APB2ENR_IOPBEN_BIT 3
+#define RCC_APB2ENR_IOPAEN_BIT 2
+#define RCC_APB2ENR_AFIOEN_BIT 0
+
+#define RCC_APB2ENR_TIM11EN (1U << RCC_APB2ENR_TIM11EN_BIT)
+#define RCC_APB2ENR_TIM10EN (1U << RCC_APB2ENR_TIM10EN_BIT)
+#define RCC_APB2ENR_TIM9EN (1U << RCC_APB2ENR_TIM9EN_BIT)
+#define RCC_APB2ENR_ADC3EN (1U << RCC_APB2ENR_ADC3EN_BIT)
+#define RCC_APB2ENR_USART1EN (1U << RCC_APB2ENR_USART1EN_BIT)
+#define RCC_APB2ENR_TIM8EN (1U << RCC_APB2ENR_TIM8EN_BIT)
+#define RCC_APB2ENR_SPI1EN (1U << RCC_APB2ENR_SPI1EN_BIT)
+#define RCC_APB2ENR_TIM1EN (1U << RCC_APB2ENR_TIM1EN_BIT)
+#define RCC_APB2ENR_ADC2EN (1U << RCC_APB2ENR_ADC2EN_BIT)
+#define RCC_APB2ENR_ADC1EN (1U << RCC_APB2ENR_ADC1EN_BIT)
+#define RCC_APB2ENR_IOPGEN (1U << RCC_APB2ENR_IOPGEN_BIT)
+#define RCC_APB2ENR_IOPFEN (1U << RCC_APB2ENR_IOPFEN_BIT)
+#define RCC_APB2ENR_IOPEEN (1U << RCC_APB2ENR_IOPEEN_BIT)
+#define RCC_APB2ENR_IOPDEN (1U << RCC_APB2ENR_IOPDEN_BIT)
+#define RCC_APB2ENR_IOPCEN (1U << RCC_APB2ENR_IOPCEN_BIT)
+#define RCC_APB2ENR_IOPBEN (1U << RCC_APB2ENR_IOPBEN_BIT)
+#define RCC_APB2ENR_IOPAEN (1U << RCC_APB2ENR_IOPAEN_BIT)
+#define RCC_APB2ENR_AFIOEN (1U << RCC_APB2ENR_AFIOEN_BIT)
+
+/* APB1 peripheral clock enable register */
+
+#define RCC_APB1ENR_DACEN_BIT 29
+#define RCC_APB1ENR_PWREN_BIT 28
+#define RCC_APB1ENR_BKPEN_BIT 27
+#define RCC_APB1ENR_CANEN_BIT 25
+#define RCC_APB1ENR_USBEN_BIT 23
+#define RCC_APB1ENR_I2C2EN_BIT 22
+#define RCC_APB1ENR_I2C1EN_BIT 21
+#define RCC_APB1ENR_UART5EN_BIT 20
+#define RCC_APB1ENR_UART4EN_BIT 19
+#define RCC_APB1ENR_USART3EN_BIT 18
+#define RCC_APB1ENR_USART2EN_BIT 17
+#define RCC_APB1ENR_SPI3EN_BIT 15
+#define RCC_APB1ENR_SPI2EN_BIT 14
+#define RCC_APB1ENR_WWDEN_BIT 11
+#define RCC_APB1ENR_TIM14EN_BIT 8
+#define RCC_APB1ENR_TIM13EN_BIT 7
+#define RCC_APB1ENR_TIM12EN_BIT 6
+#define RCC_APB1ENR_TIM7EN_BIT 5
+#define RCC_APB1ENR_TIM6EN_BIT 4
+#define RCC_APB1ENR_TIM5EN_BIT 3
+#define RCC_APB1ENR_TIM4EN_BIT 2
+#define RCC_APB1ENR_TIM3EN_BIT 1
+#define RCC_APB1ENR_TIM2EN_BIT 0
+
+#define RCC_APB1ENR_DACEN (1U << RCC_APB1ENR_DACEN_BIT)
+#define RCC_APB1ENR_PWREN (1U << RCC_APB1ENR_PWREN_BIT)
+#define RCC_APB1ENR_BKPEN (1U << RCC_APB1ENR_BKPEN_BIT)
+#define RCC_APB1ENR_CANEN (1U << RCC_APB1ENR_CANEN_BIT)
+#define RCC_APB1ENR_USBEN (1U << RCC_APB1ENR_USBEN_BIT)
+#define RCC_APB1ENR_I2C2EN (1U << RCC_APB1ENR_I2C2EN_BIT)
+#define RCC_APB1ENR_I2C1EN (1U << RCC_APB1ENR_I2C1EN_BIT)
+#define RCC_APB1ENR_UART5EN (1U << RCC_APB1ENR_UART5EN_BIT)
+#define RCC_APB1ENR_UART4EN (1U << RCC_APB1ENR_UART4EN_BIT)
+#define RCC_APB1ENR_USART3EN (1U << RCC_APB1ENR_USART3EN_BIT)
+#define RCC_APB1ENR_USART2EN (1U << RCC_APB1ENR_USART2EN_BIT)
+#define RCC_APB1ENR_SPI3EN (1U << RCC_APB1ENR_SPI3EN_BIT)
+#define RCC_APB1ENR_SPI2EN (1U << RCC_APB1ENR_SPI2EN_BIT)
+#define RCC_APB1ENR_WWDEN (1U << RCC_APB1ENR_WWDEN_BIT)
+#define RCC_APB1ENR_TIM14EN (1U << RCC_APB1ENR_TIM14EN_BIT)
+#define RCC_APB1ENR_TIM13EN (1U << RCC_APB1ENR_TIM13EN_BIT)
+#define RCC_APB1ENR_TIM12EN (1U << RCC_APB1ENR_TIM12EN_BIT)
+#define RCC_APB1ENR_TIM7EN (1U << RCC_APB1ENR_TIM7EN_BIT)
+#define RCC_APB1ENR_TIM6EN (1U << RCC_APB1ENR_TIM6EN_BIT)
+#define RCC_APB1ENR_TIM5EN (1U << RCC_APB1ENR_TIM5EN_BIT)
+#define RCC_APB1ENR_TIM4EN (1U << RCC_APB1ENR_TIM4EN_BIT)
+#define RCC_APB1ENR_TIM3EN (1U << RCC_APB1ENR_TIM3EN_BIT)
+#define RCC_APB1ENR_TIM2EN (1U << RCC_APB1ENR_TIM2EN_BIT)
+
+/* Backup domain control register */
+
+#define RCC_BDCR_BDRST_BIT 16
+#define RCC_BDCR_RTCEN_BIT 15
+#define RCC_BDCR_LSEBYP_BIT 2
+#define RCC_BDCR_LSERDY_BIT 1
+#define RCC_BDCR_LSEON_BIT 0
+
+#define RCC_BDCR_BDRST (1U << RCC_BDCR_BDRST_BIT)
+#define RCC_BDCR_RTCEN (1U << RCC_BDCR_RTC_BIT)
+#define RCC_BDCR_RTCSEL (0x3 << 8)
+#define RCC_BDCR_RTCSEL_NONE (0x0 << 8)
+#define RCC_BDCR_RTCSEL_LSE (0x1 << 8)
+#define RCC_BDCR_RTCSEL_HSE (0x3 << 8)
+#define RCC_BDCR_LSEBYP (1U << RCC_BDCR_LSEBYP_BIT)
+#define RCC_BDCR_LSERDY (1U << RCC_BDCR_LSERDY_BIT)
+#define RCC_BDCR_LSEON (1U << RCC_BDCR_LSEON_BIT)
+
+/* Control/status register */
+
+#define RCC_CSR_LPWRRSTF_BIT 31
+#define RCC_CSR_WWDGRSTF_BIT 30
+#define RCC_CSR_IWDGRSTF_BIT 29
+#define RCC_CSR_SFTRSTF_BIT 28
+#define RCC_CSR_PORRSTF_BIT 27
+#define RCC_CSR_PINRSTF_BIT 26
+#define RCC_CSR_RMVF_BIT 24
+#define RCC_CSR_LSIRDY_BIT 1
+#define RCC_CSR_LSION_BIT 0
+
+#define RCC_CSR_LPWRRSTF (1U << RCC_CSR_LPWRRSTF_BIT)
+#define RCC_CSR_WWDGRSTF (1U << RCC_CSR_WWDGRSTF_BIT)
+#define RCC_CSR_IWDGRSTF (1U << RCC_CSR_IWDGRSTF_BIT)
+#define RCC_CSR_SFTRSTF (1U << RCC_CSR_SFTRSTF_BIT)
+#define RCC_CSR_PORRSTF (1U << RCC_CSR_PORRSTF_BIT)
+#define RCC_CSR_PINRSTF (1U << RCC_CSR_PINRSTF_BIT)
+#define RCC_CSR_RMVF (1U << RCC_CSR_RMVF_BIT)
+#define RCC_CSR_LSIRDY (1U << RCC_CSR_LSIRDY_BIT)
+#define RCC_CSR_LSION (1U << RCC_CSR_LSION_BIT)
+
+/*
+ * libmaple-mandated enumeration types.
+ */
+
+/**
+ * @brief STM32F1 rcc_clk_id.
+ */
+typedef enum rcc_clk_id {
+ RCC_ADC1,
+ RCC_ADC2,
+ RCC_ADC3,
+ RCC_AFIO,
+ RCC_BKP,
+ RCC_CRC,
+ RCC_DAC,
+ RCC_DMA1,
+ RCC_DMA2,
+ RCC_FLITF,
+ RCC_FSMC,
+ RCC_GPIOA,
+ RCC_GPIOB,
+ RCC_GPIOC,
+ RCC_GPIOD,
+ RCC_GPIOE,
+ RCC_GPIOF,
+ RCC_GPIOG,
+ RCC_I2C1,
+ RCC_I2C2,
+ RCC_PWR,
+ RCC_SDIO,
+ RCC_SPI1,
+ RCC_SPI2,
+ RCC_SPI3,
+ RCC_SRAM,
+ RCC_TIMER1,
+ RCC_TIMER2,
+ RCC_TIMER3,
+ RCC_TIMER4,
+ RCC_TIMER5,
+ RCC_TIMER6,
+ RCC_TIMER7,
+ RCC_TIMER8,
+ RCC_TIMER9,
+ RCC_TIMER10,
+ RCC_TIMER11,
+ RCC_TIMER12,
+ RCC_TIMER13,
+ RCC_TIMER14,
+ RCC_USART1,
+ RCC_USART2,
+ RCC_USART3,
+ RCC_UART4,
+ RCC_UART5,
+ RCC_USB,
+} rcc_clk_id;
+
+/**
+ * @brief STM32F1 PLL clock sources.
+ * @see rcc_configure_pll()
+ */
+typedef enum rcc_pllsrc {
+ RCC_PLLSRC_HSE = (0x1 << 16),
+ RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16)
+} rcc_pllsrc;
+
+/**
+ * @brief STM32F1 clock domains.
+ * @see rcc_dev_clk()
+ */
+typedef enum rcc_clk_domain {
+ RCC_APB1,
+ RCC_APB2,
+ RCC_AHB
+} rcc_clk_domain;
+
+/**
+ * @brief STM32F1 Prescaler identifiers
+ * @see rcc_set_prescaler()
+ */
+typedef enum rcc_prescaler {
+ RCC_PRESCALER_AHB,
+ RCC_PRESCALER_APB1,
+ RCC_PRESCALER_APB2,
+ RCC_PRESCALER_USB,
+ RCC_PRESCALER_ADC
+} rcc_prescaler;
+
+/**
+ * @brief STM32F1 ADC prescaler dividers
+ * @see rcc_set_prescaler()
+ */
+typedef enum rcc_adc_divider {
+ RCC_ADCPRE_PCLK_DIV_2 = 0x0 << 14,
+ RCC_ADCPRE_PCLK_DIV_4 = 0x1 << 14,
+ RCC_ADCPRE_PCLK_DIV_6 = 0x2 << 14,
+ RCC_ADCPRE_PCLK_DIV_8 = 0x3 << 14,
+} rcc_adc_divider;
+
+/**
+ * @brief STM32F1 APB1 prescaler dividers
+ * @see rcc_set_prescaler()
+ */
+typedef enum rcc_apb1_divider {
+ RCC_APB1_HCLK_DIV_1 = 0x0 << 8,
+ RCC_APB1_HCLK_DIV_2 = 0x4 << 8,
+ RCC_APB1_HCLK_DIV_4 = 0x5 << 8,
+ RCC_APB1_HCLK_DIV_8 = 0x6 << 8,
+ RCC_APB1_HCLK_DIV_16 = 0x7 << 8,
+} rcc_apb1_divider;
+
+/**
+ * @brief STM32F1 APB2 prescaler dividers
+ * @see rcc_set_prescaler()
+ */
+typedef enum rcc_apb2_divider {
+ RCC_APB2_HCLK_DIV_1 = 0x0 << 11,
+ RCC_APB2_HCLK_DIV_2 = 0x4 << 11,
+ RCC_APB2_HCLK_DIV_4 = 0x5 << 11,
+ RCC_APB2_HCLK_DIV_8 = 0x6 << 11,
+ RCC_APB2_HCLK_DIV_16 = 0x7 << 11,
+} rcc_apb2_divider;
+
+/**
+ * @brief STM32F1 AHB prescaler dividers
+ * @see rcc_set_prescaler()
+ */
+typedef enum rcc_ahb_divider {
+ RCC_AHB_SYSCLK_DIV_1 = 0x0 << 4,
+ RCC_AHB_SYSCLK_DIV_2 = 0x8 << 4,
+ RCC_AHB_SYSCLK_DIV_4 = 0x9 << 4,
+ RCC_AHB_SYSCLK_DIV_8 = 0xA << 4,
+ RCC_AHB_SYSCLK_DIV_16 = 0xB << 4,
+ RCC_AHB_SYSCLK_DIV_32 = 0xC << 4,
+ RCC_AHB_SYSCLK_DIV_64 = 0xD << 4,
+ RCC_AHB_SYSCLK_DIV_128 = 0xD << 4,
+ RCC_AHB_SYSCLK_DIV_256 = 0xE << 4,
+ RCC_AHB_SYSCLK_DIV_512 = 0xF << 4,
+} rcc_ahb_divider;
+
+/**
+ * @brief STM32F1 clock sources.
+ */
+typedef enum rcc_clk {
+ RCC_CLK_PLL = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_PLLON_BIT), /**< Main PLL, clocked by
+ HSI or HSE. */
+ RCC_CLK_HSE = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_HSEON_BIT), /**< High speed external. */
+ RCC_CLK_HSI = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_HSION_BIT), /**< High speed internal. */
+ RCC_CLK_LSE = (uint16)((offsetof(struct rcc_reg_map, BDCR) << 8) |
+ RCC_BDCR_LSEON_BIT), /**< Low-speed external
+ * (32.768 KHz). */
+ RCC_CLK_LSI = (uint16)((offsetof(struct rcc_reg_map, CSR) << 8) |
+ RCC_CSR_LSION_BIT), /**< Low-speed internal
+ * (approximately 32 KHz). */
+} rcc_clk;
+
+/**
+ * @brief STM32F1 PLL multipliers.
+ */
+typedef enum rcc_pll_multiplier {
+ RCC_PLLMUL_2 = (0x0 << 18),
+ RCC_PLLMUL_3 = (0x1 << 18),
+ RCC_PLLMUL_4 = (0x2 << 18),
+ RCC_PLLMUL_5 = (0x3 << 18),
+ RCC_PLLMUL_6 = (0x4 << 18),
+ RCC_PLLMUL_7 = (0x5 << 18),
+ RCC_PLLMUL_8 = (0x6 << 18),
+ RCC_PLLMUL_9 = (0x7 << 18),
+ RCC_PLLMUL_10 = (0x8 << 18),
+ RCC_PLLMUL_11 = (0x9 << 18),
+ RCC_PLLMUL_12 = (0xA << 18),
+ RCC_PLLMUL_13 = (0xB << 18),
+ RCC_PLLMUL_14 = (0xC << 18),
+ RCC_PLLMUL_15 = (0xD << 18),
+ RCC_PLLMUL_16 = (0xE << 18),
+} rcc_pll_multiplier;
+
+/* FIXME [0.0.13] Just have data point to an rcc_pll_multiplier! */
+
+/**
+ * @brief STM32F1 PLL configuration values.
+ * Point to one of these with the "data" field in a struct rcc_pll_cfg.
+ * @see struct rcc_pll_cfg.
+ */
+typedef struct stm32f1_rcc_pll_data {
+ rcc_pll_multiplier pll_mul; /**< PLL multiplication factor. */
+} stm32f1_rcc_pll_data;
+
+/*
+ * Deprecated bits.
+ */
+
+/**
+ * @brief Deprecated; STM32F1 only.
+ *
+ * Initialize the clock control system. Initializes the system
+ * clock source to use the PLL driven by an external oscillator.
+ *
+ * @param sysclk_src system clock source, must be PLL
+ * @param pll_src pll clock source, must be HSE
+ * @param pll_mul pll multiplier
+ */
+__deprecated
+void rcc_clk_init(rcc_sysclk_src sysclk_src,
+ rcc_pllsrc pll_src,
+ rcc_pll_multiplier pll_mul);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/spi.h b/libmaple/stm32f1/include/series/spi.h
new file mode 100644
index 0000000..d288a0c
--- /dev/null
+++ b/libmaple/stm32f1/include/series/spi.h
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/spi.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 SPI/I2S series header.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_SPI_H_
+#define _LIBMAPLE_STM32F1_SPI_H_
+
+#include <libmaple/libmaple_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Register map base pointers
+ */
+
+struct spi_reg_map;
+
+#define SPI1_BASE ((struct spi_reg_map*)0x40013000)
+#define SPI2_BASE ((struct spi_reg_map*)0x40003800)
+#define SPI3_BASE ((struct spi_reg_map*)0x40003C00)
+
+/*
+ * Device pointers
+ */
+
+struct spi_dev;
+
+extern struct spi_dev *SPI1;
+extern struct spi_dev *SPI2;
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+extern struct spi_dev *SPI3;
+#endif
+
+/*
+ * Routines
+ */
+
+/* spi_gpio_cfg(): Backwards compatibility shim to spi_config_gpios() */
+struct gpio_dev;
+extern void spi_config_gpios(struct spi_dev*, uint8,
+ struct gpio_dev*, uint8,
+ struct gpio_dev*, uint8, uint8, uint8);
+/**
+ * @brief Deprecated. Use spi_config_gpios() instead.
+ * @see spi_config_gpios()
+ */
+static __always_inline void spi_gpio_cfg(uint8 as_master,
+ struct gpio_dev *nss_dev,
+ uint8 nss_bit,
+ struct gpio_dev *comm_dev,
+ uint8 sck_bit,
+ uint8 miso_bit,
+ uint8 mosi_bit) {
+ /* We switched style globally to foo_config_gpios() and always
+ * taking a foo_dev* argument (that last bit is the important
+ * part) after this function was written.
+ *
+ * However, spi_config_gpios() just ignores the spi_dev* on F1, so
+ * we can still keep this around for older code. */
+ spi_config_gpios(NULL, as_master, nss_dev, nss_bit,
+ comm_dev, sck_bit, miso_bit, mosi_bit);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/stm32.h b/libmaple/stm32f1/include/series/stm32.h
new file mode 100644
index 0000000..42a9744
--- /dev/null
+++ b/libmaple/stm32f1/include/series/stm32.h
@@ -0,0 +1,219 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/stm32.h
+ * @brief STM32F1 chip- and series-specific definitions.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_H_
+#define _LIBMAPLE_STM32F1_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define STM32_MCU_SERIES STM32_SERIES_F1
+
+/* The STM32F1 series is subdivided into "lines". libmaple currently
+ * officially supports STM32F103 performance line MCUs (see the
+ * MCU-specific value section below).
+ *
+ * You can use these F1 line defines if porting libmaple to support
+ * MCUs on other lines. */
+/** STM32F1 value line (STM32F100 MCUs). */
+#define STM32_F1_LINE_VALUE 0
+/** STM32F1 access line (STM32F101 MCUs). */
+#define STM32_F1_LINE_ACCESS 1
+/** STM32F1 USB access line (STM32F102 MCUs). */
+#define STM32_F1_LINE_USB_ACCESS 2
+/** STM32F1 performance line (STM32F103 MCUs). */
+#define STM32_F1_LINE_PERFORMANCE 3
+/** STM32F1 connectivity line (STM32F105/F107 MCUs). */
+#define STM32_F1_LINE_CONNECTIVITY 5
+
+/*
+ * MCU-specific values.
+ *
+ * You can use this section to override any of the below settings on a
+ * per-MCU basis. For example, if your MCU has different STM32_PCLK1
+ * or STM32_PCLK2 values, you can set them here and the values for
+ * STM32F103 microcontrollers set below won't take effect.
+ */
+
+#if defined(MCU_STM32F103RB)
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+# define STM32_NR_GPIO_PORTS 4
+# define STM32_SRAM_END ((void*)0x20005000)
+# define STM32_MEDIUM_DENSITY
+
+#elif defined(MCU_STM32F103ZE)
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+# define STM32_NR_GPIO_PORTS 7
+# define STM32_SRAM_END ((void*)0x20010000)
+# define STM32_HIGH_DENSITY
+
+#elif defined(MCU_STM32F103CB)
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+ /* This STM32_NR_GPIO_PORTS is not true, but only pins 0 and
+ * exist, and they're used for OSC (e.g. on LeafLabs' Maple Mini),
+ * so we'll live with this for now. */
+# define STM32_NR_GPIO_PORTS 3
+# define STM32_SRAM_END ((void*)0x20005000)
+# define STM32_MEDIUM_DENSITY
+
+#elif defined(MCU_STM32F103RE)
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+# define STM32_NR_GPIO_PORTS 4
+# define STM32_SRAM_END ((void*)0x20010000)
+# define STM32_HIGH_DENSITY
+
+#elif defined(MCU_STM32F100RB)
+# define STM32_F1_LINE STM32_F1_LINE_VALUE
+# define STM32_NR_GPIO_PORTS 4
+# define STM32_TIMER_MASK 0x380DE /* Timers: 1-4, 6, 7, 15-17. */
+# define STM32_SRAM_END ((void*)0x20002000)
+# define STM32_MEDIUM_DENSITY
+
+#elif defined(MCU_STM32F103C8)
+# define STM32_NR_GPIO_PORTS 4
+# define STM32_SRAM_END ((void*)0x20005000)
+# define NR_GPIO_PORTS STM32_NR_GPIO_PORTS
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+# define STM32_MEDIUM_DENSITY
+
+#else
+#warning "Unsupported or unspecified STM32F1 MCU."
+#endif
+
+/*
+ * Derived values.
+ */
+
+#if STM32_F1_LINE == STM32_F1_LINE_PERFORMANCE
+ /* All supported performance line MCUs have a USB peripheral */
+# define STM32_HAVE_USB 1
+
+# ifdef STM32_MEDIUM_DENSITY
+# define STM32_NR_INTERRUPTS 43
+# define STM32_TIMER_MASK 0x1E /* TIMER1--TIMER4 */
+# define STM32_HAVE_FSMC 0
+# define STM32_HAVE_DAC 0
+# elif defined(STM32_HIGH_DENSITY)
+# define STM32_NR_INTERRUPTS 60
+# define STM32_TIMER_MASK 0x1FE /* TIMER1--TIMER8 */
+# define STM32_HAVE_FSMC 1
+# define STM32_HAVE_DAC 1
+# elif defined(STM32_XL_DENSITY)
+# define STM32_NR_INTERRUPTS 60
+# define STM32_TIMER_MASK 0x7FFE /* TIMER1--TIMER14 */
+# define STM32_HAVE_FSMC 1
+# define STM32_HAVE_DAC 1
+# endif
+
+#elif STM32_F1_LINE == STM32_F1_LINE_VALUE
+ /* Value line MCUs don't have USB peripherals. */
+# define STM32_HAVE_USB 0
+
+# ifdef STM32_MEDIUM_DENSITY
+# define STM32_NR_INTERRUPTS 56
+# define STM32_HAVE_FSMC 0
+# define STM32_HAVE_DAC 1
+# elif defined(STM32_HIGH_DENSITY)
+ /* 61 interrupts here counts the possibility for a remapped
+ * DMA2 channel 5 IRQ occurring at NVIC index 60. */
+# define STM32_NR_INTERRUPTS 61
+# define STM32_HAVE_FSMC 1
+# define STM32_HAVE_DAC 1
+# endif
+
+#endif
+
+/*
+ * Clock configuration.
+ *
+ * You can patch these for your line, MCU, clock configuration,
+ * etc. here or by setting cflags when compiling libmaple.
+ */
+
+#if STM32_F1_LINE == STM32_F1_LINE_PERFORMANCE
+# ifndef STM32_PCLK1
+# define STM32_PCLK1 36000000U
+# endif
+# ifndef STM32_PCLK2
+# define STM32_PCLK2 72000000U
+# endif
+# ifndef STM32_DELAY_US_MULT
+# define STM32_DELAY_US_MULT 12 /* FIXME: value is incorrect. */
+# endif
+#elif STM32_F1_LINE == STM32_F1_LINE_VALUE /* TODO */
+# ifndef STM32_PCLK1
+# define STM32_PCLK1 12000000U
+# endif
+# ifndef STM32_PCLK2
+# define STM32_PCLK2 24000000U
+# endif
+# ifndef STM32_DELAY_US_MULT
+# define STM32_DELAY_US_MULT 8 /* FIXME: value is incorrect. */
+# endif
+#elif STM32_F1_LINE == STM32_F1_LINE_ACCESS /* TODO */
+#elif STM32_F1_LINE == STM32_F1_LINE_USB_ACCESS /* TODO */
+#elif STM32_F1_LINE == STM32_F1_LINE_CONNECTIVITY /* TODO */
+#endif
+
+/*
+ * Sanity checks.
+ *
+ * Make sure we have the F1-specific defines we need.
+ * <libmaple/stm32.h> will check that we've defined everything it needs.
+ */
+
+#if !defined(STM32_F1_LINE)
+#error "Bad STM32F1 configuration. Check STM32F1 <series/stm32.h> header."
+#endif
+
+/*
+ * Doxygen
+ */
+
+#ifdef __DOXYGEN__
+
+/**
+ * @brief STM32 line value for the STM32F1 MCU being targeted.
+ *
+ * At time of writing, allowed values are: STM32_F1_LINE_PERFORMANCE,
+ * STM32_F1_LINE_VALUE. This set of values may expand as libmaple adds
+ * support for more STM32F1 lines.
+ */
+#define STM32_F1_LINE
+
+#endif /* __DOXYGEN__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/timer.h b/libmaple/stm32f1/include/series/timer.h
new file mode 100644
index 0000000..cfeb770
--- /dev/null
+++ b/libmaple/stm32f1/include/series/timer.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/timer.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 timer support.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_TIMER_H_
+#define _LIBMAPLE_STM32F1_TIMER_H_
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register maps and base pointers
+ */
+
+/** STM32F1 general purpose timer register map type */
+typedef struct timer_gen_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SMCR; /**< Slave mode control register */
+ __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ __io uint32 CCMR1; /**< Capture/compare mode register 1 */
+ __io uint32 CCMR2; /**< Capture/compare mode register 2 */
+ __io uint32 CCER; /**< Capture/compare enable register */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 CCR1; /**< Capture/compare register 1 */
+ __io uint32 CCR2; /**< Capture/compare register 2 */
+ __io uint32 CCR3; /**< Capture/compare register 3 */
+ __io uint32 CCR4; /**< Capture/compare register 4 */
+ const uint32 RESERVED2; /**< Reserved */
+ __io uint32 DCR; /**< DMA control register */
+ __io uint32 DMAR; /**< DMA address for full transfer */
+} timer_gen_reg_map;
+
+struct timer_adv_reg_map;
+struct timer_bas_reg_map;
+
+/** Timer 1 register map base pointer */
+#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00)
+/** Timer 2 register map base pointer */
+#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000)
+/** Timer 3 register map base pointer */
+#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400)
+/** Timer 4 register map base pointer */
+#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800)
+/** Timer 5 register map base pointer */
+#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00)
+/** Timer 6 register map base pointer */
+#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000)
+/** Timer 7 register map base pointer */
+#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400)
+/** Timer 8 register map base pointer */
+#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400)
+/** Timer 9 register map base pointer */
+#define TIMER9_BASE ((struct timer_gen_reg_map*)0x40014C00)
+/** Timer 10 register map base pointer */
+#define TIMER10_BASE ((struct timer_gen_reg_map*)0x40015000)
+/** Timer 11 register map base pointer */
+#define TIMER11_BASE ((struct timer_gen_reg_map*)0x40015400)
+/** Timer 12 register map base pointer */
+#define TIMER12_BASE ((struct timer_gen_reg_map*)0x40001800)
+/** Timer 13 register map base pointer */
+#define TIMER13_BASE ((struct timer_gen_reg_map*)0x40001C00)
+/** Timer 14 register map base pointer */
+#define TIMER14_BASE ((struct timer_gen_reg_map*)0x40002000)
+
+/*
+ * Device pointers
+ *
+ * We only declare device pointers to timers which actually exist on
+ * the target MCU. This helps when porting programs to STM32F1 (or
+ * within F1 to a lower density MCU), as attempts to use nonexistent
+ * timers cause build errors instead of undefined behavior.
+ */
+
+struct timer_dev;
+
+extern struct timer_dev *TIMER1;
+extern struct timer_dev *TIMER2;
+extern struct timer_dev *TIMER3;
+extern struct timer_dev *TIMER4;
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+extern struct timer_dev *TIMER5;
+extern struct timer_dev *TIMER6;
+extern struct timer_dev *TIMER7;
+extern struct timer_dev *TIMER8;
+#endif
+#ifdef STM32_XL_DENSITY
+extern struct timer_dev *TIMER9;
+extern struct timer_dev *TIMER10;
+extern struct timer_dev *TIMER11;
+extern struct timer_dev *TIMER12;
+extern struct timer_dev *TIMER13;
+extern struct timer_dev *TIMER14;
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/usart.h b/libmaple/stm32f1/include/series/usart.h
new file mode 100644
index 0000000..d12a3e2
--- /dev/null
+++ b/libmaple/stm32f1/include/series/usart.h
@@ -0,0 +1,76 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/usart.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 USART support.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_USART_H_
+#define _LIBMAPLE_STM32F1_USART_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/*
+ * Register map base pointers
+ */
+
+struct usart_reg_map;
+
+/** USART1 register map base pointer */
+#define USART1_BASE ((struct usart_reg_map*)0x40013800)
+/** USART2 register map base pointer */
+#define USART2_BASE ((struct usart_reg_map*)0x40004400)
+/** USART3 register map base pointer */
+#define USART3_BASE ((struct usart_reg_map*)0x40004800)
+#ifdef STM32_HIGH_DENSITY
+/** UART4 register map base pointer */
+#define UART4_BASE ((struct usart_reg_map*)0x40004C00)
+/** UART5 register map base pointer */
+#define UART5_BASE ((struct usart_reg_map*)0x40005000)
+#endif
+
+/*
+ * Devices
+ */
+
+struct usart_dev;
+extern struct usart_dev *USART1;
+extern struct usart_dev *USART2;
+extern struct usart_dev *USART3;
+#ifdef STM32_HIGH_DENSITY
+extern struct usart_dev *UART4;
+extern struct usart_dev *UART5;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/performance/isrs.S b/libmaple/stm32f1/performance/isrs.S
new file mode 100644
index 0000000..c638078
--- /dev/null
+++ b/libmaple/stm32f1/performance/isrs.S
@@ -0,0 +1,263 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/* STM32F1 performance line ISR weak declarations */
+
+#include <libmaple/stm32.h>
+
+ .thumb
+
+/* Default handler for all non-overridden interrupts and exceptions */
+ .globl __default_handler
+ .type __default_handler, %function
+
+__default_handler:
+ b .
+
+ .weak __exc_nmi
+ .globl __exc_nmi
+ .set __exc_nmi, __default_handler
+ .weak __exc_hardfault
+ .globl __exc_hardfault
+ .set __exc_hardfault, __default_handler
+ .weak __exc_memmanage
+ .globl __exc_memmanage
+ .set __exc_memmanage, __default_handler
+ .weak __exc_busfault
+ .globl __exc_busfault
+ .set __exc_busfault, __default_handler
+ .weak __exc_usagefault
+ .globl __exc_usagefault
+ .set __exc_usagefault, __default_handler
+ .weak __stm32reservedexception7
+ .globl __stm32reservedexception7
+ .set __stm32reservedexception7, __default_handler
+ .weak __stm32reservedexception8
+ .globl __stm32reservedexception8
+ .set __stm32reservedexception8, __default_handler
+ .weak __stm32reservedexception9
+ .globl __stm32reservedexception9
+ .set __stm32reservedexception9, __default_handler
+ .weak __stm32reservedexception10
+ .globl __stm32reservedexception10
+ .set __stm32reservedexception10, __default_handler
+ .weak __exc_svc
+ .globl __exc_svc
+ .set __exc_svc, __default_handler
+ .weak __exc_debug_monitor
+ .globl __exc_debug_monitor
+ .set __exc_debug_monitor, __default_handler
+ .weak __stm32reservedexception13
+ .globl __stm32reservedexception13
+ .set __stm32reservedexception13, __default_handler
+ .weak __exc_pendsv
+ .globl __exc_pendsv
+ .set __exc_pendsv, __default_handler
+ .weak __exc_systick
+ .globl __exc_systick
+ .set __exc_systick, __default_handler
+ .weak __irq_wwdg
+ .globl __irq_wwdg
+ .set __irq_wwdg, __default_handler
+ .weak __irq_pvd
+ .globl __irq_pvd
+ .set __irq_pvd, __default_handler
+ .weak __irq_tamper
+ .globl __irq_tamper
+ .set __irq_tamper, __default_handler
+ .weak __irq_rtc
+ .globl __irq_rtc
+ .set __irq_rtc, __default_handler
+ .weak __irq_flash
+ .globl __irq_flash
+ .set __irq_flash, __default_handler
+ .weak __irq_rcc
+ .globl __irq_rcc
+ .set __irq_rcc, __default_handler
+ .weak __irq_exti0
+ .globl __irq_exti0
+ .set __irq_exti0, __default_handler
+ .weak __irq_exti1
+ .globl __irq_exti1
+ .set __irq_exti1, __default_handler
+ .weak __irq_exti2
+ .globl __irq_exti2
+ .set __irq_exti2, __default_handler
+ .weak __irq_exti3
+ .globl __irq_exti3
+ .set __irq_exti3, __default_handler
+ .weak __irq_exti4
+ .globl __irq_exti4
+ .set __irq_exti4, __default_handler
+ .weak __irq_dma1_channel1
+ .globl __irq_dma1_channel1
+ .set __irq_dma1_channel1, __default_handler
+ .weak __irq_dma1_channel2
+ .globl __irq_dma1_channel2
+ .set __irq_dma1_channel2, __default_handler
+ .weak __irq_dma1_channel3
+ .globl __irq_dma1_channel3
+ .set __irq_dma1_channel3, __default_handler
+ .weak __irq_dma1_channel4
+ .globl __irq_dma1_channel4
+ .set __irq_dma1_channel4, __default_handler
+ .weak __irq_dma1_channel5
+ .globl __irq_dma1_channel5
+ .set __irq_dma1_channel5, __default_handler
+ .weak __irq_dma1_channel6
+ .globl __irq_dma1_channel6
+ .set __irq_dma1_channel6, __default_handler
+ .weak __irq_dma1_channel7
+ .globl __irq_dma1_channel7
+ .set __irq_dma1_channel7, __default_handler
+ .weak __irq_adc
+ .globl __irq_adc
+ .set __irq_adc, __default_handler
+ .weak __irq_usb_hp_can_tx
+ .globl __irq_usb_hp_can_tx
+ .set __irq_usb_hp_can_tx, __default_handler
+ .weak __irq_usb_lp_can_rx0
+ .globl __irq_usb_lp_can_rx0
+ .set __irq_usb_lp_can_rx0, __default_handler
+ .weak __irq_can_rx1
+ .globl __irq_can_rx1
+ .set __irq_can_rx1, __default_handler
+ .weak __irq_can_sce
+ .globl __irq_can_sce
+ .set __irq_can_sce, __default_handler
+ .weak __irq_exti9_5
+ .globl __irq_exti9_5
+ .set __irq_exti9_5, __default_handler
+ .weak __irq_tim1_brk
+ .globl __irq_tim1_brk
+ .set __irq_tim1_brk, __default_handler
+ .weak __irq_tim1_up
+ .globl __irq_tim1_up
+ .set __irq_tim1_up, __default_handler
+ .weak __irq_tim1_trg_com
+ .globl __irq_tim1_trg_com
+ .set __irq_tim1_trg_com, __default_handler
+ .weak __irq_tim1_cc
+ .globl __irq_tim1_cc
+ .set __irq_tim1_cc, __default_handler
+ .weak __irq_tim2
+ .globl __irq_tim2
+ .set __irq_tim2, __default_handler
+ .weak __irq_tim3
+ .globl __irq_tim3
+ .set __irq_tim3, __default_handler
+ .weak __irq_tim4
+ .globl __irq_tim4
+ .set __irq_tim4, __default_handler
+ .weak __irq_i2c1_ev
+ .globl __irq_i2c1_ev
+ .set __irq_i2c1_ev, __default_handler
+ .weak __irq_i2c1_er
+ .globl __irq_i2c1_er
+ .set __irq_i2c1_er, __default_handler
+ .weak __irq_i2c2_ev
+ .globl __irq_i2c2_ev
+ .set __irq_i2c2_ev, __default_handler
+ .weak __irq_i2c2_er
+ .globl __irq_i2c2_er
+ .set __irq_i2c2_er, __default_handler
+ .weak __irq_spi1
+ .globl __irq_spi1
+ .set __irq_spi1, __default_handler
+ .weak __irq_spi2
+ .globl __irq_spi2
+ .set __irq_spi2, __default_handler
+ .weak __irq_usart1
+ .globl __irq_usart1
+ .set __irq_usart1, __default_handler
+ .weak __irq_usart2
+ .globl __irq_usart2
+ .set __irq_usart2, __default_handler
+ .weak __irq_usart3
+ .globl __irq_usart3
+ .set __irq_usart3, __default_handler
+ .weak __irq_exti15_10
+ .globl __irq_exti15_10
+ .set __irq_exti15_10, __default_handler
+ .weak __irq_rtcalarm
+ .globl __irq_rtcalarm
+ .set __irq_rtcalarm, __default_handler
+ .weak __irq_usbwakeup
+ .globl __irq_usbwakeup
+ .set __irq_usbwakeup, __default_handler
+#if defined (STM32_HIGH_DENSITY)
+ .weak __irq_tim8_brk
+ .globl __irq_tim8_brk
+ .set __irq_tim8_brk, __default_handler
+ .weak __irq_tim8_up
+ .globl __irq_tim8_up
+ .set __irq_tim8_up, __default_handler
+ .weak __irq_tim8_trg_com
+ .globl __irq_tim8_trg_com
+ .set __irq_tim8_trg_com, __default_handler
+ .weak __irq_tim8_cc
+ .globl __irq_tim8_cc
+ .set __irq_tim8_cc, __default_handler
+ .weak __irq_adc3
+ .globl __irq_adc3
+ .set __irq_adc3, __default_handler
+ .weak __irq_fsmc
+ .globl __irq_fsmc
+ .set __irq_fsmc, __default_handler
+ .weak __irq_sdio
+ .globl __irq_sdio
+ .set __irq_sdio, __default_handler
+ .weak __irq_tim5
+ .globl __irq_tim5
+ .set __irq_tim5, __default_handler
+ .weak __irq_spi3
+ .globl __irq_spi3
+ .set __irq_spi3, __default_handler
+ .weak __irq_uart4
+ .globl __irq_uart4
+ .set __irq_uart4, __default_handler
+ .weak __irq_uart5
+ .globl __irq_uart5
+ .set __irq_uart5, __default_handler
+ .weak __irq_tim6
+ .globl __irq_tim6
+ .set __irq_tim6, __default_handler
+ .weak __irq_tim7
+ .globl __irq_tim7
+ .set __irq_tim7, __default_handler
+ .weak __irq_dma2_channel1
+ .globl __irq_dma2_channel1
+ .set __irq_dma2_channel1, __default_handler
+ .weak __irq_dma2_channel2
+ .globl __irq_dma2_channel2
+ .set __irq_dma2_channel2, __default_handler
+ .weak __irq_dma2_channel3
+ .globl __irq_dma2_channel3
+ .set __irq_dma2_channel3, __default_handler
+ .weak __irq_dma2_channel4_5
+ .globl __irq_dma2_channel4_5
+ .set __irq_dma2_channel4_5, __default_handler
+#endif /* STM32_HIGH_DENSITY */
diff --git a/libmaple/stm32f1/performance/vector_table.S b/libmaple/stm32f1/performance/vector_table.S
new file mode 100644
index 0000000..8be3fa6
--- /dev/null
+++ b/libmaple/stm32f1/performance/vector_table.S
@@ -0,0 +1,118 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/* STM32F1 performance line vector table */
+
+#include <libmaple/stm32.h>
+
+ .section ".stm32.interrupt_vector"
+
+ .globl __stm32_vector_table
+ .type __stm32_vector_table, %object
+
+__stm32_vector_table:
+/* CM3 core interrupts */
+ .long __msp_init
+ .long __exc_reset
+ .long __exc_nmi
+ .long __exc_hardfault
+ .long __exc_memmanage
+ .long __exc_busfault
+ .long __exc_usagefault
+ .long __stm32reservedexception7
+ .long __stm32reservedexception8
+ .long __stm32reservedexception9
+ .long __stm32reservedexception10
+ .long __exc_svc
+ .long __exc_debug_monitor
+ .long __stm32reservedexception13
+ .long __exc_pendsv
+ .long __exc_systick
+/* Peripheral interrupts */
+ .long __irq_wwdg
+ .long __irq_pvd
+ .long __irq_tamper
+ .long __irq_rtc
+ .long __irq_flash
+ .long __irq_rcc
+ .long __irq_exti0
+ .long __irq_exti1
+ .long __irq_exti2
+ .long __irq_exti3
+ .long __irq_exti4
+ .long __irq_dma1_channel1
+ .long __irq_dma1_channel2
+ .long __irq_dma1_channel3
+ .long __irq_dma1_channel4
+ .long __irq_dma1_channel5
+ .long __irq_dma1_channel6
+ .long __irq_dma1_channel7
+ .long __irq_adc
+ .long __irq_usb_hp_can_tx
+ .long __irq_usb_lp_can_rx0
+ .long __irq_can_rx1
+ .long __irq_can_sce
+ .long __irq_exti9_5
+ .long __irq_tim1_brk
+ .long __irq_tim1_up
+ .long __irq_tim1_trg_com
+ .long __irq_tim1_cc
+ .long __irq_tim2
+ .long __irq_tim3
+ .long __irq_tim4
+ .long __irq_i2c1_ev
+ .long __irq_i2c1_er
+ .long __irq_i2c2_ev
+ .long __irq_i2c2_er
+ .long __irq_spi1
+ .long __irq_spi2
+ .long __irq_usart1
+ .long __irq_usart2
+ .long __irq_usart3
+ .long __irq_exti15_10
+ .long __irq_rtcalarm
+ .long __irq_usbwakeup
+#if defined (STM32_HIGH_DENSITY)
+ .long __irq_tim8_brk
+ .long __irq_tim8_up
+ .long __irq_tim8_trg_com
+ .long __irq_tim8_cc
+ .long __irq_adc3
+ .long __irq_fsmc
+ .long __irq_sdio
+ .long __irq_tim5
+ .long __irq_spi3
+ .long __irq_uart4
+ .long __irq_uart5
+ .long __irq_tim6
+ .long __irq_tim7
+ .long __irq_dma2_channel1
+ .long __irq_dma2_channel2
+ .long __irq_dma2_channel3
+ .long __irq_dma2_channel4_5
+#endif /* STM32_HIGH_DENSITY */
+
+ .size __stm32_vector_table, . - __stm32_vector_table
diff --git a/libmaple/stm32f1/rcc.c b/libmaple/stm32f1/rcc.c
new file mode 100644
index 0000000..8d71a41
--- /dev/null
+++ b/libmaple/stm32f1/rcc.c
@@ -0,0 +1,164 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/rcc.c
+ * @brief STM32F1 RCC.
+ */
+
+#include <libmaple/rcc.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/bitband.h>
+
+#include "rcc_private.h"
+
+#define APB1 RCC_APB1
+#define APB2 RCC_APB2
+#define AHB RCC_AHB
+
+/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset
+ * register bit numbers. */
+const struct rcc_dev_info rcc_dev_table[] = {
+ [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 },
+ [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 },
+ [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 },
+ [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 },
+ [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 },
+ [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 },
+ [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 },
+ [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 },
+ [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 },
+ [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 },
+ [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 },
+ [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 },
+ [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 },
+ [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 },
+ [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 },
+ [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 },
+ [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 },
+ [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 },
+ [RCC_PWR] = { .clk_domain = APB1, .line_num = 28},
+ [RCC_BKP] = { .clk_domain = APB1, .line_num = 27},
+ [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 },
+ [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 },
+ [RCC_CRC] = { .clk_domain = AHB, .line_num = 6},
+ [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4},
+ [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2},
+ [RCC_USB] = { .clk_domain = APB1, .line_num = 23},
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 },
+ [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 },
+ [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 },
+ [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 },
+ [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 },
+ [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 },
+ [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 },
+ [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 },
+ [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 },
+ [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 },
+ [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 },
+ [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 },
+ [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 },
+ [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 },
+#endif
+#ifdef STM32_XL_DENSITY
+ [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 },
+ [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 },
+ [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 },
+ [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 },
+ [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 },
+ [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 },
+#endif
+};
+
+__deprecated
+void rcc_clk_init(rcc_sysclk_src sysclk_src,
+ rcc_pllsrc pll_src,
+ rcc_pll_multiplier pll_mul) {
+ /* Assume that we're going to clock the chip off the PLL, fed by
+ * the HSE */
+ ASSERT(sysclk_src == RCC_CLKSRC_PLL &&
+ pll_src == RCC_PLLSRC_HSE);
+
+ RCC_BASE->CFGR = pll_src | pll_mul;
+
+ /* Turn on, and wait for, HSE. */
+ rcc_turn_on_clk(RCC_CLK_HSE);
+ while (!rcc_is_clk_ready(RCC_CLK_HSE))
+ ;
+
+ /* Do the same for the main PLL. */
+ rcc_turn_on_clk(RCC_CLK_PLL);
+ while(!rcc_is_clk_ready(RCC_CLK_PLL))
+ ;
+
+ /* Finally, switch over to the PLL. */
+ rcc_switch_sysclk(RCC_CLKSRC_PLL);
+}
+
+/* pll_cfg->data must point to a valid struct stm32f1_rcc_pll_data. */
+void rcc_configure_pll(rcc_pll_cfg *pll_cfg) {
+ stm32f1_rcc_pll_data *data = pll_cfg->data;
+ rcc_pll_multiplier pll_mul = data->pll_mul;
+ uint32 cfgr;
+
+ /* Check that the PLL is disabled. */
+ ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL));
+
+ cfgr = RCC_BASE->CFGR;
+ cfgr &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL);
+ cfgr |= pll_cfg->pllsrc | pll_mul;
+ RCC_BASE->CFGR = cfgr;
+}
+
+void rcc_clk_enable(rcc_clk_id id) {
+ static __io uint32* enable_regs[] = {
+ [APB1] = &RCC_BASE->APB1ENR,
+ [APB2] = &RCC_BASE->APB2ENR,
+ [AHB] = &RCC_BASE->AHBENR,
+ };
+ rcc_do_clk_enable(enable_regs, id);
+}
+
+void rcc_reset_dev(rcc_clk_id id) {
+ static __io uint32* reset_regs[] = {
+ [APB1] = &RCC_BASE->APB1RSTR,
+ [APB2] = &RCC_BASE->APB2RSTR,
+ };
+ rcc_do_reset_dev(reset_regs, id);
+}
+
+void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) {
+ static const uint32 masks[] = {
+ [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE,
+ [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1,
+ [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2,
+ [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE,
+ [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE,
+ };
+ rcc_do_set_prescaler(masks, prescaler, divider);
+}
diff --git a/libmaple/stm32f1/rules.mk b/libmaple/stm32f1/rules.mk
new file mode 100644
index 0000000..f1cc23e
--- /dev/null
+++ b/libmaple/stm32f1/rules.mk
@@ -0,0 +1,45 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror
+ASFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror
+
+# Extra BUILDDIRS
+BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_F1_LINE)
+
+# Local rules and targets
+sSRCS_$(d) := $(MCU_F1_LINE)/isrs.S
+sSRCS_$(d) += $(MCU_F1_LINE)/vector_table.S
+
+cSRCS_$(d) := adc.c
+cSRCS_$(d) += bkp.c
+cSRCS_$(d) += dma.c
+cSRCS_$(d) += exti.c
+cSRCS_$(d) += fsmc.c
+cSRCS_$(d) += gpio.c
+cSRCS_$(d) += i2c.c
+cSRCS_$(d) += rcc.c
+cSRCS_$(d) += spi.c
+cSRCS_$(d) += timer.c
+cSRCS_$(d) += usart.c
+
+sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
+ $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_ASFLAGS := $(ASFLAGS_$(d))
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp))
diff --git a/libmaple/stm32f1/spi.c b/libmaple/stm32f1/spi.c
new file mode 100644
index 0000000..1c78cc3
--- /dev/null
+++ b/libmaple/stm32f1/spi.c
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/spi.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 SPI/I2S.
+ */
+
+#include <libmaple/spi.h>
+#include <libmaple/gpio.h>
+#include "spi_private.h"
+
+/*
+ * Devices
+ */
+
+static spi_dev spi1 = SPI_DEV(1);
+static spi_dev spi2 = SPI_DEV(2);
+
+spi_dev *SPI1 = &spi1;
+spi_dev *SPI2 = &spi2;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static spi_dev spi3 = SPI_DEV(3);
+spi_dev *SPI3 = &spi3;
+#endif
+
+/*
+ * Routines
+ */
+
+void spi_config_gpios(spi_dev *ignored,
+ uint8 as_master,
+ gpio_dev *nss_dev,
+ uint8 nss_bit,
+ gpio_dev *comm_dev,
+ uint8 sck_bit,
+ uint8 miso_bit,
+ uint8 mosi_bit) {
+ if (as_master) {
+ gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING);
+ gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP);
+ } else {
+ gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING);
+ gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING);
+ gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING);
+ }
+}
+
+void spi_foreach(void (*fn)(spi_dev*)) {
+ fn(SPI1);
+ fn(SPI2);
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ fn(SPI3);
+#endif
+}
diff --git a/libmaple/stm32f1/timer.c b/libmaple/stm32f1/timer.c
new file mode 100644
index 0000000..8b9e976
--- /dev/null
+++ b/libmaple/stm32f1/timer.c
@@ -0,0 +1,124 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/timer.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 timer.
+ */
+
+#include <libmaple/timer.h>
+#include <libmaple/stm32.h>
+#include "timer_private.h"
+
+/*
+ * IRQ handlers
+ *
+ * Defer to the timer_private dispatch API.
+ *
+ * FIXME: The names of these handlers are inaccurate since XL-density
+ * devices came out. Update these to match the STM32F2 names, maybe
+ * using some weak symbol magic to preserve backwards compatibility if
+ * possible. Once that's done, we can just move the IRQ handlers into
+ * the top-level libmaple/timer.c, and there will be no need for this
+ * file.
+ */
+
+void __irq_tim1_brk(void) {
+ dispatch_adv_brk(TIMER1);
+#if STM32_HAVE_TIMER(9)
+ dispatch_tim_9_12(TIMER9);
+#endif
+}
+
+void __irq_tim1_up(void) {
+ dispatch_adv_up(TIMER1);
+#if STM32_HAVE_TIMER(10)
+ dispatch_tim_10_11_13_14(TIMER10);
+#endif
+}
+
+void __irq_tim1_trg_com(void) {
+ dispatch_adv_trg_com(TIMER1);
+#if STM32_HAVE_TIMER(11)
+ dispatch_tim_10_11_13_14(TIMER11);
+#endif
+}
+
+void __irq_tim1_cc(void) {
+ dispatch_adv_cc(TIMER1);
+}
+
+void __irq_tim2(void) {
+ dispatch_general(TIMER2);
+}
+
+void __irq_tim3(void) {
+ dispatch_general(TIMER3);
+}
+
+void __irq_tim4(void) {
+ dispatch_general(TIMER4);
+}
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+void __irq_tim5(void) {
+ dispatch_general(TIMER5);
+}
+
+void __irq_tim6(void) {
+ dispatch_basic(TIMER6);
+}
+
+void __irq_tim7(void) {
+ dispatch_basic(TIMER7);
+}
+
+void __irq_tim8_brk(void) {
+ dispatch_adv_brk(TIMER8);
+#if STM32_HAVE_TIMER(12)
+ dispatch_tim_9_12(TIMER12);
+#endif
+}
+
+void __irq_tim8_up(void) {
+ dispatch_adv_up(TIMER8);
+#if STM32_HAVE_TIMER(13)
+ dispatch_tim_10_11_13_14(TIMER13);
+#endif
+}
+
+void __irq_tim8_trg_com(void) {
+ dispatch_adv_trg_com(TIMER8);
+#if STM32_HAVE_TIMER(14)
+ dispatch_tim_10_11_13_14(TIMER14);
+#endif
+}
+
+void __irq_tim8_cc(void) {
+ dispatch_adv_cc(TIMER8);
+}
+#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */
diff --git a/libmaple/stm32f1/usart.c b/libmaple/stm32f1/usart.c
new file mode 100644
index 0000000..b3b849f
--- /dev/null
+++ b/libmaple/stm32f1/usart.c
@@ -0,0 +1,170 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/usart.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief STM32F1 USART.
+ */
+
+#include <libmaple/usart.h>
+#include <libmaple/gpio.h>
+#include "usart_private.h"
+
+/*
+ * Devices
+ */
+
+static ring_buffer usart1_rb;
+static usart_dev usart1 = {
+ .regs = USART1_BASE,
+ .rb = &usart1_rb,
+ .max_baud = 4500000UL,
+ .clk_id = RCC_USART1,
+ .irq_num = NVIC_USART1,
+};
+/** USART1 device */
+usart_dev *USART1 = &usart1;
+
+static ring_buffer usart2_rb;
+static usart_dev usart2 = {
+ .regs = USART2_BASE,
+ .rb = &usart2_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_USART2,
+ .irq_num = NVIC_USART2,
+};
+/** USART2 device */
+usart_dev *USART2 = &usart2;
+
+static ring_buffer usart3_rb;
+static usart_dev usart3 = {
+ .regs = USART3_BASE,
+ .rb = &usart3_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_USART3,
+ .irq_num = NVIC_USART3,
+};
+/** USART3 device */
+usart_dev *USART3 = &usart3;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static ring_buffer uart4_rb;
+static usart_dev uart4 = {
+ .regs = UART4_BASE,
+ .rb = &uart4_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_UART4,
+ .irq_num = NVIC_UART4,
+};
+/** UART4 device */
+usart_dev *UART4 = &uart4;
+
+static ring_buffer uart5_rb;
+static usart_dev uart5 = {
+ .regs = UART5_BASE,
+ .rb = &uart5_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_UART5,
+ .irq_num = NVIC_UART5,
+};
+/** UART5 device */
+usart_dev *UART5 = &uart5;
+#endif
+
+/*
+ * Routines
+ */
+
+void usart_config_gpios_async(usart_dev *udev,
+ gpio_dev *rx_dev, uint8 rx,
+ gpio_dev *tx_dev, uint8 tx,
+ unsigned flags) {
+ gpio_set_mode(rx_dev, rx, GPIO_INPUT_FLOATING);
+ gpio_set_mode(tx_dev, tx, GPIO_AF_OUTPUT_PP);
+}
+
+void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) {
+ uint32 integer_part;
+ uint32 fractional_part;
+ uint32 tmp;
+
+ /* Figure out the clock speed, if the user doesn't give one. */
+ if (clock_speed == 0) {
+ clock_speed = _usart_clock_freq(dev);
+ }
+ ASSERT(clock_speed);
+
+ /* Convert desired baud rate to baud rate register setting. */
+ integer_part = (25 * clock_speed) / (4 * baud);
+ tmp = (integer_part / 100) << 4;
+ fractional_part = integer_part - (100 * (tmp >> 4));
+ tmp |= (((fractional_part * 16) + 50) / 100) & ((uint8)0x0F);
+
+ dev->regs->BRR = (uint16)tmp;
+}
+
+/**
+ * @brief Call a function on each USART.
+ * @param fn Function to call.
+ */
+void usart_foreach(void (*fn)(usart_dev*)) {
+ fn(USART1);
+ fn(USART2);
+ fn(USART3);
+#ifdef STM32_HIGH_DENSITY
+ fn(UART4);
+ fn(UART5);
+#endif
+}
+
+/*
+ * Interrupt handlers.
+ */
+
+void __irq_usart1(void) {
+ usart_irq(&usart1_rb, USART1_BASE);
+}
+
+void __irq_usart2(void) {
+ usart_irq(&usart2_rb, USART2_BASE);
+}
+
+void __irq_usart3(void) {
+ usart_irq(&usart3_rb, USART3_BASE);
+}
+
+#ifdef STM32_HIGH_DENSITY
+void __irq_uart4(void) {
+ usart_irq(&uart4_rb, UART4_BASE);
+}
+
+void __irq_uart5(void) {
+ usart_irq(&uart5_rb, UART5_BASE);
+}
+#endif
diff --git a/libmaple/stm32f1/value/isrs.S b/libmaple/stm32f1/value/isrs.S
new file mode 100644
index 0000000..858016b
--- /dev/null
+++ b/libmaple/stm32f1/value/isrs.S
@@ -0,0 +1,270 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 Perry Hung.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/* STM32F1 value line ISR weak declarations */
+
+ .thumb
+
+/* Default handler for all non-overridden interrupts and exceptions */
+ .globl __default_handler
+ .type __default_handler, %function
+
+__default_handler:
+ b .
+
+ .weak __msp_init
+ .globl __msp_init
+ .set __msp_init, __default_handler
+ .weak __exc_reset
+ .globl __exc_reset
+ .set __exc_reset, __default_handler
+ .weak __exc_nmi
+ .globl __exc_nmi
+ .set __exc_nmi, __default_handler
+ .weak __exc_hardfault
+ .globl __exc_hardfault
+ .set __exc_hardfault, __default_handler
+ .weak __exc_memmanage
+ .globl __exc_memmanage
+ .set __exc_memmanage, __default_handler
+ .weak __exc_busfault
+ .globl __exc_busfault
+ .set __exc_busfault, __default_handler
+ .weak __exc_usagefault
+ .globl __exc_usagefault
+ .set __exc_usagefault, __default_handler
+ .weak __stm32reservedexception7
+ .globl __stm32reservedexception7
+ .set __stm32reservedexception7, __default_handler
+ .weak __stm32reservedexception8
+ .globl __stm32reservedexception8
+ .set __stm32reservedexception8, __default_handler
+ .weak __stm32reservedexception9
+ .globl __stm32reservedexception9
+ .set __stm32reservedexception9, __default_handler
+ .weak __stm32reservedexception10
+ .globl __stm32reservedexception10
+ .set __stm32reservedexception10, __default_handler
+ .weak __exc_svc
+ .globl __exc_svc
+ .set __exc_svc, __default_handler
+ .weak __exc_debug_monitor
+ .globl __exc_debug_monitor
+ .set __exc_debug_monitor, __default_handler
+ .weak __stm32reservedexception13
+ .globl __stm32reservedexception13
+ .set __stm32reservedexception13, __default_handler
+ .weak __exc_pendsv
+ .globl __exc_pendsv
+ .set __exc_pendsv, __default_handler
+ .weak __exc_systick
+ .globl __exc_systick
+ .set __exc_systick, __default_handler
+
+ .weak __irq_wwdg
+ .globl __irq_wwdg
+ .set __irq_wwdg, __default_handler
+ .weak __irq_pvd
+ .globl __irq_pvd
+ .set __irq_pvd, __default_handler
+ .weak __irq_tamper
+ .globl __irq_tamper
+ .set __irq_tamper, __default_handler
+ .weak __irq_rtc
+ .globl __irq_rtc
+ .set __irq_rtc, __default_handler
+ .weak __irq_flash
+ .globl __irq_flash
+ .set __irq_flash, __default_handler
+ .weak __irq_rcc
+ .globl __irq_rcc
+ .set __irq_rcc, __default_handler
+ .weak __irq_exti0
+ .globl __irq_exti0
+ .set __irq_exti0, __default_handler
+ .weak __irq_exti1
+ .globl __irq_exti1
+ .set __irq_exti1, __default_handler
+ .weak __irq_exti2
+ .globl __irq_exti2
+ .set __irq_exti2, __default_handler
+ .weak __irq_exti3
+ .globl __irq_exti3
+ .set __irq_exti3, __default_handler
+ .weak __irq_exti4
+ .globl __irq_exti4
+ .set __irq_exti4, __default_handler
+ .weak __irq_dma1_channel1
+ .globl __irq_dma1_channel1
+ .set __irq_dma1_channel1, __default_handler
+ .weak __irq_dma1_channel2
+ .globl __irq_dma1_channel2
+ .set __irq_dma1_channel2, __default_handler
+ .weak __irq_dma1_channel3
+ .globl __irq_dma1_channel3
+ .set __irq_dma1_channel3, __default_handler
+ .weak __irq_dma1_channel4
+ .globl __irq_dma1_channel4
+ .set __irq_dma1_channel4, __default_handler
+ .weak __irq_dma1_channel5
+ .globl __irq_dma1_channel5
+ .set __irq_dma1_channel5, __default_handler
+ .weak __irq_dma1_channel6
+ .globl __irq_dma1_channel6
+ .set __irq_dma1_channel6, __default_handler
+ .weak __irq_dma1_channel7
+ .globl __irq_dma1_channel7
+ .set __irq_dma1_channel7, __default_handler
+ .weak __irq_adc1
+ .globl __irq_adc1
+ .set __irq_adc1, __default_handler
+ .weak __stm32reservedexception14
+ .globl __stm32reservedexception14
+ .set __stm32reservedexception14, __default_handler
+ .weak __stm32reservedexception15
+ .globl __stm32reservedexception15
+ .set __stm32reservedexception15, __default_handler
+ .weak __stm32reservedexception16
+ .globl __stm32reservedexception16
+ .set __stm32reservedexception16, __default_handler
+ .weak __stm32reservedexception17
+ .globl __stm32reservedexception17
+ .set __stm32reservedexception17, __default_handler
+ .weak __irq_exti9_5
+ .globl __irq_exti9_5
+ .set __irq_exti9_5, __default_handler
+ .weak __irq_tim1_brk
+ .globl __irq_tim1_brk
+ .set __irq_tim1_brk, __default_handler
+ .weak __irq_tim1_up
+ .globl __irq_tim1_up
+ .set __irq_tim1_up, __default_handler
+ .weak __irq_tim1_trg_com
+ .globl __irq_tim1_trg_com
+ .set __irq_tim1_trg_com, __default_handler
+ .weak __irq_tim1_cc
+ .globl __irq_tim1_cc
+ .set __irq_tim1_cc, __default_handler
+ .weak __irq_tim2
+ .globl __irq_tim2
+ .set __irq_tim2, __default_handler
+ .weak __irq_tim3
+ .globl __irq_tim3
+ .set __irq_tim3, __default_handler
+ .weak __irq_tim4
+ .globl __irq_tim4
+ .set __irq_tim4, __default_handler
+ .weak __irq_i2c1_ev
+ .globl __irq_i2c1_ev
+ .set __irq_i2c1_ev, __default_handler
+ .weak __irq_i2c1_er
+ .globl __irq_i2c1_er
+ .set __irq_i2c1_er, __default_handler
+ .weak __irq_i2c2_ev
+ .globl __irq_i2c2_ev
+ .set __irq_i2c2_ev, __default_handler
+ .weak __irq_i2c2_er
+ .globl __irq_i2c2_er
+ .set __irq_i2c2_er, __default_handler
+ .weak __irq_spi1
+ .globl __irq_spi1
+ .set __irq_spi1, __default_handler
+ .weak __irq_spi2
+ .globl __irq_spi2
+ .set __irq_spi2, __default_handler
+ .weak __irq_usart1
+ .globl __irq_usart1
+ .set __irq_usart1, __default_handler
+ .weak __irq_usart2
+ .globl __irq_usart2
+ .set __irq_usart2, __default_handler
+ .weak __irq_usart3
+ .globl __irq_usart3
+ .set __irq_usart3, __default_handler
+ .weak __irq_exti15_10
+ .globl __irq_exti15_10
+ .set __irq_exti15_10, __default_handler
+ .weak __irq_rtcalarm
+ .globl __irq_rtcalarm
+ .set __irq_rtcalarm, __default_handler
+ .weak __irq_cec
+ .globl __irq_cec
+ .set __irq_cec, __default_handler
+ .weak __irq_tim12
+ .globl __irq_tim12
+ .set __irq_tim12, __default_handler
+ .weak __irq_tim13
+ .globl __irq_tim13
+ .set __irq_tim13, __default_handler
+ .weak __irq_tim14
+ .globl __irq_tim14
+ .set __irq_tim14, __default_handler
+ .weak __stm32reservedexception18
+ .globl __stm32reservedexception18
+ .set __stm32reservedexception18, __default_handler
+ .weak __stm32reservedexception19
+ .globl __stm32reservedexception19
+ .set __stm32reservedexception19, __default_handler
+ .weak __irq_fsmc
+ .globl __irq_fsmc
+ .set __irq_fsmc, __default_handler
+ .weak __stm32reservedexception20
+ .globl __stm32reservedexception20
+ .set __stm32reservedexception20, __default_handler
+ .weak __irq_tim5
+ .globl __irq_tim5
+ .set __irq_tim5, __default_handler
+ .weak __irq_spi3
+ .globl __irq_spi3
+ .set __irq_spi3, __default_handler
+ .weak __irq_uart4
+ .globl __irq_uart4
+ .set __irq_uart4, __default_handler
+ .weak __irq_uart5
+ .globl __irq_uart5
+ .set __irq_uart5, __default_handler
+ .weak __irq_tim6
+ .globl __irq_tim6
+ .set __irq_tim6, __default_handler
+ .weak __irq_tim7
+ .globl __irq_tim7
+ .set __irq_tim7, __default_handler
+ .weak __irq_dma2_channel1
+ .globl __irq_dma2_channel1
+ .set __irq_dma2_channel1, __default_handler
+ .weak __irq_dma2_channel2
+ .globl __irq_dma2_channel2
+ .set __irq_dma2_channel2, __default_handler
+ .weak __irq_dma2_channel3
+ .globl __irq_dma2_channel3
+ .set __irq_dma2_channel3, __default_handler
+ .weak __irq_dma2_channel4_5
+ .globl __irq_dma2_channel4_5
+ .set __irq_dma2_channel4_5, __default_handler
+ .weak __irq_dma2_channel5 /* on remap only */
+ .globl __irq_dma2_channel5
+ .set __irq_dma2_channel5, __default_handler
diff --git a/libmaple/stm32f1/value/vector_table.S b/libmaple/stm32f1/value/vector_table.S
new file mode 100644
index 0000000..76a2a6e
--- /dev/null
+++ b/libmaple/stm32f1/value/vector_table.S
@@ -0,0 +1,116 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 Perry Hung.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/* STM32F1 value line vector table */
+
+ .section ".stm32.interrupt_vector"
+
+ .globl __stm32_vector_table
+ .type __stm32_vector_table, %object
+
+__stm32_vector_table:
+/* CM3 core interrupts */
+ .long __msp_init
+ .long __exc_reset
+ .long __exc_nmi
+ .long __exc_hardfault
+ .long __exc_memmanage
+ .long __exc_busfault
+ .long __exc_usagefault
+ .long __stm32reservedexception7
+ .long __stm32reservedexception8
+ .long __stm32reservedexception9
+ .long __stm32reservedexception10
+ .long __exc_svc
+ .long __exc_debug_monitor
+ .long __stm32reservedexception13
+ .long __exc_pendsv
+ .long __exc_systick
+/* Peripheral interrupts */
+ .long __irq_wwdg
+ .long __irq_pvd
+ .long __irq_tamper
+ .long __irq_rtc
+ .long __irq_flash
+ .long __irq_rcc
+ .long __irq_exti0
+ .long __irq_exti1
+ .long __irq_exti2
+ .long __irq_exti3
+ .long __irq_exti4
+ .long __irq_dma1_channel1
+ .long __irq_dma1_channel2
+ .long __irq_dma1_channel3
+ .long __irq_dma1_channel4
+ .long __irq_dma1_channel5
+ .long __irq_dma1_channel6
+ .long __irq_dma1_channel7
+ .long __irq_adc1
+ .long __stm32reservedexception14
+ .long __stm32reservedexception15
+ .long __stm32reservedexception16
+ .long __stm32reservedexception17
+ .long __irq_exti9_5
+ .long __irq_tim1_brk
+ .long __irq_tim1_up
+ .long __irq_tim1_trg_com
+ .long __irq_tim1_cc
+ .long __irq_tim2
+ .long __irq_tim3
+ .long __irq_tim4
+ .long __irq_i2c1_ev
+ .long __irq_i2c1_er
+ .long __irq_i2c2_ev
+ .long __irq_i2c2_er
+ .long __irq_spi1
+ .long __irq_spi2
+ .long __irq_usart1
+ .long __irq_usart2
+ .long __irq_usart3
+ .long __irq_exti15_10
+ .long __irq_rtcalarm
+ .long __irq_cec
+ .long __irq_tim12
+ .long __irq_tim13
+ .long __irq_tim14
+ .long __stm32reservedexception18
+ .long __stm32reservedexception19
+ .long __irq_fsmc
+ .long __stm32reservedexception20
+ .long __irq_tim5
+ .long __irq_spi3
+ .long __irq_uart4
+ .long __irq_uart5
+ .long __irq_tim6
+ .long __irq_tim7
+ .long __irq_dma2_channel1
+ .long __irq_dma2_channel2
+ .long __irq_dma2_channel3
+ .long __irq_dma2_channel4_5
+ .long __irq_dma2_channel5 /* on remap only */
+
+ .size __stm32_vector_table, . - __stm32_vector_table
diff --git a/libmaple/stm32f2/adc.c b/libmaple/stm32f2/adc.c
new file mode 100644
index 0000000..a400d7b
--- /dev/null
+++ b/libmaple/stm32f2/adc.c
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/adc.c
+ * @brief STM32F2 ADC.
+ */
+
+#include <libmaple/adc.h>
+#include <libmaple/gpio.h>
+
+/*
+ * Devices
+ */
+
+static adc_dev adc1 = {
+ .regs = ADC1_BASE,
+ .clk_id = RCC_ADC1,
+};
+/** ADC1 device. */
+const adc_dev *ADC1 = &adc1;
+
+static adc_dev adc2 = {
+ .regs = ADC2_BASE,
+ .clk_id = RCC_ADC2,
+};
+/** ADC2 device. */
+const adc_dev *ADC2 = &adc2;
+
+static adc_dev adc3 = {
+ .regs = ADC3_BASE,
+ .clk_id = RCC_ADC3,
+};
+/** ADC3 device. */
+const adc_dev *ADC3 = &adc3;
+
+/*
+ * Common routines
+ */
+
+void adc_set_prescaler(adc_prescaler pre) {
+ uint32 ccr = ADC_COMMON_BASE->CCR;
+ ccr &= ~ADC_CCR_ADCPRE;
+ ccr |= (uint32)pre;
+ ADC_COMMON_BASE->CCR = ccr;
+}
+
+void adc_foreach(void (*fn)(const adc_dev*)) {
+ fn(ADC1);
+ fn(ADC2);
+ fn(ADC3);
+}
+
+void adc_config_gpio(const adc_dev *ignored, gpio_dev *gdev, uint8 bit) {
+ gpio_set_modef(gdev, bit, GPIO_MODE_ANALOG, GPIO_MODEF_PUPD_NONE);
+}
+
+void adc_enable_single_swstart(const adc_dev *dev) {
+ adc_init(dev);
+ adc_enable(dev);
+}
diff --git a/libmaple/stm32f2/dma.c b/libmaple/stm32f2/dma.c
new file mode 100644
index 0000000..26e87b9
--- /dev/null
+++ b/libmaple/stm32f2/dma.c
@@ -0,0 +1,504 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/dma.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 DMA support.
+ */
+
+#include <libmaple/dma.h>
+#include <libmaple/bitband.h>
+#include <libmaple/util.h>
+
+/* Hack to ensure inlining in dma_irq_handler() */
+#define DMA_GET_HANDLER(dev, tube) (dev->handlers[tube].handler)
+#include "dma_private.h"
+
+/*
+ * Devices
+ */
+
+static dma_dev dma1 = {
+ .regs = DMA1_BASE,
+ .clk_id = RCC_DMA1,
+ .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA1_STREAM0 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM1 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM2 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM3 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM4 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM5 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM6 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM7 }},
+};
+dma_dev *DMA1 = &dma1;
+
+static dma_dev dma2 = {
+ .regs = DMA2_BASE,
+ .clk_id = RCC_DMA2,
+ .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_STREAM0 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM1 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM2 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM3 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM4 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM5 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM6 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM7 }},
+};
+dma_dev *DMA2 = &dma2;
+
+/*
+ * Helpers for dealing with dma_request_src's bit encoding (see the
+ * comments in the dma_request_src definition).
+ */
+
+/* rcc_clk_id of dma_dev which supports src. */
+static __always_inline rcc_clk_id src_clk_id(dma_request_src src) {
+ return (rcc_clk_id)(((uint32)src >> 3) & 0x3F);
+}
+
+/* Bit vector of streams supporting src (e.g., bit 0 set => DMA_S0 support). */
+static __always_inline uint32 src_stream_mask(dma_request_src src) {
+ return ((uint32)src >> 10) & 0xFF;
+}
+
+/* Channel corresponding to src. */
+static __always_inline dma_channel src_channel(dma_request_src src) {
+ return (dma_channel)(src & 0x7);
+}
+
+/*
+ * Routines
+ */
+
+/* For convenience */
+#define ASSERT_NOT_ENABLED(dev, tube) ASSERT(!dma_is_enabled(dev, tube))
+
+/* Helpers for dma_tube_cfg() */
+static int preconfig_check(dma_dev *dev, dma_tube tube, dma_tube_config *cfg);
+static int postconfig_check(dma_tube_reg_map *dummy, dma_tube_config *cfg);
+static int config_fifo(dma_tube_reg_map *dummy, dma_tube_config *cfg);
+static int config_src_dst(dma_tube_reg_map *dummy, dma_tube_config *cfg);
+static void copy_regs(dma_tube_reg_map *src, dma_tube_reg_map *dst);
+
+int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg) {
+ dma_tube_reg_map dummy_regs;
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ int ret;
+
+ /* Initial error checking. */
+ ret = preconfig_check(dev, tube, cfg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Disable `tube' as per RM0033. */
+ dma_disable(dev, tube);
+ dma_clear_isr_bits(dev, tube);
+
+ /* Don't write to tregs until we've decided `cfg' is really OK,
+ * so as not to make a half-formed mess if we have to error out. */
+ copy_regs(tregs, &dummy_regs);
+
+ /* Try to reconfigure `tube', bailing on error. */
+ ret = config_fifo(&dummy_regs, cfg);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = config_src_dst(&dummy_regs, cfg);
+ if (ret < 0) {
+ return ret;
+ }
+ dummy_regs.SNDTR = cfg->tube_nr_xfers;
+ ret = postconfig_check(&dummy_regs, cfg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Ok, we're good. Commit to the new configuration. */
+ copy_regs(&dummy_regs, tregs);
+ return ret;
+}
+
+void dma_set_priority(dma_dev *dev, dma_stream stream, dma_priority priority) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, stream);
+ uint32 scr;
+ ASSERT_NOT_ENABLED(dev, stream);
+ scr = tregs->SCR;
+ scr &= ~DMA_SCR_PL;
+ scr |= (priority << 16);
+ tregs->SCR = scr;
+}
+
+void dma_set_num_transfers(dma_dev *dev, dma_tube tube, uint16 num_transfers) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ ASSERT_NOT_ENABLED(dev, tube);
+ tregs->SNDTR = num_transfers;
+}
+
+/**
+ * @brief Set memory 0 or memory 1 address.
+ *
+ * This is a general function for setting one of the two memory
+ * addresses available on the double-buffered STM32F2 DMA controllers.
+ *
+ * @param dev DMA device
+ * @param tube Tube on dev.
+ * @param n If 0, set memory 0 address. If 1, set memory 1 address.
+ * @param address Address to set
+ */
+void dma_set_mem_n_addr(dma_dev *dev, dma_tube tube, int n,
+ __io void *address) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ uint32 addr = (uint32)address;
+
+ ASSERT_NOT_ENABLED(dev, tube);
+ if (n) {
+ tregs->SM1AR = addr;
+ } else {
+ tregs->SM0AR = addr;
+ }
+}
+
+void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ ASSERT_NOT_ENABLED(dev, tube);
+ tregs->SPAR = (uint32)address;
+}
+
+/**
+ * @brief Enable a stream's FIFO.
+ *
+ * You may only call this function when the stream is disabled.
+ *
+ * @param dev DMA device
+ * @param tube Stream whose FIFO to enable.
+ */
+void dma_enable_fifo(dma_dev *dev, dma_tube tube) {
+ ASSERT_NOT_ENABLED(dev, tube);
+ bb_peri_set_bit(&(dma_tube_regs(dev, tube)->SFCR), DMA_SFCR_DMDIS_BIT, 1);
+}
+
+/**
+ * @brief Disable a stream's FIFO.
+ *
+ * You may only call this function when the stream is disabled.
+ *
+ * @param dev DMA device
+ * @param tube Stream whose FIFO to disable.
+ */
+void dma_disable_fifo(dma_dev *dev, dma_tube tube) {
+ ASSERT_NOT_ENABLED(dev, tube);
+ bb_peri_set_bit(&(dma_tube_regs(dev, tube)->SFCR), DMA_SFCR_DMDIS_BIT, 0);
+}
+
+void dma_attach_interrupt(dma_dev *dev, dma_tube tube,
+ void (*handler)(void)) {
+ dev->handlers[tube].handler = handler;
+ nvic_irq_enable(dev->handlers[tube].irq_line);
+}
+
+void dma_detach_interrupt(dma_dev *dev, dma_tube tube) {
+ nvic_irq_disable(dev->handlers[tube].irq_line);
+ dev->handlers[tube].handler = NULL;
+}
+
+void dma_enable(dma_dev *dev, dma_tube tube) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ bb_peri_set_bit(&tregs->SCR, DMA_SCR_EN_BIT, 1);
+}
+
+void dma_disable(dma_dev *dev, dma_tube tube) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ bb_peri_set_bit(&tregs->SCR, DMA_SCR_EN_BIT, 0);
+ /* The stream might not get disabled immediately, so wait. */
+ while (tregs->SCR & DMA_SCR_EN)
+ ;
+}
+
+dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube) {
+ /* TODO: does it still make sense to have this function? We should
+ * probably just be returning the ISR bits, with some defines to
+ * pull the flags out. The lack of masked status bits is an
+ * annoyance that would require documentation to solve, though. */
+ uint8 status_bits = dma_get_isr_bits(dev, tube);
+ dma_clear_isr_bits(dev, tube);
+ ASSERT(status_bits); /* Or something's very wrong */
+ /* Don't change the order of these if statements. */
+ if (status_bits & 0x0) {
+ return DMA_TRANSFER_FIFO_ERROR;
+ } else if (status_bits & 0x4) {
+ return DMA_TRANSFER_DME_ERROR;
+ } else if (status_bits & 0x8) {
+ return DMA_TRANSFER_ERROR;
+ } else if (status_bits & 0x20) {
+ return DMA_TRANSFER_COMPLETE;
+ } else if (status_bits & 0x10) {
+ return DMA_TRANSFER_HALF_COMPLETE;
+ }
+
+ /* Something's wrong; one of those bits should have been set. Fail
+ * an assert, and mimic the error behavior in case of a high debug
+ * level. */
+ ASSERT(0);
+ dma_disable(dev, tube);
+ return DMA_TRANSFER_ERROR;
+}
+
+/*
+ * IRQ handlers
+ */
+
+void __irq_dma1_stream0(void) {
+ dma_irq_handler(DMA1, DMA_S0);
+}
+
+void __irq_dma1_stream1(void) {
+ dma_irq_handler(DMA1, DMA_S1);
+}
+
+void __irq_dma1_stream2(void) {
+ dma_irq_handler(DMA1, DMA_S2);
+}
+
+void __irq_dma1_stream3(void) {
+ dma_irq_handler(DMA1, DMA_S3);
+}
+
+void __irq_dma1_stream4(void) {
+ dma_irq_handler(DMA1, DMA_S4);
+}
+
+void __irq_dma1_stream5(void) {
+ dma_irq_handler(DMA1, DMA_S5);
+}
+
+void __irq_dma1_stream6(void) {
+ dma_irq_handler(DMA1, DMA_S6);
+}
+
+void __irq_dma1_stream7(void) {
+ dma_irq_handler(DMA1, DMA_S7);
+}
+
+void __irq_dma2_stream0(void) {
+ dma_irq_handler(DMA2, DMA_S0);
+}
+
+void __irq_dma2_stream1(void) {
+ dma_irq_handler(DMA2, DMA_S1);
+}
+
+void __irq_dma2_stream2(void) {
+ dma_irq_handler(DMA2, DMA_S2);
+}
+
+void __irq_dma2_stream3(void) {
+ dma_irq_handler(DMA2, DMA_S3);
+}
+
+void __irq_dma2_stream4(void) {
+ dma_irq_handler(DMA2, DMA_S4);
+}
+
+void __irq_dma2_stream5(void) {
+ dma_irq_handler(DMA2, DMA_S5);
+}
+
+void __irq_dma2_stream6(void) {
+ dma_irq_handler(DMA2, DMA_S6);
+}
+
+void __irq_dma2_stream7(void) {
+ dma_irq_handler(DMA2, DMA_S7);
+}
+
+/*
+ * Auxiliary routines for dma_tube_cfg()
+ */
+
+/* Is addr acceptable for use as DMA src/dst? */
+static int cfg_mem_ok(__io void *addr) {
+ enum dma_atype atype = _dma_addr_type(addr);
+ return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER;
+}
+
+/* Is src -> dst a reasonable combination of [MEM,PER] -> [MEM,PER]? */
+static int cfg_dir_ok(dma_dev *dev, __io void *src, __io void *dst) {
+ switch (_dma_addr_type(dst)) {
+ case DMA_ATYPE_MEM:
+ /* Only DMA2 can do memory-to-memory */
+ return ((_dma_addr_type(src) == DMA_ATYPE_PER) ||
+ (dev->clk_id == RCC_DMA2));
+ case DMA_ATYPE_PER:
+ /* Peripheral-to-peripheral is illegal */
+ return _dma_addr_type(src) == DMA_ATYPE_PER;
+ default: /* Can't happen */
+ ASSERT(0);
+ return 0;
+ }
+}
+
+/* Initial sanity check for dma_tube_cfg() */
+static int preconfig_check(dma_dev *dev, dma_tube tube,
+ dma_tube_config *cfg) {
+ if (!(src_stream_mask(cfg->tube_req_src) & (1U << tube))) {
+ /* ->tube_req_src not supported by stream */
+ return -DMA_TUBE_CFG_EREQ;
+ }
+ if (cfg->tube_nr_xfers > 65535) {
+ /* That's too many. */
+ return -DMA_TUBE_CFG_ENDATA;
+ }
+ if (src_clk_id(cfg->tube_req_src) != dev->clk_id) {
+ /* ->tube_req_src not supported by dev */
+ return -DMA_TUBE_CFG_EDEV;
+ }
+ if (!cfg_mem_ok(cfg->tube_src)) {
+ return -DMA_TUBE_CFG_ESRC;
+ }
+ if (!cfg_mem_ok(cfg->tube_dst)) {
+ return -DMA_TUBE_CFG_EDST;
+ }
+ if (!cfg_dir_ok(dev, cfg->tube_src, cfg->tube_dst)) {
+ return -DMA_TUBE_CFG_EDIR;
+ }
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+static int config_fifo(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ /* TODO: FIFO configuration based on cfg->target_data */
+ uint32 sfcr = dummy->SFCR;
+ sfcr &= ~DMA_SFCR_FEIE;
+ sfcr |= (cfg->tube_flags & DMA_CFG_FIFO_ERR_IE) ? DMA_SFCR_FEIE : 0;
+ dummy->SFCR = sfcr;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Helper for configuring (DMA_SxCR) */
+#define BITS_WE_CARE_ABOUT \
+ (DMA_SCR_CHSEL | DMA_SCR_MBURST | DMA_SCR_PBURST | DMA_SCR_PINCOS | \
+ DMA_SCR_MINC | DMA_SCR_PINC | DMA_SCR_CIRC | DMA_SCR_DIR | \
+ DMA_SCR_PFCTRL | DMA_SCR_TCIE | DMA_SCR_HTIE | DMA_SCR_TEIE | \
+ DMA_SCR_DMEIE)
+static inline void config_scr(dma_tube_reg_map *dummy, dma_tube_config *cfg,
+ unsigned src_shift, uint32 src_inc,
+ unsigned dst_shift, uint32 dst_inc,
+ uint32 dir) {
+ /* These would go here if we supported them: MBURST, PBURST,
+ * PINCOS, PFCTRL. We explicitly choose low priority, and double
+ * buffering belongs elsewhere, I think. [mbolivar] */
+ uint32 flags = cfg->tube_flags & BITS_WE_CARE_ABOUT;
+ uint32 scr = dummy->SCR;
+ scr &= ~(BITS_WE_CARE_ABOUT | DMA_SCR_PL);
+ scr |= (/* CHSEL */
+ (src_channel(cfg->tube_req_src) << 25) |
+ /* MSIZE/PSIZE */
+ (cfg->tube_src_size << src_shift) |
+ (cfg->tube_dst_size << dst_shift) |
+ /* MINC/PINC */
+ ((cfg->tube_flags & DMA_CFG_SRC_INC) ? src_inc : 0) |
+ ((cfg->tube_flags & DMA_CFG_DST_INC) ? dst_inc : 0) |
+ /* DIR */
+ dir |
+ /* Other flags carried by cfg->tube_flags */
+ flags);
+ dummy->SCR = scr;
+}
+#undef BITS_WE_CARE_ABOUT
+
+/* Helper for when cfg->tube_dst is memory */
+static int config_to_mem(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ uint32 dir = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ?
+ DMA_SCR_DIR_MEM_TO_MEM : DMA_SCR_DIR_PER_TO_MEM);
+
+ if ((dir == DMA_SCR_DIR_MEM_TO_MEM) && (cfg->tube_flags & DMA_CFG_CIRC)) {
+ return -DMA_TUBE_CFG_ECFG; /* Can't do DMA_CFG_CIRC and mem->mem. */
+ }
+
+ config_scr(dummy, cfg, 11, DMA_SCR_PINC, 13, DMA_SCR_MINC, dir);
+ dummy->SPAR = (uint32)cfg->tube_src;
+ dummy->SM0AR = (uint32)cfg->tube_dst;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Helper for when cfg->tube_src is peripheral */
+static int config_to_per(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ config_scr(dummy, cfg, 13, DMA_SCR_MINC, 11, DMA_SCR_PINC,
+ DMA_SCR_DIR_MEM_TO_PER);
+ dummy->SM0AR = (uint32)cfg->tube_src;
+ dummy->SPAR = (uint32)cfg->tube_dst;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Configures SCR, SPAR, SM0AR, and checks that the result is OK. */
+static int config_src_dst(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ switch (_dma_addr_type(cfg->tube_dst)) {
+ case DMA_ATYPE_MEM:
+ return config_to_mem(dummy, cfg);
+ case DMA_ATYPE_PER:
+ return config_to_per(dummy, cfg);
+ case DMA_ATYPE_OTHER:
+ default: /* shut up, GCC */
+ /* Can't happen */
+ ASSERT(0);
+ return -DMA_TUBE_CFG_ECFG;
+ }
+}
+
+/* Final checks we can only perform when fully configured */
+static int postconfig_check(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ /* TODO add dma_get_[mem,per]_size() and use them here */
+ /* msize and psize are in bytes here: */
+ uint32 scr = dummy->SCR;
+ uint32 msize = 1U << ((scr >> 13) & 0x3);
+ uint32 psize = 1U << ((scr >> 11) & 0x3);
+
+ /* Ensure NDT will work with PSIZE/MSIZE.
+ *
+ * RM0033 specifies that PSIZE, MSIZE, and NDT must be such that
+ * the last transfer completes; i.e. that if PSIZE < MSIZE, then
+ * NDT is a multiple of MSIZE/PSIZE. See e.g. Table 27. */
+ if ((psize < msize) && (cfg->tube_nr_xfers % (msize / psize))) {
+ return -DMA_TUBE_CFG_ENDATA;
+ }
+
+ /* Direct mode is only possible if MSIZE == PSIZE. */
+ if ((msize != psize) && !(dummy->SFCR & DMA_SFCR_DMDIS)) {
+ return -DMA_TUBE_CFG_ESIZE;
+ }
+
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Convenience for dealing with dummy registers */
+static void copy_regs(dma_tube_reg_map *src, dma_tube_reg_map *dst) {
+ dst->SCR = src->SCR;
+ dst->SNDTR = src->SNDTR;
+ dst->SPAR = src->SPAR;
+ dst->SM0AR = src->SM0AR;
+ dst->SFCR = src->SFCR;
+}
diff --git a/libmaple/stm32f2/exti.c b/libmaple/stm32f2/exti.c
new file mode 100644
index 0000000..208415f
--- /dev/null
+++ b/libmaple/stm32f2/exti.c
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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 <libmaple/exti.h>
+#include <libmaple/syscfg.h>
+#include "exti_private.h"
+
+void exti_select(exti_num num, exti_cfg cfg) {
+ exti_do_select(&SYSCFG_BASE->EXTICR[num / 4], num, cfg);
+}
diff --git a/libmaple/stm32f2/fsmc.c b/libmaple/stm32f2/fsmc.c
new file mode 100644
index 0000000..ec41720
--- /dev/null
+++ b/libmaple/stm32f2/fsmc.c
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/fsmc.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 FSMC support.
+ */
+
+#include <libmaple/fsmc.h>
+#include <libmaple/gpio.h>
+
+#define CONFIG_GPIO(dev, bit) \
+ do { \
+ gpio_set_modef(dev, bit, GPIO_MODE_AF, GPIO_MODEF_SPEED_HIGH); \
+ gpio_set_af(dev, bit, GPIO_AF_FSMC_SDIO_OTG_FS); \
+ } while (0)
+void fsmc_sram_init_gpios(void) {
+ /* Data lines... */
+ CONFIG_GPIO(GPIOD, 0);
+ CONFIG_GPIO(GPIOD, 1);
+ CONFIG_GPIO(GPIOD, 8);
+ CONFIG_GPIO(GPIOD, 9);
+ CONFIG_GPIO(GPIOD, 10);
+ CONFIG_GPIO(GPIOD, 14);
+ CONFIG_GPIO(GPIOD, 15);
+ CONFIG_GPIO(GPIOE, 7);
+ CONFIG_GPIO(GPIOE, 8);
+ CONFIG_GPIO(GPIOE, 9);
+ CONFIG_GPIO(GPIOE, 10);
+ CONFIG_GPIO(GPIOE, 11);
+ CONFIG_GPIO(GPIOE, 12);
+ CONFIG_GPIO(GPIOE, 13);
+ CONFIG_GPIO(GPIOE, 14);
+ CONFIG_GPIO(GPIOE, 15);
+
+ /* Address lines... */
+ CONFIG_GPIO(GPIOD, 11);
+ CONFIG_GPIO(GPIOD, 12);
+ CONFIG_GPIO(GPIOD, 13);
+ CONFIG_GPIO(GPIOF, 0);
+ CONFIG_GPIO(GPIOF, 1);
+ CONFIG_GPIO(GPIOF, 2);
+ CONFIG_GPIO(GPIOF, 3);
+ CONFIG_GPIO(GPIOF, 4);
+ CONFIG_GPIO(GPIOF, 5);
+ CONFIG_GPIO(GPIOF, 12);
+ CONFIG_GPIO(GPIOF, 13);
+ CONFIG_GPIO(GPIOF, 14);
+ CONFIG_GPIO(GPIOF, 15);
+ CONFIG_GPIO(GPIOG, 0);
+ CONFIG_GPIO(GPIOG, 1);
+ CONFIG_GPIO(GPIOG, 2);
+ CONFIG_GPIO(GPIOG, 3);
+ CONFIG_GPIO(GPIOG, 4);
+ CONFIG_GPIO(GPIOG, 5);
+
+ /* And control lines... */
+ CONFIG_GPIO(GPIOD, 4);
+ CONFIG_GPIO(GPIOD, 5);
+ CONFIG_GPIO(GPIOD, 7);
+ CONFIG_GPIO(GPIOG, 9);
+ CONFIG_GPIO(GPIOG, 10);
+ CONFIG_GPIO(GPIOG, 12);
+ CONFIG_GPIO(GPIOE, 0);
+ CONFIG_GPIO(GPIOE, 1);
+}
diff --git a/libmaple/stm32f2/gpio.c b/libmaple/stm32f2/gpio.c
new file mode 100644
index 0000000..a26edaa
--- /dev/null
+++ b/libmaple/stm32f2/gpio.c
@@ -0,0 +1,194 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/gpio.c
+ * @brief STM32F2 GPIO.
+ */
+
+#include <libmaple/gpio.h>
+#include <libmaple/rcc.h>
+#include <libmaple/bitband.h>
+
+/*
+ * GPIO devices
+ */
+
+gpio_dev gpioa = {
+ .regs = GPIOA_BASE,
+ .clk_id = RCC_GPIOA,
+ .exti_port = EXTI_PA,
+};
+/** GPIO port A device. */
+gpio_dev* const GPIOA = &gpioa;
+
+gpio_dev gpiob = {
+ .regs = GPIOB_BASE,
+ .clk_id = RCC_GPIOB,
+ .exti_port = EXTI_PB,
+};
+/** GPIO port B device. */
+gpio_dev* const GPIOB = &gpiob;
+
+gpio_dev gpioc = {
+ .regs = GPIOC_BASE,
+ .clk_id = RCC_GPIOC,
+ .exti_port = EXTI_PC,
+};
+/** GPIO port C device. */
+gpio_dev* const GPIOC = &gpioc;
+
+gpio_dev gpiod = {
+ .regs = GPIOD_BASE,
+ .clk_id = RCC_GPIOD,
+ .exti_port = EXTI_PD,
+};
+/** GPIO port D device. */
+gpio_dev* const GPIOD = &gpiod;
+
+gpio_dev gpioe = {
+ .regs = GPIOE_BASE,
+ .clk_id = RCC_GPIOE,
+ .exti_port = EXTI_PE,
+};
+/** GPIO port E device. */
+gpio_dev* const GPIOE = &gpioe;
+
+gpio_dev gpiof = {
+ .regs = GPIOF_BASE,
+ .clk_id = RCC_GPIOF,
+ .exti_port = EXTI_PF,
+};
+/** GPIO port F device. */
+gpio_dev* const GPIOF = &gpiof;
+
+gpio_dev gpiog = {
+ .regs = GPIOG_BASE,
+ .clk_id = RCC_GPIOG,
+ .exti_port = EXTI_PG,
+};
+/** GPIO port G device. */
+gpio_dev* const GPIOG = &gpiog;
+
+gpio_dev gpioh = {
+ .regs = GPIOH_BASE,
+ .clk_id = RCC_GPIOH,
+ .exti_port = EXTI_PH,
+};
+/** GPIO port G device. */
+gpio_dev* const GPIOH = &gpioh;
+
+gpio_dev gpioi = {
+ .regs = GPIOI_BASE,
+ .clk_id = RCC_GPIOI,
+ .exti_port = EXTI_PI,
+};
+/** GPIO port G device. */
+gpio_dev* const GPIOI = &gpioi;
+
+/*
+ * GPIO routines
+ */
+
+/**
+ * Initialize and reset all available GPIO devices.
+ */
+void gpio_init_all(void) {
+ gpio_init(GPIOA);
+ gpio_init(GPIOB);
+ gpio_init(GPIOC);
+ gpio_init(GPIOD);
+ gpio_init(GPIOE);
+ gpio_init(GPIOF);
+ gpio_init(GPIOG);
+ gpio_init(GPIOH);
+ gpio_init(GPIOI);
+}
+
+/**
+ * @brief Set the mode of a GPIO pin.
+ * @param dev GPIO device.
+ * @param bit Bit on dev whose mode to set, 0--15.
+ * @param mode Mode to set the pin to.
+ * @param flags Flags to modify basic mode configuration
+ */
+void gpio_set_modef(gpio_dev *dev,
+ uint8 bit,
+ gpio_pin_mode mode,
+ unsigned flags) {
+ gpio_reg_map *regs = dev->regs;
+ unsigned shift = bit * 2;
+ uint32 tmp;
+
+ /* Mode */
+ tmp = regs->MODER;
+ tmp &= ~(0x3 << shift);
+ tmp |= mode << shift;
+ regs->MODER = tmp;
+
+ /* Output type */
+ bb_peri_set_bit(&regs->OTYPER, bit, flags & 0x1);
+
+ /* Speed */
+ tmp = regs->OSPEEDR;
+ tmp &= ~(0x3 << shift);
+ tmp |= ((flags >> 1) & 0x3) << shift;
+ regs->OSPEEDR = tmp;
+
+ /* Pull-up/pull-down */
+ tmp = regs->PUPDR;
+ tmp &= ~(0x3 << shift);
+ tmp |= ((flags >> 3) & 0x3) << shift;
+ regs->PUPDR = tmp;
+}
+
+/**
+ * @brief Set a pin's alternate function.
+ *
+ * The pin must have its mode set to GPIO_MODE_AF for this to take
+ * effect.
+ *
+ * @param dev Device whose pin to configure.
+ * @param bit Pin whose alternate function to set.
+ * @param af Alternate function to use for pin.
+ * @see gpio_set_modef()
+ */
+void gpio_set_af(gpio_dev *dev, uint8 bit, gpio_af af) {
+ __io uint32 *afr;
+ unsigned shift;
+ uint32 tmp;
+ if (bit >= 8) {
+ afr = &dev->regs->AFRH;
+ shift = 4 * (bit - 8);
+ } else{
+ afr = &dev->regs->AFRL;
+ shift = 4 * bit;
+ }
+ tmp = *afr;
+ tmp &= ~(0xF << shift);
+ tmp |= (af << shift);
+ *afr = tmp;
+}
diff --git a/libmaple/stm32f2/include/series/adc.h b/libmaple/stm32f2/include/series/adc.h
new file mode 100644
index 0000000..175fe11
--- /dev/null
+++ b/libmaple/stm32f2/include/series/adc.h
@@ -0,0 +1,335 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/adc.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * @brief STM32F2 ADC support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_ADC_H_
+#define _LIBMAPLE_STM32F2_ADC_H_
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Devices
+ */
+
+extern const struct adc_dev *ADC1;
+extern const struct adc_dev *ADC2;
+extern const struct adc_dev *ADC3;
+
+/*
+ * Common register map
+ */
+
+/** ADC common register map type */
+typedef struct adc_common_reg_map {
+ __io uint32 CSR; /**< Common status register */
+ __io uint32 CCR; /**< Common control register */
+ __io uint32 CDR; /**<
+ * @brief Common regular data register
+ * for dual and triple modes */
+} adc_common_reg_map;
+
+/*
+ * Register map base pointers
+ */
+
+/** ADC1 register map base pointer. */
+#define ADC1_BASE ((struct adc_reg_map*)0x40012000)
+/** ADC2 register map base pointer. */
+#define ADC2_BASE ((struct adc_reg_map*)0x40012100)
+/** ADC3 register map base pointer. */
+#define ADC3_BASE ((struct adc_reg_map*)0x40012200)
+/** ADC common register map base pointer. */
+#define ADC_COMMON_BASE ((struct adc_common_reg_map*)0x40012300)
+
+/*
+ * Register bit definitions
+ */
+
+/* Status register */
+
+/** Overrun bit. */
+#define ADC_SR_OVR_BIT 5
+/** Overrun. */
+#define ADC_SR_OVR (1U << ADC_SR_OVR_BIT)
+
+/* Control register 1 */
+
+/** Overrun interrupt enable bit. */
+#define ADC_CR1_OVRIE_BIT 26
+
+/** Overrun interrupt error enable. */
+#define ADC_CR1_OVRIE (1U << ADC_CR1_OVRIE_BIT)
+/** Conversion resolution. */
+#define ADC_CR1_RES (0x3U << 24)
+/** Conversion resolution: 12 bit (at least 15 ADCCLK cycles). */
+#define ADC_CR1_RES_12BIT (0x0U << 24)
+/** Conversion resolution: 10 bit (at least 13 ADCCLK cycles). */
+#define ADC_CR1_RES_10BIT (0x1U << 24)
+/** Conversion resolution: 8 bit (at least 11 ADCCLK cycles). */
+#define ADC_CR1_RES_8BIT (0x2U << 24)
+/** Conversion resolution: 6 bit (at least 9 ADCCLK cycles). */
+#define ADC_CR1_RES_6BIT (0x3U << 24)
+
+/* Control register 2 */
+
+#define ADC_CR2_SWSTART_BIT 30
+#define ADC_CR2_JSWSTART_BIT 22
+#define ADC_CR2_ALIGN_BIT 11
+#define ADC_CR2_EOCS_BIT 10
+#define ADC_CR2_DDS_BIT 9
+#define ADC_CR2_DMA_BIT 8
+#define ADC_CR2_CONT_BIT 1
+#define ADC_CR2_ADON_BIT 0
+
+#define ADC_CR2_SWSTART (1U << ADC_CR2_SWSTART_BIT)
+#define ADC_CR2_EXTEN (0x3 << 28)
+#define ADC_CR2_EXTEN_DISABLED (0x0 << 28)
+#define ADC_CR2_EXTEN_RISE (0x1 << 28)
+#define ADC_CR2_EXTEN_FALL (0x2 << 28)
+#define ADC_CR2_EXTEN_RISE_FALL (0x3 << 28)
+#define ADC_CR2_EXTSEL (0xF << 24)
+#define ADC_CR2_EXTSEL_TIM1_CC1 (0x0 << 24)
+#define ADC_CR2_EXTSEL_TIM1_CC2 (0x1 << 24)
+#define ADC_CR2_EXTSEL_TIM1_CC3 (0x2 << 24)
+#define ADC_CR2_EXTSEL_TIM2_CC2 (0x3 << 24)
+#define ADC_CR2_EXTSEL_TIM2_CC3 (0x4 << 24)
+#define ADC_CR2_EXTSEL_TIM2_CC4 (0x5 << 24)
+#define ADC_CR2_EXTSEL_TIM1_TRGO (0x6 << 24)
+#define ADC_CR2_EXTSEL_TIM3_CC1 (0x7 << 24)
+#define ADC_CR2_EXTSEL_TIM3_TRGO (0x8 << 24)
+#define ADC_CR2_EXTSEL_TIM4_CC4 (0x9 << 24)
+#define ADC_CR2_EXTSEL_TIM5_CC1 (0xA << 24)
+#define ADC_CR2_EXTSEL_TIM5_CC2 (0xB << 24)
+#define ADC_CR2_EXTSEL_TIM5_CC3 (0xC << 24)
+#define ADC_CR2_EXTSEL_TIM8_CC1 (0xD << 24)
+#define ADC_CR2_EXTSEL_TIM8_TRGO (0xE << 24)
+#define ADC_CR2_EXTSEL_TIM1_EXTI11 (0xF << 24)
+#define ADC_CR2_JSWSTART (1U << ADC_CR2_JSWSTART_BIT)
+#define ADC_CR2_JEXTEN (0x3 << 20)
+#define ADC_CR2_JEXTEN_DISABLED (0x0 << 20)
+#define ADC_CR2_JEXTEN_RISE (0x1 << 20)
+#define ADC_CR2_JEXTEN_FALL (0x2 << 20)
+#define ADC_CR2_JEXTEN_RISE_FALL (0x3 << 20)
+#define ADC_CR2_JEXTSEL (0xF << 16)
+#define ADC_CR2_JEXTSEL_TIM1_CC4 (0x0 << 16)
+#define ADC_CR2_JEXTSEL_TIM1_TRGO (0x1 << 16)
+#define ADC_CR2_JEXTSEL_TIM2_CC1 (0x2 << 16)
+#define ADC_CR2_JEXTSEL_TIM2_TRGO (0x3 << 16)
+#define ADC_CR2_JEXTSEL_TIM3_CC2 (0x4 << 16)
+#define ADC_CR2_JEXTSEL_TIM3_CC4 (0x5 << 16)
+#define ADC_CR2_JEXTSEL_TIM4_CC1 (0x6 << 16)
+#define ADC_CR2_JEXTSEL_TIM4_CC2 (0x7 << 16)
+#define ADC_CR2_JEXTSEL_TIM4_CC3 (0x8 << 16)
+#define ADC_CR2_JEXTSEL_TIM4_TRGO (0x9 << 16)
+#define ADC_CR2_JEXTSEL_TIM5_CC4 (0xA << 16)
+#define ADC_CR2_JEXTSEL_TIM5_TRGO (0xB << 16)
+#define ADC_CR2_JEXTSEL_TIM8_CC2 (0xC << 16)
+#define ADC_CR2_JEXTSEL_TIM8_CC3 (0xD << 16)
+#define ADC_CR2_JEXTSEL_TIM8_CC4 (0xE << 16)
+#define ADC_CR2_JEXTSEL_TIM1_EXTI15 (0xF << 16)
+#define ADC_CR2_ALIGN (1U << ADC_CR2_ALIGN_BIT)
+#define ADC_CR2_ALIGN_RIGHT (0U << ADC_CR2_ALIGN_BIT)
+#define ADC_CR2_ALIGN_LEFT (1U << ADC_CR2_ALIGN_BIT)
+#define ADC_CR2_EOCS (1U << ADC_CR2_EOCS_BIT)
+#define ADC_CR2_EOCS_SEQUENCE (0U << ADC_CR2_EOCS_BIT)
+#define ADC_CR2_EOCS_CONVERSION (1U << ADC_CR2_EOCS_BIT)
+#define ADC_CR2_DDS (1U << ADC_CR2_DDS_BIT)
+#define ADC_CR2_DMA (1U << ADC_CR2_DMA_BIT)
+#define ADC_CR2_CONT (1U << ADC_CR2_CONT_BIT)
+#define ADC_CR2_ADON (1U << ADC_CR2_ADON_BIT)
+
+/* Common status register */
+
+#define ADC_CSR_OVR3_BIT 21
+#define ADC_CSR_STRT3_BIT 20
+#define ADC_CSR_JSTRT3_BIT 19
+#define ADC_CSR_JEOC3_BIT 18
+#define ADC_CSR_EOC3_BIT 17
+#define ADC_CSR_AWD3_BIT 16
+#define ADC_CSR_OVR2_BIT 13
+#define ADC_CSR_STRT2_BIT 12
+#define ADC_CSR_JSTRT2_BIT 11
+#define ADC_CSR_JEOC2_BIT 10
+#define ADC_CSR_EOC2_BIT 9
+#define ADC_CSR_AWD2_BIT 8
+#define ADC_CSR_OVR1_BIT 5
+#define ADC_CSR_STRT1_BIT 4
+#define ADC_CSR_JSTRT1_BIT 3
+#define ADC_CSR_JEOC1_BIT 2
+#define ADC_CSR_EOC1_BIT 1
+#define ADC_CSR_AWD1_BIT 0
+
+#define ADC_CSR_OVR3 (1U << ADC_CSR_OVR3_BIT)
+#define ADC_CSR_STRT3 (1U << ADC_CSR_STRT3_BIT)
+#define ADC_CSR_JSTRT3 (1U << ADC_CSR_JSTRT3_BIT)
+#define ADC_CSR_JEOC3 (1U << ADC_CSR_JEOC3_BIT)
+#define ADC_CSR_EOC3 (1U << ADC_CSR_EOC3_BIT)
+#define ADC_CSR_AWD3 (1U << ADC_CSR_AWD3_BIT)
+#define ADC_CSR_OVR2 (1U << ADC_CSR_OVR2_BIT)
+#define ADC_CSR_STRT2 (1U << ADC_CSR_STRT2_BIT)
+#define ADC_CSR_JSTRT2 (1U << ADC_CSR_JSTRT2_BIT)
+#define ADC_CSR_JEOC2 (1U << ADC_CSR_JEOC2_BIT)
+#define ADC_CSR_EOC2 (1U << ADC_CSR_EOC2_BIT)
+#define ADC_CSR_AWD2 (1U << ADC_CSR_AWD2_BIT)
+#define ADC_CSR_OVR1 (1U << ADC_CSR_OVR1_BIT)
+#define ADC_CSR_STRT1 (1U << ADC_CSR_STRT1_BIT)
+#define ADC_CSR_JSTRT1 (1U << ADC_CSR_JSTRT1_BIT)
+#define ADC_CSR_JEOC1 (1U << ADC_CSR_JEOC1_BIT)
+#define ADC_CSR_EOC1 (1U << ADC_CSR_EOC1_BIT)
+#define ADC_CSR_AWD1 (1U << ADC_CSR_AWD1_BIT)
+
+/* Common control register */
+
+#define ADC_CCR_TSVREFE_BIT 23
+#define ADC_CCR_VBATE_BIT 22
+#define ADC_CCR_DDS_BIT 13
+
+#define ADC_CCR_TSVREFE (1U << ADC_CCR_TSVREFE_BIT)
+#define ADC_CCR_VBATE (1U << ADC_CCR_VBATE_BIT)
+#define ADC_CCR_ADCPRE (0x3 << 16)
+#define ADC_CCR_ADCPRE_PCLK2_DIV_2 (0x0 << 16)
+#define ADC_CCR_ADCPRE_PCLK2_DIV_4 (0x1 << 16)
+#define ADC_CCR_ADCPRE_PCLK2_DIV_6 (0x2 << 16)
+#define ADC_CCR_ADCPRE_PCLK2_DIV_8 (0x3 << 16)
+#define ADC_CCR_DMA (0x3 << 14)
+#define ADC_CCR_DMA_DIS (0x0 << 14)
+#define ADC_CCR_DMA_MODE_1 (0x1 << 14)
+#define ADC_CCR_DMA_MODE_2 (0x2 << 14)
+#define ADC_CCR_DMA_MODE_3 (0x3 << 14)
+#define ADC_CCR_DDS (1U << ADC_CCR_DDS_BIT)
+#define ADC_CCR_DELAY (0xF << 8)
+#define ADC_CCR_DELAY_5 (0x0 << 8)
+#define ADC_CCR_DELAY_6 (0x1 << 8)
+#define ADC_CCR_DELAY_7 (0x2 << 8)
+#define ADC_CCR_DELAY_8 (0x3 << 8)
+#define ADC_CCR_DELAY_9 (0x4 << 8)
+#define ADC_CCR_DELAY_10 (0x5 << 8)
+#define ADC_CCR_DELAY_11 (0x6 << 8)
+#define ADC_CCR_DELAY_12 (0x7 << 8)
+#define ADC_CCR_DELAY_13 (0x8 << 8)
+#define ADC_CCR_DELAY_14 (0x9 << 8)
+#define ADC_CCR_DELAY_15 (0xA << 8)
+#define ADC_CCR_DELAY_16 (0xB << 8)
+#define ADC_CCR_DELAY_17 (0xC << 8)
+#define ADC_CCR_DELAY_18 (0xD << 8)
+#define ADC_CCR_DELAY_19 (0xE << 8)
+#define ADC_CCR_DELAY_20 (0xF << 8)
+/** Multi ADC mode selection. */
+#define ADC_CCR_MULTI 0x1F
+/** All ADCs independent. */
+#define ADC_CCR_MULTI_INDEPENDENT 0x0
+/** Dual mode: combined regular simultaneous/injected simultaneous. */
+#define ADC_CCR_MULTI_DUAL_REG_SIM_INJ_SIM 0x1
+/** Dual mode: combined regular simultaneous/alternate trigger. */
+#define ADC_CCR_MULTI_DUAL_REG_SIM_ALT_TRIG 0x2
+/** Dual mode: injected simultaneous mode only. */
+#define ADC_CCR_MULTI_DUAL_INJ_SIM 0x5
+/** Dual mode: regular simultaneous mode only. */
+#define ADC_CCR_MULTI_DUAL_REG_SIM 0x6
+/** Dual mode: interleaved mode only. */
+#define ADC_CCR_MULTI_DUAL_INTER 0x7
+/** Dual mode: alternate trigger mode only. */
+#define ADC_CCR_MULTI_DUAL_ALT_TRIG 0x9
+/** Triple mode: combined regular simultaneous/injected simultaneous. */
+#define ADC_CCR_MULTI_TRIPLE_REG_SIM_INJ_SIM 0x10
+/** Triple mode: combined regular simultaneous/alternate trigger. */
+#define ADC_CCR_MULTI_TRIPLE_REG_SIM_ALT_TRIG 0x11
+/** Triple mode: injected simultaneous mode only. */
+#define ADC_CCR_MULTI_TRIPLE_INJ_SIM 0x12
+/** Triple mode: regular simultaneous mode only. */
+#define ADC_CCR_MULTI_TRIPLE_REG_SIM 0x15
+/** Triple mode: interleaved mode only. */
+#define ADC_CCR_MULTI_TRIPLE_INTER 0x17
+/** Triple mode: alternate trigger mode only. */
+#define ADC_CCR_MULTI_TRIPLE_ALT_TRIG 0x19
+
+/* Common regular data register for dual and triple modes */
+
+#define ADC_CDR_DATA2 0xFFFF0000
+#define ADC_CDR_DATA1 0xFFFF
+
+/*
+ * Other types
+ */
+
+/**
+ * @brief STM32F2 external event selectors for regular group
+ * conversion.
+ * @see adc_set_extsel()
+ */
+typedef enum adc_extsel_event {
+ ADC_EXT_EV_TIM1_CC1 = ADC_CR2_EXTSEL_TIM1_CC1,
+ ADC_EXT_EV_TIM1_CC2 = ADC_CR2_EXTSEL_TIM1_CC2,
+ ADC_EXT_EV_TIM1_CC3 = ADC_CR2_EXTSEL_TIM1_CC3,
+ ADC_EXT_EV_TIM2_CC2 = ADC_CR2_EXTSEL_TIM2_CC2,
+ ADC_EXT_EV_TIM2_CC3 = ADC_CR2_EXTSEL_TIM2_CC3,
+ ADC_EXT_EV_TIM2_CC4 = ADC_CR2_EXTSEL_TIM2_CC4,
+ ADC_EXT_EV_TIM1_TRGO = ADC_CR2_EXTSEL_TIM1_TRGO,
+ ADC_EXT_EV_TIM3_CC1 = ADC_CR2_EXTSEL_TIM3_CC1,
+ ADC_EXT_EV_TIM3_TRGO = ADC_CR2_EXTSEL_TIM3_TRGO,
+ ADC_EXT_EV_TIM4_CC4 = ADC_CR2_EXTSEL_TIM4_CC4,
+ ADC_EXT_EV_TIM5_CC1 = ADC_CR2_EXTSEL_TIM5_CC1,
+ ADC_EXT_EV_TIM5_CC2 = ADC_CR2_EXTSEL_TIM5_CC2,
+ ADC_EXT_EV_TIM5_CC3 = ADC_CR2_EXTSEL_TIM5_CC3,
+ ADC_EXT_EV_TIM8_CC1 = ADC_CR2_EXTSEL_TIM8_CC1,
+ ADC_EXT_EV_TIM8_TRGO = ADC_CR2_EXTSEL_TIM8_TRGO,
+ ADC_EXT_EV_TIM1_EXTI11 = ADC_CR2_EXTSEL_TIM1_EXTI11,
+} adc_extsel_event;
+
+/**
+ * @brief STM32F2 sample times, in ADC clock cycles.
+ */
+typedef enum adc_smp_rate {
+ ADC_SMPR_3, /**< 3 ADC cycles */
+ ADC_SMPR_15, /**< 15 ADC cycles */
+ ADC_SMPR_28, /**< 28 ADC cycles */
+ ADC_SMPR_56, /**< 56 ADC cycles */
+ ADC_SMPR_84, /**< 84 ADC cycles */
+ ADC_SMPR_112, /**< 112 ADC cycles */
+ ADC_SMPR_144, /**< 144 ADC cycles */
+ ADC_SMPR_480, /**< 480 ADC cycles */
+} adc_smp_rate;
+
+/**
+ * @brief STM32F2 ADC prescalers, as divisors of PCLK2.
+ */
+typedef enum adc_prescaler {
+ /** PCLK2 divided by 2 */
+ ADC_PRE_PCLK2_DIV_2 = ADC_CCR_ADCPRE_PCLK2_DIV_2,
+ /** PCLK2 divided by 4 */
+ ADC_PRE_PCLK2_DIV_4 = ADC_CCR_ADCPRE_PCLK2_DIV_4,
+ /** PCLK2 divided by 6 */
+ ADC_PRE_PCLK2_DIV_6 = ADC_CCR_ADCPRE_PCLK2_DIV_6,
+ /** PCLK2 divided by 8 */
+ ADC_PRE_PCLK2_DIV_8 = ADC_CCR_ADCPRE_PCLK2_DIV_8,
+} adc_prescaler;
+
+#endif
diff --git a/libmaple/stm32f2/include/series/dac.h b/libmaple/stm32f2/include/series/dac.h
new file mode 100644
index 0000000..0a578ca
--- /dev/null
+++ b/libmaple/stm32f2/include/series/dac.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/dac.h
+ * @brief STM32F2 DAC support
+ */
+
+#ifndef _LIBMAPLE_STM32F2_DAC_H_
+#define _LIBMAPLE_STM32F2_DAC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map type
+ */
+
+/** STM32F2 DAC register map type. */
+typedef struct dac_reg_map {
+ __io uint32 CR; /**< Control register */
+ __io uint32 SWTRIGR; /**< Software trigger register */
+ __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding
+ register */
+ __io uint32 DOR1; /**< Channel 1 data output register */
+ __io uint32 DOR2; /**< Channel 2 data output register */
+ __io uint32 SR; /**< Status register */
+} dac_reg_map;
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+
+#define DAC_CR_DMAUDRIE1 (1U << 13) /* Channel 1 DMA underrun
+ * interrupt enable */
+#define DAC_CR_DMAUDRIE2 (1U << 29) /* Channel 2 DMA underrun
+ * interrupt enable */
+
+/* Status register */
+
+#define DAC_SR_DMAUDR1 (1U << 13) /* Channel 1 DMA underrun
+ * occurred */
+#define DAC_SR_DMAUDR2 (1U << 29) /* Channel 2 DMA underrun
+ * ocurred */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/dma.h b/libmaple/stm32f2/include/series/dma.h
new file mode 100644
index 0000000..43bd1a2
--- /dev/null
+++ b/libmaple/stm32f2/include/series/dma.h
@@ -0,0 +1,810 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/dma.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 DMA series header
+ */
+
+#ifndef _LIBMAPLE_STM32F2_DMA_H_
+#define _LIBMAPLE_STM32F2_DMA_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/dma_common.h>
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map and base pointers
+ */
+
+/**
+ * @brief STM32F2 DMA register map type.
+ */
+typedef struct dma_reg_map {
+ /* Isn't it nice how on F1, it's CCR1, but on F2, it's S1CR? */
+
+ /* Global DMA registers */
+ __io uint32 LISR; /**< Low interrupt status register */
+ __io uint32 HISR; /**< High interrupt status register */
+ __io uint32 LIFCR; /**< Low interrupt flag clear register */
+ __io uint32 HIFCR; /**< High interrupt flag clear register */
+ /* Stream 0 registers */
+ __io uint32 S0CR; /**< Stream 0 control register */
+ __io uint32 S0NDTR; /**< Stream 0 number of data register */
+ __io uint32 S0PAR; /**< Stream 0 peripheral address register */
+ __io uint32 S0M0AR; /**< Stream 0 memory 0 address register */
+ __io uint32 S0M1AR; /**< Stream 0 memory 1 address register */
+ __io uint32 S0FCR; /**< Stream 0 FIFO control register */
+ /* Stream 1 registers */
+ __io uint32 S1CR; /**< Stream 1 control register */
+ __io uint32 S1NDTR; /**< Stream 1 number of data register */
+ __io uint32 S1PAR; /**< Stream 1 peripheral address register */
+ __io uint32 S1M0AR; /**< Stream 1 memory 0 address register */
+ __io uint32 S1M1AR; /**< Stream 1 memory 1 address register */
+ __io uint32 S1FCR; /**< Stream 1 FIFO control register */
+ /* Stream 2 registers */
+ __io uint32 S2CR; /**< Stream 2 control register */
+ __io uint32 S2NDTR; /**< Stream 2 number of data register */
+ __io uint32 S2PAR; /**< Stream 2 peripheral address register */
+ __io uint32 S2M0AR; /**< Stream 2 memory 0 address register */
+ __io uint32 S2M1AR; /**< Stream 2 memory 1 address register */
+ __io uint32 S2FCR; /**< Stream 2 FIFO control register */
+ /* Stream 3 registers */
+ __io uint32 S3CR; /**< Stream 3 control register */
+ __io uint32 S3NDTR; /**< Stream 3 number of data register */
+ __io uint32 S3PAR; /**< Stream 3 peripheral address register */
+ __io uint32 S3M0AR; /**< Stream 3 memory 0 address register */
+ __io uint32 S3M1AR; /**< Stream 3 memory 1 address register */
+ __io uint32 S3FCR; /**< Stream 3 FIFO control register */
+ /* Stream 4 registers */
+ __io uint32 S4CR; /**< Stream 4 control register */
+ __io uint32 S4NDTR; /**< Stream 4 number of data register */
+ __io uint32 S4PAR; /**< Stream 4 peripheral address register */
+ __io uint32 S4M0AR; /**< Stream 4 memory 0 address register */
+ __io uint32 S4M1AR; /**< Stream 4 memory 1 address register */
+ __io uint32 S4FCR; /**< Stream 4 FIFO control register */
+ /* Stream 5 registers */
+ __io uint32 S5CR; /**< Stream 5 control register */
+ __io uint32 S5NDTR; /**< Stream 5 number of data register */
+ __io uint32 S5PAR; /**< Stream 5 peripheral address register */
+ __io uint32 S5M0AR; /**< Stream 5 memory 0 address register */
+ __io uint32 S5M1AR; /**< Stream 5 memory 1 address register */
+ __io uint32 S5FCR; /**< Stream 5 FIFO control register */
+ /* Stream 6 registers */
+ __io uint32 S6CR; /**< Stream 6 control register */
+ __io uint32 S6NDTR; /**< Stream 6 number of data register */
+ __io uint32 S6PAR; /**< Stream 6 peripheral address register */
+ __io uint32 S6M0AR; /**< Stream 6 memory 0 address register */
+ __io uint32 S6M1AR; /**< Stream 6 memory 1 address register */
+ __io uint32 S6FCR; /**< Stream 6 FIFO control register */
+ /* Stream 7 registers */
+ __io uint32 S7CR; /**< Stream 7 control register */
+ __io uint32 S7NDTR; /**< Stream 7 number of data register */
+ __io uint32 S7PAR; /**< Stream 7 peripheral address register */
+ __io uint32 S7M0AR; /**< Stream 7 memory 0 address register */
+ __io uint32 S7M1AR; /**< Stream 7 memory 1 address register */
+ __io uint32 S7FCR; /**< Stream 7 FIFO control register */
+} dma_reg_map;
+
+/** DMA controller 1 register map base pointer */
+#define DMA1_BASE ((struct dma_reg_map*)0x40026000)
+/** DMA controller 2 register map base pointer */
+#define DMA2_BASE ((struct dma_reg_map*)0x40026400)
+
+/**
+ * @brief STM32F2 DMA stream (i.e. tube) register map type.
+ * Provides access to an individual stream's registers.
+ * @see dma_tube_regs()
+ */
+typedef struct dma_tube_reg_map {
+ __io uint32 SCR; /**< Stream configuration register */
+ __io uint32 SNDTR; /**< Stream number of data register */
+ __io uint32 SPAR; /**< Stream peripheral address register */
+ __io uint32 SM0AR; /**< Stream memory 0 address register */
+ __io uint32 SM1AR; /**< Stream memory 1 address register */
+ __io uint32 SFCR; /**< Stream FIFO control register */
+} dma_tube_reg_map;
+
+/** DMA1 stream 0 register map base pointer */
+#define DMA1S0_BASE ((struct dma_tube_reg_map*)0x40026010)
+/** DMA1 stream 1 register map base pointer */
+#define DMA1S1_BASE ((struct dma_tube_reg_map*)0x40026028)
+/** DMA1 stream 2 register map base pointer */
+#define DMA1S2_BASE ((struct dma_tube_reg_map*)0x40026040)
+/** DMA1 stream 3 register map base pointer */
+#define DMA1S3_BASE ((struct dma_tube_reg_map*)0x40026058)
+/** DMA1 stream 4 register map base pointer */
+#define DMA1S4_BASE ((struct dma_tube_reg_map*)0x40026070)
+/** DMA1 stream 5 register map base pointer */
+#define DMA1S5_BASE ((struct dma_tube_reg_map*)0x40026088)
+/** DMA1 stream 6 register map base pointer */
+#define DMA1S6_BASE ((struct dma_tube_reg_map*)0x400260A0)
+/** DMA1 stream 7 register map base pointer */
+#define DMA1S7_BASE ((struct dma_tube_reg_map*)0x400260B8)
+
+/** DMA2 stream 0 register map base pointer */
+#define DMA2S0_BASE ((struct dma_tube_reg_map*)0x40026410)
+/** DMA2 stream 1 register map base pointer */
+#define DMA2S1_BASE ((struct dma_tube_reg_map*)0x40026028)
+/** DMA2 stream 2 register map base pointer */
+#define DMA2S2_BASE ((struct dma_tube_reg_map*)0x40026040)
+/** DMA2 stream 3 register map base pointer */
+#define DMA2S3_BASE ((struct dma_tube_reg_map*)0x40026058)
+/** DMA2 stream 4 register map base pointer */
+#define DMA2S4_BASE ((struct dma_tube_reg_map*)0x40026070)
+/** DMA2 stream 5 register map base pointer */
+#define DMA2S5_BASE ((struct dma_tube_reg_map*)0x40026088)
+/** DMA2 stream 6 register map base pointer */
+#define DMA2S6_BASE ((struct dma_tube_reg_map*)0x400260A0)
+/** DMA2 stream 7 register map base pointer */
+#define DMA2S7_BASE ((struct dma_tube_reg_map*)0x400260B8)
+
+/*
+ * Register bit definitions
+ */
+
+/* Low interrupt status register */
+
+#define DMA_LISR_TCIF3_BIT 27
+#define DMA_LISR_HTIF3_BIT 26
+#define DMA_LISR_TEIF3_BIT 25
+#define DMA_LISR_DMEIF3_BIT 24
+#define DMA_LISR_FEIF3_BIT 22
+#define DMA_LISR_TCIF2_BIT 21
+#define DMA_LISR_HTIF2_BIT 20
+#define DMA_LISR_TEIF2_BIT 19
+#define DMA_LISR_DMEIF2_BIT 18
+#define DMA_LISR_FEIF2_BIT 16
+#define DMA_LISR_TCIF1_BIT 11
+#define DMA_LISR_HTIF1_BIT 10
+#define DMA_LISR_TEIF1_BIT 9
+#define DMA_LISR_DMEIF1_BIT 8
+#define DMA_LISR_FEIF1_BIT 6
+#define DMA_LISR_TCIF0_BIT 5
+#define DMA_LISR_HTIF0_BIT 4
+#define DMA_LISR_TEIF0_BIT 3
+#define DMA_LISR_DMEIF0_BIT 2
+#define DMA_LISR_FEIF0_BIT 0
+
+#define DMA_LISR_TCIF3 (1U << DMA_LISR_TCIF3_BIT)
+#define DMA_LISR_HTIF3 (1U << DMA_LISR_HTIF3_BIT)
+#define DMA_LISR_TEIF3 (1U << DMA_LISR_TEIF3_BIT)
+#define DMA_LISR_DMEIF3 (1U << DMA_LISR_DMEIF3_BIT)
+#define DMA_LISR_FEIF3 (1U << DMA_LISR_FEIF3_BIT)
+#define DMA_LISR_TCIF2 (1U << DMA_LISR_TCIF2_BIT)
+#define DMA_LISR_HTIF2 (1U << DMA_LISR_HTIF2_BIT)
+#define DMA_LISR_TEIF2 (1U << DMA_LISR_TEIF2_BIT)
+#define DMA_LISR_DMEIF2 (1U << DMA_LISR_DMEIF2_BIT)
+#define DMA_LISR_FEIF2 (1U << DMA_LISR_FEIF2_BIT)
+#define DMA_LISR_TCIF1 (1U << DMA_LISR_TCIF1_BIT)
+#define DMA_LISR_HTIF1 (1U << DMA_LISR_HTIF1_BIT)
+#define DMA_LISR_TEIF1 (1U << DMA_LISR_TEIF1_BIT)
+#define DMA_LISR_DMEIF1 (1U << DMA_LISR_DMEIF1_BIT)
+#define DMA_LISR_FEIF1 (1U << DMA_LISR_FEIF1_BIT)
+#define DMA_LISR_TCIF0 (1U << DMA_LISR_TCIF0_BIT)
+#define DMA_LISR_HTIF0 (1U << DMA_LISR_HTIF0_BIT)
+#define DMA_LISR_TEIF0 (1U << DMA_LISR_TEIF0_BIT)
+#define DMA_LISR_DMEIF0 (1U << DMA_LISR_DMEIF0_BIT)
+#define DMA_LISR_FEIF0 (1U << DMA_LISR_FEIF0_BIT)
+
+/* High interrupt status register */
+
+#define DMA_HISR_TCIF7_BIT 27
+#define DMA_HISR_HTIF7_BIT 26
+#define DMA_HISR_TEIF7_BIT 25
+#define DMA_HISR_DMEIF7_BIT 24
+#define DMA_HISR_FEIF7_BIT 22
+#define DMA_HISR_TCIF6_BIT 21
+#define DMA_HISR_HTIF6_BIT 20
+#define DMA_HISR_TEIF6_BIT 19
+#define DMA_HISR_DMEIF6_BIT 18
+#define DMA_HISR_FEIF6_BIT 16
+#define DMA_HISR_TCIF5_BIT 11
+#define DMA_HISR_HTIF5_BIT 10
+#define DMA_HISR_TEIF5_BIT 9
+#define DMA_HISR_DMEIF5_BIT 8
+#define DMA_HISR_FEIF5_BIT 6
+#define DMA_HISR_TCIF4_BIT 5
+#define DMA_HISR_HTIF4_BIT 4
+#define DMA_HISR_TEIF4_BIT 3
+#define DMA_HISR_DMEIF4_BIT 2
+#define DMA_HISR_FEIF4_BIT 0
+
+#define DMA_HISR_TCIF7 (1U << DMA_HISR_TCIF7_BIT)
+#define DMA_HISR_HTIF7 (1U << DMA_HISR_HTIF7_BIT)
+#define DMA_HISR_TEIF7 (1U << DMA_HISR_TEIF7_BIT)
+#define DMA_HISR_DMEIF7 (1U << DMA_HISR_DMEIF7_BIT)
+#define DMA_HISR_FEIF7 (1U << DMA_HISR_FEIF7_BIT)
+#define DMA_HISR_TCIF6 (1U << DMA_HISR_TCIF6_BIT)
+#define DMA_HISR_HTIF6 (1U << DMA_HISR_HTIF6_BIT)
+#define DMA_HISR_TEIF6 (1U << DMA_HISR_TEIF6_BIT)
+#define DMA_HISR_DMEIF6 (1U << DMA_HISR_DMEIF6_BIT)
+#define DMA_HISR_FEIF6 (1U << DMA_HISR_FEIF6_BIT)
+#define DMA_HISR_TCIF5 (1U << DMA_HISR_TCIF5_BIT)
+#define DMA_HISR_HTIF5 (1U << DMA_HISR_HTIF5_BIT)
+#define DMA_HISR_TEIF5 (1U << DMA_HISR_TEIF5_BIT)
+#define DMA_HISR_DMEIF5 (1U << DMA_HISR_DMEIF5_BIT)
+#define DMA_HISR_FEIF5 (1U << DMA_HISR_FEIF5_BIT)
+#define DMA_HISR_TCIF4 (1U << DMA_HISR_TCIF4_BIT)
+#define DMA_HISR_HTIF4 (1U << DMA_HISR_HTIF4_BIT)
+#define DMA_HISR_TEIF4 (1U << DMA_HISR_TEIF4_BIT)
+#define DMA_HISR_DMEIF4 (1U << DMA_HISR_DMEIF4_BIT)
+#define DMA_HISR_FEIF4 (1U << DMA_HISR_FEIF4_BIT)
+
+/* Low interrupt flag clear register */
+
+#define DMA_LIFCR_CTCIF3_BIT 27
+#define DMA_LIFCR_CHTIF3_BIT 26
+#define DMA_LIFCR_CTEIF3_BIT 25
+#define DMA_LIFCR_CDMEIF3_BIT 24
+#define DMA_LIFCR_CFEIF3_BIT 22
+#define DMA_LIFCR_CTCIF2_BIT 21
+#define DMA_LIFCR_CHTIF2_BIT 20
+#define DMA_LIFCR_CTEIF2_BIT 19
+#define DMA_LIFCR_CDMEIF2_BIT 18
+#define DMA_LIFCR_CFEIF2_BIT 16
+#define DMA_LIFCR_CTCIF1_BIT 11
+#define DMA_LIFCR_CHTIF1_BIT 10
+#define DMA_LIFCR_CTEIF1_BIT 9
+#define DMA_LIFCR_CDMEIF1_BIT 8
+#define DMA_LIFCR_CFEIF1_BIT 6
+#define DMA_LIFCR_CTCIF0_BIT 5
+#define DMA_LIFCR_CHTIF0_BIT 4
+#define DMA_LIFCR_CTEIF0_BIT 3
+#define DMA_LIFCR_CDMEIF0_BIT 2
+#define DMA_LIFCR_CFEIF0_BIT 0
+
+#define DMA_LIFCR_CTCIF3 (1U << DMA_LIFCR_CTCIF3_BIT)
+#define DMA_LIFCR_CHTIF3 (1U << DMA_LIFCR_CHTIF3_BIT)
+#define DMA_LIFCR_CTEIF3 (1U << DMA_LIFCR_CTEIF3_BIT)
+#define DMA_LIFCR_CDMEIF3 (1U << DMA_LIFCR_CDMEIF3_BIT)
+#define DMA_LIFCR_CFEIF3 (1U << DMA_LIFCR_CFEIF3_BIT)
+#define DMA_LIFCR_CTCIF2 (1U << DMA_LIFCR_CTCIF2_BIT)
+#define DMA_LIFCR_CHTIF2 (1U << DMA_LIFCR_CHTIF2_BIT)
+#define DMA_LIFCR_CTEIF2 (1U << DMA_LIFCR_CTEIF2_BIT)
+#define DMA_LIFCR_CDMEIF2 (1U << DMA_LIFCR_CDMEIF2_BIT)
+#define DMA_LIFCR_CFEIF2 (1U << DMA_LIFCR_CFEIF2_BIT)
+#define DMA_LIFCR_CTCIF1 (1U << DMA_LIFCR_CTCIF1_BIT)
+#define DMA_LIFCR_CHTIF1 (1U << DMA_LIFCR_CHTIF1_BIT)
+#define DMA_LIFCR_CTEIF1 (1U << DMA_LIFCR_CTEIF1_BIT)
+#define DMA_LIFCR_CDMEIF1 (1U << DMA_LIFCR_CDMEIF1_BIT)
+#define DMA_LIFCR_CFEIF1 (1U << DMA_LIFCR_CFEIF1_BIT)
+#define DMA_LIFCR_CTCIF0 (1U << DMA_LIFCR_CTCIF0_BIT)
+#define DMA_LIFCR_CHTIF0 (1U << DMA_LIFCR_CHTIF0_BIT)
+#define DMA_LIFCR_CTEIF0 (1U << DMA_LIFCR_CTEIF0_BIT)
+#define DMA_LIFCR_CDMEIF0 (1U << DMA_LIFCR_CDMEIF0_BIT)
+#define DMA_LIFCR_CFEIF0 (1U << DMA_LIFCR_CFEIF0_BIT)
+
+/* High interrupt flag clear regsister */
+
+#define DMA_HIFCR_CTCIF7_BIT 27
+#define DMA_HIFCR_CHTIF7_BIT 26
+#define DMA_HIFCR_CTEIF7_BIT 25
+#define DMA_HIFCR_CDMEIF7_BIT 24
+#define DMA_HIFCR_CFEIF7_BIT 22
+#define DMA_HIFCR_CTCIF6_BIT 21
+#define DMA_HIFCR_CHTIF6_BIT 20
+#define DMA_HIFCR_CTEIF6_BIT 19
+#define DMA_HIFCR_CDMEIF6_BIT 18
+#define DMA_HIFCR_CFEIF6_BIT 16
+#define DMA_HIFCR_CTCIF5_BIT 11
+#define DMA_HIFCR_CHTIF5_BIT 10
+#define DMA_HIFCR_CTEIF5_BIT 9
+#define DMA_HIFCR_CDMEIF5_BIT 8
+#define DMA_HIFCR_CFEIF5_BIT 6
+#define DMA_HIFCR_CTCIF4_BIT 5
+#define DMA_HIFCR_CHTIF4_BIT 4
+#define DMA_HIFCR_CTEIF4_BIT 3
+#define DMA_HIFCR_CDMEIF4_BIT 2
+#define DMA_HIFCR_CFEIF4_BIT 0
+
+#define DMA_HIFCR_CTCIF7 (1U << DMA_HIFCR_CTCIF7_BIT)
+#define DMA_HIFCR_CHTIF7 (1U << DMA_HIFCR_CHTIF7_BIT)
+#define DMA_HIFCR_CTEIF7 (1U << DMA_HIFCR_CTEIF7_BIT)
+#define DMA_HIFCR_CDMEIF7 (1U << DMA_HIFCR_CDMEIF7_BIT)
+#define DMA_HIFCR_CFEIF7 (1U << DMA_HIFCR_CFEIF7_BIT)
+#define DMA_HIFCR_CTCIF6 (1U << DMA_HIFCR_CTCIF6_BIT)
+#define DMA_HIFCR_CHTIF6 (1U << DMA_HIFCR_CHTIF6_BIT)
+#define DMA_HIFCR_CTEIF6 (1U << DMA_HIFCR_CTEIF6_BIT)
+#define DMA_HIFCR_CDMEIF6 (1U << DMA_HIFCR_CDMEIF6_BIT)
+#define DMA_HIFCR_CFEIF6 (1U << DMA_HIFCR_CFEIF6_BIT)
+#define DMA_HIFCR_CTCIF5 (1U << DMA_HIFCR_CTCIF5_BIT)
+#define DMA_HIFCR_CHTIF5 (1U << DMA_HIFCR_CHTIF5_BIT)
+#define DMA_HIFCR_CTEIF5 (1U << DMA_HIFCR_CTEIF5_BIT)
+#define DMA_HIFCR_CDMEIF5 (1U << DMA_HIFCR_CDMEIF5_BIT)
+#define DMA_HIFCR_CFEIF5 (1U << DMA_HIFCR_CFEIF5_BIT)
+#define DMA_HIFCR_CTCIF4 (1U << DMA_HIFCR_CTCIF4_BIT)
+#define DMA_HIFCR_CHTIF4 (1U << DMA_HIFCR_CHTIF4_BIT)
+#define DMA_HIFCR_CTEIF4 (1U << DMA_HIFCR_CTEIF4_BIT)
+#define DMA_HIFCR_CDMEIF4 (1U << DMA_HIFCR_CDMEIF4_BIT)
+#define DMA_HIFCR_CFEIF4 (1U << DMA_HIFCR_CFEIF4_BIT)
+
+/* Stream configuration register */
+
+#define DMA_SCR_CT_BIT 19
+#define DMA_SCR_DBM_BIT 18
+#define DMA_SCR_PINCOS_BIT 15
+#define DMA_SCR_MINC_BIT 10
+#define DMA_SCR_PINC_BIT 9
+#define DMA_SCR_CIRC_BIT 8
+#define DMA_SCR_PFCTRL_BIT 5
+#define DMA_SCR_TCIE_BIT 4
+#define DMA_SCR_HTIE_BIT 3
+#define DMA_SCR_TEIE_BIT 2
+#define DMA_SCR_DMEIE_BIT 1
+#define DMA_SCR_EN_BIT 0
+
+#define DMA_SCR_CHSEL (0x7 << 25)
+#define DMA_SCR_CHSEL_CH_0 (0x0 << 25)
+#define DMA_SCR_CHSEL_CH_1 (0x1 << 25)
+#define DMA_SCR_CHSEL_CH_2 (0x2 << 25)
+#define DMA_SCR_CHSEL_CH_3 (0x3 << 25)
+#define DMA_SCR_CHSEL_CH_4 (0x4 << 25)
+#define DMA_SCR_CHSEL_CH_5 (0x5 << 25)
+#define DMA_SCR_CHSEL_CH_6 (0x6 << 25)
+#define DMA_SCR_CHSEL_CH_7 (0x7 << 25)
+#define DMA_SCR_MBURST (0x3 << 23)
+#define DMA_SCR_MBURST_SINGLE (0x0 << 23)
+#define DMA_SCR_MBURST_INCR4 (0x1 << 23)
+#define DMA_SCR_MBURST_INCR8 (0x2 << 23)
+#define DMA_SCR_MBURST_INCR16 (0x3 << 23)
+#define DMA_SCR_PBURST (0x3 << 21)
+#define DMA_SCR_PBURST_SINGLE (0x0 << 21)
+#define DMA_SCR_PBURST_INCR4 (0x1 << 21)
+#define DMA_SCR_PBURST_INCR8 (0x2 << 21)
+#define DMA_SCR_PBURST_INCR16 (0x3 << 21)
+#define DMA_SCR_CT (1U << DMA_SCR_CT_BIT)
+#define DMA_SCR_DBM (1U << DMA_SCR_DBM_BIT)
+#define DMA_SCR_PL (0x3 << 16)
+#define DMA_SCR_PL_LOW (0x0 << 16)
+#define DMA_SCR_PL_MEDIUM (0x1 << 16)
+#define DMA_SCR_PL_HIGH (0x2 << 16)
+#define DMA_SCR_VERY_HIGH (0x3 << 16)
+#define DMA_SCR_PINCOS (1U << DMA_SCR_PINCOS_BIT)
+#define DMA_SCR_MSIZE (0x3 << 13)
+#define DMA_SCR_MSIZE_8BITS (0x0 << 13)
+#define DMA_SCR_MSIZE_16BITS (0x1 << 13)
+#define DMA_SCR_MSIZE_32BITS (0x2 << 13)
+#define DMA_SCR_PSIZE (0x3 << 11)
+#define DMA_SCR_PSIZE_8BITS (0x0 << 11)
+#define DMA_SCR_PSIZE_16BITS (0x1 << 11)
+#define DMA_SCR_PSIZE_32BITS (0x2 << 11)
+#define DMA_SCR_MINC (1U << DMA_SCR_MINC_BIT)
+#define DMA_SCR_PINC (1U << DMA_SCR_PINC_BIT)
+#define DMA_SCR_CIRC (1U << DMA_SCR_CIRC_BIT)
+#define DMA_SCR_DIR (0x3 << 6)
+#define DMA_SCR_DIR_PER_TO_MEM (0x0 << 6)
+#define DMA_SCR_DIR_MEM_TO_PER (0x1 << 6)
+#define DMA_SCR_DIR_MEM_TO_MEM (0x2 << 6)
+#define DMA_SCR_PFCTRL (1U << DMA_SCR_PFCTRL_BIT)
+#define DMA_SCR_TCIE (1U << DMA_SCR_TCIE_BIT)
+#define DMA_SCR_HTIE (1U << DMA_SCR_HTIE_BIT)
+#define DMA_SCR_TEIE (1U << DMA_SCR_TEIE_BIT)
+#define DMA_SCR_DMEIE (1U << DMA_SCR_DMEIE_BIT)
+#define DMA_SCR_EN (1U << DMA_SCR_EN_BIT)
+
+/* Stream FIFO control register */
+
+#define DMA_SFCR_FEIE_BIT 7
+#define DMA_SFCR_DMDIS_BIT 2
+
+#define DMA_SFCR_FEIE (1U << DMA_SFCR_FEIE_BIT)
+#define DMA_SFCR_FS (0x7 << 3)
+#define DMA_SFCR_FS_ZERO_TO_QUARTER (0x0 << 3)
+#define DMA_SFCR_FS_QUARTER_TO_HALF (0x1 << 3)
+#define DMA_SFCR_FS_HALF_TO_THREE_QUARTERS (0x2 << 3)
+#define DMA_SFCR_FS_THREE_QUARTERS_TO_FULL (0x3 << 3)
+#define DMA_SFCR_FS_EMPTY (0x4 << 3)
+#define DMA_SFCR_FS_FULL (0x5 << 3)
+#define DMA_SFCR_DMDIS (1U << DMA_SFCR_DMDIS_BIT)
+#define DMA_SFCR_FTH (0x3 << 0)
+#define DMA_SFCR_FTH_QUARTER_FULL (0x0 << 3)
+#define DMA_SFCR_FTH_HALF_FULL (0x1 << 3)
+#define DMA_SFCR_FTH_THREE_QUARTERS_FULL (0x2 << 3)
+#define DMA_SFCR_FTH_FULL (0x3 << 3)
+
+/*
+ * Devices
+ */
+
+extern dma_dev *DMA1;
+extern dma_dev *DMA2;
+
+/*
+ * Other types needed by, or useful for, <libmaple/dma.h>
+ */
+
+/**
+ * @brief DMA streams
+ * This is also the dma_tube type for STM32F2.
+ * @see dma_tube
+ */
+typedef enum dma_stream {
+ DMA_S0 = 0,
+ DMA_S1 = 1,
+ DMA_S2 = 2,
+ DMA_S3 = 3,
+ DMA_S4 = 4,
+ DMA_S5 = 5,
+ DMA_S6 = 6,
+ DMA_S7 = 7,
+} dma_stream;
+
+/** STM32F2 dma_tube (=dma_stream) */
+#define dma_tube dma_stream
+
+/**
+ * @brief STM32F2 configuration flags for dma_tube_config.
+ * @see struct dma_tube_config
+ */
+typedef enum dma_cfg_flags {
+ /* NB: flags that aren't SCR bits are treated specially. */
+
+ /**
+ * Source address increment mode
+ *
+ * If this flag is set, the source address is incremented (by the
+ * source size) after each DMA transfer.
+ */
+ DMA_CFG_SRC_INC = 1U << 31,
+
+ /**
+ * Destination address increment mode
+ *
+ * If this flag is set, the destination address is incremented (by
+ * the destination size) after each DMA transfer.
+ */
+ DMA_CFG_DST_INC = 1U << 30,
+
+ /**
+ * Circular mode
+ *
+ * This mode is not available for memory-to-memory transfers.
+ */
+ DMA_CFG_CIRC = DMA_SCR_CIRC,
+
+ /** Transfer complete interrupt enable */
+ DMA_CFG_CMPLT_IE = DMA_SCR_TCIE,
+ /** Transfer half-complete interrupt enable */
+ DMA_CFG_HALF_CMPLT_IE = DMA_SCR_HTIE,
+ /** Transfer error interrupt enable */
+ DMA_CFG_ERR_IE = DMA_SCR_TEIE,
+ /** Direct mode error interrupt enable */
+ DMA_CFG_DM_ERR_IE = DMA_SCR_DMEIE,
+ /** FIFO error interrupt enable */
+ DMA_CFG_FIFO_ERR_IE = (1U << 29),
+} dma_cfg_flags;
+
+/**
+ * @brief STM32F2 DMA request sources.
+ *
+ * IMPORTANT:
+ *
+ * 1. On STM32F2, a particular dma_request_src is always tied to a
+ * single DMA controller, but often can be supported by multiple
+ * streams. For example, DMA requests from ADC1 (DMA_REQ_SRC_ADC1) can
+ * only be handled by DMA2, but they can go to either stream 0 or
+ * stream 4 (though not any other stream). If you try to use a request
+ * source with the wrong DMA controller or the wrong stream on
+ * STM32F2, dma_tube_cfg() will fail.
+ *
+ * 2. A single stream can only handle a single request source at a
+ * time. If you change a stream's request source later, it will stop
+ * serving requests from the old source. However, for some streams,
+ * some sources conflict with one another (when they correspond to the
+ * same channel on that stream), and on STM32F2, Terrible Super-Bad
+ * Things will happen if two conflicting request sources are active at
+ * the same time.
+ *
+ * @see struct dma_tube_config
+ * @see dma_tube_cfg()
+ */
+typedef enum dma_request_src {
+ /* These are constructed like so (though this may change, so user
+ * code shouldn't depend on it):
+ *
+ * Bits 0--2: Channel associated with request source
+ *
+ * Bits 3--9: rcc_clk_id of DMA controller associated with request source
+ *
+ * Bits 10--17: Bit mask of streams which can handle that request
+ * source. (E.g., bit 10 set means stream 0 can
+ * handle the source, bit 11 set means stream 1 can,
+ * etc.)
+ *
+ * Among other things, this is used for error checking in
+ * dma_tube_cfg(). If you change this bit encoding, you need to
+ * update the helper functions in stm32f2/dma.c.
+ */
+#define _DMA_STM32F2_REQ_SRC(stream_mask, clk_id, channel) \
+ (((stream_mask) << 10) | ((clk_id) << 3) | (channel))
+#define _DMA_S(n) (1U << (n))
+
+ /* DMA1 request sources */
+#define _DMA_1_REQ_SRC(stream_mask, channel) \
+ _DMA_STM32F2_REQ_SRC(stream_mask, RCC_DMA1, channel)
+
+ /* Channel 0 */
+ DMA_REQ_SRC_SPI3_RX = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(2), 0),
+ DMA_REQ_SRC_SPI2_RX = _DMA_1_REQ_SRC(_DMA_S(3), 0),
+ DMA_REQ_SRC_SPI2_TX = _DMA_1_REQ_SRC(_DMA_S(4), 0),
+ DMA_REQ_SRC_SPI3_TX = _DMA_1_REQ_SRC(_DMA_S(5) | _DMA_S(7), 0),
+
+ /* Channel 1 */
+ DMA_REQ_SRC_I2C1_RX = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(5), 1),
+ DMA_REQ_SRC_TIM7_UP = _DMA_1_REQ_SRC(_DMA_S(2) | _DMA_S(4), 1),
+ DMA_REQ_SRC_I2C1_TX = _DMA_1_REQ_SRC(_DMA_S(6) | _DMA_S(7), 1),
+
+ /* Channel 2 */
+ DMA_REQ_SRC_TIM4_CH1 = _DMA_1_REQ_SRC(_DMA_S(0), 2),
+ DMA_REQ_SRC_TIM4_CH2 = _DMA_1_REQ_SRC(_DMA_S(3), 2),
+ DMA_REQ_SRC_TIM4_UP = _DMA_1_REQ_SRC(_DMA_S(6), 2),
+ DMA_REQ_SRC_TIM4_CH3 = _DMA_1_REQ_SRC(_DMA_S(7), 2),
+
+ /* Channel 3 */
+ DMA_REQ_SRC_TIM2_UP = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(7), 3),
+ DMA_REQ_SRC_TIM2_CH3 = _DMA_1_REQ_SRC(_DMA_S(1), 3),
+ DMA_REQ_SRC_I2C3_RX = _DMA_1_REQ_SRC(_DMA_S(2), 3),
+ DMA_REQ_SRC_I2C3_TX = _DMA_1_REQ_SRC(_DMA_S(4), 3),
+ DMA_REQ_SRC_TIM2_CH1 = _DMA_1_REQ_SRC(_DMA_S(5), 3),
+ DMA_REQ_SRC_TIM2_CH2 = _DMA_1_REQ_SRC(_DMA_S(6), 3),
+ DMA_REQ_SRC_TIM2_CH4 = _DMA_1_REQ_SRC(_DMA_S(6) | _DMA_S(7), 3),
+
+ /* Channel 4 */
+ DMA_REQ_SRC_UART5_RX = _DMA_1_REQ_SRC(_DMA_S(0), 4),
+ DMA_REQ_SRC_USART3_RX = _DMA_1_REQ_SRC(_DMA_S(1), 4),
+ DMA_REQ_SRC_UART4_RX = _DMA_1_REQ_SRC(_DMA_S(2), 4),
+ DMA_REQ_SRC_USART3_TX = _DMA_1_REQ_SRC(_DMA_S(3), 4),
+ DMA_REQ_SRC_UART4_TX = _DMA_1_REQ_SRC(_DMA_S(4), 4),
+ DMA_REQ_SRC_USART2_RX = _DMA_1_REQ_SRC(_DMA_S(5), 4),
+ DMA_REQ_SRC_USART2_TX = _DMA_1_REQ_SRC(_DMA_S(6), 4),
+ DMA_REQ_SRC_UART5_TX = _DMA_1_REQ_SRC(_DMA_S(7), 4),
+
+ /* Channel 5 */
+ DMA_REQ_SRC_TIM3_CH4 = _DMA_1_REQ_SRC(_DMA_S(2), 5),
+ DMA_REQ_SRC_TIM3_UP = _DMA_1_REQ_SRC(_DMA_S(2), 5),
+ DMA_REQ_SRC_TIM3_CH1 = _DMA_1_REQ_SRC(_DMA_S(4), 5),
+ DMA_REQ_SRC_TIM3_TRIG = _DMA_1_REQ_SRC(_DMA_S(4), 5),
+ DMA_REQ_SRC_TIM3_CH2 = _DMA_1_REQ_SRC(_DMA_S(5), 5),
+ DMA_REQ_SRC_TIM3_CH3 = _DMA_1_REQ_SRC(_DMA_S(7), 5),
+
+ /* Channel 6 */
+ DMA_REQ_SRC_TIM5_CH3 = _DMA_1_REQ_SRC(_DMA_S(0), 6),
+ DMA_REQ_SRC_TIM5_UP = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(6), 6),
+ DMA_REQ_SRC_TIM5_CH4 = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6),
+ DMA_REQ_SRC_TIM5_TRIG = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6),
+ DMA_REQ_SRC_TIM5_CH1 = _DMA_1_REQ_SRC(_DMA_S(2), 6),
+ DMA_REQ_SRC_TIM5_CH2 = _DMA_1_REQ_SRC(_DMA_S(4), 6),
+
+ /* Channel 7 */
+ DMA_REQ_SRC_TIM6_UP = _DMA_1_REQ_SRC(_DMA_S(1), 7),
+ DMA_REQ_SRC_I2C2_RX = _DMA_1_REQ_SRC(_DMA_S(2) | _DMA_S(3), 7),
+ DMA_REQ_SRC_USART3_TX_ALTERNATE = _DMA_1_REQ_SRC(_DMA_S(4), 7),
+ DMA_REQ_SRC_DAC1 = _DMA_1_REQ_SRC(_DMA_S(5), 7),
+ DMA_REQ_SRC_DAC2 = _DMA_1_REQ_SRC(_DMA_S(6), 7),
+ DMA_REQ_SRC_I2C2_TX = _DMA_1_REQ_SRC(_DMA_S(7), 7),
+#undef _DMA_1_REQ_SRC
+
+ /* DMA2 request sources */
+#define _DMA_2_REQ_SRC(stream_mask, channel) \
+ _DMA_STM32F2_REQ_SRC(stream_mask, RCC_DMA2, channel)
+
+ /* Channel 0 */
+ DMA_REQ_SRC_ADC1 = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(4), 0),
+ /* You can use these "DMA_REQ_SRC_TIMx_CHx_ALTERNATE" if you know
+ * what you're doing, but the other ones (for channels 6 and 7),
+ * are better, in that they don't conflict with one another. */
+ DMA_REQ_SRC_TIM8_CH1_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0),
+ DMA_REQ_SRC_TIM8_CH2_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0),
+ DMA_REQ_SRC_TIM8_CH3_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0),
+ DMA_REQ_SRC_TIM1_CH1_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(6), 0),
+ DMA_REQ_SRC_TIM1_CH2_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(6), 0),
+ DMA_REQ_SRC_TIM1_CH3_ALTENRATE = _DMA_2_REQ_SRC(_DMA_S(6), 0),
+
+ /* Channel 1 */
+ DMA_REQ_SRC_DCMI = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(7), 1),
+ DMA_REQ_SRC_ADC2 = _DMA_2_REQ_SRC(_DMA_S(2) | _DMA_S(3), 1),
+
+ /* Channel 2 */
+ DMA_REQ_SRC_ADC3 = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(1), 2),
+ DMA_REQ_SRC_CRYP_OUT = _DMA_2_REQ_SRC(_DMA_S(5), 2),
+ DMA_REQ_SRC_CRYP_IN = _DMA_2_REQ_SRC(_DMA_S(6), 2),
+ DMA_REQ_SRC_HASH_IN = _DMA_2_REQ_SRC(_DMA_S(7), 2),
+
+ /* Channel 3 */
+ DMA_REQ_SRC_SPI1_RX = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(2), 3),
+ DMA_REQ_SRC_SPI1_TX = _DMA_2_REQ_SRC(_DMA_S(3) | _DMA_S(5), 3),
+
+ /* Channel 4 */
+ DMA_REQ_SRC_USART1_RX = _DMA_2_REQ_SRC(_DMA_S(2) | _DMA_S(5), 4),
+ DMA_REQ_SRC_SDIO = _DMA_2_REQ_SRC(_DMA_S(3) | _DMA_S(6), 4),
+ DMA_REQ_SRC_USART1_TX = _DMA_2_REQ_SRC(_DMA_S(7), 4),
+
+ /* Channel 5 */
+ DMA_REQ_SRC_USART6_RX = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(2), 5),
+ DMA_REQ_SRC_USART6_TX = _DMA_2_REQ_SRC(_DMA_S(6) | _DMA_S(7), 5),
+
+ /* Channel 6 */
+ DMA_REQ_SRC_TIM1_TRIG = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(4), 6),
+ DMA_REQ_SRC_TIM1_CH1 = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6),
+ DMA_REQ_SRC_TIM1_CH2 = _DMA_2_REQ_SRC(_DMA_S(3), 6),
+ DMA_REQ_SRC_TIM1_CH4 = _DMA_2_REQ_SRC(_DMA_S(4), 6),
+ DMA_REQ_SRC_TIM1_COM = _DMA_2_REQ_SRC(_DMA_S(4), 6),
+ DMA_REQ_SRC_TIM1_UP = _DMA_2_REQ_SRC(_DMA_S(5), 6),
+ DMA_REQ_SRC_TIM1_CH3 = _DMA_2_REQ_SRC(_DMA_S(6), 6),
+
+ /* Channel 7 */
+ DMA_REQ_SRC_TIM8_UP = _DMA_2_REQ_SRC(_DMA_S(1), 7),
+ DMA_REQ_SRC_TIM8_CH1 = _DMA_2_REQ_SRC(_DMA_S(2), 7),
+ DMA_REQ_SRC_TIM8_CH2 = _DMA_2_REQ_SRC(_DMA_S(3), 7),
+ DMA_REQ_SRC_TIM8_CH3 = _DMA_2_REQ_SRC(_DMA_S(4), 7),
+ DMA_REQ_SRC_TIM8_CH4 = _DMA_2_REQ_SRC(_DMA_S(7), 7),
+ DMA_REQ_SRC_TIM8_TRIG = _DMA_2_REQ_SRC(_DMA_S(7), 7),
+ DMA_REQ_SRC_TIM8_COM = _DMA_2_REQ_SRC(_DMA_S(7), 7),
+#undef _DMA_2_REQ_SRC
+#undef _DMA_S
+} dma_request_src;
+
+/*
+ * Tube conveniences
+ */
+
+static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev,
+ dma_tube tube) {
+ ASSERT(DMA_S0 <= tube && tube <= DMA_S7);
+ switch (dev->clk_id) {
+ case RCC_DMA1:
+ return DMA1S0_BASE + (int)tube;
+ case RCC_DMA2:
+ return DMA2S0_BASE + (int)tube;
+ default:
+ /* Can't happen */
+ ASSERT(0);
+ return 0;
+ }
+}
+
+static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube) {
+ return dma_tube_regs(dev, tube)->SCR & DMA_SCR_EN;
+}
+
+/* F2-only; available because of double-buffering. */
+void dma_set_mem_n_addr(dma_dev *dev, dma_tube tube, int n,
+ __io void *address);
+
+/**
+ * @brief Set memory 0 address.
+ * Availability: STM32F2.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose memory 0 address to set
+ * @param addr Address to use as memory 0
+ */
+static __always_inline void
+dma_set_mem0_addr(dma_dev *dev, dma_tube tube, __io void *addr) {
+ dma_set_mem_n_addr(dev, tube, 0, addr);
+}
+
+/**
+ * @brief Set memory 1 address.
+ * Availability: STM32F2.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose memory 1 address to set
+ * @param addr Address to use as memory 1
+ */
+static __always_inline void
+dma_set_mem1_addr(dma_dev *dev, dma_tube tube, __io void *addr) {
+ dma_set_mem_n_addr(dev, tube, 1, addr);
+}
+
+/* Assume the user means SM0AR in a non-double-buffered configuration. */
+static __always_inline void
+dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *addr) {
+ dma_set_mem0_addr(dev, tube, addr);
+}
+
+/* SM0AR and SM1AR are treated as though they have the same size */
+static inline dma_xfer_size dma_get_mem_size(dma_dev *dev, dma_tube tube) {
+ return (dma_xfer_size)(dma_tube_regs(dev, tube)->SCR >> 13);
+}
+
+static inline dma_xfer_size dma_get_per_size(dma_dev *dev, dma_tube tube) {
+ return (dma_xfer_size)(dma_tube_regs(dev, tube)->SCR >> 11);
+}
+
+void dma_enable_fifo(dma_dev *dev, dma_tube tube);
+void dma_disable_fifo(dma_dev *dev, dma_tube tube);
+
+static __always_inline int dma_is_fifo_enabled(dma_dev *dev, dma_tube tube) {
+ return dma_tube_regs(dev, tube)->SFCR & DMA_SFCR_DMDIS;
+}
+
+/*
+ * TODO:
+ * - Double-buffer configuration function
+ * - FIFO configuration function
+ * - MBURST/PBURST configuration function
+ */
+
+/*
+ * ISR/IFCR conveniences.
+ */
+
+/* (undocumented) helper for reading LISR/HISR and writing
+ * LIFCR/HIFCR. For these registers,
+ *
+ * S0, S4: bits start at bit 0
+ * S1, S5: 6
+ * S2, S6: 16
+ * S3, S7: 22
+ *
+ * I can't imagine why ST didn't just use a byte for each group. The
+ * bits fit, and it would have made functions like these simpler and
+ * faster. Oh well. */
+static __always_inline uint32 _dma_sr_fcr_shift(dma_tube tube) {
+ switch (tube) {
+ case DMA_S0: /* fall through */
+ case DMA_S4:
+ return 0;
+ case DMA_S1: /* fall through */
+ case DMA_S5:
+ return 6;
+ case DMA_S2: /* fall through */
+ case DMA_S6:
+ return 16;
+ case DMA_S3: /* fall through */
+ case DMA_S7:
+ return 22;
+ }
+ /* Can't happen */
+ ASSERT(0);
+ return 0;
+}
+
+static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube) {
+ dma_reg_map *regs = dev->regs;
+ __io uint32 *isr = tube > DMA_S3 ? &regs->HISR : &regs->LISR;
+ return (*isr >> _dma_sr_fcr_shift(tube)) & 0x3D;
+}
+
+static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) {
+ dma_reg_map *regs = dev->regs;
+ __io uint32 *ifcr = tube > DMA_S3 ? &regs->HIFCR : &regs->LIFCR;
+ *ifcr = (0x3D << _dma_sr_fcr_shift(tube));
+}
+
+#undef _DMA_IRQ_BIT_SHIFT
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/exti.h b/libmaple/stm32f2/include/series/exti.h
new file mode 100644
index 0000000..4643fcf
--- /dev/null
+++ b/libmaple/stm32f2/include/series/exti.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f1/include/series/exti.h
+ * @brief STM32F2 external interrupts
+ */
+
+#ifndef _LIBMAPLE_STM32F2_EXTI_H_
+#define _LIBMAPLE_STM32F2_EXTI_H_
+
+#ifdef __cpluspus
+extern "C" {
+#endif
+
+struct exti_reg_map;
+#define EXTI_BASE ((struct exti_reg_map*)0x40013C00)
+
+#ifdef __cpluspus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/flash.h b/libmaple/stm32f2/include/series/flash.h
new file mode 100644
index 0000000..a3c3933
--- /dev/null
+++ b/libmaple/stm32f2/include/series/flash.h
@@ -0,0 +1,202 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/flash.h
+ * @brief STM32F2 Flash header.
+ *
+ * Provides register map, base pointer, and register bit definitions
+ * for the Flash controller on the STM32F2 series, along with
+ * series-specific configuration values.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_FLASH_H_
+#define _LIBMAPLE_STM32F2_FLASH_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** @brief STM32F2 Flash register map type */
+typedef struct flash_reg_map {
+ __io uint32 ACR; /**< Access control register */
+ __io uint32 KEYR; /**< Key register */
+ __io uint32 OPTKEYR; /**< Option key register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 CR; /**< Control register */
+ __io uint32 OPTCR; /**< Option control register */
+} flash_reg_map;
+
+#define FLASH_BASE ((struct flash_reg_map*)0x40023C00)
+
+/*
+ * Register bit definitions
+ */
+
+/* Access control register */
+
+#define FLASH_ACR_DCRST_BIT 12
+#define FLASH_ACR_ICRST_BIT 11
+#define FLASH_ACR_DCEN_BIT 10
+#define FLASH_ACR_ICEN_BIT 9
+#define FLASH_ACR_PRFTEN_BIT 8
+
+#define FLASH_ACR_DCRST (1U << FLASH_ACR_DCRST_BIT)
+#define FLASH_ACR_ICRST (1U << FLASH_ACR_ICRST_BIT)
+#define FLASH_ACR_DCEN (1U << FLASH_ACR_DCEN_BIT)
+#define FLASH_ACR_ICEN (1U << FLASH_ACR_ICEN_BIT)
+#define FLASH_ACR_PRFTEN (1U << FLASH_ACR_PRFTEN_BIT)
+#define FLASH_ACR_LATENCY 0x7
+#define FLASH_ACR_LATENCY_0WS 0x0
+#define FLASH_ACR_LATENCY_1WS 0x1
+#define FLASH_ACR_LATENCY_2WS 0x2
+#define FLASH_ACR_LATENCY_3WS 0x3
+#define FLASH_ACR_LATENCY_4WS 0x4
+#define FLASH_ACR_LATENCY_5WS 0x5
+#define FLASH_ACR_LATENCY_6WS 0x6
+#define FLASH_ACR_LATENCY_7WS 0x7
+
+/* Key register */
+
+#define FLASH_KEYR_KEY1 0x45670123
+#define FLASH_KEYR_KEY2 0xCDEF89AB
+
+/* Option key register */
+
+#define FLASH_OPTKEYR_OPTKEY1 0x08192A3B
+#define FLASH_OPTKEYR_OPTKEY2 0x4C5D6E7F
+
+/* Status register */
+
+#define FLASH_SR_BSY_BIT 16
+#define FLASH_SR_PGSERR_BIT 7
+#define FLASH_SR_PGPERR_BIT 6
+#define FLASH_SR_PGAERR_BIT 5
+#define FLASH_SR_WRPERR_BIT 4
+#define FLASH_SR_OPERR_BIT 1
+#define FLASH_SR_EOP_BIT 0
+
+#define FLASH_SR_BSY (1U << FLASH_SR_BSY_BIT)
+#define FLASH_SR_PGSERR (1U << FLASH_SR_PGSERR_BIT)
+#define FLASH_SR_PGPERR (1U << FLASH_SR_PGPERR_BIT)
+#define FLASH_SR_PGAERR (1U << FLASH_SR_PGAERR_BIT)
+#define FLASH_SR_WRPERR (1U << FLASH_SR_WRPERR_BIT)
+#define FLASH_SR_OPERR (1U << FLASH_SR_OPERR_BIT)
+#define FLASH_SR_EOP (1U << FLASH_SR_EOP_BIT)
+
+/* Control register */
+
+#define FLASH_CR_LOCK_BIT 31
+#define FLASH_CR_ERRIE_BIT 25
+#define FLASH_CR_EOPIE_BIT 24
+#define FLASH_CR_STRT_BIT 16
+#define FLASH_CR_MER_BIT 2
+#define FLASH_CR_SER_BIT 1
+#define FLASH_CR_PG_BIT 0
+
+#define FLASH_CR_LOCK (1U << FLASH_CR_LOCK_BIT)
+#define FLASH_CR_ERRIE (1U << FLASH_CR_ERRIE_BIT)
+#define FLASH_CR_EOPIE (1U << FLASH_CR_EOPIE_BIT)
+#define FLASH_CR_STRT (1U << FLASH_CR_STRT_BIT)
+
+#define FLASH_CR_PSIZE (0x3 << 8)
+#define FLASH_CR_PSIZE_MUL8 (0x0 << 8)
+#define FLASH_CR_PSIZE_MUL16 (0x1 << 8)
+#define FLASH_CR_PSIZE_MUL32 (0x2 << 8)
+#define FLASH_CR_PSIZE_MUL64 (0x3 << 8)
+
+#define FLASH_CR_SNB (0xF << 3)
+#define FLASH_CR_SNB_0 (0x0 << 3)
+#define FLASH_CR_SNB_1 (0x1 << 3)
+#define FLASH_CR_SNB_2 (0x2 << 3)
+#define FLASH_CR_SNB_3 (0x3 << 3)
+#define FLASH_CR_SNB_4 (0x4 << 3)
+#define FLASH_CR_SNB_5 (0x5 << 3)
+#define FLASH_CR_SNB_6 (0x6 << 3)
+#define FLASH_CR_SNB_7 (0x7 << 3)
+#define FLASH_CR_SNB_8 (0x8 << 3)
+#define FLASH_CR_SNB_9 (0x9 << 3)
+#define FLASH_CR_SNB_10 (0xA << 3)
+#define FLASH_CR_SNB_11 (0xB << 3)
+
+#define FLASH_CR_MER (1U << FLASH_CR_MER_BIT)
+#define FLASH_CR_SER (1U << FLASH_CR_SER_BIT)
+#define FLASH_CR_PG (1U << FLASH_CR_PG_BIT)
+
+/* Option control register */
+
+#define FLASH_OPTCR_NRST_STDBY_BIT 7
+#define FLASH_OPTCR_NRST_STOP_BIT 6
+#define FLASH_OPTCR_WDG_SW_BIT 5
+#define FLASH_OPTCR_OPTSTRT_BIT 1
+#define FLASH_OPTCR_OPTLOCK_BIT 0
+
+#define FLASH_OPTCR_NWRP (0x3FF << 16)
+
+/* Excluded: The many level 1 values */
+#define FLASH_OPTCR_RDP (0xFF << 8)
+#define FLASH_OPTCR_RDP_LEVEL0 (0xAA << 8)
+#define FLASH_OPTCR_RDP_LEVEL2 (0xCC << 8)
+
+#define FLASH_OPTCR_USER (0x7 << 5)
+#define FLASH_OPTCR_nRST_STDBY (1U << FLASH_OPTCR_nRST_STDBY_BIT)
+#define FLASH_OPTCR_nRST_STOP (1U << FLASH_OPTCR_nRST_STOP_BIT)
+#define FLASH_OPTCR_WDG_SW (1U << FLASH_OPTCR_WDG_SW_BIT)
+
+#define FLASH_OPTCR_BOR_LEV (0x3 << 2)
+#define FLASH_OPTCR_BOR_LEVEL3 (0x0 << 2)
+#define FLASH_OPTCR_BOR_LEVEL2 (0x1 << 2)
+#define FLASH_OPTCR_BOR_LEVEL1 (0x2 << 2)
+#define FLASH_OPTCR_BOR_OFF (0x3 << 2)
+
+#define FLASH_OPTCR_OPTSTRT (1U << FLASH_OPTCR_OPTSTRT_BIT)
+#define FLASH_OPTCR_OPTLOCK (1U << FLASH_OPTCR_OPTLOCK_BIT)
+
+/*
+ * Series-specific configuration values
+ */
+
+/* Note that this value depends on a 2.7V--3.6V supply voltage */
+#define FLASH_SAFE_WAIT_STATES FLASH_WAIT_STATE_3
+
+/* Flash memory features available via ACR. */
+enum {
+ FLASH_PREFETCH = 0x100,
+ FLASH_ICACHE = 0x200,
+ FLASH_DCACHE = 0x400,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/gpio.h b/libmaple/stm32f2/include/series/gpio.h
new file mode 100644
index 0000000..4d0d98c
--- /dev/null
+++ b/libmaple/stm32f2/include/series/gpio.h
@@ -0,0 +1,264 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 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.
+*****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/gpio.h
+ * @brief STM32F2 GPIO support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_GPIO_H_
+#define _LIBMAPLE_STM32F2_GPIO_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * GPIO register maps and devices
+ */
+
+/** GPIO register map type */
+typedef struct gpio_reg_map {
+ __io uint32 MODER; /**< Mode register */
+ __io uint32 OTYPER; /**< Output type register */
+ __io uint32 OSPEEDR; /**< Output speed register */
+ __io uint32 PUPDR; /**< Pull-up/pull-down register */
+ __io uint32 IDR; /**< Input data register */
+ __io uint32 ODR; /**< Output data register */
+ __io uint32 BSRR; /**< Bit set/reset register */
+ __io uint32 LCKR; /**< Configuration lock register */
+ __io uint32 AFRL; /**< Alternate function low register */
+ __io uint32 AFRH; /**< Alternate function high register */
+} gpio_reg_map;
+
+/** GPIO port A register map base pointer */
+#define GPIOA_BASE ((struct gpio_reg_map*)0x40020000)
+/** GPIO port B register map base pointer */
+#define GPIOB_BASE ((struct gpio_reg_map*)0x40020400)
+/** GPIO port C register map base pointer */
+#define GPIOC_BASE ((struct gpio_reg_map*)0x40020800)
+/** GPIO port D register map base pointer */
+#define GPIOD_BASE ((struct gpio_reg_map*)0x40020C00)
+/** GPIO port E register map base pointer */
+#define GPIOE_BASE ((struct gpio_reg_map*)0x40021000)
+/** GPIO port F register map base pointer */
+#define GPIOF_BASE ((struct gpio_reg_map*)0x40021400)
+/** GPIO port G register map base pointer */
+#define GPIOG_BASE ((struct gpio_reg_map*)0x40021800)
+/** GPIO port H register map base pointer */
+#define GPIOH_BASE ((struct gpio_reg_map*)0x40021C00)
+/** GPIO port I register map base pointer */
+#define GPIOI_BASE ((struct gpio_reg_map*)0x40022000)
+
+struct gpio_dev;
+extern struct gpio_dev* const GPIOA;
+extern struct gpio_dev gpioa;
+extern struct gpio_dev* const GPIOB;
+extern struct gpio_dev gpiob;
+extern struct gpio_dev* const GPIOC;
+extern struct gpio_dev gpioc;
+extern struct gpio_dev* const GPIOD;
+extern struct gpio_dev gpiod;
+extern struct gpio_dev* const GPIOE;
+extern struct gpio_dev gpioe;
+extern struct gpio_dev* const GPIOF;
+extern struct gpio_dev gpiof;
+extern struct gpio_dev* const GPIOG;
+extern struct gpio_dev gpiog;
+extern struct gpio_dev* const GPIOH;
+extern struct gpio_dev gpioh;
+extern struct gpio_dev* const GPIOI;
+extern struct gpio_dev gpioi;
+
+/*
+ * Register bit definitions
+ *
+ * Currently, we only provide masks to be used for shifting for some
+ * registers, rather than repeating the same values 16 times.
+ */
+
+/* Mode register */
+
+#define GPIO_MODER_INPUT 0x0
+#define GPIO_MODER_OUTPUT 0x1
+#define GPIO_MODER_AF 0x2
+#define GPIO_MODER_ANALOG 0x3
+
+/* Output type register */
+
+#define GPIO_OTYPER_PP 0x0
+#define GPIO_OTYPER_OD 0x1
+
+/* Output speed register */
+
+#define GPIO_OSPEEDR_LOW 0x0
+#define GPIO_OSPEEDR_MED 0x1
+#define GPIO_OSPEEDR_FAST 0x2
+#define GPIO_OSPEEDR_HIGH 0x3
+
+/* Pull-up/pull-down register */
+
+#define GPIO_PUPDR_NOPUPD 0x0
+#define GPIO_PUPDR_PU 0x1
+#define GPIO_PUPDR_PD 0x2
+
+/* Alternate function register low */
+
+#define GPIO_AFRL_AF0 (0xFU << 0)
+#define GPIO_AFRL_AF1 (0xFU << 4)
+#define GPIO_AFRL_AF2 (0xFU << 8)
+#define GPIO_AFRL_AF3 (0xFU << 12)
+#define GPIO_AFRL_AF4 (0xFU << 16)
+#define GPIO_AFRL_AF5 (0xFU << 20)
+#define GPIO_AFRL_AF6 (0xFU << 24)
+#define GPIO_AFRL_AF7 (0xFU << 28)
+
+/* Alternate function register high */
+
+#define GPIO_AFRH_AF8 (0xFU << 0)
+#define GPIO_AFRH_AF9 (0xFU << 4)
+#define GPIO_AFRH_AF10 (0xFU << 8)
+#define GPIO_AFRH_AF11 (0xFU << 12)
+#define GPIO_AFRH_AF12 (0xFU << 16)
+#define GPIO_AFRH_AF13 (0xFU << 20)
+#define GPIO_AFRH_AF14 (0xFU << 24)
+#define GPIO_AFRH_AF15 (0xFU << 28)
+
+/*
+ * GPIO routines
+ */
+
+/**
+ * @brief GPIO pin modes
+ */
+typedef enum gpio_pin_mode {
+ GPIO_MODE_INPUT = GPIO_MODER_INPUT, /**< Input mode */
+ GPIO_MODE_OUTPUT = GPIO_MODER_OUTPUT, /**< Output mode */
+ GPIO_MODE_AF = GPIO_MODER_AF, /**< Alternate function mode */
+ GPIO_MODE_ANALOG = GPIO_MODER_ANALOG, /**< Analog mode */
+} gpio_pin_mode;
+
+/**
+ * @brief Additional flags to be used when setting a pin's mode.
+ *
+ * Beyond the basic modes (input, general purpose output, alternate
+ * function, and analog), there are three parameters that can affect a
+ * pin's mode:
+ *
+ * 1. Output type: push/pull or open-drain. This only has an effect
+ * for output modes. Choices are: GPIO_MODEF_TYPE_PP (the default)
+ * and GPIO_MODEF_TYPE_OD.
+ *
+ * 2. Output speed: specifies the frequency at which a pin changes
+ * state. This only has an effect for output modes. Choices are:
+ * GPIO_MODEF_SPEED_LOW (default), GPIO_MODEF_SPEED_MED,
+ * GPIO_MODEF_SPEED_FAST, and GPIO_MODEF_SPEED_HIGH.
+ *
+ * 3. Push/pull setting: All GPIO pins have weak pull-up and pull-down
+ * resistors that can be enabled when the pin's mode is
+ * set. Choices are: GPIO_MODEF_PUPD_NONE (default),
+ * GPIO_MODEF_PUPD_PU, and GPIO_MODEF_PUPD_PD.
+ */
+typedef enum gpio_mode_flags {
+ /* Output type in bit 0 */
+ GPIO_MODEF_TYPE_PP = GPIO_OTYPER_PP, /**< Output push/pull (default).
+ Applies only when the mode
+ specifies output. */
+ GPIO_MODEF_TYPE_OD = GPIO_OTYPER_OD, /**< Output open drain.
+ Applies only when the mode
+ specifies output. */
+
+ /* Speed in bits 2:1 */
+ GPIO_MODEF_SPEED_LOW = GPIO_OSPEEDR_LOW << 1, /**< Low speed (default):
+ 2 MHz. */
+ GPIO_MODEF_SPEED_MED = GPIO_OSPEEDR_MED << 1, /**< Medium speed: 25 MHz. */
+ GPIO_MODEF_SPEED_FAST = GPIO_OSPEEDR_FAST << 1, /**< Fast speed: 50 MHz. */
+ GPIO_MODEF_SPEED_HIGH = GPIO_OSPEEDR_HIGH << 1, /**< High speed:
+ 100 MHz on 30 pF,
+ 80 MHz on 15 pF. */
+
+ /* Pull-up/pull-down in bits 4:3 */
+ GPIO_MODEF_PUPD_NONE = GPIO_PUPDR_NOPUPD << 3, /**< No pull-up/pull-down
+ (default). */
+ GPIO_MODEF_PUPD_PU = GPIO_PUPDR_PU << 3, /**< Pull-up */
+ GPIO_MODEF_PUPD_PD = GPIO_PUPDR_PD << 3, /**< Pull-down */
+} gpio_mode_flags;
+
+void gpio_set_modef(struct gpio_dev *dev,
+ uint8 bit,
+ gpio_pin_mode mode,
+ unsigned flags);
+
+/**
+ * @brief Set the mode of a GPIO pin.
+ *
+ * Calling this function is equivalent to calling gpio_set_modef(dev,
+ * pin, mode, GPIO_MODE_SPEED_HIGH). Note that this overrides the
+ * default speed.
+ *
+ * @param dev GPIO device.
+ * @param bit Bit on the device whose mode to set, 0--15.
+ * @param mode Mode to set the pin to.
+ */
+static inline void gpio_set_mode(struct gpio_dev *dev,
+ uint8 bit,
+ gpio_pin_mode mode) {
+ gpio_set_modef(dev, bit, mode, GPIO_MODEF_SPEED_HIGH);
+}
+
+/**
+ * @brief GPIO alternate functions.
+ * Use these to select an alternate function for a pin.
+ * @see gpio_set_af()
+ */
+typedef enum gpio_af {
+ GPIO_AF_SYS = 0, /**< System. */
+ GPIO_AF_TIM_1_2 = 1, /**< Timers 1 and 2. */
+ GPIO_AF_TIM_3_4_5 = 2, /**< Timers 3, 4, and 5. */
+ GPIO_AF_TIM_8_9_10_11 = 3, /**< Timers 8 through 11. */
+ GPIO_AF_I2C = 4, /**< I2C 1, 2, and 3. */
+ GPIO_AF_SPI_1_2 = 5, /**< SPI1, SPI2/I2S2. */
+ GPIO_AF_SPI3 = 6, /**< SPI3/I2S3. */
+ GPIO_AF_USART_1_2_3 = 7, /**< USART 1, 2, and 3. */
+ GPIO_AF_USART_4_5_6 = 8, /**< UART 4 and 5, USART 6. */
+ GPIO_AF_CAN_1_2_TIM_12_13_14 = 9, /**<
+ * CAN 1 and 2, timers 12, 13, and 14. */
+ GPIO_AF_USB_OTG_FS_HS = 10, /**< USB OTG HS and FS. */
+ GPIO_AF_ETH = 11, /**< Ethernet MII and RMII. */
+ GPIO_AF_FSMC_SDIO_OTG_FS = 12, /**< FSMC, SDIO, and USB OTG FS. */
+ GPIO_AF_DCMI = 13, /**< DCMI. */
+ GPIO_AF_EVENTOUT = 15, /**< EVENTOUT. */
+} gpio_af;
+
+void gpio_set_af(struct gpio_dev *dev, uint8 bit, gpio_af af);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/nvic.h b/libmaple/stm32f2/include/series/nvic.h
new file mode 100644
index 0000000..dc03806
--- /dev/null
+++ b/libmaple/stm32f2/include/series/nvic.h
@@ -0,0 +1,160 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/nvic.h
+ * @brief STM32F2 nested vectored interrupt controller (NVIC) header.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_NVIC_H_
+#define _LIBMAPLE_STM32F2_NVIC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/**
+ * @brief STM32F2 interrupt vector table interrupt numbers.
+ */
+typedef enum nvic_irq_num {
+ NVIC_NMI = -14, /**< Non-maskable interrupt */
+ NVIC_HARDFAULT = -13, /**< Hard fault (all class of fault) */
+ NVIC_MEM_MANAGE = -12, /**< Memory management */
+ NVIC_BUS_FAULT = -11, /**< Bus fault: prefetch fault, memory
+ access fault. */
+ NVIC_USAGE_FAULT = -10, /**< Usage fault: Undefined instruction
+ or illegal state. */
+ NVIC_SVC = -5, /**< System service call via SWI
+ instruction */
+ NVIC_DEBUG_MON = -4, /**< Debug monitor */
+ NVIC_PEND_SVC = -2, /**< Pendable request for system
+ service */
+ NVIC_SYSTICK = -1, /**< System tick timer */
+ NVIC_WWDG = 0, /**< Window watchdog interrupt */
+ NVIC_PVD = 1, /**< PVD through EXTI line detection */
+ NVIC_TAMP_STAMP = 2, /**< Tamper and TimeStamp */
+ NVIC_RTC_WKUP = 3, /**< Real-time clock wakeup */
+ NVIC_FLASH = 4, /**< Flash */
+ NVIC_RCC = 5, /**< Reset and clock control */
+ NVIC_EXTI0 = 6, /**< EXTI line 0 */
+ NVIC_EXTI1 = 7, /**< EXTI line 1 */
+ NVIC_EXTI2 = 8, /**< EXTI line 2 */
+ NVIC_EXTI3 = 9, /**< EXTI line 3 */
+ NVIC_EXTI4 = 10, /**< EXTI line 4 */
+ NVIC_DMA1_STREAM0 = 11, /**< DMA1 stream 0 */
+ NVIC_DMA1_STREAM1 = 12, /**< DMA1 stream 1 */
+ NVIC_DMA1_STREAM2 = 13, /**< DMA1 stream 2 */
+ NVIC_DMA1_STREAM3 = 14, /**< DMA1 stream 3 */
+ NVIC_DMA1_STREAM4 = 15, /**< DMA1 stream 4 */
+ NVIC_DMA1_STREAM5 = 16, /**< DMA1 stream 5 */
+ NVIC_DMA1_STREAM6 = 17, /**< DMA1 stream 6 */
+ NVIC_ADC = 18, /**< ADC */
+ NVIC_CAN1_TX = 19, /**< CAN1 TX */
+ NVIC_CAN1_RX0 = 20, /**< CAN1 RX0 */
+ NVIC_CAN1_RX1 = 21, /**< CAN1 RX1 */
+ NVIC_CAN1_SCE = 22, /**< CAN1 SCE */
+ NVIC_EXTI_9_5 = 23, /**< EXTI lines [9:5] */
+ NVIC_TIMER1_BRK_TIMER9 = 24, /**< Timer 1 break and timer 9 */
+ NVIC_TIMER1_UP_TIMER10 = 25, /**< Timer 1 update and timer 10 */
+ NVIC_TIMER1_TRG_COM_TIMER11 = 26, /**< Timer 1 trigger and commutation and
+ timer 11.*/
+ NVIC_TIMER1_CC = 27, /**< Timer 1 capture and compare */
+ NVIC_TIMER2 = 28, /**< Timer 2 */
+ NVIC_TIMER3 = 29, /**< Timer 3 */
+ NVIC_TIMER4 = 30, /**< Timer 4 */
+ NVIC_I2C1_EV = 31, /**< I2C1 event */
+ NVIC_I2C1_ER = 32, /**< I2C2 error */
+ NVIC_I2C2_EV = 33, /**< I2C2 event */
+ NVIC_I2C2_ER = 34, /**< I2C2 error */
+ NVIC_SPI1 = 35, /**< SPI1 */
+ NVIC_SPI2 = 36, /**< SPI2 */
+ NVIC_USART1 = 37, /**< USART1 */
+ NVIC_USART2 = 38, /**< USART2 */
+ NVIC_USART3 = 39, /**< USART3 */
+ NVIC_EXTI_15_10 = 40, /**< EXTI lines [15:10] */
+ NVIC_RTCALARM = 41, /**< RTC alarms A and B through EXTI */
+ NVIC_OTG_FS_WKUP = 42, /**< USB on-the-go full-speed wakeup
+ through EXTI*/
+ NVIC_TIMER8_BRK_TIMER12 = 43, /**< Timer 8 break and timer 12 */
+ NVIC_TIMER8_UP_TIMER13 = 44, /**< Timer 8 update and timer 13 */
+ NVIC_TIMER8_TRG_COM_TIMER14 = 45, /**< Timer 8 trigger and commutation and
+ timer 14 */
+ NVIC_TIMER8_CC = 46, /**< Timer 8 capture and compare */
+ NVIC_DMA1_STREAM7 = 47, /**< DMA1 stream 7 */
+ NVIC_FSMC = 48, /**< FSMC */
+ NVIC_SDIO = 49, /**< SDIO */
+ NVIC_TIMER5 = 50, /**< Timer 5 */
+ NVIC_SPI3 = 51, /**< SPI3 */
+ NVIC_UART4 = 52, /**< UART4 */
+ NVIC_UART5 = 53, /**< UART5 */
+ NVIC_TIMER6_DAC = 54, /**< Timer 6 and DAC underrun */
+ NVIC_TIMER7 = 55, /**< Timer 7 */
+ NVIC_DMA2_STREAM0 = 56, /**< DMA2 stream 0 */
+ NVIC_DMA2_STREAM1 = 57, /**< DMA2 stream 1 */
+ NVIC_DMA2_STREAM2 = 58, /**< DMA2 stream 2 */
+ NVIC_DMA2_STREAM3 = 59, /**< DMA2 stream 3 */
+ NVIC_DMA2_STREAM4 = 60, /**< DMA2 stream 4 */
+ NVIC_ETH = 61, /**< Ethernet */
+ NVIC_ETH_WKUP = 62, /**< Ethernet wakeup through EXTI */
+ NVIC_CAN2_TX = 63, /**< CAN2 TX */
+ NVIC_CAN2_RX0 = 64, /**< CAN2 RX0 */
+ NVIC_CAN2_RX1 = 65, /**< CAN2 RX1 */
+ NVIC_CAN2_SCE = 66, /**< CAN2 SCE */
+ NVIC_OTG_FS = 67, /**< USB on-the-go full-speed */
+ NVIC_DMA2_STREAM5 = 68, /**< DMA2 stream 5 */
+ NVIC_DMA2_STREAM6 = 69, /**< DMA2 stream 6 */
+ NVIC_DMA2_STREAM7 = 70, /**< DMA2 stream 7 */
+ NVIC_USART6 = 71, /**< USART6 */
+ NVIC_I2C3_EV = 72, /**< I2C3 event */
+ NVIC_I2C3_ER = 73, /**< I2C3 error */
+ NVIC_OTG_HS_EP1_OUT = 74, /**< USB on-the-go high-speed
+ endpoint 1 OUT */
+ NVIC_OTG_HS_EP1_IN = 75, /**< USB on-the-go high-speed
+ endpoint 1 IN */
+ NVIC_OTG_HS_WKUP = 76, /**< USB on-the-go high-speed wakeup
+ through EXTI*/
+ NVIC_OTG_HS = 77, /**< USB on-the-go high-speed */
+ NVIC_DCMI = 78, /**< DCMI */
+ NVIC_CRYP = 79, /**< Cryptographic processor */
+ NVIC_HASH_RNG = 80, /**< Hash and random number
+ generation */
+
+ /* Fake enumerator values, for compatiblity with F1.
+ * TODO decide if this is actually a good idea. */
+ NVIC_TIMER6 = NVIC_TIMER6_DAC, /**< For compatibility with STM32F1. */
+} nvic_irq_num;
+
+static inline void nvic_irq_disable_all(void) {
+ NVIC_BASE->ICER[0] = 0xFFFFFFFF;
+ NVIC_BASE->ICER[1] = 0xFFFFFFFF;
+ NVIC_BASE->ICER[2] = 0xFFFFFFFF;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/pwr.h b/libmaple/stm32f2/include/series/pwr.h
new file mode 100644
index 0000000..96353a4
--- /dev/null
+++ b/libmaple/stm32f2/include/series/pwr.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/pwr.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 Power control (PWR) support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_PWR_H_
+#define _LIBMAPLE_STM32F2_PWR_H_
+
+/*
+ * Additional register bits
+ */
+
+/* Control register */
+
+/**
+ * @brief Flash power down in stop mode bit.
+ * Availability: STM32F2 */
+#define PWR_CR_FPDS_BIT 9
+/**
+ * @brief Flash power down in stop mode.
+ * Availability: STM32F2 */
+#define PWR_CR_FPDS (1U << PWR_CR_FPDS_BIT)
+
+/* PVD level selection */
+#define PWR_CR_PLS_2_0V (0x0 << 5)
+#define PWR_CR_PLS_2_1V (0x1 << 5)
+#define PWR_CR_PLS_2_3V (0x2 << 5)
+#define PWR_CR_PLS_2_5V (0x3 << 5)
+#define PWR_CR_PLS_2_6V (0x4 << 5)
+#define PWR_CR_PLS_2_7V (0x5 << 5)
+#define PWR_CR_PLS_2_8V (0x6 << 5)
+#define PWR_CR_PLS_2_9V (0x7 << 5)
+
+/* Control/Status register */
+
+/** Backup regulator enable bit. */
+#define PWR_CSR_BRE_BIT 9
+/** Backup regulator ready bit. */
+#define PWR_CSR_BRR_BIT 3
+
+/** Backup regulator enable. */
+#define PWR_CSR_BRE (1U << PWR_CSR_BRE_BIT)
+/** Backup regulator ready. */
+#define PWR_CSR_BRR (1U << PWR_CSR_BRR_BIT)
+
+#endif
diff --git a/libmaple/stm32f2/include/series/rcc.h b/libmaple/stm32f2/include/series/rcc.h
new file mode 100644
index 0000000..441a5a8
--- /dev/null
+++ b/libmaple/stm32f2/include/series/rcc.h
@@ -0,0 +1,951 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/rcc.h
+ * @brief STM32F2 reset and clock control (RCC) support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_RCC_H_
+#define _LIBMAPLE_STM32F2_RCC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** STM32F2 RCC register map type */
+typedef struct rcc_reg_map {
+ __io uint32 CR; /**< Clock control register */
+ __io uint32 PLLCFGR; /**< PLL configuration register */
+ __io uint32 CFGR; /**< Clock configuration register */
+ __io uint32 CIR; /**< Clock interrupt register */
+ __io uint32 AHB1RSTR; /**< AHB1 peripheral reset register */
+ __io uint32 AHB2RSTR; /**< AHB2 peripheral reset register */
+ __io uint32 AHB3RSTR; /**< AHB3 peripheral reset register */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 APB1RSTR; /**< APB1 peripheral reset register */
+ __io uint32 APB2RSTR; /**< APB2 peripheral reset register */
+ const uint32 RESERVED2; /**< Reserved */
+ const uint32 RESERVED3; /**< Reserved */
+ __io uint32 AHB1ENR; /**< AHB1 peripheral clock enable register */
+ __io uint32 AHB2ENR; /**< AHB2 peripheral clock enable register */
+ __io uint32 AHB3ENR; /**< AHB3 peripheral clock enable register */
+ const uint32 RESERVED4; /**< Reserved */
+ __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */
+ __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */
+ const uint32 RESERVED5; /**< Reserved */
+ const uint32 RESERVED6; /**< Reserved */
+ __io uint32 AHB1LPENR; /**< AHB1 peripheral clock enable in
+ low power mode register */
+ __io uint32 AHB2LPENR; /**< AHB2 peripheral clock enable in
+ low power mode register */
+ __io uint32 AHB3LPENR; /**< AHB3 peripheral clock enable in
+ low power mode register */
+ const uint32 RESERVED7; /**< Reserved */
+ __io uint32 APB1LPENR; /**< APB1 peripheral clock enable in
+ low power mode register */
+ __io uint32 APB2LPENR; /**< APB2 peripheral clock enable in
+ low power mode register */
+ const uint32 RESERVED8; /**< Reserved */
+ const uint32 RESERVED9; /**< Reserved */
+ __io uint32 BDCR; /**< Backup domain control register */
+ __io uint32 CSR; /**< Clock control and status register */
+ const uint32 RESERVED10; /**< Reserved */
+ const uint32 RESERVED11; /**< Reserved */
+ __io uint32 SSCGR; /**< Spread spectrum clock generation
+ register */
+ __io uint32 PLLI2SCFGR; /**< PLLI2S configuration register */
+} rcc_reg_map;
+
+#define RCC_BASE ((struct rcc_reg_map*)0x40023800)
+
+/*
+ * Register bit definitions
+ */
+
+/* Clock control register */
+
+#define RCC_CR_PLLI2SRDY_BIT 27
+#define RCC_CR_PLLI2SON_BIT 26
+#define RCC_CR_PLLRDY_BIT 25
+#define RCC_CR_PLLON_BIT 24
+#define RCC_CR_CSSON_BIT 19
+#define RCC_CR_HSEBYP_BIT 18
+#define RCC_CR_HSERDY_BIT 17
+#define RCC_CR_HSEON_BIT 16
+#define RCC_CR_HSIRDY_BIT 1
+#define RCC_CR_HSION_BIT 0
+
+#define RCC_CR_PLLI2SRDY (1U << RCC_CR_PLLI2SRDY_BIT)
+#define RCC_CR_PLLI2SON (1U << RCC_CR_PLLI2SON_BIT)
+#define RCC_CR_PLLRDY (1U << RCC_CR_PLLRDY_BIT)
+#define RCC_CR_PLLON (1U << RCC_CR_PLLON_BIT)
+#define RCC_CR_CSSON (1U << RCC_CR_CSSON_BIT)
+#define RCC_CR_HSEBYP (1U << RCC_CR_HSEBYP_BIT)
+#define RCC_CR_HSERDY (1U << RCC_CR_HSERDY_BIT)
+#define RCC_CR_HSEON (1U << RCC_CR_HSEON_BIT)
+#define RCC_CR_HSICAL (0xFF << 8)
+#define RCC_CR_HSITRIM (0x1F << 3)
+#define RCC_CR_HSIRDY (1U << RCC_CR_HSIRDY_BIT)
+#define RCC_CR_HSION (1U << RCC_CR_HSION_BIT)
+
+/* PLL configuration register */
+
+#define RCC_PLLCFGR_PLLSRC_BIT 22
+
+#define RCC_PLLCFGR_PLLQ (0xF << 24)
+#define RCC_PLLCFGR_PLLSRC (1U << RCC_PLLCFGR_PLLSRC_BIT)
+#define RCC_PLLCFGR_PLLSRC_HSI (0x0 << RCC_PLLCFGR_PLLSRC_BIT)
+#define RCC_PLLCFGR_PLLSRC_HSE (0x1 << RCC_PLLCFGR_PLLSRC_BIT)
+#define RCC_PLLCFGR_PLLP (0x3 << 16)
+#define RCC_PLLCFGR_PLLN (0x1FF << 6)
+#define RCC_PLLCFGR_PLLM 0x1F
+
+/* Clock configuration register */
+
+#define RCC_CFGR_I2SSRC_BIT 23
+
+#define RCC_CFGR_MCO2 (0x3 << 30)
+#define RCC_CFGR_MCO2_SYSCLK (0x0 << 30)
+#define RCC_CFGR_MCO2_PLLI2S (0x1 << 30)
+#define RCC_CFGR_MCO2_HSE (0x2 << 30)
+#define RCC_CFGR_MCO2_PLL (0x3 << 30)
+
+#define RCC_CFGR_MCO2PRE (0x7 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_1 (0x0 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_2 (0x4 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_3 (0x5 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_4 (0x6 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_5 (0x7 << 27)
+
+#define RCC_CFGR_MCO1PRE (0x7 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_1 (0x0 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_2 (0x4 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_3 (0x5 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_4 (0x6 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_5 (0x7 << 24)
+
+#define RCC_CFGR_I2SSRC (1U << RCC_CFGR_I2SSRC_BIT)
+#define RCC_CFGR_I2SSRC_PLLI2S (0 << RCC_CFGR_I2SSRC_BIT)
+#define RCC_CFGR_I2SSRC_I2S_CKIN (1 << RCC_CFGR_I2SSRC_BIT)
+
+#define RCC_CFGR_MCO1 (0x3 << 21)
+#define RCC_CFGR_MCO1_HSI (0x0 << 21)
+#define RCC_CFGR_MCO1_LSE (0x1 << 21)
+#define RCC_CFGR_MCO1_HSE (0x2 << 21)
+#define RCC_CFGR_MCO1_PLL (0x3 << 21)
+
+#define RCC_CFGR_RTCPRE (0x1F << 16)
+
+/* Skipped: all the 0b0xx values meaning "not divided" */
+#define RCC_CFGR_PPRE2 (0x7 << 13)
+#define RCC_CFGR_PPRE2_AHB_DIV_2 (0x4 << 13)
+#define RCC_CFGR_PPRE2_AHB_DIV_4 (0x5 << 13)
+#define RCC_CFGR_PPRE2_AHB_DIV_8 (0x6 << 13)
+#define RCC_CFGR_PPRE2_AHB_DIV_16 (0x7 << 13)
+
+/* Skipped: all the 0b0xx values meaning "not divided" */
+#define RCC_CFGR_PPRE1 (0x7 << 10)
+#define RCC_CFGR_PPRE1_AHB_DIV_2 (0x4 << 10)
+#define RCC_CFGR_PPRE1_AHB_DIV_4 (0x5 << 10)
+#define RCC_CFGR_PPRE1_AHB_DIV_8 (0x6 << 10)
+#define RCC_CFGR_PPRE1_AHB_DIV_16 (0x7 << 10)
+
+/* Skipped: all the 0b0xxx values meaning "not divided" */
+#define RCC_CFGR_HPRE (0xF << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_2 (0x8 << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_4 (0x9 << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_8 (0xA << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_16 (0xB << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_64 (0xC << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_128 (0xD << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_256 (0xE << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_512 (0xF << 4)
+
+#define RCC_CFGR_SWS (0x3 << 2)
+#define RCC_CFGR_SWS_HSI (0x0 << 2)
+#define RCC_CFGR_SWS_HSE (0x1 << 2)
+#define RCC_CFGR_SWS_PLL (0x2 << 2)
+
+#define RCC_CFGR_SW 0x3
+#define RCC_CFGR_SW_HSI 0x0
+#define RCC_CFGR_SW_HSE 0x1
+#define RCC_CFGR_SW_PLL 0x2
+
+/* Clock interrupt register */
+
+#define RCC_CIR_CSSC_BIT 23
+
+#define RCC_CIR_PLLI2SRDYC_BIT 21
+#define RCC_CIR_PLLRDYC_BIT 20
+#define RCC_CIR_HSERDYC_BIT 19
+#define RCC_CIR_HSIRDYC_BIT 18
+#define RCC_CIR_LSERDYC_BIT 17
+#define RCC_CIR_LSIRDYC_BIT 16
+
+#define RCC_CIR_PLLI2SRDYIE_BIT 13
+#define RCC_CIR_PLLRDYIE_BIT 12
+#define RCC_CIR_HSERDYIE_BIT 11
+#define RCC_CIR_HSIRDYIE_BIT 10
+#define RCC_CIR_LSERDYIE_BIT 9
+#define RCC_CIR_LSIRDYIE_BIT 8
+
+#define RCC_CIR_CSSF_BIT 7
+
+#define RCC_CIR_PLLI2SRDYF_BIT 5
+#define RCC_CIR_PLLRDYF_BIT 4
+#define RCC_CIR_HSERDYF_BIT 3
+#define RCC_CIR_HSIRDYF_BIT 2
+#define RCC_CIR_LSERDYF_BIT 1
+#define RCC_CIR_LSIRDYF_BIT 0
+
+#define RCC_CIR_CSSC (1U << RCC_CIR_CSSC_BIT)
+
+#define RCC_CIR_PLLI2SRDYC (1U << RCC_CIR_PLLI2SRDYC_BIT)
+#define RCC_CIR_PLLRDYC (1U << RCC_CIR_PLLRDYC_BIT)
+#define RCC_CIR_HSERDYC (1U << RCC_CIR_HSERDYC_BIT)
+#define RCC_CIR_HSIRDYC (1U << RCC_CIR_HSIRDYC_BIT)
+#define RCC_CIR_LSERDYC (1U << RCC_CIR_LSERDYC_BIT)
+#define RCC_CIR_LSIRDYC (1U << RCC_CIR_LSIRDYC_BIT)
+
+#define RCC_CIR_PLLI2SRDYIE (1U << RCC_CIR_PLLI2SRDYIE_BIT)
+#define RCC_CIR_PLLRDYIE (1U << RCC_CIR_PLLRDYIE_BIT)
+#define RCC_CIR_HSERDYIE (1U << RCC_CIR_HSERDYIE_BIT)
+#define RCC_CIR_HSIRDYIE (1U << RCC_CIR_HSIRDYIE_BIT)
+#define RCC_CIR_LSERDYIE (1U << RCC_CIR_LSERDYIE_BIT)
+#define RCC_CIR_LSIRDYIE (1U << RCC_CIR_LSIRDYIE_BIT)
+
+#define RCC_CIR_CSSF (1U << RCC_CIR_CSSF_BIT)
+
+#define RCC_CIR_PLLI2SRDYF (1U << RCC_CIR_PLLI2SRDYF_BIT)
+#define RCC_CIR_PLLRDYF (1U << RCC_CIR_PLLRDYF_BIT)
+#define RCC_CIR_HSERDYF (1U << RCC_CIR_HSERDYF_BIT)
+#define RCC_CIR_HSIRDYF (1U << RCC_CIR_HSIRDYF_BIT)
+#define RCC_CIR_LSERDYF (1U << RCC_CIR_LSERDYF_BIT)
+#define RCC_CIR_LSIRDYF (1U << RCC_CIR_LSIRDYF_BIT)
+
+/* AHB1 peripheral reset register */
+
+#define RCC_AHB1RSTR_OTGHSRST_BIT 29
+#define RCC_AHB1RSTR_ETHMACRST_BIT 25
+#define RCC_AHB1RSTR_DMA2RST_BIT 22
+#define RCC_AHB1RSTR_DMA1RST_BIT 21
+#define RCC_AHB1RSTR_CRCRST_BIT 12
+#define RCC_AHB1RSTR_GPIOIRST_BIT 8
+#define RCC_AHB1RSTR_GPIOHRST_BIT 7
+#define RCC_AHB1RSTR_GPIOGRST_BIT 6
+#define RCC_AHB1RSTR_GPIOFRST_BIT 5
+#define RCC_AHB1RSTR_GPIOERST_BIT 4
+#define RCC_AHB1RSTR_GPIODRST_BIT 3
+#define RCC_AHB1RSTR_GPIOCRST_BIT 2
+#define RCC_AHB1RSTR_GPIOBRST_BIT 1
+#define RCC_AHB1RSTR_GPIOARST_BIT 0
+
+#define RCC_AHB1RSTR_OTGHSRST (1U << RCC_AHB1RSTR_OTGHSRST_BIT)
+#define RCC_AHB1RSTR_ETHMACRST (1U << RCC_AHB1RSTR_ETHMACRST_BIT)
+#define RCC_AHB1RSTR_DMA2RST (1U << RCC_AHB1RSTR_DMA2RST_BIT)
+#define RCC_AHB1RSTR_DMA1RST (1U << RCC_AHB1RSTR_DMA1RST_BIT)
+#define RCC_AHB1RSTR_CRCRST (1U << RCC_AHB1RSTR_CRCRST_BIT)
+#define RCC_AHB1RSTR_GPIOIRST (1U << RCC_AHB1RSTR_GPIOIRST_BIT)
+#define RCC_AHB1RSTR_GPIOHRST (1U << RCC_AHB1RSTR_GPIOHRST_BIT)
+#define RCC_AHB1RSTR_GPIOGRST (1U << RCC_AHB1RSTR_GPIOGRST_BIT)
+#define RCC_AHB1RSTR_GPIOFRST (1U << RCC_AHB1RSTR_GPIOFRST_BIT)
+#define RCC_AHB1RSTR_GPIOERST (1U << RCC_AHB1RSTR_GPIOERST_BIT)
+#define RCC_AHB1RSTR_GPIODRST (1U << RCC_AHB1RSTR_GPIODRST_BIT)
+#define RCC_AHB1RSTR_GPIOCRST (1U << RCC_AHB1RSTR_GPIOCRST_BIT)
+#define RCC_AHB1RSTR_GPIOBRST (1U << RCC_AHB1RSTR_GPIOBRST_BIT)
+#define RCC_AHB1RSTR_GPIOARST (1U << RCC_AHB1RSTR_GPIOARST_BIT)
+
+/* AHB2 peripheral reset register */
+
+#define RCC_AHB2RSTR_OTGFSRST_BIT 7
+#define RCC_AHB2RSTR_RNGRST_BIT 6
+#define RCC_AHB2RSTR_HASHRST_BIT 5
+#define RCC_AHB2RSTR_CRYPRST_BIT 4
+#define RCC_AHB2RSTR_DCMIRST_BIT 0
+
+#define RCC_AHB2RSTR_OTGFSRST (1U << RCC_AHB2RSTR_OTGFSRST_BIT)
+#define RCC_AHB2RSTR_RNGRST (1U << RCC_AHB2RSTR_RNGRST_BIT)
+#define RCC_AHB2RSTR_HASHRST (1U << RCC_AHB2RSTR_HASHRST_BIT)
+#define RCC_AHB2RSTR_CRYPRST (1U << RCC_AHB2RSTR_CRYPRST_BIT)
+#define RCC_AHB2RSTR_DCMIRST (1U << RCC_AHB2RSTR_DCMIRST_BIT)
+
+/* AHB3 peripheral reset register */
+
+#define RCC_AHB3RSTR_FSMCRST_BIT 0
+
+#define RCC_AHB3RSTR_FSMCRST (1U << RCC_AHB3RSTR_FSMCRST_BIT)
+
+/* APB1 peripheral reset register */
+
+#define RCC_APB1RSTR_DACRST_BIT 29
+#define RCC_APB1RSTR_PWRRST_BIT 28
+#define RCC_APB1RSTR_CAN2RST_BIT 26
+#define RCC_APB1RSTR_CAN1RST_BIT 25
+#define RCC_APB1RSTR_I2C3RST_BIT 23
+#define RCC_APB1RSTR_I2C2RST_BIT 22
+#define RCC_APB1RSTR_I2C1RST_BIT 21
+#define RCC_APB1RSTR_UART5RST_BIT 20
+#define RCC_APB1RSTR_UART4RST_BIT 19
+#define RCC_APB1RSTR_UART3RST_BIT 18
+#define RCC_APB1RSTR_UART2RST_BIT 17
+#define RCC_APB1RSTR_SPI3RST_BIT 15
+#define RCC_APB1RSTR_SPI2RST_BIT 14
+#define RCC_APB1RSTR_WWDGRST_BIT 11
+#define RCC_APB1RSTR_TIM14RST_BIT 8
+#define RCC_APB1RSTR_TIM13RST_BIT 7
+#define RCC_APB1RSTR_TIM12RST_BIT 6
+#define RCC_APB1RSTR_TIM7RST_BIT 5
+#define RCC_APB1RSTR_TIM6RST_BIT 4
+#define RCC_APB1RSTR_TIM5RST_BIT 3
+#define RCC_APB1RSTR_TIM4RST_BIT 2
+#define RCC_APB1RSTR_TIM3RST_BIT 1
+#define RCC_APB1RSTR_TIM2RST_BIT 0
+
+#define RCC_APB1RSTR_DACRST (1U << RCC_APB1RSTR_DACRST_BIT)
+#define RCC_APB1RSTR_PWRRST (1U << RCC_APB1RSTR_PWRRST_BIT)
+#define RCC_APB1RSTR_CAN2RST (1U << RCC_APB1RSTR_CAN2RST_BIT)
+#define RCC_APB1RSTR_CAN1RST (1U << RCC_APB1RSTR_CAN1RST_BIT)
+#define RCC_APB1RSTR_I2C3RST (1U << RCC_APB1RSTR_I2C3RST_BIT)
+#define RCC_APB1RSTR_I2C2RST (1U << RCC_APB1RSTR_I2C2RST_BIT)
+#define RCC_APB1RSTR_I2C1RST (1U << RCC_APB1RSTR_I2C1RST_BIT)
+#define RCC_APB1RSTR_UART5RST (1U << RCC_APB1RSTR_UART5RST_BIT)
+#define RCC_APB1RSTR_UART4RST (1U << RCC_APB1RSTR_UART4RST_BIT)
+#define RCC_APB1RSTR_UART3RST (1U << RCC_APB1RSTR_UART3RST_BIT)
+#define RCC_APB1RSTR_UART2RST (1U << RCC_APB1RSTR_UART2RST_BIT)
+#define RCC_APB1RSTR_SPI3RST (1U << RCC_APB1RSTR_SPI3RST_BIT)
+#define RCC_APB1RSTR_SPI2RST (1U << RCC_APB1RSTR_SPI2RST_BIT)
+#define RCC_APB1RSTR_WWDGRST (1U << RCC_APB1RSTR_WWDGRST_BIT)
+#define RCC_APB1RSTR_TIM14RST (1U << RCC_APB1RSTR_TIM14RST_BIT)
+#define RCC_APB1RSTR_TIM13RST (1U << RCC_APB1RSTR_TIM13RST_BIT)
+#define RCC_APB1RSTR_TIM12RST (1U << RCC_APB1RSTR_TIM12RST_BIT)
+#define RCC_APB1RSTR_TIM7RST (1U << RCC_APB1RSTR_TIM7RST_BIT)
+#define RCC_APB1RSTR_TIM6RST (1U << RCC_APB1RSTR_TIM6RST_BIT)
+#define RCC_APB1RSTR_TIM5RST (1U << RCC_APB1RSTR_TIM5RST_BIT)
+#define RCC_APB1RSTR_TIM4RST (1U << RCC_APB1RSTR_TIM4RST_BIT)
+#define RCC_APB1RSTR_TIM3RST (1U << RCC_APB1RSTR_TIM3RST_BIT)
+#define RCC_APB1RSTR_TIM2RST (1U << RCC_APB1RSTR_TIM2RST_BIT)
+
+/* APB2 peripheral reset register */
+
+#define RCC_APB2RSTR_TIM11RST_BIT 18
+#define RCC_APB2RSTR_TIM10RST_BIT 17
+#define RCC_APB2RSTR_TIM9RST_BIT 16
+#define RCC_APB2RSTR_SYSCFGRST_BIT 14
+#define RCC_APB2RSTR_SPI1RST_BIT 12
+#define RCC_APB2RSTR_SDIORST_BIT 11
+#define RCC_APB2RSTR_ADCRST_BIT 8
+#define RCC_APB2RSTR_USART6RST_BIT 5
+#define RCC_APB2RSTR_USART1RST_BIT 4
+#define RCC_APB2RSTR_TIM8RST_BIT 1
+#define RCC_APB2RSTR_TIM1RST_BIT 0
+
+#define RCC_APB2RSTR_TIM11RST (1U << RCC_APB2RSTR_TIM11RST_BIT)
+#define RCC_APB2RSTR_TIM10RST (1U << RCC_APB2RSTR_TIM10RST_BIT)
+#define RCC_APB2RSTR_TIM9RST (1U << RCC_APB2RSTR_TIM9RST_BIT)
+#define RCC_APB2RSTR_SYSCFGRST (1U << RCC_APB2RSTR_SYSCFGRST_BIT)
+#define RCC_APB2RSTR_SPI1RST (1U << RCC_APB2RSTR_SPI1RST_BIT)
+#define RCC_APB2RSTR_SDIORST (1U << RCC_APB2RSTR_SDIORST_BIT)
+#define RCC_APB2RSTR_ADCRST (1U << RCC_APB2RSTR_ADCRST_BIT)
+#define RCC_APB2RSTR_USART6RST (1U << RCC_APB2RSTR_USART6RST_BIT)
+#define RCC_APB2RSTR_USART1RST (1U << RCC_APB2RSTR_USART1RST_BIT)
+#define RCC_APB2RSTR_TIM8RST (1U << RCC_APB2RSTR_TIM8RST_BIT)
+#define RCC_APB2RSTR_TIM1RST (1U << RCC_APB2RSTR_TIM1RST_BIT)
+
+/* AHB1 peripheral clock enable register */
+
+#define RCC_AHB1ENR_OTGHSULPIEN_BIT 30
+#define RCC_AHB1ENR_OTGHSEN_BIT 29
+#define RCC_AHB1ENR_ETHMACPTPEN_BIT 28
+#define RCC_AHB1ENR_ETHMACRXEN_BIT 27
+#define RCC_AHB1ENR_ETHMACTXEN_BIT 26
+#define RCC_AHB1ENR_ETHMACEN_BIT 25
+#define RCC_AHB1ENR_DMA2EN_BIT 22
+#define RCC_AHB1ENR_DMA1EN_BIT 21
+#define RCC_AHB1ENR_BKPSRAMEN_BIT 18
+#define RCC_AHB1ENR_CRCEN_BIT 12
+#define RCC_AHB1ENR_GPIOIEN_BIT 8
+#define RCC_AHB1ENR_GPIOHEN_BIT 7
+#define RCC_AHB1ENR_GPIOGEN_BIT 6
+#define RCC_AHB1ENR_GPIOFEN_BIT 5
+#define RCC_AHB1ENR_GPIOEEN_BIT 4
+#define RCC_AHB1ENR_GPIODEN_BIT 3
+#define RCC_AHB1ENR_GPIOCEN_BIT 2
+#define RCC_AHB1ENR_GPIOBEN_BIT 1
+#define RCC_AHB1ENR_GPIOAEN_BIT 0
+
+#define RCC_AHB1ENR_OTGHSULPIEN (1U << RCC_AHB1ENR_OTGHSULPIEN_BIT)
+#define RCC_AHB1ENR_OTGHSEN (1U << RCC_AHB1ENR_OTGHSEN_BIT)
+#define RCC_AHB1ENR_ETHMACPTPEN (1U << RCC_AHB1ENR_ETHMACPTPEN_BIT)
+#define RCC_AHB1ENR_ETHMACRXEN (1U << RCC_AHB1ENR_ETHMACRXEN_BIT)
+#define RCC_AHB1ENR_ETHMACTXEN (1U << RCC_AHB1ENR_ETHMACTXEN_BIT)
+#define RCC_AHB1ENR_ETHMACEN (1U << RCC_AHB1ENR_ETHMACEN_BIT)
+#define RCC_AHB1ENR_DMA2EN (1U << RCC_AHB1ENR_DMA2EN_BIT)
+#define RCC_AHB1ENR_DMA1EN (1U << RCC_AHB1ENR_DMA1EN_BIT)
+#define RCC_AHB1ENR_BKPSRAMEN (1U << RCC_AHB1ENR_BKPSRAMEN_BIT)
+#define RCC_AHB1ENR_CRCEN (1U << RCC_AHB1ENR_CRCEN_BIT)
+#define RCC_AHB1ENR_GPIOIEN (1U << RCC_AHB1ENR_GPIOIEN_BIT)
+#define RCC_AHB1ENR_GPIOHEN (1U << RCC_AHB1ENR_GPIOHEN_BIT)
+#define RCC_AHB1ENR_GPIOGEN (1U << RCC_AHB1ENR_GPIOGEN_BIT)
+#define RCC_AHB1ENR_GPIOFEN (1U << RCC_AHB1ENR_GPIOFEN_BIT)
+#define RCC_AHB1ENR_GPIOEEN (1U << RCC_AHB1ENR_GPIOEEN_BIT)
+#define RCC_AHB1ENR_GPIODEN (1U << RCC_AHB1ENR_GPIODEN_BIT)
+#define RCC_AHB1ENR_GPIOCEN (1U << RCC_AHB1ENR_GPIOCEN_BIT)
+#define RCC_AHB1ENR_GPIOBEN (1U << RCC_AHB1ENR_GPIOBEN_BIT)
+#define RCC_AHB1ENR_GPIOAEN (1U << RCC_AHB1ENR_GPIOAEN_BIT)
+
+/* AHB2 peripheral clock enable register */
+
+#define RCC_AHB2ENR_OTGFSEN_BIT 7
+#define RCC_AHB2ENR_RNGEN_BIT 6
+#define RCC_AHB2ENR_HASHEN_BIT 5
+#define RCC_AHB2ENR_CRYPEN_BIT 4
+#define RCC_AHB2ENR_DCMIEN_BIT 0
+
+#define RCC_AHB2ENR_OTGFSEN (1U << RCC_AHB2ENR_OTGFSEN_BIT)
+#define RCC_AHB2ENR_RNGEN (1U << RCC_AHB2ENR_RNGEN_BIT)
+#define RCC_AHB2ENR_HASHEN (1U << RCC_AHB2ENR_HASHEN_BIT)
+#define RCC_AHB2ENR_CRYPEN (1U << RCC_AHB2ENR_CRYPEN_BIT)
+#define RCC_AHB2ENR_DCMIEN (1U << RCC_AHB2ENR_DCMIEN_BIT)
+
+/* AHB3 peripheral clock enable register */
+
+#define RCC_AHB3ENR_FSMCEN_BIT 0
+
+#define RCC_AHB3ENR_FSMCEN (1U << RCC_AHB3ENR_FSMCEN_BIT)
+
+/* APB1 peripheral clock enable register */
+
+#define RCC_APB1ENR_DACEN_BIT 29
+#define RCC_APB1ENR_PWREN_BIT 28
+#define RCC_APB1ENR_CAN2EN_BIT 26
+#define RCC_APB1ENR_CAN1EN_BIT 25
+#define RCC_APB1ENR_I2C3EN_BIT 23
+#define RCC_APB1ENR_I2C2EN_BIT 22
+#define RCC_APB1ENR_I2C1EN_BIT 21
+#define RCC_APB1ENR_UART5EN_BIT 20
+#define RCC_APB1ENR_UART4EN_BIT 19
+#define RCC_APB1ENR_USART3EN_BIT 18
+#define RCC_APB1ENR_USART2EN_BIT 17
+#define RCC_APB1ENR_SPI3EN_BIT 15
+#define RCC_APB1ENR_SPI2EN_BIT 14
+#define RCC_APB1ENR_WWDGEN_BIT 11
+#define RCC_APB1ENR_TIM14EN_BIT 8
+#define RCC_APB1ENR_TIM13EN_BIT 7
+#define RCC_APB1ENR_TIM12EN_BIT 6
+#define RCC_APB1ENR_TIM7EN_BIT 5
+#define RCC_APB1ENR_TIM6EN_BIT 4
+#define RCC_APB1ENR_TIM5EN_BIT 3
+#define RCC_APB1ENR_TIM4EN_BIT 2
+#define RCC_APB1ENR_TIM3EN_BIT 1
+#define RCC_APB1ENR_TIM2EN_BIT 0
+
+#define RCC_APB1ENR_DACEN (1U << RCC_APB1ENR_DACEN_BIT)
+#define RCC_APB1ENR_PWREN (1U << RCC_APB1ENR_PWREN_BIT)
+#define RCC_APB1ENR_CAN2EN (1U << RCC_APB1ENR_CAN2EN_BIT)
+#define RCC_APB1ENR_CAN1EN (1U << RCC_APB1ENR_CAN1EN_BIT)
+#define RCC_APB1ENR_I2C3EN (1U << RCC_APB1ENR_I2C3EN_BIT)
+#define RCC_APB1ENR_I2C2EN (1U << RCC_APB1ENR_I2C2EN_BIT)
+#define RCC_APB1ENR_I2C1EN (1U << RCC_APB1ENR_I2C1EN_BIT)
+#define RCC_APB1ENR_UART5EN (1U << RCC_APB1ENR_UART5EN_BIT)
+#define RCC_APB1ENR_UART4EN (1U << RCC_APB1ENR_UART4EN_BIT)
+#define RCC_APB1ENR_USART3EN (1U << RCC_APB1ENR_USART3EN_BIT)
+#define RCC_APB1ENR_USART2EN (1U << RCC_APB1ENR_USART2EN_BIT)
+#define RCC_APB1ENR_SPI3EN (1U << RCC_APB1ENR_SPI3EN_BIT)
+#define RCC_APB1ENR_SPI2EN (1U << RCC_APB1ENR_SPI2EN_BIT)
+#define RCC_APB1ENR_WWDGEN (1U << RCC_APB1ENR_WWDGEN_BIT)
+#define RCC_APB1ENR_TIM14EN (1U << RCC_APB1ENR_TIM14EN_BIT)
+#define RCC_APB1ENR_TIM13EN (1U << RCC_APB1ENR_TIM13EN_BIT)
+#define RCC_APB1ENR_TIM12EN (1U << RCC_APB1ENR_TIM12EN_BIT)
+#define RCC_APB1ENR_TIM7EN (1U << RCC_APB1ENR_TIM7EN_BIT)
+#define RCC_APB1ENR_TIM6EN (1U << RCC_APB1ENR_TIM6EN_BIT)
+#define RCC_APB1ENR_TIM5EN (1U << RCC_APB1ENR_TIM5EN_BIT)
+#define RCC_APB1ENR_TIM4EN (1U << RCC_APB1ENR_TIM4EN_BIT)
+#define RCC_APB1ENR_TIM3EN (1U << RCC_APB1ENR_TIM3EN_BIT)
+#define RCC_APB1ENR_TIM2EN (1U << RCC_APB1ENR_TIM2EN_BIT)
+
+/* APB2 peripheral clock enable register */
+
+#define RCC_APB2ENR_TIM11EN_BIT 18
+#define RCC_APB2ENR_TIM10EN_BIT 17
+#define RCC_APB2ENR_TIM9EN_BIT 16
+#define RCC_APB2ENR_SYSCFGEN_BIT 14
+#define RCC_APB2ENR_SPI1EN_BIT 12
+#define RCC_APB2ENR_SDIOEN_BIT 11
+#define RCC_APB2ENR_ADC3EN_BIT 10
+#define RCC_APB2ENR_ADC2EN_BIT 9
+#define RCC_APB2ENR_ADC1EN_BIT 8
+#define RCC_APB2ENR_USART6EN_BIT 5
+#define RCC_APB2ENR_USART1EN_BIT 4
+#define RCC_APB2ENR_TIM8EN_BIT 1
+#define RCC_APB2ENR_TIM1EN_BIT 0
+
+#define RCC_APB2ENR_TIM11EN (1U << RCC_APB2ENR_TIM11EN_BIT)
+#define RCC_APB2ENR_TIM10EN (1U << RCC_APB2ENR_TIM10EN_BIT)
+#define RCC_APB2ENR_TIM9EN (1U << RCC_APB2ENR_TIM9EN_BIT)
+#define RCC_APB2ENR_SYSCFGEN (1U << RCC_APB2ENR_SYSCFGEN_BIT)
+#define RCC_APB2ENR_SPI1EN (1U << RCC_APB2ENR_SPI1EN_BIT)
+#define RCC_APB2ENR_SDIOEN (1U << RCC_APB2ENR_SDIOEN_BIT)
+#define RCC_APB2ENR_ADC3EN (1U << RCC_APB2ENR_ADC3EN_BIT)
+#define RCC_APB2ENR_ADC2EN (1U << RCC_APB2ENR_ADC2EN_BIT)
+#define RCC_APB2ENR_ADC1EN (1U << RCC_APB2ENR_ADC1EN_BIT)
+#define RCC_APB2ENR_USART6EN (1U << RCC_APB2ENR_USART6EN_BIT)
+#define RCC_APB2ENR_USART1EN (1U << RCC_APB2ENR_USART1EN_BIT)
+#define RCC_APB2ENR_TIM8EN (1U << RCC_APB2ENR_TIM8EN_BIT)
+#define RCC_APB2ENR_TIM1EN (1U << RCC_APB2ENR_TIM1EN_BIT)
+
+/* AHB1 peripheral clock enable in low power mode register */
+
+#define RCC_AHB1LPENR_OTGHSULPILPEN_BIT 30
+#define RCC_AHB1LPENR_OTGHSLPEN_BIT 29
+#define RCC_AHB1LPENR_ETHMACPTPLPEN_BIT 28
+#define RCC_AHB1LPENR_ETHMACRXLPEN_BIT 27
+#define RCC_AHB1LPENR_ETHMACTXLPEN_BIT 26
+#define RCC_AHB1LPENR_ETHMACLPEN_BIT 25
+#define RCC_AHB1LPENR_DMA2LPEN_BIT 22
+#define RCC_AHB1LPENR_DMA1LPEN_BIT 21
+#define RCC_AHB1LPENR_BKPSRAMLPEN_BIT 18
+#define RCC_AHB1LPENR_SRAM2LPEN_BIT 17
+#define RCC_AHB1LPENR_SRAM1LPEN_BIT 16
+#define RCC_AHB1LPENR_FLITFLPEN_BIT 15
+#define RCC_AHB1LPENR_CRCLPEN_BIT 12
+#define RCC_AHB1LPENR_GPIOILPEN_BIT 8
+#define RCC_AHB1LPENR_GPIOGLPEN_BIT 6
+#define RCC_AHB1LPENR_GPIOFLPEN_BIT 5
+#define RCC_AHB1LPENR_GPIOELPEN_BIT 4
+#define RCC_AHB1LPENR_GPIODLPEN_BIT 3
+#define RCC_AHB1LPENR_GPIOCLPEN_BIT 2
+#define RCC_AHB1LPENR_GPIOBLPEN_BIT 1
+#define RCC_AHB1LPENR_GPIOALPEN_BIT 0
+
+#define RCC_AHB1LPENR_OTGHSULPILPEN (1U << RCC_AHB1LPENR_OTGHSULPILPEN_BIT)
+#define RCC_AHB1LPENR_OTGHSLPEN (1U << RCC_AHB1LPENR_OTGHSLPEN_BIT)
+#define RCC_AHB1LPENR_ETHMACPTPLPEN (1U << RCC_AHB1LPENR_ETHMACPTPLPEN_BIT)
+#define RCC_AHB1LPENR_ETHMACRXLPEN (1U << RCC_AHB1LPENR_ETHMACRXLPEN_BIT)
+#define RCC_AHB1LPENR_ETHMACTXLPEN (1U << RCC_AHB1LPENR_ETHMACTXLPEN_BIT)
+#define RCC_AHB1LPENR_ETHMACLPEN (1U << RCC_AHB1LPENR_ETHMACLPEN_BIT)
+#define RCC_AHB1LPENR_DMA2LPEN (1U << RCC_AHB1LPENR_DMA2LPEN_BIT)
+#define RCC_AHB1LPENR_DMA1LPEN (1U << RCC_AHB1LPENR_DMA1LPEN_BIT)
+#define RCC_AHB1LPENR_BKPSRAMLPEN (1U << RCC_AHB1LPENR_BKPSRAMLPEN_BIT)
+#define RCC_AHB1LPENR_SRAM2LPEN (1U << RCC_AHB1LPENR_SRAM2LPEN_BIT)
+#define RCC_AHB1LPENR_SRAM1LPEN (1U << RCC_AHB1LPENR_SRAM1LPEN_BIT)
+#define RCC_AHB1LPENR_FLITFLPEN (1U << RCC_AHB1LPENR_FLITFLPEN_BIT)
+#define RCC_AHB1LPENR_CRCLPEN (1U << RCC_AHB1LPENR_CRCLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOILPEN (1U << RCC_AHB1LPENR_GPIOILPEN_BIT)
+#define RCC_AHB1LPENR_GPIOGLPEN (1U << RCC_AHB1LPENR_GPIOGLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOFLPEN (1U << RCC_AHB1LPENR_GPIOFLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOELPEN (1U << RCC_AHB1LPENR_GPIOELPEN_BIT)
+#define RCC_AHB1LPENR_GPIODLPEN (1U << RCC_AHB1LPENR_GPIODLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOCLPEN (1U << RCC_AHB1LPENR_GPIOCLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOBLPEN (1U << RCC_AHB1LPENR_GPIOBLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOALPEN (1U << RCC_AHB1LPENR_GPIOALPEN_BIT)
+
+/* AHB2 peripheral clock enable in low power mode register */
+
+#define RCC_AHB2LPENR_OTGFSLPEN_BIT 7
+#define RCC_AHB2LPENR_RNGLPEN_BIT 6
+#define RCC_AHB2LPENR_HASHLPEN_BIT 5
+#define RCC_AHB2LPENR_CRYPLPEN_BIT 4
+#define RCC_AHB2LPENR_DCMILPEN_BIT 0
+
+#define RCC_AHB2LPENR_OTGFSLPEN (1U << RCC_AHB2LPENR_OTGFSLPEN_BIT)
+#define RCC_AHB2LPENR_RNGLPEN (1U << RCC_AHB2LPENR_RNGLPEN_BIT)
+#define RCC_AHB2LPENR_HASHLPEN (1U << RCC_AHB2LPENR_HASHLPEN_BIT)
+#define RCC_AHB2LPENR_CRYPLPEN (1U << RCC_AHB2LPENR_CRYPLPEN_BIT)
+#define RCC_AHB2LPENR_DCMILPEN (1U << RCC_AHB2LPENR_DCMILPEN_BIT)
+
+/* AHB3 peripheral clock enable in low power mode register */
+
+#define RCC_AHB3LPENR_FSMCLPEN_BIT 0
+
+#define RCC_AHB3LPENR_FSMCLPEN (1U << RCC_AHB3LPENR_FSMCLPEN_BIT)
+
+/* APB1 peripheral clock enable in low power mode register */
+
+#define RCC_APB1LPENR_DACLPEN_BIT 29
+#define RCC_APB1LPENR_PWRLPEN_BIT 28
+#define RCC_APB1LPENR_CAN2LPEN_BIT 26
+#define RCC_APB1LPENR_CAN1LPEN_BIT 25
+#define RCC_APB1LPENR_I2C3LPEN_BIT 23
+#define RCC_APB1LPENR_I2C2LPEN_BIT 22
+#define RCC_APB1LPENR_I2C1LPEN_BIT 21
+#define RCC_APB1LPENR_UART5LPEN_BIT 20
+#define RCC_APB1LPENR_UART4LPEN_BIT 19
+#define RCC_APB1LPENR_USART3LPEN_BIT 18
+#define RCC_APB1LPENR_USART2LPEN_BIT 17
+#define RCC_APB1LPENR_SPI3LPEN_BIT 15
+#define RCC_APB1LPENR_SPI2LPEN_BIT 14
+#define RCC_APB1LPENR_WWDGLPEN_BIT 11
+#define RCC_APB1LPENR_TIM14LPEN_BIT 8
+#define RCC_APB1LPENR_TIM13LPEN_BIT 7
+#define RCC_APB1LPENR_TIM12LPEN_BIT 6
+#define RCC_APB1LPENR_TIM7LPEN_BIT 5
+#define RCC_APB1LPENR_TIM6LPEN_BIT 4
+#define RCC_APB1LPENR_TIM5LPEN_BIT 3
+#define RCC_APB1LPENR_TIM4LPEN_BIT 2
+#define RCC_APB1LPENR_TIM3LPEN_BIT 1
+#define RCC_APB1LPENR_TIM2LPEN_BIT 0
+
+#define RCC_APB1LPENR_DACLPEN (1U << RCC_APB1LPENR_DACLPEN_BIT)
+#define RCC_APB1LPENR_PWRLPEN (1U << RCC_APB1LPENR_PWRLPEN_BIT)
+#define RCC_APB1LPENR_CAN2LPEN (1U << RCC_APB1LPENR_CAN2LPEN_BIT)
+#define RCC_APB1LPENR_CAN1LPEN (1U << RCC_APB1LPENR_CAN1LPEN_BIT)
+#define RCC_APB1LPENR_I2C3LPEN (1U << RCC_APB1LPENR_I2C3LPEN_BIT)
+#define RCC_APB1LPENR_I2C2LPEN (1U << RCC_APB1LPENR_I2C2LPEN_BIT)
+#define RCC_APB1LPENR_I2C1LPEN (1U << RCC_APB1LPENR_I2C1LPEN_BIT)
+#define RCC_APB1LPENR_UART5LPEN (1U << RCC_APB1LPENR_UART5LPEN_BIT)
+#define RCC_APB1LPENR_UART4LPEN (1U << RCC_APB1LPENR_UART4LPEN_BIT)
+#define RCC_APB1LPENR_USART3LPEN (1U << RCC_APB1LPENR_USART3LPEN_BIT)
+#define RCC_APB1LPENR_USART2LPEN (1U << RCC_APB1LPENR_USART2LPEN_BIT)
+#define RCC_APB1LPENR_SPI3LPEN (1U << RCC_APB1LPENR_SPI3LPEN_BIT)
+#define RCC_APB1LPENR_SPI2LPEN (1U << RCC_APB1LPENR_SPI2LPEN_BIT)
+#define RCC_APB1LPENR_WWDGLPEN (1U << RCC_APB1LPENR_WWDGLPEN_BIT)
+#define RCC_APB1LPENR_TIM14LPEN (1U << RCC_APB1LPENR_TIM14LPEN_BIT)
+#define RCC_APB1LPENR_TIM13LPEN (1U << RCC_APB1LPENR_TIM13LPEN_BIT)
+#define RCC_APB1LPENR_TIM12LPEN (1U << RCC_APB1LPENR_TIM12LPEN_BIT)
+#define RCC_APB1LPENR_TIM7LPEN (1U << RCC_APB1LPENR_TIM7LPEN_BIT)
+#define RCC_APB1LPENR_TIM6LPEN (1U << RCC_APB1LPENR_TIM6LPEN_BIT)
+#define RCC_APB1LPENR_TIM5LPEN (1U << RCC_APB1LPENR_TIM5LPEN_BIT)
+#define RCC_APB1LPENR_TIM4LPEN (1U << RCC_APB1LPENR_TIM4LPEN_BIT)
+#define RCC_APB1LPENR_TIM3LPEN (1U << RCC_APB1LPENR_TIM3LPEN_BIT)
+#define RCC_APB1LPENR_TIM2LPEN (1U << RCC_APB1LPENR_TIM2LPEN_BIT)
+
+/* APB2 peripheral clock enable in low power mode register */
+
+#define RCC_APB2LPENR_TIM11LPEN_BIT 18
+#define RCC_APB2LPENR_TIM10LPEN_BIT 17
+#define RCC_APB2LPENR_TIM9LPEN_BIT 16
+#define RCC_APB2LPENR_SYSCFGLPEN_BIT 14
+#define RCC_APB2LPENR_SPI1LPEN_BIT 12
+#define RCC_APB2LPENR_SDIOLPEN_BIT 11
+#define RCC_APB2LPENR_ADC3LPEN_BIT 10
+#define RCC_APB2LPENR_ADC2LPEN_BIT 9
+#define RCC_APB2LPENR_ADC1LPEN_BIT 8
+#define RCC_APB2LPENR_USART6LPEN_BIT 5
+#define RCC_APB2LPENR_USART1LPEN_BIT 4
+#define RCC_APB2LPENR_TIM8LPEN_BIT 1
+#define RCC_APB2LPENR_TIM1LPEN_BIT 0
+
+#define RCC_APB2LPENR_TIM11LPEN (1U << RCC_APB2LPENR_TIM11LPEN_BIT)
+#define RCC_APB2LPENR_TIM10LPEN (1U << RCC_APB2LPENR_TIM10LPEN_BIT)
+#define RCC_APB2LPENR_TIM9LPEN (1U << RCC_APB2LPENR_TIM9LPEN_BIT)
+#define RCC_APB2LPENR_SYSCFGLPEN (1U << RCC_APB2LPENR_SYSCFGLPEN_BIT)
+#define RCC_APB2LPENR_SPI1LPEN (1U << RCC_APB2LPENR_SPI1LPEN_BIT)
+#define RCC_APB2LPENR_SDIOLPEN (1U << RCC_APB2LPENR_SDIOLPEN_BIT)
+#define RCC_APB2LPENR_ADC3LPEN (1U << RCC_APB2LPENR_ADC3LPEN_BIT)
+#define RCC_APB2LPENR_ADC2LPEN (1U << RCC_APB2LPENR_ADC2LPEN_BIT)
+#define RCC_APB2LPENR_ADC1LPEN (1U << RCC_APB2LPENR_ADC1LPEN_BIT)
+#define RCC_APB2LPENR_USART6LPEN (1U << RCC_APB2LPENR_USART6LPEN_BIT)
+#define RCC_APB2LPENR_USART1LPEN (1U << RCC_APB2LPENR_USART1LPEN_BIT)
+#define RCC_APB2LPENR_TIM8LPEN (1U << RCC_APB2LPENR_TIM8LPEN_BIT)
+#define RCC_APB2LPENR_TIM1LPEN (1U << RCC_APB2LPENR_TIM1LPEN_BIT)
+
+/* Backup domain control register */
+
+#define RCC_BDCR_BDRST_BIT 16
+#define RCC_BDCR_RTCEN_BIT 15
+#define RCC_BDCR_LSEBYP_BIT 2
+#define RCC_BDCR_LSERDY_BIT 1
+#define RCC_BDCR_LSEON_BIT 0
+
+#define RCC_BDCR_BDRST (1U << RCC_BDCR_BDRST_BIT)
+#define RCC_BDCR_RTCEN (1U << RCC_BDCR_RTCEN_BIT)
+#define RCC_BDCR_RTCSEL (0x3 << 8)
+#define RCC_BDCR_RTCSEL_NOCLOCK (0x0 << 8)
+#define RCC_BDCR_RTCSEL_LSE (0x1 << 8)
+#define RCC_BDCR_RTCSEL_LSI (0x2 << 8)
+#define RCC_BDCR_RTCSEL_HSE_DIV (0x3 << 8)
+#define RCC_BDCR_LSEBYP (1U << RCC_BDCR_LSEBYP_BIT)
+#define RCC_BDCR_LSERDY (1U << RCC_BDCR_LSERDY_BIT)
+#define RCC_BDCR_LSEON (1U << RCC_BDCR_LSEON_BIT)
+
+/* Clock control and status register */
+
+#define RCC_CSR_LPWRRSTF_BIT 31
+#define RCC_CSR_WWDGRSTF_BIT 30
+#define RCC_CSR_IWDGRSTF_BIT 29
+#define RCC_CSR_SFTRSTF_BIT 28
+#define RCC_CSR_PORRSTF_BIT 27
+#define RCC_CSR_PINRSTF_BIT 26
+#define RCC_CSR_BORRSTF_BIT 25
+#define RCC_CSR_RMVF_BIT 24
+#define RCC_CSR_LSIRDY_BIT 1
+#define RCC_CSR_LSION_BIT 0
+
+#define RCC_CSR_LPWRRSTF (1U << RCC_CSR_LPWRRSTF_BIT)
+#define RCC_CSR_WWDGRSTF (1U << RCC_CSR_WWDGRSTF_BIT)
+#define RCC_CSR_IWDGRSTF (1U << RCC_CSR_IWDGRSTF_BIT)
+#define RCC_CSR_SFTRSTF (1U << RCC_CSR_SFTRSTF_BIT)
+#define RCC_CSR_PORRSTF (1U << RCC_CSR_PORRSTF_BIT)
+#define RCC_CSR_PINRSTF (1U << RCC_CSR_PINRSTF_BIT)
+#define RCC_CSR_BORRSTF (1U << RCC_CSR_BORRSTF_BIT)
+#define RCC_CSR_RMVF (1U << RCC_CSR_RMVF_BIT)
+#define RCC_CSR_LSIRDY (1U << RCC_CSR_LSIRDY_BIT)
+#define RCC_CSR_LSION (1U << RCC_CSR_LSION_BIT)
+
+/* Spread spectrum clock generation register */
+
+#define RCC_SSCGR_SSCGEN_BIT 31
+#define RCC_SSCGR_SPREADSEL_BIT 30
+
+#define RCC_SSCGR_SSCGEN (1U << RCC_SSCGR_SSCGEN_BIT)
+#define RCC_SSCGR_SPREADSEL (1U << RCC_SSCGR_SPREADSEL_BIT)
+#define RCC_SSCGR_SPREADSEL_CENTER (0x0 << RCC_SSCGR_SPREADSEL_BIT)
+#define RCC_SSCGR_SPREADSEL_DOWN (0x1 << RCC_SSCGR_SPREADSEL_BIT)
+#define RCC_SSCGR_INCSTEP (0xFFF << 16)
+#define RCC_SSCGR_MODPER 0xFFFF
+
+/* PLLI2S configuration register */
+
+#define RCC_PLLI2SCFGR_PLLI2SR (0x7 << 28)
+#define RCC_PLLI2SCFGR_PLLI2SN (0x1FF << 6)
+
+/*
+ * Clock sources, domains, and peripheral clock IDs.
+ */
+
+/**
+ * @brief STM32F2 clock sources.
+ */
+typedef enum rcc_clk {
+ RCC_CLK_PLLI2S = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_PLLI2SON_BIT), /**< Dedicated PLL
+ for I2S. */
+ RCC_CLK_PLL = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_PLLON_BIT), /**< Main PLL, clocked by
+ HSI or HSE. */
+ RCC_CLK_HSE = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_HSEON_BIT), /**< High speed external. */
+ RCC_CLK_HSI = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_HSION_BIT), /**< High speed internal. */
+ RCC_CLK_LSE = (uint16)((offsetof(struct rcc_reg_map, BDCR) << 8) |
+ RCC_BDCR_LSEON_BIT), /**< Low-speed external
+ * (32.768 KHz). */
+ RCC_CLK_LSI = (uint16)((offsetof(struct rcc_reg_map, CSR) << 8) |
+ RCC_CSR_LSION_BIT), /**< Low-speed internal
+ * (approximately 32 KHz). */
+} rcc_clk;
+
+/**
+ * @brief STM32F2 rcc_clk_id.
+ */
+typedef enum rcc_clk_id {
+ RCC_ADC1,
+ RCC_ADC2,
+ RCC_ADC3,
+ RCC_BKPSRAM,
+ RCC_CAN1,
+ RCC_CAN2,
+ RCC_CRC,
+ RCC_CRYP,
+ RCC_DAC,
+ RCC_DCMI,
+ RCC_DMA1,
+ RCC_DMA2,
+ RCC_ETHMAC,
+ RCC_ETHMACPTP,
+ RCC_ETHMACRX,
+ RCC_ETHMACTX,
+ RCC_FSMC,
+ RCC_GPIOA,
+ RCC_GPIOB,
+ RCC_GPIOC,
+ RCC_GPIOD,
+ RCC_GPIOE,
+ RCC_GPIOF,
+ RCC_GPIOG,
+ RCC_GPIOH,
+ RCC_GPIOI,
+ RCC_HASH,
+ RCC_I2C1,
+ RCC_I2C2,
+ RCC_I2C3,
+ RCC_OTGFS,
+ RCC_OTGHS,
+ RCC_OTGHSULPI,
+ RCC_PWR,
+ RCC_RNG,
+ RCC_SDIO,
+ RCC_SPI1,
+ RCC_SPI2,
+ RCC_SPI3,
+ RCC_SYSCFG,
+ RCC_TIMER1,
+ RCC_TIMER10,
+ RCC_TIMER11,
+ RCC_TIMER12,
+ RCC_TIMER13,
+ RCC_TIMER14,
+ RCC_TIMER2,
+ RCC_TIMER3,
+ RCC_TIMER4,
+ RCC_TIMER5,
+ RCC_TIMER6,
+ RCC_TIMER7,
+ RCC_TIMER8,
+ RCC_TIMER9,
+ RCC_USART1,
+ RCC_USART2,
+ RCC_USART3,
+ RCC_UART4,
+ RCC_UART5,
+ RCC_USART6,
+ RCC_WWDG,
+} rcc_clk_id;
+
+/**
+ * @brief STM32F2 PLL entry clock source
+ * @see rcc_configure_pll()
+ */
+typedef enum rcc_pllsrc {
+ RCC_PLLSRC_HSI = 0,
+ RCC_PLLSRC_HSE = RCC_PLLCFGR_PLLSRC,
+} rcc_pllsrc;
+
+/**
+ * @brief STM32F2 Peripheral clock domains.
+ */
+typedef enum rcc_clk_domain {
+ RCC_APB1,
+ RCC_APB2,
+ RCC_AHB1,
+ RCC_AHB2,
+ RCC_AHB3,
+} rcc_clk_domain;
+
+/*
+ * Prescalers and dividers.
+ */
+
+/**
+ * @brief STM32F2 Prescaler identifiers.
+ */
+typedef enum rcc_prescaler {
+ RCC_PRESCALER_MCO2,
+ RCC_PRESCALER_MCO1,
+ RCC_PRESCALER_RTC,
+ RCC_PRESCALER_APB2,
+ RCC_PRESCALER_APB1,
+ RCC_PRESCALER_AHB
+} rcc_prescaler;
+
+/**
+ * @brief STM32F2 MCO2 prescaler dividers.
+ */
+typedef enum rcc_mco2_divider {
+ RCC_MCO2_DIV_1 = RCC_CFGR_MCO2PRE_DIV_1,
+ RCC_MCO2_DIV_2 = RCC_CFGR_MCO2PRE_DIV_2,
+ RCC_MCO2_DIV_3 = RCC_CFGR_MCO2PRE_DIV_3,
+ RCC_MCO2_DIV_4 = RCC_CFGR_MCO2PRE_DIV_4,
+ RCC_MCO2_DIV_5 = RCC_CFGR_MCO2PRE_DIV_5,
+} rcc_mco2_divider;
+
+/**
+ * @brief STM32F2 MCO1 prescaler dividers.
+ */
+typedef enum rcc_mco1_divider {
+ RCC_MCO1_DIV_1 = RCC_CFGR_MCO1PRE_DIV_1,
+ RCC_MCO1_DIV_2 = RCC_CFGR_MCO1PRE_DIV_2,
+ RCC_MCO1_DIV_3 = RCC_CFGR_MCO1PRE_DIV_3,
+ RCC_MCO1_DIV_4 = RCC_CFGR_MCO1PRE_DIV_4,
+ RCC_MCO1_DIV_5 = RCC_CFGR_MCO1PRE_DIV_5,
+} rcc_mco1_divider;
+
+/**
+ * @brief STM32F2 RTC prescaler dividers.
+ */
+typedef enum rcc_rtc_divider { /* FIXME [0.0.13] TODO */
+ RCC_RTC_DIV_TODO = 0xFFFFFFFF,
+} rcc_rtc_divider;
+
+/**
+ * @brief STM32F2 AP2 prescaler dividers.
+ */
+typedef enum rcc_apb2_divider {
+ RCC_APB2_HCLK_DIV_1 = 0,
+ RCC_APB2_HCLK_DIV_2 = RCC_CFGR_PPRE2_AHB_DIV_2,
+ RCC_APB2_HCLK_DIV_4 = RCC_CFGR_PPRE2_AHB_DIV_4,
+ RCC_APB2_HCLK_DIV_8 = RCC_CFGR_PPRE2_AHB_DIV_8,
+ RCC_APB2_HCLK_DIV_16 = RCC_CFGR_PPRE2_AHB_DIV_16,
+} rcc_apb2_divider;
+
+/**
+ * @brief STM32F2 APB1 prescaler dividers.
+ */
+typedef enum rcc_apb1_divider {
+ RCC_APB1_HCLK_DIV_1 = 0,
+ RCC_APB1_HCLK_DIV_2 = RCC_CFGR_PPRE1_AHB_DIV_2,
+ RCC_APB1_HCLK_DIV_4 = RCC_CFGR_PPRE1_AHB_DIV_4,
+ RCC_APB1_HCLK_DIV_8 = RCC_CFGR_PPRE1_AHB_DIV_8,
+ RCC_APB1_HCLK_DIV_16 = RCC_CFGR_PPRE1_AHB_DIV_16,
+} rcc_apb1_divider;
+
+/**
+ * @brief STM32F2 AHB prescaler dividers.
+ */
+typedef enum rcc_ahb_divider {
+ RCC_AHB_SYSCLK_DIV_1 = 0,
+ RCC_AHB_SYSCLK_DIV_2 = RCC_CFGR_HPRE_SYSCLK_DIV_2,
+ RCC_AHB_SYSCLK_DIV_4 = RCC_CFGR_HPRE_SYSCLK_DIV_4,
+ RCC_AHB_SYSCLK_DIV_8 = RCC_CFGR_HPRE_SYSCLK_DIV_8,
+ RCC_AHB_SYSCLK_DIV_16 = RCC_CFGR_HPRE_SYSCLK_DIV_16,
+ RCC_AHB_SYSCLK_DIV_64 = RCC_CFGR_HPRE_SYSCLK_DIV_64,
+ RCC_AHB_SYSCLK_DIV_128 = RCC_CFGR_HPRE_SYSCLK_DIV_128,
+ RCC_AHB_SYSCLK_DIV_256 = RCC_CFGR_HPRE_SYSCLK_DIV_256,
+ RCC_AHB_SYSCLK_DIV_512 = RCC_CFGR_HPRE_SYSCLK_DIV_512,
+} rcc_ahb_divider;
+
+/**
+ * @brief STM32F2 PLL configuration values.
+ * Point to one of these with the "data" field in a struct rcc_pll_cfg.
+ * @see struct rcc_pll_cfg.
+ */
+typedef struct stm32f2_rcc_pll_data {
+ uint8 pllq; /**<
+ * @brief PLLQ value.
+ * Allowed values: 4, 5, ..., 15. */
+ uint8 pllp; /**<
+ * @brief PLLP value.
+ * Allowed values: 2, 4, 6, 8. */
+ uint16 plln; /**<
+ * @brief PLLN value.
+ * Allowed values: 192, 193, ..., 432. */
+ uint8 pllm; /**<
+ * @brief PLLM value.
+ * Allowed values: 2, 3, ..., 63. */
+} stm32f2_rcc_pll_data;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/spi.h b/libmaple/stm32f2/include/series/spi.h
new file mode 100644
index 0000000..7b9f94a
--- /dev/null
+++ b/libmaple/stm32f2/include/series/spi.h
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/spi.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 SPI/I2S series header.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_SPI_H_
+#define _LIBMAPLE_STM32F2_SPI_H_
+
+#include <libmaple/gpio.h> /* for gpio_af */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Register map base pointers
+ */
+
+struct spi_reg_map;
+
+#define SPI1_BASE ((struct spi_reg_map*)0x40013000)
+#define SPI2_BASE ((struct spi_reg_map*)0x40003800)
+#define SPI3_BASE ((struct spi_reg_map*)0x40003C00)
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 2 */
+
+#define SPI_CR2_FRF_BIT 4
+
+#define SPI_CR2_FRF (1U << SPI_CR2_FRF_BIT)
+
+/* Status register */
+
+#define SPI_SR_TIFRFE_BIT 8
+
+#define SPI_SR_TIFRFE (1U << SPI_SR_TIFRFE_BIT)
+
+/*
+ * Device pointers
+ */
+
+struct spi_dev;
+
+extern struct spi_dev *SPI1;
+extern struct spi_dev *SPI2;
+extern struct spi_dev *SPI3;
+
+/*
+ * Routines
+ */
+
+gpio_af spi_get_af(struct spi_dev *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/stm32.h b/libmaple/stm32f2/include/series/stm32.h
new file mode 100644
index 0000000..180ab30
--- /dev/null
+++ b/libmaple/stm32f2/include/series/stm32.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/stm32.h
+ * @brief STM32F2 chip- and series-specific definitions.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_STM32_H_
+#define _LIBMAPLE_STM32F2_STM32_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Chip configuration
+ */
+
+#ifndef STM32_PCLK1
+#define STM32_PCLK1 30000000U
+#endif
+
+#ifndef STM32_PCLK2
+#define STM32_PCLK2 60000000U
+#endif
+
+#ifndef STM32_DELAY_US_MULT
+#define STM32_DELAY_US_MULT 20 /* FIXME: dummy value. */
+#endif
+
+/*
+ * Series- and MCU-specific values
+ */
+
+#define STM32_MCU_SERIES STM32_SERIES_F2
+#define STM32_NR_INTERRUPTS 81
+#define STM32_HAVE_FSMC 1
+#define STM32_HAVE_USB 1
+#define STM32_HAVE_DAC 1
+
+#if defined(MCU_STM32F207IC) || defined(MCU_STM32F207IG)
+# define STM32_NR_GPIO_PORTS 9
+# define STM32_TIMER_MASK 0x7FFE /* TIMER1-TIMER14. */
+# define STM32_SRAM_END ((void*)0x20020000)
+#else
+#warning "Unsupported or unspecified STM32F2 MCU."
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/timer.h b/libmaple/stm32f2/include/series/timer.h
new file mode 100644
index 0000000..a7ac276
--- /dev/null
+++ b/libmaple/stm32f2/include/series/timer.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011,2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/timer.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 timer support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_TIMER_H_
+#define _LIBMAPLE_STM32F2_TIMER_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/gpio.h> /* for gpio_af */
+
+/*
+ * Register maps and base pointers
+ */
+
+/**
+ * @brief STM32F2 general purpose timer register map type
+ *
+ * Note that not all general purpose timers have all of these
+ * registers. Consult your chip's reference manual for the details.
+ */
+typedef struct timer_gen_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SMCR; /**< Slave mode control register */
+ __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ __io uint32 CCMR1; /**< Capture/compare mode register 1 */
+ __io uint32 CCMR2; /**< Capture/compare mode register 2 */
+ __io uint32 CCER; /**< Capture/compare enable register */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 CCR1; /**< Capture/compare register 1 */
+ __io uint32 CCR2; /**< Capture/compare register 2 */
+ __io uint32 CCR3; /**< Capture/compare register 3 */
+ __io uint32 CCR4; /**< Capture/compare register 4 */
+ const uint32 RESERVED2; /**< Reserved */
+ __io uint32 DCR; /**< DMA control register */
+ __io uint32 DMAR; /**< DMA address for full transfer */
+ __io uint32 OR; /**< Option register. */
+} timer_gen_reg_map;
+
+struct timer_adv_reg_map;
+struct timer_bas_reg_map;
+
+/** Timer 1 register map base pointer */
+#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000)
+/** Timer 2 register map base pointer */
+#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000)
+/** Timer 3 register map base pointer */
+#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400)
+/** Timer 4 register map base pointer */
+#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800)
+/** Timer 5 register map base pointer */
+#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00)
+/** Timer 6 register map base pointer */
+#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000)
+/** Timer 7 register map base pointer */
+#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400)
+/** Timer 8 register map base pointer */
+#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400)
+/** Timer 9 register map base pointer */
+#define TIMER9_BASE ((struct timer_gen_reg_map*)0x40014000)
+/** Timer 10 register map base pointer */
+#define TIMER10_BASE ((struct timer_gen_reg_map*)0x40014400)
+/** Timer 11 register map base pointer */
+#define TIMER11_BASE ((struct timer_gen_reg_map*)0x40014800)
+/** Timer 12 register map base pointer */
+#define TIMER12_BASE ((struct timer_gen_reg_map*)0x40001800)
+/** Timer 13 register map base pointer */
+#define TIMER13_BASE ((struct timer_gen_reg_map*)0x40001C00)
+/** Timer 14 register map base pointer */
+#define TIMER14_BASE ((struct timer_gen_reg_map*)0x40002000)
+
+/*
+ * Register bit definitions
+ */
+
+/* TIM2 option register */
+
+/** Timer 2 option register internal trigger 1 remap */
+#define TIMER2_OR_ITR1_RMP (0x3 << 10)
+/** Timer 2 OR internal trigger 1: TIM8_TRGOUT */
+#define TIMER2_OR_ITR1_RMP_TIM8_TRGOUT (0x0 << 10)
+/** Timer 2 OR internal trigger 1: Ethernet PTP trigger output */
+#define TIMER2_OR_ITR1_RMP_PTP_TRGOUT (0x1 << 10)
+/** Timer 2 OR internal trigger 1: USB OTG full speed start of frame */
+#define TIMER2_OR_ITR1_RMP_OTG_FS_SOF (0x2 << 10)
+/** Timer 2 OR internal trigger 1: USB OTG high speed start of frame */
+#define TIMER2_OR_ITR1_RMP_OTG_HS_SOF (0x3 << 10)
+
+/* TIM5 option register */
+
+/**
+ * Timer 5 option register input 4 remap.
+ *
+ * These bits control whether TIM5_CH4 is connected to a GPIO or a
+ * clock. Connecting to a GPIO is the normal mode, useful for e.g. PWM
+ * generation or input pulse duration measurement. Connecting to a
+ * clock is useful for calibrating that clock.
+ */
+#define TIMER5_OR_TI4_RMP (0x3 << 6)
+/**
+ * Timer 5 OR input 4: Timer 5 channel 4 connected to GPIO. */
+#define TIMER5_OR_TI4_RMP_GPIO (0x0 << 6)
+/**
+ * Timer 5 OR input 4: low speed internal clock (LSI) is connected to
+ * TIM5_CH4. */
+#define TIMER5_OR_TI4_RMP_LSI (0x1 << 6)
+/**
+ * Timer 5 OR input 4: low speed external clock (LSE) is connected to
+ * TIM5_CH4. */
+#define TIMER5_OR_TI4_RMP_LSE (0x2 << 6)
+/**
+ * Timer 5 OR input 4: real time clock (RTC) output is connected to
+ * TIM5_CH4. */
+#define TIMER5_OR_TI4_RMP_RTC (0x3 << 6)
+
+/*
+ * Device pointers
+ */
+
+struct timer_dev;
+
+extern struct timer_dev *TIMER1;
+extern struct timer_dev *TIMER2;
+extern struct timer_dev *TIMER3;
+extern struct timer_dev *TIMER4;
+extern struct timer_dev *TIMER5;
+extern struct timer_dev *TIMER6;
+extern struct timer_dev *TIMER7;
+extern struct timer_dev *TIMER8;
+extern struct timer_dev *TIMER9;
+extern struct timer_dev *TIMER10;
+extern struct timer_dev *TIMER11;
+extern struct timer_dev *TIMER12;
+extern struct timer_dev *TIMER13;
+extern struct timer_dev *TIMER14;
+
+/*
+ * Routines
+ */
+
+gpio_af timer_get_af(struct timer_dev *dev);
+
+#endif
diff --git a/libmaple/stm32f2/include/series/usart.h b/libmaple/stm32f2/include/series/usart.h
new file mode 100644
index 0000000..8936efa
--- /dev/null
+++ b/libmaple/stm32f2/include/series/usart.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/include/series/usart.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 USART support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_USART_H_
+#define _LIBMAPLE_STM32F2_USART_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/gpio.h> /* for gpio_af */
+
+/*
+ * Register map base pointers.
+ */
+
+struct usart_reg_map;
+
+/** USART1 register map base pointer */
+#define USART1_BASE ((struct usart_reg_map*)0x40011000)
+/** USART2 register map base pointer */
+#define USART2_BASE ((struct usart_reg_map*)0x40004400)
+/** USART3 register map base pointer */
+#define USART3_BASE ((struct usart_reg_map*)0x40004800)
+/** UART4 register map base pointer */
+#define UART4_BASE ((struct usart_reg_map*)0x40004C00)
+/** UART5 register map base pointer */
+#define UART5_BASE ((struct usart_reg_map*)0x40005000)
+/** USART6 register map base pointer */
+#define USART6_BASE ((struct usart_reg_map*)0x40011400)
+
+/*
+ * F2-only register bit definitions.
+ */
+
+/* Control register 1 */
+
+/**
+ * @brief Oversampling mode bit.
+ * Availability: STM32F2. */
+#define USART_CR1_OVER8_BIT 15
+
+/**
+ * @brief Oversampling mode.
+ * Availability: STM32F2. */
+#define USART_CR1_OVER8 (1U << USART_CR1_OVER8_BIT)
+
+/* Control register 3 */
+
+/** One sample bit method enable bit. */
+#define USART_CR3_ONEBIT_BIT 11
+
+/** One bit sample method enable. */
+#define USART_CR3_ONEBIT (1 << USART_CR3_ONEBIT_BIT)
+/** Sample method: Three sample bit method. */
+#define USART_CR3_ONEBIT_3SAMPLE (0 << USART_CR3_ONEBIT_BIT)
+/** Sample method: One sample bit method. */
+#define USART_CR3_ONEBIT_1SAMPLE (1 << USART_CR3_ONEBIT_BIT)
+
+/*
+ * Devices
+ */
+
+struct usart_dev;
+extern struct usart_dev *USART1;
+extern struct usart_dev *USART2;
+extern struct usart_dev *USART3;
+extern struct usart_dev *UART4;
+extern struct usart_dev *UART5;
+extern struct usart_dev *USART6;
+
+/*
+ * Routines
+ */
+
+gpio_af usart_get_af(struct usart_dev *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/isrs.S b/libmaple/stm32f2/isrs.S
new file mode 100644
index 0000000..5baaf8b
--- /dev/null
+++ b/libmaple/stm32f2/isrs.S
@@ -0,0 +1,322 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/* STM32F2 ISR weak declarations */
+
+ .thumb
+
+/* Default handler, as with STM32F1 */
+ .globl __default_handler
+ .type __default_handler, %function
+
+__default_handler:
+ b .
+
+ .weak __exc_nmi
+ .globl __exc_nmi
+ .set __exc_nmi, __default_handler
+ .weak __exc_hardfault
+ .globl __exc_hardfault
+ .set __exc_hardfault, __default_handler
+ .weak __exc_memmanage
+ .globl __exc_memmanage
+ .set __exc_memmanage, __default_handler
+ .weak __exc_busfault
+ .globl __exc_busfault
+ .set __exc_busfault, __default_handler
+ .weak __exc_usagefault
+ .globl __exc_usagefault
+ .set __exc_usagefault, __default_handler
+ .weak __stm32reservedexception7
+ .globl __stm32reservedexception7
+ .set __stm32reservedexception7, __default_handler
+ .weak __stm32reservedexception8
+ .globl __stm32reservedexception8
+ .set __stm32reservedexception8, __default_handler
+ .weak __stm32reservedexception9
+ .globl __stm32reservedexception9
+ .set __stm32reservedexception9, __default_handler
+ .weak __stm32reservedexception10
+ .globl __stm32reservedexception10
+ .set __stm32reservedexception10, __default_handler
+ .weak __exc_svc
+ .globl __exc_svc
+ .set __exc_svc, __default_handler
+ .weak __exc_debug_monitor
+ .globl __exc_debug_monitor
+ .set __exc_debug_monitor, __default_handler
+ .weak __stm32reservedexception13
+ .globl __stm32reservedexception13
+ .set __stm32reservedexception13, __default_handler
+ .weak __exc_pendsv
+ .globl __exc_pendsv
+ .set __exc_pendsv, __default_handler
+ .weak __exc_systick
+ .globl __exc_systick
+ .set __exc_systick, __default_handler
+ .weak __irq_wwdg
+ .globl __irq_wwdg
+ .set __irq_wwdg, __default_handler
+ .weak __irq_pvd
+ .globl __irq_pvd
+ .set __irq_pvd, __default_handler
+ .weak __irq_tamp_stamp
+ .globl __irq_tamp_stamp
+ .set __irq_tamp_stamp, __default_handler
+ .weak __irq_rtc_wkup
+ .globl __irq_rtc_wkup
+ .set __irq_rtc_wkup, __default_handler
+ .weak __irq_flash
+ .globl __irq_flash
+ .set __irq_flash, __default_handler
+ .weak __irq_rcc
+ .globl __irq_rcc
+ .set __irq_rcc, __default_handler
+ .weak __irq_exti0
+ .globl __irq_exti0
+ .set __irq_exti0, __default_handler
+ .weak __irq_exti1
+ .globl __irq_exti1
+ .set __irq_exti1, __default_handler
+ .weak __irq_exti2
+ .globl __irq_exti2
+ .set __irq_exti2, __default_handler
+ .weak __irq_exti3
+ .globl __irq_exti3
+ .set __irq_exti3, __default_handler
+ .weak __irq_exti4
+ .globl __irq_exti4
+ .set __irq_exti4, __default_handler
+ .weak __irq_dma1_stream0
+ .globl __irq_dma1_stream0
+ .set __irq_dma1_stream0, __default_handler
+ .weak __irq_dma1_stream1
+ .globl __irq_dma1_stream1
+ .set __irq_dma1_stream1, __default_handler
+ .weak __irq_dma1_stream2
+ .globl __irq_dma1_stream2
+ .set __irq_dma1_stream2, __default_handler
+ .weak __irq_dma1_stream3
+ .globl __irq_dma1_stream3
+ .set __irq_dma1_stream3, __default_handler
+ .weak __irq_dma1_stream4
+ .globl __irq_dma1_stream4
+ .set __irq_dma1_stream4, __default_handler
+ .weak __irq_dma1_stream5
+ .globl __irq_dma1_stream5
+ .set __irq_dma1_stream5, __default_handler
+ .weak __irq_dma1_stream6
+ .globl __irq_dma1_stream6
+ .set __irq_dma1_stream6, __default_handler
+ .weak __irq_adc
+ .globl __irq_adc
+ .set __irq_adc, __default_handler
+ .weak __irq_can1_tx
+ .globl __irq_can1_tx
+ .set __irq_can1_tx, __default_handler
+ .weak __irq_can1_rx0
+ .globl __irq_can1_rx0
+ .set __irq_can1_rx0, __default_handler
+ .weak __irq_can1_rx1
+ .globl __irq_can1_rx1
+ .set __irq_can1_rx1, __default_handler
+ .weak __irq_can1_sce
+ .globl __irq_can1_sce
+ .set __irq_can1_sce, __default_handler
+ .weak __irq_exti9_5
+ .globl __irq_exti9_5
+ .set __irq_exti9_5, __default_handler
+ .weak __irq_tim1_brk_tim9
+ .globl __irq_tim1_brk_tim9
+ .set __irq_tim1_brk_tim9, __default_handler
+ .weak __irq_tim1_up_tim10
+ .globl __irq_tim1_up_tim10
+ .set __irq_tim1_up_tim10, __default_handler
+ .weak __irq_tim1_trg_com_tim11
+ .globl __irq_tim1_trg_com_tim11
+ .set __irq_tim1_trg_com_tim11, __default_handler
+ .weak __irq_tim1_cc
+ .globl __irq_tim1_cc
+ .set __irq_tim1_cc, __default_handler
+ .weak __irq_tim2
+ .globl __irq_tim2
+ .set __irq_tim2, __default_handler
+ .weak __irq_tim3
+ .globl __irq_tim3
+ .set __irq_tim3, __default_handler
+ .weak __irq_tim4
+ .globl __irq_tim4
+ .set __irq_tim4, __default_handler
+ .weak __irq_i2c1_ev
+ .globl __irq_i2c1_ev
+ .set __irq_i2c1_ev, __default_handler
+ .weak __irq_i2c1_er
+ .globl __irq_i2c1_er
+ .set __irq_i2c1_er, __default_handler
+ .weak __irq_i2c2_ev
+ .globl __irq_i2c2_ev
+ .set __irq_i2c2_ev, __default_handler
+ .weak __irq_i2c2_er
+ .globl __irq_i2c2_er
+ .set __irq_i2c2_er, __default_handler
+ .weak __irq_spi1
+ .globl __irq_spi1
+ .set __irq_spi1, __default_handler
+ .weak __irq_spi2
+ .globl __irq_spi2
+ .set __irq_spi2, __default_handler
+ .weak __irq_usart1
+ .globl __irq_usart1
+ .set __irq_usart1, __default_handler
+ .weak __irq_usart2
+ .globl __irq_usart2
+ .set __irq_usart2, __default_handler
+ .weak __irq_usart3
+ .globl __irq_usart3
+ .set __irq_usart3, __default_handler
+ .weak __irq_exti15_10
+ .globl __irq_exti15_10
+ .set __irq_exti15_10, __default_handler
+ .weak __irq_rtc_alarm
+ .globl __irq_rtc_alarm
+ .set __irq_rtc_alarm, __default_handler
+ .weak __irq_otg_fs_wkup
+ .globl __irq_otg_fs_wkup
+ .set __irq_otg_fs_wkup, __default_handler
+ .weak __irq_tim8_brk_tim12
+ .globl __irq_tim8_brk_tim12
+ .set __irq_tim8_brk_tim12, __default_handler
+ .weak __irq_tim8_up_tim13
+ .globl __irq_tim8_up_tim13
+ .set __irq_tim8_up_tim13, __default_handler
+ .weak __irq_tim8_trg_com_tim14
+ .globl __irq_tim8_trg_com_tim14
+ .set __irq_tim8_trg_com_tim14, __default_handler
+ .weak __irq_tim8_cc
+ .globl __irq_tim8_cc
+ .set __irq_tim8_cc, __default_handler
+ .weak __irq_dma1_stream7
+ .globl __irq_dma1_stream7
+ .set __irq_dma1_stream7, __default_handler
+ .weak __irq_fsmc
+ .globl __irq_fsmc
+ .set __irq_fsmc, __default_handler
+ .weak __irq_sdio
+ .globl __irq_sdio
+ .set __irq_sdio, __default_handler
+ .weak __irq_tim5
+ .globl __irq_tim5
+ .set __irq_tim5, __default_handler
+ .weak __irq_spi3
+ .globl __irq_spi3
+ .set __irq_spi3, __default_handler
+ .weak __irq_uart4
+ .globl __irq_uart4
+ .set __irq_uart4, __default_handler
+ .weak __irq_uart5
+ .globl __irq_uart5
+ .set __irq_uart5, __default_handler
+ .weak __irq_tim6_dac
+ .globl __irq_tim6_dac
+ .set __irq_tim6_dac, __default_handler
+ .weak __irq_tim7
+ .globl __irq_tim7
+ .set __irq_tim7, __default_handler
+ .weak __irq_dma2_stream0
+ .globl __irq_dma2_stream0
+ .set __irq_dma2_stream0, __default_handler
+ .weak __irq_dma2_stream1
+ .globl __irq_dma2_stream1
+ .set __irq_dma2_stream1, __default_handler
+ .weak __irq_dma2_stream2
+ .globl __irq_dma2_stream2
+ .set __irq_dma2_stream2, __default_handler
+ .weak __irq_dma2_stream3
+ .globl __irq_dma2_stream3
+ .set __irq_dma2_stream3, __default_handler
+ .weak __irq_dma2_stream4
+ .globl __irq_dma2_stream4
+ .set __irq_dma2_stream4, __default_handler
+ .weak __irq_eth
+ .globl __irq_eth
+ .set __irq_eth, __default_handler
+ .weak __irq_eth_wkup
+ .globl __irq_eth_wkup
+ .set __irq_eth_wkup, __default_handler
+ .weak __irq_can2_tx
+ .globl __irq_can2_tx
+ .set __irq_can2_tx, __default_handler
+ .weak __irq_can2_rx0
+ .globl __irq_can2_rx0
+ .set __irq_can2_rx0, __default_handler
+ .weak __irq_can2_rx1
+ .globl __irq_can2_rx1
+ .set __irq_can2_rx1, __default_handler
+ .weak __irq_can2_sce
+ .globl __irq_can2_sce
+ .set __irq_can2_sce, __default_handler
+ .weak __irq_otg_fs
+ .globl __irq_otg_fs
+ .set __irq_otg_fs, __default_handler
+ .weak __irq_dma2_stream5
+ .globl __irq_dma2_stream5
+ .set __irq_dma2_stream5, __default_handler
+ .weak __irq_dma2_stream6
+ .globl __irq_dma2_stream6
+ .set __irq_dma2_stream6, __default_handler
+ .weak __irq_dma2_stream7
+ .globl __irq_dma2_stream7
+ .set __irq_dma2_stream7, __default_handler
+ .weak __irq_usart6
+ .globl __irq_usart6
+ .set __irq_usart6, __default_handler
+ .weak __irq_i2c3_ev
+ .globl __irq_i2c3_ev
+ .set __irq_i2c3_ev, __default_handler
+ .weak __irq_i2c3_er
+ .globl __irq_i2c3_er
+ .set __irq_i2c3_er, __default_handler
+ .weak __irq_otg_hs_ep1_out
+ .globl __irq_otg_hs_ep1_out
+ .set __irq_otg_hs_ep1_out, __default_handler
+ .weak __irq_otg_hs_ep1_in
+ .globl __irq_otg_hs_ep1_in
+ .set __irq_otg_hs_ep1_in, __default_handler
+ .weak __irq_otg_hs_wkup
+ .globl __irq_otg_hs_wkup
+ .set __irq_otg_hs_wkup, __default_handler
+ .weak __irq_otg_hs
+ .globl __irq_otg_hs
+ .set __irq_otg_hs, __default_handler
+ .weak __irq_dcmi
+ .globl __irq_dcmi
+ .set __irq_dcmi, __default_handler
+ .weak __irq_cryp
+ .globl __irq_cryp
+ .set __irq_cryp, __default_handler
+ .weak __irq_hash_rng
+ .globl __irq_hash_rng
+ .set __irq_hash_rng, __default_handler
diff --git a/libmaple/stm32f2/rcc.c b/libmaple/stm32f2/rcc.c
new file mode 100644
index 0000000..7fc7eb0
--- /dev/null
+++ b/libmaple/stm32f2/rcc.c
@@ -0,0 +1,175 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/rcc.c
+ * @brief STM32F2 RCC.
+ */
+
+#include <libmaple/rcc.h>
+#include <libmaple/libmaple.h>
+
+#include "rcc_private.h"
+
+#define DEV_ENTRY(domain, dev) \
+ {.clk_domain = RCC_##domain, .line_num = RCC_##domain##ENR_##dev##EN_BIT}
+
+const struct rcc_dev_info rcc_dev_table[] = {
+ /* AHB1 */
+ [RCC_OTGHSULPI] = DEV_ENTRY(AHB1, OTGHSULPI),
+ [RCC_OTGHS] = DEV_ENTRY(AHB1, OTGHS),
+ [RCC_ETHMACPTP] = DEV_ENTRY(AHB1, ETHMACPTP),
+ [RCC_ETHMACRX] = DEV_ENTRY(AHB1, ETHMACRX),
+ [RCC_ETHMACTX] = DEV_ENTRY(AHB1, ETHMACTX),
+ [RCC_ETHMAC] = DEV_ENTRY(AHB1, ETHMAC),
+ [RCC_DMA2] = DEV_ENTRY(AHB1, DMA2),
+ [RCC_DMA1] = DEV_ENTRY(AHB1, DMA1),
+ [RCC_BKPSRAM] = DEV_ENTRY(AHB1, BKPSRAM),
+ [RCC_CRC] = DEV_ENTRY(AHB1, CRC),
+ [RCC_GPIOI] = DEV_ENTRY(AHB1, GPIOI),
+ [RCC_GPIOH] = DEV_ENTRY(AHB1, GPIOH),
+ [RCC_GPIOG] = DEV_ENTRY(AHB1, GPIOG),
+ [RCC_GPIOF] = DEV_ENTRY(AHB1, GPIOF),
+ [RCC_GPIOE] = DEV_ENTRY(AHB1, GPIOE),
+ [RCC_GPIOD] = DEV_ENTRY(AHB1, GPIOD),
+ [RCC_GPIOC] = DEV_ENTRY(AHB1, GPIOC),
+ [RCC_GPIOB] = DEV_ENTRY(AHB1, GPIOB),
+ [RCC_GPIOA] = DEV_ENTRY(AHB1, GPIOA),
+
+ /* AHB2 */
+ [RCC_OTGFS] = DEV_ENTRY(AHB2, OTGFS),
+ [RCC_RNG] = DEV_ENTRY(AHB2, RNG),
+ [RCC_HASH] = DEV_ENTRY(AHB2, HASH),
+ [RCC_CRYP] = DEV_ENTRY(AHB2, CRYP),
+ [RCC_DCMI] = DEV_ENTRY(AHB2, DCMI),
+
+ /* AHB3 */
+ [RCC_FSMC] = DEV_ENTRY(AHB3, FSMC),
+
+ /* APB1 */
+ [RCC_DAC] = DEV_ENTRY(APB1, DAC),
+ [RCC_PWR] = DEV_ENTRY(APB1, PWR),
+ [RCC_CAN2] = DEV_ENTRY(APB1, CAN2),
+ [RCC_CAN1] = DEV_ENTRY(APB1, CAN1),
+ [RCC_I2C3] = DEV_ENTRY(APB1, I2C3),
+ [RCC_I2C2] = DEV_ENTRY(APB1, I2C2),
+ [RCC_I2C1] = DEV_ENTRY(APB1, I2C1),
+ [RCC_UART5] = DEV_ENTRY(APB1, UART5),
+ [RCC_UART4] = DEV_ENTRY(APB1, UART4),
+ [RCC_USART3] = DEV_ENTRY(APB1, USART3),
+ [RCC_USART2] = DEV_ENTRY(APB1, USART2),
+ [RCC_SPI3] = DEV_ENTRY(APB1, SPI3),
+ [RCC_SPI2] = DEV_ENTRY(APB1, SPI2),
+ [RCC_WWDG] = DEV_ENTRY(APB1, WWDG),
+ [RCC_TIMER14] = DEV_ENTRY(APB1, TIM14),
+ [RCC_TIMER13] = DEV_ENTRY(APB1, TIM13),
+ [RCC_TIMER12] = DEV_ENTRY(APB1, TIM12),
+ [RCC_TIMER7] = DEV_ENTRY(APB1, TIM7),
+ [RCC_TIMER6] = DEV_ENTRY(APB1, TIM6),
+ [RCC_TIMER5] = DEV_ENTRY(APB1, TIM5),
+ [RCC_TIMER4] = DEV_ENTRY(APB1, TIM4),
+ [RCC_TIMER3] = DEV_ENTRY(APB1, TIM3),
+ [RCC_TIMER2] = DEV_ENTRY(APB1, TIM2),
+
+ /* APB2 */
+ [RCC_TIMER11] = DEV_ENTRY(APB2, TIM11),
+ [RCC_TIMER10] = DEV_ENTRY(APB2, TIM10),
+ [RCC_TIMER9] = DEV_ENTRY(APB2, TIM9),
+ [RCC_SYSCFG] = DEV_ENTRY(APB2, SYSCFG),
+ [RCC_SPI1] = DEV_ENTRY(APB2, SPI1),
+ [RCC_SDIO] = DEV_ENTRY(APB2, SDIO),
+ [RCC_ADC3] = DEV_ENTRY(APB2, ADC3),
+ [RCC_ADC2] = DEV_ENTRY(APB2, ADC2),
+ [RCC_ADC1] = DEV_ENTRY(APB2, ADC1),
+ [RCC_USART6] = DEV_ENTRY(APB2, USART6),
+ [RCC_USART1] = DEV_ENTRY(APB2, USART1),
+ [RCC_TIMER8] = DEV_ENTRY(APB2, TIM8),
+ [RCC_TIMER1] = DEV_ENTRY(APB2, TIM1),
+};
+
+void rcc_clk_enable(rcc_clk_id id) {
+ static __io uint32* enable_regs[] = {
+ [RCC_AHB1] = &RCC_BASE->AHB1ENR,
+ [RCC_AHB2] = &RCC_BASE->AHB2ENR,
+ [RCC_AHB3] = &RCC_BASE->AHB3ENR,
+ [RCC_APB1] = &RCC_BASE->APB1ENR,
+ [RCC_APB2] = &RCC_BASE->APB2ENR,
+ };
+ rcc_do_clk_enable(enable_regs, id);
+}
+
+void rcc_reset_dev(rcc_clk_id id) {
+ static __io uint32* reset_regs[] = {
+ [RCC_AHB1] = &RCC_BASE->AHB1RSTR,
+ [RCC_AHB2] = &RCC_BASE->AHB2RSTR,
+ [RCC_AHB3] = &RCC_BASE->AHB3RSTR,
+ [RCC_APB1] = &RCC_BASE->AHB3RSTR,
+ [RCC_APB2] = &RCC_BASE->AHB3RSTR,
+ };
+ rcc_do_reset_dev(reset_regs, id);
+}
+
+void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) {
+ static const uint32 masks[] = {
+ [RCC_PRESCALER_MCO2] = RCC_CFGR_MCO2PRE,
+ [RCC_PRESCALER_MCO1] = RCC_CFGR_MCO1PRE,
+ [RCC_PRESCALER_RTC] = RCC_CFGR_RTCPRE,
+ [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2,
+ [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1,
+ [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE,
+ };
+ rcc_do_set_prescaler(masks, prescaler, divider);
+}
+
+/* pll_cfg->data must point to a struct stm32f2_rcc_pll_data. */
+void rcc_configure_pll(rcc_pll_cfg *pll_cfg) {
+ stm32f2_rcc_pll_data *data = pll_cfg->data;
+ uint32 pllcfgr;
+
+ /* Check that the PLL is disabled. */
+ ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL));
+
+ /* Sanity-check all the parameters */
+ ASSERT_FAULT((data->pllq >= 4) && (data->pllq <= 15));
+ ASSERT_FAULT((data->pllp >= 2) && (data->pllp <= 8));
+ ASSERT_FAULT(!(data->pllp & 1));
+ ASSERT_FAULT((data->plln >= 192) && (data->plln <= 432));
+ ASSERT_FAULT((data->pllm >= 2) && (data->pllm <= 63));
+
+ /* Update RCC_PLLCFGR to reflect new values. */
+ pllcfgr = RCC_BASE->PLLCFGR;
+ pllcfgr &= ~(RCC_PLLCFGR_PLLQ |
+ RCC_PLLCFGR_PLLP |
+ RCC_PLLCFGR_PLLN |
+ RCC_PLLCFGR_PLLM |
+ RCC_PLLCFGR_PLLSRC);
+ pllcfgr |= (pll_cfg->pllsrc |
+ (data->pllq << 24) |
+ (((data->pllp >> 1) - 1) << 16) |
+ (data->plln << 6) |
+ data->pllm);
+ RCC_BASE->PLLCFGR = pllcfgr;
+}
diff --git a/libmaple/stm32f2/rules.mk b/libmaple/stm32f2/rules.mk
new file mode 100644
index 0000000..4c62cc2
--- /dev/null
+++ b/libmaple/stm32f2/rules.mk
@@ -0,0 +1,40 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) $(LIBMAPLE_PRIVATE_INCLUDES) -Wall -Werror
+
+# Local rules and targets
+sSRCS_$(d) := isrs.S
+sSRCS_$(d) += vector_table.S
+
+cSRCS_$(d) := adc.c
+cSRCS_$(d) += dma.c
+cSRCS_$(d) += exti.c
+cSRCS_$(d) += fsmc.c
+cSRCS_$(d) += gpio.c
+cSRCS_$(d) += rcc.c
+cSRCS_$(d) += spi.c
+cSRCS_$(d) += syscfg.c
+cSRCS_$(d) += timer.c
+cSRCS_$(d) += usart.c
+
+sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
+ $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_ASFLAGS :=
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp))
diff --git a/libmaple/stm32f2/spi.c b/libmaple/stm32f2/spi.c
new file mode 100644
index 0000000..cfd9995
--- /dev/null
+++ b/libmaple/stm32f2/spi.c
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/spi.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 SPI/I2S.
+ */
+
+#include <libmaple/spi.h>
+#include "spi_private.h"
+
+/*
+ * Devices
+ */
+
+static spi_dev spi1 = SPI_DEV(1);
+static spi_dev spi2 = SPI_DEV(2);
+static spi_dev spi3 = SPI_DEV(3);
+
+spi_dev *SPI1 = &spi1;
+spi_dev *SPI2 = &spi2;
+spi_dev *SPI3 = &spi3;
+
+/*
+ * Routines
+ */
+
+void spi_config_gpios(spi_dev *dev,
+ uint8 as_master,
+ gpio_dev *nss_dev,
+ uint8 nss_bit,
+ gpio_dev *comm_dev,
+ uint8 sck_bit,
+ uint8 miso_bit,
+ uint8 mosi_bit) {
+ gpio_af dev_af = spi_get_af(dev);
+ gpio_set_mode(nss_dev, nss_bit, GPIO_MODE_AF);
+ gpio_set_mode(comm_dev, sck_bit, GPIO_MODE_AF);
+ gpio_set_mode(comm_dev, miso_bit, GPIO_MODE_AF);
+ gpio_set_mode(comm_dev, mosi_bit, GPIO_MODE_AF);
+ gpio_set_af(nss_dev, nss_bit, dev_af);
+ gpio_set_af(comm_dev, sck_bit, dev_af);
+ gpio_set_af(comm_dev, miso_bit, dev_af);
+ gpio_set_af(comm_dev, mosi_bit, dev_af);
+}
+
+void spi_foreach(void (*fn)(spi_dev*)) {
+ fn(SPI1);
+ fn(SPI2);
+ fn(SPI3);
+}
+
+gpio_af spi_get_af(spi_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_SPI1: /* Fall through */
+ case RCC_SPI2:
+ return GPIO_AF_SPI_1_2;
+ case RCC_SPI3:
+ return GPIO_AF_SPI3;
+ default:
+ ASSERT(0); /* Can't happen */
+ return (gpio_af)-1;
+ }
+}
diff --git a/libmaple/stm32f2/syscfg.c b/libmaple/stm32f2/syscfg.c
new file mode 100644
index 0000000..19e932e
--- /dev/null
+++ b/libmaple/stm32f2/syscfg.c
@@ -0,0 +1,78 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/syscfg.c
+ * @brief SYSCFG routines.
+ */
+
+#include <libmaple/syscfg.h>
+#include <libmaple/bitband.h>
+#include <libmaple/rcc.h>
+
+/**
+ * @brief Initialize the SYSCFG peripheral.
+ */
+void syscfg_init(void) {
+ rcc_clk_enable(RCC_SYSCFG);
+ rcc_reset_dev(RCC_SYSCFG);
+}
+
+/**
+ * @brief Turn on the I/O compensation cell.
+ *
+ * It's only safe to do this when the supply voltage is between 2.4 V
+ * and 3.6 V.
+ */
+void syscfg_enable_io_compensation(void) {
+ bb_peri_set_bit(&SYSCFG_BASE->CMPCR, SYSCFG_CMPCR_CMP_PD_BIT, 1);
+ while (!(SYSCFG_BASE->CMPCR & SYSCFG_CMPCR_READY))
+ ;
+}
+
+/**
+ * @brief Turn off the I/O compensation cell.
+ */
+void syscfg_disable_io_compensation(void) {
+ bb_peri_set_bit(&SYSCFG_BASE->CMPCR, SYSCFG_CMPCR_CMP_PD_BIT, 0);
+}
+
+/**
+ * @brief Set the memory to be mapped at address 0x00000000.
+ *
+ * This function can be used to override the BOOT pin
+ * configuration. Some restrictions apply; see your chip's reference
+ * manual for the details.
+ *
+ * @param mode Mode to set
+ * @see syscfg_mem_mode
+ */
+void syscfg_set_mem_mode(syscfg_mem_mode mode) {
+ uint32 memrmp = SYSCFG_BASE->MEMRMP;
+ memrmp &= ~SYSCFG_MEMRMP_MEM_MODE;
+ memrmp |= (uint32)mode;
+ SYSCFG_BASE->MEMRMP = memrmp;
+}
diff --git a/libmaple/stm32f2/timer.c b/libmaple/stm32f2/timer.c
new file mode 100644
index 0000000..a85bea0
--- /dev/null
+++ b/libmaple/stm32f2/timer.c
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/timer.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 timers.
+ */
+
+#include <libmaple/timer.h>
+#include "timer_private.h"
+
+/*
+ * Routines
+ */
+
+/**
+ * @brief Get the GPIO alternate function corresponding to a timer.
+ *
+ * For example, if dev is TIMER1, this function returns
+ * GPIO_AF_TIM_1_2. This is useful for e.g. using gpio_set_af() to set
+ * a pin's alternate function to a timer.
+ *
+ * @param dev Timer device, must not be TIMER6 or TIMER7.
+ * @return gpio_af corresponding to dev
+ * @see gpio_set_af
+ * @see gpio_af
+ */
+gpio_af timer_get_af(timer_dev *dev) {
+ rcc_clk_id clk_id = dev->clk_id;
+ /* Timers 6 and 7 don't have any capture/compare, so they can't do
+ * PWM (and in fact have no AF values). */
+ ASSERT(clk_id != RCC_TIMER6 && clk_id != RCC_TIMER7);
+ switch(dev->clk_id) {
+ case RCC_TIMER1: // fall-through
+ case RCC_TIMER2:
+ return GPIO_AF_TIM_1_2;
+ case RCC_TIMER3: // fall-through
+ case RCC_TIMER4: // ...
+ case RCC_TIMER5:
+ return GPIO_AF_TIM_3_4_5;
+ case RCC_TIMER8: // fall-through
+ case RCC_TIMER9: // ...
+ case RCC_TIMER10: // ...
+ case RCC_TIMER11:
+ return GPIO_AF_TIM_8_9_10_11;
+ case RCC_TIMER12: // fall-through
+ case RCC_TIMER13: // ...
+ case RCC_TIMER14:
+ return GPIO_AF_CAN_1_2_TIM_12_13_14;
+ default:
+ ASSERT(0); // Can't happen
+ return (gpio_af)-1;
+ }
+}
+
+/*
+ * IRQ handlers
+ *
+ * Defer to the timer_private dispatch API.
+ */
+
+void __irq_tim1_brk_tim9(void) {
+ dispatch_adv_brk(TIMER1);
+ dispatch_tim_9_12(TIMER9);
+}
+
+void __irq_tim1_up_tim10(void) {
+ dispatch_adv_up(TIMER1);
+ dispatch_tim_10_11_13_14(TIMER10);
+}
+
+void __irq_tim1_trg_com_tim11(void) {
+ dispatch_adv_trg_com(TIMER1);
+ dispatch_tim_10_11_13_14(TIMER11);
+}
+
+void __irq_tim1_cc(void) {
+ dispatch_adv_cc(TIMER1);
+}
+
+void __irq_tim2(void) {
+ dispatch_general(TIMER2);
+}
+
+void __irq_tim3(void) {
+ dispatch_general(TIMER3);
+}
+
+void __irq_tim4(void) {
+ dispatch_general(TIMER4);
+}
+
+void __irq_tim5(void) {
+ dispatch_general(TIMER5);
+}
+
+/* FIXME: this is also the DAC DMA underrun interrupt, so it needs a
+ * different name (and to be supported?). */
+void __irq_tim6(void) {
+ dispatch_basic(TIMER6);
+}
+
+void __irq_tim7(void) {
+ dispatch_basic(TIMER7);
+}
+
+void __irq_tim8_brk_tim12(void) {
+ dispatch_adv_brk(TIMER8);
+ dispatch_tim_9_12(TIMER12);
+}
+
+void __irq_tim8_up_tim13(void) {
+ dispatch_adv_up(TIMER8);
+ dispatch_tim_10_11_13_14(TIMER13);
+}
+
+void __irq_tim8_trg_com_tim14(void) {
+ dispatch_adv_trg_com(TIMER8);
+ dispatch_tim_10_11_13_14(TIMER14);
+}
+
+void __irq_tim8_cc(void) {
+ dispatch_adv_cc(TIMER8);
+}
diff --git a/libmaple/stm32f2/usart.c b/libmaple/stm32f2/usart.c
new file mode 100644
index 0000000..1472d13
--- /dev/null
+++ b/libmaple/stm32f2/usart.c
@@ -0,0 +1,204 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/stm32f2/usart.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 USART.
+ */
+
+#include <libmaple/usart.h>
+#include <libmaple/gpio.h>
+#include "usart_private.h"
+
+/*
+ * Devices
+ */
+
+static ring_buffer usart1_rb;
+static usart_dev usart1 = {
+ .regs = USART1_BASE,
+ .rb = &usart1_rb,
+ .max_baud = 4500000UL, /* TODO: are these correct? */
+ .clk_id = RCC_USART1,
+ .irq_num = NVIC_USART1,
+};
+/** USART1 device */
+usart_dev *USART1 = &usart1;
+
+static ring_buffer usart2_rb;
+static usart_dev usart2 = {
+ .regs = USART2_BASE,
+ .rb = &usart2_rb,
+ .max_baud = 2250000UL, /* TODO: are these correct? */
+ .clk_id = RCC_USART2,
+ .irq_num = NVIC_USART2,
+};
+/** USART2 device */
+usart_dev *USART2 = &usart2;
+
+static ring_buffer usart3_rb;
+static usart_dev usart3 = {
+ .regs = USART3_BASE,
+ .rb = &usart3_rb,
+ .max_baud = 2250000UL, /* TODO: are these correct? */
+ .clk_id = RCC_USART3,
+ .irq_num = NVIC_USART3,
+};
+/** USART3 device */
+usart_dev *USART3 = &usart3;
+
+static ring_buffer uart4_rb;
+static usart_dev uart4 = {
+ .regs = UART4_BASE,
+ .rb = &uart4_rb,
+ .max_baud = 2250000UL, /* TODO: are these correct? */
+ .clk_id = RCC_UART4,
+ .irq_num = NVIC_UART4,
+};
+/** UART4 device */
+usart_dev *UART4 = &uart4;
+
+static ring_buffer uart5_rb;
+static usart_dev uart5 = {
+ .regs = UART5_BASE,
+ .rb = &uart5_rb,
+ .max_baud = 2250000UL, /* TODO: are these correct? */
+ .clk_id = RCC_UART5,
+ .irq_num = NVIC_UART5,
+};
+/** UART5 device */
+usart_dev *UART5 = &uart5;
+
+static ring_buffer usart6_rb;
+static usart_dev usart6 = {
+ .regs = USART6_BASE,
+ .rb = &usart6_rb,
+ .max_baud = 4500000UL, /* TODO: are these correct? */
+ .clk_id = RCC_USART6,
+ .irq_num = NVIC_USART6,
+};
+usart_dev *USART6 = &usart6;
+
+/*
+ * Routines
+ */
+
+void usart_config_gpios_async(usart_dev *udev,
+ gpio_dev *rx_dev, uint8 rx,
+ gpio_dev *tx_dev, uint8 tx,
+ unsigned flags) {
+ gpio_af af = usart_get_af(udev);
+ gpio_set_modef(rx_dev, rx, GPIO_MODE_AF, 0);
+ gpio_set_modef(tx_dev, tx, GPIO_MODE_AF, 0);
+ gpio_set_af(rx_dev, rx, af);
+ gpio_set_af(tx_dev, tx, af);
+}
+
+void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) {
+ uint32 integer_part;
+ uint32 fractional_part;
+ uint32 tmp;
+ uint32 over8 = !!(dev->regs->CR1 & USART_CR1_OVER8);
+
+ ASSERT(!over8); /* OVER8 is currently unsupported. */
+
+ /* Figure out the clock speed, if the user doesn't give one. */
+ if (clock_speed == 0) {
+ clock_speed = _usart_clock_freq(dev);
+ }
+ ASSERT(clock_speed);
+
+ /* Convert desired baud rate to baud rate register setting. */
+ integer_part = (25 * clock_speed) / (2 * (2 - over8) * baud);
+ tmp = (integer_part / 100) << 4;
+ fractional_part = integer_part - (100 * (tmp >> 4));
+ tmp |= ((fractional_part * 16 + 50) / 100) & (uint8)0x0F;
+
+ dev->regs->BRR = tmp;
+}
+
+/**
+ * @brief Call a function on each USART.
+ * @param fn Function to call.
+ */
+void usart_foreach(void (*fn)(usart_dev*)) {
+ fn(USART1);
+ fn(USART2);
+ fn(USART3);
+ fn(UART4);
+ fn(UART5);
+ fn(USART6);
+}
+
+/**
+ * @brief Get GPIO alternate function mode for a USART.
+ * @param dev USART whose gpio_af to get.
+ * @return gpio_af corresponding to dev.
+ */
+gpio_af usart_get_af(usart_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_USART1:
+ case RCC_USART2:
+ case RCC_USART3:
+ return GPIO_AF_USART_1_2_3;
+ case RCC_UART4:
+ case RCC_UART5:
+ case RCC_USART6:
+ return GPIO_AF_USART_4_5_6;
+ default:
+ ASSERT(0); /* Can't happen */
+ return (gpio_af)-1;
+ }
+}
+
+/*
+ * Interrupt handlers.
+ */
+
+void __irq_usart1(void) {
+ usart_irq(&usart1_rb, USART1_BASE);
+}
+
+void __irq_usart2(void) {
+ usart_irq(&usart2_rb, USART2_BASE);
+}
+
+void __irq_usart3(void) {
+ usart_irq(&usart3_rb, USART3_BASE);
+}
+
+void __irq_uart4(void) {
+ usart_irq(&uart4_rb, UART4_BASE);
+}
+
+void __irq_uart5(void) {
+ usart_irq(&uart5_rb, UART5_BASE);
+}
+
+void __irq_usart6(void) {
+ usart_irq(&usart6_rb, USART6_BASE);
+}
diff --git a/libmaple/stm32f2/vector_table.S b/libmaple/stm32f2/vector_table.S
new file mode 100644
index 0000000..147e516
--- /dev/null
+++ b/libmaple/stm32f2/vector_table.S
@@ -0,0 +1,135 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/* STM32F2 vector table */
+
+ .section ".stm32.interrupt_vector"
+
+ .globl __stm32_vector_table
+ .type __stm32_vector_table, %object
+
+__stm32_vector_table:
+/* CM3 core interrupts */
+ .long __msp_init
+ .long __exc_reset
+ .long __exc_nmi
+ .long __exc_hardfault
+ .long __exc_memmanage
+ .long __exc_busfault
+ .long __exc_usagefault
+ .long __stm32reservedexception7
+ .long __stm32reservedexception8
+ .long __stm32reservedexception9
+ .long __stm32reservedexception10
+ .long __exc_svc
+ .long __exc_debug_monitor
+ .long __stm32reservedexception13
+ .long __exc_pendsv
+ .long __exc_systick
+/* Peripheral interrupts */
+ .long __irq_wwdg
+ .long __irq_pvd
+ .long __irq_tamp_stamp
+ .long __irq_rtc_wkup
+ .long __irq_flash
+ .long __irq_rcc
+ .long __irq_exti0
+ .long __irq_exti1
+ .long __irq_exti2
+ .long __irq_exti3
+ .long __irq_exti4
+ .long __irq_dma1_stream0
+ .long __irq_dma1_stream1
+ .long __irq_dma1_stream2
+ .long __irq_dma1_stream3
+ .long __irq_dma1_stream4
+ .long __irq_dma1_stream5
+ .long __irq_dma1_stream6
+ .long __irq_adc
+ .long __irq_can1_tx
+ .long __irq_can1_rx0
+ .long __irq_can1_rx1
+ .long __irq_can1_sce
+ .long __irq_exti9_5
+ .long __irq_tim1_brk_tim9
+ .long __irq_tim1_up_tim10
+ .long __irq_tim1_trg_com_tim11
+ .long __irq_tim1_cc
+ .long __irq_tim2
+ .long __irq_tim3
+ .long __irq_tim4
+ .long __irq_i2c1_ev
+ .long __irq_i2c1_er
+ .long __irq_i2c2_ev
+ .long __irq_i2c2_er
+ .long __irq_spi1
+ .long __irq_spi2
+ .long __irq_usart1
+ .long __irq_usart2
+ .long __irq_usart3
+ .long __irq_exti15_10
+ .long __irq_rtc_alarm
+ .long __irq_otg_fs_wkup
+ .long __irq_tim8_brk_tim12
+ .long __irq_tim8_up_tim13
+ .long __irq_tim8_trg_com_tim14
+ .long __irq_tim8_cc
+ .long __irq_dma1_stream7
+ .long __irq_fsmc
+ .long __irq_sdio
+ .long __irq_tim5
+ .long __irq_spi3
+ .long __irq_uart4
+ .long __irq_uart5
+ .long __irq_tim6_dac
+ .long __irq_tim7
+ .long __irq_dma2_stream0
+ .long __irq_dma2_stream1
+ .long __irq_dma2_stream2
+ .long __irq_dma2_stream3
+ .long __irq_dma2_stream4
+ .long __irq_eth
+ .long __irq_eth_wkup
+ .long __irq_can2_tx
+ .long __irq_can2_rx0
+ .long __irq_can2_rx1
+ .long __irq_can2_sce
+ .long __irq_otg_fs
+ .long __irq_dma2_stream5
+ .long __irq_dma2_stream6
+ .long __irq_dma2_stream7
+ .long __irq_usart6
+ .long __irq_i2c3_ev
+ .long __irq_i2c3_er
+ .long __irq_otg_hs_ep1_out
+ .long __irq_otg_hs_ep1_in
+ .long __irq_otg_hs_wkup
+ .long __irq_otg_hs
+ .long __irq_dcmi
+ .long __irq_cryp
+ .long __irq_hash_rng
+
+ .size __stm32_vector_table, . - __stm32_vector_table
diff --git a/libmaple/systick.c b/libmaple/systick.c
new file mode 100644
index 0000000..7568abe
--- /dev/null
+++ b/libmaple/systick.c
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2010, 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/systick.c
+ * @brief System timer (SysTick).
+ */
+
+#include <libmaple/systick.h>
+
+volatile uint32 systick_uptime_millis;
+static void (*systick_user_callback)(void);
+
+/**
+ * @brief Initialize and enable SysTick.
+ *
+ * Clocks the system timer with the core clock, turns it on, and
+ * enables interrupts.
+ *
+ * @param reload_val Appropriate reload counter to tick every 1 ms.
+ */
+void systick_init(uint32 reload_val) {
+ SYSTICK_BASE->RVR = reload_val;
+ systick_enable();
+}
+
+/**
+ * Clock the system timer with the core clock, but don't turn it
+ * on or enable interrupt.
+ */
+void systick_disable() {
+ SYSTICK_BASE->CSR = SYSTICK_CSR_CLKSOURCE_CORE;
+}
+
+/**
+ * Clock the system timer with the core clock and turn it on;
+ * interrupt every 1 ms, for systick_timer_millis.
+ */
+void systick_enable() {
+ /* re-enables init registers without changing reload val */
+ SYSTICK_BASE->CSR = (SYSTICK_CSR_CLKSOURCE_CORE |
+ SYSTICK_CSR_ENABLE |
+ SYSTICK_CSR_TICKINT_PEND);
+}
+
+/**
+ * @brief Attach a callback to be called from the SysTick exception handler.
+ *
+ * To detach a callback, call this function again with a null argument.
+ */
+void systick_attach_callback(void (*callback)(void)) {
+ systick_user_callback = callback;
+}
+
+/*
+ * SysTick ISR
+ */
+
+void __exc_systick(void) {
+ systick_uptime_millis++;
+ if (systick_user_callback) {
+ systick_user_callback();
+ }
+}
diff --git a/libmaple/timer.c b/libmaple/timer.c
new file mode 100644
index 0000000..c22fe9d
--- /dev/null
+++ b/libmaple/timer.c
@@ -0,0 +1,412 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/timer.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Portable timer routines.
+ */
+
+#include <libmaple/timer.h>
+#include <libmaple/stm32.h>
+#include "timer_private.h"
+
+static void disable_channel(timer_dev *dev, uint8 channel);
+static void pwm_mode(timer_dev *dev, uint8 channel);
+static void output_compare_mode(timer_dev *dev, uint8 channel);
+
+static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid);
+
+/*
+ * Devices
+ *
+ * Defer to the timer_private API for declaring these.
+ */
+
+#if STM32_HAVE_TIMER(1)
+static timer_dev timer1 = ADVANCED_TIMER(1);
+/** Timer 1 device (advanced) */
+timer_dev *TIMER1 = &timer1;
+#endif
+#if STM32_HAVE_TIMER(2)
+static timer_dev timer2 = GENERAL_TIMER(2);
+/** Timer 2 device (general-purpose) */
+timer_dev *TIMER2 = &timer2;
+#endif
+#if STM32_HAVE_TIMER(3)
+static timer_dev timer3 = GENERAL_TIMER(3);
+/** Timer 3 device (general-purpose) */
+timer_dev *TIMER3 = &timer3;
+#endif
+#if STM32_HAVE_TIMER(4)
+static timer_dev timer4 = GENERAL_TIMER(4);
+/** Timer 4 device (general-purpose) */
+timer_dev *TIMER4 = &timer4;
+#endif
+#if STM32_HAVE_TIMER(5)
+static timer_dev timer5 = GENERAL_TIMER(5);
+/** Timer 5 device (general-purpose) */
+timer_dev *TIMER5 = &timer5;
+#endif
+#if STM32_HAVE_TIMER(6)
+static timer_dev timer6 = BASIC_TIMER(6);
+/** Timer 6 device (basic) */
+timer_dev *TIMER6 = &timer6;
+#endif
+#if STM32_HAVE_TIMER(7)
+static timer_dev timer7 = BASIC_TIMER(7);
+/** Timer 7 device (basic) */
+timer_dev *TIMER7 = &timer7;
+#endif
+#if STM32_HAVE_TIMER(8)
+static timer_dev timer8 = ADVANCED_TIMER(8);
+/** Timer 8 device (advanced) */
+timer_dev *TIMER8 = &timer8;
+#endif
+#if STM32_HAVE_TIMER(9)
+static timer_dev timer9 = RESTRICTED_GENERAL_TIMER(9, TIMER_DIER_TIE_BIT);
+/** Timer 9 device (general-purpose) */
+timer_dev *TIMER9 = &timer9;
+#endif
+#if STM32_HAVE_TIMER(10)
+static timer_dev timer10 = RESTRICTED_GENERAL_TIMER(10, TIMER_DIER_CC1IE_BIT);
+/** Timer 10 device (general-purpose) */
+timer_dev *TIMER10 = &timer10;
+#endif
+#if STM32_HAVE_TIMER(11)
+static timer_dev timer11 = RESTRICTED_GENERAL_TIMER(11, TIMER_DIER_CC1IE_BIT);
+/** Timer 11 device (general-purpose) */
+timer_dev *TIMER11 = &timer11;
+#endif
+#if STM32_HAVE_TIMER(12)
+static timer_dev timer12 = RESTRICTED_GENERAL_TIMER(12, TIMER_DIER_TIE_BIT);
+/** Timer 12 device (general-purpose) */
+timer_dev *TIMER12 = &timer12;
+#endif
+#if STM32_HAVE_TIMER(13)
+static timer_dev timer13 = RESTRICTED_GENERAL_TIMER(13, TIMER_DIER_CC1IE_BIT);
+/** Timer 13 device (general-purpose) */
+timer_dev *TIMER13 = &timer13;
+#endif
+#if STM32_HAVE_TIMER(14)
+static timer_dev timer14 = RESTRICTED_GENERAL_TIMER(14, TIMER_DIER_CC1IE_BIT);
+/** Timer 14 device (general-purpose) */
+timer_dev *TIMER14 = &timer14;
+#endif
+
+/*
+ * Routines
+ */
+
+/**
+ * @brief Call a function on timer devices.
+ * @param fn Function to call on each timer device.
+ */
+void timer_foreach(void (*fn)(timer_dev*)) {
+#if STM32_HAVE_TIMER(1)
+ fn(TIMER1);
+#endif
+#if STM32_HAVE_TIMER(2)
+ fn(TIMER2);
+#endif
+#if STM32_HAVE_TIMER(3)
+ fn(TIMER3);
+#endif
+#if STM32_HAVE_TIMER(4)
+ fn(TIMER4);
+#endif
+#if STM32_HAVE_TIMER(5)
+ fn(TIMER5);
+#endif
+#if STM32_HAVE_TIMER(6)
+ fn(TIMER6);
+#endif
+#if STM32_HAVE_TIMER(7)
+ fn(TIMER7);
+#endif
+#if STM32_HAVE_TIMER(8)
+ fn(TIMER8);
+#endif
+#if STM32_HAVE_TIMER(9)
+ fn(TIMER9);
+#endif
+#if STM32_HAVE_TIMER(10)
+ fn(TIMER10);
+#endif
+#if STM32_HAVE_TIMER(11)
+ fn(TIMER11);
+#endif
+#if STM32_HAVE_TIMER(12)
+ fn(TIMER12);
+#endif
+#if STM32_HAVE_TIMER(13)
+ fn(TIMER13);
+#endif
+#if STM32_HAVE_TIMER(14)
+ fn(TIMER14);
+#endif
+}
+
+/**
+ * Initialize a timer, and reset its register map.
+ * @param dev Timer to initialize
+ */
+void timer_init(timer_dev *dev) {
+ rcc_clk_enable(dev->clk_id);
+ rcc_reset_dev(dev->clk_id);
+}
+
+/**
+ * @brief Disable a timer.
+ *
+ * The timer will stop counting, all DMA requests and interrupts will
+ * be disabled, and no state changes will be output.
+ *
+ * @param dev Timer to disable.
+ */
+void timer_disable(timer_dev *dev) {
+ (dev->regs).bas->CR1 = 0;
+ (dev->regs).bas->DIER = 0;
+ switch (dev->type) {
+ case TIMER_ADVANCED: /* fall-through */
+ case TIMER_GENERAL:
+ (dev->regs).gen->CCER = 0;
+ break;
+ case TIMER_BASIC:
+ break;
+ }
+}
+
+/**
+ * Sets the mode of an individual timer channel.
+ *
+ * Note that not all timers can be configured in every mode. For
+ * example, basic timers cannot be configured to output compare mode.
+ * Be sure to use a timer which is appropriate for the mode you want.
+ *
+ * @param dev Timer whose channel mode to set
+ * @param channel Relevant channel
+ * @param mode New timer mode for channel
+ */
+void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) {
+ ASSERT_FAULT(channel > 0 && channel <= 4);
+
+ /* TODO decide about the basic timers */
+ ASSERT(dev->type != TIMER_BASIC);
+ if (dev->type == TIMER_BASIC)
+ return;
+
+ switch (mode) {
+ case TIMER_DISABLED:
+ disable_channel(dev, channel);
+ break;
+ case TIMER_PWM:
+ pwm_mode(dev, channel);
+ break;
+ case TIMER_OUTPUT_COMPARE:
+ output_compare_mode(dev, channel);
+ break;
+ }
+}
+
+/**
+ * @brief Determine whether a timer has a particular capture/compare channel.
+ *
+ * Different timers have different numbers of capture/compare channels
+ * (and some have none at all). Use this function to test whether a
+ * given timer/channel combination will work.
+ *
+ * @param dev Timer device
+ * @param channel Capture/compare channel, from 1 to 4
+ * @return Nonzero if dev has channel, zero otherwise.
+ */
+int timer_has_cc_channel(timer_dev *dev, uint8 channel) {
+ /* On all currently supported series: advanced and "full-featured"
+ * general purpose timers have all four channels. Of the
+ * restricted general timers, timers 9 and 12 have channels 1 and
+ * 2; the others have channel 1 only. Basic timers have none. */
+ rcc_clk_id id = dev->clk_id;
+ ASSERT((1 <= channel) && (channel <= 4));
+ if (id <= RCC_TIMER5 || id == RCC_TIMER8) {
+ return 1; /* 1 and 8 are advanced, 2-5 are "full" general */
+ } else if (id <= RCC_TIMER7) {
+ return 0; /* 6 and 7 are basic */
+ }
+ /* The rest are restricted general. */
+ return (((id == RCC_TIMER9 || id == RCC_TIMER12) && channel <= 2) ||
+ channel == 1);
+}
+
+/**
+ * @brief Attach a timer interrupt.
+ * @param dev Timer device
+ * @param interrupt Interrupt number to attach to; this may be any
+ * timer_interrupt_id or timer_channel value appropriate
+ * for the timer.
+ * @param handler Handler to attach to the given interrupt.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+void timer_attach_interrupt(timer_dev *dev,
+ uint8 interrupt,
+ voidFuncPtr handler) {
+ dev->handlers[interrupt] = handler;
+ timer_enable_irq(dev, interrupt);
+ enable_irq(dev, interrupt);
+}
+
+/**
+ * @brief Detach a timer interrupt.
+ * @param dev Timer device
+ * @param interrupt Interrupt number to detach; this may be any
+ * timer_interrupt_id or timer_channel value appropriate
+ * for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+void timer_detach_interrupt(timer_dev *dev, uint8 interrupt) {
+ timer_disable_irq(dev, interrupt);
+ dev->handlers[interrupt] = NULL;
+}
+
+/*
+ * Utilities
+ */
+
+static void disable_channel(timer_dev *dev, uint8 channel) {
+ timer_detach_interrupt(dev, channel);
+ timer_cc_disable(dev, channel);
+}
+
+static void pwm_mode(timer_dev *dev, uint8 channel) {
+ timer_disable_irq(dev, channel);
+ timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, TIMER_OC_PE);
+ timer_cc_enable(dev, channel);
+}
+
+static void output_compare_mode(timer_dev *dev, uint8 channel) {
+ timer_oc_set_mode(dev, channel, TIMER_OC_MODE_ACTIVE_ON_MATCH, 0);
+ timer_cc_enable(dev, channel);
+}
+
+static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id);
+static void enable_bas_gen_irq(timer_dev *dev);
+
+static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid) {
+ if (dev->type == TIMER_ADVANCED) {
+ enable_adv_irq(dev, iid);
+ } else {
+ enable_bas_gen_irq(dev);
+ }
+}
+
+/* Advanced control timers have several IRQ lines corresponding to
+ * different timer interrupts.
+ *
+ * Note: This function assumes that the only advanced timers are TIM1
+ * and TIM8, and needs the obvious changes if that assumption is
+ * violated by a later STM32 series. */
+static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id) {
+ uint8 is_tim1 = dev->clk_id == RCC_TIMER1;
+ nvic_irq_num irq_num;
+ switch (id) {
+ case TIMER_UPDATE_INTERRUPT:
+ irq_num = (is_tim1 ?
+ NVIC_TIMER1_UP_TIMER10 :
+ NVIC_TIMER8_UP_TIMER13);
+ break;
+ case TIMER_CC1_INTERRUPT: /* Fall through */
+ case TIMER_CC2_INTERRUPT: /* ... */
+ case TIMER_CC3_INTERRUPT: /* ... */
+ case TIMER_CC4_INTERRUPT:
+ irq_num = is_tim1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC;
+ break;
+ case TIMER_COM_INTERRUPT: /* Fall through */
+ case TIMER_TRG_INTERRUPT:
+ irq_num = (is_tim1 ?
+ NVIC_TIMER1_TRG_COM_TIMER11 :
+ NVIC_TIMER8_TRG_COM_TIMER14);
+ break;
+ case TIMER_BREAK_INTERRUPT:
+ irq_num = (is_tim1 ?
+ NVIC_TIMER1_BRK_TIMER9 :
+ NVIC_TIMER8_BRK_TIMER12);
+ break;
+ default:
+ /* Can't happen, but placate the compiler */
+ ASSERT(0);
+ return;
+ }
+ nvic_irq_enable(irq_num);
+}
+
+/* Basic and general purpose timers have a single IRQ line, which is
+ * shared by all interrupts supported by a particular timer. */
+static void enable_bas_gen_irq(timer_dev *dev) {
+ nvic_irq_num irq_num;
+ switch (dev->clk_id) {
+ case RCC_TIMER2:
+ irq_num = NVIC_TIMER2;
+ break;
+ case RCC_TIMER3:
+ irq_num = NVIC_TIMER3;
+ break;
+ case RCC_TIMER4:
+ irq_num = NVIC_TIMER4;
+ break;
+ case RCC_TIMER5:
+ irq_num = NVIC_TIMER5;
+ break;
+ case RCC_TIMER6:
+ irq_num = NVIC_TIMER6;
+ break;
+ case RCC_TIMER7:
+ irq_num = NVIC_TIMER7;
+ break;
+ case RCC_TIMER9:
+ irq_num = NVIC_TIMER1_BRK_TIMER9;
+ break;
+ case RCC_TIMER10:
+ irq_num = NVIC_TIMER1_UP_TIMER10;
+ break;
+ case RCC_TIMER11:
+ irq_num = NVIC_TIMER1_TRG_COM_TIMER11;
+ break;
+ case RCC_TIMER12:
+ irq_num = NVIC_TIMER8_BRK_TIMER12;
+ break;
+ case RCC_TIMER13:
+ irq_num = NVIC_TIMER8_UP_TIMER13;
+ break;
+ case RCC_TIMER14:
+ irq_num = NVIC_TIMER8_TRG_COM_TIMER14;
+ break;
+ default:
+ ASSERT_FAULT(0);
+ return;
+ }
+ nvic_irq_enable(irq_num);
+}
diff --git a/libmaple/timer_private.h b/libmaple/timer_private.h
new file mode 100644
index 0000000..320c636
--- /dev/null
+++ b/libmaple/timer_private.h
@@ -0,0 +1,235 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/timer_private.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Private, internal timer APIs.
+ */
+
+#ifndef _LIBMAPLE_TIMER_PRIVATE_H_
+#define _LIBMAPLE_TIMER_PRIVATE_H_
+
+/*
+ * Helper macros for declaring timer_devs of various timer_types
+ */
+
+/* The indexes of user handlers in a timer_dev.handlers are just like
+ * the corresponding DIER bits, as follows: */
+
+/* Advanced timers:
+ * [0] = Update handler;
+ * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively;
+ * [5] = COM;
+ * [6] = TRG;
+ * [7] = BRK. */
+#define NR_ADV_HANDLERS 8
+/* General purpose timers:
+ * [0] = update;
+ * [1,2,3,4] = capture/compare 1,2,3,4;
+ * [5] = <junk>;
+ * [6] = trigger. */
+#define NR_GEN_HANDLERS 7
+/* Basic timers:
+ * [0] = update. */
+#define NR_BAS_HANDLERS 1
+
+/* For declaring advanced timers. */
+#define ADVANCED_TIMER(num) \
+ { \
+ .regs = { .adv = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_ADVANCED, \
+ .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, \
+ }
+
+/* For declaring full-featured general purpose timers. */
+#define GENERAL_TIMER(num) \
+ { \
+ .regs = { .gen = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_GENERAL, \
+ .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, \
+ }
+
+/* For declaring general purpose timers with limited interrupt
+ * capability (e.g. timers 9 through 14 on STM32F2 and XL-density
+ * STM32F1). */
+#define RESTRICTED_GENERAL_TIMER(num, max_dier_bit) \
+ { \
+ .regs = { .gen = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_GENERAL, \
+ .handlers = { [max_dier_bit] = 0 }, \
+ }
+
+/* For declaring basic timers (e.g. TIM6 and TIM7). */
+#define BASIC_TIMER(num) \
+ { \
+ .regs = { .bas = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_BASIC, \
+ .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, \
+ }
+
+/*
+ * IRQ handlers
+ *
+ * These decode TIMx_DIER and TIMx_SR, then dispatch to the user-level
+ * IRQ handlers. They also clean up TIMx_SR afterwards, so the user
+ * doesn't have to deal with register details.
+ *
+ * Notes:
+ *
+ * - These dispatch routines make use of the fact that DIER interrupt
+ * enable bits and SR interrupt flags have common bit positions.
+ * Thus, ANDing DIER and SR lets us check if an interrupt is enabled
+ * and if it has occurred simultaneously.
+ *
+ * - We force these routines to inline to avoid call overhead, but
+ * there aren't any measurements to prove that this is actually a
+ * good idea. Profile-directed optimizations are definitely wanted. */
+
+/* A special-case dispatch routine for timers which only serve a
+ * single interrupt on a given IRQ line.
+ *
+ * This function still checks DIER & SR, as in some cases, a timer may
+ * only serve a single interrupt on a particular NVIC line, but that
+ * line may be shared with another timer. For example, the timer 1
+ * update interrupt shares an IRQ line with the timer 10 interrupt on
+ * STM32F1 (XL-density), STM32F2, and STM32F4. */
+static __always_inline void dispatch_single_irq(timer_dev *dev,
+ timer_interrupt_id iid,
+ uint32 irq_mask) {
+ timer_bas_reg_map *regs = (dev->regs).bas;
+ if (regs->DIER & regs->SR & irq_mask) {
+ void (*handler)(void) = dev->handlers[iid];
+ if (handler) {
+ handler();
+ regs->SR &= ~irq_mask;
+ }
+ }
+}
+
+/* Helper macro for dispatch routines which service multiple interrupts. */
+#define handle_irq(dier_sr, irq_mask, handlers, iid, handled_irq) do { \
+ if ((dier_sr) & (irq_mask)) { \
+ void (*__handler)(void) = (handlers)[iid]; \
+ if (__handler) { \
+ __handler(); \
+ handled_irq |= (irq_mask); \
+ } \
+ } \
+ } while (0)
+
+static __always_inline void dispatch_adv_brk(timer_dev *dev) {
+ dispatch_single_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF);
+}
+
+static __always_inline void dispatch_adv_up(timer_dev *dev) {
+ dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
+}
+
+static __always_inline void dispatch_adv_trg_com(timer_dev *dev) {
+ timer_adv_reg_map *regs = (dev->regs).adv;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0; /* Logical OR of SR interrupt flags we end up
+ * handling. We clear these. User handlers
+ * must clear overcapture flags, to avoid
+ * wasting time in output mode. */
+
+ handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_COMIF, hs, TIMER_COM_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+static __always_inline void dispatch_adv_cc(timer_dev *dev) {
+ timer_adv_reg_map *regs = (dev->regs).adv;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0;
+
+ handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+static __always_inline void dispatch_general(timer_dev *dev) {
+ timer_gen_reg_map *regs = (dev->regs).gen;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0;
+
+ handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+/* On F1 (XL-density), F2, and F4, TIM9 and TIM12 are restricted
+ * general-purpose timers with update, CC1, CC2, and TRG interrupts. */
+static __always_inline void dispatch_tim_9_12(timer_dev *dev) {
+ timer_gen_reg_map *regs = (dev->regs).gen;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0;
+
+ handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+/* On F1 (XL-density), F2, and F4, timers 10, 11, 13, and 14 are
+ * restricted general-purpose timers with update and CC1 interrupts. */
+static __always_inline void dispatch_tim_10_11_13_14(timer_dev *dev) {
+ timer_gen_reg_map *regs = (dev->regs).gen;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0;
+
+ handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+static __always_inline void dispatch_basic(timer_dev *dev) {
+ dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
+}
+
+#endif
diff --git a/libmaple/usart.c b/libmaple/usart.c
new file mode 100644
index 0000000..1d88234
--- /dev/null
+++ b/libmaple/usart.c
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/usart.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief Portable USART routines
+ */
+
+#include <libmaple/usart.h>
+
+/**
+ * @brief Initialize a serial port.
+ * @param dev Serial port to be initialized
+ */
+void usart_init(usart_dev *dev) {
+ rb_init(dev->rb, USART_RX_BUF_SIZE, dev->rx_buf);
+ rcc_clk_enable(dev->clk_id);
+ nvic_irq_enable(dev->irq_num);
+}
+
+/**
+ * @brief Enable a serial port.
+ *
+ * USART is enabled in single buffer transmission mode, multibuffer
+ * receiver mode, 8n1.
+ *
+ * Serial port must have a baud rate configured to work properly.
+ *
+ * @param dev Serial port to enable.
+ * @see usart_set_baud_rate()
+ */
+void usart_enable(usart_dev *dev) {
+ usart_reg_map *regs = dev->regs;
+ regs->CR1 = (USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE |
+ USART_CR1_M_8N1);
+ regs->CR1 |= USART_CR1_UE;
+}
+
+/**
+ * @brief Turn off a serial port.
+ * @param dev Serial port to be disabled
+ */
+void usart_disable(usart_dev *dev) {
+ /* FIXME this misbehaves (on F1) if you try to use PWM on TX afterwards */
+ usart_reg_map *regs = dev->regs;
+
+ /* TC bit must be high before disabling the USART */
+ while((regs->CR1 & USART_CR1_UE) && !(regs->SR & USART_SR_TC))
+ ;
+
+ /* Disable UE */
+ regs->CR1 &= ~USART_CR1_UE;
+
+ /* Clean up buffer */
+ usart_reset_rx(dev);
+}
+
+/**
+ * @brief Nonblocking USART transmit
+ * @param dev Serial port to transmit over
+ * @param buf Buffer to transmit
+ * @param len Maximum number of bytes to transmit
+ * @return Number of bytes transmitted
+ */
+uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len) {
+ usart_reg_map *regs = dev->regs;
+ uint32 txed = 0;
+ while ((regs->SR & USART_SR_TXE) && (txed < len)) {
+ regs->DR = buf[txed++];
+ }
+ return txed;
+}
+
+/**
+ * @brief Nonblocking USART receive.
+ * @param dev Serial port to receive bytes from
+ * @param buf Buffer to store received bytes into
+ * @param len Maximum number of bytes to store
+ * @return Number of bytes received
+ */
+uint32 usart_rx(usart_dev *dev, uint8 *buf, uint32 len) {
+ uint32 rxed = 0;
+ while (usart_data_available(dev) && rxed < len) {
+ *buf++ = usart_getc(dev);
+ rxed++;
+ }
+ return rxed;
+}
+
+/**
+ * @brief Transmit an unsigned integer to the specified serial port in
+ * decimal format.
+ *
+ * This function blocks until the integer's digits have been
+ * completely transmitted.
+ *
+ * @param dev Serial port to send on
+ * @param val Number to print
+ */
+void usart_putudec(usart_dev *dev, uint32 val) {
+ char digits[12];
+ int i = 0;
+
+ do {
+ digits[i++] = val % 10 + '0';
+ val /= 10;
+ } while (val > 0);
+
+ while (--i >= 0) {
+ usart_putc(dev, digits[i]);
+ }
+}
diff --git a/libmaple/usart_private.c b/libmaple/usart_private.c
new file mode 100644
index 0000000..0eaacdf
--- /dev/null
+++ b/libmaple/usart_private.c
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/usart_private.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Private USART routines.
+ */
+
+#include "usart_private.h"
+#include <libmaple/rcc.h>
+#include <libmaple/stm32.h>
+
+uint32 _usart_clock_freq(usart_dev *dev) {
+ rcc_clk_domain domain = rcc_dev_clk(dev->clk_id);
+ return (domain == RCC_APB1 ? STM32_PCLK1 :
+ (domain == RCC_APB2 ? STM32_PCLK2 : 0));
+}
diff --git a/libmaple/usart_private.h b/libmaple/usart_private.h
new file mode 100644
index 0000000..8e8e11b
--- /dev/null
+++ b/libmaple/usart_private.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/usart_private.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Private USART header.
+ */
+
+#ifndef _LIBMAPLE_USART_PRIVATE_H_
+#define _LIBMAPLE_USART_PRIVATE_H_
+
+#include <libmaple/ring_buffer.h>
+#include <libmaple/usart.h>
+
+static __always_inline void usart_irq(ring_buffer *rb, usart_reg_map *regs) {
+#ifdef USART_SAFE_INSERT
+ /* If the buffer is full and the user defines USART_SAFE_INSERT,
+ * ignore new bytes. */
+ rb_safe_insert(rb, (uint8)regs->DR);
+#else
+ /* By default, push bytes around in the ring buffer. */
+ rb_push_insert(rb, (uint8)regs->DR);
+#endif
+}
+
+uint32 _usart_clock_freq(usart_dev *dev);
+
+#endif
diff --git a/libmaple/usb/README b/libmaple/usb/README
new file mode 100644
index 0000000..d0fca8d
--- /dev/null
+++ b/libmaple/usb/README
@@ -0,0 +1,63 @@
+The USB submodule of libmaple is a separate piece of the codebase for
+reasons that are largely historical.
+
+Current Status:
+
+ There's only support for the USB device peripheral found on
+ STM32F103s.
+
+ We rely on the low level core library provided by ST to implement
+ the USB transfer protocol for control endpoint transfers.
+
+ The virtual com port (which is exposed via
+ <libmaple/usb_cdcacm.h>) serves two important purposes.
+
+ 1) It allows serial data transfers between user sketches an a
+ host computer.
+
+ 2) It allows the host PC to issue a system reset into the DFU
+ bootloader with the DTR + RTS + "1EAF" sequence (see
+ leaflabs.com/docs/bootloader.html for more information on
+ this).
+
+ 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 (e.g. to use faster isochronous enpoints for streaming
+ audio, or implement the USB HID or Mass Storage specs), then
+ ensure that you leave some hook for resetting Maple remotely in
+ order to spin up the DFU bootloader. Please make sure to get
+ yourself a unique vendor/product ID pair for your application, as
+ some operating systems will assign a host-side driver based on
+ these tags.
+
+ 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 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 enabling the USB peripheral isn't "free." The
+ device must respond to periodic bus activity (every few
+ 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, a USB_DISC pin is
+ asserted (e.g. on Maple, this is PC12). Alternatively, the NVIC
+ can be directly configured to disable the USB LP/HP IRQ's.
+
+ The files inside of usb_lib were provided by ST and are subject to
+ their own license, all other files were written by the LeafLabs
+ team and fall under the MIT license.
+
+TODO:
+
+ - Generic USB driver core with series-provided backends, like
+ libopencm3 has.
+ - Strip out ST code.
+ - Integration with a high level USB library (like LUFA/MyUSB) to
+ allow users to write custom USB applications.
diff --git a/libmaple/usb/rules.mk b/libmaple/usb/rules.mk
new file mode 100644
index 0000000..e8ccc15
--- /dev/null
+++ b/libmaple/usb/rules.mk
@@ -0,0 +1,45 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) = -I$(d) -I$(d)/$(MCU_SERIES) -I$(d)/usb_lib $(LIBMAPLE_INCLUDES) $(LIBMAPLE_PRIVATE_INCLUDES) -Wall
+
+# Add usblib and series subdirectory to BUILDDIRS.
+BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_SERIES)
+BUILDDIRS += $(BUILD_PATH)/$(d)/usb_lib
+
+# Local rules and targets
+sSRCS_$(d) :=
+cSRCS_$(d) :=
+# We currently only have F1 performance line support. Sigh.
+ifeq ($(MCU_SERIES), stm32f1)
+ifeq ($(MCU_F1_LINE), performance)
+cSRCS_$(d) += $(MCU_SERIES)/usb.c
+cSRCS_$(d) += $(MCU_SERIES)/usb_reg_map.c
+cSRCS_$(d) += $(MCU_SERIES)/usb_cdcacm.c
+cSRCS_$(d) += usb_lib/usb_core.c
+cSRCS_$(d) += usb_lib/usb_init.c
+cSRCS_$(d) += usb_lib/usb_mem.c
+cSRCS_$(d) += usb_lib/usb_regs.c
+endif
+endif
+
+sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
+ $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+$(OBJS_$(d)): TGT_ASFLAGS :=
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp))
diff --git a/libmaple/usb/stm32f1/usb.c b/libmaple/usb/stm32f1/usb.c
new file mode 100644
index 0000000..f694f04
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb.c
@@ -0,0 +1,387 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/usb/stm32f1/usb.c
+ * @brief USB support.
+ *
+ * This is a mess.
+ */
+
+#include <libmaple/usb.h>
+
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
+
+/* Private headers */
+#include "usb_reg_map.h"
+#include "usb_lib_globals.h"
+
+/* usb_lib headers */
+#include "usb_type.h"
+#include "usb_core.h"
+
+static void dispatch_ctr_lp(void);
+
+/*
+ * usb_lib/ globals
+ */
+
+uint16 SaveTState; /* caches TX status for later use */
+uint16 SaveRState; /* caches RX status for later use */
+
+/*
+ * Other state
+ */
+
+typedef enum {
+ RESUME_EXTERNAL,
+ RESUME_INTERNAL,
+ RESUME_LATER,
+ RESUME_WAIT,
+ RESUME_START,
+ RESUME_ON,
+ RESUME_OFF,
+ RESUME_ESOF
+} RESUME_STATE;
+
+struct {
+ volatile RESUME_STATE eState;
+ volatile uint8 bESOFcnt;
+} ResumeS;
+
+static usblib_dev usblib = {
+ .irq_mask = USB_ISR_MSK,
+ .state = USB_UNCONNECTED,
+ .prevState = USB_UNCONNECTED,
+ .clk_id = RCC_USB,
+};
+usblib_dev *USBLIB = &usblib;
+
+/*
+ * Routines
+ */
+
+void usb_init_usblib(usblib_dev *dev,
+ void (**ep_int_in)(void),
+ void (**ep_int_out)(void)) {
+ rcc_clk_enable(dev->clk_id);
+
+ dev->ep_int_in = ep_int_in;
+ dev->ep_int_out = ep_int_out;
+
+ /* usb_lib/ declares both and then assumes that pFoo points to Foo
+ * (even though the names don't always match), which is stupid for
+ * all of the obvious reasons, but whatever. Here we are. */
+ pInformation = &Device_Info;
+ pProperty = &Device_Property;
+ pUser_Standard_Requests = &User_Standard_Requests;
+
+ pInformation->ControlState = 2; /* FIXME [0.0.12] use
+ CONTROL_STATE enumerator */
+ pProperty->Init();
+}
+
+static void usb_suspend(void) {
+ uint16 cntr;
+
+ /* TODO decide if read/modify/write is really what we want
+ * (e.g. usb_resume_init() reconfigures CNTR). */
+ cntr = USB_BASE->CNTR;
+ cntr |= USB_CNTR_FSUSP;
+ USB_BASE->CNTR = cntr;
+ cntr |= USB_CNTR_LP_MODE;
+ USB_BASE->CNTR = cntr;
+
+ USBLIB->prevState = USBLIB->state;
+ USBLIB->state = USB_SUSPENDED;
+}
+
+static void usb_resume_init(void) {
+ uint16 cntr;
+
+ cntr = USB_BASE->CNTR;
+ cntr &= ~USB_CNTR_LP_MODE;
+ USB_BASE->CNTR = cntr;
+
+ /* Enable interrupt lines */
+ USB_BASE->CNTR = USB_ISR_MSK;
+}
+
+static void usb_resume(RESUME_STATE eResumeSetVal) {
+ uint16 cntr;
+
+ if (eResumeSetVal != RESUME_ESOF) {
+ ResumeS.eState = eResumeSetVal;
+ }
+
+ switch (ResumeS.eState) {
+ case RESUME_EXTERNAL:
+ usb_resume_init();
+ ResumeS.eState = RESUME_OFF;
+ USBLIB->state = USBLIB->prevState;
+ break;
+ case RESUME_INTERNAL:
+ usb_resume_init();
+ ResumeS.eState = RESUME_START;
+ break;
+ case RESUME_LATER:
+ ResumeS.bESOFcnt = 2;
+ ResumeS.eState = RESUME_WAIT;
+ break;
+ case RESUME_WAIT:
+ ResumeS.bESOFcnt--;
+ if (ResumeS.bESOFcnt == 0) {
+ ResumeS.eState = RESUME_START;
+ }
+ break;
+ case RESUME_START:
+ cntr = USB_BASE->CNTR;
+ cntr |= USB_CNTR_RESUME;
+ USB_BASE->CNTR = cntr;
+ ResumeS.eState = RESUME_ON;
+ ResumeS.bESOFcnt = 10;
+ break;
+ case RESUME_ON:
+ ResumeS.bESOFcnt--;
+ if (ResumeS.bESOFcnt == 0) {
+ cntr = USB_BASE->CNTR;
+ cntr &= ~USB_CNTR_RESUME;
+ USB_BASE->CNTR = cntr;
+ USBLIB->state = USBLIB->prevState;
+ ResumeS.eState = RESUME_OFF;
+ }
+ break;
+ case RESUME_OFF:
+ case RESUME_ESOF:
+ default:
+ ResumeS.eState = RESUME_OFF;
+ break;
+ }
+}
+
+#define SUSPEND_ENABLED 1
+void __irq_usb_lp_can_rx0(void) {
+ uint16 istr = USB_BASE->ISTR;
+
+ /* Use USB_ISR_MSK to only include code for bits we care about. */
+
+#if (USB_ISR_MSK & USB_ISTR_RESET)
+ if (istr & USB_ISTR_RESET & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_RESET;
+ pProperty->Reset();
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_PMAOVR)
+ if (istr & ISTR_PMAOVR & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_PMAOVR;
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_ERR)
+ if (istr & USB_ISTR_ERR & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_ERR;
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_WKUP)
+ if (istr & USB_ISTR_WKUP & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_WKUP;
+ usb_resume(RESUME_EXTERNAL);
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_SUSP)
+ if (istr & USB_ISTR_SUSP & USBLIB->irq_mask) {
+ /* check if SUSPEND is possible */
+ if (SUSPEND_ENABLED) {
+ usb_suspend();
+ } else {
+ /* if not possible then resume after xx ms */
+ usb_resume(RESUME_LATER);
+ }
+ /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
+ USB_BASE->ISTR = ~USB_ISTR_SUSP;
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_SOF)
+ if (istr & USB_ISTR_SOF & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_SOF;
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_ESOF)
+ if (istr & USB_ISTR_ESOF & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_ESOF;
+ /* resume handling timing is made with ESOFs */
+ usb_resume(RESUME_ESOF); /* request without change of the machine state */
+ }
+#endif
+
+ /*
+ * Service the correct transfer interrupt.
+ */
+
+#if (USB_ISR_MSK & USB_ISTR_CTR)
+ if (istr & USB_ISTR_CTR & USBLIB->irq_mask) {
+ dispatch_ctr_lp();
+ }
+#endif
+}
+
+/*
+ * Auxiliary routines
+ */
+
+static inline uint8 dispatch_endpt_zero(uint16 istr_dir);
+static inline void dispatch_endpt(uint8 ep);
+static inline void set_rx_tx_status0(uint16 rx, uint16 tx);
+
+static void handle_setup0(void);
+static void handle_in0(void);
+static void handle_out0(void);
+
+static void dispatch_ctr_lp() {
+ uint16 istr;
+ while (((istr = USB_BASE->ISTR) & USB_ISTR_CTR) != 0) {
+ /* TODO WTF, figure this out: RM0008 says CTR is read-only,
+ * but ST's firmware claims it's clear-only, and emphasizes
+ * the importance of clearing it in more than one place. */
+ USB_BASE->ISTR = ~USB_ISTR_CTR;
+ uint8 ep_id = istr & USB_ISTR_EP_ID;
+ if (ep_id == 0) {
+ /* TODO figure out why it's OK to break out of the loop
+ * once we're done serving endpoint zero, but not okay if
+ * there are multiple nonzero endpoint transfers to
+ * handle. */
+ if (dispatch_endpt_zero(istr & USB_ISTR_DIR)) {
+ return;
+ }
+ } else {
+ dispatch_endpt(ep_id);
+ }
+ }
+}
+
+/* FIXME Dataflow on endpoint 0 RX/TX status is based off of ST's
+ * code, and is ugly/confusing in its use of SaveRState/SaveTState.
+ * Fixing this requires filling in handle_in0(), handle_setup0(),
+ * handle_out0(). */
+static inline uint8 dispatch_endpt_zero(uint16 istr_dir) {
+ uint32 epr = (uint16)USB_BASE->EP[0];
+
+ if (!(epr & (USB_EP_CTR_TX | USB_EP_SETUP | USB_EP_CTR_RX))) {
+ return 0;
+ }
+
+ /* Cache RX/TX statuses in SaveRState/SaveTState, respectively.
+ * The various handle_foo0() may clobber these values
+ * before we reset them at the end of this routine. */
+ SaveRState = epr & USB_EP_STAT_RX;
+ SaveTState = epr & USB_EP_STAT_TX;
+
+ /* Set actual RX/TX statuses to NAK while we're thinking */
+ set_rx_tx_status0(USB_EP_STAT_RX_NAK, USB_EP_STAT_TX_NAK);
+
+ if (istr_dir == 0) {
+ /* ST RM0008: "If DIR bit=0, CTR_TX bit is set in the USB_EPnR
+ * register related to the interrupting endpoint. The
+ * interrupting transaction is of IN type (data transmitted by
+ * the USB peripheral to the host PC)." */
+ ASSERT_FAULT(epr & USB_EP_CTR_TX);
+ usb_clear_ctr_tx(USB_EP0);
+ handle_in0();
+ } else {
+ /* RM0008: "If DIR bit=1, CTR_RX bit or both CTR_TX/CTR_RX
+ * are set in the USB_EPnR register related to the
+ * interrupting endpoint. The interrupting transaction is of
+ * OUT type (data received by the USB peripheral from the host
+ * PC) or two pending transactions are waiting to be
+ * processed."
+ *
+ * [mbolivar] Note how the following control flow (which
+ * replicates ST's) doesn't seem to actually handle both
+ * interrupts that are ostensibly pending when both CTR_RX and
+ * CTR_TX are set.
+ *
+ * TODO sort this mess out.
+ */
+ if (epr & USB_EP_CTR_TX) {
+ usb_clear_ctr_tx(USB_EP0);
+ handle_in0();
+ } else { /* SETUP or CTR_RX */
+ /* SETUP is held constant while CTR_RX is set, so clear it
+ * either way */
+ usb_clear_ctr_rx(USB_EP0);
+ if (epr & USB_EP_SETUP) {
+ handle_setup0();
+ } else { /* CTR_RX */
+ handle_out0();
+ }
+ }
+ }
+
+ set_rx_tx_status0(SaveRState, SaveTState);
+ return 1;
+}
+
+static inline void dispatch_endpt(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ /* If ISTR_CTR is set and the ISTR gave us this EP_ID to handle,
+ * then presumably at least one of CTR_RX and CTR_TX is set, but
+ * again, ST's control flow allows for the possibility of neither.
+ *
+ * TODO try to find out if neither being set is possible. */
+ if (epr & USB_EP_CTR_RX) {
+ usb_clear_ctr_rx(ep);
+ (USBLIB->ep_int_out[ep - 1])();
+ }
+ if (epr & USB_EP_CTR_TX) {
+ usb_clear_ctr_tx(ep);
+ (USBLIB->ep_int_in[ep - 1])();
+ }
+}
+
+static inline void set_rx_tx_status0(uint16 rx, uint16 tx) {
+ usb_set_ep_rx_stat(USB_EP0, rx);
+ usb_set_ep_tx_stat(USB_EP0, tx);
+}
+
+/* TODO Rip out usb_lib/ dependency from the following functions: */
+
+static void handle_setup0(void) {
+ Setup0_Process();
+}
+
+static void handle_in0(void) {
+ In0_Process();
+}
+
+static void handle_out0(void) {
+ Out0_Process();
+}
diff --git a/libmaple/usb/stm32f1/usb_cdcacm.c b/libmaple/usb/stm32f1/usb_cdcacm.c
new file mode 100644
index 0000000..d4d4262
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_cdcacm.c
@@ -0,0 +1,709 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/usb/stm32f1/usb_cdcacm.c
+ * @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM).
+ *
+ * FIXME: this works on the STM32F1 USB peripherals, and probably no
+ * place else. Nonportable bits really need to be factored out, and
+ * the result made cleaner.
+ */
+
+#include <libmaple/usb_cdcacm.h>
+
+#include <libmaple/usb.h>
+#include <libmaple/nvic.h>
+#include <libmaple/delay.h>
+
+/* Private headers */
+#include "usb_lib_globals.h"
+#include "usb_reg_map.h"
+
+/* usb_lib headers */
+#include "usb_type.h"
+#include "usb_core.h"
+#include "usb_def.h"
+
+/******************************************************************************
+ ******************************************************************************
+ ***
+ *** HACK ALERT! FIXME FIXME FIXME FIXME!
+ ***
+ *** A bunch of LeafLabs-specific configuration lives in here for
+ *** now. This mess REALLY needs to get teased apart, with
+ *** appropriate pieces moved into Wirish.
+ ***
+ ******************************************************************************
+ *****************************************************************************/
+
+#if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \
+ defined(BOARD_maple_mini) || defined(BOARD_maple_native))
+#warning USB CDC ACM relies on LeafLabs board-specific configuration.\
+ You may have problems on non-LeafLabs boards.
+#endif
+
+static void vcomDataTxCb(void);
+static void vcomDataRxCb(void);
+static uint8* vcomGetSetLineCoding(uint16);
+
+static void usbInit(void);
+static void usbReset(void);
+static RESULT usbDataSetup(uint8 request);
+static RESULT usbNoDataSetup(uint8 request);
+static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting);
+static uint8* usbGetDeviceDescriptor(uint16 length);
+static uint8* usbGetConfigDescriptor(uint16 length);
+static uint8* usbGetStringDescriptor(uint16 length);
+static void usbSetConfiguration(void);
+static void usbSetDeviceAddress(void);
+
+/*
+ * Descriptors
+ */
+
+/* FIXME move to Wirish */
+#define LEAFLABS_ID_VENDOR 0x1EAF
+#define MAPLE_ID_PRODUCT 0x0004
+static const usb_descriptor_device usbVcomDescriptor_Device =
+ USB_CDCACM_DECLARE_DEV_DESC(LEAFLABS_ID_VENDOR, MAPLE_ID_PRODUCT);
+
+typedef struct {
+ usb_descriptor_config_header Config_Header;
+ usb_descriptor_interface CCI_Interface;
+ CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader;
+ CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement;
+ CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_ACM;
+ CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union;
+ usb_descriptor_endpoint ManagementEndpoint;
+ usb_descriptor_interface DCI_Interface;
+ usb_descriptor_endpoint DataOutEndpoint;
+ usb_descriptor_endpoint DataInEndpoint;
+} __packed usb_descriptor_config;
+
+#define MAX_POWER (100 >> 1)
+static const usb_descriptor_config usbVcomDescriptor_Config = {
+ .Config_Header = {
+ .bLength = sizeof(usb_descriptor_config_header),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION,
+ .wTotalLength = sizeof(usb_descriptor_config),
+ .bNumInterfaces = 0x02,
+ .bConfigurationValue = 0x01,
+ .iConfiguration = 0x00,
+ .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED |
+ USB_CONFIG_ATTR_SELF_POWERED),
+ .bMaxPower = MAX_POWER,
+ },
+
+ .CCI_Interface = {
+ .bLength = sizeof(usb_descriptor_interface),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x01,
+ .bInterfaceClass = USB_INTERFACE_CLASS_CDC,
+ .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_CDC_ACM,
+ .bInterfaceProtocol = 0x01, /* Common AT Commands */
+ .iInterface = 0x00,
+ },
+
+ .CDC_Functional_IntHeader = {
+ .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
+ .bDescriptorType = 0x24,
+ .SubType = 0x00,
+ .Data = {0x01, 0x10},
+ },
+
+ .CDC_Functional_CallManagement = {
+ .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
+ .bDescriptorType = 0x24,
+ .SubType = 0x01,
+ .Data = {0x03, 0x01},
+ },
+
+ .CDC_Functional_ACM = {
+ .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1),
+ .bDescriptorType = 0x24,
+ .SubType = 0x02,
+ .Data = {0x06},
+ },
+
+ .CDC_Functional_Union = {
+ .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
+ .bDescriptorType = 0x24,
+ .SubType = 0x06,
+ .Data = {0x00, 0x01},
+ },
+
+ .ManagementEndpoint = {
+ .bLength = sizeof(usb_descriptor_endpoint),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
+ .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN |
+ USB_CDCACM_MANAGEMENT_ENDP),
+ .bmAttributes = USB_EP_TYPE_INTERRUPT,
+ .wMaxPacketSize = USB_CDCACM_MANAGEMENT_EPSIZE,
+ .bInterval = 0xFF,
+ },
+
+ .DCI_Interface = {
+ .bLength = sizeof(usb_descriptor_interface),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
+ .bInterfaceNumber = 0x01,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x02,
+ .bInterfaceClass = USB_INTERFACE_CLASS_DIC,
+ .bInterfaceSubClass = 0x00, /* None */
+ .bInterfaceProtocol = 0x00, /* None */
+ .iInterface = 0x00,
+ },
+
+ .DataOutEndpoint = {
+ .bLength = sizeof(usb_descriptor_endpoint),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
+ .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT |
+ USB_CDCACM_RX_ENDP),
+ .bmAttributes = USB_EP_TYPE_BULK,
+ .wMaxPacketSize = USB_CDCACM_RX_EPSIZE,
+ .bInterval = 0x00,
+ },
+
+ .DataInEndpoint = {
+ .bLength = sizeof(usb_descriptor_endpoint),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
+ .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | USB_CDCACM_TX_ENDP),
+ .bmAttributes = USB_EP_TYPE_BULK,
+ .wMaxPacketSize = USB_CDCACM_TX_EPSIZE,
+ .bInterval = 0x00,
+ },
+};
+
+/*
+ String Descriptors:
+
+ we may choose to specify any or none of the following string
+ identifiers:
+
+ iManufacturer: LeafLabs
+ iProduct: Maple
+ iSerialNumber: NONE
+ iConfiguration: NONE
+ iInterface(CCI): NONE
+ iInterface(DCI): NONE
+
+*/
+
+/* Unicode language identifier: 0x0409 is US English */
+/* FIXME move to Wirish */
+static const usb_descriptor_string usbVcomDescriptor_LangID = {
+ .bLength = USB_DESCRIPTOR_STRING_LEN(1),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
+ .bString = {0x09, 0x04},
+};
+
+/* FIXME move to Wirish */
+static const usb_descriptor_string usbVcomDescriptor_iManufacturer = {
+ .bLength = USB_DESCRIPTOR_STRING_LEN(8),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
+ .bString = {'L', 0, 'e', 0, 'a', 0, 'f', 0,
+ 'L', 0, 'a', 0, 'b', 0, 's', 0},
+};
+
+/* FIXME move to Wirish */
+static const usb_descriptor_string usbVcomDescriptor_iProduct = {
+ .bLength = USB_DESCRIPTOR_STRING_LEN(5),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
+ .bString = {'M', 0, 'a', 0, 'p', 0, 'l', 0, 'e', 0},
+};
+
+static ONE_DESCRIPTOR Device_Descriptor = {
+ (uint8*)&usbVcomDescriptor_Device,
+ sizeof(usb_descriptor_device)
+};
+
+static ONE_DESCRIPTOR Config_Descriptor = {
+ (uint8*)&usbVcomDescriptor_Config,
+ sizeof(usb_descriptor_config)
+};
+
+#define N_STRING_DESCRIPTORS 3
+static ONE_DESCRIPTOR String_Descriptor[N_STRING_DESCRIPTORS] = {
+ {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)},
+ {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)},
+ {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(5)}
+};
+
+/*
+ * Etc.
+ */
+
+/* I/O state */
+
+/* Received data */
+static volatile uint8 vcomBufferRx[USB_CDCACM_RX_EPSIZE];
+/* Read index into vcomBufferRx */
+static volatile uint32 rx_offset = 0;
+/* Number of bytes left to transmit */
+static volatile uint32 n_unsent_bytes = 0;
+/* Are we currently sending an IN packet? */
+static volatile uint8 transmitting = 0;
+/* Number of unread bytes */
+static volatile uint32 n_unread_bytes = 0;
+
+/* Other state (line coding, DTR/RTS) */
+
+static volatile usb_cdcacm_line_coding line_coding = {
+ /* This default is 115200 baud, 8N1. */
+ .dwDTERate = 115200,
+ .bCharFormat = USB_CDCACM_STOP_BITS_1,
+ .bParityType = USB_CDCACM_PARITY_NONE,
+ .bDataBits = 8,
+};
+
+/* DTR in bit 0, RTS in bit 1. */
+static volatile uint8 line_dtr_rts = 0;
+
+/*
+ * Endpoint callbacks
+ */
+
+static void (*ep_int_in[7])(void) =
+ {vcomDataTxCb,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process};
+
+static void (*ep_int_out[7])(void) =
+ {NOP_Process,
+ NOP_Process,
+ vcomDataRxCb,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process};
+
+/*
+ * Globals required by usb_lib/
+ *
+ * Mark these weak so they can be overriden to implement other USB
+ * functionality.
+ */
+
+#define NUM_ENDPTS 0x04
+__weak DEVICE Device_Table = {
+ .Total_Endpoint = NUM_ENDPTS,
+ .Total_Configuration = 1
+};
+
+#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */
+__weak DEVICE_PROP Device_Property = {
+ .Init = usbInit,
+ .Reset = usbReset,
+ .Process_Status_IN = NOP_Process,
+ .Process_Status_OUT = NOP_Process,
+ .Class_Data_Setup = usbDataSetup,
+ .Class_NoData_Setup = usbNoDataSetup,
+ .Class_Get_Interface_Setting = usbGetInterfaceSetting,
+ .GetDeviceDescriptor = usbGetDeviceDescriptor,
+ .GetConfigDescriptor = usbGetConfigDescriptor,
+ .GetStringDescriptor = usbGetStringDescriptor,
+ .RxEP_buffer = NULL,
+ .MaxPacketSize = MAX_PACKET_SIZE
+};
+
+__weak USER_STANDARD_REQUESTS User_Standard_Requests = {
+ .User_GetConfiguration = NOP_Process,
+ .User_SetConfiguration = usbSetConfiguration,
+ .User_GetInterface = NOP_Process,
+ .User_SetInterface = NOP_Process,
+ .User_GetStatus = NOP_Process,
+ .User_ClearFeature = NOP_Process,
+ .User_SetEndPointFeature = NOP_Process,
+ .User_SetDeviceFeature = NOP_Process,
+ .User_SetDeviceAddress = usbSetDeviceAddress
+};
+
+/*
+ * User hooks
+ */
+
+static void (*rx_hook)(unsigned, void*) = 0;
+static void (*iface_setup_hook)(unsigned, void*) = 0;
+
+void usb_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)) {
+ if (hook_flags & USB_CDCACM_HOOK_RX) {
+ rx_hook = hook;
+ }
+ if (hook_flags & USB_CDCACM_HOOK_IFACE_SETUP) {
+ iface_setup_hook = hook;
+ }
+}
+
+/*
+ * CDC ACM interface
+ */
+
+void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) {
+ /* Present ourselves to the host. Writing 0 to "disc" pin must
+ * pull USB_DP pin up while leaving USB_DM pulled down by the
+ * transceiver. See USB 2.0 spec, section 7.1.7.3. */
+ gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP);
+ gpio_write_bit(disc_dev, disc_bit, 0);
+
+ /* Initialize the USB peripheral. */
+ usb_init_usblib(USBLIB, ep_int_in, ep_int_out);
+}
+
+void usb_cdcacm_disable(gpio_dev *disc_dev, uint8 disc_bit) {
+ /* Turn off the interrupt and signal disconnect (see e.g. USB 2.0
+ * spec, section 7.1.7.3). */
+ nvic_irq_disable(NVIC_USB_LP_CAN_RX0);
+ gpio_write_bit(disc_dev, disc_bit, 1);
+}
+
+void usb_cdcacm_putc(char ch) {
+ while (!usb_cdcacm_tx((uint8*)&ch, 1))
+ ;
+}
+
+/* This function is non-blocking.
+ *
+ * It copies data from a usercode buffer into the USB peripheral TX
+ * buffer, and returns the number of bytes copied. */
+uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) {
+ /* Last transmission hasn't finished, so abort. */
+ if (usb_cdcacm_is_transmitting()) {
+ return 0;
+ }
+
+ /* We can only put USB_CDCACM_TX_EPSIZE bytes in the buffer. */
+ if (len > USB_CDCACM_TX_EPSIZE) {
+ len = USB_CDCACM_TX_EPSIZE;
+ }
+
+ /* Queue bytes for sending. */
+ if (len) {
+ usb_copy_to_pma(buf, len, USB_CDCACM_TX_ADDR);
+ }
+ // We still need to wait for the interrupt, even if we're sending
+ // zero bytes. (Sending zero-size packets is useful for flushing
+ // host-side buffers.)
+ usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, len);
+ n_unsent_bytes = len;
+ transmitting = 1;
+ usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID);
+
+ return len;
+}
+
+uint32 usb_cdcacm_data_available(void) {
+ return n_unread_bytes;
+}
+
+uint8 usb_cdcacm_is_transmitting(void) {
+ return transmitting;
+}
+
+uint16 usb_cdcacm_get_pending(void) {
+ return n_unsent_bytes;
+}
+
+/* Nonblocking byte receive.
+ *
+ * Copies up to len bytes from our private data buffer (*NOT* the PMA)
+ * into buf and deq's the FIFO. */
+uint32 usb_cdcacm_rx(uint8* buf, uint32 len) {
+ /* Copy bytes to buffer. */
+ uint32 n_copied = usb_cdcacm_peek(buf, len);
+
+ /* Mark bytes as read. */
+ n_unread_bytes -= n_copied;
+ rx_offset += n_copied;
+
+ /* If all bytes have been read, re-enable the RX endpoint, which
+ * was set to NAK when the current batch of bytes was received. */
+ if (n_unread_bytes == 0) {
+ usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE);
+ usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
+ rx_offset = 0;
+ }
+
+ return n_copied;
+}
+
+/* Nonblocking byte lookahead.
+ *
+ * Looks at unread bytes without marking them as read. */
+uint32 usb_cdcacm_peek(uint8* buf, uint32 len) {
+ int i;
+
+ if (len > n_unread_bytes) {
+ len = n_unread_bytes;
+ }
+
+ for (i = 0; i < len; i++) {
+ buf[i] = vcomBufferRx[i + rx_offset];
+ }
+
+ return len;
+}
+
+uint8 usb_cdcacm_get_dtr() {
+ return ((line_dtr_rts & USB_CDCACM_CONTROL_LINE_DTR) != 0);
+}
+
+uint8 usb_cdcacm_get_rts() {
+ return ((line_dtr_rts & USB_CDCACM_CONTROL_LINE_RTS) != 0);
+}
+
+void usb_cdcacm_get_line_coding(usb_cdcacm_line_coding *ret) {
+ ret->dwDTERate = line_coding.dwDTERate;
+ ret->bCharFormat = line_coding.bCharFormat;
+ ret->bParityType = line_coding.bParityType;
+ ret->bDataBits = line_coding.bDataBits;
+}
+
+int usb_cdcacm_get_baud(void) {
+ return line_coding.dwDTERate;
+}
+
+int usb_cdcacm_get_stop_bits(void) {
+ return line_coding.bCharFormat;
+}
+
+int usb_cdcacm_get_parity(void) {
+ return line_coding.bParityType;
+}
+
+int usb_cdcacm_get_n_data_bits(void) {
+ return line_coding.bDataBits;
+}
+
+
+/*
+ * Callbacks
+ */
+
+static void vcomDataTxCb(void) {
+ n_unsent_bytes = 0;
+ transmitting = 0;
+}
+
+static void vcomDataRxCb(void) {
+ usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_NAK);
+ n_unread_bytes = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP);
+ /* This copy won't overwrite unread bytes, since we've set the RX
+ * endpoint to NAK, and will only set it to VALID when all bytes
+ * have been read. */
+ usb_copy_from_pma((uint8*)vcomBufferRx, n_unread_bytes,
+ USB_CDCACM_RX_ADDR);
+
+
+ if (n_unread_bytes == 0) {
+ usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE);
+ usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
+ rx_offset = 0;
+ }
+
+ if (rx_hook) {
+ rx_hook(USB_CDCACM_HOOK_RX, 0);
+ }
+}
+
+static uint8* vcomGetSetLineCoding(uint16 length) {
+ if (length == 0) {
+ pInformation->Ctrl_Info.Usb_wLength = sizeof(struct usb_cdcacm_line_coding);
+ }
+ return (uint8*)&line_coding;
+}
+
+static void usbInit(void) {
+ pInformation->Current_Configuration = 0;
+
+ USB_BASE->CNTR = USB_CNTR_FRES;
+
+ USBLIB->irq_mask = 0;
+ USB_BASE->CNTR = USBLIB->irq_mask;
+ USB_BASE->ISTR = 0;
+ USBLIB->irq_mask = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
+ USB_BASE->CNTR = USBLIB->irq_mask;
+
+ USB_BASE->ISTR = 0;
+ USBLIB->irq_mask = USB_ISR_MSK;
+ USB_BASE->CNTR = USBLIB->irq_mask;
+
+ nvic_irq_enable(NVIC_USB_LP_CAN_RX0);
+ USBLIB->state = USB_UNCONNECTED;
+}
+
+#define BTABLE_ADDRESS 0x00
+static void usbReset(void) {
+ pInformation->Current_Configuration = 0;
+
+ /* current feature is current bmAttributes */
+ pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED |
+ USB_CONFIG_ATTR_SELF_POWERED);
+
+ USB_BASE->BTABLE = BTABLE_ADDRESS;
+
+ /* setup control endpoint 0 */
+ usb_set_ep_type(USB_EP0, USB_EP_EP_TYPE_CONTROL);
+ usb_set_ep_tx_stat(USB_EP0, USB_EP_STAT_TX_STALL);
+ usb_set_ep_rx_addr(USB_EP0, USB_CDCACM_CTRL_RX_ADDR);
+ usb_set_ep_tx_addr(USB_EP0, USB_CDCACM_CTRL_TX_ADDR);
+ usb_clear_status_out(USB_EP0);
+
+ usb_set_ep_rx_count(USB_EP0, pProperty->MaxPacketSize);
+ usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID);
+
+ /* setup management endpoint 1 */
+ usb_set_ep_type(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_EP_TYPE_INTERRUPT);
+ usb_set_ep_tx_addr(USB_CDCACM_MANAGEMENT_ENDP,
+ USB_CDCACM_MANAGEMENT_ADDR);
+ usb_set_ep_tx_stat(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_STAT_TX_NAK);
+ usb_set_ep_rx_stat(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_STAT_RX_DISABLED);
+
+ /* TODO figure out differences in style between RX/TX EP setup */
+
+ /* set up data endpoint OUT (RX) */
+ usb_set_ep_type(USB_CDCACM_RX_ENDP, USB_EP_EP_TYPE_BULK);
+ usb_set_ep_rx_addr(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_ADDR);
+ usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE);
+ usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
+
+ /* set up data endpoint IN (TX) */
+ usb_set_ep_type(USB_CDCACM_TX_ENDP, USB_EP_EP_TYPE_BULK);
+ usb_set_ep_tx_addr(USB_CDCACM_TX_ENDP, USB_CDCACM_TX_ADDR);
+ usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_NAK);
+ usb_set_ep_rx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_RX_DISABLED);
+
+ USBLIB->state = USB_ATTACHED;
+ SetDeviceAddress(0);
+
+ /* Reset the RX/TX state */
+ n_unread_bytes = 0;
+ n_unsent_bytes = 0;
+ rx_offset = 0;
+ transmitting = 0;
+}
+
+static RESULT usbDataSetup(uint8 request) {
+ uint8* (*CopyRoutine)(uint16) = 0;
+
+ if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
+ switch (request) {
+ case USB_CDCACM_GET_LINE_CODING:
+ CopyRoutine = vcomGetSetLineCoding;
+ break;
+ case USB_CDCACM_SET_LINE_CODING:
+ CopyRoutine = vcomGetSetLineCoding;
+ break;
+ default:
+ break;
+ }
+
+ /* Call the user hook. */
+ if (iface_setup_hook) {
+ uint8 req_copy = request;
+ iface_setup_hook(USB_CDCACM_HOOK_IFACE_SETUP, &req_copy);
+ }
+ }
+
+ if (CopyRoutine == NULL) {
+ return USB_UNSUPPORT;
+ }
+
+ pInformation->Ctrl_Info.CopyData = CopyRoutine;
+ pInformation->Ctrl_Info.Usb_wOffset = 0;
+ (*CopyRoutine)(0);
+ return USB_SUCCESS;
+}
+
+static RESULT usbNoDataSetup(uint8 request) {
+ RESULT ret = USB_UNSUPPORT;
+
+ if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
+ switch (request) {
+ case USB_CDCACM_SET_COMM_FEATURE:
+ /* We support set comm. feature, but don't handle it. */
+ ret = USB_SUCCESS;
+ break;
+ case USB_CDCACM_SET_CONTROL_LINE_STATE:
+ /* Track changes to DTR and RTS. */
+ line_dtr_rts = (pInformation->USBwValues.bw.bb0 &
+ (USB_CDCACM_CONTROL_LINE_DTR |
+ USB_CDCACM_CONTROL_LINE_RTS));
+ ret = USB_SUCCESS;
+ break;
+ }
+
+ /* Call the user hook. */
+ if (iface_setup_hook) {
+ uint8 req_copy = request;
+ iface_setup_hook(USB_CDCACM_HOOK_IFACE_SETUP, &req_copy);
+ }
+ }
+ return ret;
+}
+
+static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) {
+ if (alt_setting > 0) {
+ return USB_UNSUPPORT;
+ } else if (interface > 1) {
+ return USB_UNSUPPORT;
+ }
+
+ return USB_SUCCESS;
+}
+
+static uint8* usbGetDeviceDescriptor(uint16 length) {
+ return Standard_GetDescriptorData(length, &Device_Descriptor);
+}
+
+static uint8* usbGetConfigDescriptor(uint16 length) {
+ return Standard_GetDescriptorData(length, &Config_Descriptor);
+}
+
+static uint8* usbGetStringDescriptor(uint16 length) {
+ uint8 wValue0 = pInformation->USBwValue0;
+
+ if (wValue0 > N_STRING_DESCRIPTORS) {
+ return NULL;
+ }
+ return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]);
+}
+
+static void usbSetConfiguration(void) {
+ if (pInformation->Current_Configuration != 0) {
+ USBLIB->state = USB_CONFIGURED;
+ }
+}
+
+static void usbSetDeviceAddress(void) {
+ USBLIB->state = USB_ADDRESSED;
+}
diff --git a/libmaple/usb/stm32f1/usb_lib_globals.h b/libmaple/usb/stm32f1/usb_lib_globals.h
new file mode 100644
index 0000000..1cd2754
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_lib_globals.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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_LIB_GLOBALS_H_
+#define _USB_LIB_GLOBALS_H_
+
+/* usb_lib headers */
+#include "usb_type.h"
+#include "usb_core.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern USER_STANDARD_REQUESTS User_Standard_Requests;
+extern USER_STANDARD_REQUESTS *pUser_Standard_Requests;
+
+extern DEVICE_PROP Device_Property;
+extern DEVICE_PROP *pProperty;
+
+extern DEVICE_INFO Device_Info;
+extern DEVICE_INFO *pInformation;
+
+extern DEVICE Device_Table;
+extern u16 SaveRState;
+extern u16 SaveTState;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/usb/stm32f1/usb_reg_map.c b/libmaple/usb/stm32f1/usb_reg_map.c
new file mode 100644
index 0000000..ea60cb3
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_reg_map.c
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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 "usb_reg_map.h"
+
+/* TODO these could use some improvement; they're fairly
+ * straightforward ports of the analogous ST code. The PMA blit
+ * routines in particular are obvious targets for performance
+ * measurement and tuning. */
+
+void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) {
+ uint16 *dst = (uint16*)usb_pma_ptr(pma_offset);
+ uint16 n = len >> 1;
+ uint16 i;
+ for (i = 0; i < n; i++) {
+ *dst = (uint16)(*buf) | *(buf + 1) << 8;
+ buf += 2;
+ dst += 2;
+ }
+ if (len & 1) {
+ *dst = *buf;
+ }
+}
+
+void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) {
+ uint32 *src = (uint32*)usb_pma_ptr(pma_offset);
+ uint16 *dst = (uint16*)buf;
+ uint16 n = len >> 1;
+ uint16 i;
+ for (i = 0; i < n; i++) {
+ *dst++ = *src++;
+ }
+ if (len & 1) {
+ *dst = *src & 0xFF;
+ }
+}
+
+static void usb_set_ep_rx_count_common(uint32 *rxc, uint16 count) {
+ uint16 nblocks;
+ if (count > 62) {
+ /* use 32-byte memory block size */
+ nblocks = count >> 5;
+ if ((count & 0x1F) == 0) {
+ nblocks--;
+ }
+ *rxc = (nblocks << 10) | 0x8000;
+ } else {
+ /* use 2-byte memory block size */
+ nblocks = count >> 1;
+ if ((count & 0x1) != 0) {
+ nblocks++;
+ }
+ *rxc = nblocks << 10;
+ }
+}
+
+void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count) {
+ uint32 *rxc = usb_ep_rx_buf0_count_ptr(ep);
+ usb_set_ep_rx_count_common(rxc, count);
+}
+
+void usb_set_ep_rx_count(uint8 ep, uint16 count) {
+ uint32 *rxc = usb_ep_rx_count_ptr(ep);
+ usb_set_ep_rx_count_common(rxc, count);
+}
diff --git a/libmaple/usb/stm32f1/usb_reg_map.h b/libmaple/usb/stm32f1/usb_reg_map.h
new file mode 100644
index 0000000..2e3f6bc
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_reg_map.h
@@ -0,0 +1,617 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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 <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
+
+#ifndef _USB_REG_MAP_H_
+#define _USB_REG_MAP_H_
+
+/* TODO:
+ * - Pick one of "endp", "ep" "endpt"
+ */
+
+/*
+ * Register map and base pointer
+ */
+
+#define USB_NR_EP_REGS 8
+
+/** USB register map type */
+typedef struct usb_reg_map {
+ __io uint32 EP[USB_NR_EP_REGS]; /**< Endpoint registers */
+ const uint32 RESERVED[8]; /**< Reserved */
+ __io uint32 CNTR; /**< Control register */
+ __io uint32 ISTR; /**< Interrupt status register */
+ __io uint32 FNR; /**< Frame number register */
+ __io uint32 DADDR; /**< Device address */
+ __io uint32 BTABLE; /**< @brief Buffer table address
+ *
+ * Address offset within the USB
+ * packet memory area which points
+ * to the base of the buffer
+ * descriptor table. Must be
+ * aligned to an 8 byte boundary.
+ */
+} usb_reg_map;
+
+/** USB register map base pointer */
+#define USB_BASE ((struct usb_reg_map*)0x40005C00)
+
+/*
+ * Register bit definitions
+ */
+
+/* Endpoint registers (USB_EPnR) */
+
+#define USB_EP_CTR_RX_BIT 15
+#define USB_EP_DTOG_RX_BIT 14
+#define USB_EP_SETUP_BIT 11
+#define USB_EP_EP_KIND_BIT 8
+#define USB_EP_CTR_TX_BIT 7
+#define USB_EP_DTOG_TX_BIT 6
+
+#define USB_EP_CTR_RX BIT(USB_EP_CTR_RX_BIT)
+#define USB_EP_DTOG_RX BIT(USB_EP_DTOG_RX_BIT)
+#define USB_EP_STAT_RX (0x3 << 12)
+#define USB_EP_STAT_RX_DISABLED (0x0 << 12)
+#define USB_EP_STAT_RX_STALL (0x1 << 12)
+#define USB_EP_STAT_RX_NAK (0x2 << 12)
+#define USB_EP_STAT_RX_VALID (0x3 << 12)
+#define USB_EP_SETUP BIT(USB_EP_SETUP_BIT)
+#define USB_EP_EP_TYPE (0x3 << 9)
+#define USB_EP_EP_TYPE_BULK (0x0 << 9)
+#define USB_EP_EP_TYPE_CONTROL (0x1 << 9)
+#define USB_EP_EP_TYPE_ISO (0x2 << 9)
+#define USB_EP_EP_TYPE_INTERRUPT (0x3 << 9)
+#define USB_EP_EP_KIND BIT(USB_EP_EP_KIND_BIT)
+#define USB_EP_EP_KIND_DBL_BUF (0x1 << USB_EP_EP_KIND_BIT)
+#define USB_EP_CTR_TX BIT(USB_EP_CTR_TX_BIT)
+#define USB_EP_DTOG_TX BIT(USB_EP_DTOG_TX_BIT)
+#define USB_EP_STAT_TX (0x3 << 4)
+#define USB_EP_STAT_TX_DISABLED (0x0 << 4)
+#define USB_EP_STAT_TX_STALL (0x1 << 4)
+#define USB_EP_STAT_TX_NAK (0x2 << 4)
+#define USB_EP_STAT_TX_VALID (0x3 << 4)
+#define USB_EP_EA 0xF
+
+/* Control register (USB_CNTR) */
+
+#define USB_CNTR_CTRM_BIT 15
+#define USB_CNTR_PMAOVERM_BIT 14
+#define USB_CNTR_ERRM_BIT 13
+#define USB_CNTR_WKUPM_BIT 12
+#define USB_CNTR_SUSPM_BIT 11
+#define USB_CNTR_RESETM_BIT 10
+#define USB_CNTR_SOFM_BIT 9
+#define USB_CNTR_ESOFM_BIT 8
+#define USB_CNTR_RESUME_BIT 4
+#define USB_CNTR_FSUSP_BIT 3
+#define USB_CNTR_LP_MODE_BIT 2
+#define USB_CNTR_PDWN_BIT 1
+#define USB_CNTR_FRES_BIT 0
+
+#define USB_CNTR_CTRM BIT(USB_CNTR_CTRM_BIT)
+#define USB_CNTR_PMAOVERM BIT(USB_CNTR_PMAOVERM_BIT)
+#define USB_CNTR_ERRM BIT(USB_CNTR_ERRM_BIT)
+#define USB_CNTR_WKUPM BIT(USB_CNTR_WKUPM_BIT)
+#define USB_CNTR_SUSPM BIT(USB_CNTR_SUSPM_BIT)
+#define USB_CNTR_RESETM BIT(USB_CNTR_RESETM_BIT)
+#define USB_CNTR_SOFM BIT(USB_CNTR_SOFM_BIT)
+#define USB_CNTR_ESOFM BIT(USB_CNTR_ESOFM_BIT)
+#define USB_CNTR_RESUME BIT(USB_CNTR_RESUME_BIT)
+#define USB_CNTR_FSUSP BIT(USB_CNTR_FSUSP_BIT)
+#define USB_CNTR_LP_MODE BIT(USB_CNTR_LP_MODE_BIT)
+#define USB_CNTR_PDWN BIT(USB_CNTR_PDWN_BIT)
+#define USB_CNTR_FRES BIT(USB_CNTR_FRES_BIT)
+
+/* Interrupt status register (USB_ISTR) */
+
+#define USB_ISTR_CTR_BIT 15
+#define USB_ISTR_PMAOVR_BIT 14
+#define USB_ISTR_ERR_BIT 13
+#define USB_ISTR_WKUP_BIT 12
+#define USB_ISTR_SUSP_BIT 11
+#define USB_ISTR_RESET_BIT 10
+#define USB_ISTR_SOF_BIT 9
+#define USB_ISTR_ESOF_BIT 8
+#define USB_ISTR_DIR_BIT 4
+
+#define USB_ISTR_CTR BIT(USB_ISTR_CTR_BIT)
+#define USB_ISTR_PMAOVR BIT(USB_ISTR_PMAOVR_BIT)
+#define USB_ISTR_ERR BIT(USB_ISTR_ERR_BIT)
+#define USB_ISTR_WKUP BIT(USB_ISTR_WKUP_BIT)
+#define USB_ISTR_SUSP BIT(USB_ISTR_SUSP_BIT)
+#define USB_ISTR_RESET BIT(USB_ISTR_RESET_BIT)
+#define USB_ISTR_SOF BIT(USB_ISTR_SOF_BIT)
+#define USB_ISTR_ESOF BIT(USB_ISTR_ESOF_BIT)
+#define USB_ISTR_DIR BIT(USB_ISTR_DIR_BIT)
+#define USB_ISTR_EP_ID 0xF
+
+/* Frame number register (USB_FNR) */
+
+#define USB_FNR_RXDP_BIT 15
+#define USB_FNR_RXDM_BIT 14
+#define USB_FNR_LCK_BIT 13
+
+#define USB_FNR_RXDP BIT(USB_FNR_RXDP_BIT)
+#define USB_FNR_RXDM BIT(USB_FNR_RXDM_BIT)
+#define USB_FNR_LCK BIT(USB_FNR_LCK_BIT)
+#define USB_FNR_LSOF (0x3 << 11)
+#define USB_FNR_FN 0x7FF
+
+/* Device address (USB_DADDR) */
+
+#define USB_DADDR_EF_BIT 7
+#define USB_DADDR_ADD6_BIT 6
+#define USB_DADDR_ADD5_BIT 5
+#define USB_DADDR_ADD4_BIT 4
+#define USB_DADDR_ADD3_BIT 3
+#define USB_DADDR_ADD2_BIT 2
+#define USB_DADDR_ADD1_BIT 1
+#define USB_DADDR_ADD0_BIT 0
+
+#define USB_DADDR_EF BIT(USB_DADDR_EF_BIT)
+#define USB_DADDR_ADD6 BIT(USB_DADDR_ADD6_BIT)
+#define USB_DADDR_ADD5 BIT(USB_DADDR_ADD5_BIT)
+#define USB_DADDR_ADD4 BIT(USB_DADDR_ADD4_BIT)
+#define USB_DADDR_ADD3 BIT(USB_DADDR_ADD3_BIT)
+#define USB_DADDR_ADD2 BIT(USB_DADDR_ADD2_BIT)
+#define USB_DADDR_ADD1 BIT(USB_DADDR_ADD1_BIT)
+#define USB_DADDR_ADD0 BIT(USB_DADDR_ADD0_BIT)
+
+/* Buffer table address (USB_BTABLE) */
+
+#define USB_BTABLE_BTABLE (0x1FFF << 3)
+
+/*
+ * Register convenience routines
+ */
+
+#define __EP_CTR_NOP (USB_EP_CTR_RX | USB_EP_CTR_TX)
+#define __EP_NONTOGGLE (USB_EP_CTR_RX | USB_EP_SETUP | \
+ USB_EP_EP_TYPE | USB_EP_EP_KIND | \
+ USB_EP_CTR_TX | USB_EP_EA)
+
+static inline void usb_clear_ctr_rx(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ USB_BASE->EP[ep] = epr & ~USB_EP_CTR_RX & __EP_NONTOGGLE;
+}
+
+static inline void usb_clear_ctr_tx(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ USB_BASE->EP[ep] = epr & ~USB_EP_CTR_TX & __EP_NONTOGGLE;
+}
+
+static inline uint32 usb_get_ep_dtog_tx(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ return epr & USB_EP_DTOG_TX;
+}
+
+static inline uint32 usb_get_ep_dtog_rx(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ return epr & USB_EP_DTOG_RX;
+}
+
+static inline uint32 usb_get_ep_tx_sw_buf(uint8 ep) {
+ return usb_get_ep_dtog_rx(ep);
+}
+
+static inline uint32 usb_get_ep_rx_sw_buf(uint8 ep) {
+ return usb_get_ep_dtog_tx(ep);
+}
+
+static inline void usb_toggle_ep_dtog_tx(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= __EP_NONTOGGLE;
+ epr |= USB_EP_DTOG_TX;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_toggle_ep_dtog_rx(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= __EP_NONTOGGLE;
+ epr |= USB_EP_DTOG_RX;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_clear_ep_dtog_tx(uint8 ep) {
+ if (usb_get_ep_dtog_tx(ep) != 0) {
+ usb_toggle_ep_dtog_tx(ep);
+ }
+}
+
+static inline void usb_clear_ep_dtog_rx(uint8 ep) {
+ if (usb_get_ep_dtog_rx(ep) != 0) {
+ usb_toggle_ep_dtog_rx(ep);
+ }
+}
+
+static inline void usb_set_ep_dtog_tx(uint8 ep) {
+ if (usb_get_ep_dtog_tx(ep) == 0) {
+ usb_toggle_ep_dtog_tx(ep);
+ }
+}
+
+static inline void usb_set_ep_dtog_rx(uint8 ep) {
+ if (usb_get_ep_dtog_rx(ep) == 0) {
+ usb_toggle_ep_dtog_rx(ep);
+ }
+}
+
+static inline void usb_toggle_ep_rx_sw_buf(uint8 ep) {
+ usb_toggle_ep_dtog_tx(ep);
+}
+
+static inline void usb_toggle_ep_tx_sw_buf(uint8 ep) {
+ usb_toggle_ep_dtog_rx(ep);
+}
+
+static inline void usb_clear_ep_rx_sw_buf(uint8 ep) {
+ usb_clear_ep_dtog_tx(ep);
+}
+
+static inline void usb_clear_ep_tx_sw_buf(uint8 ep) {
+ usb_clear_ep_dtog_rx(ep);
+}
+
+static inline void usb_set_ep_rx_sw_buf(uint8 ep) {
+ usb_set_ep_dtog_tx(ep);
+}
+
+static inline void usb_set_ep_tx_sw_buf(uint8 ep) {
+ usb_set_ep_dtog_rx(ep);
+}
+
+static inline void usb_set_ep_rx_stat(uint8 ep, uint32 status) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= ~(USB_EP_STAT_TX | USB_EP_DTOG_RX | USB_EP_DTOG_TX);
+ epr |= __EP_CTR_NOP;
+ epr ^= status;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_set_ep_tx_stat(uint8 ep, uint32 status) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= ~(USB_EP_STAT_RX | USB_EP_DTOG_RX | USB_EP_DTOG_TX);
+ epr |= __EP_CTR_NOP;
+ epr ^= status;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_set_ep_type(uint8 ep, uint32 type) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= ~USB_EP_EP_TYPE & __EP_NONTOGGLE;
+ epr |= type;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_set_ep_kind(uint8 ep, uint32 kind) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= ~USB_EP_EP_KIND & __EP_NONTOGGLE;
+ epr |= kind;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline uint32 usb_get_ep_type(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ return epr & USB_EP_EP_TYPE;
+}
+
+static inline uint32 usb_get_ep_kind(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ return epr & USB_EP_EP_TYPE;
+}
+
+
+static inline void usb_clear_status_out(uint8 ep) {
+ usb_set_ep_kind(ep, 0);
+}
+
+/*
+ * Packet memory area (PMA) base pointer
+ */
+
+/**
+ * @brief USB packet memory area (PMA) base pointer.
+ *
+ * The USB PMA is SRAM shared between USB and CAN. The USB peripheral
+ * accesses this memory directly via the packet buffer interface. */
+#define USB_PMA_BASE ((__io void*)0x40006000)
+
+/*
+ * PMA conveniences
+ */
+
+void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset);
+void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset);
+
+static inline void* usb_pma_ptr(uint32 offset) {
+ return (void*)(USB_PMA_BASE + 2 * offset);
+}
+
+/*
+ * BTABLE
+ */
+
+/* (Forward-declared) BTABLE entry.
+ *
+ * The BTABLE can be viewed as an array of usb_btable_ent values;
+ * these vary in structure according to the configuration of the
+ * endpoint.
+ */
+union usb_btable_ent;
+
+/* Bidirectional endpoint BTABLE entry */
+typedef struct usb_btable_bidi {
+ __io uint16 addr_tx; const uint16 PAD1;
+ __io uint16 count_tx; const uint16 PAD2;
+ __io uint16 addr_rx; const uint16 PAD3;
+ __io uint16 count_rx; const uint16 PAD4;
+} usb_btable_bidi;
+
+/* Unidirectional receive-only endpoint BTABLE entry */
+typedef struct usb_btable_uni_rx {
+ __io uint16 empty1; const uint16 PAD1;
+ __io uint16 empty2; const uint16 PAD2;
+ __io uint16 addr_rx; const uint16 PAD3;
+ __io uint16 count_rx; const uint16 PAD4;
+} usb_btable_uni_rx;
+
+/* Unidirectional transmit-only endpoint BTABLE entry */
+typedef struct usb_btable_uni_tx {
+ __io uint16 addr_tx; const uint16 PAD1;
+ __io uint16 count_tx; const uint16 PAD2;
+ __io uint16 empty1; const uint16 PAD3;
+ __io uint16 empty2; const uint16 PAD4;
+} usb_btable_uni_tx;
+
+/* Double-buffered transmission endpoint BTABLE entry */
+typedef struct usb_btable_dbl_tx {
+ __io uint16 addr_tx0; const uint16 PAD1;
+ __io uint16 count_tx0; const uint16 PAD2;
+ __io uint16 addr_tx1; const uint16 PAD3;
+ __io uint16 count_tx1; const uint16 PAD4;
+} usb_btable_dbl_tx;
+
+/* Double-buffered reception endpoint BTABLE entry */
+typedef struct usb_btable_dbl_rx {
+ __io uint16 addr_rx0; const uint16 PAD1;
+ __io uint16 count_rx0; const uint16 PAD2;
+ __io uint16 addr_rx1; const uint16 PAD3;
+ __io uint16 count_rx1; const uint16 PAD4;
+} usb_btable_dbl_rx;
+
+/* TODO isochronous endpoint entries */
+
+/* Definition for above forward-declared BTABLE entry. */
+typedef union usb_btable_ent {
+ usb_btable_bidi bidi;
+ usb_btable_uni_rx u_rx;
+ usb_btable_uni_tx u_tx;
+ usb_btable_dbl_tx d_tx;
+ usb_btable_dbl_rx d_rx;
+} usb_btable_ent;
+
+/*
+ * BTABLE conveniences
+ */
+
+/* TODO (?) Convert usages of the many (and lengthily-named)
+ * accessors/mutators below to just manipulating usb_btable_entry
+ * values. */
+
+static inline uint32* usb_btable_ptr(uint32 offset) {
+ return (uint32*)usb_pma_ptr(USB_BASE->BTABLE + offset);
+}
+
+/* TX address */
+
+static inline uint32* usb_ep_tx_addr_ptr(uint8 ep) {
+ return usb_btable_ptr(ep * 8);
+}
+
+static inline uint16 usb_get_ep_tx_addr(uint8 ep) {
+ return (uint16)*usb_ep_tx_addr_ptr(ep);
+}
+
+static inline void usb_set_ep_tx_addr(uint8 ep, uint16 addr) {
+ uint32 *tx_addr = usb_ep_tx_addr_ptr(ep);
+ *tx_addr = addr & ~0x1;
+}
+
+/* RX address */
+
+static inline uint32* usb_ep_rx_addr_ptr(uint8 ep) {
+ return usb_btable_ptr(ep * 8 + 4);
+}
+
+static inline uint16 usb_get_ep_rx_addr(uint8 ep) {
+ return (uint16)*usb_ep_rx_addr_ptr(ep);
+}
+
+static inline void usb_set_ep_rx_addr(uint8 ep, uint16 addr) {
+ uint32 *rx_addr = usb_ep_rx_addr_ptr(ep);
+ *rx_addr = addr & ~0x1;
+}
+
+/* TX count (doesn't cover double-buffered and isochronous in) */
+
+static inline uint32* usb_ep_tx_count_ptr(uint8 ep) {
+ return usb_btable_ptr(ep * 8 + 2);
+}
+
+static inline uint16 usb_get_ep_tx_count(uint8 ep) {
+ /* FIXME: this is broken somehow; calling it seems to
+ * confuse/crash the chip. */
+ return (uint16)(*usb_ep_tx_count_ptr(ep) & 0x3FF);
+}
+
+static inline void usb_set_ep_tx_count(uint8 ep, uint16 count) {
+ uint32 *txc = usb_ep_tx_count_ptr(ep);
+ *txc = count;
+}
+
+/* RX count */
+
+static inline uint32* usb_ep_rx_count_ptr(uint8 ep) {
+ return usb_btable_ptr(ep * 8 + 6);
+}
+
+static inline uint16 usb_get_ep_rx_count(uint8 ep) {
+ return (uint16)*usb_ep_rx_count_ptr(ep) & 0x3FF;
+}
+
+void usb_set_ep_rx_count(uint8 ep, uint16 count);
+
+/* double buffer definitions */
+static inline uint32* usb_get_ep_tx_buf0_addr_ptr(uint8 ep) {
+ return usb_ep_tx_addr_ptr(ep);
+}
+
+static inline uint16 usb_get_ep_tx_buf0_addr(uint8 ep) {
+ return usb_get_ep_tx_addr(ep);
+}
+
+static inline void usb_set_ep_tx_buf0_addr(uint8 ep, uint16 addr) {
+ usb_set_ep_tx_addr(ep, addr);
+}
+
+static inline uint32* usb_get_ep_tx_buf1_addr_ptr(uint8 ep) {
+ return usb_ep_rx_addr_ptr(ep);
+}
+
+static inline uint16 usb_get_ep_tx_buf1_addr(uint8 ep) {
+ return usb_get_ep_rx_addr(ep);
+}
+
+static inline void usb_set_ep_tx_buf1_addr(uint8 ep, uint16 addr) {
+ usb_set_ep_rx_addr(ep, addr);
+}
+
+static inline uint32* usb_ep_tx_buf0_count_ptr(uint8 ep) {
+ return usb_ep_tx_count_ptr(ep);
+}
+
+static inline uint16 usb_get_ep_tx_buf0_count(uint8 ep) {
+ return usb_get_ep_tx_count(ep);
+}
+
+static inline void usb_set_ep_tx_buf0_count(uint8 ep, uint16 count) {
+ usb_set_ep_tx_count(ep, count);
+}
+
+static inline uint32* usb_ep_tx_buf1_count_ptr(uint8 ep) {
+ return usb_ep_rx_count_ptr(ep);
+}
+
+static inline uint16 usb_get_ep_tx_buf1_count(uint8 ep) {
+ return usb_get_ep_rx_count(ep);
+}
+
+static inline void usb_set_ep_tx_buf1_count(uint8 ep, uint16 count) {
+ usb_set_ep_rx_count(ep, count);
+}
+static inline uint32* usb_get_ep_rx_buf0_addr_ptr(uint8 ep) {
+ return usb_ep_tx_addr_ptr(ep);
+}
+
+static inline uint16 usb_get_ep_rx_buf0_addr(uint8 ep) {
+ return usb_get_ep_tx_addr(ep);
+}
+
+static inline void usb_set_ep_rx_buf0_addr(uint8 ep, uint16 addr) {
+ usb_set_ep_tx_addr(ep, addr);
+}
+
+static inline uint32* usb_get_ep_rx_buf1_addr_ptr(uint8 ep) {
+ return usb_ep_rx_addr_ptr(ep);
+}
+
+static inline uint16 usb_get_ep_rx_buf1_addr(uint8 ep) {
+ return usb_get_ep_rx_addr(ep);
+}
+
+static inline void usb_set_ep_rx_buf1_addr(uint8 ep, uint16 addr) {
+ usb_set_ep_rx_addr(ep, addr);
+}
+
+static inline uint32* usb_ep_rx_buf0_count_ptr(uint8 ep) {
+ return usb_ep_tx_count_ptr(ep);
+}
+
+static inline uint16 usb_get_ep_rx_buf0_count(uint8 ep) {
+ return usb_get_ep_tx_count(ep);
+}
+
+void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count);
+
+static inline uint32* usb_ep_rx_buf1_count_ptr(uint8 ep) {
+ return usb_ep_rx_count_ptr(ep);
+}
+
+static inline uint16 usb_get_ep_rx_buf1_count(uint8 ep) {
+ return usb_get_ep_rx_count(ep);
+}
+
+static inline void usb_set_ep_rx_buf1_count(uint8 ep, uint16 count) {
+ usb_set_ep_rx_count(ep, count);
+}
+
+/*
+ * Misc. types
+ */
+
+typedef enum usb_ep {
+ USB_EP0,
+ USB_EP1,
+ USB_EP2,
+ USB_EP3,
+ USB_EP4,
+ USB_EP5,
+ USB_EP6,
+ USB_EP7,
+} usb_ep;
+
+typedef enum usb_ep_type {
+ USB_EP_T_CTL = USB_EP_EP_TYPE_CONTROL,
+ USB_EP_T_BULK = USB_EP_EP_TYPE_BULK,
+ USB_EP_T_INT = USB_EP_EP_TYPE_INTERRUPT,
+ USB_EP_T_ISO = USB_EP_EP_TYPE_ISO
+} usb_ep_type;
+
+typedef enum usb_ep_stat {
+ USB_EP_ST_RX_DIS = USB_EP_STAT_RX_DISABLED,
+ USB_EP_ST_RX_STL = USB_EP_STAT_RX_STALL,
+ USB_EP_ST_RX_NAK = USB_EP_STAT_RX_NAK,
+ USB_EP_ST_RX_VAL = USB_EP_STAT_RX_VALID,
+ USB_EP_ST_TX_DIS = USB_EP_STAT_TX_DISABLED,
+ USB_EP_ST_TX_STL = USB_EP_STAT_TX_STALL,
+ USB_EP_ST_TX_NAK = USB_EP_STAT_TX_NAK,
+ USB_EP_ST_TX_VAL = USB_EP_STAT_TX_VALID
+} usb_ep_stat;
+
+#endif
diff --git a/libmaple/usb/usb_lib/usb_core.c b/libmaple/usb/usb_lib/usb_core.c
new file mode 100644
index 0000000..5cf9e87
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_core.c
@@ -0,0 +1,1013 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_core.c
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Standard protocol processing (USB v2.0)
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Includes ------------------------------------------------------------------*/
+#include "usb_lib.h"
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+#define ValBit(VAR,Place) (VAR & (1 << Place))
+#define SetBit(VAR,Place) (VAR |= (1 << Place))
+#define ClrBit(VAR,Place) (VAR &= ((1 << Place) ^ 255))
+
+#define Send0LengthData() { _SetEPTxCount(ENDP0, 0); \
+ vSetEPTxStatus(EP_TX_VALID); \
+ }
+
+#define vSetEPRxStatus(st) (SaveRState = st)
+#define vSetEPTxStatus(st) (SaveTState = st)
+
+#define USB_StatusIn() Send0LengthData()
+#define USB_StatusOut() vSetEPRxStatus(EP_RX_VALID)
+
+#define StatusInfo0 StatusInfo.bw.bb1 /* Reverse bb0 & bb1 */
+#define StatusInfo1 StatusInfo.bw.bb0
+
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+u16_u8 StatusInfo;
+USB_Bool Data_Mul_MaxPacketSize = FALSE;
+/* Private function prototypes -----------------------------------------------*/
+static void DataStageOut(void);
+static void DataStageIn(void);
+static void NoData_Setup0(void);
+static void Data_Setup0(void);
+/* Private functions ---------------------------------------------------------*/
+
+/*******************************************************************************
+* Function Name : Standard_GetConfiguration.
+* Description : Return the current configuration variable address.
+* Input : Length - How many bytes are needed.
+* Output : None.
+* Return : Return 1 , if the request is invalid when "Length" is 0.
+* Return "Buffer" if the "Length" is not 0.
+*******************************************************************************/
+u8 *Standard_GetConfiguration(u16 Length)
+{
+ if (Length == 0)
+ {
+ pInformation->Ctrl_Info.Usb_wLength =
+ sizeof(pInformation->Current_Configuration);
+ return 0;
+ }
+ pUser_Standard_Requests->User_GetConfiguration();
+ return (u8 *)&pInformation->Current_Configuration;
+}
+
+/*******************************************************************************
+* Function Name : Standard_SetConfiguration.
+* Description : This routine is called to set the configuration value
+* Then each class should configure device themself.
+* Input : None.
+* Output : None.
+* Return : Return USB_SUCCESS, if the request is performed.
+* Return USB_UNSUPPORT, if the request is invalid.
+*******************************************************************************/
+RESULT Standard_SetConfiguration(void)
+{
+
+ if ((pInformation->USBwValue0 <=
+ Device_Table.Total_Configuration) && (pInformation->USBwValue1 == 0)
+ && (pInformation->USBwIndex == 0)) /*call Back usb spec 2.0*/
+ {
+ pInformation->Current_Configuration = pInformation->USBwValue0;
+ pUser_Standard_Requests->User_SetConfiguration();
+ return USB_SUCCESS;
+ }
+ else
+ {
+ return USB_UNSUPPORT;
+ }
+}
+
+/*******************************************************************************
+* Function Name : Standard_GetInterface.
+* Description : Return the Alternate Setting of the current interface.
+* Input : Length - How many bytes are needed.
+* Output : None.
+* Return : Return 0, if the request is invalid when "Length" is 0.
+* Return "Buffer" if the "Length" is not 0.
+*******************************************************************************/
+u8 *Standard_GetInterface(u16 Length)
+{
+ if (Length == 0)
+ {
+ pInformation->Ctrl_Info.Usb_wLength =
+ sizeof(pInformation->Current_AlternateSetting);
+ return 0;
+ }
+ pUser_Standard_Requests->User_GetInterface();
+ return (u8 *)&pInformation->Current_AlternateSetting;
+}
+
+/*******************************************************************************
+* Function Name : Standard_SetInterface.
+* Description : This routine is called to set the interface.
+* Then each class should configure the interface them self.
+* Input : None.
+* Output : None.
+* Return : - Return USB_SUCCESS, if the request is performed.
+* - Return USB_UNSUPPORT, if the request is invalid.
+*******************************************************************************/
+RESULT Standard_SetInterface(void)
+{
+ RESULT Re;
+ /*Test if the specified Interface and Alternate Setting are supported by
+ the application Firmware*/
+ Re = (*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, pInformation->USBwValue0);
+
+ if (pInformation->Current_Configuration != 0)
+ {
+ if ((Re != USB_SUCCESS) || (pInformation->USBwIndex1 != 0)
+ || (pInformation->USBwValue1 != 0))
+ {
+ return USB_UNSUPPORT;
+ }
+ else if (Re == USB_SUCCESS)
+ {
+ pUser_Standard_Requests->User_SetInterface();
+ pInformation->Current_Interface = pInformation->USBwIndex0;
+ pInformation->Current_AlternateSetting = pInformation->USBwValue0;
+ return USB_SUCCESS;
+ }
+
+ }
+
+ return USB_UNSUPPORT;
+}
+
+/*******************************************************************************
+* Function Name : Standard_GetStatus.
+* Description : Copy the device request data to "StatusInfo buffer".
+* Input : - Length - How many bytes are needed.
+* Output : None.
+* Return : Return 0, if the request is at end of data block,
+* or is invalid when "Length" is 0.
+*******************************************************************************/
+u8 *Standard_GetStatus(u16 Length)
+{
+ if (Length == 0)
+ {
+ pInformation->Ctrl_Info.Usb_wLength = 2;
+ return 0;
+ }
+
+ StatusInfo.w = 0;
+ /* Reset Status Information */
+
+ if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
+ {
+ /*Get Device Status */
+ u8 Feature = pInformation->Current_Feature;
+
+ /* Remote Wakeup enabled */
+ if (ValBit(Feature, 5))
+ {
+ SetBit(StatusInfo0, 1);
+ }
+
+ /* Bus-powered */
+ if (ValBit(Feature, 6))
+ {
+ ClrBit(StatusInfo0, 0);
+ }
+ else /* Self-powered */
+ {
+ SetBit(StatusInfo0, 0);
+ }
+ }
+ /*Interface Status*/
+ else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
+ {
+ return (u8 *)&StatusInfo;
+ }
+ /*Get EndPoint Status*/
+ else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))
+ {
+ u8 Related_Endpoint;
+ u8 wIndex0 = pInformation->USBwIndex0;
+
+ Related_Endpoint = (wIndex0 & 0x0f);
+ if (ValBit(wIndex0, 7))
+ {
+ /* IN endpoint */
+ if (_GetTxStallStatus(Related_Endpoint))
+ {
+ SetBit(StatusInfo0, 0); /* IN Endpoint stalled */
+ }
+ }
+ else
+ {
+ /* OUT endpoint */
+ if (_GetRxStallStatus(Related_Endpoint))
+ {
+ SetBit(StatusInfo0, 0); /* OUT Endpoint stalled */
+ }
+ }
+
+ }
+ else
+ {
+ return NULL;
+ }
+ pUser_Standard_Requests->User_GetStatus();
+ return (u8 *)&StatusInfo;
+}
+
+/*******************************************************************************
+* Function Name : Standard_ClearFeature.
+* Description : Clear or disable a specific feature.
+* Input : None.
+* Output : None.
+* Return : - Return USB_SUCCESS, if the request is performed.
+* - Return USB_UNSUPPORT, if the request is invalid.
+*******************************************************************************/
+RESULT Standard_ClearFeature(void)
+{
+ u32 Type_Rec = Type_Recipient;
+ u32 Status;
+
+
+ if (Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT))
+ {/*Device Clear Feature*/
+ ClrBit(pInformation->Current_Feature, 5);
+ return USB_SUCCESS;
+ }
+ else if (Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))
+ {/*EndPoint Clear Feature*/
+ DEVICE* pDev;
+ u32 Related_Endpoint;
+ u32 wIndex0;
+ u32 rEP;
+
+ if ((pInformation->USBwValue != ENDPOINT_STALL)
+ || (pInformation->USBwIndex1 != 0))
+ {
+ return USB_UNSUPPORT;
+ }
+
+ pDev = &Device_Table;
+ wIndex0 = pInformation->USBwIndex0;
+ rEP = wIndex0 & ~0x80;
+ Related_Endpoint = ENDP0 + rEP;
+
+ if (ValBit(pInformation->USBwIndex0, 7))
+ {
+ /*Get Status of endpoint & stall the request if the related_ENdpoint
+ is Disabled*/
+ Status = _GetEPTxStatus(Related_Endpoint);
+ }
+ else
+ {
+ Status = _GetEPRxStatus(Related_Endpoint);
+ }
+
+ if ((rEP >= pDev->Total_Endpoint) || (Status == 0)
+ || (pInformation->Current_Configuration == 0))
+ {
+ return USB_UNSUPPORT;
+ }
+
+
+ if (wIndex0 & 0x80)
+ {
+ /* IN endpoint */
+ if (_GetTxStallStatus(Related_Endpoint ))
+ {
+ ClearDTOG_TX(Related_Endpoint);
+ SetEPTxStatus(Related_Endpoint, EP_TX_VALID);
+ }
+ }
+ else
+ {
+ /* OUT endpoint */
+ if (_GetRxStallStatus(Related_Endpoint))
+ {
+ if (Related_Endpoint == ENDP0)
+ {
+ /* After clear the STALL, enable the default endpoint receiver */
+ SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize);
+ _SetEPRxStatus(Related_Endpoint, EP_RX_VALID);
+ }
+ else
+ {
+ ClearDTOG_RX(Related_Endpoint);
+ _SetEPRxStatus(Related_Endpoint, EP_RX_VALID);
+ }
+ }
+ }
+ pUser_Standard_Requests->User_ClearFeature();
+ return USB_SUCCESS;
+ }
+
+ return USB_UNSUPPORT;
+}
+
+/*******************************************************************************
+* Function Name : Standard_SetEndPointFeature
+* Description : Set or enable a specific feature of EndPoint
+* Input : None.
+* Output : None.
+* Return : - Return USB_SUCCESS, if the request is performed.
+* - Return USB_UNSUPPORT, if the request is invalid.
+*******************************************************************************/
+RESULT Standard_SetEndPointFeature(void)
+{
+ u32 wIndex0;
+ u32 Related_Endpoint;
+ u32 rEP;
+ u32 Status;
+
+ wIndex0 = pInformation->USBwIndex0;
+ rEP = wIndex0 & ~0x80;
+ Related_Endpoint = ENDP0 + rEP;
+
+ if (ValBit(pInformation->USBwIndex0, 7))
+ {
+ /* get Status of endpoint & stall the request if the related_ENdpoint
+ is Disabled*/
+ Status = _GetEPTxStatus(Related_Endpoint);
+ }
+ else
+ {
+ Status = _GetEPRxStatus(Related_Endpoint);
+ }
+
+ if (Related_Endpoint >= Device_Table.Total_Endpoint
+ || pInformation->USBwValue != 0 || Status == 0
+ || pInformation->Current_Configuration == 0)
+ {
+ return USB_UNSUPPORT;
+ }
+ else
+ {
+ if (wIndex0 & 0x80)
+ {
+ /* IN endpoint */
+ _SetEPTxStatus(Related_Endpoint, EP_TX_STALL);
+ }
+
+ else
+ {
+ /* OUT endpoint */
+ _SetEPRxStatus(Related_Endpoint, EP_RX_STALL);
+ }
+ }
+ pUser_Standard_Requests->User_SetEndPointFeature();
+ return USB_SUCCESS;
+}
+
+/*******************************************************************************
+* Function Name : Standard_SetDeviceFeature.
+* Description : Set or enable a specific feature of Device.
+* Input : None.
+* Output : None.
+* Return : - Return USB_SUCCESS, if the request is performed.
+* - Return USB_UNSUPPORT, if the request is invalid.
+*******************************************************************************/
+RESULT Standard_SetDeviceFeature(void)
+{
+ SetBit(pInformation->Current_Feature, 5);
+ pUser_Standard_Requests->User_SetDeviceFeature();
+ return USB_SUCCESS;
+}
+
+/*******************************************************************************
+* Function Name : Standard_GetDescriptorData.
+* Description : Standard_GetDescriptorData is used for descriptors transfer.
+* : This routine is used for the descriptors resident in Flash
+* or RAM
+* pDesc can be in either Flash or RAM
+* The purpose of this routine is to have a versatile way to
+* response descriptors request. It allows user to generate
+* certain descriptors with software or read descriptors from
+* external storage part by part.
+* Input : - Length - Length of the data in this transfer.
+* - pDesc - A pointer points to descriptor struct.
+* The structure gives the initial address of the descriptor and
+* its original size.
+* Output : None.
+* Return : Address of a part of the descriptor pointed by the Usb_
+* wOffset The buffer pointed by this address contains at least
+* Length bytes.
+*******************************************************************************/
+u8 *Standard_GetDescriptorData(u16 Length, ONE_DESCRIPTOR *pDesc)
+{
+ u32 wOffset;
+
+ wOffset = pInformation->Ctrl_Info.Usb_wOffset;
+ if (Length == 0)
+ {
+ pInformation->Ctrl_Info.Usb_wLength = pDesc->Descriptor_Size - wOffset;
+ return 0;
+ }
+
+ return pDesc->Descriptor + wOffset;
+}
+
+/*******************************************************************************
+* Function Name : DataStageOut.
+* Description : Data stage of a Control Write Transfer.
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void DataStageOut(void)
+{
+ ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;
+ u32 save_rLength;
+
+ save_rLength = pEPinfo->Usb_rLength;
+
+ if (pEPinfo->CopyData && save_rLength)
+ {
+ u8 *Buffer;
+ u32 Length;
+
+ Length = pEPinfo->PacketSize;
+ if (Length > save_rLength)
+ {
+ Length = save_rLength;
+ }
+
+ Buffer = (*pEPinfo->CopyData)(Length);
+ pEPinfo->Usb_rLength -= Length;
+ pEPinfo->Usb_rOffset += Length;
+
+ PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length);
+ }
+
+ if (pEPinfo->Usb_rLength != 0)
+ {
+ vSetEPRxStatus(EP_RX_VALID);/* re-enable for next data reception */
+ SetEPTxCount(ENDP0, 0);
+ vSetEPTxStatus(EP_TX_VALID);/* Expect the host to abort the data OUT stage */
+ }
+ /* Set the next State*/
+ if (pEPinfo->Usb_rLength >= pEPinfo->PacketSize)
+ {
+ pInformation->ControlState = OUT_DATA;
+ }
+ else
+ {
+ if (pEPinfo->Usb_rLength > 0)
+ {
+ pInformation->ControlState = LAST_OUT_DATA;
+ }
+ else if (pEPinfo->Usb_rLength == 0)
+ {
+ pInformation->ControlState = WAIT_STATUS_IN;
+ USB_StatusIn();
+ }
+ }
+}
+
+/*******************************************************************************
+* Function Name : DataStageIn.
+* Description : Data stage of a Control Read Transfer.
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void DataStageIn(void)
+{
+ ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;
+ u32 save_wLength = pEPinfo->Usb_wLength;
+ u32 ControlState = pInformation->ControlState;
+
+ u8 *DataBuffer;
+ u32 Length;
+
+ if ((save_wLength == 0) && (ControlState == LAST_IN_DATA))
+ {
+ if(Data_Mul_MaxPacketSize == TRUE)
+ {
+ /* No more data to send and empty packet */
+ Send0LengthData();
+ ControlState = LAST_IN_DATA;
+ Data_Mul_MaxPacketSize = FALSE;
+ }
+ else
+ {
+ /* No more data to send so STALL the TX Status*/
+ ControlState = WAIT_STATUS_OUT;
+ vSetEPTxStatus(EP_TX_STALL);
+ }
+
+ goto Expect_Status_Out;
+ }
+
+ Length = pEPinfo->PacketSize;
+ ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA;
+
+ if (Length > save_wLength)
+ {
+ Length = save_wLength;
+ }
+
+ DataBuffer = (*pEPinfo->CopyData)(Length);
+
+ UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);
+
+ SetEPTxCount(ENDP0, Length);
+
+ pEPinfo->Usb_wLength -= Length;
+ pEPinfo->Usb_wOffset += Length;
+ vSetEPTxStatus(EP_TX_VALID);
+
+ USB_StatusOut();/* Expect the host to abort the data IN stage */
+
+Expect_Status_Out:
+ pInformation->ControlState = ControlState;
+}
+
+/*******************************************************************************
+* Function Name : NoData_Setup0.
+* Description : Proceed the processing of setup request without data stage.
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void NoData_Setup0(void)
+{
+ RESULT Result = USB_UNSUPPORT;
+ u32 RequestNo = pInformation->USBbRequest;
+ u32 ControlState;
+
+ if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
+ {
+ /* Device Request*/
+ /* SET_CONFIGURATION*/
+ if (RequestNo == SET_CONFIGURATION)
+ {
+ Result = Standard_SetConfiguration();
+ }
+
+ /*SET ADDRESS*/
+ else if (RequestNo == SET_ADDRESS)
+ {
+ if ((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0)
+ || (pInformation->USBwIndex != 0)
+ || (pInformation->Current_Configuration != 0))
+ /* Device Address should be 127 or less*/
+ {
+ ControlState = STALLED;
+ goto exit_NoData_Setup0;
+ }
+ else
+ {
+ Result = USB_SUCCESS;
+ }
+ }
+ /*SET FEATURE for Device*/
+ else if (RequestNo == SET_FEATURE)
+ {
+ if ((pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP)
+ && (pInformation->USBwIndex == 0)
+ && (ValBit(pInformation->Current_Feature, 5)))
+ {
+ Result = Standard_SetDeviceFeature();
+ }
+ else
+ {
+ Result = USB_UNSUPPORT;
+ }
+ }
+ /*Clear FEATURE for Device */
+ else if (RequestNo == CLEAR_FEATURE)
+ {
+ if (pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP
+ && pInformation->USBwIndex == 0
+ && ValBit(pInformation->Current_Feature, 5))
+ {
+ Result = Standard_ClearFeature();
+ }
+ else
+ {
+ Result = USB_UNSUPPORT;
+ }
+ }
+
+ }
+
+ /* Interface Request*/
+ else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
+ {
+ /*SET INTERFACE*/
+ if (RequestNo == SET_INTERFACE)
+ {
+ Result = Standard_SetInterface();
+ }
+ }
+
+ /* EndPoint Request*/
+ else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))
+ {
+ /*CLEAR FEATURE for EndPoint*/
+ if (RequestNo == CLEAR_FEATURE)
+ {
+ Result = Standard_ClearFeature();
+ }
+ /* SET FEATURE for EndPoint*/
+ else if (RequestNo == SET_FEATURE)
+ {
+ Result = Standard_SetEndPointFeature();
+ }
+ }
+ else
+ {
+ Result = USB_UNSUPPORT;
+ }
+
+
+ if (Result != USB_SUCCESS)
+ {
+ Result = (*pProperty->Class_NoData_Setup)(RequestNo);
+ if (Result == USB_NOT_READY)
+ {
+ ControlState = PAUSE;
+ goto exit_NoData_Setup0;
+ }
+ }
+
+ if (Result != USB_SUCCESS)
+ {
+ ControlState = STALLED;
+ goto exit_NoData_Setup0;
+ }
+
+ ControlState = WAIT_STATUS_IN;/* After no data stage SETUP */
+
+ USB_StatusIn();
+
+exit_NoData_Setup0:
+ pInformation->ControlState = ControlState;
+ return;
+}
+
+/*******************************************************************************
+* Function Name : Data_Setup0.
+* Description : Proceed the processing of setup request with data stage.
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void Data_Setup0(void)
+{
+ u8 *(*CopyRoutine)(u16);
+ RESULT Result;
+ u32 Request_No = pInformation->USBbRequest;
+
+ u32 Related_Endpoint, Reserved;
+ u32 wOffset, Status;
+
+
+
+ CopyRoutine = NULL;
+ wOffset = 0;
+
+ if (Request_No == GET_DESCRIPTOR)
+ {
+ if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
+ {
+ u8 wValue1 = pInformation->USBwValue1;
+ if (wValue1 == DEVICE_DESCRIPTOR)
+ {
+ CopyRoutine = pProperty->GetDeviceDescriptor;
+ }
+ else if (wValue1 == CONFIG_DESCRIPTOR)
+ {
+ CopyRoutine = pProperty->GetConfigDescriptor;
+ }
+ else if (wValue1 == STRING_DESCRIPTOR)
+ {
+ CopyRoutine = pProperty->GetStringDescriptor;
+ } /* End of GET_DESCRIPTOR */
+ }
+ }
+
+ /*GET STATUS*/
+ else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0)
+ && (pInformation->USBwLength == 0x0002)
+ && (pInformation->USBwIndex1 == 0))
+ {
+ /* GET STATUS for Device*/
+ if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
+ && (pInformation->USBwIndex == 0))
+ {
+ CopyRoutine = Standard_GetStatus;
+ }
+
+ /* GET STATUS for Interface*/
+ else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
+ {
+ if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)
+ && (pInformation->Current_Configuration != 0))
+ {
+ CopyRoutine = Standard_GetStatus;
+ }
+ }
+
+ /* GET STATUS for EndPoint*/
+ else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))
+ {
+ Related_Endpoint = (pInformation->USBwIndex0 & 0x0f);
+ Reserved = pInformation->USBwIndex0 & 0x70;
+
+ if (ValBit(pInformation->USBwIndex0, 7))
+ {
+ /*Get Status of endpoint & stall the request if the related_ENdpoint
+ is Disabled*/
+ Status = _GetEPTxStatus(Related_Endpoint);
+ }
+ else
+ {
+ Status = _GetEPRxStatus(Related_Endpoint);
+ }
+
+ if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0)
+ && (Status != 0))
+ {
+ CopyRoutine = Standard_GetStatus;
+ }
+ }
+
+ }
+
+ /*GET CONFIGURATION*/
+ else if (Request_No == GET_CONFIGURATION)
+ {
+ if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
+ {
+ CopyRoutine = Standard_GetConfiguration;
+ }
+ }
+ /*GET INTERFACE*/
+ else if (Request_No == GET_INTERFACE)
+ {
+ if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
+ && (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0)
+ && (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001)
+ && ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS))
+ {
+ CopyRoutine = Standard_GetInterface;
+ }
+
+ }
+
+ if (CopyRoutine)
+ {
+ pInformation->Ctrl_Info.Usb_wOffset = wOffset;
+ pInformation->Ctrl_Info.CopyData = CopyRoutine;
+ /* sb in the original the cast to word was directly */
+ /* now the cast is made step by step */
+ (*CopyRoutine)(0);
+ Result = USB_SUCCESS;
+ }
+ else
+ {
+ Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
+ if (Result == USB_NOT_READY)
+ {
+ pInformation->ControlState = PAUSE;
+ return;
+ }
+ }
+
+ if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF)
+ {
+ /* Data is not ready, wait it */
+ pInformation->ControlState = PAUSE;
+ return;
+ }
+ if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0))
+ {
+ /* Unsupported request */
+ pInformation->ControlState = STALLED;
+ return;
+ }
+
+
+ if (ValBit(pInformation->USBbmRequestType, 7))
+ {
+ /* Device ==> Host */
+ vu32 wLength = pInformation->USBwLength;
+
+ /* Restrict the data length to be the one host asks */
+ if (pInformation->Ctrl_Info.Usb_wLength > wLength)
+ {
+ pInformation->Ctrl_Info.Usb_wLength = wLength;
+ }
+
+ else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength)
+ {
+ if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize)
+ {
+ Data_Mul_MaxPacketSize = FALSE;
+ }
+ else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0)
+ {
+ Data_Mul_MaxPacketSize = TRUE;
+ }
+ }
+
+ pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;
+ DataStageIn();
+ }
+ else
+ {
+ pInformation->ControlState = OUT_DATA;
+ vSetEPRxStatus(EP_RX_VALID); /* enable for next data reception */
+ }
+
+ return;
+}
+
+/*******************************************************************************
+* Function Name : Setup0_Process
+* Description : Get the device request data and dispatch to individual process.
+* Input : None.
+* Output : None.
+* Return : Post0_Process.
+*******************************************************************************/
+u8 Setup0_Process(void)
+{
+
+ union
+ {
+ u8* b;
+ u16* w;
+ } pBuf;
+
+ pBuf.b = PMAAddr + (u8 *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */
+
+ if (pInformation->ControlState != PAUSE)
+ {
+ pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */
+ pInformation->USBbRequest = *pBuf.b++; /* bRequest */
+ pBuf.w++; /* word not accessed because of 32 bits addressing */
+ pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */
+ pBuf.w++; /* word not accessed because of 32 bits addressing */
+ pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */
+ pBuf.w++; /* word not accessed because of 32 bits addressing */
+ pInformation->USBwLength = *pBuf.w; /* wLength */
+ }
+
+ pInformation->ControlState = SETTING_UP;
+ if (pInformation->USBwLength == 0)
+ {
+ /* Setup with no data stage */
+ NoData_Setup0();
+ }
+ else
+ {
+ /* Setup with data stage */
+ Data_Setup0();
+ }
+ return Post0_Process();
+}
+
+/*******************************************************************************
+* Function Name : In0_Process
+* Description : Process the IN token on all default endpoint.
+* Input : None.
+* Output : None.
+* Return : Post0_Process.
+*******************************************************************************/
+u8 In0_Process(void)
+{
+ u32 ControlState = pInformation->ControlState;
+
+ if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA))
+ {
+ DataStageIn();
+ /* ControlState may be changed outside the function */
+ ControlState = pInformation->ControlState;
+ }
+
+ else if (ControlState == WAIT_STATUS_IN)
+ {
+ if ((pInformation->USBbRequest == SET_ADDRESS) &&
+ (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
+ {
+ SetDeviceAddress(pInformation->USBwValue0);
+ pUser_Standard_Requests->User_SetDeviceAddress();
+ }
+ (*pProperty->Process_Status_IN)();
+ ControlState = STALLED;
+ }
+
+ else
+ {
+ ControlState = STALLED;
+ }
+
+ pInformation->ControlState = ControlState;
+
+ return Post0_Process();
+}
+
+/*******************************************************************************
+* Function Name : Out0_Process
+* Description : Process the OUT token on all default endpoint.
+* Input : None.
+* Output : None.
+* Return : Post0_Process.
+*******************************************************************************/
+u8 Out0_Process(void)
+{
+ u32 ControlState = pInformation->ControlState;
+
+ if ((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA))
+ {
+ DataStageOut();
+ ControlState = pInformation->ControlState; /* may be changed outside the function */
+ }
+
+ else if (ControlState == WAIT_STATUS_OUT)
+ {
+ (*pProperty->Process_Status_OUT)();
+ ControlState = STALLED;
+ }
+
+ else if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA))
+ {
+ /* host aborts the transfer before finish */
+ ControlState = STALLED;
+ }
+
+ /* Unexpect state, STALL the endpoint */
+ else
+ {
+ ControlState = STALLED;
+ }
+
+ pInformation->ControlState = ControlState;
+
+ return Post0_Process();
+}
+
+/*******************************************************************************
+* Function Name : Post0_Process
+* Description : Stall the Endpoint 0 in case of error.
+* Input : None.
+* Output : None.
+* Return : - 0 if the control State is in PAUSE
+* - 1 if not.
+*******************************************************************************/
+u8 Post0_Process(void)
+{
+ SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
+
+ if (pInformation->ControlState == STALLED)
+ {
+ vSetEPRxStatus(EP_RX_STALL);
+ vSetEPTxStatus(EP_TX_STALL);
+ }
+
+ return (pInformation->ControlState == PAUSE);
+}
+
+/*******************************************************************************
+* Function Name : SetDeviceAddress.
+* Description : Set the device and all the used Endpoints addresses.
+* Input : - Val: device adress.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetDeviceAddress(u8 Val)
+{
+ u32 i;
+ u32 nEP = Device_Table.Total_Endpoint;
+
+ /* set address in every used endpoint */
+ for (i = 0; i < nEP; i++)
+ {
+ _SetEPAddress((u8)i, (u8)i);
+ } /* for */
+ _SetDADDR(Val | DADDR_EF); /* set device address and enable function */
+}
+
+/*******************************************************************************
+* Function Name : NOP_Process
+* Description : No operation function.
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void NOP_Process(void)
+{
+}
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_core.h b/libmaple/usb/usb_lib/usb_core.h
new file mode 100644
index 0000000..fa29a18
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_core.h
@@ -0,0 +1,251 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_core.h
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Standard protocol processing functions prototypes
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_CORE_H
+#define __USB_CORE_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+typedef enum _CONTROL_STATE
+{
+ WAIT_SETUP, /* 0 */
+ SETTING_UP, /* 1 */
+ IN_DATA, /* 2 */
+ OUT_DATA, /* 3 */
+ LAST_IN_DATA, /* 4 */
+ LAST_OUT_DATA, /* 5 */
+ WAIT_STATUS_IN, /* 7 */
+ WAIT_STATUS_OUT, /* 8 */
+ STALLED, /* 9 */
+ PAUSE /* 10 */
+} CONTROL_STATE; /* The state machine states of a control pipe */
+
+typedef struct OneDescriptor
+{
+ u8 *Descriptor;
+ u16 Descriptor_Size;
+}
+ONE_DESCRIPTOR, *PONE_DESCRIPTOR;
+/* All the request process routines return a value of this type
+ If the return value is not SUCCESS or NOT_READY,
+ the software will STALL the correspond endpoint */
+typedef enum _RESULT
+{
+ USB_SUCCESS = 0, /* Process sucessfully */
+ USB_ERROR,
+ USB_UNSUPPORT,
+ USB_NOT_READY /* The process has not been finished, endpoint will be
+ NAK to further rquest */
+} RESULT;
+
+
+/*-*-*-*-*-*-*-*-*-*-* Definitions for endpoint level -*-*-*-*-*-*-*-*-*-*-*-*/
+typedef struct _ENDPOINT_INFO
+{
+ /* When send data out of the device,
+ CopyData() is used to get data buffer 'Length' bytes data
+ if Length is 0,
+ CopyData() returns the total length of the data
+ if the request is not supported, returns 0
+ (NEW Feature )
+ if CopyData() returns -1, the calling routine should not proceed
+ further and will resume the SETUP process by the class device
+ if Length is not 0,
+ CopyData() returns a pointer to indicate the data location
+ Usb_wLength is the data remain to be sent,
+ Usb_wOffset is the Offset of original data
+ When receive data from the host,
+ CopyData() is used to get user data buffer which is capable
+ of Length bytes data to copy data from the endpoint buffer.
+ if Length is 0,
+ CopyData() returns the available data length,
+ if Length is not 0,
+ CopyData() returns user buffer address
+ Usb_rLength is the data remain to be received,
+ Usb_rPointer is the Offset of data buffer
+ */
+ u16 Usb_wLength;
+ u16 Usb_wOffset;
+ u16 PacketSize;
+ u8 *(*CopyData)(u16 Length);
+}ENDPOINT_INFO;
+
+/*-*-*-*-*-*-*-*-*-*-*-* Definitions for device level -*-*-*-*-*-*-*-*-*-*-*-*/
+
+typedef struct _DEVICE
+{
+ u8 Total_Endpoint; /* Number of endpoints that are used */
+ u8 Total_Configuration;/* Number of configuration available */
+}
+DEVICE;
+
+typedef union
+{
+ u16 w;
+ struct BW
+ {
+ u8 bb1;
+ u8 bb0;
+ }
+ bw;
+} u16_u8;
+
+typedef struct _DEVICE_INFO
+{
+ u8 USBbmRequestType; /* bmRequestType */
+ u8 USBbRequest; /* bRequest */
+ u16_u8 USBwValues; /* wValue */
+ u16_u8 USBwIndexs; /* wIndex */
+ u16_u8 USBwLengths; /* wLength */
+
+ u8 ControlState; /* of type CONTROL_STATE */
+ u8 Current_Feature;
+ u8 Current_Configuration; /* Selected configuration */
+ u8 Current_Interface; /* Selected interface of current configuration */
+ u8 Current_AlternateSetting;/* Selected Alternate Setting of current
+ interface*/
+
+ ENDPOINT_INFO Ctrl_Info;
+}DEVICE_INFO;
+
+typedef struct _DEVICE_PROP
+{
+ void (*Init)(void); /* Initialize the device */
+ void (*Reset)(void); /* Reset routine of this device */
+
+ /* Device dependent process after the status stage */
+ void (*Process_Status_IN)(void);
+ void (*Process_Status_OUT)(void);
+
+ /* Procedure of process on setup stage of a class specified request with data stage */
+ /* All class specified requests with data stage are processed in Class_Data_Setup
+ Class_Data_Setup()
+ responses to check all special requests and fills ENDPOINT_INFO
+ according to the request
+ If IN tokens are expected, then wLength & wOffset will be filled
+ with the total transferring bytes and the starting position
+ If OUT tokens are expected, then rLength & rOffset will be filled
+ with the total expected bytes and the starting position in the buffer
+
+ If the request is valid, Class_Data_Setup returns SUCCESS, else UNSUPPORT
+
+ CAUTION:
+ Since GET_CONFIGURATION & GET_INTERFACE are highly related to
+ the individual classes, they will be checked and processed here.
+ */
+ RESULT (*Class_Data_Setup)(u8 RequestNo);
+
+ /* Procedure of process on setup stage of a class specified request without data stage */
+ /* All class specified requests without data stage are processed in Class_NoData_Setup
+ Class_NoData_Setup
+ responses to check all special requests and perform the request
+
+ CAUTION:
+ Since SET_CONFIGURATION & SET_INTERFACE are highly related to
+ the individual classes, they will be checked and processed here.
+ */
+ RESULT (*Class_NoData_Setup)(u8 RequestNo);
+
+ /*Class_Get_Interface_Setting
+ This function is used by the file usb_core.c to test if the selected Interface
+ and Alternate Setting (u8 Interface, u8 AlternateSetting) are supported by
+ the application.
+ This function is writing by user. It should return "SUCCESS" if the Interface
+ and Alternate Setting are supported by the application or "UNSUPPORT" if they
+ are not supported. */
+
+ RESULT (*Class_Get_Interface_Setting)(u8 Interface, u8 AlternateSetting);
+
+ u8* (*GetDeviceDescriptor)(u16 Length);
+ u8* (*GetConfigDescriptor)(u16 Length);
+ u8* (*GetStringDescriptor)(u16 Length);
+
+ u8* RxEP_buffer;
+ u8 MaxPacketSize;
+
+}DEVICE_PROP;
+
+typedef struct _USER_STANDARD_REQUESTS
+{
+ void (*User_GetConfiguration)(void); /* Get Configuration */
+ void (*User_SetConfiguration)(void); /* Set Configuration */
+ void (*User_GetInterface)(void); /* Get Interface */
+ void (*User_SetInterface)(void); /* Set Interface */
+ void (*User_GetStatus)(void); /* Get Status */
+ void (*User_ClearFeature)(void); /* Clear Feature */
+ void (*User_SetEndPointFeature)(void); /* Set Endpoint Feature */
+ void (*User_SetDeviceFeature)(void); /* Set Device Feature */
+ void (*User_SetDeviceAddress)(void); /* Set Device Address */
+}
+USER_STANDARD_REQUESTS;
+
+/* Exported constants --------------------------------------------------------*/
+#define Type_Recipient (pInformation->USBbmRequestType & (REQUEST_TYPE | RECIPIENT))
+
+#define Usb_rLength Usb_wLength
+#define Usb_rOffset Usb_wOffset
+
+#define USBwValue USBwValues.w
+#define USBwValue0 USBwValues.bw.bb0
+#define USBwValue1 USBwValues.bw.bb1
+#define USBwIndex USBwIndexs.w
+#define USBwIndex0 USBwIndexs.bw.bb0
+#define USBwIndex1 USBwIndexs.bw.bb1
+#define USBwLength USBwLengths.w
+#define USBwLength0 USBwLengths.bw.bb0
+#define USBwLength1 USBwLengths.bw.bb1
+
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+u8 Setup0_Process(void);
+u8 Post0_Process(void);
+u8 Out0_Process(void);
+u8 In0_Process(void);
+
+RESULT Standard_SetEndPointFeature(void);
+RESULT Standard_SetDeviceFeature(void);
+
+u8 *Standard_GetConfiguration(u16 Length);
+RESULT Standard_SetConfiguration(void);
+u8 *Standard_GetInterface(u16 Length);
+RESULT Standard_SetInterface(void);
+u8 *Standard_GetDescriptorData(u16 Length, PONE_DESCRIPTOR pDesc);
+
+u8 *Standard_GetStatus(u16 Length);
+RESULT Standard_ClearFeature(void);
+void SetDeviceAddress(u8);
+void NOP_Process(void);
+
+extern DEVICE_PROP Device_Property;
+extern USER_STANDARD_REQUESTS User_Standard_Requests;
+extern DEVICE Device_Table;
+extern DEVICE_INFO Device_Info;
+
+/* cells saving status during interrupt servicing */
+extern u16 SaveRState;
+extern u16 SaveTState;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __USB_CORE_H */
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_def.h b/libmaple/usb/usb_lib/usb_def.h
new file mode 100644
index 0000000..80aa303
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_def.h
@@ -0,0 +1,88 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_def.h
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Definitions related to USB Core
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_DEF_H
+#define __USB_DEF_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+typedef enum _RECIPIENT_TYPE
+{
+ DEVICE_RECIPIENT, /* Recipient device */
+ INTERFACE_RECIPIENT, /* Recipient interface */
+ ENDPOINT_RECIPIENT, /* Recipient endpoint */
+ OTHER_RECIPIENT
+} RECIPIENT_TYPE;
+
+
+typedef enum _STANDARD_REQUESTS
+{
+ GET_STATUS = 0,
+ CLEAR_FEATURE,
+ RESERVED1,
+ SET_FEATURE,
+ RESERVED2,
+ SET_ADDRESS,
+ GET_DESCRIPTOR,
+ SET_DESCRIPTOR,
+ GET_CONFIGURATION,
+ SET_CONFIGURATION,
+ GET_INTERFACE,
+ SET_INTERFACE,
+ TOTAL_sREQUEST, /* Total number of Standard request */
+ SYNCH_FRAME = 12
+} STANDARD_REQUESTS;
+
+/* Definition of "USBwValue" */
+typedef enum _DESCRIPTOR_TYPE
+{
+ DEVICE_DESCRIPTOR = 1,
+ CONFIG_DESCRIPTOR,
+ STRING_DESCRIPTOR,
+ INTERFACE_DESCRIPTOR,
+ ENDPOINT_DESCRIPTOR
+} DESCRIPTOR_TYPE;
+
+/* Feature selector of a SET_FEATURE or CLEAR_FEATURE */
+typedef enum _FEATURE_SELECTOR
+{
+ ENDPOINT_STALL,
+ DEVICE_REMOTE_WAKEUP
+} FEATURE_SELECTOR;
+
+/* Exported constants --------------------------------------------------------*/
+/* Definition of "USBbmRequestType" */
+#define REQUEST_TYPE 0x60 /* Mask to get request type */
+#define STANDARD_REQUEST 0x00 /* Standard request */
+#define CLASS_REQUEST 0x20 /* Class request */
+#define VENDOR_REQUEST 0x40 /* Vendor request */
+
+#define RECIPIENT 0x1F /* Mask to get recipient */
+
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __USB_DEF_H */
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_init.c b/libmaple/usb/usb_lib/usb_init.c
new file mode 100644
index 0000000..94f3a83
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_init.c
@@ -0,0 +1,64 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_init.c
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Initialization routines & global variables
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Includes ------------------------------------------------------------------*/
+#include "usb_lib.h"
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* The number of current endpoint, it will be used to specify an endpoint */
+ u8 EPindex;
+/* The number of current device, it is an index to the Device_Table */
+/* u8 Device_no; */
+/* Points to the DEVICE_INFO structure of current device */
+/* The purpose of this register is to speed up the execution */
+DEVICE_INFO *pInformation;
+/* Points to the DEVICE_PROP structure of current device */
+/* The purpose of this register is to speed up the execution */
+DEVICE_PROP *pProperty;
+/* Temporary save the state of Rx & Tx status. */
+/* Whenever the Rx or Tx state is changed, its value is saved */
+/* in this variable first and will be set to the EPRB or EPRA */
+/* at the end of interrupt process */
+u16 SaveState ;
+u16 wInterrupt_Mask;
+DEVICE_INFO Device_Info;
+USER_STANDARD_REQUESTS *pUser_Standard_Requests;
+
+/* Extern variables ----------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+
+/*******************************************************************************
+* Function Name : USB_Init
+* Description : USB system initialization
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void USB_Init(void)
+{
+ pInformation = &Device_Info;
+ pInformation->ControlState = 2;
+ pProperty = &Device_Property;
+ pUser_Standard_Requests = &User_Standard_Requests;
+ /* Initialize devices one by one */
+
+ pProperty->Init();
+}
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_init.h b/libmaple/usb/usb_lib/usb_init.h
new file mode 100644
index 0000000..80ee2fb
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_init.h
@@ -0,0 +1,57 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_init.h
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Initialization routines & global variables
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_INIT_H
+#define __USB_INIT_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+void USB_Init(void);
+
+/* External variables --------------------------------------------------------*/
+/* The number of current endpoint, it will be used to specify an endpoint */
+extern u8 EPindex;
+/* The number of current device, it is an index to the Device_Table */
+/*extern u8 Device_no; */
+/* Points to the DEVICE_INFO structure of current device */
+/* The purpose of this register is to speed up the execution */
+extern DEVICE_INFO* pInformation;
+/* Points to the DEVICE_PROP structure of current device */
+/* The purpose of this register is to speed up the execution */
+extern DEVICE_PROP* pProperty;
+/* Temporary save the state of Rx & Tx status. */
+/* Whenever the Rx or Tx state is changed, its value is saved */
+/* in this variable first and will be set to the EPRB or EPRA */
+/* at the end of interrupt process */
+extern USER_STANDARD_REQUESTS *pUser_Standard_Requests;
+
+extern u16 SaveState ;
+extern u16 wInterrupt_Mask;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __USB_INIT_H */
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_lib.h b/libmaple/usb/usb_lib/usb_lib.h
new file mode 100644
index 0000000..85f94ab
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_lib.h
@@ -0,0 +1,36 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_lib.h
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : USB library include files
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_LIB_H
+#define __USB_LIB_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usb_type.h"
+#include "usb_regs.h"
+#include "usb_def.h"
+#include "usb_core.h"
+#include "usb_init.h"
+#include "usb_mem.h"
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+/* External variables --------------------------------------------------------*/
+
+#endif /* __USB_LIB_H */
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_mem.c b/libmaple/usb/usb_lib/usb_mem.c
new file mode 100644
index 0000000..ad9740a
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_mem.c
@@ -0,0 +1,73 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_mem.c
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Utility functions for memory transfers to/from PMA
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Includes ------------------------------------------------------------------*/
+#include "usb_lib.h"
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Extern variables ----------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+/*******************************************************************************
+* Function Name : UserToPMABufferCopy
+* Description : Copy a buffer from user memory area to packet memory area (PMA)
+* Input : - pbUsrBuf: pointer to user memory area.
+* - wPMABufAddr: address into PMA.
+* - wNBytes: no. of bytes to be copied.
+* Output : None.
+* Return : None .
+*******************************************************************************/
+void UserToPMABufferCopy(const u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes)
+{
+ u32 n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */
+ u32 i, temp1, temp2;
+ u16 *pdwVal;
+ pdwVal = (u16 *)(wPMABufAddr * 2 + PMAAddr);
+ for (i = n; i != 0; i--)
+ {
+ temp1 = (u16) * pbUsrBuf;
+ pbUsrBuf++;
+ temp2 = temp1 | (u16) * pbUsrBuf << 8;
+ *pdwVal++ = temp2;
+ pdwVal++;
+ pbUsrBuf++;
+ }
+}
+/*******************************************************************************
+* Function Name : PMAToUserBufferCopy
+* Description : Copy a buffer from user memory area to packet memory area (PMA)
+* Input : - pbUsrBuf = pointer to user memory area.
+* - wPMABufAddr = address into PMA.
+* - wNBytes = no. of bytes to be copied.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes)
+{
+ u32 n = (wNBytes + 1) >> 1;/* /2*/
+ u32 i;
+ u32 *pdwVal;
+ pdwVal = (u32 *)(wPMABufAddr * 2 + PMAAddr);
+ for (i = n; i != 0; i--)
+ {
+ *(u16*)pbUsrBuf++ = *pdwVal++;
+ pbUsrBuf++;
+ }
+}
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_mem.h b/libmaple/usb/usb_lib/usb_mem.h
new file mode 100644
index 0000000..b0e0474
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_mem.h
@@ -0,0 +1,40 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_mem.h
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Utility prototypes functions for memory/PMA transfers
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_MEM_H
+#define __USB_MEM_H
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void UserToPMABufferCopy(const u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes);
+void PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* External variables --------------------------------------------------------*/
+
+#endif /*__USB_MEM_H*/
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_regs.c b/libmaple/usb/usb_lib/usb_regs.c
new file mode 100644
index 0000000..c7e0276
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_regs.c
@@ -0,0 +1,748 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_regs.c
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Interface functions to USB cell registers
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Includes ------------------------------------------------------------------*/
+#include "usb_lib.h"
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Extern variables ----------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+
+/*******************************************************************************
+* Function Name : SetCNTR.
+* Description : Set the CNTR register value.
+* Input : wRegValue: new register value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetCNTR(u16 wRegValue)
+{
+ _SetCNTR(wRegValue);
+}
+
+/*******************************************************************************
+* Function Name : GetCNTR.
+* Description : returns the CNTR register value.
+* Input : None.
+* Output : None.
+* Return : CNTR register Value.
+*******************************************************************************/
+u16 GetCNTR(void)
+{
+ return(_GetCNTR());
+}
+
+/*******************************************************************************
+* Function Name : SetISTR.
+* Description : Set the ISTR register value.
+* Input : wRegValue: new register value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetISTR(u16 wRegValue)
+{
+ _SetISTR(wRegValue);
+}
+
+/*******************************************************************************
+* Function Name : GetISTR
+* Description : Returns the ISTR register value.
+* Input : None.
+* Output : None.
+* Return : ISTR register Value
+*******************************************************************************/
+u16 GetISTR(void)
+{
+ return(_GetISTR());
+}
+
+/*******************************************************************************
+* Function Name : GetFNR
+* Description : Returns the FNR register value.
+* Input : None.
+* Output : None.
+* Return : FNR register Value
+*******************************************************************************/
+u16 GetFNR(void)
+{
+ return(_GetFNR());
+}
+
+/*******************************************************************************
+* Function Name : SetDADDR
+* Description : Set the DADDR register value.
+* Input : wRegValue: new register value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetDADDR(u16 wRegValue)
+{
+ _SetDADDR(wRegValue);
+}
+
+/*******************************************************************************
+* Function Name : GetDADDR
+* Description : Returns the DADDR register value.
+* Input : None.
+* Output : None.
+* Return : DADDR register Value
+*******************************************************************************/
+u16 GetDADDR(void)
+{
+ return(_GetDADDR());
+}
+
+/*******************************************************************************
+* Function Name : SetBTABLE
+* Description : Set the BTABLE.
+* Input : wRegValue: New register value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetBTABLE(u16 wRegValue)
+{
+ _SetBTABLE(wRegValue);
+}
+
+/*******************************************************************************
+* Function Name : GetBTABLE.
+* Description : Returns the BTABLE register value.
+* Input : None.
+* Output : None.
+* Return : BTABLE address.
+*******************************************************************************/
+u16 GetBTABLE(void)
+{
+ return(_GetBTABLE());
+}
+
+/*******************************************************************************
+* Function Name : SetENDPOINT
+* Description : Setthe Endpoint register value.
+* Input : bEpNum: Endpoint Number.
+* wRegValue.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetENDPOINT(u8 bEpNum, u16 wRegValue)
+{
+ _SetENDPOINT(bEpNum, wRegValue);
+}
+
+/*******************************************************************************
+* Function Name : GetENDPOINT
+* Description : Return the Endpoint register value.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint register value.
+*******************************************************************************/
+u16 GetENDPOINT(u8 bEpNum)
+{
+ return(_GetENDPOINT(bEpNum));
+}
+
+/*******************************************************************************
+* Function Name : SetEPType
+* Description : sets the type in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* wType: type definition.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPType(u8 bEpNum, u16 wType)
+{
+ _SetEPType(bEpNum, wType);
+}
+
+/*******************************************************************************
+* Function Name : GetEPType
+* Description : Returns the endpoint type.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint Type
+*******************************************************************************/
+u16 GetEPType(u8 bEpNum)
+{
+ return(_GetEPType(bEpNum));
+}
+
+/*******************************************************************************
+* Function Name : SetEPTxStatus
+* Description : Set the status of Tx endpoint.
+* Input : bEpNum: Endpoint Number.
+* wState: new state.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPTxStatus(u8 bEpNum, u16 wState)
+{
+ _SetEPTxStatus(bEpNum, wState);
+}
+
+/*******************************************************************************
+* Function Name : SetEPRxStatus
+* Description : Set the status of Rx endpoint.
+* Input : bEpNum: Endpoint Number.
+* wState: new state.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPRxStatus(u8 bEpNum, u16 wState)
+{
+ _SetEPRxStatus(bEpNum, wState);
+}
+
+/*******************************************************************************
+* Function Name : SetDouBleBuffEPStall
+* Description : sets the status for Double Buffer Endpoint to STALL
+* Input : bEpNum: Endpoint Number.
+* bDir: Endpoint direction.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetDouBleBuffEPStall(u8 bEpNum, u8 bDir)
+{
+ u16 Endpoint_DTOG_Status;
+ Endpoint_DTOG_Status = GetENDPOINT(bEpNum);
+ if (bDir == EP_DBUF_OUT)
+ { /* OUT double buffered endpoint */
+ _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPRX_DTOG1);
+ }
+ else if (bDir == EP_DBUF_IN)
+ { /* IN double buffered endpoint */
+ _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPTX_DTOG1);
+ }
+}
+
+/*******************************************************************************
+* Function Name : GetEPTxStatus
+* Description : Returns the endpoint Tx status.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint TX Status
+*******************************************************************************/
+u16 GetEPTxStatus(u8 bEpNum)
+{
+ return(_GetEPTxStatus(bEpNum));
+}
+
+/*******************************************************************************
+* Function Name : GetEPRxStatus
+* Description : Returns the endpoint Rx status.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint RX Status
+*******************************************************************************/
+u16 GetEPRxStatus(u8 bEpNum)
+{
+ return(_GetEPRxStatus(bEpNum));
+}
+
+/*******************************************************************************
+* Function Name : SetEPTxValid
+* Description : Valid the endpoint Tx Status.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPTxValid(u8 bEpNum)
+{
+ _SetEPTxStatus(bEpNum, EP_TX_VALID);
+}
+
+/*******************************************************************************
+* Function Name : SetEPRxValid
+* Description : Valid the endpoint Rx Status.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPRxValid(u8 bEpNum)
+{
+ _SetEPRxStatus(bEpNum, EP_RX_VALID);
+}
+
+/*******************************************************************************
+* Function Name : SetEP_KIND
+* Description : Clear the EP_KIND bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEP_KIND(u8 bEpNum)
+{
+ _SetEP_KIND(bEpNum);
+}
+
+/*******************************************************************************
+* Function Name : ClearEP_KIND
+* Description : set the EP_KIND bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void ClearEP_KIND(u8 bEpNum)
+{
+ _ClearEP_KIND(bEpNum);
+}
+/*******************************************************************************
+* Function Name : Clear_Status_Out
+* Description : Clear the Status Out of the related Endpoint
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void Clear_Status_Out(u8 bEpNum)
+{
+ _ClearEP_KIND(bEpNum);
+}
+/*******************************************************************************
+* Function Name : Set_Status_Out
+* Description : Set the Status Out of the related Endpoint
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void Set_Status_Out(u8 bEpNum)
+{
+ _SetEP_KIND(bEpNum);
+}
+/*******************************************************************************
+* Function Name : SetEPDoubleBuff
+* Description : Enable the double buffer feature for the endpoint.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPDoubleBuff(u8 bEpNum)
+{
+ _SetEP_KIND(bEpNum);
+}
+/*******************************************************************************
+* Function Name : ClearEPDoubleBuff
+* Description : Disable the double buffer feature for the endpoint.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void ClearEPDoubleBuff(u8 bEpNum)
+{
+ _ClearEP_KIND(bEpNum);
+}
+/*******************************************************************************
+* Function Name : GetTxStallStatus
+* Description : Returns the Stall status of the Tx endpoint.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Tx Stall status.
+*******************************************************************************/
+u16 GetTxStallStatus(u8 bEpNum)
+{
+ return(_GetTxStallStatus(bEpNum));
+}
+/*******************************************************************************
+* Function Name : GetRxStallStatus
+* Description : Returns the Stall status of the Rx endpoint.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Rx Stall status.
+*******************************************************************************/
+u16 GetRxStallStatus(u8 bEpNum)
+{
+ return(_GetRxStallStatus(bEpNum));
+}
+/*******************************************************************************
+* Function Name : ClearEP_CTR_RX
+* Description : Clear the CTR_RX bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void ClearEP_CTR_RX(u8 bEpNum)
+{
+ _ClearEP_CTR_RX(bEpNum);
+}
+/*******************************************************************************
+* Function Name : ClearEP_CTR_TX
+* Description : Clear the CTR_TX bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void ClearEP_CTR_TX(u8 bEpNum)
+{
+ _ClearEP_CTR_TX(bEpNum);
+}
+/*******************************************************************************
+* Function Name : ToggleDTOG_RX
+* Description : Toggle the DTOG_RX bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void ToggleDTOG_RX(u8 bEpNum)
+{
+ _ToggleDTOG_RX(bEpNum);
+}
+/*******************************************************************************
+* Function Name : ToggleDTOG_TX
+* Description : Toggle the DTOG_TX bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void ToggleDTOG_TX(u8 bEpNum)
+{
+ _ToggleDTOG_TX(bEpNum);
+}
+/*******************************************************************************
+* Function Name : ClearDTOG_RX.
+* Description : Clear the DTOG_RX bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void ClearDTOG_RX(u8 bEpNum)
+{
+ _ClearDTOG_RX(bEpNum);
+}
+/*******************************************************************************
+* Function Name : ClearDTOG_TX.
+* Description : Clear the DTOG_TX bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void ClearDTOG_TX(u8 bEpNum)
+{
+ _ClearDTOG_TX(bEpNum);
+}
+/*******************************************************************************
+* Function Name : SetEPAddress
+* Description : Set the endpoint address.
+* Input : bEpNum: Endpoint Number.
+* bAddr: New endpoint address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPAddress(u8 bEpNum, u8 bAddr)
+{
+ _SetEPAddress(bEpNum, bAddr);
+}
+/*******************************************************************************
+* Function Name : GetEPAddress
+* Description : Get the endpoint address.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint address.
+*******************************************************************************/
+u8 GetEPAddress(u8 bEpNum)
+{
+ return(_GetEPAddress(bEpNum));
+}
+/*******************************************************************************
+* Function Name : SetEPTxAddr
+* Description : Set the endpoint Tx buffer address.
+* Input : bEpNum: Endpoint Number.
+* wAddr: new address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPTxAddr(u8 bEpNum, u16 wAddr)
+{
+ _SetEPTxAddr(bEpNum, wAddr);
+}
+/*******************************************************************************
+* Function Name : SetEPRxAddr
+* Description : Set the endpoint Rx buffer address.
+* Input : bEpNum: Endpoint Number.
+* wAddr: new address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPRxAddr(u8 bEpNum, u16 wAddr)
+{
+ _SetEPRxAddr(bEpNum, wAddr);
+}
+/*******************************************************************************
+* Function Name : GetEPTxAddr
+* Description : Returns the endpoint Tx buffer address.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Rx buffer address.
+*******************************************************************************/
+u16 GetEPTxAddr(u8 bEpNum)
+{
+ return(_GetEPTxAddr(bEpNum));
+}
+/*******************************************************************************
+* Function Name : GetEPRxAddr.
+* Description : Returns the endpoint Rx buffer address.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Rx buffer address.
+*******************************************************************************/
+u16 GetEPRxAddr(u8 bEpNum)
+{
+ return(_GetEPRxAddr(bEpNum));
+}
+/*******************************************************************************
+* Function Name : SetEPTxCount.
+* Description : Set the Tx count.
+* Input : bEpNum: Endpoint Number.
+* wCount: new count value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPTxCount(u8 bEpNum, u16 wCount)
+{
+ _SetEPTxCount(bEpNum, wCount);
+}
+/*******************************************************************************
+* Function Name : SetEPCountRxReg.
+* Description : Set the Count Rx Register value.
+* Input : *pdwReg: point to the register.
+* wCount: the new register value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPCountRxReg(u32 *pdwReg, u16 wCount)
+{
+ _SetEPCountRxReg(dwReg, wCount);
+}
+/*******************************************************************************
+* Function Name : SetEPRxCount
+* Description : Set the Rx count.
+* Input : bEpNum: Endpoint Number.
+* wCount: the new count value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPRxCount(u8 bEpNum, u16 wCount)
+{
+ _SetEPRxCount(bEpNum, wCount);
+}
+/*******************************************************************************
+* Function Name : GetEPTxCount
+* Description : Get the Tx count.
+* Input : bEpNum: Endpoint Number.
+* Output : None
+* Return : Tx count value.
+*******************************************************************************/
+u16 GetEPTxCount(u8 bEpNum)
+{
+ return(_GetEPTxCount(bEpNum));
+}
+/*******************************************************************************
+* Function Name : GetEPRxCount
+* Description : Get the Rx count.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Rx count value.
+*******************************************************************************/
+u16 GetEPRxCount(u8 bEpNum)
+{
+ return(_GetEPRxCount(bEpNum));
+}
+/*******************************************************************************
+* Function Name : SetEPDblBuffAddr
+* Description : Set the addresses of the buffer 0 and 1.
+* Input : bEpNum: Endpoint Number.
+* wBuf0Addr: new address of buffer 0.
+* wBuf1Addr: new address of buffer 1.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPDblBuffAddr(u8 bEpNum, u16 wBuf0Addr, u16 wBuf1Addr)
+{
+ _SetEPDblBuffAddr(bEpNum, wBuf0Addr, wBuf1Addr);
+}
+/*******************************************************************************
+* Function Name : SetEPDblBuf0Addr
+* Description : Set the Buffer 1 address.
+* Input : bEpNum: Endpoint Number
+* wBuf0Addr: new address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPDblBuf0Addr(u8 bEpNum, u16 wBuf0Addr)
+{
+ _SetEPDblBuf0Addr(bEpNum, wBuf0Addr);
+}
+/*******************************************************************************
+* Function Name : SetEPDblBuf1Addr
+* Description : Set the Buffer 1 address.
+* Input : bEpNum: Endpoint Number
+* wBuf1Addr: new address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPDblBuf1Addr(u8 bEpNum, u16 wBuf1Addr)
+{
+ _SetEPDblBuf1Addr(bEpNum, wBuf1Addr);
+}
+/*******************************************************************************
+* Function Name : GetEPDblBuf0Addr
+* Description : Returns the address of the Buffer 0.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+u16 GetEPDblBuf0Addr(u8 bEpNum)
+{
+ return(_GetEPDblBuf0Addr(bEpNum));
+}
+/*******************************************************************************
+* Function Name : GetEPDblBuf1Addr
+* Description : Returns the address of the Buffer 1.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Address of the Buffer 1.
+*******************************************************************************/
+u16 GetEPDblBuf1Addr(u8 bEpNum)
+{
+ return(_GetEPDblBuf1Addr(bEpNum));
+}
+/*******************************************************************************
+* Function Name : SetEPDblBuffCount
+* Description : Set the number of bytes for a double Buffer
+* endpoint.
+* Input : bEpNum,bDir, wCount
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPDblBuffCount(u8 bEpNum, u8 bDir, u16 wCount)
+{
+ _SetEPDblBuffCount(bEpNum, bDir, wCount);
+}
+/*******************************************************************************
+* Function Name : SetEPDblBuf0Count
+* Description : Set the number of bytes in the buffer 0 of a double Buffer
+* endpoint.
+* Input : bEpNum, bDir, wCount
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPDblBuf0Count(u8 bEpNum, u8 bDir, u16 wCount)
+{
+ _SetEPDblBuf0Count(bEpNum, bDir, wCount);
+}
+/*******************************************************************************
+* Function Name : SetEPDblBuf1Count
+* Description : Set the number of bytes in the buffer 0 of a double Buffer
+* endpoint.
+* Input : bEpNum, bDir, wCount
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void SetEPDblBuf1Count(u8 bEpNum, u8 bDir, u16 wCount)
+{
+ _SetEPDblBuf1Count(bEpNum, bDir, wCount);
+}
+/*******************************************************************************
+* Function Name : GetEPDblBuf0Count
+* Description : Returns the number of byte received in the buffer 0 of a double
+* Buffer endpoint.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint Buffer 0 count
+*******************************************************************************/
+u16 GetEPDblBuf0Count(u8 bEpNum)
+{
+ return(_GetEPDblBuf0Count(bEpNum));
+}
+/*******************************************************************************
+* Function Name : GetEPDblBuf1Count
+* Description : Returns the number of data received in the buffer 1 of a double
+* Buffer endpoint.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint Buffer 1 count.
+*******************************************************************************/
+u16 GetEPDblBuf1Count(u8 bEpNum)
+{
+ return(_GetEPDblBuf1Count(bEpNum));
+}
+/*******************************************************************************
+* Function Name : GetEPDblBufDir
+* Description : gets direction of the double buffered endpoint
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : EP_DBUF_OUT, EP_DBUF_IN,
+* EP_DBUF_ERR if the endpoint counter not yet programmed.
+*******************************************************************************/
+EP_DBUF_DIR GetEPDblBufDir(u8 bEpNum)
+{
+ if ((u16)(*_pEPRxCount(bEpNum) & 0xFC00) != 0)
+ return(EP_DBUF_OUT);
+ else if (((u16)(*_pEPTxCount(bEpNum)) & 0x03FF) != 0)
+ return(EP_DBUF_IN);
+ else
+ return(EP_DBUF_ERR);
+}
+/*******************************************************************************
+* Function Name : FreeUserBuffer
+* Description : free buffer used from the application realizing it to the line
+ toggles bit SW_BUF in the double buffered endpoint register
+* Input : bEpNum, bDir
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void FreeUserBuffer(u8 bEpNum, u8 bDir)
+{
+ if (bDir == EP_DBUF_OUT)
+ { /* OUT double buffered endpoint */
+ _ToggleDTOG_TX(bEpNum);
+ }
+ else if (bDir == EP_DBUF_IN)
+ { /* IN double buffered endpoint */
+ _ToggleDTOG_RX(bEpNum);
+ }
+}
+
+/*******************************************************************************
+* Function Name : ToWord
+* Description : merge two byte in a word.
+* Input : bh: byte high, bl: bytes low.
+* Output : None.
+* Return : resulted word.
+*******************************************************************************/
+u16 ToWord(u8 bh, u8 bl)
+{
+ u16 wRet;
+ wRet = (u16)bl | ((u16)bh << 8);
+ return(wRet);
+}
+/*******************************************************************************
+* Function Name : ByteSwap
+* Description : Swap two byte in a word.
+* Input : wSwW: word to Swap.
+* Output : None.
+* Return : resulted word.
+*******************************************************************************/
+u16 ByteSwap(u16 wSwW)
+{
+ u8 bTemp;
+ u16 wRet;
+ bTemp = (u8)(wSwW & 0xff);
+ wRet = (wSwW >> 8) | ((u16)bTemp << 8);
+ return(wRet);
+}
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_regs.h b/libmaple/usb/usb_lib/usb_regs.h
new file mode 100644
index 0000000..b63cc5f
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_regs.h
@@ -0,0 +1,627 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_regs.h
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Interface prototype functions to USB cell registers
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_REGS_H
+#define __USB_REGS_H
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef enum _EP_DBUF_DIR
+{
+ /* double buffered endpoint direction */
+ EP_DBUF_ERR,
+ EP_DBUF_OUT,
+ EP_DBUF_IN
+}EP_DBUF_DIR;
+
+/* endpoint buffer number */
+enum EP_BUF_NUM
+{
+ EP_NOBUF,
+ EP_BUF0,
+ EP_BUF1
+};
+
+/* Exported constants --------------------------------------------------------*/
+#define RegBase (0x40005C00L) /* USB_IP Peripheral Registers base address */
+#define PMAAddr (0x40006000L) /* USB_IP Packet Memory Area base address */
+
+/******************************************************************************/
+/* General registers */
+/******************************************************************************/
+
+/* Control register */
+#define CNTR ((volatile unsigned *)(RegBase + 0x40))
+/* Interrupt status register */
+#define ISTR ((volatile unsigned *)(RegBase + 0x44))
+/* Frame number register */
+#define FNR ((volatile unsigned *)(RegBase + 0x48))
+/* Device address register */
+#define DADDR ((volatile unsigned *)(RegBase + 0x4C))
+/* Buffer Table address register */
+#define BTABLE ((volatile unsigned *)(RegBase + 0x50))
+/******************************************************************************/
+/* Endpoint registers */
+/******************************************************************************/
+#define EP0REG ((volatile unsigned *)(RegBase)) /* endpoint 0 register address */
+
+/* endpoints enumeration */
+#define ENDP0 ((u8)0)
+#define ENDP1 ((u8)1)
+#define ENDP2 ((u8)2)
+#define ENDP3 ((u8)3)
+#define ENDP4 ((u8)4)
+#define ENDP5 ((u8)5)
+#define ENDP6 ((u8)6)
+#define ENDP7 ((u8)7)
+/******************************************************************************/
+/* ISTR interrupt events */
+/******************************************************************************/
+#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */
+#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */
+#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */
+#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */
+#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */
+#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */
+#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */
+#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */
+
+
+#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */
+#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */
+
+#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */
+#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/
+#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */
+#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */
+#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */
+#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */
+#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */
+#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */
+
+/******************************************************************************/
+/* CNTR control register bits definitions */
+/******************************************************************************/
+#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */
+#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */
+#define CNTR_ERRM (0x2000) /* ERRor Mask */
+#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */
+#define CNTR_SUSPM (0x0800) /* SUSPend Mask */
+#define CNTR_RESETM (0x0400) /* RESET Mask */
+#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */
+#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */
+
+
+#define CNTR_RESUME (0x0010) /* RESUME request */
+#define CNTR_FSUSP (0x0008) /* Force SUSPend */
+#define CNTR_LPMODE (0x0004) /* Low-power MODE */
+#define CNTR_PDWN (0x0002) /* Power DoWN */
+#define CNTR_FRES (0x0001) /* Force USB RESet */
+
+/******************************************************************************/
+/* FNR Frame Number Register bit definitions */
+/******************************************************************************/
+#define FNR_RXDP (0x8000) /* status of D+ data line */
+#define FNR_RXDM (0x4000) /* status of D- data line */
+#define FNR_LCK (0x2000) /* LoCKed */
+#define FNR_LSOF (0x1800) /* Lost SOF */
+#define FNR_FN (0x07FF) /* Frame Number */
+/******************************************************************************/
+/* DADDR Device ADDRess bit definitions */
+/******************************************************************************/
+#define DADDR_EF (0x80)
+#define DADDR_ADD (0x7F)
+/******************************************************************************/
+/* Endpoint register */
+/******************************************************************************/
+/* bit positions */
+#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */
+#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */
+#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */
+#define EP_SETUP (0x0800) /* EndPoint SETUP */
+#define EP_T_FIELD (0x0600) /* EndPoint TYPE */
+#define EP_KIND (0x0100) /* EndPoint KIND */
+#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */
+#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */
+#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */
+#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */
+
+/* EndPoint REGister MASK (no toggle fields) */
+#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD)
+
+/* EP_TYPE[1:0] EndPoint TYPE */
+#define EP_TYPE_MASK (0x0600) /* EndPoint TYPE Mask */
+#define EP_BULK (0x0000) /* EndPoint BULK */
+#define EP_CONTROL (0x0200) /* EndPoint CONTROL */
+#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */
+#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */
+#define EP_T_MASK (~EP_T_FIELD & EPREG_MASK)
+
+
+/* EP_KIND EndPoint KIND */
+#define EPKIND_MASK (~EP_KIND & EPREG_MASK)
+
+/* STAT_TX[1:0] STATus for TX transfer */
+#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */
+#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */
+#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */
+#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */
+#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */
+#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */
+#define EPTX_DTOGMASK (EPTX_STAT|EPREG_MASK)
+
+/* STAT_RX[1:0] STATus for RX transfer */
+#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */
+#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */
+#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */
+#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */
+#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */
+#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */
+#define EPRX_DTOGMASK (EPRX_STAT|EPREG_MASK)
+/* Exported macro ------------------------------------------------------------*/
+/* SetCNTR */
+#define _SetCNTR(wRegValue) (*CNTR = (u16)wRegValue)
+
+/* SetISTR */
+#define _SetISTR(wRegValue) (*ISTR = (u16)wRegValue)
+
+/* SetDADDR */
+#define _SetDADDR(wRegValue) (*DADDR = (u16)wRegValue)
+
+/* SetBTABLE */
+#define _SetBTABLE(wRegValue)(*BTABLE = (u16)(wRegValue & 0xFFF8))
+
+/* GetCNTR */
+#define _GetCNTR() ((u16) *CNTR)
+
+/* GetISTR */
+#define _GetISTR() ((u16) *ISTR)
+
+/* GetFNR */
+#define _GetFNR() ((u16) *FNR)
+
+/* GetDADDR */
+#define _GetDADDR() ((u16) *DADDR)
+
+/* GetBTABLE */
+#define _GetBTABLE() ((u16) *BTABLE)
+
+/* SetENDPOINT */
+#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \
+ (u16)wRegValue)
+
+/* GetENDPOINT */
+#define _GetENDPOINT(bEpNum) ((u16)(*(EP0REG + bEpNum)))
+
+/*******************************************************************************
+* Macro Name : SetEPType
+* Description : sets the type in the endpoint register(bits EP_TYPE[1:0])
+* Input : bEpNum: Endpoint Number.
+* wType
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPType(bEpNum,wType) (_SetENDPOINT(bEpNum,\
+ ((_GetENDPOINT(bEpNum) & EP_T_MASK) | wType)))
+
+/*******************************************************************************
+* Macro Name : GetEPType
+* Description : gets the type in the endpoint register(bits EP_TYPE[1:0])
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint Type
+*******************************************************************************/
+#define _GetEPType(bEpNum) (_GetENDPOINT(bEpNum) & EP_T_FIELD)
+
+/*******************************************************************************
+* Macro Name : SetEPTxStatus
+* Description : sets the status for tx transfer (bits STAT_TX[1:0]).
+* Input : bEpNum: Endpoint Number.
+* wState: new state
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPTxStatus(bEpNum,wState) {\
+ register u16 _wRegVal; \
+ _wRegVal = _GetENDPOINT(bEpNum) & EPTX_DTOGMASK;\
+ /* toggle first bit ? */ \
+ if((EPTX_DTOG1 & wState)!= 0) \
+ _wRegVal ^= EPTX_DTOG1; \
+ /* toggle second bit ? */ \
+ if((EPTX_DTOG2 & wState)!= 0) \
+ _wRegVal ^= EPTX_DTOG2; \
+ _SetENDPOINT(bEpNum, _wRegVal); \
+ } /* _SetEPTxStatus */
+
+/*******************************************************************************
+* Macro Name : SetEPRxStatus
+* Description : sets the status for rx transfer (bits STAT_TX[1:0])
+* Input : bEpNum: Endpoint Number.
+* wState: new state.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPRxStatus(bEpNum,wState) {\
+ register u16 _wRegVal; \
+ \
+ _wRegVal = _GetENDPOINT(bEpNum) & EPRX_DTOGMASK;\
+ /* toggle first bit ? */ \
+ if((EPRX_DTOG1 & wState)!= 0) \
+ _wRegVal ^= EPRX_DTOG1; \
+ /* toggle second bit ? */ \
+ if((EPRX_DTOG2 & wState)!= 0) \
+ _wRegVal ^= EPRX_DTOG2; \
+ _SetENDPOINT(bEpNum, _wRegVal); \
+ } /* _SetEPRxStatus */
+/*******************************************************************************
+* Macro Name : GetEPTxStatus / GetEPRxStatus
+* Description : gets the status for tx/rx transfer (bits STAT_TX[1:0]
+* /STAT_RX[1:0])
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : status .
+*******************************************************************************/
+#define _GetEPTxStatus(bEpNum) ((u16)_GetENDPOINT(bEpNum) & EPTX_STAT)
+
+#define _GetEPRxStatus(bEpNum) ((u16)_GetENDPOINT(bEpNum) & EPRX_STAT)
+
+/*******************************************************************************
+* Macro Name : SetEPTxValid / SetEPRxValid
+* Description : sets directly the VALID tx/rx-status into the enpoint register
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPTxValid(bEpNum) (_SetEPTxStatus(bEpNum, EP_TX_VALID))
+
+#define _SetEPRxValid(bEpNum) (_SetEPRxStatus(bEpNum, EP_RX_VALID))
+
+/*******************************************************************************
+* Macro Name : GetTxStallStatus / GetRxStallStatus.
+* Description : checks stall condition in an endpoint.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : TRUE = endpoint in stall condition.
+*******************************************************************************/
+#define _GetTxStallStatus(bEpNum) (_GetEPTxStatus(bEpNum) \
+ == EP_TX_STALL)
+#define _GetRxStallStatus(bEpNum) (_GetEPRxStatus(bEpNum) \
+ == EP_RX_STALL)
+
+/*******************************************************************************
+* Macro Name : SetEP_KIND / ClearEP_KIND.
+* Description : set & clear EP_KIND bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \
+ (_GetENDPOINT(bEpNum) | EP_KIND) & EPREG_MASK))
+#define _ClearEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \
+ (_GetENDPOINT(bEpNum) & EPKIND_MASK)))
+
+/*******************************************************************************
+* Macro Name : Set_Status_Out / Clear_Status_Out.
+* Description : Sets/clears directly STATUS_OUT bit in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _Set_Status_Out(bEpNum) _SetEP_KIND(bEpNum)
+#define _Clear_Status_Out(bEpNum) _ClearEP_KIND(bEpNum)
+
+/*******************************************************************************
+* Macro Name : SetEPDoubleBuff / ClearEPDoubleBuff.
+* Description : Sets/clears directly EP_KIND bit in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPDoubleBuff(bEpNum) _SetEP_KIND(bEpNum)
+#define _ClearEPDoubleBuff(bEpNum) _ClearEP_KIND(bEpNum)
+
+/*******************************************************************************
+* Macro Name : ClearEP_CTR_RX / ClearEP_CTR_TX.
+* Description : Clears bit CTR_RX / CTR_TX in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\
+ _GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK))
+#define _ClearEP_CTR_TX(bEpNum) (_SetENDPOINT(bEpNum,\
+ _GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK))
+
+/*******************************************************************************
+* Macro Name : ToggleDTOG_RX / ToggleDTOG_TX .
+* Description : Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _ToggleDTOG_RX(bEpNum) (_SetENDPOINT(bEpNum, \
+ EP_DTOG_RX | (_GetENDPOINT(bEpNum) & EPREG_MASK)))
+#define _ToggleDTOG_TX(bEpNum) (_SetENDPOINT(bEpNum, \
+ EP_DTOG_TX | (_GetENDPOINT(bEpNum) & EPREG_MASK)))
+
+/*******************************************************************************
+* Macro Name : ClearDTOG_RX / ClearDTOG_TX.
+* Description : Clears DTOG_RX / DTOG_TX bit in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _ClearDTOG_RX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_RX) != 0)\
+ _ToggleDTOG_RX(bEpNum)
+#define _ClearDTOG_TX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_TX) != 0)\
+ _ToggleDTOG_TX(bEpNum)
+/*******************************************************************************
+* Macro Name : SetEPAddress.
+* Description : Sets address in an endpoint register.
+* Input : bEpNum: Endpoint Number.
+* bAddr: Address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPAddress(bEpNum,bAddr) _SetENDPOINT(bEpNum,\
+ (_GetENDPOINT(bEpNum) & EPREG_MASK) | bAddr)
+
+/*******************************************************************************
+* Macro Name : GetEPAddress.
+* Description : Gets address in an endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _GetEPAddress(bEpNum) ((u8)(_GetENDPOINT(bEpNum) & EPADDR_FIELD))
+
+#define _pEPTxAddr(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr))
+#define _pEPTxCount(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr))
+#define _pEPRxAddr(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr))
+#define _pEPRxCount(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr))
+
+/*******************************************************************************
+* Macro Name : SetEPTxAddr / SetEPRxAddr.
+* Description : sets address of the tx/rx buffer.
+* Input : bEpNum: Endpoint Number.
+* wAddr: address to be set (must be word aligned).
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPTxAddr(bEpNum,wAddr) (*_pEPTxAddr(bEpNum) = ((wAddr >> 1) << 1))
+#define _SetEPRxAddr(bEpNum,wAddr) (*_pEPRxAddr(bEpNum) = ((wAddr >> 1) << 1))
+
+/*******************************************************************************
+* Macro Name : GetEPTxAddr / GetEPRxAddr.
+* Description : Gets address of the tx/rx buffer.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : address of the buffer.
+*******************************************************************************/
+#define _GetEPTxAddr(bEpNum) ((u16)*_pEPTxAddr(bEpNum))
+#define _GetEPRxAddr(bEpNum) ((u16)*_pEPRxAddr(bEpNum))
+
+/*******************************************************************************
+* Macro Name : SetEPCountRxReg.
+* Description : Sets counter of rx buffer with no. of blocks.
+* Input : pdwReg: pointer to counter.
+* wCount: Counter.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _BlocksOf32(dwReg,wCount,wNBlocks) {\
+ wNBlocks = wCount >> 5;\
+ if((wCount & 0x1f) == 0)\
+ wNBlocks--;\
+ *pdwReg = (u32)((wNBlocks << 10) | 0x8000);\
+ }/* _BlocksOf32 */
+
+#define _BlocksOf2(dwReg,wCount,wNBlocks) {\
+ wNBlocks = wCount >> 1;\
+ if((wCount & 0x1) != 0)\
+ wNBlocks++;\
+ *pdwReg = (u32)(wNBlocks << 10);\
+ }/* _BlocksOf2 */
+
+#define _SetEPCountRxReg(dwReg,wCount) {\
+ u16 wNBlocks;\
+ if(wCount > 62){_BlocksOf32(dwReg,wCount,wNBlocks);}\
+ else {_BlocksOf2(dwReg,wCount,wNBlocks);}\
+ }/* _SetEPCountRxReg */
+
+
+
+#define _SetEPRxDblBuf0Count(bEpNum,wCount) {\
+ u32 *pdwReg = _pEPTxCount(bEpNum); \
+ _SetEPCountRxReg(pdwReg, wCount);\
+ }
+/*******************************************************************************
+* Macro Name : SetEPTxCount / SetEPRxCount.
+* Description : sets counter for the tx/rx buffer.
+* Input : bEpNum: endpoint number.
+* wCount: Counter value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount)
+#define _SetEPRxCount(bEpNum,wCount) {\
+ u32 *pdwReg = _pEPRxCount(bEpNum); \
+ _SetEPCountRxReg(pdwReg, wCount);\
+ }
+/*******************************************************************************
+* Macro Name : GetEPTxCount / GetEPRxCount.
+* Description : gets counter of the tx buffer.
+* Input : bEpNum: endpoint number.
+* Output : None.
+* Return : Counter value.
+*******************************************************************************/
+#define _GetEPTxCount(bEpNum)((u16)(*_pEPTxCount(bEpNum)) & 0x3ff)
+#define _GetEPRxCount(bEpNum)((u16)(*_pEPRxCount(bEpNum)) & 0x3ff)
+
+/*******************************************************************************
+* Macro Name : SetEPDblBuf0Addr / SetEPDblBuf1Addr.
+* Description : Sets buffer 0/1 address in a double buffer endpoint.
+* Input : bEpNum: endpoint number.
+* : wBuf0Addr: buffer 0 address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPDblBuf0Addr(bEpNum,wBuf0Addr) {_SetEPTxAddr(bEpNum, wBuf0Addr);}
+#define _SetEPDblBuf1Addr(bEpNum,wBuf1Addr) {_SetEPRxAddr(bEpNum, wBuf1Addr);}
+
+/*******************************************************************************
+* Macro Name : SetEPDblBuffAddr.
+* Description : Sets addresses in a double buffer endpoint.
+* Input : bEpNum: endpoint number.
+* : wBuf0Addr: buffer 0 address.
+* : wBuf1Addr = buffer 1 address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPDblBuffAddr(bEpNum,wBuf0Addr,wBuf1Addr) { \
+ _SetEPDblBuf0Addr(bEpNum, wBuf0Addr);\
+ _SetEPDblBuf1Addr(bEpNum, wBuf1Addr);\
+ } /* _SetEPDblBuffAddr */
+
+/*******************************************************************************
+* Macro Name : GetEPDblBuf0Addr / GetEPDblBuf1Addr.
+* Description : Gets buffer 0/1 address of a double buffer endpoint.
+* Input : bEpNum: endpoint number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _GetEPDblBuf0Addr(bEpNum) (_GetEPTxAddr(bEpNum))
+#define _GetEPDblBuf1Addr(bEpNum) (_GetEPRxAddr(bEpNum))
+
+/*******************************************************************************
+* Macro Name : SetEPDblBuffCount / SetEPDblBuf0Count / SetEPDblBuf1Count.
+* Description : Gets buffer 0/1 address of a double buffer endpoint.
+* Input : bEpNum: endpoint number.
+* : bDir: endpoint dir EP_DBUF_OUT = OUT
+* EP_DBUF_IN = IN
+* : wCount: Counter value
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPDblBuf0Count(bEpNum, bDir, wCount) { \
+ if(bDir == EP_DBUF_OUT)\
+ /* OUT endpoint */ \
+ {_SetEPRxDblBuf0Count(bEpNum,wCount);} \
+ else if(bDir == EP_DBUF_IN)\
+ /* IN endpoint */ \
+ *_pEPTxCount(bEpNum) = (u32)wCount; \
+ } /* SetEPDblBuf0Count*/
+
+#define _SetEPDblBuf1Count(bEpNum, bDir, wCount) { \
+ if(bDir == EP_DBUF_OUT)\
+ /* OUT endpoint */ \
+ {_SetEPRxCount(bEpNum,wCount);}\
+ else if(bDir == EP_DBUF_IN)\
+ /* IN endpoint */\
+ *_pEPRxCount(bEpNum) = (u32)wCount; \
+ } /* SetEPDblBuf1Count */
+
+#define _SetEPDblBuffCount(bEpNum, bDir, wCount) {\
+ _SetEPDblBuf0Count(bEpNum, bDir, wCount); \
+ _SetEPDblBuf1Count(bEpNum, bDir, wCount); \
+ } /* _SetEPDblBuffCount */
+
+/*******************************************************************************
+* Macro Name : GetEPDblBuf0Count / GetEPDblBuf1Count.
+* Description : Gets buffer 0/1 rx/tx counter for double buffering.
+* Input : bEpNum: endpoint number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _GetEPDblBuf0Count(bEpNum) (_GetEPTxCount(bEpNum))
+#define _GetEPDblBuf1Count(bEpNum) (_GetEPRxCount(bEpNum))
+
+
+/* External variables --------------------------------------------------------*/
+extern volatile u16 wIstr; /* ISTR register last read value */
+
+/* Exported functions ------------------------------------------------------- */
+void SetCNTR(u16 /*wRegValue*/);
+void SetISTR(u16 /*wRegValue*/);
+void SetDADDR(u16 /*wRegValue*/);
+void SetBTABLE(u16 /*wRegValue*/);
+u16 GetCNTR(void);
+u16 GetISTR(void);
+u16 GetFNR(void);
+u16 GetDADDR(void);
+u16 GetBTABLE(void);
+void SetENDPOINT(u8 /*bEpNum*/, u16 /*wRegValue*/);
+u16 GetENDPOINT(u8 /*bEpNum*/);
+void SetEPType(u8 /*bEpNum*/, u16 /*wType*/);
+u16 GetEPType(u8 /*bEpNum*/);
+void SetEPTxStatus(u8 /*bEpNum*/, u16 /*wState*/);
+void SetEPRxStatus(u8 /*bEpNum*/, u16 /*wState*/);
+void SetDouBleBuffEPStall(u8 /*bEpNum*/, u8 bDir);
+u16 GetEPTxStatus(u8 /*bEpNum*/);
+u16 GetEPRxStatus(u8 /*bEpNum*/);
+void SetEPTxValid(u8 /*bEpNum*/);
+void SetEPRxValid(u8 /*bEpNum*/);
+u16 GetTxStallStatus(u8 /*bEpNum*/);
+u16 GetRxStallStatus(u8 /*bEpNum*/);
+void SetEP_KIND(u8 /*bEpNum*/);
+void ClearEP_KIND(u8 /*bEpNum*/);
+void Set_Status_Out(u8 /*bEpNum*/);
+void Clear_Status_Out(u8 /*bEpNum*/);
+void SetEPDoubleBuff(u8 /*bEpNum*/);
+void ClearEPDoubleBuff(u8 /*bEpNum*/);
+void ClearEP_CTR_RX(u8 /*bEpNum*/);
+void ClearEP_CTR_TX(u8 /*bEpNum*/);
+void ToggleDTOG_RX(u8 /*bEpNum*/);
+void ToggleDTOG_TX(u8 /*bEpNum*/);
+void ClearDTOG_RX(u8 /*bEpNum*/);
+void ClearDTOG_TX(u8 /*bEpNum*/);
+void SetEPAddress(u8 /*bEpNum*/, u8 /*bAddr*/);
+u8 GetEPAddress(u8 /*bEpNum*/);
+void SetEPTxAddr(u8 /*bEpNum*/, u16 /*wAddr*/);
+void SetEPRxAddr(u8 /*bEpNum*/, u16 /*wAddr*/);
+u16 GetEPTxAddr(u8 /*bEpNum*/);
+u16 GetEPRxAddr(u8 /*bEpNum*/);
+void SetEPCountRxReg(u32 * /*pdwReg*/, u16 /*wCount*/);
+void SetEPTxCount(u8 /*bEpNum*/, u16 /*wCount*/);
+void SetEPRxCount(u8 /*bEpNum*/, u16 /*wCount*/);
+u16 GetEPTxCount(u8 /*bEpNum*/);
+u16 GetEPRxCount(u8 /*bEpNum*/);
+void SetEPDblBuf0Addr(u8 /*bEpNum*/, u16 /*wBuf0Addr*/);
+void SetEPDblBuf1Addr(u8 /*bEpNum*/, u16 /*wBuf1Addr*/);
+void SetEPDblBuffAddr(u8 /*bEpNum*/, u16 /*wBuf0Addr*/, u16 /*wBuf1Addr*/);
+u16 GetEPDblBuf0Addr(u8 /*bEpNum*/);
+u16 GetEPDblBuf1Addr(u8 /*bEpNum*/);
+void SetEPDblBuffCount(u8 /*bEpNum*/, u8 /*bDir*/, u16 /*wCount*/);
+void SetEPDblBuf0Count(u8 /*bEpNum*/, u8 /*bDir*/, u16 /*wCount*/);
+void SetEPDblBuf1Count(u8 /*bEpNum*/, u8 /*bDir*/, u16 /*wCount*/);
+u16 GetEPDblBuf0Count(u8 /*bEpNum*/);
+u16 GetEPDblBuf1Count(u8 /*bEpNum*/);
+EP_DBUF_DIR GetEPDblBufDir(u8 /*bEpNum*/);
+void FreeUserBuffer(u8 bEpNum/*bEpNum*/, u8 bDir);
+u16 ToWord(u8, u8);
+u16 ByteSwap(u16);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __USB_REGS_H */
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/usb/usb_lib/usb_type.h b/libmaple/usb/usb_lib/usb_type.h
new file mode 100644
index 0000000..34b3bf5
--- /dev/null
+++ b/libmaple/usb/usb_lib/usb_type.h
@@ -0,0 +1,77 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_type.h
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Type definitions used by the USB Library
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_TYPE_H
+#define __USB_TYPE_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+typedef signed long s32;
+typedef signed short s16;
+typedef signed char s8;
+
+typedef volatile signed long vs32;
+typedef volatile signed short vs16;
+typedef volatile signed char vs8;
+
+typedef unsigned long u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+
+typedef unsigned long const uc32; /* Read Only */
+typedef unsigned short const uc16; /* Read Only */
+typedef unsigned char const uc8; /* Read Only */
+
+typedef volatile unsigned long vu32;
+typedef volatile unsigned short vu16;
+typedef volatile unsigned char vu8;
+
+typedef volatile unsigned long const vuc32; /* Read Only */
+typedef volatile unsigned short const vuc16; /* Read Only */
+typedef volatile unsigned char const vuc8; /* Read Only */
+
+
+typedef enum
+{
+ FALSE = 0, TRUE = !FALSE
+}
+USB_Bool;
+
+typedef enum { RESET = 0, SET = !RESET } FlagStatus, ITStatus;
+
+typedef enum { DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
+
+typedef enum { ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
+
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+/* External variables --------------------------------------------------------*/
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __USB_TYPE_H */
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/util.c b/libmaple/util.c
new file mode 100644
index 0000000..4c0b2c8
--- /dev/null
+++ b/libmaple/util.c
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/util.c
+ * @brief Utility procedures for debugging
+ */
+
+#include <libmaple/libmaple.h>
+#include <libmaple/usart.h>
+#include <libmaple/gpio.h>
+#include <libmaple/nvic.h>
+
+/* (Undocumented) hooks used by Wirish to direct our behavior here */
+extern __weak void __lm_error(void);
+extern __weak usart_dev* __lm_enable_error_usart(void);
+
+/* If you define ERROR_LED_PORT and ERROR_LED_PIN, then a failed
+ * ASSERT() will also throb() an LED connected to that port and pin.
+ */
+#if defined(ERROR_LED_PORT) && defined(ERROR_LED_PIN)
+#define HAVE_ERROR_LED
+#endif
+
+/* (Called from exc.S with global interrupts disabled.) */
+__attribute__((noreturn)) void __error(void) {
+ if (__lm_error) {
+ __lm_error();
+ }
+ /* Reenable global interrupts */
+ nvic_globalirq_enable();
+ throb();
+}
+
+/*
+ * Print an error message on a UART upon a failed assertion (if one is
+ * available), and punt to __error().
+ *
+ * @param file Source file of failed assertion
+ * @param line Source line of failed assertion
+ * @param exp String representation of failed assertion
+ * @sideeffect Turns of all peripheral interrupts except USB.
+ */
+void _fail(const char* file, int line, const char* exp) {
+ if (__lm_enable_error_usart) {
+ /* Initialize the error USART */
+ usart_dev *err_usart = __lm_enable_error_usart();
+
+ /* Print failed assert message */
+ usart_putstr(err_usart, "ERROR: FAILED ASSERT(");
+ usart_putstr(err_usart, exp);
+ usart_putstr(err_usart, "): ");
+ usart_putstr(err_usart, file);
+ usart_putstr(err_usart, ": ");
+ usart_putudec(err_usart, line);
+ usart_putc(err_usart, '\n');
+ usart_putc(err_usart, '\r');
+ }
+ /* Shutdown and error fade */
+ __error();
+}
+
+/*
+ * Provide an __assert_func handler to libc so that calls to assert()
+ * get redirected to _fail.
+ */
+void __assert_func(const char* file, int line, const char* method,
+ const char* expression) {
+ _fail(file, line, expression);
+}
+
+/*
+ * Provide an abort() implementation that aborts execution and punts
+ * to __error().
+ */
+void abort() {
+ if (__lm_enable_error_usart) {
+ /* Initialize the error USART */
+ usart_dev *err_usart = __lm_enable_error_usart();
+ /* Print abort message. */
+ usart_putstr(err_usart, "ERROR: PROGRAM ABORTED VIA abort()\r\n");
+ }
+
+ /* Shutdown and error fade */
+ __error();
+}
+
+/* This was public as of v0.0.12, so we've got to keep it public. */
+/**
+ * @brief Fades the error LED on and off
+ * @sideeffect Sets output push-pull on ERROR_LED_PIN.
+ */
+__attribute__((noreturn)) void throb(void) {
+#ifdef HAVE_ERROR_LED
+ int32 slope = 1;
+ uint32 CC = 0x0000;
+ uint32 TOP_CNT = 0x0200;
+ uint32 i = 0;
+
+ gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT);
+ /* Error fade. */
+ while (1) {
+ if (CC == TOP_CNT) {
+ slope = -1;
+ } else if (CC == 0) {
+ slope = 1;
+ }
+
+ if (i == TOP_CNT) {
+ CC += slope;
+ i = 0;
+ }
+
+ if (i < CC) {
+ gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 1);
+ } else {
+ gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 0);
+ }
+ i++;
+ }
+#else
+ /* No error LED is defined; do nothing. */
+ while (1)
+ ;
+#endif
+}
diff --git a/libraries/FreeRTOS/MapleFreeRTOS.cpp b/libraries/FreeRTOS/MapleFreeRTOS.cpp
new file mode 100644
index 0000000..d235ceb
--- /dev/null
+++ b/libraries/FreeRTOS/MapleFreeRTOS.cpp
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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 "MapleFreeRTOS.h"
+
+extern "C" {
+
+void vApplicationStackOverflowHook(xTaskHandle *pxTask,
+ signed char *pcTaskName) {
+ /* This function will get called if a task overflows its stack.
+ * If the parameters are corrupt then inspect pxCurrentTCB to find
+ * which was the offending task. */
+
+ (void) pxTask;
+ (void) pcTaskName;
+
+ while (1)
+ ;
+}
+
+}
diff --git a/libraries/FreeRTOS/MapleFreeRTOS.h b/libraries/FreeRTOS/MapleFreeRTOS.h
new file mode 100644
index 0000000..dc06979
--- /dev/null
+++ b/libraries/FreeRTOS/MapleFreeRTOS.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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 __MAPLE_FREERTOS_H__
+#define __MAPLE_FREERTOS_H__
+
+#include <wirish/wirish.h>
+
+extern "C" {
+#define GCC_ARMCM3
+#include "utility/FreeRTOS.h"
+#include "utility/task.h"
+#include "utility/queue.h"
+#include "utility/semphr.h"
+}
+
+#endif
diff --git a/libraries/FreeRTOS/keywords.txt b/libraries/FreeRTOS/keywords.txt
new file mode 100644
index 0000000..4a20bae
--- /dev/null
+++ b/libraries/FreeRTOS/keywords.txt
@@ -0,0 +1,27 @@
+#######################################
+# Syntax Coloring Map For CoOS
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+vTaskDelay KEYWORD2
+vTaskDelayUntil KEYWORD2
+xTaskCreate KEYWORD2
+vTaskSuspend KEYWORD2
+vTaskDelete KEYWORD2
+vTaskPrioritySet KEYWORD2
+uxTaskPriorityGet KEYWORD2
+vTaskStartScheduler KEYWORD2
+vApplicationIdleHook KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+configUSE_IDLE_HOOK LITERAL1
+configMINIMAL_STACK_SIZE LITERAL1
+tskIDLE_PRIORITY LITERAL1 \ No newline at end of file
diff --git a/libraries/FreeRTOS/rules.mk b/libraries/FreeRTOS/rules.mk
new file mode 100644
index 0000000..2b415ba
--- /dev/null
+++ b/libraries/FreeRTOS/rules.mk
@@ -0,0 +1,38 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+BUILDDIRS += $(BUILD_PATH)/$(d)/utility
+
+# Local flags
+CXXFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+
+# Local rules and targets
+cSRCS_$(d) := utility/croutine.c \
+ utility/heap_2.c \
+ utility/list.c \
+ utility/port.c \
+ utility/queue.c \
+ utility/timers.c \
+ utility/tasks.c \
+
+cppSRCS_$(d) := MapleFreeRTOS.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_CXXFLAGS := $(CXXFLAGS_$(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/FreeRTOS/utility/FreeRTOS.h b/libraries/FreeRTOS/utility/FreeRTOS.h
new file mode 100755
index 0000000..a609bb3
--- /dev/null
+++ b/libraries/FreeRTOS/utility/FreeRTOS.h
@@ -0,0 +1,468 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#ifndef INC_FREERTOS_H
+#define INC_FREERTOS_H
+
+
+/*
+ * Include the generic headers required for the FreeRTOS port being used.
+ */
+#include <stddef.h>
+
+/* Basic FreeRTOS definitions. */
+#include "projdefs.h"
+
+/* Application specific configuration options. */
+#include "FreeRTOSConfig.h"
+
+/* Definitions specific to the port being used. */
+#include "portable.h"
+
+
+/* Defines the prototype to which the application task hook function must
+conform. */
+typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * );
+
+
+
+
+
+/*
+ * Check all the required application specific macros have been defined.
+ * These macros are application specific and (as downloaded) are defined
+ * within FreeRTOSConfig.h.
+ */
+
+#ifndef configUSE_PREEMPTION
+ #error Missing definition: configUSE_PREEMPTION should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_IDLE_HOOK
+ #error Missing definition: configUSE_IDLE_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_TICK_HOOK
+ #error Missing definition: configUSE_TICK_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_CO_ROUTINES
+ #error Missing definition: configUSE_CO_ROUTINES should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskPrioritySet
+ #error Missing definition: INCLUDE_vTaskPrioritySet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_uxTaskPriorityGet
+ #error Missing definition: INCLUDE_uxTaskPriorityGet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelete
+ #error Missing definition: INCLUDE_vTaskDelete should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskCleanUpResources
+ #error Missing definition: INCLUDE_vTaskCleanUpResources should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskSuspend
+ #error Missing definition: INCLUDE_vTaskSuspend should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelayUntil
+ #error Missing definition: INCLUDE_vTaskDelayUntil should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelay
+ #error Missing definition: INCLUDE_vTaskDelay should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_16_BIT_TICKS
+ #error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_APPLICATION_TASK_TAG
+ #define configUSE_APPLICATION_TASK_TAG 0
+#endif
+
+#ifndef INCLUDE_uxTaskGetStackHighWaterMark
+ #define INCLUDE_uxTaskGetStackHighWaterMark 0
+#endif
+
+#ifndef configUSE_RECURSIVE_MUTEXES
+ #define configUSE_RECURSIVE_MUTEXES 0
+#endif
+
+#ifndef configUSE_MUTEXES
+ #define configUSE_MUTEXES 0
+#endif
+
+#ifndef configUSE_TIMERS
+ #define configUSE_TIMERS 0
+#endif
+
+#ifndef configUSE_COUNTING_SEMAPHORES
+ #define configUSE_COUNTING_SEMAPHORES 0
+#endif
+
+#ifndef configUSE_ALTERNATIVE_API
+ #define configUSE_ALTERNATIVE_API 0
+#endif
+
+#ifndef portCRITICAL_NESTING_IN_TCB
+ #define portCRITICAL_NESTING_IN_TCB 0
+#endif
+
+#ifndef configMAX_TASK_NAME_LEN
+ #define configMAX_TASK_NAME_LEN 16
+#endif
+
+#ifndef configIDLE_SHOULD_YIELD
+ #define configIDLE_SHOULD_YIELD 1
+#endif
+
+#if configMAX_TASK_NAME_LEN < 1
+ #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h
+#endif
+
+#ifndef INCLUDE_xTaskResumeFromISR
+ #define INCLUDE_xTaskResumeFromISR 1
+#endif
+
+#ifndef configASSERT
+ #define configASSERT( x )
+#endif
+
+/* The timers module relies on xTaskGetSchedulerState(). */
+#if configUSE_TIMERS == 1
+
+ #ifndef configTIMER_TASK_PRIORITY
+ #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined.
+ #endif /* configTIMER_TASK_PRIORITY */
+
+ #ifndef configTIMER_QUEUE_LENGTH
+ #error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined.
+ #endif /* configTIMER_QUEUE_LENGTH */
+
+ #ifndef configTIMER_TASK_STACK_DEPTH
+ #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined.
+ #endif /* configTIMER_TASK_STACK_DEPTH */
+
+#endif /* configUSE_TIMERS */
+
+#ifndef INCLUDE_xTaskGetSchedulerState
+ #define INCLUDE_xTaskGetSchedulerState 0
+#endif
+
+#ifndef INCLUDE_xTaskGetCurrentTaskHandle
+ #define INCLUDE_xTaskGetCurrentTaskHandle 0
+#endif
+
+
+#ifndef portSET_INTERRUPT_MASK_FROM_ISR
+ #define portSET_INTERRUPT_MASK_FROM_ISR() 0
+#endif
+
+#ifndef portCLEAR_INTERRUPT_MASK_FROM_ISR
+ #define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue
+#endif
+
+
+#ifndef configQUEUE_REGISTRY_SIZE
+ #define configQUEUE_REGISTRY_SIZE 0U
+#endif
+
+#if ( configQUEUE_REGISTRY_SIZE < 1U )
+ #define vQueueAddToRegistry( xQueue, pcName )
+ #define vQueueUnregisterQueue( xQueue )
+#endif
+
+
+/* Remove any unused trace macros. */
+#ifndef traceSTART
+ /* Used to perform any necessary initialisation - for example, open a file
+ into which trace is to be written. */
+ #define traceSTART()
+#endif
+
+#ifndef traceEND
+ /* Use to close a trace, for example close a file into which trace has been
+ written. */
+ #define traceEND()
+#endif
+
+#ifndef traceTASK_SWITCHED_IN
+ /* Called after a task has been selected to run. pxCurrentTCB holds a pointer
+ to the task control block of the selected task. */
+ #define traceTASK_SWITCHED_IN()
+#endif
+
+#ifndef traceTASK_SWITCHED_OUT
+ /* Called before a task has been selected to run. pxCurrentTCB holds a pointer
+ to the task control block of the task being switched out. */
+ #define traceTASK_SWITCHED_OUT()
+#endif
+
+#ifndef traceBLOCKING_ON_QUEUE_RECEIVE
+ /* Task is about to block because it cannot read from a
+ queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore
+ upon which the read was attempted. pxCurrentTCB points to the TCB of the
+ task that attempted the read. */
+ #define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue )
+#endif
+
+#ifndef traceBLOCKING_ON_QUEUE_SEND
+ /* Task is about to block because it cannot write to a
+ queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore
+ upon which the write was attempted. pxCurrentTCB points to the TCB of the
+ task that attempted the write. */
+ #define traceBLOCKING_ON_QUEUE_SEND( pxQueue )
+#endif
+
+#ifndef configCHECK_FOR_STACK_OVERFLOW
+ #define configCHECK_FOR_STACK_OVERFLOW 0
+#endif
+
+/* The following event macros are embedded in the kernel API calls. */
+
+#ifndef traceQUEUE_CREATE
+ #define traceQUEUE_CREATE( pxNewQueue )
+#endif
+
+#ifndef traceQUEUE_CREATE_FAILED
+ #define traceQUEUE_CREATE_FAILED()
+#endif
+
+#ifndef traceCREATE_MUTEX
+ #define traceCREATE_MUTEX( pxNewQueue )
+#endif
+
+#ifndef traceCREATE_MUTEX_FAILED
+ #define traceCREATE_MUTEX_FAILED()
+#endif
+
+#ifndef traceGIVE_MUTEX_RECURSIVE
+ #define traceGIVE_MUTEX_RECURSIVE( pxMutex )
+#endif
+
+#ifndef traceGIVE_MUTEX_RECURSIVE_FAILED
+ #define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex )
+#endif
+
+#ifndef traceTAKE_MUTEX_RECURSIVE
+ #define traceTAKE_MUTEX_RECURSIVE( pxMutex )
+#endif
+
+#ifndef traceTAKE_MUTEX_RECURSIVE_FAILED
+ #define traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex )
+#endif
+
+#ifndef traceCREATE_COUNTING_SEMAPHORE
+ #define traceCREATE_COUNTING_SEMAPHORE()
+#endif
+
+#ifndef traceCREATE_COUNTING_SEMAPHORE_FAILED
+ #define traceCREATE_COUNTING_SEMAPHORE_FAILED()
+#endif
+
+#ifndef traceQUEUE_SEND
+ #define traceQUEUE_SEND( pxQueue )
+#endif
+
+#ifndef traceQUEUE_SEND_FAILED
+ #define traceQUEUE_SEND_FAILED( pxQueue )
+#endif
+
+#ifndef traceQUEUE_RECEIVE
+ #define traceQUEUE_RECEIVE( pxQueue )
+#endif
+
+#ifndef traceQUEUE_PEEK
+ #define traceQUEUE_PEEK( pxQueue )
+#endif
+
+#ifndef traceQUEUE_RECEIVE_FAILED
+ #define traceQUEUE_RECEIVE_FAILED( pxQueue )
+#endif
+
+#ifndef traceQUEUE_SEND_FROM_ISR
+ #define traceQUEUE_SEND_FROM_ISR( pxQueue )
+#endif
+
+#ifndef traceQUEUE_SEND_FROM_ISR_FAILED
+ #define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue )
+#endif
+
+#ifndef traceQUEUE_RECEIVE_FROM_ISR
+ #define traceQUEUE_RECEIVE_FROM_ISR( pxQueue )
+#endif
+
+#ifndef traceQUEUE_RECEIVE_FROM_ISR_FAILED
+ #define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue )
+#endif
+
+#ifndef traceQUEUE_DELETE
+ #define traceQUEUE_DELETE( pxQueue )
+#endif
+
+#ifndef traceTASK_CREATE
+ #define traceTASK_CREATE( pxNewTCB )
+#endif
+
+#ifndef traceTASK_CREATE_FAILED
+ #define traceTASK_CREATE_FAILED()
+#endif
+
+#ifndef traceTASK_DELETE
+ #define traceTASK_DELETE( pxTaskToDelete )
+#endif
+
+#ifndef traceTASK_DELAY_UNTIL
+ #define traceTASK_DELAY_UNTIL()
+#endif
+
+#ifndef traceTASK_DELAY
+ #define traceTASK_DELAY()
+#endif
+
+#ifndef traceTASK_PRIORITY_SET
+ #define traceTASK_PRIORITY_SET( pxTask, uxNewPriority )
+#endif
+
+#ifndef traceTASK_SUSPEND
+ #define traceTASK_SUSPEND( pxTaskToSuspend )
+#endif
+
+#ifndef traceTASK_RESUME
+ #define traceTASK_RESUME( pxTaskToResume )
+#endif
+
+#ifndef traceTASK_RESUME_FROM_ISR
+ #define traceTASK_RESUME_FROM_ISR( pxTaskToResume )
+#endif
+
+#ifndef traceTASK_INCREMENT_TICK
+ #define traceTASK_INCREMENT_TICK( xTickCount )
+#endif
+
+#ifndef traceTIMER_CREATE
+ #define traceTIMER_CREATE( pxNewTimer )
+#endif
+
+#ifndef traceTIMER_CREATE_FAILED
+ #define traceTIMER_CREATE_FAILED()
+#endif
+
+#ifndef traceTIMER_COMMAND_SEND
+ #define traceTIMER_COMMAND_SEND( xTimer, xMessageID, xMessageValueValue, xReturn )
+#endif
+
+#ifndef traceTIMER_EXPIRED
+ #define traceTIMER_EXPIRED( pxTimer )
+#endif
+
+#ifndef traceTIMER_COMMAND_RECEIVED
+ #define traceTIMER_COMMAND_RECEIVED( pxTimer, xMessageID, xMessageValue )
+#endif
+
+#ifndef configGENERATE_RUN_TIME_STATS
+ #define configGENERATE_RUN_TIME_STATS 0
+#endif
+
+#if ( configGENERATE_RUN_TIME_STATS == 1 )
+
+ #ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS
+ #error If configGENERATE_RUN_TIME_STATS is defined then portCONFIGURE_TIMER_FOR_RUN_TIME_STATS must also be defined. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS should call a port layer function to setup a peripheral timer/counter that can then be used as the run time counter time base.
+ #endif /* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS */
+
+ #ifndef portGET_RUN_TIME_COUNTER_VALUE
+ #ifndef portALT_GET_RUN_TIME_COUNTER_VALUE
+ #error If configGENERATE_RUN_TIME_STATS is defined then either portGET_RUN_TIME_COUNTER_VALUE or portALT_GET_RUN_TIME_COUNTER_VALUE must also be defined. See the examples provided and the FreeRTOS web site for more information.
+ #endif /* portALT_GET_RUN_TIME_COUNTER_VALUE */
+ #endif /* portGET_RUN_TIME_COUNTER_VALUE */
+
+#endif /* configGENERATE_RUN_TIME_STATS */
+
+#ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS
+ #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
+#endif
+
+#ifndef configUSE_MALLOC_FAILED_HOOK
+ #define configUSE_MALLOC_FAILED_HOOK 0
+#endif
+
+#ifndef portPRIVILEGE_BIT
+ #define portPRIVILEGE_BIT ( ( unsigned portBASE_TYPE ) 0x00 )
+#endif
+
+#ifndef portYIELD_WITHIN_API
+ #define portYIELD_WITHIN_API portYIELD
+#endif
+
+#ifndef pvPortMallocAligned
+ #define pvPortMallocAligned( x, puxStackBuffer ) ( ( ( puxStackBuffer ) == NULL ) ? ( pvPortMalloc( ( x ) ) ) : ( puxStackBuffer ) )
+#endif
+
+#ifndef vPortFreeAligned
+ #define vPortFreeAligned( pvBlockToFree ) vPortFree( pvBlockToFree )
+#endif
+
+#endif /* INC_FREERTOS_H */
+
diff --git a/libraries/FreeRTOS/utility/FreeRTOSConfig.h b/libraries/FreeRTOS/utility/FreeRTOSConfig.h
new file mode 100755
index 0000000..3f451a1
--- /dev/null
+++ b/libraries/FreeRTOS/utility/FreeRTOSConfig.h
@@ -0,0 +1,126 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+#define configUSE_PREEMPTION 1
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 )
+#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
+#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )
+#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 120 )
+#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 8 * 1024 ) )
+#define configMAX_TASK_NAME_LEN ( 16 )
+#define configUSE_TRACE_FACILITY 1
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
+
+#define configUSE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configUSE_ALTERNATIVE_API 0
+#define configCHECK_FOR_STACK_OVERFLOW 2
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configQUEUE_REGISTRY_SIZE 0
+#define configGENERATE_RUN_TIME_STATS 0
+
+/* Set the following definitions to 1 to include the API function, or zero
+to exclude the API function. */
+
+#define INCLUDE_vTaskPrioritySet 1
+#define INCLUDE_uxTaskPriorityGet 1
+#define INCLUDE_vTaskDelete 1
+#define INCLUDE_vTaskCleanUpResources 0
+#define INCLUDE_vTaskSuspend 1
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+
+/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
+(lowest) to 0 (1?) (highest). */
+#define configKERNEL_INTERRUPT_PRIORITY 255
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
+
+
+/* This is the value being used as per the ST library which permits 16
+priority values, 0 to 15. This must correspond to the
+configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest
+NVIC value of 255. */
+#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
+
+/*-----------------------------------------------------------
+ * UART configuration.
+ *-----------------------------------------------------------*/
+#define configCOM0_RX_BUFFER_LENGTH 128
+#define configCOM0_TX_BUFFER_LENGTH 128
+#define configCOM1_RX_BUFFER_LENGTH 128
+#define configCOM1_TX_BUFFER_LENGTH 128
+
+#endif /* FREERTOS_CONFIG_H */
+
diff --git a/libraries/FreeRTOS/utility/StackMacros.h b/libraries/FreeRTOS/utility/StackMacros.h
new file mode 100755
index 0000000..547a58c
--- /dev/null
+++ b/libraries/FreeRTOS/utility/StackMacros.h
@@ -0,0 +1,174 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#ifndef STACK_MACROS_H
+#define STACK_MACROS_H
+
+/*
+ * Call the stack overflow hook function if the stack of the task being swapped
+ * out is currently overflowed, or looks like it might have overflowed in the
+ * past.
+ *
+ * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
+ * the current stack state only - comparing the current top of stack value to
+ * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
+ * will also cause the last few stack bytes to be checked to ensure the value
+ * to which the bytes were set when the task was created have not been
+ * overwritten. Note this second test does not guarantee that an overflowed
+ * stack will always be recognised.
+ */
+
+/*-----------------------------------------------------------*/
+
+#if( configCHECK_FOR_STACK_OVERFLOW == 0 )
+
+ /* FreeRTOSConfig.h is not set to check for stack overflows. */
+ #define taskFIRST_CHECK_FOR_STACK_OVERFLOW()
+ #define taskSECOND_CHECK_FOR_STACK_OVERFLOW()
+
+#endif /* configCHECK_FOR_STACK_OVERFLOW == 0 */
+/*-----------------------------------------------------------*/
+
+#if( configCHECK_FOR_STACK_OVERFLOW == 1 )
+
+ /* FreeRTOSConfig.h is only set to use the first method of
+ overflow checking. */
+ #define taskSECOND_CHECK_FOR_STACK_OVERFLOW()
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH < 0 ) )
+
+ /* Only the current stack state is to be checked. */
+ #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \
+ { \
+ /* Is the currently saved stack pointer within the stack limit? */ \
+ if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
+ { \
+ vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
+ } \
+ }
+
+#endif /* configCHECK_FOR_STACK_OVERFLOW > 0 */
+/*-----------------------------------------------------------*/
+
+#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH > 0 ) )
+
+ /* Only the current stack state is to be checked. */
+ #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \
+ { \
+ \
+ /* Is the currently saved stack pointer within the stack limit? */ \
+ if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \
+ { \
+ vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
+ } \
+ }
+
+#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
+
+ #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \
+ { \
+ static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
+ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
+ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
+ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
+ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
+ \
+ \
+ /* Has the extremity of the task stack ever been written over? */ \
+ if( memcmp( ( void * ) pxCurrentTCB->pxStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
+ { \
+ vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
+ } \
+ }
+
+#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
+/*-----------------------------------------------------------*/
+
+#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
+
+ #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \
+ { \
+ char *pcEndOfStack = ( char * ) pxCurrentTCB->pxEndOfStack; \
+ static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
+ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
+ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
+ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
+ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
+ \
+ \
+ pcEndOfStack -= sizeof( ucExpectedStackBytes ); \
+ \
+ /* Has the extremity of the task stack ever been written over? */ \
+ if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
+ { \
+ vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
+ } \
+ }
+
+#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
+/*-----------------------------------------------------------*/
+
+#endif /* STACK_MACROS_H */
+
diff --git a/libraries/FreeRTOS/utility/croutine.c b/libraries/FreeRTOS/utility/croutine.c
new file mode 100755
index 0000000..fe56730
--- /dev/null
+++ b/libraries/FreeRTOS/utility/croutine.c
@@ -0,0 +1,380 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "croutine.h"
+
+/*
+ * Some kernel aware debuggers require data to be viewed to be global, rather
+ * than file scope.
+ */
+#ifdef portREMOVE_STATIC_QUALIFIER
+ #define static
+#endif
+
+
+/* Lists for ready and blocked co-routines. --------------------*/
+static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
+static xList xDelayedCoRoutineList1; /*< Delayed co-routines. */
+static xList xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
+static xList * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
+static xList * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
+static xList xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
+
+/* Other file private variables. --------------------------------*/
+corCRCB * pxCurrentCoRoutine = NULL;
+static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
+static portTickType xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
+
+/* The initial state of the co-routine when it is created. */
+#define corINITIAL_STATE ( 0 )
+
+/*
+ * Place the co-routine represented by pxCRCB into the appropriate ready queue
+ * for the priority. It is inserted at the end of the list.
+ *
+ * This macro accesses the co-routine ready lists and therefore must not be
+ * used from within an ISR.
+ */
+#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
+{ \
+ if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
+ { \
+ uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
+ } \
+ vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
+}
+
+/*
+ * Utility to ready all the lists used by the scheduler. This is called
+ * automatically upon the creation of the first co-routine.
+ */
+static void prvInitialiseCoRoutineLists( void );
+
+/*
+ * Co-routines that are readied by an interrupt cannot be placed directly into
+ * the ready lists (there is no mutual exclusion). Instead they are placed in
+ * in the pending ready list in order that they can later be moved to the ready
+ * list by the co-routine scheduler.
+ */
+static void prvCheckPendingReadyList( void );
+
+/*
+ * Macro that looks at the list of co-routines that are currently delayed to
+ * see if any require waking.
+ *
+ * Co-routines are stored in the queue in the order of their wake time -
+ * meaning once one co-routine has been found whose timer has not expired
+ * we need not look any further down the list.
+ */
+static void prvCheckDelayedList( void );
+
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
+{
+signed portBASE_TYPE xReturn;
+corCRCB *pxCoRoutine;
+
+ /* Allocate the memory that will store the co-routine control block. */
+ pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
+ if( pxCoRoutine )
+ {
+ /* If pxCurrentCoRoutine is NULL then this is the first co-routine to
+ be created and the co-routine data structures need initialising. */
+ if( pxCurrentCoRoutine == NULL )
+ {
+ pxCurrentCoRoutine = pxCoRoutine;
+ prvInitialiseCoRoutineLists();
+ }
+
+ /* Check the priority is within limits. */
+ if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
+ {
+ uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
+ }
+
+ /* Fill out the co-routine control block from the function parameters. */
+ pxCoRoutine->uxState = corINITIAL_STATE;
+ pxCoRoutine->uxPriority = uxPriority;
+ pxCoRoutine->uxIndex = uxIndex;
+ pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
+
+ /* Initialise all the other co-routine control block parameters. */
+ vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
+ vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
+
+ /* Set the co-routine control block as a link back from the xListItem.
+ This is so we can get back to the containing CRCB from a generic item
+ in a list. */
+ listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
+ listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
+
+ /* Event lists are always in priority order. */
+ listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
+
+ /* Now the co-routine has been initialised it can be added to the ready
+ list at the correct priority. */
+ prvAddCoRoutineToReadyQueue( pxCoRoutine );
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
+{
+portTickType xTimeToWake;
+
+ /* Calculate the time to wake - this may overflow but this is
+ not a problem. */
+ xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
+
+ /* We must remove ourselves from the ready list before adding
+ ourselves to the blocked list as the same list item is used for
+ both lists. */
+ vListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+
+ /* The list item will be inserted in wake time order. */
+ listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
+
+ if( xTimeToWake < xCoRoutineTickCount )
+ {
+ /* Wake time has overflowed. Place this item in the
+ overflow list. */
+ vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+ }
+ else
+ {
+ /* The wake time has not overflowed, so we can use the
+ current block list. */
+ vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+ }
+
+ if( pxEventList )
+ {
+ /* Also add the co-routine to an event list. If this is done then the
+ function must be called with interrupts disabled. */
+ vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckPendingReadyList( void )
+{
+ /* Are there any co-routines waiting to get moved to the ready list? These
+ are co-routines that have been readied by an ISR. The ISR cannot access
+ the ready lists itself. */
+ while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
+ {
+ corCRCB *pxUnblockedCRCB;
+
+ /* The pending ready list can be accessed by an ISR. */
+ portDISABLE_INTERRUPTS();
+ {
+ pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
+ vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
+ }
+ portENABLE_INTERRUPTS();
+
+ vListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
+ prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckDelayedList( void )
+{
+corCRCB *pxCRCB;
+
+ xPassedTicks = xTaskGetTickCount() - xLastTickCount;
+ while( xPassedTicks )
+ {
+ xCoRoutineTickCount++;
+ xPassedTicks--;
+
+ /* If the tick count has overflowed we need to swap the ready lists. */
+ if( xCoRoutineTickCount == 0 )
+ {
+ xList * pxTemp;
+
+ /* Tick count has overflowed so we need to swap the delay lists. If there are
+ any items in pxDelayedCoRoutineList here then there is an error! */
+ pxTemp = pxDelayedCoRoutineList;
+ pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
+ pxOverflowDelayedCoRoutineList = pxTemp;
+ }
+
+ /* See if this tick has made a timeout expire. */
+ while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
+ {
+ pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
+
+ if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
+ {
+ /* Timeout not yet expired. */
+ break;
+ }
+
+ portDISABLE_INTERRUPTS();
+ {
+ /* The event could have occurred just before this critical
+ section. If this is the case then the generic list item will
+ have been moved to the pending ready list and the following
+ line is still valid. Also the pvContainer parameter will have
+ been set to NULL so the following lines are also valid. */
+ vListRemove( &( pxCRCB->xGenericListItem ) );
+
+ /* Is the co-routine waiting on an event also? */
+ if( pxCRCB->xEventListItem.pvContainer )
+ {
+ vListRemove( &( pxCRCB->xEventListItem ) );
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ prvAddCoRoutineToReadyQueue( pxCRCB );
+ }
+ }
+
+ xLastTickCount = xCoRoutineTickCount;
+}
+/*-----------------------------------------------------------*/
+
+void vCoRoutineSchedule( void )
+{
+ /* See if any co-routines readied by events need moving to the ready lists. */
+ prvCheckPendingReadyList();
+
+ /* See if any delayed co-routines have timed out. */
+ prvCheckDelayedList();
+
+ /* Find the highest priority queue that contains ready co-routines. */
+ while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
+ {
+ if( uxTopCoRoutineReadyPriority == 0 )
+ {
+ /* No more co-routines to check. */
+ return;
+ }
+ --uxTopCoRoutineReadyPriority;
+ }
+
+ /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
+ of the same priority get an equal share of the processor time. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
+
+ /* Call the co-routine. */
+ ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
+
+ return;
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitialiseCoRoutineLists( void )
+{
+unsigned portBASE_TYPE uxPriority;
+
+ for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
+ {
+ vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
+ }
+
+ vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
+ vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
+ vListInitialise( ( xList * ) &xPendingReadyCoRoutineList );
+
+ /* Start with pxDelayedCoRoutineList using list1 and the
+ pxOverflowDelayedCoRoutineList using list2. */
+ pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
+ pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
+{
+corCRCB *pxUnblockedCRCB;
+signed portBASE_TYPE xReturn;
+
+ /* This function is called from within an interrupt. It can only access
+ event lists and the pending ready list. This function assumes that a
+ check has already been made to ensure pxEventList is not empty. */
+ pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
+ vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
+ vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
+
+ if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+}
+
diff --git a/libraries/FreeRTOS/utility/croutine.h b/libraries/FreeRTOS/utility/croutine.h
new file mode 100755
index 0000000..6801c41
--- /dev/null
+++ b/libraries/FreeRTOS/utility/croutine.h
@@ -0,0 +1,752 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#ifndef CO_ROUTINE_H
+#define CO_ROUTINE_H
+
+#ifndef INC_FREERTOS_H
+ #error "include FreeRTOS.h must appear in source files before include croutine.h"
+#endif
+
+#include "list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Used to hide the implementation of the co-routine control block. The
+control block structure however has to be included in the header due to
+the macro implementation of the co-routine functionality. */
+typedef void * xCoRoutineHandle;
+
+/* Defines the prototype to which co-routine functions must conform. */
+typedef void (*crCOROUTINE_CODE)( xCoRoutineHandle, unsigned portBASE_TYPE );
+
+typedef struct corCoRoutineControlBlock
+{
+ crCOROUTINE_CODE pxCoRoutineFunction;
+ xListItem xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */
+ xListItem xEventListItem; /*< List item used to place the CRCB in event lists. */
+ unsigned portBASE_TYPE uxPriority; /*< The priority of the co-routine in relation to other co-routines. */
+ unsigned portBASE_TYPE uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */
+ unsigned short uxState; /*< Used internally by the co-routine implementation. */
+} corCRCB; /* Co-routine control block. Note must be identical in size down to uxPriority with tskTCB. */
+
+/**
+ * croutine. h
+ *<pre>
+ portBASE_TYPE xCoRoutineCreate(
+ crCOROUTINE_CODE pxCoRoutineCode,
+ unsigned portBASE_TYPE uxPriority,
+ unsigned portBASE_TYPE uxIndex
+ );</pre>
+ *
+ * Create a new co-routine and add it to the list of co-routines that are
+ * ready to run.
+ *
+ * @param pxCoRoutineCode Pointer to the co-routine function. Co-routine
+ * functions require special syntax - see the co-routine section of the WEB
+ * documentation for more information.
+ *
+ * @param uxPriority The priority with respect to other co-routines at which
+ * the co-routine will run.
+ *
+ * @param uxIndex Used to distinguish between different co-routines that
+ * execute the same function. See the example below and the co-routine section
+ * of the WEB documentation for further information.
+ *
+ * @return pdPASS if the co-routine was successfully created and added to a ready
+ * list, otherwise an error code defined with ProjDefs.h.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine to be created.
+ void vFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ static const char cLedToFlash[ 2 ] = { 5, 6 };
+ static const portTickType uxFlashRates[ 2 ] = { 200, 400 };
+
+ // Must start every co-routine with a call to crSTART();
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // This co-routine just delays for a fixed period, then toggles
+ // an LED. Two co-routines are created using this function, so
+ // the uxIndex parameter is used to tell the co-routine which
+ // LED to flash and how long to delay. This assumes xQueue has
+ // already been created.
+ vParTestToggleLED( cLedToFlash[ uxIndex ] );
+ crDELAY( xHandle, uxFlashRates[ uxIndex ] );
+ }
+
+ // Must end every co-routine with a call to crEND();
+ crEND();
+ }
+
+ // Function that creates two co-routines.
+ void vOtherFunction( void )
+ {
+ unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+
+ // Create two co-routines at priority 0. The first is given index 0
+ // so (from the code above) toggles LED 5 every 200 ticks. The second
+ // is given index 1 so toggles LED 6 every 400 ticks.
+ for( uxIndex = 0; uxIndex < 2; uxIndex++ )
+ {
+ xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
+ }
+ }
+ </pre>
+ * \defgroup xCoRoutineCreate xCoRoutineCreate
+ * \ingroup Tasks
+ */
+signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex );
+
+
+/**
+ * croutine. h
+ *<pre>
+ void vCoRoutineSchedule( void );</pre>
+ *
+ * Run a co-routine.
+ *
+ * vCoRoutineSchedule() executes the highest priority co-routine that is able
+ * to run. The co-routine will execute until it either blocks, yields or is
+ * preempted by a task. Co-routines execute cooperatively so one
+ * co-routine cannot be preempted by another, but can be preempted by a task.
+ *
+ * If an application comprises of both tasks and co-routines then
+ * vCoRoutineSchedule should be called from the idle task (in an idle task
+ * hook).
+ *
+ * Example usage:
+ <pre>
+ // This idle task hook will schedule a co-routine each time it is called.
+ // The rest of the idle task will execute between co-routine calls.
+ void vApplicationIdleHook( void )
+ {
+ vCoRoutineSchedule();
+ }
+
+ // Alternatively, if you do not require any other part of the idle task to
+ // execute, the idle task hook can call vCoRoutineScheduler() within an
+ // infinite loop.
+ void vApplicationIdleHook( void )
+ {
+ for( ;; )
+ {
+ vCoRoutineSchedule();
+ }
+ }
+ </pre>
+ * \defgroup vCoRoutineSchedule vCoRoutineSchedule
+ * \ingroup Tasks
+ */
+void vCoRoutineSchedule( void );
+
+/**
+ * croutine. h
+ * <pre>
+ crSTART( xCoRoutineHandle xHandle );</pre>
+ *
+ * This macro MUST always be called at the start of a co-routine function.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static long ulAVariable;
+
+ // Must start every co-routine with a call to crSTART();
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Co-routine functionality goes here.
+ }
+
+ // Must end every co-routine with a call to crEND();
+ crEND();
+ }</pre>
+ * \defgroup crSTART crSTART
+ * \ingroup Tasks
+ */
+#define crSTART( pxCRCB ) switch( ( ( corCRCB * )( pxCRCB ) )->uxState ) { case 0:
+
+/**
+ * croutine. h
+ * <pre>
+ crEND();</pre>
+ *
+ * This macro MUST always be called at the end of a co-routine function.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static long ulAVariable;
+
+ // Must start every co-routine with a call to crSTART();
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Co-routine functionality goes here.
+ }
+
+ // Must end every co-routine with a call to crEND();
+ crEND();
+ }</pre>
+ * \defgroup crSTART crSTART
+ * \ingroup Tasks
+ */
+#define crEND() }
+
+/*
+ * These macros are intended for internal use by the co-routine implementation
+ * only. The macros should not be used directly by application writers.
+ */
+#define crSET_STATE0( xHandle ) ( ( corCRCB * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):
+#define crSET_STATE1( xHandle ) ( ( corCRCB * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):
+
+/**
+ * croutine. h
+ *<pre>
+ crDELAY( xCoRoutineHandle xHandle, portTickType xTicksToDelay );</pre>
+ *
+ * Delay a co-routine for a fixed period of time.
+ *
+ * crDELAY can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function. This is because
+ * co-routines do not maintain their own stack.
+ *
+ * @param xHandle The handle of the co-routine to delay. This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should delay
+ * for. The actual amount of time this equates to is defined by
+ * configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_RATE_MS
+ * can be used to convert ticks to milliseconds.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ // We are to delay for 200ms.
+ static const xTickType xDelayTime = 200 / portTICK_RATE_MS;
+
+ // Must start every co-routine with a call to crSTART();
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Delay for 200ms.
+ crDELAY( xHandle, xDelayTime );
+
+ // Do something here.
+ }
+
+ // Must end every co-routine with a call to crEND();
+ crEND();
+ }</pre>
+ * \defgroup crDELAY crDELAY
+ * \ingroup Tasks
+ */
+#define crDELAY( xHandle, xTicksToDelay ) \
+ if( ( xTicksToDelay ) > 0 ) \
+ { \
+ vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \
+ } \
+ crSET_STATE0( ( xHandle ) );
+
+/**
+ * <pre>
+ crQUEUE_SEND(
+ xCoRoutineHandle xHandle,
+ xQueueHandle pxQueue,
+ void *pvItemToQueue,
+ portTickType xTicksToWait,
+ portBASE_TYPE *pxResult
+ )</pre>
+ *
+ * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
+ * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
+ *
+ * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
+ * xQueueSend() and xQueueReceive() can only be used from tasks.
+ *
+ * crQUEUE_SEND can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function. This is because
+ * co-routines do not maintain their own stack.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xHandle The handle of the calling co-routine. This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param pxQueue The handle of the queue on which the data will be posted.
+ * The handle is obtained as the return value when the queue is created using
+ * the xQueueCreate() API function.
+ *
+ * @param pvItemToQueue A pointer to the data being posted onto the queue.
+ * The number of bytes of each queued item is specified when the queue is
+ * created. This number of bytes is copied from pvItemToQueue into the queue
+ * itself.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should block
+ * to wait for space to become available on the queue, should space not be
+ * available immediately. The actual amount of time this equates to is defined
+ * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
+ * portTICK_RATE_MS can be used to convert ticks to milliseconds (see example
+ * below).
+ *
+ * @param pxResult The variable pointed to by pxResult will be set to pdPASS if
+ * data was successfully posted onto the queue, otherwise it will be set to an
+ * error defined within ProjDefs.h.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine function that blocks for a fixed period then posts a number onto
+ // a queue.
+ static void prvCoRoutineFlashTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portBASE_TYPE xNumberToPost = 0;
+ static portBASE_TYPE xResult;
+
+ // Co-routines must begin with a call to crSTART().
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // This assumes the queue has already been created.
+ crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
+
+ if( xResult != pdPASS )
+ {
+ // The message was not posted!
+ }
+
+ // Increment the number to be posted onto the queue.
+ xNumberToPost++;
+
+ // Delay for 100 ticks.
+ crDELAY( xHandle, 100 );
+ }
+
+ // Co-routines must end with a call to crEND().
+ crEND();
+ }</pre>
+ * \defgroup crQUEUE_SEND crQUEUE_SEND
+ * \ingroup Tasks
+ */
+#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \
+{ \
+ *( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) ); \
+ if( *( pxResult ) == errQUEUE_BLOCKED ) \
+ { \
+ crSET_STATE0( ( xHandle ) ); \
+ *pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \
+ } \
+ if( *pxResult == errQUEUE_YIELD ) \
+ { \
+ crSET_STATE1( ( xHandle ) ); \
+ *pxResult = pdPASS; \
+ } \
+}
+
+/**
+ * croutine. h
+ * <pre>
+ crQUEUE_RECEIVE(
+ xCoRoutineHandle xHandle,
+ xQueueHandle pxQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait,
+ portBASE_TYPE *pxResult
+ )</pre>
+ *
+ * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
+ * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
+ *
+ * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
+ * xQueueSend() and xQueueReceive() can only be used from tasks.
+ *
+ * crQUEUE_RECEIVE can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function. This is because
+ * co-routines do not maintain their own stack.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xHandle The handle of the calling co-routine. This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param pxQueue The handle of the queue from which the data will be received.
+ * The handle is obtained as the return value when the queue is created using
+ * the xQueueCreate() API function.
+ *
+ * @param pvBuffer The buffer into which the received item is to be copied.
+ * The number of bytes of each queued item is specified when the queue is
+ * created. This number of bytes is copied into pvBuffer.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should block
+ * to wait for data to become available from the queue, should data not be
+ * available immediately. The actual amount of time this equates to is defined
+ * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
+ * portTICK_RATE_MS can be used to convert ticks to milliseconds (see the
+ * crQUEUE_SEND example).
+ *
+ * @param pxResult The variable pointed to by pxResult will be set to pdPASS if
+ * data was successfully retrieved from the queue, otherwise it will be set to
+ * an error code as defined within ProjDefs.h.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine receives the number of an LED to flash from a queue. It
+ // blocks on the queue until the number is received.
+ static void prvCoRoutineFlashWorkTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portBASE_TYPE xResult;
+ static unsigned portBASE_TYPE uxLEDToFlash;
+
+ // All co-routines must start with a call to crSTART().
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Wait for data to become available on the queue.
+ crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+ if( xResult == pdPASS )
+ {
+ // We received the LED to flash - flash it!
+ vParTestToggleLED( uxLEDToFlash );
+ }
+ }
+
+ crEND();
+ }</pre>
+ * \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE
+ * \ingroup Tasks
+ */
+#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \
+{ \
+ *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) ); \
+ if( *( pxResult ) == errQUEUE_BLOCKED ) \
+ { \
+ crSET_STATE0( ( xHandle ) ); \
+ *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 ); \
+ } \
+ if( *( pxResult ) == errQUEUE_YIELD ) \
+ { \
+ crSET_STATE1( ( xHandle ) ); \
+ *( pxResult ) = pdPASS; \
+ } \
+}
+
+/**
+ * croutine. h
+ * <pre>
+ crQUEUE_SEND_FROM_ISR(
+ xQueueHandle pxQueue,
+ void *pvItemToQueue,
+ portBASE_TYPE xCoRoutinePreviouslyWoken
+ )</pre>
+ *
+ * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
+ * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
+ * functions used by tasks.
+ *
+ * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
+ * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
+ * xQueueReceiveFromISR() can only be used to pass data between a task and and
+ * ISR.
+ *
+ * crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue
+ * that is being used from within a co-routine.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto
+ * the same queue multiple times from a single interrupt. The first call
+ * should always pass in pdFALSE. Subsequent calls should pass in
+ * the value returned from the previous call.
+ *
+ * @return pdTRUE if a co-routine was woken by posting onto the queue. This is
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine that blocks on a queue waiting for characters to be received.
+ static void vReceivingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ char cRxedChar;
+ portBASE_TYPE xResult;
+
+ // All co-routines must start with a call to crSTART().
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Wait for data to become available on the queue. This assumes the
+ // queue xCommsRxQueue has already been created!
+ crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+ // Was a character received?
+ if( xResult == pdPASS )
+ {
+ // Process the character here.
+ }
+ }
+
+ // All co-routines must end with a call to crEND().
+ crEND();
+ }
+
+ // An ISR that uses a queue to send characters received on a serial port to
+ // a co-routine.
+ void vUART_ISR( void )
+ {
+ char cRxedChar;
+ portBASE_TYPE xCRWokenByPost = pdFALSE;
+
+ // We loop around reading characters until there are none left in the UART.
+ while( UART_RX_REG_NOT_EMPTY() )
+ {
+ // Obtain the character from the UART.
+ cRxedChar = UART_RX_REG;
+
+ // Post the character onto a queue. xCRWokenByPost will be pdFALSE
+ // the first time around the loop. If the post causes a co-routine
+ // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
+ // In this manner we can ensure that if more than one co-routine is
+ // blocked on the queue only one is woken by this ISR no matter how
+ // many characters are posted to the queue.
+ xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
+ }
+ }</pre>
+ * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
+ * \ingroup Tasks
+ */
+#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) )
+
+
+/**
+ * croutine. h
+ * <pre>
+ crQUEUE_SEND_FROM_ISR(
+ xQueueHandle pxQueue,
+ void *pvBuffer,
+ portBASE_TYPE * pxCoRoutineWoken
+ )</pre>
+ *
+ * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
+ * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
+ * functions used by tasks.
+ *
+ * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
+ * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
+ * xQueueReceiveFromISR() can only be used to pass data between a task and and
+ * ISR.
+ *
+ * crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data
+ * from a queue that is being used from within a co-routine (a co-routine
+ * posted to the queue).
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvBuffer A pointer to a buffer into which the received item will be
+ * placed. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from the queue into
+ * pvBuffer.
+ *
+ * @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become
+ * available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a
+ * co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise
+ * *pxCoRoutineWoken will remain unchanged.
+ *
+ * @return pdTRUE an item was successfully received from the queue, otherwise
+ * pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine that posts a character to a queue then blocks for a fixed
+ // period. The character is incremented each time.
+ static void vSendingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // cChar holds its value while this co-routine is blocked and must therefore
+ // be declared static.
+ static char cCharToTx = 'a';
+ portBASE_TYPE xResult;
+
+ // All co-routines must start with a call to crSTART().
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Send the next character to the queue.
+ crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
+
+ if( xResult == pdPASS )
+ {
+ // The character was successfully posted to the queue.
+ }
+ else
+ {
+ // Could not post the character to the queue.
+ }
+
+ // Enable the UART Tx interrupt to cause an interrupt in this
+ // hypothetical UART. The interrupt will obtain the character
+ // from the queue and send it.
+ ENABLE_RX_INTERRUPT();
+
+ // Increment to the next character then block for a fixed period.
+ // cCharToTx will maintain its value across the delay as it is
+ // declared static.
+ cCharToTx++;
+ if( cCharToTx > 'x' )
+ {
+ cCharToTx = 'a';
+ }
+ crDELAY( 100 );
+ }
+
+ // All co-routines must end with a call to crEND().
+ crEND();
+ }
+
+ // An ISR that uses a queue to receive characters to send on a UART.
+ void vUART_ISR( void )
+ {
+ char cCharToTx;
+ portBASE_TYPE xCRWokenByPost = pdFALSE;
+
+ while( UART_TX_REG_EMPTY() )
+ {
+ // Are there any characters in the queue waiting to be sent?
+ // xCRWokenByPost will automatically be set to pdTRUE if a co-routine
+ // is woken by the post - ensuring that only a single co-routine is
+ // woken no matter how many times we go around this loop.
+ if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
+ {
+ SEND_CHARACTER( cCharToTx );
+ }
+ }
+ }</pre>
+ * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
+ * \ingroup Tasks
+ */
+#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) )
+
+/*
+ * This function is intended for internal use by the co-routine macros only.
+ * The macro nature of the co-routine implementation requires that the
+ * prototype appears here. The function should not be used by application
+ * writers.
+ *
+ * Removes the current co-routine from its ready list and places it in the
+ * appropriate delayed list.
+ */
+void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList );
+
+/*
+ * This function is intended for internal use by the queue implementation only.
+ * The function should not be used by application writers.
+ *
+ * Removes the highest priority co-routine from the event list and places it in
+ * the pending ready list.
+ */
+signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CO_ROUTINE_H */
diff --git a/libraries/FreeRTOS/utility/heap_2.c b/libraries/FreeRTOS/utility/heap_2.c
new file mode 100755
index 0000000..d135d8f
--- /dev/null
+++ b/libraries/FreeRTOS/utility/heap_2.c
@@ -0,0 +1,278 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+/*
+ * A sample implementation of pvPortMalloc() and vPortFree() that permits
+ * allocated blocks to be freed, but does not combine adjacent free blocks
+ * into a single larger block.
+ *
+ * See heap_1.c and heap_3.c for alternative implementations, and the memory
+ * management pages of http://www.FreeRTOS.org for more information.
+ */
+#include <stdlib.h>
+
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
+all the API functions to use the MPU wrappers. That should only be done when
+task.h is included from an application file. */
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+/* Allocate the memory for the heap. The struct is used to force byte
+alignment without using any non-portable code. */
+static union xRTOS_HEAP
+{
+ #if portBYTE_ALIGNMENT == 8
+ volatile portDOUBLE dDummy;
+ #else
+ volatile unsigned long ulDummy;
+ #endif
+ unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];
+} xHeap;
+
+/* Define the linked list structure. This is used to link free blocks in order
+of their size. */
+typedef struct A_BLOCK_LINK
+{
+ struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
+ size_t xBlockSize; /*<< The size of the free block. */
+} xBlockLink;
+
+
+static const unsigned short heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + portBYTE_ALIGNMENT - ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );
+#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
+
+/* Create a couple of list links to mark the start and end of the list. */
+static xBlockLink xStart, xEnd;
+
+/* Keeps track of the number of free bytes remaining, but says nothing about
+fragmentation. */
+static size_t xFreeBytesRemaining = configTOTAL_HEAP_SIZE;
+
+/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
+
+/*
+ * Insert a block into the list of free blocks - which is ordered by size of
+ * the block. Small blocks at the start of the list and large blocks at the end
+ * of the list.
+ */
+#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \
+{ \
+xBlockLink *pxIterator; \
+size_t xBlockSize; \
+ \
+ xBlockSize = pxBlockToInsert->xBlockSize; \
+ \
+ /* Iterate through the list until a block is found that has a larger size */ \
+ /* than the block we are inserting. */ \
+ for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \
+ { \
+ /* There is nothing to do here - just iterate to the correct position. */ \
+ } \
+ \
+ /* Update the list to include the block being inserted in the correct */ \
+ /* position. */ \
+ pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \
+ pxIterator->pxNextFreeBlock = pxBlockToInsert; \
+}
+/*-----------------------------------------------------------*/
+
+#define prvHeapInit() \
+{ \
+xBlockLink *pxFirstFreeBlock; \
+ \
+ /* xStart is used to hold a pointer to the first item in the list of free */ \
+ /* blocks. The void cast is used to prevent compiler warnings. */ \
+ xStart.pxNextFreeBlock = ( void * ) xHeap.ucHeap; \
+ xStart.xBlockSize = ( size_t ) 0; \
+ \
+ /* xEnd is used to mark the end of the list of free blocks. */ \
+ xEnd.xBlockSize = configTOTAL_HEAP_SIZE; \
+ xEnd.pxNextFreeBlock = NULL; \
+ \
+ /* To start with there is a single free block that is sized to take up the \
+ entire heap space. */ \
+ pxFirstFreeBlock = ( void * ) xHeap.ucHeap; \
+ pxFirstFreeBlock->xBlockSize = configTOTAL_HEAP_SIZE; \
+ pxFirstFreeBlock->pxNextFreeBlock = &xEnd; \
+}
+/*-----------------------------------------------------------*/
+
+void *pvPortMalloc( size_t xWantedSize )
+{
+xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
+static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE;
+void *pvReturn = NULL;
+
+ vTaskSuspendAll();
+ {
+ /* If this is the first call to malloc then the heap will require
+ initialisation to setup the list of free blocks. */
+ if( xHeapHasBeenInitialised == pdFALSE )
+ {
+ prvHeapInit();
+ xHeapHasBeenInitialised = pdTRUE;
+ }
+
+ /* The wanted size is increased so it can contain a xBlockLink
+ structure in addition to the requested amount of bytes. */
+ if( xWantedSize > 0 )
+ {
+ xWantedSize += heapSTRUCT_SIZE;
+
+ /* Ensure that blocks are always aligned to the required number of bytes. */
+ if( xWantedSize & portBYTE_ALIGNMENT_MASK )
+ {
+ /* Byte alignment required. */
+ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
+ }
+ }
+
+ if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) )
+ {
+ /* Blocks are stored in byte order - traverse the list from the start
+ (smallest) block until one of adequate size is found. */
+ pxPreviousBlock = &xStart;
+ pxBlock = xStart.pxNextFreeBlock;
+ while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) )
+ {
+ pxPreviousBlock = pxBlock;
+ pxBlock = pxBlock->pxNextFreeBlock;
+ }
+
+ /* If we found the end marker then a block of adequate size was not found. */
+ if( pxBlock != &xEnd )
+ {
+ /* Return the memory space - jumping over the xBlockLink structure
+ at its start. */
+ pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
+
+ /* This block is being returned for use so must be taken our of the
+ list of free blocks. */
+ pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
+
+ /* If the block is larger than required it can be split into two. */
+ if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
+ {
+ /* This block is to be split into two. Create a new block
+ following the number of bytes requested. The void cast is
+ used to prevent byte alignment warnings from the compiler. */
+ pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize );
+
+ /* Calculate the sizes of two blocks split from the single
+ block. */
+ pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
+ pxBlock->xBlockSize = xWantedSize;
+
+ /* Insert the new block into the list of free blocks. */
+ prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
+ }
+
+ xFreeBytesRemaining -= pxBlock->xBlockSize;
+ }
+ }
+ }
+ xTaskResumeAll();
+
+ #if( configUSE_MALLOC_FAILED_HOOK == 1 )
+ {
+ if( pvReturn == NULL )
+ {
+ extern void vApplicationMallocFailedHook( void );
+ vApplicationMallocFailedHook();
+ }
+ }
+ #endif
+
+ return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void *pv )
+{
+unsigned char *puc = ( unsigned char * ) pv;
+xBlockLink *pxLink;
+
+ if( pv )
+ {
+ /* The memory being freed will have an xBlockLink structure immediately
+ before it. */
+ puc -= heapSTRUCT_SIZE;
+
+ /* This casting is to keep the compiler from issuing warnings. */
+ pxLink = ( void * ) puc;
+
+ vTaskSuspendAll();
+ {
+ /* Add this block to the list of free blocks. */
+ prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) );
+ xFreeBytesRemaining += pxLink->xBlockSize;
+ }
+ xTaskResumeAll();
+ }
+}
+/*-----------------------------------------------------------*/
+
+size_t xPortGetFreeHeapSize( void )
+{
+ return xFreeBytesRemaining;
+}
+/*-----------------------------------------------------------*/
+
+void vPortInitialiseBlocks( void )
+{
+ /* This just exists to keep the linker quiet. */
+}
diff --git a/libraries/FreeRTOS/utility/list.c b/libraries/FreeRTOS/utility/list.c
new file mode 100755
index 0000000..872b7dd
--- /dev/null
+++ b/libraries/FreeRTOS/utility/list.c
@@ -0,0 +1,197 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "list.h"
+
+/*-----------------------------------------------------------
+ * PUBLIC LIST API documented in list.h
+ *----------------------------------------------------------*/
+
+void vListInitialise( xList *pxList )
+{
+ /* The list structure contains a list item which is used to mark the
+ end of the list. To initialise the list the list end is inserted
+ as the only list entry. */
+ pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );
+
+ /* The list end value is the highest possible value in the list to
+ ensure it remains at the end of the list. */
+ pxList->xListEnd.xItemValue = portMAX_DELAY;
+
+ /* The list end next and previous pointers point to itself so we know
+ when the list is empty. */
+ pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );
+ pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );
+
+ pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U;
+}
+/*-----------------------------------------------------------*/
+
+void vListInitialiseItem( xListItem *pxItem )
+{
+ /* Make sure the list item is not recorded as being on a list. */
+ pxItem->pvContainer = NULL;
+}
+/*-----------------------------------------------------------*/
+
+void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )
+{
+volatile xListItem * pxIndex;
+
+ /* Insert a new list item into pxList, but rather than sort the list,
+ makes the new list item the last item to be removed by a call to
+ pvListGetOwnerOfNextEntry. This means it has to be the item pointed to by
+ the pxIndex member. */
+ pxIndex = pxList->pxIndex;
+
+ pxNewListItem->pxNext = pxIndex->pxNext;
+ pxNewListItem->pxPrevious = pxList->pxIndex;
+ pxIndex->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
+ pxIndex->pxNext = ( volatile xListItem * ) pxNewListItem;
+ pxList->pxIndex = ( volatile xListItem * ) pxNewListItem;
+
+ /* Remember which list the item is in. */
+ pxNewListItem->pvContainer = ( void * ) pxList;
+
+ ( pxList->uxNumberOfItems )++;
+}
+/*-----------------------------------------------------------*/
+
+void vListInsert( xList *pxList, xListItem *pxNewListItem )
+{
+volatile xListItem *pxIterator;
+portTickType xValueOfInsertion;
+
+ /* Insert the new list item into the list, sorted in ulListItem order. */
+ xValueOfInsertion = pxNewListItem->xItemValue;
+
+ /* If the list already contains a list item with the same item value then
+ the new list item should be placed after it. This ensures that TCB's which
+ are stored in ready lists (all of which have the same ulListItem value)
+ get an equal share of the CPU. However, if the xItemValue is the same as
+ the back marker the iteration loop below will not end. This means we need
+ to guard against this by checking the value first and modifying the
+ algorithm slightly if necessary. */
+ if( xValueOfInsertion == portMAX_DELAY )
+ {
+ pxIterator = pxList->xListEnd.pxPrevious;
+ }
+ else
+ {
+ /* *** NOTE ***********************************************************
+ If you find your application is crashing here then likely causes are:
+ 1) Stack overflow -
+ see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
+ 2) Incorrect interrupt priority assignment, especially on Cortex-M3
+ parts where numerically high priority values denote low actual
+ interrupt priories, which can seem counter intuitive. See
+ configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html
+ 3) Calling an API function from within a critical section or when
+ the scheduler is suspended.
+ 4) Using a queue or semaphore before it has been initialised or
+ before the scheduler has been started (are interrupts firing
+ before vTaskStartScheduler() has been called?).
+ See http://www.freertos.org/FAQHelp.html for more tips.
+ **********************************************************************/
+
+ for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
+ {
+ /* There is nothing to do here, we are just iterating to the
+ wanted insertion position. */
+ }
+ }
+
+ pxNewListItem->pxNext = pxIterator->pxNext;
+ pxNewListItem->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
+ pxNewListItem->pxPrevious = pxIterator;
+ pxIterator->pxNext = ( volatile xListItem * ) pxNewListItem;
+
+ /* Remember which list the item is in. This allows fast removal of the
+ item later. */
+ pxNewListItem->pvContainer = ( void * ) pxList;
+
+ ( pxList->uxNumberOfItems )++;
+}
+/*-----------------------------------------------------------*/
+
+void vListRemove( xListItem *pxItemToRemove )
+{
+xList * pxList;
+
+ pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
+ pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
+
+ /* The list item knows which list it is in. Obtain the list from the list
+ item. */
+ pxList = ( xList * ) pxItemToRemove->pvContainer;
+
+ /* Make sure the index is left pointing to a valid item. */
+ if( pxList->pxIndex == pxItemToRemove )
+ {
+ pxList->pxIndex = pxItemToRemove->pxPrevious;
+ }
+
+ pxItemToRemove->pvContainer = NULL;
+ ( pxList->uxNumberOfItems )--;
+}
+/*-----------------------------------------------------------*/
+
diff --git a/libraries/FreeRTOS/utility/list.h b/libraries/FreeRTOS/utility/list.h
new file mode 100755
index 0000000..01e69cb
--- /dev/null
+++ b/libraries/FreeRTOS/utility/list.h
@@ -0,0 +1,314 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+/*
+ * This is the list implementation used by the scheduler. While it is tailored
+ * heavily for the schedulers needs, it is also available for use by
+ * application code.
+ *
+ * xLists can only store pointers to xListItems. Each xListItem contains a
+ * numeric value (xItemValue). Most of the time the lists are sorted in
+ * descending item value order.
+ *
+ * Lists are created already containing one list item. The value of this
+ * item is the maximum possible that can be stored, it is therefore always at
+ * the end of the list and acts as a marker. The list member pxHead always
+ * points to this marker - even though it is at the tail of the list. This
+ * is because the tail contains a wrap back pointer to the true head of
+ * the list.
+ *
+ * In addition to it's value, each list item contains a pointer to the next
+ * item in the list (pxNext), a pointer to the list it is in (pxContainer)
+ * and a pointer to back to the object that contains it. These later two
+ * pointers are included for efficiency of list manipulation. There is
+ * effectively a two way link between the object containing the list item and
+ * the list item itself.
+ *
+ *
+ * \page ListIntroduction List Implementation
+ * \ingroup FreeRTOSIntro
+ */
+
+
+#ifndef LIST_H
+#define LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Definition of the only type of object that a list can contain.
+ */
+struct xLIST_ITEM
+{
+ portTickType xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
+ volatile struct xLIST_ITEM * pxNext; /*< Pointer to the next xListItem in the list. */
+ volatile struct xLIST_ITEM * pxPrevious;/*< Pointer to the previous xListItem in the list. */
+ void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
+ void * pvContainer; /*< Pointer to the list in which this list item is placed (if any). */
+};
+typedef struct xLIST_ITEM xListItem; /* For some reason lint wants this as two separate definitions. */
+
+struct xMINI_LIST_ITEM
+{
+ portTickType xItemValue;
+ volatile struct xLIST_ITEM *pxNext;
+ volatile struct xLIST_ITEM *pxPrevious;
+};
+typedef struct xMINI_LIST_ITEM xMiniListItem;
+
+/*
+ * Definition of the type of queue used by the scheduler.
+ */
+typedef struct xLIST
+{
+ volatile unsigned portBASE_TYPE uxNumberOfItems;
+ volatile xListItem * pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to pvListGetOwnerOfNextEntry (). */
+ volatile xMiniListItem xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
+} xList;
+
+/*
+ * Access macro to set the owner of a list item. The owner of a list item
+ * is the object (usually a TCB) that contains the list item.
+ *
+ * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
+ * \ingroup LinkedList
+ */
+#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( pxListItem )->pvOwner = ( void * ) ( pxOwner )
+
+/*
+ * Access macro to set the value of the list item. In most cases the value is
+ * used to sort the list in descending order.
+ *
+ * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
+ * \ingroup LinkedList
+ */
+#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( pxListItem )->xItemValue = ( xValue )
+
+/*
+ * Access macro the retrieve the value of the list item. The value can
+ * represent anything - for example a the priority of a task, or the time at
+ * which a task should be unblocked.
+ *
+ * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
+ * \ingroup LinkedList
+ */
+#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
+
+/*
+ * Access macro the retrieve the value of the list item at the head of a given
+ * list.
+ *
+ * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
+ * \ingroup LinkedList
+ */
+#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->xItemValue )
+
+/*
+ * Access macro to determine if a list contains any items. The macro will
+ * only have the value true if the list is empty.
+ *
+ * \page listLIST_IS_EMPTY listLIST_IS_EMPTY
+ * \ingroup LinkedList
+ */
+#define listLIST_IS_EMPTY( pxList ) ( ( pxList )->uxNumberOfItems == ( unsigned portBASE_TYPE ) 0 )
+
+/*
+ * Access macro to return the number of items in the list.
+ */
+#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
+
+/*
+ * Access function to obtain the owner of the next entry in a list.
+ *
+ * The list member pxIndex is used to walk through a list. Calling
+ * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
+ * and returns that entries pxOwner parameter. Using multiple calls to this
+ * function it is therefore possible to move through every item contained in
+ * a list.
+ *
+ * The pxOwner parameter of a list item is a pointer to the object that owns
+ * the list item. In the scheduler this is normally a task control block.
+ * The pxOwner parameter effectively creates a two way link between the list
+ * item and its owner.
+ *
+ * @param pxList The list from which the next item owner is to be returned.
+ *
+ * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
+ * \ingroup LinkedList
+ */
+#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
+{ \
+xList * const pxConstList = ( pxList ); \
+ /* Increment the index to the next item and return the item, ensuring */ \
+ /* we don't return the marker used at the end of the list. */ \
+ ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
+ if( ( pxConstList )->pxIndex == ( xListItem * ) &( ( pxConstList )->xListEnd ) ) \
+ { \
+ ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
+ } \
+ ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
+}
+
+
+/*
+ * Access function to obtain the owner of the first entry in a list. Lists
+ * are normally sorted in ascending item value order.
+ *
+ * This function returns the pxOwner member of the first item in the list.
+ * The pxOwner parameter of a list item is a pointer to the object that owns
+ * the list item. In the scheduler this is normally a task control block.
+ * The pxOwner parameter effectively creates a two way link between the list
+ * item and its owner.
+ *
+ * @param pxList The list from which the owner of the head item is to be
+ * returned.
+ *
+ * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
+ * \ingroup LinkedList
+ */
+#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )
+
+/*
+ * Check to see if a list item is within a list. The list item maintains a
+ * "container" pointer that points to the list it is in. All this macro does
+ * is check to see if the container and the list match.
+ *
+ * @param pxList The list we want to know if the list item is within.
+ * @param pxListItem The list item we want to know if is in the list.
+ * @return pdTRUE is the list item is in the list, otherwise pdFALSE.
+ * pointer against
+ */
+#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) )
+
+/*
+ * Must be called before a list is used! This initialises all the members
+ * of the list structure and inserts the xListEnd item into the list as a
+ * marker to the back of the list.
+ *
+ * @param pxList Pointer to the list being initialised.
+ *
+ * \page vListInitialise vListInitialise
+ * \ingroup LinkedList
+ */
+void vListInitialise( xList *pxList );
+
+/*
+ * Must be called before a list item is used. This sets the list container to
+ * null so the item does not think that it is already contained in a list.
+ *
+ * @param pxItem Pointer to the list item being initialised.
+ *
+ * \page vListInitialiseItem vListInitialiseItem
+ * \ingroup LinkedList
+ */
+void vListInitialiseItem( xListItem *pxItem );
+
+/*
+ * Insert a list item into a list. The item will be inserted into the list in
+ * a position determined by its item value (descending item value order).
+ *
+ * @param pxList The list into which the item is to be inserted.
+ *
+ * @param pxNewListItem The item to that is to be placed in the list.
+ *
+ * \page vListInsert vListInsert
+ * \ingroup LinkedList
+ */
+void vListInsert( xList *pxList, xListItem *pxNewListItem );
+
+/*
+ * Insert a list item into a list. The item will be inserted in a position
+ * such that it will be the last item within the list returned by multiple
+ * calls to listGET_OWNER_OF_NEXT_ENTRY.
+ *
+ * The list member pvIndex is used to walk through a list. Calling
+ * listGET_OWNER_OF_NEXT_ENTRY increments pvIndex to the next item in the list.
+ * Placing an item in a list using vListInsertEnd effectively places the item
+ * in the list position pointed to by pvIndex. This means that every other
+ * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
+ * the pvIndex parameter again points to the item being inserted.
+ *
+ * @param pxList The list into which the item is to be inserted.
+ *
+ * @param pxNewListItem The list item to be inserted into the list.
+ *
+ * \page vListInsertEnd vListInsertEnd
+ * \ingroup LinkedList
+ */
+void vListInsertEnd( xList *pxList, xListItem *pxNewListItem );
+
+/*
+ * Remove an item from a list. The list item has a pointer to the list that
+ * it is in, so only the list item need be passed into the function.
+ *
+ * @param vListRemove The item to be removed. The item will remove itself from
+ * the list pointed to by it's pxContainer parameter.
+ *
+ * \page vListRemove vListRemove
+ * \ingroup LinkedList
+ */
+void vListRemove( xListItem *pxItemToRemove );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libraries/FreeRTOS/utility/mpu_wrappers.h b/libraries/FreeRTOS/utility/mpu_wrappers.h
new file mode 100755
index 0000000..a0c2723
--- /dev/null
+++ b/libraries/FreeRTOS/utility/mpu_wrappers.h
@@ -0,0 +1,141 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#ifndef MPU_WRAPPERS_H
+#define MPU_WRAPPERS_H
+
+/* This file redefines API functions to be called through a wrapper macro, but
+only for ports that are using the MPU. */
+#ifdef portUSING_MPU_WRAPPERS
+
+ /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is
+ included from queue.c or task.c to prevent it from having an effect within
+ those files. */
+ #ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+ #define xTaskGenericCreate MPU_xTaskGenericCreate
+ #define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions
+ #define vTaskDelete MPU_vTaskDelete
+ #define vTaskDelayUntil MPU_vTaskDelayUntil
+ #define vTaskDelay MPU_vTaskDelay
+ #define uxTaskPriorityGet MPU_uxTaskPriorityGet
+ #define vTaskPrioritySet MPU_vTaskPrioritySet
+ #define vTaskSuspend MPU_vTaskSuspend
+ #define xTaskIsTaskSuspended MPU_xTaskIsTaskSuspended
+ #define vTaskResume MPU_vTaskResume
+ #define vTaskSuspendAll MPU_vTaskSuspendAll
+ #define xTaskResumeAll MPU_xTaskResumeAll
+ #define xTaskGetTickCount MPU_xTaskGetTickCount
+ #define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks
+ #define vTaskList MPU_vTaskList
+ #define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats
+ #define vTaskStartTrace MPU_vTaskStartTrace
+ #define ulTaskEndTrace MPU_ulTaskEndTrace
+ #define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag
+ #define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag
+ #define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook
+ #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark
+ #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle
+ #define xTaskGetSchedulerState MPU_xTaskGetSchedulerState
+
+ #define xQueueCreate MPU_xQueueCreate
+ #define xQueueCreateMutex MPU_xQueueCreateMutex
+ #define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive
+ #define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive
+ #define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore
+ #define xQueueGenericSend MPU_xQueueGenericSend
+ #define xQueueAltGenericSend MPU_xQueueAltGenericSend
+ #define xQueueAltGenericReceive MPU_xQueueAltGenericReceive
+ #define xQueueGenericReceive MPU_xQueueGenericReceive
+ #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting
+ #define vQueueDelete MPU_vQueueDelete
+
+ #define pvPortMalloc MPU_pvPortMalloc
+ #define vPortFree MPU_vPortFree
+ #define xPortGetFreeHeapSize MPU_xPortGetFreeHeapSize
+ #define vPortInitialiseBlocks MPU_vPortInitialiseBlocks
+
+ #if configQUEUE_REGISTRY_SIZE > 0
+ #define vQueueAddToRegistry MPU_vQueueAddToRegistry
+ #define vQueueUnregisterQueue MPU_vQueueUnregisterQueue
+ #endif
+
+ /* Remove the privileged function macro. */
+ #define PRIVILEGED_FUNCTION
+
+ #else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
+
+ /* Ensure API functions go in the privileged execution section. */
+ #define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions")))
+ #define PRIVILEGED_DATA __attribute__((section("privileged_data")))
+ //#define PRIVILEGED_DATA
+
+ #endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
+
+#else /* portUSING_MPU_WRAPPERS */
+
+ #define PRIVILEGED_FUNCTION
+ #define PRIVILEGED_DATA
+ #define portUSING_MPU_WRAPPERS 0
+
+#endif /* portUSING_MPU_WRAPPERS */
+
+
+#endif /* MPU_WRAPPERS_H */
+
diff --git a/libraries/FreeRTOS/utility/port.c b/libraries/FreeRTOS/utility/port.c
new file mode 100755
index 0000000..dc01720
--- /dev/null
+++ b/libraries/FreeRTOS/utility/port.c
@@ -0,0 +1,292 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+/*-----------------------------------------------------------
+ * Implementation of functions defined in portable.h for the ARM CM3 port.
+ *----------------------------------------------------------*/
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* For backward compatibility, ensure configKERNEL_INTERRUPT_PRIORITY is
+defined. The value should also ensure backward compatibility.
+FreeRTOS.org versions prior to V4.4.0 did not include this definition. */
+#ifndef configKERNEL_INTERRUPT_PRIORITY
+ #define configKERNEL_INTERRUPT_PRIORITY 255
+#endif
+
+/* Constants required to manipulate the NVIC. */
+#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 )
+#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 )
+#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 )
+#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 )
+#define portNVIC_SYSTICK_CLK 0x00000004
+#define portNVIC_SYSTICK_INT 0x00000002
+#define portNVIC_SYSTICK_ENABLE 0x00000001
+#define portNVIC_PENDSVSET 0x10000000
+#define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16 )
+#define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24 )
+
+/* Constants required to set up the initial stack. */
+#define portINITIAL_XPSR ( 0x01000000 )
+
+/* The priority used by the kernel is assigned to a variable to make access
+from inline assembler easier. */
+const unsigned long ulKernelPriority = configKERNEL_INTERRUPT_PRIORITY;
+
+/* Each task maintains its own interrupt status in the critical nesting
+variable. */
+static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa;
+
+/*
+ * Setup the timer to generate the tick interrupts.
+ */
+static void prvSetupTimerInterrupt( void );
+
+/*
+ * Exception handlers.
+ */
+void xPortPendSVHandler( void ) __attribute__ (( naked ));
+void xPortSysTickHandler( void );
+void vPortSVCHandler( void ) __attribute__ (( naked ));
+
+/*
+ * Start first task is a separate function so it can be tested in isolation.
+ */
+void vPortStartFirstTask( void ) __attribute__ (( naked ));
+
+/*-----------------------------------------------------------*/
+
+/*
+ * See header file for description.
+ */
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
+{
+ /* Simulate the stack frame as it would be created by a context switch
+ interrupt. */
+ pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
+ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */
+ pxTopOfStack--;
+ *pxTopOfStack = 0; /* LR */
+ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
+ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
+ pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
+
+ return pxTopOfStack;
+}
+/*-----------------------------------------------------------*/
+
+// !!! Maple
+// void vPortSVCHandler( void )
+void __exc_svc( void )
+// !!! Maple
+{
+ __asm volatile (
+ " ldr r3, pxCurrentTCBConst2 \n" /* Restore the context. */
+ " ldr r1, [r3] \n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
+ " ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */
+ " ldmia r0!, {r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
+ " msr psp, r0 \n" /* Restore the task stack pointer. */
+ " mov r0, #0 \n"
+ " msr basepri, r0 \n"
+ " orr r14, #0xd \n"
+ " bx r14 \n"
+ " \n"
+ " .align 2 \n"
+ "pxCurrentTCBConst2: .word pxCurrentTCB \n"
+ );
+}
+/*-----------------------------------------------------------*/
+
+void vPortStartFirstTask( void )
+{
+ __asm volatile(
+ " ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */
+ " ldr r0, [r0] \n"
+ " ldr r0, [r0] \n"
+ " msr msp, r0 \n" /* Set the msp back to the start of the stack. */
+ " cpsie i \n" /* Globally enable interrupts. */
+ " svc 0 \n" /* System call to start first task. */
+ " nop \n"
+ );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * See header file for description.
+ */
+portBASE_TYPE xPortStartScheduler( void )
+{
+ /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */
+ *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
+ *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;
+
+// !!! Maple
+ systick_attach_callback(&xPortSysTickHandler);
+// /* Start the timer that generates the tick ISR. Interrupts are disabled
+// here already. */
+// prvSetupTimerInterrupt();
+// !!! Maple
+
+ /* Initialise the critical nesting count ready for the first task. */
+ uxCriticalNesting = 0;
+
+ /* Start the first task. */
+ vPortStartFirstTask();
+
+ /* Should not get here! */
+ return 0;
+}
+/*-----------------------------------------------------------*/
+
+void vPortEndScheduler( void )
+{
+ /* It is unlikely that the CM3 port will require this function as there
+ is nothing to return to. */
+}
+/*-----------------------------------------------------------*/
+
+void vPortYieldFromISR( void )
+{
+ /* Set a PendSV to request a context switch. */
+ *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
+}
+/*-----------------------------------------------------------*/
+
+void vPortEnterCritical( void )
+{
+ portDISABLE_INTERRUPTS();
+ uxCriticalNesting++;
+}
+/*-----------------------------------------------------------*/
+
+void vPortExitCritical( void )
+{
+ uxCriticalNesting--;
+ if( uxCriticalNesting == 0 )
+ {
+ portENABLE_INTERRUPTS();
+ }
+}
+/*-----------------------------------------------------------*/
+
+// !!! Maple
+// void xPortPendSVHandler( void )
+void __exc_pendsv( void )
+// !!! Maple
+{
+ /* This is a naked function. */
+
+ __asm volatile
+ (
+ " mrs r0, psp \n"
+ " \n"
+ " ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */
+ " ldr r2, [r3] \n"
+ " \n"
+ " stmdb r0!, {r4-r11} \n" /* Save the remaining registers. */
+ " str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */
+ " \n"
+ " stmdb sp!, {r3, r14} \n"
+ " mov r0, %0 \n"
+ " msr basepri, r0 \n"
+ " bl vTaskSwitchContext \n"
+ " mov r0, #0 \n"
+ " msr basepri, r0 \n"
+ " ldmia sp!, {r3, r14} \n"
+ " \n" /* Restore the context, including the critical nesting count. */
+ " ldr r1, [r3] \n"
+ " ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */
+ " ldmia r0!, {r4-r11} \n" /* Pop the registers. */
+ " msr psp, r0 \n"
+ " bx r14 \n"
+ " \n"
+ " .align 2 \n"
+ "pxCurrentTCBConst: .word pxCurrentTCB \n"
+ ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
+ );
+}
+/*-----------------------------------------------------------*/
+
+void xPortSysTickHandler( void )
+{
+unsigned long ulDummy;
+
+ /* If using preemption, also force a context switch. */
+ #if configUSE_PREEMPTION == 1
+ *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
+ #endif
+
+ ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
+ {
+ vTaskIncrementTick();
+ }
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Setup the systick timer to generate the tick interrupts at the required
+ * frequency.
+ */
+void prvSetupTimerInterrupt( void )
+{
+ /* Configure SysTick to interrupt at the requested rate. */
+ *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
+ *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;
+}
+/*-----------------------------------------------------------*/
+
diff --git a/libraries/FreeRTOS/utility/portable.h b/libraries/FreeRTOS/utility/portable.h
new file mode 100755
index 0000000..b48a675
--- /dev/null
+++ b/libraries/FreeRTOS/utility/portable.h
@@ -0,0 +1,396 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+/*-----------------------------------------------------------
+ * Portable layer API. Each function must be defined for each port.
+ *----------------------------------------------------------*/
+
+#ifndef PORTABLE_H
+#define PORTABLE_H
+
+/* Include the macro file relevant to the port being used. */
+
+#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT
+ #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h"
+ typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT
+ #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h"
+ typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef GCC_MEGA_AVR
+ #include "../portable/GCC/ATMega323/portmacro.h"
+#endif
+
+#ifdef IAR_MEGA_AVR
+ #include "../portable/IAR/ATMega323/portmacro.h"
+#endif
+
+#ifdef MPLAB_PIC24_PORT
+ #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h"
+#endif
+
+#ifdef MPLAB_DSPIC_PORT
+ #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h"
+#endif
+
+#ifdef MPLAB_PIC18F_PORT
+ #include "..\..\Source\portable\MPLAB\PIC18F\portmacro.h"
+#endif
+
+#ifdef MPLAB_PIC32MX_PORT
+ #include "..\..\Source\portable\MPLAB\PIC32MX\portmacro.h"
+#endif
+
+#ifdef _FEDPICC
+ #include "libFreeRTOS/Include/portmacro.h"
+#endif
+
+#ifdef SDCC_CYGNAL
+ #include "../../Source/portable/SDCC/Cygnal/portmacro.h"
+#endif
+
+#ifdef GCC_ARM7
+ #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h"
+#endif
+
+#ifdef GCC_ARM7_ECLIPSE
+ #include "portmacro.h"
+#endif
+
+#ifdef ROWLEY_LPC23xx
+ #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h"
+#endif
+
+#ifdef IAR_MSP430
+ #include "..\..\Source\portable\IAR\MSP430\portmacro.h"
+#endif
+
+#ifdef GCC_MSP430
+ #include "../../Source/portable/GCC/MSP430F449/portmacro.h"
+#endif
+
+#ifdef ROWLEY_MSP430
+ #include "../../Source/portable/Rowley/MSP430F449/portmacro.h"
+#endif
+
+#ifdef ARM7_LPC21xx_KEIL_RVDS
+ #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h"
+#endif
+
+#ifdef SAM7_GCC
+ #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h"
+#endif
+
+#ifdef SAM7_IAR
+ #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h"
+#endif
+
+#ifdef SAM9XE_IAR
+ #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h"
+#endif
+
+#ifdef LPC2000_IAR
+ #include "..\..\Source\portable\IAR\LPC2000\portmacro.h"
+#endif
+
+#ifdef STR71X_IAR
+ #include "..\..\Source\portable\IAR\STR71x\portmacro.h"
+#endif
+
+#ifdef STR75X_IAR
+ #include "..\..\Source\portable\IAR\STR75x\portmacro.h"
+#endif
+
+#ifdef STR75X_GCC
+ #include "..\..\Source\portable\GCC\STR75x\portmacro.h"
+#endif
+
+#ifdef STR91X_IAR
+ #include "..\..\Source\portable\IAR\STR91x\portmacro.h"
+#endif
+
+#ifdef GCC_H8S
+ #include "../../Source/portable/GCC/H8S2329/portmacro.h"
+#endif
+
+#ifdef GCC_AT91FR40008
+ #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h"
+#endif
+
+#ifdef RVDS_ARMCM3_LM3S102
+ #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef GCC_ARMCM3_LM3S102
+ #include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef GCC_ARMCM3
+ #include "portmacro.h"
+#endif
+
+#ifdef IAR_ARM_CM3
+ #include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef IAR_ARMCM3_LM
+ #include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef HCS12_CODE_WARRIOR
+ #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h"
+#endif
+
+#ifdef MICROBLAZE_GCC
+ #include "../../Source/portable/GCC/MicroBlaze/portmacro.h"
+#endif
+
+#ifdef TERN_EE
+ #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h"
+#endif
+
+#ifdef GCC_HCS12
+ #include "../../Source/portable/GCC/HCS12/portmacro.h"
+#endif
+
+#ifdef GCC_MCF5235
+ #include "../../Source/portable/GCC/MCF5235/portmacro.h"
+#endif
+
+#ifdef COLDFIRE_V2_GCC
+ #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h"
+#endif
+
+#ifdef COLDFIRE_V2_CODEWARRIOR
+ #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h"
+#endif
+
+#ifdef GCC_PPC405
+ #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h"
+#endif
+
+#ifdef GCC_PPC440
+ #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h"
+#endif
+
+#ifdef _16FX_SOFTUNE
+ #include "..\..\Source\portable\Softune\MB96340\portmacro.h"
+#endif
+
+#ifdef BCC_INDUSTRIAL_PC_PORT
+ /* A short file name has to be used in place of the normal
+ FreeRTOSConfig.h when using the Borland compiler. */
+ #include "frconfig.h"
+ #include "..\portable\BCC\16BitDOS\PC\prtmacro.h"
+ typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef BCC_FLASH_LITE_186_PORT
+ /* A short file name has to be used in place of the normal
+ FreeRTOSConfig.h when using the Borland compiler. */
+ #include "frconfig.h"
+ #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h"
+ typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef __GNUC__
+ #ifdef __AVR32_AVR32A__
+ #include "portmacro.h"
+ #endif
+#endif
+
+#ifdef __ICCAVR32__
+ #ifdef __CORE__
+ #if __CORE__ == __AVR32A__
+ #include "portmacro.h"
+ #endif
+ #endif
+#endif
+
+#ifdef __91467D
+ #include "portmacro.h"
+#endif
+
+#ifdef __96340
+ #include "portmacro.h"
+#endif
+
+
+#ifdef __IAR_V850ES_Fx3__
+ #include "../../Source/portable/IAR/V850ES/portmacro.h"
+#endif
+
+#ifdef __IAR_V850ES_Jx3__
+ #include "../../Source/portable/IAR/V850ES/portmacro.h"
+#endif
+
+#ifdef __IAR_V850ES_Jx3_L__
+ #include "../../Source/portable/IAR/V850ES/portmacro.h"
+#endif
+
+#ifdef __IAR_V850ES_Jx2__
+ #include "../../Source/portable/IAR/V850ES/portmacro.h"
+#endif
+
+#ifdef __IAR_V850ES_Hx2__
+ #include "../../Source/portable/IAR/V850ES/portmacro.h"
+#endif
+
+#ifdef __IAR_78K0R_Kx3__
+ #include "../../Source/portable/IAR/78K0R/portmacro.h"
+#endif
+
+#ifdef __IAR_78K0R_Kx3L__
+ #include "../../Source/portable/IAR/78K0R/portmacro.h"
+#endif
+
+/* Catch all to ensure portmacro.h is included in the build. Newer demos
+have the path as part of the project options, rather than as relative from
+the project location. If portENTER_CRITICAL() has not been defined then
+portmacro.h has not yet been included - as every portmacro.h provides a
+portENTER_CRITICAL() definition. Check the demo application for your demo
+to find the path to the correct portmacro.h file. */
+#ifndef portENTER_CRITICAL
+ #include "portmacro.h"
+#endif
+
+#if portBYTE_ALIGNMENT == 8
+ #define portBYTE_ALIGNMENT_MASK ( 0x0007 )
+#endif
+
+#if portBYTE_ALIGNMENT == 4
+ #define portBYTE_ALIGNMENT_MASK ( 0x0003 )
+#endif
+
+#if portBYTE_ALIGNMENT == 2
+ #define portBYTE_ALIGNMENT_MASK ( 0x0001 )
+#endif
+
+#if portBYTE_ALIGNMENT == 1
+ #define portBYTE_ALIGNMENT_MASK ( 0x0000 )
+#endif
+
+#ifndef portBYTE_ALIGNMENT_MASK
+ #error "Invalid portBYTE_ALIGNMENT definition"
+#endif
+
+#ifndef portNUM_CONFIGURABLE_REGIONS
+ #define portNUM_CONFIGURABLE_REGIONS 1
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mpu_wrappers.h"
+
+/*
+ * Setup the stack of a new task so it is ready to be placed under the
+ * scheduler control. The registers have to be placed on the stack in
+ * the order that the port expects to find them.
+ *
+ */
+#if( portUSING_MPU_WRAPPERS == 1 )
+ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters, portBASE_TYPE xRunPrivileged ) PRIVILEGED_FUNCTION;
+#else
+ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters );
+#endif
+
+/*
+ * Map to the memory management routines required for the port.
+ */
+void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;
+void vPortFree( void *pv ) PRIVILEGED_FUNCTION;
+void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
+size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Setup the hardware ready for the scheduler to take control. This generally
+ * sets up a tick interrupt and sets timers for the correct tick frequency.
+ */
+portBASE_TYPE xPortStartScheduler( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so
+ * the hardware is left in its original condition after the scheduler stops
+ * executing.
+ */
+void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * The structures and methods of manipulating the MPU are contained within the
+ * port layer.
+ *
+ * Fills the xMPUSettings structure with the memory region information
+ * contained in xRegions.
+ */
+#if( portUSING_MPU_WRAPPERS == 1 )
+ struct xMEMORY_REGION;
+ void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, portSTACK_TYPE *pxBottomOfStack, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PORTABLE_H */
+
diff --git a/libraries/FreeRTOS/utility/portmacro.h b/libraries/FreeRTOS/utility/portmacro.h
new file mode 100755
index 0000000..7f2d1af
--- /dev/null
+++ b/libraries/FreeRTOS/utility/portmacro.h
@@ -0,0 +1,156 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#ifndef PORTMACRO_H
+#define PORTMACRO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-----------------------------------------------------------
+ * Port specific definitions.
+ *
+ * The settings in this file configure FreeRTOS correctly for the
+ * given hardware and compiler.
+ *
+ * These settings should not be altered.
+ *-----------------------------------------------------------
+ */
+
+/* Type definitions. */
+#define portCHAR char
+#define portFLOAT float
+#define portDOUBLE double
+#define portLONG long
+#define portSHORT short
+#define portSTACK_TYPE unsigned portLONG
+#define portBASE_TYPE long
+
+#if( configUSE_16_BIT_TICKS == 1 )
+ typedef unsigned portSHORT portTickType;
+ #define portMAX_DELAY ( portTickType ) 0xffff
+#else
+ typedef unsigned portLONG portTickType;
+ #define portMAX_DELAY ( portTickType ) 0xffffffff
+#endif
+/*-----------------------------------------------------------*/
+
+/* Architecture specifics. */
+#define portSTACK_GROWTH ( -1 )
+#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
+#define portBYTE_ALIGNMENT 8
+/*-----------------------------------------------------------*/
+
+
+/* Scheduler utilities. */
+extern void vPortYieldFromISR( void );
+
+#define portYIELD() vPortYieldFromISR()
+
+#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()
+/*-----------------------------------------------------------*/
+
+
+/* Critical section management. */
+
+/*
+ * Set basepri to portMAX_SYSCALL_INTERRUPT_PRIORITY without effecting other
+ * registers. r0 is clobbered.
+ */
+#define portSET_INTERRUPT_MASK() \
+ __asm volatile \
+ ( \
+ " mov r0, %0 \n" \
+ " msr basepri, r0 \n" \
+ ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY):"r0" \
+ )
+
+/*
+ * Set basepri back to 0 without effective other registers.
+ * r0 is clobbered.
+ */
+#define portCLEAR_INTERRUPT_MASK() \
+ __asm volatile \
+ ( \
+ " mov r0, #0 \n" \
+ " msr basepri, r0 \n" \
+ :::"r0" \
+ )
+
+#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK()
+#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x
+
+
+extern void vPortEnterCritical( void );
+extern void vPortExitCritical( void );
+
+#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK()
+#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK()
+#define portENTER_CRITICAL() vPortEnterCritical()
+#define portEXIT_CRITICAL() vPortExitCritical()
+/*-----------------------------------------------------------*/
+
+/* Task function macros as described on the FreeRTOS.org WEB site. */
+#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
+#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
+
+#define portNOP()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PORTMACRO_H */
+
diff --git a/libraries/FreeRTOS/utility/projdefs.h b/libraries/FreeRTOS/utility/projdefs.h
new file mode 100755
index 0000000..18366fa
--- /dev/null
+++ b/libraries/FreeRTOS/utility/projdefs.h
@@ -0,0 +1,83 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#ifndef PROJDEFS_H
+#define PROJDEFS_H
+
+/* Defines the prototype to which task functions must conform. */
+typedef void (*pdTASK_CODE)( void * );
+
+#define pdTRUE ( 1 )
+#define pdFALSE ( 0 )
+
+#define pdPASS ( 1 )
+#define pdFAIL ( 0 )
+#define errQUEUE_EMPTY ( 0 )
+#define errQUEUE_FULL ( 0 )
+
+/* Error definitions. */
+#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )
+#define errNO_TASK_TO_RUN ( -2 )
+#define errQUEUE_BLOCKED ( -4 )
+#define errQUEUE_YIELD ( -5 )
+
+#endif /* PROJDEFS_H */
+
+
+
diff --git a/libraries/FreeRTOS/utility/queue.c b/libraries/FreeRTOS/utility/queue.c
new file mode 100755
index 0000000..c7ed600
--- /dev/null
+++ b/libraries/FreeRTOS/utility/queue.c
@@ -0,0 +1,1539 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
+all the API functions to use the MPU wrappers. That should only be done when
+task.h is included from an application file. */
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "croutine.h"
+
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+/*-----------------------------------------------------------
+ * PUBLIC LIST API documented in list.h
+ *----------------------------------------------------------*/
+
+/* Constants used with the cRxLock and cTxLock structure members. */
+#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
+#define queueLOCKED_UNMODIFIED ( ( signed portBASE_TYPE ) 0 )
+
+#define queueERRONEOUS_UNBLOCK ( -1 )
+
+/* For internal use only. */
+#define queueSEND_TO_BACK ( 0 )
+#define queueSEND_TO_FRONT ( 1 )
+
+/* Effectively make a union out of the xQUEUE structure. */
+#define pxMutexHolder pcTail
+#define uxQueueType pcHead
+#define uxRecursiveCallCount pcReadFrom
+#define queueQUEUE_IS_MUTEX NULL
+
+/* Semaphores do not actually store or copy data, so have an items size of
+zero. */
+#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( 0 )
+#define queueDONT_BLOCK ( ( portTickType ) 0 )
+#define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0 )
+
+/*
+ * Definition of the queue used by the scheduler.
+ * Items are queued by copy, not reference.
+ */
+typedef struct QueueDefinition
+{
+ signed char *pcHead; /*< Points to the beginning of the queue storage area. */
+ signed char *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
+
+ signed char *pcWriteTo; /*< Points to the free next place in the storage area. */
+ signed char *pcReadFrom; /*< Points to the last place that a queued item was read from. */
+
+ xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
+ xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
+
+ volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
+ unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
+ unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
+
+ signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
+ signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
+
+} xQUEUE;
+/*-----------------------------------------------------------*/
+
+/*
+ * Inside this file xQueueHandle is a pointer to a xQUEUE structure.
+ * To keep the definition private the API header file defines it as a
+ * pointer to void.
+ */
+typedef xQUEUE * xQueueHandle;
+
+/*
+ * Prototypes for public functions are included here so we don't have to
+ * include the API header file (as it defines xQueueHandle differently). These
+ * functions are documented in the API header file.
+ */
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+void vQueueDelete( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION;
+xQueueHandle xQueueCreateMutex( void ) PRIVILEGED_FUNCTION;
+xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) PRIVILEGED_FUNCTION;
+portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ) PRIVILEGED_FUNCTION;
+portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+
+/*
+ * Co-routine queue functions differ from task queue functions. Co-routines are
+ * an optional component.
+ */
+#if configUSE_CO_ROUTINES == 1
+ signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) PRIVILEGED_FUNCTION;
+ signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION;
+ signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+ signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+#endif
+
+/*
+ * The queue registry is just a means for kernel aware debuggers to locate
+ * queue structures. It has no other purpose so is an optional component.
+ */
+#if configQUEUE_REGISTRY_SIZE > 0
+
+ /* The type stored within the queue registry array. This allows a name
+ to be assigned to each queue making kernel aware debugging a little
+ more user friendly. */
+ typedef struct QUEUE_REGISTRY_ITEM
+ {
+ signed char *pcQueueName;
+ xQueueHandle xHandle;
+ } xQueueRegistryItem;
+
+ /* The queue registry is simply an array of xQueueRegistryItem structures.
+ The pcQueueName member of a structure being NULL is indicative of the
+ array position being vacant. */
+ xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ];
+
+ /* Removes a queue from the registry by simply setting the pcQueueName
+ member to NULL. */
+ static void vQueueUnregisterQueue( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;
+ void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) PRIVILEGED_FUNCTION;
+#endif
+
+/*
+ * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
+ * prevent an ISR from adding or removing items to the queue, but does prevent
+ * an ISR from removing tasks from the queue event lists. If an ISR finds a
+ * queue is locked it will instead increment the appropriate queue lock count
+ * to indicate that a task may require unblocking. When the queue in unlocked
+ * these lock counts are inspected, and the appropriate action taken.
+ */
+static void prvUnlockQueue( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+
+/*
+ * Uses a critical section to determine if there is any data in a queue.
+ *
+ * @return pdTRUE if the queue contains no items, otherwise pdFALSE.
+ */
+static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+
+/*
+ * Uses a critical section to determine if there is any space in a queue.
+ *
+ * @return pdTRUE if there is no space, otherwise pdFALSE;
+ */
+static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+
+/*
+ * Copies an item into the queue, either at the front of the queue or the
+ * back of the queue.
+ */
+static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) PRIVILEGED_FUNCTION;
+
+/*
+ * Copies an item out of a queue.
+ */
+static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) PRIVILEGED_FUNCTION;
+/*-----------------------------------------------------------*/
+
+/*
+ * Macro to mark a queue as locked. Locking a queue prevents an ISR from
+ * accessing the queue event lists.
+ */
+#define prvLockQueue( pxQueue ) \
+ taskENTER_CRITICAL(); \
+ { \
+ if( ( pxQueue )->xRxLock == queueUNLOCKED ) \
+ { \
+ ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED; \
+ } \
+ if( ( pxQueue )->xTxLock == queueUNLOCKED ) \
+ { \
+ ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED; \
+ } \
+ } \
+ taskEXIT_CRITICAL()
+/*-----------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------
+ * PUBLIC QUEUE MANAGEMENT API documented in queue.h
+ *----------------------------------------------------------*/
+
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
+{
+xQUEUE *pxNewQueue;
+size_t xQueueSizeInBytes;
+xQueueHandle xReturn = NULL;
+
+ /* Allocate the new queue structure. */
+ if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
+ {
+ pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
+ if( pxNewQueue != NULL )
+ {
+ /* Create the list of pointers to queue items. The queue is one byte
+ longer than asked for to make wrap checking easier/faster. */
+ xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
+
+ pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes );
+ if( pxNewQueue->pcHead != NULL )
+ {
+ /* Initialise the queue members as described above where the
+ queue type is defined. */
+ pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
+ pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;
+ pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
+ pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - ( unsigned portBASE_TYPE ) 1U ) * uxItemSize );
+ pxNewQueue->uxLength = uxQueueLength;
+ pxNewQueue->uxItemSize = uxItemSize;
+ pxNewQueue->xRxLock = queueUNLOCKED;
+ pxNewQueue->xTxLock = queueUNLOCKED;
+
+ /* Likewise ensure the event queues start with the correct state. */
+ vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
+ vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
+
+ traceQUEUE_CREATE( pxNewQueue );
+ xReturn = pxNewQueue;
+ }
+ else
+ {
+ traceQUEUE_CREATE_FAILED();
+ vPortFree( pxNewQueue );
+ }
+ }
+ }
+
+ configASSERT( xReturn );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_MUTEXES == 1 )
+
+ xQueueHandle xQueueCreateMutex( void )
+ {
+ xQUEUE *pxNewQueue;
+
+ /* Allocate the new queue structure. */
+ pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
+ if( pxNewQueue != NULL )
+ {
+ /* Information required for priority inheritance. */
+ pxNewQueue->pxMutexHolder = NULL;
+ pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;
+
+ /* Queues used as a mutex no data is actually copied into or out
+ of the queue. */
+ pxNewQueue->pcWriteTo = NULL;
+ pxNewQueue->pcReadFrom = NULL;
+
+ /* Each mutex has a length of 1 (like a binary semaphore) and
+ an item size of 0 as nothing is actually copied into or out
+ of the mutex. */
+ pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;
+ pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U;
+ pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U;
+ pxNewQueue->xRxLock = queueUNLOCKED;
+ pxNewQueue->xTxLock = queueUNLOCKED;
+
+ /* Ensure the event queues start with the correct state. */
+ vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
+ vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
+
+ /* Start with the semaphore in the expected state. */
+ xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK );
+
+ traceCREATE_MUTEX( pxNewQueue );
+ }
+ else
+ {
+ traceCREATE_MUTEX_FAILED();
+ }
+
+ configASSERT( pxNewQueue );
+ return pxNewQueue;
+ }
+
+#endif /* configUSE_MUTEXES */
+/*-----------------------------------------------------------*/
+
+#if configUSE_RECURSIVE_MUTEXES == 1
+
+ portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )
+ {
+ portBASE_TYPE xReturn;
+
+ configASSERT( pxMutex );
+
+ /* If this is the task that holds the mutex then pxMutexHolder will not
+ change outside of this task. If this task does not hold the mutex then
+ pxMutexHolder can never coincidentally equal the tasks handle, and as
+ this is the only condition we are interested in it does not matter if
+ pxMutexHolder is accessed simultaneously by another task. Therefore no
+ mutual exclusion is required to test the pxMutexHolder variable. */
+ if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
+ {
+ traceGIVE_MUTEX_RECURSIVE( pxMutex );
+
+ /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to
+ the task handle, therefore no underflow check is required. Also,
+ uxRecursiveCallCount is only modified by the mutex holder, and as
+ there can only be one, no mutual exclusion is required to modify the
+ uxRecursiveCallCount member. */
+ ( pxMutex->uxRecursiveCallCount )--;
+
+ /* Have we unwound the call count? */
+ if( pxMutex->uxRecursiveCallCount == 0 )
+ {
+ /* Return the mutex. This will automatically unblock any other
+ task that might be waiting to access the mutex. */
+ xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ /* We cannot give the mutex because we are not the holder. */
+ xReturn = pdFAIL;
+
+ traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );
+ }
+
+ return xReturn;
+ }
+
+#endif /* configUSE_RECURSIVE_MUTEXES */
+/*-----------------------------------------------------------*/
+
+#if configUSE_RECURSIVE_MUTEXES == 1
+
+ portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )
+ {
+ portBASE_TYPE xReturn;
+
+ configASSERT( pxMutex );
+
+ /* Comments regarding mutual exclusion as per those within
+ xQueueGiveMutexRecursive(). */
+
+ traceTAKE_MUTEX_RECURSIVE( pxMutex );
+
+ if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
+ {
+ ( pxMutex->uxRecursiveCallCount )++;
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );
+
+ /* pdPASS will only be returned if we successfully obtained the mutex,
+ we may have blocked to reach here. */
+ if( xReturn == pdPASS )
+ {
+ ( pxMutex->uxRecursiveCallCount )++;
+ }
+ else
+ {
+ traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex );
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif /* configUSE_RECURSIVE_MUTEXES */
+/*-----------------------------------------------------------*/
+
+#if configUSE_COUNTING_SEMAPHORES == 1
+
+ xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )
+ {
+ xQueueHandle pxHandle;
+
+ pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );
+
+ if( pxHandle != NULL )
+ {
+ pxHandle->uxMessagesWaiting = uxInitialCount;
+
+ traceCREATE_COUNTING_SEMAPHORE();
+ }
+ else
+ {
+ traceCREATE_COUNTING_SEMAPHORE_FAILED();
+ }
+
+ configASSERT( pxHandle );
+ return pxHandle;
+ }
+
+#endif /* configUSE_COUNTING_SEMAPHORES */
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
+{
+signed portBASE_TYPE xEntryTimeSet = pdFALSE;
+xTimeOutType xTimeOut;
+
+ configASSERT( pxQueue );
+ configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ /* This function relaxes the coding standard somewhat to allow return
+ statements within the function itself. This is done in the interest
+ of execution time efficiency. */
+ for( ;; )
+ {
+ taskENTER_CRITICAL();
+ {
+ /* Is there room on the queue now? To be running we must be
+ the highest priority task wanting to access the queue. */
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ traceQUEUE_SEND( pxQueue );
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
+
+ /* If there was a task waiting for data to arrive on the
+ queue then unblock it now. */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
+ {
+ /* The unblocked task has a priority higher than
+ our own so yield immediately. Yes it is ok to do
+ this from within the critical section - the kernel
+ takes care of that. */
+ portYIELD_WITHIN_API();
+ }
+ }
+
+ taskEXIT_CRITICAL();
+
+ /* Return to the original privilege level before exiting the
+ function. */
+ return pdPASS;
+ }
+ else
+ {
+ if( xTicksToWait == ( portTickType ) 0 )
+ {
+ /* The queue was full and no block time is specified (or
+ the block time has expired) so leave now. */
+ taskEXIT_CRITICAL();
+
+ /* Return to the original privilege level before exiting
+ the function. */
+ traceQUEUE_SEND_FAILED( pxQueue );
+ return errQUEUE_FULL;
+ }
+ else if( xEntryTimeSet == pdFALSE )
+ {
+ /* The queue was full and a block time was specified so
+ configure the timeout structure. */
+ vTaskSetTimeOutState( &xTimeOut );
+ xEntryTimeSet = pdTRUE;
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ /* Interrupts and other tasks can send to and receive from the queue
+ now the critical section has been exited. */
+
+ vTaskSuspendAll();
+ prvLockQueue( pxQueue );
+
+ /* Update the timeout state to see if it has expired yet. */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ if( prvIsQueueFull( pxQueue ) )
+ {
+ traceBLOCKING_ON_QUEUE_SEND( pxQueue );
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
+
+ /* Unlocking the queue means queue events can effect the
+ event list. It is possible that interrupts occurring now
+ remove this task from the event list again - but as the
+ scheduler is suspended the task will go onto the pending
+ ready last instead of the actual ready list. */
+ prvUnlockQueue( pxQueue );
+
+ /* Resuming the scheduler will move tasks from the pending
+ ready list into the ready list - so it is feasible that this
+ task is already in a ready list before it yields - in which
+ case the yield will not cause a context switch unless there
+ is also a higher priority task in the pending ready list. */
+ if( !xTaskResumeAll() )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ else
+ {
+ /* Try again. */
+ prvUnlockQueue( pxQueue );
+ ( void ) xTaskResumeAll();
+ }
+ }
+ else
+ {
+ /* The timeout has expired. */
+ prvUnlockQueue( pxQueue );
+ ( void ) xTaskResumeAll();
+
+ /* Return to the original privilege level before exiting the
+ function. */
+ traceQUEUE_SEND_FAILED( pxQueue );
+ return errQUEUE_FULL;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+#if configUSE_ALTERNATIVE_API == 1
+
+ signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
+ {
+ signed portBASE_TYPE xEntryTimeSet = pdFALSE;
+ xTimeOutType xTimeOut;
+
+ configASSERT( pxQueue );
+ configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ for( ;; )
+ {
+ taskENTER_CRITICAL();
+ {
+ /* Is there room on the queue now? To be running we must be
+ the highest priority task wanting to access the queue. */
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ traceQUEUE_SEND( pxQueue );
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
+
+ /* If there was a task waiting for data to arrive on the
+ queue then unblock it now. */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
+ {
+ /* The unblocked task has a priority higher than
+ our own so yield immediately. */
+ portYIELD_WITHIN_API();
+ }
+ }
+
+ taskEXIT_CRITICAL();
+ return pdPASS;
+ }
+ else
+ {
+ if( xTicksToWait == ( portTickType ) 0 )
+ {
+ taskEXIT_CRITICAL();
+ return errQUEUE_FULL;
+ }
+ else if( xEntryTimeSet == pdFALSE )
+ {
+ vTaskSetTimeOutState( &xTimeOut );
+ xEntryTimeSet = pdTRUE;
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ taskENTER_CRITICAL();
+ {
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ if( prvIsQueueFull( pxQueue ) )
+ {
+ traceBLOCKING_ON_QUEUE_SEND( pxQueue );
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
+ portYIELD_WITHIN_API();
+ }
+ }
+ else
+ {
+ taskEXIT_CRITICAL();
+ traceQUEUE_SEND_FAILED( pxQueue );
+ return errQUEUE_FULL;
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+#endif /* configUSE_ALTERNATIVE_API */
+/*-----------------------------------------------------------*/
+
+#if configUSE_ALTERNATIVE_API == 1
+
+ signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
+ {
+ signed portBASE_TYPE xEntryTimeSet = pdFALSE;
+ xTimeOutType xTimeOut;
+ signed char *pcOriginalReadPosition;
+
+ configASSERT( pxQueue );
+ configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ for( ;; )
+ {
+ taskENTER_CRITICAL();
+ {
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Remember our read position in case we are just peeking. */
+ pcOriginalReadPosition = pxQueue->pcReadFrom;
+
+ prvCopyDataFromQueue( pxQueue, pvBuffer );
+
+ if( xJustPeeking == pdFALSE )
+ {
+ traceQUEUE_RECEIVE( pxQueue );
+
+ /* We are actually removing data. */
+ --( pxQueue->uxMessagesWaiting );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ /* Record the information required to implement
+ priority inheritance should it become necessary. */
+ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
+ }
+ }
+ #endif
+
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ else
+ {
+ traceQUEUE_PEEK( pxQueue );
+
+ /* We are not removing the data, so reset our read
+ pointer. */
+ pxQueue->pcReadFrom = pcOriginalReadPosition;
+
+ /* The data is being left in the queue, so see if there are
+ any other tasks waiting for the data. */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ /* Tasks that are removed from the event list will get added to
+ the pending ready list as the scheduler is still suspended. */
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority than this task. */
+ portYIELD_WITHIN_API();
+ }
+ }
+
+ }
+
+ taskEXIT_CRITICAL();
+ return pdPASS;
+ }
+ else
+ {
+ if( xTicksToWait == ( portTickType ) 0 )
+ {
+ taskEXIT_CRITICAL();
+ traceQUEUE_RECEIVE_FAILED( pxQueue );
+ return errQUEUE_EMPTY;
+ }
+ else if( xEntryTimeSet == pdFALSE )
+ {
+ vTaskSetTimeOutState( &xTimeOut );
+ xEntryTimeSet = pdTRUE;
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ taskENTER_CRITICAL();
+ {
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ if( prvIsQueueEmpty( pxQueue ) )
+ {
+ traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ portENTER_CRITICAL();
+ vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
+ portEXIT_CRITICAL();
+ }
+ }
+ #endif
+
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+ portYIELD_WITHIN_API();
+ }
+ }
+ else
+ {
+ taskEXIT_CRITICAL();
+ traceQUEUE_RECEIVE_FAILED( pxQueue );
+ return errQUEUE_EMPTY;
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+
+#endif /* configUSE_ALTERNATIVE_API */
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition )
+{
+signed portBASE_TYPE xReturn;
+unsigned portBASE_TYPE uxSavedInterruptStatus;
+
+ configASSERT( pxQueue );
+ configASSERT( pxHigherPriorityTaskWoken );
+ configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ /* Similar to xQueueGenericSend, except we don't block if there is no room
+ in the queue. Also we don't directly wake a task that was blocked on a
+ queue read, instead we return a flag to say whether a context switch is
+ required or not (i.e. has a task with a higher priority than us been woken
+ by this post). */
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
+ {
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ traceQUEUE_SEND_FROM_ISR( pxQueue );
+
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
+
+ /* If the queue is locked we do not alter the event list. This will
+ be done when the queue is unlocked later. */
+ if( pxQueue->xTxLock == queueUNLOCKED )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority so record that a
+ context switch is required. */
+ *pxHigherPriorityTaskWoken = pdTRUE;
+ }
+ }
+ }
+ else
+ {
+ /* Increment the lock count so the task that unlocks the queue
+ knows that data was posted while it was locked. */
+ ++( pxQueue->xTxLock );
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
+ xReturn = errQUEUE_FULL;
+ }
+ }
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
+{
+signed portBASE_TYPE xEntryTimeSet = pdFALSE;
+xTimeOutType xTimeOut;
+signed char *pcOriginalReadPosition;
+
+ configASSERT( pxQueue );
+ configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ /* This function relaxes the coding standard somewhat to allow return
+ statements within the function itself. This is done in the interest
+ of execution time efficiency. */
+
+ for( ;; )
+ {
+ taskENTER_CRITICAL();
+ {
+ /* Is there data in the queue now? To be running we must be
+ the highest priority task wanting to access the queue. */
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Remember our read position in case we are just peeking. */
+ pcOriginalReadPosition = pxQueue->pcReadFrom;
+
+ prvCopyDataFromQueue( pxQueue, pvBuffer );
+
+ if( xJustPeeking == pdFALSE )
+ {
+ traceQUEUE_RECEIVE( pxQueue );
+
+ /* We are actually removing data. */
+ --( pxQueue->uxMessagesWaiting );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ /* Record the information required to implement
+ priority inheritance should it become necessary. */
+ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
+ }
+ }
+ #endif
+
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ else
+ {
+ traceQUEUE_PEEK( pxQueue );
+
+ /* We are not removing the data, so reset our read
+ pointer. */
+ pxQueue->pcReadFrom = pcOriginalReadPosition;
+
+ /* The data is being left in the queue, so see if there are
+ any other tasks waiting for the data. */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ /* Tasks that are removed from the event list will get added to
+ the pending ready list as the scheduler is still suspended. */
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority than this task. */
+ portYIELD_WITHIN_API();
+ }
+ }
+
+ }
+
+ taskEXIT_CRITICAL();
+ return pdPASS;
+ }
+ else
+ {
+ if( xTicksToWait == ( portTickType ) 0 )
+ {
+ /* The queue was empty and no block time is specified (or
+ the block time has expired) so leave now. */
+ taskEXIT_CRITICAL();
+ traceQUEUE_RECEIVE_FAILED( pxQueue );
+ return errQUEUE_EMPTY;
+ }
+ else if( xEntryTimeSet == pdFALSE )
+ {
+ /* The queue was empty and a block time was specified so
+ configure the timeout structure. */
+ vTaskSetTimeOutState( &xTimeOut );
+ xEntryTimeSet = pdTRUE;
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ /* Interrupts and other tasks can send to and receive from the queue
+ now the critical section has been exited. */
+
+ vTaskSuspendAll();
+ prvLockQueue( pxQueue );
+
+ /* Update the timeout state to see if it has expired yet. */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ if( prvIsQueueEmpty( pxQueue ) )
+ {
+ traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ portENTER_CRITICAL();
+ {
+ vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
+ }
+ portEXIT_CRITICAL();
+ }
+ }
+ #endif
+
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+ prvUnlockQueue( pxQueue );
+ if( !xTaskResumeAll() )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ else
+ {
+ /* Try again. */
+ prvUnlockQueue( pxQueue );
+ ( void ) xTaskResumeAll();
+ }
+ }
+ else
+ {
+ prvUnlockQueue( pxQueue );
+ ( void ) xTaskResumeAll();
+ traceQUEUE_RECEIVE_FAILED( pxQueue );
+ return errQUEUE_EMPTY;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )
+{
+signed portBASE_TYPE xReturn;
+unsigned portBASE_TYPE uxSavedInterruptStatus;
+
+ configASSERT( pxQueue );
+ configASSERT( pxTaskWoken );
+ configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
+ {
+ /* We cannot block from an ISR, so check there is data available. */
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
+
+ prvCopyDataFromQueue( pxQueue, pvBuffer );
+ --( pxQueue->uxMessagesWaiting );
+
+ /* If the queue is locked we will not modify the event list. Instead
+ we update the lock count so the task that unlocks the queue will know
+ that an ISR has removed data while the queue was locked. */
+ if( pxQueue->xRxLock == queueUNLOCKED )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority than us so
+ force a context switch. */
+ *pxTaskWoken = pdTRUE;
+ }
+ }
+ }
+ else
+ {
+ /* Increment the lock count so the task that unlocks the queue
+ knows that data was removed while it was locked. */
+ ++( pxQueue->xRxLock );
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );
+ }
+ }
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )
+{
+unsigned portBASE_TYPE uxReturn;
+
+ configASSERT( pxQueue );
+
+ taskENTER_CRITICAL();
+ uxReturn = pxQueue->uxMessagesWaiting;
+ taskEXIT_CRITICAL();
+
+ return uxReturn;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )
+{
+unsigned portBASE_TYPE uxReturn;
+
+ configASSERT( pxQueue );
+
+ uxReturn = pxQueue->uxMessagesWaiting;
+
+ return uxReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vQueueDelete( xQueueHandle pxQueue )
+{
+ configASSERT( pxQueue );
+
+ traceQUEUE_DELETE( pxQueue );
+ vQueueUnregisterQueue( pxQueue );
+ vPortFree( pxQueue->pcHead );
+ vPortFree( pxQueue );
+}
+/*-----------------------------------------------------------*/
+
+static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )
+{
+ if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 )
+ {
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ /* The mutex is no longer being held. */
+ vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );
+ pxQueue->pxMutexHolder = NULL;
+ }
+ }
+ #endif
+ }
+ else if( xPosition == queueSEND_TO_BACK )
+ {
+ memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
+ pxQueue->pcWriteTo += pxQueue->uxItemSize;
+ if( pxQueue->pcWriteTo >= pxQueue->pcTail )
+ {
+ pxQueue->pcWriteTo = pxQueue->pcHead;
+ }
+ }
+ else
+ {
+ memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
+ pxQueue->pcReadFrom -= pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom < pxQueue->pcHead )
+ {
+ pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
+ }
+ }
+
+ ++( pxQueue->uxMessagesWaiting );
+}
+/*-----------------------------------------------------------*/
+
+static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )
+{
+ if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )
+ {
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvUnlockQueue( xQueueHandle pxQueue )
+{
+ /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
+
+ /* The lock counts contains the number of extra data items placed or
+ removed from the queue while the queue was locked. When a queue is
+ locked items can be added or removed, but the event lists cannot be
+ updated. */
+ taskENTER_CRITICAL();
+ {
+ /* See if data was added to the queue while it was locked. */
+ while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )
+ {
+ /* Data was posted while the queue was locked. Are any tasks
+ blocked waiting for data to become available? */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ /* Tasks that are removed from the event list will get added to
+ the pending ready list as the scheduler is still suspended. */
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority so record that a
+ context switch is required. */
+ vTaskMissedYield();
+ }
+
+ --( pxQueue->xTxLock );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ pxQueue->xTxLock = queueUNLOCKED;
+ }
+ taskEXIT_CRITICAL();
+
+ /* Do the same for the Rx lock. */
+ taskENTER_CRITICAL();
+ {
+ while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ vTaskMissedYield();
+ }
+
+ --( pxQueue->xRxLock );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ pxQueue->xRxLock = queueUNLOCKED;
+ }
+ taskEXIT_CRITICAL();
+}
+/*-----------------------------------------------------------*/
+
+static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ taskENTER_CRITICAL();
+ xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ configASSERT( pxQueue );
+ xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ taskENTER_CRITICAL();
+ xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ configASSERT( pxQueue );
+ xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn;
+
+ /* If the queue is already full we may have to block. A critical section
+ is required to prevent an interrupt removing something from the queue
+ between the check to see if the queue is full and blocking on the queue. */
+ portDISABLE_INTERRUPTS();
+ {
+ if( prvIsQueueFull( pxQueue ) )
+ {
+ /* The queue is full - do we want to block or just leave without
+ posting? */
+ if( xTicksToWait > ( portTickType ) 0 )
+ {
+ /* As this is called from a coroutine we cannot block directly, but
+ return indicating that we need to block. */
+ vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
+ portENABLE_INTERRUPTS();
+ return errQUEUE_BLOCKED;
+ }
+ else
+ {
+ portENABLE_INTERRUPTS();
+ return errQUEUE_FULL;
+ }
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ portNOP();
+
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ /* There is room in the queue, copy the data into the queue. */
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
+ xReturn = pdPASS;
+
+ /* Were any co-routines waiting for data to become available? */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ /* In this instance the co-routine could be placed directly
+ into the ready list as we are within a critical section.
+ Instead the same pending ready list mechanism is used as if
+ the event were caused from within an interrupt. */
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The co-routine waiting has a higher priority so record
+ that a yield might be appropriate. */
+ xReturn = errQUEUE_YIELD;
+ }
+ }
+ }
+ else
+ {
+ xReturn = errQUEUE_FULL;
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn;
+
+ /* If the queue is already empty we may have to block. A critical section
+ is required to prevent an interrupt adding something to the queue
+ between the check to see if the queue is empty and blocking on the queue. */
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* There are no messages in the queue, do we want to block or just
+ leave with nothing? */
+ if( xTicksToWait > ( portTickType ) 0 )
+ {
+ /* As this is a co-routine we cannot block directly, but return
+ indicating that we need to block. */
+ vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );
+ portENABLE_INTERRUPTS();
+ return errQUEUE_BLOCKED;
+ }
+ else
+ {
+ portENABLE_INTERRUPTS();
+ return errQUEUE_FULL;
+ }
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ portNOP();
+
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Data is available from the queue. */
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ --( pxQueue->uxMessagesWaiting );
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+
+ xReturn = pdPASS;
+
+ /* Were any co-routines waiting for space to become available? */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ /* In this instance the co-routine could be placed directly
+ into the ready list as we are within a critical section.
+ Instead the same pending ready list mechanism is used as if
+ the event were caused from within an interrupt. */
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ xReturn = errQUEUE_YIELD;
+ }
+ }
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )
+{
+ /* Cannot block within an ISR so if there is no space on the queue then
+ exit without doing anything. */
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
+
+ /* We only want to wake one co-routine per ISR, so check that a
+ co-routine has not already been woken. */
+ if( !xCoRoutinePreviouslyWoken )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ return pdTRUE;
+ }
+ }
+ }
+ }
+
+ return xCoRoutinePreviouslyWoken;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )
+{
+signed portBASE_TYPE xReturn;
+
+ /* We cannot block from an ISR, so check there is data available. If
+ not then just leave without doing anything. */
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Copy the data from the queue. */
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ --( pxQueue->uxMessagesWaiting );
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+
+ if( !( *pxCoRoutineWoken ) )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ *pxCoRoutineWoken = pdTRUE;
+ }
+ }
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+#if configQUEUE_REGISTRY_SIZE > 0
+
+ void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName )
+ {
+ unsigned portBASE_TYPE ux;
+
+ /* See if there is an empty space in the registry. A NULL name denotes
+ a free slot. */
+ for( ux = ( unsigned portBASE_TYPE ) 0U; ux < configQUEUE_REGISTRY_SIZE; ux++ )
+ {
+ if( xQueueRegistry[ ux ].pcQueueName == NULL )
+ {
+ /* Store the information on this queue. */
+ xQueueRegistry[ ux ].pcQueueName = pcQueueName;
+ xQueueRegistry[ ux ].xHandle = xQueue;
+ break;
+ }
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if configQUEUE_REGISTRY_SIZE > 0
+
+ static void vQueueUnregisterQueue( xQueueHandle xQueue )
+ {
+ unsigned portBASE_TYPE ux;
+
+ /* See if the handle of the queue being unregistered in actually in the
+ registry. */
+ for( ux = ( unsigned portBASE_TYPE ) 0U; ux < configQUEUE_REGISTRY_SIZE; ux++ )
+ {
+ if( xQueueRegistry[ ux ].xHandle == xQueue )
+ {
+ /* Set the name to NULL to show that this slot if free again. */
+ xQueueRegistry[ ux ].pcQueueName = NULL;
+ break;
+ }
+ }
+
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if configUSE_TIMERS == 1
+
+ void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait )
+ {
+ /* This function should not be called by application code hence the
+ 'Restricted' in its name. It is not part of the public API. It is
+ designed for use by kernel code, and has special calling requirements.
+ It can result in vListInsert() being called on a list that can only
+ possibly ever have one item in it, so the list will be fast, but even
+ so it should be called with the scheduler locked and not from a critical
+ section. */
+
+ /* Only do anything if there are no messages in the queue. This function
+ will not actually cause the task to block, just place it on a blocked
+ list. It will not block until the scheduler is unlocked - at which
+ time a yield will be performed. If an item is added to the queue while
+ the queue is locked, and the calling task blocks on the queue, then the
+ calling task will be immediately unblocked when the queue is unlocked. */
+ prvLockQueue( pxQueue );
+ if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U )
+ {
+ /* There is nothing in the queue, block for the specified period. */
+ vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+ }
+ prvUnlockQueue( pxQueue );
+ }
+
+#endif
+
diff --git a/libraries/FreeRTOS/utility/queue.h b/libraries/FreeRTOS/utility/queue.h
new file mode 100755
index 0000000..9a6c86a
--- /dev/null
+++ b/libraries/FreeRTOS/utility/queue.h
@@ -0,0 +1,1270 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#ifndef QUEUE_H
+#define QUEUE_H
+
+#ifndef INC_FREERTOS_H
+ #error "#include FreeRTOS.h" must appear in source files before "#include queue.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "mpu_wrappers.h"
+
+/**
+ * Type by which queues are referenced. For example, a call to xQueueCreate
+ * returns (via a pointer parameter) an xQueueHandle variable that can then
+ * be used as a parameter to xQueueSend(), xQueueReceive(), etc.
+ */
+typedef void * xQueueHandle;
+
+
+/* For internal use only. */
+#define queueSEND_TO_BACK ( 0 )
+#define queueSEND_TO_FRONT ( 1 )
+
+
+/**
+ * queue. h
+ * <pre>
+ xQueueHandle xQueueCreate(
+ unsigned portBASE_TYPE uxQueueLength,
+ unsigned portBASE_TYPE uxItemSize
+ );
+ * </pre>
+ *
+ * Creates a new queue instance. This allocates the storage required by the
+ * new queue and returns a handle for the queue.
+ *
+ * @param uxQueueLength The maximum number of items that the queue can contain.
+ *
+ * @param uxItemSize The number of bytes each item in the queue will require.
+ * Items are queued by copy, not by reference, so this is the number of bytes
+ * that will be copied for each posted item. Each item on the queue must be
+ * the same size.
+ *
+ * @return If the queue is successfully create then a handle to the newly
+ * created queue is returned. If the queue cannot be created then 0 is
+ * returned.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ };
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+ if( xQueue1 == 0 )
+ {
+ // Queue was not created and must not be used.
+ }
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue2 == 0 )
+ {
+ // Queue was not created and must not be used.
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueCreate xQueueCreate
+ * \ingroup QueueManagement
+ */
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendToToFront(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ * </pre>
+ *
+ * This is a macro that calls xQueueGenericSend().
+ *
+ * Post an item to the front of a queue. The item is queued by copy, not by
+ * reference. This function must not be called from an interrupt service
+ * routine. See xQueueSendFromISR () for an alternative which may be used
+ * in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0 and the
+ * queue is full. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendToBack(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ * </pre>
+ *
+ * This is a macro that calls xQueueGenericSend().
+ *
+ * Post an item to the back of a queue. The item is queued by copy, not by
+ * reference. This function must not be called from an interrupt service
+ * routine. See xQueueSendFromISR () for an alternative which may be used
+ * in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0 and the queue
+ * is full. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSend(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ * </pre>
+ *
+ * This is a macro that calls xQueueGenericSend(). It is included for
+ * backward compatibility with versions of FreeRTOS.org that did not
+ * include the xQueueSendToFront() and xQueueSendToBack() macros. It is
+ * equivalent to xQueueSendToBack().
+ *
+ * Post an item on a queue. The item is queued by copy, not by reference.
+ * This function must not be called from an interrupt service routine.
+ * See xQueueSendFromISR () for an alternative which may be used in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0 and the
+ * queue is full. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
+
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueGenericSend(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ portBASE_TYPE xCopyPosition
+ );
+ * </pre>
+ *
+ * It is preferred that the macros xQueueSend(), xQueueSendToFront() and
+ * xQueueSendToBack() are used in place of calling this function directly.
+ *
+ * Post an item on a queue. The item is queued by copy, not by reference.
+ * This function must not be called from an interrupt service routine.
+ * See xQueueSendFromISR () for an alternative which may be used in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0 and the
+ * queue is full. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
+ * item at the back of the queue, or queueSEND_TO_FRONT to place the item
+ * at the front of the queue (for high priority messages).
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10, queueSEND_TO_BACK ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0, queueSEND_TO_BACK );
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueuePeek(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ );</pre>
+ *
+ * This is a macro that calls the xQueueGenericReceive() function.
+ *
+ * Receive an item from a queue without removing the item from the queue.
+ * The item is received by copy so a buffer of adequate size must be
+ * provided. The number of bytes copied into the buffer was defined when
+ * the queue was created.
+ *
+ * Successfully received items remain on the queue so will be returned again
+ * by the next call, or a call to xQueueReceive().
+ *
+ * This macro must not be used in an interrupt service routine.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue
+ * is empty.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to peek the data from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Peek a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueuePeek( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask, but the item still remains on the queue.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueReceive(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ );</pre>
+ *
+ * This is a macro that calls the xQueueGenericReceive() function.
+ *
+ * Receive an item from a queue. The item is received by copy so a buffer of
+ * adequate size must be provided. The number of bytes copied into the buffer
+ * was defined when the queue was created.
+ *
+ * Successfully received items are removed from the queue.
+ *
+ * This function must not be used in an interrupt service routine. See
+ * xQueueReceiveFromISR for an alternative that can.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. xQueueReceive() will return immediately if xTicksToWait
+ * is zero and the queue is empty. The time is defined in tick periods so the
+ * constant portTICK_RATE_MS should be used to convert to real time if this is
+ * required.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Receive a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
+
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueGenericReceive(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ portBASE_TYPE xJustPeek
+ );</pre>
+ *
+ * It is preferred that the macro xQueueReceive() be used rather than calling
+ * this function directly.
+ *
+ * Receive an item from a queue. The item is received by copy so a buffer of
+ * adequate size must be provided. The number of bytes copied into the buffer
+ * was defined when the queue was created.
+ *
+ * This function must not be used in an interrupt service routine. See
+ * xQueueReceiveFromISR for an alternative that can.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ * xQueueGenericReceive() will return immediately if the queue is empty and
+ * xTicksToWait is 0.
+ *
+ * @param xJustPeek When set to true, the item received from the queue is not
+ * actually removed from the queue - meaning a subsequent call to
+ * xQueueReceive() will return the same item. When set to false, the item
+ * being received from the queue is also removed from the queue.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Receive a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeek );
+
+/**
+ * queue. h
+ * <pre>unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );</pre>
+ *
+ * Return the number of messages stored in a queue.
+ *
+ * @param xQueue A handle to the queue being queried.
+ *
+ * @return The number of messages available in the queue.
+ *
+ * \page uxQueueMessagesWaiting uxQueueMessagesWaiting
+ * \ingroup QueueManagement
+ */
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );
+
+/**
+ * queue. h
+ * <pre>void vQueueDelete( xQueueHandle xQueue );</pre>
+ *
+ * Delete a queue - freeing all the memory allocated for storing of items
+ * placed on the queue.
+ *
+ * @param xQueue A handle to the queue to be deleted.
+ *
+ * \page vQueueDelete vQueueDelete
+ * \ingroup QueueManagement
+ */
+void vQueueDelete( xQueueHandle pxQueue );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendToFrontFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE *pxHigherPriorityTaskWoken
+ );
+ </pre>
+ *
+ * This is a macro that calls xQueueGenericSendFromISR().
+ *
+ * Post an item to the front of a queue. It is safe to use this macro from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xQueueSendToFromFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @return pdTRUE if the data was successfully sent to the queue, otherwise
+ * errQUEUE_FULL.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+ <pre>
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPrioritTaskWoken;
+
+ // We have not woken a task at the start of the ISR.
+ xHigherPriorityTaskWoken = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte.
+ xQueueSendToFrontFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( xHigherPriorityTaskWoken )
+ {
+ taskYIELD ();
+ }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToFrontFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT )
+
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendToBackFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE *pxHigherPriorityTaskWoken
+ );
+ </pre>
+ *
+ * This is a macro that calls xQueueGenericSendFromISR().
+ *
+ * Post an item to the back of a queue. It is safe to use this macro from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param pxHigherPriorityTaskWoken xQueueSendToBackFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @return pdTRUE if the data was successfully sent to the queue, otherwise
+ * errQUEUE_FULL.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+ <pre>
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWoken;
+
+ // We have not woken a task at the start of the ISR.
+ xHigherPriorityTaskWoken = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte.
+ xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( xHigherPriorityTaskWoken )
+ {
+ taskYIELD ();
+ }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToBackFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE *pxHigherPriorityTaskWoken
+ );
+ </pre>
+ *
+ * This is a macro that calls xQueueGenericSendFromISR(). It is included
+ * for backward compatibility with versions of FreeRTOS.org that did not
+ * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR()
+ * macros.
+ *
+ * Post an item to the back of a queue. It is safe to use this function from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param pxHigherPriorityTaskWoken xQueueSendFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xQueueSendFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @return pdTRUE if the data was successfully sent to the queue, otherwise
+ * errQUEUE_FULL.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+ <pre>
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWoken;
+
+ // We have not woken a task at the start of the ISR.
+ xHigherPriorityTaskWoken = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte.
+ xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( xHigherPriorityTaskWoken )
+ {
+ // Actual macro used here is port specific.
+ taskYIELD_FROM_ISR ();
+ }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueGenericSendFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE *pxHigherPriorityTaskWoken,
+ portBASE_TYPE xCopyPosition
+ );
+ </pre>
+ *
+ * It is preferred that the macros xQueueSendFromISR(),
+ * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place
+ * of calling this function directly.
+ *
+ * Post an item on a queue. It is safe to use this function from within an
+ * interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xQueueGenericSendFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
+ * item at the back of the queue, or queueSEND_TO_FRONT to place the item
+ * at the front of the queue (for high priority messages).
+ *
+ * @return pdTRUE if the data was successfully sent to the queue, otherwise
+ * errQUEUE_FULL.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+ <pre>
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWokenByPost;
+
+ // We have not woken a task at the start of the ISR.
+ xHigherPriorityTaskWokenByPost = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post each byte.
+ xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary. Note that the
+ // name of the yield function required is port specific.
+ if( xHigherPriorityTaskWokenByPost )
+ {
+ taskYIELD_YIELD_FROM_ISR();
+ }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueReceiveFromISR(
+ xQueueHandle pxQueue,
+ void *pvBuffer,
+ portBASE_TYPE *pxTaskWoken
+ );
+ * </pre>
+ *
+ * Receive an item from a queue. It is safe to use this function from within an
+ * interrupt service routine.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param pxTaskWoken A task may be blocked waiting for space to become
+ * available on the queue. If xQueueReceiveFromISR causes such a task to
+ * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will
+ * remain unchanged.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+ <pre>
+
+ xQueueHandle xQueue;
+
+ // Function to create a queue and post some values.
+ void vAFunction( void *pvParameters )
+ {
+ char cValueToPost;
+ const portTickType xBlockTime = ( portTickType )0xff;
+
+ // Create a queue capable of containing 10 characters.
+ xQueue = xQueueCreate( 10, sizeof( char ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Post some characters that will be used within an ISR. If the queue
+ // is full then this task will block for xBlockTime ticks.
+ cValueToPost = 'a';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+ cValueToPost = 'b';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+
+ // ... keep posting characters ... this task may block when the queue
+ // becomes full.
+
+ cValueToPost = 'c';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+ }
+
+ // ISR that outputs all the characters received on the queue.
+ void vISR_Routine( void )
+ {
+ portBASE_TYPE xTaskWokenByReceive = pdFALSE;
+ char cRxedChar;
+
+ while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
+ {
+ // A character was received. Output the character now.
+ vOutputCharacter( cRxedChar );
+
+ // If removing the character from the queue woke the task that was
+ // posting onto the queue cTaskWokenByReceive will have been set to
+ // pdTRUE. No matter how many times this loop iterates only one
+ // task will be woken.
+ }
+
+ if( cTaskWokenByPost != ( char ) pdFALSE;
+ {
+ taskYIELD ();
+ }
+ }
+ </pre>
+ * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+
+/*
+ * Utilities to query queue that are safe to use from an ISR. These utilities
+ * should be used only from witin an ISR, or within a critical section.
+ */
+signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );
+signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue );
+
+
+/*
+ * xQueueAltGenericSend() is an alternative version of xQueueGenericSend().
+ * Likewise xQueueAltGenericReceive() is an alternative version of
+ * xQueueGenericReceive().
+ *
+ * The source code that implements the alternative (Alt) API is much
+ * simpler because it executes everything from within a critical section.
+ * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
+ * preferred fully featured API too. The fully featured API has more
+ * complex code that takes longer to execute, but makes much less use of
+ * critical sections. Therefore the alternative API sacrifices interrupt
+ * responsiveness to gain execution speed, whereas the fully featured API
+ * sacrifices execution speed to ensure better interrupt responsiveness.
+ */
+signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
+signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
+#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
+#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
+#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
+#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )
+
+/*
+ * The functions defined above are for passing data to and from tasks. The
+ * functions below are the equivalents for passing data to and from
+ * co-routines.
+ *
+ * These functions are called from the co-routine macro implementation and
+ * should not be called directly from application code. Instead use the macro
+ * wrappers defined within croutine.h.
+ */
+signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
+signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
+signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
+
+/*
+ * For internal use only. Use xSemaphoreCreateMutex() or
+ * xSemaphoreCreateCounting() instead of calling these functions directly.
+ */
+xQueueHandle xQueueCreateMutex( void );
+xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount );
+
+/*
+ * For internal use only. Use xSemaphoreTakeMutexRecursive() or
+ * xSemaphoreGiveMutexRecursive() instead of calling these functions directly.
+ */
+portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime );
+portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex );
+
+/*
+ * The registry is provided as a means for kernel aware debuggers to
+ * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add
+ * a queue, semaphore or mutex handle to the registry if you want the handle
+ * to be available to a kernel aware debugger. If you are not using a kernel
+ * aware debugger then this function can be ignored.
+ *
+ * configQUEUE_REGISTRY_SIZE defines the maximum number of handles the
+ * registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0
+ * within FreeRTOSConfig.h for the registry to be available. Its value
+ * does not effect the number of queues, semaphores and mutexes that can be
+ * created - just the number that the registry can hold.
+ *
+ * @param xQueue The handle of the queue being added to the registry. This
+ * is the handle returned by a call to xQueueCreate(). Semaphore and mutex
+ * handles can also be passed in here.
+ *
+ * @param pcName The name to be associated with the handle. This is the
+ * name that the kernel aware debugger will display.
+ */
+#if configQUEUE_REGISTRY_SIZE > 0U
+ void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcName );
+#endif
+
+/* Not a public API function, hence the 'Restricted' in the name. */
+void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QUEUE_H */
+
diff --git a/libraries/FreeRTOS/utility/semphr.h b/libraries/FreeRTOS/utility/semphr.h
new file mode 100755
index 0000000..7a9e83f
--- /dev/null
+++ b/libraries/FreeRTOS/utility/semphr.h
@@ -0,0 +1,717 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#ifndef SEMAPHORE_H
+#define SEMAPHORE_H
+
+#ifndef INC_FREERTOS_H
+ #error "#include FreeRTOS.h" must appear in source files before "#include semphr.h"
+#endif
+
+#include "queue.h"
+
+typedef xQueueHandle xSemaphoreHandle;
+
+#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned char ) 1U )
+#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned char ) 0U )
+#define semGIVE_BLOCK_TIME ( ( portTickType ) 0U )
+
+
+/**
+ * semphr. h
+ * <pre>vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )</pre>
+ *
+ * <i>Macro</i> that implements a semaphore by using the existing queue mechanism.
+ * The queue length is 1 as this is a binary semaphore. The data size is 0
+ * as we don't want to actually store any data - we just want to know if the
+ * queue is empty or full.
+ *
+ * This type of semaphore can be used for pure synchronisation between tasks or
+ * between an interrupt and a task. The semaphore need not be given back once
+ * obtained, so one task/interrupt can continuously 'give' the semaphore while
+ * another continuously 'takes' the semaphore. For this reason this type of
+ * semaphore does not use a priority inheritance mechanism. For an alternative
+ * that does use priority inheritance see xSemaphoreCreateMutex().
+ *
+ * @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+ // This is a macro so pass the variable in directly.
+ vSemaphoreCreateBinary( xSemaphore );
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+ </pre>
+ * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
+ * \ingroup Semaphores
+ */
+#define vSemaphoreCreateBinary( xSemaphore ) { \
+ ( xSemaphore ) = xQueueCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \
+ if( ( xSemaphore ) != NULL ) \
+ { \
+ xSemaphoreGive( ( xSemaphore ) ); \
+ } \
+ }
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreTake(
+ * xSemaphoreHandle xSemaphore,
+ * portTickType xBlockTime
+ * )</pre>
+ *
+ * <i>Macro</i> to obtain a semaphore. The semaphore must have previously been
+ * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or
+ * xSemaphoreCreateCounting().
+ *
+ * @param xSemaphore A handle to the semaphore being taken - obtained when
+ * the semaphore was created.
+ *
+ * @param xBlockTime The time in ticks to wait for the semaphore to become
+ * available. The macro portTICK_RATE_MS can be used to convert this to a
+ * real time. A block time of zero can be used to poll the semaphore. A block
+ * time of portMAX_DELAY can be used to block indefinitely (provided
+ * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h).
+ *
+ * @return pdTRUE if the semaphore was obtained. pdFALSE
+ * if xBlockTime expired without the semaphore becoming available.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // A task that creates a semaphore.
+ void vATask( void * pvParameters )
+ {
+ // Create the semaphore to guard a shared resource.
+ vSemaphoreCreateBinary( xSemaphore );
+ }
+
+ // A task that uses the semaphore.
+ void vAnotherTask( void * pvParameters )
+ {
+ // ... Do other things.
+
+ if( xSemaphore != NULL )
+ {
+ // See if we can obtain the semaphore. If the semaphore is not available
+ // wait 10 ticks to see if it becomes free.
+ if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+ {
+ // We were able to obtain the semaphore and can now access the
+ // shared resource.
+
+ // ...
+
+ // We have finished accessing the shared resource. Release the
+ // semaphore.
+ xSemaphoreGive( xSemaphore );
+ }
+ else
+ {
+ // We could not obtain the semaphore and can therefore not access
+ // the shared resource safely.
+ }
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreTake xSemaphoreTake
+ * \ingroup Semaphores
+ */
+#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
+
+/**
+ * semphr. h
+ * xSemaphoreTakeRecursive(
+ * xSemaphoreHandle xMutex,
+ * portTickType xBlockTime
+ * )
+ *
+ * <i>Macro</i> to recursively obtain, or 'take', a mutex type semaphore.
+ * The mutex must have previously been created using a call to
+ * xSemaphoreCreateRecursiveMutex();
+ *
+ * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this
+ * macro to be available.
+ *
+ * This macro must not be used on mutexes created using xSemaphoreCreateMutex().
+ *
+ * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
+ * doesn't become available again until the owner has called
+ * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
+ * if a task successfully 'takes' the same mutex 5 times then the mutex will
+ * not be available to any other task until it has also 'given' the mutex back
+ * exactly five times.
+ *
+ * @param xMutex A handle to the mutex being obtained. This is the
+ * handle returned by xSemaphoreCreateRecursiveMutex();
+ *
+ * @param xBlockTime The time in ticks to wait for the semaphore to become
+ * available. The macro portTICK_RATE_MS can be used to convert this to a
+ * real time. A block time of zero can be used to poll the semaphore. If
+ * the task already owns the semaphore then xSemaphoreTakeRecursive() will
+ * return immediately no matter what the value of xBlockTime.
+ *
+ * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime
+ * expired without the semaphore becoming available.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+ // Create the mutex to guard a shared resource.
+ xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+ // ... Do other things.
+
+ if( xMutex != NULL )
+ {
+ // See if we can obtain the mutex. If the mutex is not available
+ // wait 10 ticks to see if it becomes free.
+ if( xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+ {
+ // We were able to obtain the mutex and can now access the
+ // shared resource.
+
+ // ...
+ // For some reason due to the nature of the code further calls to
+ // xSemaphoreTakeRecursive() are made on the same mutex. In real
+ // code these would not be just sequential calls as this would make
+ // no sense. Instead the calls are likely to be buried inside
+ // a more complex call structure.
+ xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+ xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+
+ // The mutex has now been 'taken' three times, so will not be
+ // available to another task until it has also been given back
+ // three times. Again it is unlikely that real code would have
+ // these calls sequentially, but instead buried in a more complex
+ // call structure. This is just for illustrative purposes.
+ xSemaphoreGiveRecursive( xMutex );
+ xSemaphoreGiveRecursive( xMutex );
+ xSemaphoreGiveRecursive( xMutex );
+
+ // Now the mutex can be taken by other tasks.
+ }
+ else
+ {
+ // We could not obtain the mutex and can therefore not access
+ // the shared resource safely.
+ }
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive
+ * \ingroup Semaphores
+ */
+#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
+
+
+/*
+ * xSemaphoreAltTake() is an alternative version of xSemaphoreTake().
+ *
+ * The source code that implements the alternative (Alt) API is much
+ * simpler because it executes everything from within a critical section.
+ * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
+ * preferred fully featured API too. The fully featured API has more
+ * complex code that takes longer to execute, but makes much less use of
+ * critical sections. Therefore the alternative API sacrifices interrupt
+ * responsiveness to gain execution speed, whereas the fully featured API
+ * sacrifices execution speed to ensure better interrupt responsiveness.
+ */
+#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreGive( xSemaphoreHandle xSemaphore )</pre>
+ *
+ * <i>Macro</i> to release a semaphore. The semaphore must have previously been
+ * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or
+ * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake().
+ *
+ * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for
+ * an alternative which can be used from an ISR.
+ *
+ * This macro must also not be used on semaphores created using
+ * xSemaphoreCreateRecursiveMutex().
+ *
+ * @param xSemaphore A handle to the semaphore being released. This is the
+ * handle returned when the semaphore was created.
+ *
+ * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred.
+ * Semaphores are implemented using queues. An error can occur if there is
+ * no space on the queue to post a message - indicating that the
+ * semaphore was not first obtained correctly.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+ // Create the semaphore to guard a shared resource.
+ vSemaphoreCreateBinary( xSemaphore );
+
+ if( xSemaphore != NULL )
+ {
+ if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+ {
+ // We would expect this call to fail because we cannot give
+ // a semaphore without first "taking" it!
+ }
+
+ // Obtain the semaphore - don't block if the semaphore is not
+ // immediately available.
+ if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) )
+ {
+ // We now have the semaphore and can access the shared resource.
+
+ // ...
+
+ // We have finished accessing the shared resource so can free the
+ // semaphore.
+ if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+ {
+ // We would not expect this call to fail because we must have
+ // obtained the semaphore to get here.
+ }
+ }
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreGive xSemaphoreGive
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreGiveRecursive( xSemaphoreHandle xMutex )</pre>
+ *
+ * <i>Macro</i> to recursively release, or 'give', a mutex type semaphore.
+ * The mutex must have previously been created using a call to
+ * xSemaphoreCreateRecursiveMutex();
+ *
+ * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this
+ * macro to be available.
+ *
+ * This macro must not be used on mutexes created using xSemaphoreCreateMutex().
+ *
+ * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
+ * doesn't become available again until the owner has called
+ * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
+ * if a task successfully 'takes' the same mutex 5 times then the mutex will
+ * not be available to any other task until it has also 'given' the mutex back
+ * exactly five times.
+ *
+ * @param xMutex A handle to the mutex being released, or 'given'. This is the
+ * handle returned by xSemaphoreCreateMutex();
+ *
+ * @return pdTRUE if the semaphore was given.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+ // Create the mutex to guard a shared resource.
+ xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+ // ... Do other things.
+
+ if( xMutex != NULL )
+ {
+ // See if we can obtain the mutex. If the mutex is not available
+ // wait 10 ticks to see if it becomes free.
+ if( xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 ) == pdTRUE )
+ {
+ // We were able to obtain the mutex and can now access the
+ // shared resource.
+
+ // ...
+ // For some reason due to the nature of the code further calls to
+ // xSemaphoreTakeRecursive() are made on the same mutex. In real
+ // code these would not be just sequential calls as this would make
+ // no sense. Instead the calls are likely to be buried inside
+ // a more complex call structure.
+ xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+ xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+
+ // The mutex has now been 'taken' three times, so will not be
+ // available to another task until it has also been given back
+ // three times. Again it is unlikely that real code would have
+ // these calls sequentially, it would be more likely that the calls
+ // to xSemaphoreGiveRecursive() would be called as a call stack
+ // unwound. This is just for demonstrative purposes.
+ xSemaphoreGiveRecursive( xMutex );
+ xSemaphoreGiveRecursive( xMutex );
+ xSemaphoreGiveRecursive( xMutex );
+
+ // Now the mutex can be taken by other tasks.
+ }
+ else
+ {
+ // We could not obtain the mutex and can therefore not access
+ // the shared resource safely.
+ }
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) )
+
+/*
+ * xSemaphoreAltGive() is an alternative version of xSemaphoreGive().
+ *
+ * The source code that implements the alternative (Alt) API is much
+ * simpler because it executes everything from within a critical section.
+ * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
+ * preferred fully featured API too. The fully featured API has more
+ * complex code that takes longer to execute, but makes much less use of
+ * critical sections. Therefore the alternative API sacrifices interrupt
+ * responsiveness to gain execution speed, whereas the fully featured API
+ * sacrifices execution speed to ensure better interrupt responsiveness.
+ */
+#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
+
+/**
+ * semphr. h
+ * <pre>
+ xSemaphoreGiveFromISR(
+ xSemaphoreHandle xSemaphore,
+ signed portBASE_TYPE *pxHigherPriorityTaskWoken
+ )</pre>
+ *
+ * <i>Macro</i> to release a semaphore. The semaphore must have previously been
+ * created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting().
+ *
+ * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())
+ * must not be used with this macro.
+ *
+ * This macro can be used from an ISR.
+ *
+ * @param xSemaphore A handle to the semaphore being released. This is the
+ * handle returned when the semaphore was created.
+ *
+ * @param pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ \#define LONG_TIME 0xffff
+ \#define TICKS_TO_WAIT 10
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // Repetitive task.
+ void vATask( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // We want this task to run every 10 ticks of a timer. The semaphore
+ // was created before this task was started.
+
+ // Block waiting for the semaphore to become available.
+ if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
+ {
+ // It is time to execute.
+
+ // ...
+
+ // We have finished our task. Return to the top of the loop where
+ // we will block on the semaphore until it is time to execute
+ // again. Note when using the semaphore for synchronisation with an
+ // ISR in this manner there is no need to 'give' the semaphore back.
+ }
+ }
+ }
+
+ // Timer ISR
+ void vTimerISR( void * pvParameters )
+ {
+ static unsigned char ucLocalTickCount = 0;
+ static signed portBASE_TYPE xHigherPriorityTaskWoken;
+
+ // A timer tick has occurred.
+
+ // ... Do other time functions.
+
+ // Is it time for vATask () to run?
+ xHigherPriorityTaskWoken = pdFALSE;
+ ucLocalTickCount++;
+ if( ucLocalTickCount >= TICKS_TO_WAIT )
+ {
+ // Unblock the task by releasing the semaphore.
+ xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
+
+ // Reset the count so we release the semaphore again in 10 ticks time.
+ ucLocalTickCount = 0;
+ }
+
+ if( xHigherPriorityTaskWoken != pdFALSE )
+ {
+ // We can force a context switch here. Context switching from an
+ // ISR uses port specific syntax. Check the demo task for your port
+ // to find the syntax required.
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueueHandle ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreHandle xSemaphoreCreateMutex( void )</pre>
+ *
+ * <i>Macro</i> that implements a mutex semaphore by using the existing queue
+ * mechanism.
+ *
+ * Mutexes created using this macro can be accessed using the xSemaphoreTake()
+ * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and
+ * xSemaphoreGiveRecursive() macros should not be used.
+ *
+ * This type of semaphore uses a priority inheritance mechanism so a task
+ * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
+ * semaphore it is no longer required.
+ *
+ * Mutex type semaphores cannot be used from within interrupt service routines.
+ *
+ * See vSemaphoreCreateBinary() for an alternative implementation that can be
+ * used for pure synchronisation (where one task or interrupt always 'gives' the
+ * semaphore and another always 'takes' the semaphore) and from within interrupt
+ * service routines.
+ *
+ * @return xSemaphore Handle to the created mutex semaphore. Should be of type
+ * xSemaphoreHandle.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+ // This is a macro so pass the variable in directly.
+ xSemaphore = xSemaphoreCreateMutex();
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+ </pre>
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
+ * \ingroup Semaphores
+ */
+#define xSemaphoreCreateMutex() xQueueCreateMutex()
+
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreHandle xSemaphoreCreateRecursiveMutex( void )</pre>
+ *
+ * <i>Macro</i> that implements a recursive mutex by using the existing queue
+ * mechanism.
+ *
+ * Mutexes created using this macro can be accessed using the
+ * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The
+ * xSemaphoreTake() and xSemaphoreGive() macros should not be used.
+ *
+ * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
+ * doesn't become available again until the owner has called
+ * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
+ * if a task successfully 'takes' the same mutex 5 times then the mutex will
+ * not be available to any other task until it has also 'given' the mutex back
+ * exactly five times.
+ *
+ * This type of semaphore uses a priority inheritance mechanism so a task
+ * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
+ * semaphore it is no longer required.
+ *
+ * Mutex type semaphores cannot be used from within interrupt service routines.
+ *
+ * See vSemaphoreCreateBinary() for an alternative implementation that can be
+ * used for pure synchronisation (where one task or interrupt always 'gives' the
+ * semaphore and another always 'takes' the semaphore) and from within interrupt
+ * service routines.
+ *
+ * @return xSemaphore Handle to the created mutex semaphore. Should be of type
+ * xSemaphoreHandle.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+ // This is a macro so pass the variable in directly.
+ xSemaphore = xSemaphoreCreateRecursiveMutex();
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+ </pre>
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
+ * \ingroup Semaphores
+ */
+#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex()
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreHandle xSemaphoreCreateCounting( unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount )</pre>
+ *
+ * <i>Macro</i> that creates a counting semaphore by using the existing
+ * queue mechanism.
+ *
+ * Counting semaphores are typically used for two things:
+ *
+ * 1) Counting events.
+ *
+ * In this usage scenario an event handler will 'give' a semaphore each time
+ * an event occurs (incrementing the semaphore count value), and a handler
+ * task will 'take' a semaphore each time it processes an event
+ * (decrementing the semaphore count value). The count value is therefore
+ * the difference between the number of events that have occurred and the
+ * number that have been processed. In this case it is desirable for the
+ * initial count value to be zero.
+ *
+ * 2) Resource management.
+ *
+ * In this usage scenario the count value indicates the number of resources
+ * available. To obtain control of a resource a task must first obtain a
+ * semaphore - decrementing the semaphore count value. When the count value
+ * reaches zero there are no free resources. When a task finishes with the
+ * resource it 'gives' the semaphore back - incrementing the semaphore count
+ * value. In this case it is desirable for the initial count value to be
+ * equal to the maximum count value, indicating that all resources are free.
+ *
+ * @param uxMaxCount The maximum count value that can be reached. When the
+ * semaphore reaches this value it can no longer be 'given'.
+ *
+ * @param uxInitialCount The count value assigned to the semaphore when it is
+ * created.
+ *
+ * @return Handle to the created semaphore. Null if the semaphore could not be
+ * created.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // Semaphore cannot be used before a call to xSemaphoreCreateCounting().
+ // The max value to which the semaphore can count should be 10, and the
+ // initial value assigned to the count should be 0.
+ xSemaphore = xSemaphoreCreateCounting( 10, 0 );
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting
+ * \ingroup Semaphores
+ */
+#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
+
+
+#endif /* SEMAPHORE_H */
+
+
diff --git a/libraries/FreeRTOS/utility/task.h b/libraries/FreeRTOS/utility/task.h
new file mode 100755
index 0000000..96ba68e
--- /dev/null
+++ b/libraries/FreeRTOS/utility/task.h
@@ -0,0 +1,1307 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#ifndef TASK_H
+#define TASK_H
+
+#ifndef INC_FREERTOS_H
+ #error "include FreeRTOS.h must appear in source files before include task.h"
+#endif
+
+#include "portable.h"
+#include "list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-----------------------------------------------------------
+ * MACROS AND DEFINITIONS
+ *----------------------------------------------------------*/
+
+#define tskKERNEL_VERSION_NUMBER "V7.0.1"
+
+/**
+ * task. h
+ *
+ * Type by which tasks are referenced. For example, a call to xTaskCreate
+ * returns (via a pointer parameter) an xTaskHandle variable that can then
+ * be used as a parameter to vTaskDelete to delete the task.
+ *
+ * \page xTaskHandle xTaskHandle
+ * \ingroup Tasks
+ */
+typedef void * xTaskHandle;
+
+/*
+ * Used internally only.
+ */
+typedef struct xTIME_OUT
+{
+ portBASE_TYPE xOverflowCount;
+ portTickType xTimeOnEntering;
+} xTimeOutType;
+
+/*
+ * Defines the memory ranges allocated to the task when an MPU is used.
+ */
+typedef struct xMEMORY_REGION
+{
+ void *pvBaseAddress;
+ unsigned long ulLengthInBytes;
+ unsigned long ulParameters;
+} xMemoryRegion;
+
+/*
+ * Parameters required to create an MPU protected task.
+ */
+typedef struct xTASK_PARAMTERS
+{
+ pdTASK_CODE pvTaskCode;
+ const signed char * const pcName;
+ unsigned short usStackDepth;
+ void *pvParameters;
+ unsigned portBASE_TYPE uxPriority;
+ portSTACK_TYPE *puxStackBuffer;
+ xMemoryRegion xRegions[ portNUM_CONFIGURABLE_REGIONS ];
+} xTaskParameters;
+
+/*
+ * Defines the priority used by the idle task. This must not be modified.
+ *
+ * \ingroup TaskUtils
+ */
+#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0U )
+
+/**
+ * task. h
+ *
+ * Macro for forcing a context switch.
+ *
+ * \page taskYIELD taskYIELD
+ * \ingroup SchedulerControl
+ */
+#define taskYIELD() portYIELD()
+
+/**
+ * task. h
+ *
+ * Macro to mark the start of a critical code region. Preemptive context
+ * switches cannot occur when in a critical region.
+ *
+ * NOTE: This may alter the stack (depending on the portable implementation)
+ * so must be used with care!
+ *
+ * \page taskENTER_CRITICAL taskENTER_CRITICAL
+ * \ingroup SchedulerControl
+ */
+#define taskENTER_CRITICAL() portENTER_CRITICAL()
+
+/**
+ * task. h
+ *
+ * Macro to mark the end of a critical code region. Preemptive context
+ * switches cannot occur when in a critical region.
+ *
+ * NOTE: This may alter the stack (depending on the portable implementation)
+ * so must be used with care!
+ *
+ * \page taskEXIT_CRITICAL taskEXIT_CRITICAL
+ * \ingroup SchedulerControl
+ */
+#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
+
+/**
+ * task. h
+ *
+ * Macro to disable all maskable interrupts.
+ *
+ * \page taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS
+ * \ingroup SchedulerControl
+ */
+#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
+
+/**
+ * task. h
+ *
+ * Macro to enable microcontroller interrupts.
+ *
+ * \page taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS
+ * \ingroup SchedulerControl
+ */
+#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
+
+/* Definitions returned by xTaskGetSchedulerState(). */
+#define taskSCHEDULER_NOT_STARTED 0
+#define taskSCHEDULER_RUNNING 1
+#define taskSCHEDULER_SUSPENDED 2
+
+/*-----------------------------------------------------------
+ * TASK CREATION API
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ *<pre>
+ portBASE_TYPE xTaskCreate(
+ pdTASK_CODE pvTaskCode,
+ const char * const pcName,
+ unsigned short usStackDepth,
+ void *pvParameters,
+ unsigned portBASE_TYPE uxPriority,
+ xTaskHandle *pvCreatedTask
+ );</pre>
+ *
+ * Create a new task and add it to the list of tasks that are ready to run.
+ *
+ * xTaskCreate() can only be used to create a task that has unrestricted
+ * access to the entire microcontroller memory map. Systems that include MPU
+ * support can alternatively create an MPU constrained task using
+ * xTaskCreateRestricted().
+ *
+ * @param pvTaskCode Pointer to the task entry function. Tasks
+ * must be implemented to never return (i.e. continuous loop).
+ *
+ * @param pcName A descriptive name for the task. This is mainly used to
+ * facilitate debugging. Max length defined by tskMAX_TASK_NAME_LEN - default
+ * is 16.
+ *
+ * @param usStackDepth The size of the task stack specified as the number of
+ * variables the stack can hold - not the number of bytes. For example, if
+ * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes
+ * will be allocated for stack storage.
+ *
+ * @param pvParameters Pointer that will be used as the parameter for the task
+ * being created.
+ *
+ * @param uxPriority The priority at which the task should run. Systems that
+ * include MPU support can optionally create tasks in a privileged (system)
+ * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For
+ * example, to create a privileged task at priority 2 the uxPriority parameter
+ * should be set to ( 2 | portPRIVILEGE_BIT ).
+ *
+ * @param pvCreatedTask Used to pass back a handle by which the created task
+ * can be referenced.
+ *
+ * @return pdPASS if the task was successfully created and added to a ready
+ * list, otherwise an error code defined in the file errors. h
+ *
+ * Example usage:
+ <pre>
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+ }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ static unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+
+ // Create the task, storing the handle. Note that the passed parameter ucParameterToPass
+ // must exist for the lifetime of the task, so in this case is declared static. If it was just an
+ // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
+ // the new task attempts to access it.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
+
+ // Use the handle to delete the task.
+ vTaskDelete( xHandle );
+ }
+ </pre>
+ * \defgroup xTaskCreate xTaskCreate
+ * \ingroup Tasks
+ */
+#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )
+
+/**
+ * task. h
+ *<pre>
+ portBASE_TYPE xTaskCreateRestricted( xTaskParameters *pxTaskDefinition, xTaskHandle *pxCreatedTask );</pre>
+ *
+ * xTaskCreateRestricted() should only be used in systems that include an MPU
+ * implementation.
+ *
+ * Create a new task and add it to the list of tasks that are ready to run.
+ * The function parameters define the memory regions and associated access
+ * permissions allocated to the task.
+ *
+ * @param pxTaskDefinition Pointer to a structure that contains a member
+ * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
+ * documentation) plus an optional stack buffer and the memory region
+ * definitions.
+ *
+ * @param pxCreatedTask Used to pass back a handle by which the created task
+ * can be referenced.
+ *
+ * @return pdPASS if the task was successfully created and added to a ready
+ * list, otherwise an error code defined in the file errors. h
+ *
+ * Example usage:
+ <pre>
+// Create an xTaskParameters structure that defines the task to be created.
+static const xTaskParameters xCheckTaskParameters =
+{
+ vATask, // pvTaskCode - the function that implements the task.
+ "ATask", // pcName - just a text name for the task to assist debugging.
+ 100, // usStackDepth - the stack size DEFINED IN WORDS.
+ NULL, // pvParameters - passed into the task function as the function parameters.
+ ( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
+ cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
+
+ // xRegions - Allocate up to three separate memory regions for access by
+ // the task, with appropriate access permissions. Different processors have
+ // different memory alignment requirements - refer to the FreeRTOS documentation
+ // for full information.
+ {
+ // Base address Length Parameters
+ { cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
+ { cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
+ { cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
+ }
+};
+
+int main( void )
+{
+xTaskHandle xHandle;
+
+ // Create a task from the const structure defined above. The task handle
+ // is requested (the second parameter is not NULL) but in this case just for
+ // demonstration purposes as its not actually used.
+ xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
+
+ // Start the scheduler.
+ vTaskStartScheduler();
+
+ // Will only get here if there was insufficient memory to create the idle
+ // task.
+ for( ;; );
+}
+ </pre>
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted
+ * \ingroup Tasks
+ */
+#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) )
+
+/**
+ * task. h
+ *<pre>
+ void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions );</pre>
+ *
+ * Memory regions are assigned to a restricted task when the task is created by
+ * a call to xTaskCreateRestricted(). These regions can be redefined using
+ * vTaskAllocateMPURegions().
+ *
+ * @param xTask The handle of the task being updated.
+ *
+ * @param xRegions A pointer to an xMemoryRegion structure that contains the
+ * new memory region definitions.
+ *
+ * Example usage:
+ <pre>
+// Define an array of xMemoryRegion structures that configures an MPU region
+// allowing read/write access for 1024 bytes starting at the beginning of the
+// ucOneKByte array. The other two of the maximum 3 definable regions are
+// unused so set to zero.
+static const xMemoryRegion xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =
+{
+ // Base address Length Parameters
+ { ucOneKByte, 1024, portMPU_REGION_READ_WRITE },
+ { 0, 0, 0 },
+ { 0, 0, 0 }
+};
+
+void vATask( void *pvParameters )
+{
+ // This task was created such that it has access to certain regions of
+ // memory as defined by the MPU configuration. At some point it is
+ // desired that these MPU regions are replaced with that defined in the
+ // xAltRegions const struct above. Use a call to vTaskAllocateMPURegions()
+ // for this purpose. NULL is used as the task handle to indicate that this
+ // function should modify the MPU regions of the calling task.
+ vTaskAllocateMPURegions( NULL, xAltRegions );
+
+ // Now the task can continue its function, but from this point on can only
+ // access its stack and the ucOneKByte array (unless any other statically
+ // defined or shared regions have been declared elsewhere).
+}
+ </pre>
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted
+ * \ingroup Tasks
+ */
+void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>void vTaskDelete( xTaskHandle pxTask );</pre>
+ *
+ * INCLUDE_vTaskDelete must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Remove a task from the RTOS real time kernels management. The task being
+ * deleted will be removed from all ready, blocked, suspended and event lists.
+ *
+ * NOTE: The idle task is responsible for freeing the kernel allocated
+ * memory from tasks that have been deleted. It is therefore important that
+ * the idle task is not starved of microcontroller processing time if your
+ * application makes any calls to vTaskDelete (). Memory allocated by the
+ * task code is not automatically freed, and should be freed before the task
+ * is deleted.
+ *
+ * See the demo application file death.c for sample code that utilises
+ * vTaskDelete ().
+ *
+ * @param pxTask The handle of the task to be deleted. Passing NULL will
+ * cause the calling task to be deleted.
+ *
+ * Example usage:
+ <pre>
+ void vOtherFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create the task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // Use the handle to delete the task.
+ vTaskDelete( xHandle );
+ }
+ </pre>
+ * \defgroup vTaskDelete vTaskDelete
+ * \ingroup Tasks
+ */
+void vTaskDelete( xTaskHandle pxTaskToDelete ) PRIVILEGED_FUNCTION;
+
+/*-----------------------------------------------------------
+ * TASK CONTROL API
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <pre>void vTaskDelay( portTickType xTicksToDelay );</pre>
+ *
+ * Delay a task for a given number of ticks. The actual time that the
+ * task remains blocked depends on the tick rate. The constant
+ * portTICK_RATE_MS can be used to calculate real time from the tick
+ * rate - with the resolution of one tick period.
+ *
+ * INCLUDE_vTaskDelay must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ *
+ * vTaskDelay() specifies a time at which the task wishes to unblock relative to
+ * the time at which vTaskDelay() is called. For example, specifying a block
+ * period of 100 ticks will cause the task to unblock 100 ticks after
+ * vTaskDelay() is called. vTaskDelay() does not therefore provide a good method
+ * of controlling the frequency of a cyclical task as the path taken through the
+ * code, as well as other task and interrupt activity, will effect the frequency
+ * at which vTaskDelay() gets called and therefore the time at which the task
+ * next executes. See vTaskDelayUntil() for an alternative API function designed
+ * to facilitate fixed frequency execution. It does this by specifying an
+ * absolute time (rather than a relative time) at which the calling task should
+ * unblock.
+ *
+ * @param xTicksToDelay The amount of time, in tick periods, that
+ * the calling task should block.
+ *
+ * Example usage:
+
+ void vTaskFunction( void * pvParameters )
+ {
+ void vTaskFunction( void * pvParameters )
+ {
+ // Block for 500ms.
+ const portTickType xDelay = 500 / portTICK_RATE_MS;
+
+ for( ;; )
+ {
+ // Simply toggle the LED every 500ms, blocking between each toggle.
+ vToggleLED();
+ vTaskDelay( xDelay );
+ }
+ }
+
+ * \defgroup vTaskDelay vTaskDelay
+ * \ingroup TaskCtrl
+ */
+void vTaskDelay( portTickType xTicksToDelay ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );</pre>
+ *
+ * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Delay a task until a specified time. This function can be used by cyclical
+ * tasks to ensure a constant execution frequency.
+ *
+ * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will
+ * cause a task to block for the specified number of ticks from the time vTaskDelay () is
+ * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed
+ * execution frequency as the time between a task starting to execute and that task
+ * calling vTaskDelay () may not be fixed [the task may take a different path though the
+ * code between calls, or may get interrupted or preempted a different number of times
+ * each time it executes].
+ *
+ * Whereas vTaskDelay () specifies a wake time relative to the time at which the function
+ * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to
+ * unblock.
+ *
+ * The constant portTICK_RATE_MS can be used to calculate real time from the tick
+ * rate - with the resolution of one tick period.
+ *
+ * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the
+ * task was last unblocked. The variable must be initialised with the current time
+ * prior to its first use (see the example below). Following this the variable is
+ * automatically updated within vTaskDelayUntil ().
+ *
+ * @param xTimeIncrement The cycle time period. The task will be unblocked at
+ * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the
+ * same xTimeIncrement parameter value will cause the task to execute with
+ * a fixed interface period.
+ *
+ * Example usage:
+ <pre>
+ // Perform an action every 10 ticks.
+ void vTaskFunction( void * pvParameters )
+ {
+ portTickType xLastWakeTime;
+ const portTickType xFrequency = 10;
+
+ // Initialise the xLastWakeTime variable with the current time.
+ xLastWakeTime = xTaskGetTickCount ();
+ for( ;; )
+ {
+ // Wait for the next cycle.
+ vTaskDelayUntil( &xLastWakeTime, xFrequency );
+
+ // Perform action here.
+ }
+ }
+ </pre>
+ * \defgroup vTaskDelayUntil vTaskDelayUntil
+ * \ingroup TaskCtrl
+ */
+void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );</pre>
+ *
+ * INCLUDE_xTaskPriorityGet must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Obtain the priority of any task.
+ *
+ * @param pxTask Handle of the task to be queried. Passing a NULL
+ * handle results in the priority of the calling task being returned.
+ *
+ * @return The priority of pxTask.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to obtain the priority of the created task.
+ // It was created with tskIDLE_PRIORITY, but may have changed
+ // it itself.
+ if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
+ {
+ // The task has changed it's priority.
+ }
+
+ // ...
+
+ // Is our priority higher than the created task?
+ if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
+ {
+ // Our priority (obtained using NULL handle) is higher.
+ }
+ }
+ </pre>
+ * \defgroup uxTaskPriorityGet uxTaskPriorityGet
+ * \ingroup TaskCtrl
+ */
+unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );</pre>
+ *
+ * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Set the priority of any task.
+ *
+ * A context switch will occur before the function returns if the priority
+ * being set is higher than the currently executing task.
+ *
+ * @param pxTask Handle to the task for which the priority is being set.
+ * Passing a NULL handle results in the priority of the calling task being set.
+ *
+ * @param uxNewPriority The priority to which the task will be set.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to raise the priority of the created task.
+ vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
+
+ // ...
+
+ // Use a NULL handle to raise our priority to the same value.
+ vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
+ }
+ </pre>
+ * \defgroup vTaskPrioritySet vTaskPrioritySet
+ * \ingroup TaskCtrl
+ */
+void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>void vTaskSuspend( xTaskHandle pxTaskToSuspend );</pre>
+ *
+ * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Suspend any task. When suspended a task will never get any microcontroller
+ * processing time, no matter what its priority.
+ *
+ * Calls to vTaskSuspend are not accumulative -
+ * i.e. calling vTaskSuspend () twice on the same task still only requires one
+ * call to vTaskResume () to ready the suspended task.
+ *
+ * @param pxTaskToSuspend Handle to the task being suspended. Passing a NULL
+ * handle will cause the calling task to be suspended.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to suspend the created task.
+ vTaskSuspend( xHandle );
+
+ // ...
+
+ // The created task will not run during this period, unless
+ // another task calls vTaskResume( xHandle ).
+
+ //...
+
+
+ // Suspend ourselves.
+ vTaskSuspend( NULL );
+
+ // We cannot get here unless another task calls vTaskResume
+ // with our handle as the parameter.
+ }
+ </pre>
+ * \defgroup vTaskSuspend vTaskSuspend
+ * \ingroup TaskCtrl
+ */
+void vTaskSuspend( xTaskHandle pxTaskToSuspend ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>void vTaskResume( xTaskHandle pxTaskToResume );</pre>
+ *
+ * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Resumes a suspended task.
+ *
+ * A task that has been suspended by one of more calls to vTaskSuspend ()
+ * will be made available for running again by a single call to
+ * vTaskResume ().
+ *
+ * @param pxTaskToResume Handle to the task being readied.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to suspend the created task.
+ vTaskSuspend( xHandle );
+
+ // ...
+
+ // The created task will not run during this period, unless
+ // another task calls vTaskResume( xHandle ).
+
+ //...
+
+
+ // Resume the suspended task ourselves.
+ vTaskResume( xHandle );
+
+ // The created task will once again get microcontroller processing
+ // time in accordance with it priority within the system.
+ }
+ </pre>
+ * \defgroup vTaskResume vTaskResume
+ * \ingroup TaskCtrl
+ */
+void vTaskResume( xTaskHandle pxTaskToResume ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>void xTaskResumeFromISR( xTaskHandle pxTaskToResume );</pre>
+ *
+ * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be
+ * available. See the configuration section for more information.
+ *
+ * An implementation of vTaskResume() that can be called from within an ISR.
+ *
+ * A task that has been suspended by one of more calls to vTaskSuspend ()
+ * will be made available for running again by a single call to
+ * xTaskResumeFromISR ().
+ *
+ * @param pxTaskToResume Handle to the task being readied.
+ *
+ * \defgroup vTaskResumeFromISR vTaskResumeFromISR
+ * \ingroup TaskCtrl
+ */
+portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume ) PRIVILEGED_FUNCTION;
+
+/*-----------------------------------------------------------
+ * SCHEDULER CONTROL
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <pre>void vTaskStartScheduler( void );</pre>
+ *
+ * Starts the real time kernel tick processing. After calling the kernel
+ * has control over which tasks are executed and when. This function
+ * does not return until an executing task calls vTaskEndScheduler ().
+ *
+ * At least one task should be created via a call to xTaskCreate ()
+ * before calling vTaskStartScheduler (). The idle task is created
+ * automatically when the first application task is created.
+ *
+ * See the demo application file main.c for an example of creating
+ * tasks and starting the kernel.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ // Create at least one task before starting the kernel.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+ // Start the real time kernel with preemption.
+ vTaskStartScheduler ();
+
+ // Will not get here unless a task calls vTaskEndScheduler ()
+ }
+ </pre>
+ *
+ * \defgroup vTaskStartScheduler vTaskStartScheduler
+ * \ingroup SchedulerControl
+ */
+void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>void vTaskEndScheduler( void );</pre>
+ *
+ * Stops the real time kernel tick. All created tasks will be automatically
+ * deleted and multitasking (either preemptive or cooperative) will
+ * stop. Execution then resumes from the point where vTaskStartScheduler ()
+ * was called, as if vTaskStartScheduler () had just returned.
+ *
+ * See the demo application file main. c in the demo/PC directory for an
+ * example that uses vTaskEndScheduler ().
+ *
+ * vTaskEndScheduler () requires an exit function to be defined within the
+ * portable layer (see vPortEndScheduler () in port. c for the PC port). This
+ * performs hardware specific operations such as stopping the kernel tick.
+ *
+ * vTaskEndScheduler () will cause all of the resources allocated by the
+ * kernel to be freed - but will not free resources allocated by application
+ * tasks.
+ *
+ * Example usage:
+ <pre>
+ void vTaskCode( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // At some point we want to end the real time kernel processing
+ // so call ...
+ vTaskEndScheduler ();
+ }
+ }
+
+ void vAFunction( void )
+ {
+ // Create at least one task before starting the kernel.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+ // Start the real time kernel with preemption.
+ vTaskStartScheduler ();
+
+ // Will only get here when the vTaskCode () task has called
+ // vTaskEndScheduler (). When we get here we are back to single task
+ // execution.
+ }
+ </pre>
+ *
+ * \defgroup vTaskEndScheduler vTaskEndScheduler
+ * \ingroup SchedulerControl
+ */
+void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>void vTaskSuspendAll( void );</pre>
+ *
+ * Suspends all real time kernel activity while keeping interrupts (including the
+ * kernel tick) enabled.
+ *
+ * After calling vTaskSuspendAll () the calling task will continue to execute
+ * without risk of being swapped out until a call to xTaskResumeAll () has been
+ * made.
+ *
+ * API functions that have the potential to cause a context switch (for example,
+ * vTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler
+ * is suspended.
+ *
+ * Example usage:
+ <pre>
+ void vTask1( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // ...
+
+ // At some point the task wants to perform a long operation during
+ // which it does not want to get swapped out. It cannot use
+ // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+ // operation may cause interrupts to be missed - including the
+ // ticks.
+
+ // Prevent the real time kernel swapping out the task.
+ vTaskSuspendAll ();
+
+ // Perform the operation here. There is no need to use critical
+ // sections as we have all the microcontroller processing time.
+ // During this time interrupts will still operate and the kernel
+ // tick count will be maintained.
+
+ // ...
+
+ // The operation is complete. Restart the kernel.
+ xTaskResumeAll ();
+ }
+ }
+ </pre>
+ * \defgroup vTaskSuspendAll vTaskSuspendAll
+ * \ingroup SchedulerControl
+ */
+void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>char xTaskResumeAll( void );</pre>
+ *
+ * Resumes real time kernel activity following a call to vTaskSuspendAll ().
+ * After a call to vTaskSuspendAll () the kernel will take control of which
+ * task is executing at any time.
+ *
+ * @return If resuming the scheduler caused a context switch then pdTRUE is
+ * returned, otherwise pdFALSE is returned.
+ *
+ * Example usage:
+ <pre>
+ void vTask1( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // ...
+
+ // At some point the task wants to perform a long operation during
+ // which it does not want to get swapped out. It cannot use
+ // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+ // operation may cause interrupts to be missed - including the
+ // ticks.
+
+ // Prevent the real time kernel swapping out the task.
+ vTaskSuspendAll ();
+
+ // Perform the operation here. There is no need to use critical
+ // sections as we have all the microcontroller processing time.
+ // During this time interrupts will still operate and the real
+ // time kernel tick count will be maintained.
+
+ // ...
+
+ // The operation is complete. Restart the kernel. We want to force
+ // a context switch - but there is no point if resuming the scheduler
+ // caused a context switch already.
+ if( !xTaskResumeAll () )
+ {
+ taskYIELD ();
+ }
+ }
+ }
+ </pre>
+ * \defgroup xTaskResumeAll xTaskResumeAll
+ * \ingroup SchedulerControl
+ */
+signed portBASE_TYPE xTaskResumeAll( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <pre>signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask );</pre>
+ *
+ * Utility task that simply returns pdTRUE if the task referenced by xTask is
+ * currently in the Suspended state, or pdFALSE if the task referenced by xTask
+ * is in any other state.
+ *
+ */
+signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
+
+/*-----------------------------------------------------------
+ * TASK UTILITIES
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <PRE>portTickType xTaskGetTickCount( void );</PRE>
+ *
+ * @return The count of ticks since vTaskStartScheduler was called.
+ *
+ * \page xTaskGetTickCount xTaskGetTickCount
+ * \ingroup TaskUtils
+ */
+portTickType xTaskGetTickCount( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <PRE>portTickType xTaskGetTickCountFromISR( void );</PRE>
+ *
+ * @return The count of ticks since vTaskStartScheduler was called.
+ *
+ * This is a version of xTaskGetTickCount() that is safe to be called from an
+ * ISR - provided that portTickType is the natural word size of the
+ * microcontroller being used or interrupt nesting is either not supported or
+ * not being used.
+ *
+ * \page xTaskGetTickCount xTaskGetTickCount
+ * \ingroup TaskUtils
+ */
+portTickType xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <PRE>unsigned short uxTaskGetNumberOfTasks( void );</PRE>
+ *
+ * @return The number of tasks that the real time kernel is currently managing.
+ * This includes all ready, blocked and suspended tasks. A task that
+ * has been deleted but not yet freed by the idle task will also be
+ * included in the count.
+ *
+ * \page uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks
+ * \ingroup TaskUtils
+ */
+unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <PRE>void vTaskList( char *pcWriteBuffer );</PRE>
+ *
+ * configUSE_TRACE_FACILITY must be defined as 1 for this function to be
+ * available. See the configuration section for more information.
+ *
+ * NOTE: This function will disable interrupts for its duration. It is
+ * not intended for normal application runtime use but as a debug aid.
+ *
+ * Lists all the current tasks, along with their current state and stack
+ * usage high water mark.
+ *
+ * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or
+ * suspended ('S').
+ *
+ * @param pcWriteBuffer A buffer into which the above mentioned details
+ * will be written, in ascii form. This buffer is assumed to be large
+ * enough to contain the generated report. Approximately 40 bytes per
+ * task should be sufficient.
+ *
+ * \page vTaskList vTaskList
+ * \ingroup TaskUtils
+ */
+void vTaskList( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <PRE>void vTaskGetRunTimeStats( char *pcWriteBuffer );</PRE>
+ *
+ * configGENERATE_RUN_TIME_STATS must be defined as 1 for this function
+ * to be available. The application must also then provide definitions
+ * for portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and
+ * portGET_RUN_TIME_COUNTER_VALUE to configure a peripheral timer/counter
+ * and return the timers current count value respectively. The counter
+ * should be at least 10 times the frequency of the tick count.
+ *
+ * NOTE: This function will disable interrupts for its duration. It is
+ * not intended for normal application runtime use but as a debug aid.
+ *
+ * Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total
+ * accumulated execution time being stored for each task. The resolution
+ * of the accumulated time value depends on the frequency of the timer
+ * configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro.
+ * Calling vTaskGetRunTimeStats() writes the total execution time of each
+ * task into a buffer, both as an absolute count value and as a percentage
+ * of the total system execution time.
+ *
+ * @param pcWriteBuffer A buffer into which the execution times will be
+ * written, in ascii form. This buffer is assumed to be large enough to
+ * contain the generated report. Approximately 40 bytes per task should
+ * be sufficient.
+ *
+ * \page vTaskGetRunTimeStats vTaskGetRunTimeStats
+ * \ingroup TaskUtils
+ */
+void vTaskGetRunTimeStats( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <PRE>void vTaskStartTrace( char * pcBuffer, unsigned portBASE_TYPE uxBufferSize );</PRE>
+ *
+ * Starts a real time kernel activity trace. The trace logs the identity of
+ * which task is running when.
+ *
+ * The trace file is stored in binary format. A separate DOS utility called
+ * convtrce.exe is used to convert this into a tab delimited text file which
+ * can be viewed and plotted in a spread sheet.
+ *
+ * @param pcBuffer The buffer into which the trace will be written.
+ *
+ * @param ulBufferSize The size of pcBuffer in bytes. The trace will continue
+ * until either the buffer in full, or ulTaskEndTrace () is called.
+ *
+ * \page vTaskStartTrace vTaskStartTrace
+ * \ingroup TaskUtils
+ */
+void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * <PRE>unsigned long ulTaskEndTrace( void );</PRE>
+ *
+ * Stops a kernel activity trace. See vTaskStartTrace ().
+ *
+ * @return The number of bytes that have been written into the trace buffer.
+ *
+ * \page usTaskEndTrace usTaskEndTrace
+ * \ingroup TaskUtils
+ */
+unsigned long ulTaskEndTrace( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task.h
+ * <PRE>unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask );</PRE>
+ *
+ * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for
+ * this function to be available.
+ *
+ * Returns the high water mark of the stack associated with xTask. That is,
+ * the minimum free stack space there has been (in words, so on a 32 bit machine
+ * a value of 1 means 4 bytes) since the task started. The smaller the returned
+ * number the closer the task has come to overflowing its stack.
+ *
+ * @param xTask Handle of the task associated with the stack to be checked.
+ * Set xTask to NULL to check the stack of the calling task.
+ *
+ * @return The smallest amount of free stack space there has been (in bytes)
+ * since the task referenced by xTask was created.
+ */
+unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
+
+/* When using trace macros it is sometimes necessary to include tasks.h before
+FreeRTOS.h. When this is done pdTASK_HOOK_CODE will not yet have been defined,
+so the following two prototypes will cause a compilation error. This can be
+fixed by simply guarding against the inclusion of these two prototypes unless
+they are explicitly required by the configUSE_APPLICATION_TASK_TAG configuration
+constant. */
+#ifdef configUSE_APPLICATION_TASK_TAG
+ #if configUSE_APPLICATION_TASK_TAG == 1
+ /**
+ * task.h
+ * <pre>void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );</pre>
+ *
+ * Sets pxHookFunction to be the task hook function used by the task xTask.
+ * Passing xTask as NULL has the effect of setting the calling tasks hook
+ * function.
+ */
+ void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction ) PRIVILEGED_FUNCTION;
+
+ /**
+ * task.h
+ * <pre>void xTaskGetApplicationTaskTag( xTaskHandle xTask );</pre>
+ *
+ * Returns the pxHookFunction value assigned to the task xTask.
+ */
+ pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
+ #endif /* configUSE_APPLICATION_TASK_TAG ==1 */
+#endif /* ifdef configUSE_APPLICATION_TASK_TAG */
+
+/**
+ * task.h
+ * <pre>portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );</pre>
+ *
+ * Calls the hook function associated with xTask. Passing xTask as NULL has
+ * the effect of calling the Running tasks (the calling task) hook function.
+ *
+ * pvParameter is passed to the hook function for the task to interpret as it
+ * wants.
+ */
+portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter ) PRIVILEGED_FUNCTION;
+
+
+/*-----------------------------------------------------------
+ * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
+ *----------------------------------------------------------*/
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
+ * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
+ * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * Called from the real time kernel tick (either preemptive or cooperative),
+ * this increments the tick count and checks if any tasks that are blocked
+ * for a finite period required removing from a blocked list and placing on
+ * a ready list.
+ */
+void vTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
+ *
+ * Removes the calling task from the ready list and places it both
+ * on the list of tasks waiting for a particular event, and the
+ * list of delayed tasks. The task will be removed from both lists
+ * and replaced on the ready list should either the event occur (and
+ * there be no higher priority tasks waiting on the same event) or
+ * the delay period expires.
+ *
+ * @param pxEventList The list containing tasks that are blocked waiting
+ * for the event to occur.
+ *
+ * @param xTicksToWait The maximum amount of time that the task should wait
+ * for the event to occur. This is specified in kernel ticks,the constant
+ * portTICK_RATE_MS can be used to convert kernel ticks into a real time
+ * period.
+ */
+void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
+ *
+ * This function performs nearly the same function as vTaskPlaceOnEventList().
+ * The difference being that this function does not permit tasks to block
+ * indefinitely, whereas vTaskPlaceOnEventList() does.
+ *
+ * @return pdTRUE if the task being removed has a higher priority than the task
+ * making the call, otherwise pdFALSE.
+ */
+void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
+ *
+ * Removes a task from both the specified event list and the list of blocked
+ * tasks, and places it on a ready queue.
+ *
+ * xTaskRemoveFromEventList () will be called if either an event occurs to
+ * unblock a task, or the block timeout period expires.
+ *
+ * @return pdTRUE if the task being removed has a higher priority than the task
+ * making the call, otherwise pdFALSE.
+ */
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * INCLUDE_vTaskCleanUpResources and INCLUDE_vTaskSuspend must be defined as 1
+ * for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Empties the ready and delayed queues of task control blocks, freeing the
+ * memory allocated for the task control block and task stacks as it goes.
+ */
+void vTaskCleanUpResources( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
+ * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
+ * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * Sets the pointer to the current TCB to the TCB of the highest priority task
+ * that is ready to run.
+ */
+void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Return the handle of the calling task.
+ */
+xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Capture the current time status for future reference.
+ */
+void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) PRIVILEGED_FUNCTION;
+
+/*
+ * Compare the time status now with that previously captured to see if the
+ * timeout has expired.
+ */
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ) PRIVILEGED_FUNCTION;
+
+/*
+ * Shortcut used by the queue implementation to prevent unnecessary call to
+ * taskYIELD();
+ */
+void vTaskMissedYield( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Returns the scheduler state as taskSCHEDULER_RUNNING,
+ * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED.
+ */
+portBASE_TYPE xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Raises the priority of the mutex holder to that of the calling task should
+ * the mutex holder have a priority less than the calling task.
+ */
+void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUNCTION;
+
+/*
+ * Set the priority of a task back to its proper priority in the case that it
+ * inherited a higher priority while it was holding a semaphore.
+ */
+void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUNCTION;
+
+/*
+ * Generic version of the task creation function which is in turn called by the
+ * xTaskCreate() and xTaskCreateRestricted() macros.
+ */
+signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) PRIVILEGED_FUNCTION;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* TASK_H */
+
+
+
diff --git a/libraries/FreeRTOS/utility/tasks.c b/libraries/FreeRTOS/utility/tasks.c
new file mode 100755
index 0000000..d48dd4d
--- /dev/null
+++ b/libraries/FreeRTOS/utility/tasks.c
@@ -0,0 +1,2522 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
+all the API functions to use the MPU wrappers. That should only be done when
+task.h is included from an application file. */
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+#include "StackMacros.h"
+
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+/*
+ * Macro to define the amount of stack available to the idle task.
+ */
+#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
+
+/*
+ * Task control block. A task control block (TCB) is allocated to each task,
+ * and stores the context of the task.
+ */
+typedef struct tskTaskControlBlock
+{
+ volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
+
+ #if ( portUSING_MPU_WRAPPERS == 1 )
+ xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
+ #endif
+
+ xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
+ xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
+ unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
+ portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
+ signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
+
+ #if ( portSTACK_GROWTH > 0 )
+ portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
+ #endif
+
+ #if ( portCRITICAL_NESTING_IN_TCB == 1 )
+ unsigned portBASE_TYPE uxCriticalNesting;
+ #endif
+
+ #if ( configUSE_TRACE_FACILITY == 1 )
+ unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
+ #endif
+
+ #if ( configUSE_MUTEXES == 1 )
+ unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
+ #endif
+
+ #if ( configUSE_APPLICATION_TASK_TAG == 1 )
+ pdTASK_HOOK_CODE pxTaskTag;
+ #endif
+
+ #if ( configGENERATE_RUN_TIME_STATS == 1 )
+ unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
+ #endif
+
+} tskTCB;
+
+
+/*
+ * Some kernel aware debuggers require data to be viewed to be global, rather
+ * than file scope.
+ */
+#ifdef portREMOVE_STATIC_QUALIFIER
+ #define static
+#endif
+
+/*lint -e956 */
+PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
+
+/* Lists for ready and blocked tasks. --------------------*/
+
+PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
+PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
+PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
+PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
+PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
+PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */
+
+#if ( INCLUDE_vTaskDelete == 1 )
+
+ PRIVILEGED_DATA static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
+ PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
+
+#endif
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
+
+#endif
+
+/* File private variables. --------------------------------*/
+PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
+PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0;
+PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
+PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
+PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
+PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
+PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
+PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
+PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
+PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0;
+PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY;
+
+#if ( configGENERATE_RUN_TIME_STATS == 1 )
+
+ PRIVILEGED_DATA static char pcStatsString[ 50 ] ;
+ PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
+ static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime ) PRIVILEGED_FUNCTION;
+
+#endif
+
+/* Debugging and trace facilities private variables and macros. ------------*/
+
+/*
+ * The value used to fill the stack of a task when the task is created. This
+ * is used purely for checking the high water mark for tasks.
+ */
+#define tskSTACK_FILL_BYTE ( 0xa5U )
+
+/*
+ * Macros used by vListTask to indicate which state a task is in.
+ */
+#define tskBLOCKED_CHAR ( ( signed char ) 'B' )
+#define tskREADY_CHAR ( ( signed char ) 'R' )
+#define tskDELETED_CHAR ( ( signed char ) 'D' )
+#define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
+
+/*
+ * Macros and private variables used by the trace facility.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ #define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )
+ PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;
+ PRIVILEGED_DATA static signed char *pcTraceBufferStart;
+ PRIVILEGED_DATA static signed char *pcTraceBufferEnd;
+ PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;
+ static unsigned portBASE_TYPE uxPreviousTask = 255U;
+ PRIVILEGED_DATA static char pcStatusString[ 50 ];
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Macro that writes a trace of scheduler activity to a buffer. This trace
+ * shows which task is running when and is very useful as a debugging tool.
+ * As this macro is called each context switch it is a good idea to undefine
+ * it if not using the facility.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ #define vWriteTraceToBuffer() \
+ { \
+ if( xTracing ) \
+ { \
+ if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
+ { \
+ if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
+ { \
+ uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
+ *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \
+ pcTraceBuffer += sizeof( unsigned long ); \
+ *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \
+ pcTraceBuffer += sizeof( unsigned long ); \
+ } \
+ else \
+ { \
+ xTracing = pdFALSE; \
+ } \
+ } \
+ } \
+ }
+
+#else
+
+ #define vWriteTraceToBuffer()
+
+#endif
+/*-----------------------------------------------------------*/
+
+/*
+ * Place the task represented by pxTCB into the appropriate ready queue for
+ * the task. It is inserted at the end of the list. One quirk of this is
+ * that if the task being inserted is at the same priority as the currently
+ * executing task, then it will only be rescheduled after the currently
+ * executing task has been rescheduled.
+ */
+#define prvAddTaskToReadyQueue( pxTCB ) \
+ if( ( pxTCB )->uxPriority > uxTopReadyPriority ) \
+ { \
+ uxTopReadyPriority = ( pxTCB )->uxPriority; \
+ } \
+ vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
+/*-----------------------------------------------------------*/
+
+/*
+ * Macro that looks at the list of tasks that are currently delayed to see if
+ * any require waking.
+ *
+ * Tasks are stored in the queue in the order of their wake time - meaning
+ * once one tasks has been found whose timer has not expired we need not look
+ * any further down the list.
+ */
+#define prvCheckDelayedTasks() \
+{ \
+portTickType xItemValue; \
+ \
+ /* Is the tick count greater than or equal to the wake time of the first \
+ task referenced from the delayed tasks list? */ \
+ if( xTickCount >= xNextTaskUnblockTime ) \
+ { \
+ for( ;; ) \
+ { \
+ if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \
+ { \
+ /* The delayed list is empty. Set xNextTaskUnblockTime to the \
+ maximum possible value so it is extremely unlikely that the \
+ if( xTickCount >= xNextTaskUnblockTime ) test will pass next \
+ time through. */ \
+ xNextTaskUnblockTime = portMAX_DELAY; \
+ break; \
+ } \
+ else \
+ { \
+ /* The delayed list is not empty, get the value of the item at \
+ the head of the delayed list. This is the time at which the \
+ task at the head of the delayed list should be removed from \
+ the Blocked state. */ \
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \
+ xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \
+ \
+ if( xTickCount < xItemValue ) \
+ { \
+ /* It is not time to unblock this item yet, but the item \
+ value is the time at which the task at the head of the \
+ blocked list should be removed from the Blocked state - \
+ so record the item value in xNextTaskUnblockTime. */ \
+ xNextTaskUnblockTime = xItemValue; \
+ break; \
+ } \
+ \
+ /* It is time to remove the item from the Blocked state. */ \
+ vListRemove( &( pxTCB->xGenericListItem ) ); \
+ \
+ /* Is the task waiting on an event also? */ \
+ if( pxTCB->xEventListItem.pvContainer ) \
+ { \
+ vListRemove( &( pxTCB->xEventListItem ) ); \
+ } \
+ prvAddTaskToReadyQueue( pxTCB ); \
+ } \
+ } \
+ } \
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Several functions take an xTaskHandle parameter that can optionally be NULL,
+ * where NULL is used to indicate that the handle of the currently executing
+ * task should be used in place of the parameter. This macro simply checks to
+ * see if the parameter is NULL and returns a pointer to the appropriate TCB.
+ */
+#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) )
+
+/* Callback function prototypes. --------------------------*/
+extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName );
+extern void vApplicationTickHook( void );
+
+/* File private functions. --------------------------------*/
+
+/*
+ * Utility to ready a TCB for a given task. Mainly just copies the parameters
+ * into the TCB structure.
+ */
+static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
+
+/*
+ * Utility to ready all the lists used by the scheduler. This is called
+ * automatically upon the creation of the first task.
+ */
+static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * The idle task, which as all tasks is implemented as a never ending loop.
+ * The idle task is automatically created and added to the ready lists upon
+ * creation of the first user task.
+ *
+ * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
+ * language extensions. The equivalent prototype for this function is:
+ *
+ * void prvIdleTask( void *pvParameters );
+ *
+ */
+static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
+
+/*
+ * Utility to free all memory allocated by the scheduler to hold a TCB,
+ * including the stack pointed to by the TCB.
+ *
+ * This does not free memory allocated by the task itself (i.e. memory
+ * allocated by calls to pvPortMalloc from within the tasks application code).
+ */
+#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
+
+ static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
+
+#endif
+
+/*
+ * Used only by the idle task. This checks to see if anything has been placed
+ * in the list of tasks waiting to be deleted. If so the task is cleaned up
+ * and its TCB deleted.
+ */
+static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * The currently executing task is entering the Blocked state. Add the task to
+ * either the current or the overflow delayed task list.
+ */
+static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION;
+
+/*
+ * Allocates memory from the heap for a TCB and associated stack. Checks the
+ * allocation was successful.
+ */
+static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
+
+/*
+ * Called from vTaskList. vListTasks details all the tasks currently under
+ * control of the scheduler. The tasks may be in one of a number of lists.
+ * prvListTaskWithinSingleList accepts a list and details the tasks from
+ * within just that list.
+ *
+ * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
+ * NORMAL APPLICATION CODE.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;
+
+#endif
+
+/*
+ * When a task is created, the stack of the task is filled with a known value.
+ * This function determines the 'high water mark' of the task stack by
+ * determining how much of the stack remains at the original preset value.
+ */
+#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
+
+ static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
+
+#endif
+
+
+/*lint +e956 */
+
+
+
+/*-----------------------------------------------------------
+ * TASK CREATION API documented in task.h
+ *----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
+{
+signed portBASE_TYPE xReturn;
+tskTCB * pxNewTCB;
+
+ configASSERT( pxTaskCode );
+ configASSERT( ( uxPriority < configMAX_PRIORITIES ) );
+
+ /* Allocate the memory required by the TCB and stack for the new task,
+ checking that the allocation was successful. */
+ pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
+
+ if( pxNewTCB != NULL )
+ {
+ portSTACK_TYPE *pxTopOfStack;
+
+ #if( portUSING_MPU_WRAPPERS == 1 )
+ /* Should the task be created in privileged mode? */
+ portBASE_TYPE xRunPrivileged;
+ if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )
+ {
+ xRunPrivileged = pdTRUE;
+ }
+ else
+ {
+ xRunPrivileged = pdFALSE;
+ }
+ uxPriority &= ~portPRIVILEGE_BIT;
+ #endif /* portUSING_MPU_WRAPPERS == 1 */
+
+ /* Calculate the top of stack address. This depends on whether the
+ stack grows from high memory to low (as per the 80x86) or visa versa.
+ portSTACK_GROWTH is used to make the result positive or negative as
+ required by the port. */
+ #if( portSTACK_GROWTH < 0 )
+ {
+ pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
+ pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK ) );
+
+ /* Check the alignment of the calculated top of stack is correct. */
+ configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
+ }
+ #else
+ {
+ pxTopOfStack = pxNewTCB->pxStack;
+
+ /* Check the alignment of the stack buffer is correct. */
+ configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
+
+ /* If we want to use stack checking on architectures that use
+ a positive stack growth direction then we also need to store the
+ other extreme of the stack space. */
+ pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
+ }
+ #endif
+
+ /* Setup the newly allocated TCB with the initial state of the task. */
+ prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
+
+ /* Initialize the TCB stack to look as if the task was already running,
+ but had been interrupted by the scheduler. The return address is set
+ to the start of the task function. Once the stack has been initialised
+ the top of stack variable is updated. */
+ #if( portUSING_MPU_WRAPPERS == 1 )
+ {
+ pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
+ }
+ #else
+ {
+ pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
+ }
+ #endif
+
+ /* Check the alignment of the initialised stack. */
+ configASSERT( ( ( ( unsigned long ) pxNewTCB->pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
+
+ if( ( void * ) pxCreatedTask != NULL )
+ {
+ /* Pass the TCB out - in an anonymous way. The calling function/
+ task can use this as a handle to delete the task later if
+ required.*/
+ *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
+ }
+
+ /* We are going to manipulate the task queues to add this task to a
+ ready list, so must make sure no interrupts occur. */
+ taskENTER_CRITICAL();
+ {
+ uxCurrentNumberOfTasks++;
+ if( pxCurrentTCB == NULL )
+ {
+ /* There are no other tasks, or all the other tasks are in
+ the suspended state - make this the current task. */
+ pxCurrentTCB = pxNewTCB;
+
+ if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
+ {
+ /* This is the first task to be created so do the preliminary
+ initialisation required. We will not recover if this call
+ fails, but we will report the failure. */
+ prvInitialiseTaskLists();
+ }
+ }
+ else
+ {
+ /* If the scheduler is not already running, make this task the
+ current task if it is the highest priority task to be created
+ so far. */
+ if( xSchedulerRunning == pdFALSE )
+ {
+ if( pxCurrentTCB->uxPriority <= uxPriority )
+ {
+ pxCurrentTCB = pxNewTCB;
+ }
+ }
+ }
+
+ /* Remember the top priority to make context switching faster. Use
+ the priority in pxNewTCB as this has been capped to a valid value. */
+ if( pxNewTCB->uxPriority > uxTopUsedPriority )
+ {
+ uxTopUsedPriority = pxNewTCB->uxPriority;
+ }
+
+ #if ( configUSE_TRACE_FACILITY == 1 )
+ {
+ /* Add a counter into the TCB for tracing only. */
+ pxNewTCB->uxTCBNumber = uxTaskNumber;
+ }
+ #endif
+ uxTaskNumber++;
+
+ prvAddTaskToReadyQueue( pxNewTCB );
+
+ xReturn = pdPASS;
+ traceTASK_CREATE( pxNewTCB );
+ }
+ taskEXIT_CRITICAL();
+ }
+ else
+ {
+ xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+ traceTASK_CREATE_FAILED();
+ }
+
+ if( xReturn == pdPASS )
+ {
+ if( xSchedulerRunning != pdFALSE )
+ {
+ /* If the created task is of a higher priority than the current task
+ then it should run now. */
+ if( pxCurrentTCB->uxPriority < uxPriority )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelete == 1 )
+
+ void vTaskDelete( xTaskHandle pxTaskToDelete )
+ {
+ tskTCB *pxTCB;
+
+ taskENTER_CRITICAL();
+ {
+ /* Ensure a yield is performed if the current task is being
+ deleted. */
+ if( pxTaskToDelete == pxCurrentTCB )
+ {
+ pxTaskToDelete = NULL;
+ }
+
+ /* If null is passed in here then we are deleting ourselves. */
+ pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
+
+ /* Remove task from the ready list and place in the termination list.
+ This will stop the task from be scheduled. The idle task will check
+ the termination list and free up any memory allocated by the
+ scheduler for the TCB and stack. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Is the task waiting on an event also? */
+ if( pxTCB->xEventListItem.pvContainer )
+ {
+ vListRemove( &( pxTCB->xEventListItem ) );
+ }
+
+ vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
+
+ /* Increment the ucTasksDeleted variable so the idle task knows
+ there is a task that has been deleted and that it should therefore
+ check the xTasksWaitingTermination list. */
+ ++uxTasksDeleted;
+
+ /* Increment the uxTaskNumberVariable also so kernel aware debuggers
+ can detect that the task lists need re-generating. */
+ uxTaskNumber++;
+
+ traceTASK_DELETE( pxTCB );
+ }
+ taskEXIT_CRITICAL();
+
+ /* Force a reschedule if we have just deleted the current task. */
+ if( xSchedulerRunning != pdFALSE )
+ {
+ if( ( void * ) pxTaskToDelete == NULL )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+
+#endif
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * TASK CONTROL API documented in task.h
+ *----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelayUntil == 1 )
+
+ void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
+ {
+ portTickType xTimeToWake;
+ portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
+
+ configASSERT( pxPreviousWakeTime );
+ configASSERT( ( xTimeIncrement > 0 ) );
+
+ vTaskSuspendAll();
+ {
+ /* Generate the tick time at which the task wants to wake. */
+ xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
+
+ if( xTickCount < *pxPreviousWakeTime )
+ {
+ /* The tick count has overflowed since this function was
+ lasted called. In this case the only time we should ever
+ actually delay is if the wake time has also overflowed,
+ and the wake time is greater than the tick time. When this
+ is the case it is as if neither time had overflowed. */
+ if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
+ {
+ xShouldDelay = pdTRUE;
+ }
+ }
+ else
+ {
+ /* The tick time has not overflowed. In this case we will
+ delay if either the wake time has overflowed, and/or the
+ tick time is less than the wake time. */
+ if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
+ {
+ xShouldDelay = pdTRUE;
+ }
+ }
+
+ /* Update the wake time ready for the next call. */
+ *pxPreviousWakeTime = xTimeToWake;
+
+ if( xShouldDelay != pdFALSE )
+ {
+ traceTASK_DELAY_UNTIL();
+
+ /* We must remove ourselves from the ready list before adding
+ ourselves to the blocked list as the same list item is used for
+ both lists. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+ }
+ xAlreadyYielded = xTaskResumeAll();
+
+ /* Force a reschedule if xTaskResumeAll has not already done so, we may
+ have put ourselves to sleep. */
+ if( !xAlreadyYielded )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelay == 1 )
+
+ void vTaskDelay( portTickType xTicksToDelay )
+ {
+ portTickType xTimeToWake;
+ signed portBASE_TYPE xAlreadyYielded = pdFALSE;
+
+ /* A delay time of zero just forces a reschedule. */
+ if( xTicksToDelay > ( portTickType ) 0 )
+ {
+ vTaskSuspendAll();
+ {
+ traceTASK_DELAY();
+
+ /* A task that is removed from the event list while the
+ scheduler is suspended will not get placed in the ready
+ list or removed from the blocked list until the scheduler
+ is resumed.
+
+ This task cannot be in an event list as it is the currently
+ executing task. */
+
+ /* Calculate the time to wake - this may overflow but this is
+ not a problem. */
+ xTimeToWake = xTickCount + xTicksToDelay;
+
+ /* We must remove ourselves from the ready list before adding
+ ourselves to the blocked list as the same list item is used for
+ both lists. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+ xAlreadyYielded = xTaskResumeAll();
+ }
+
+ /* Force a reschedule if xTaskResumeAll has not already done so, we may
+ have put ourselves to sleep. */
+ if( !xAlreadyYielded )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_uxTaskPriorityGet == 1 )
+
+ unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
+ {
+ tskTCB *pxTCB;
+ unsigned portBASE_TYPE uxReturn;
+
+ taskENTER_CRITICAL();
+ {
+ /* If null is passed in here then we are changing the
+ priority of the calling function. */
+ pxTCB = prvGetTCBFromHandle( pxTask );
+ uxReturn = pxTCB->uxPriority;
+ }
+ taskEXIT_CRITICAL();
+
+ return uxReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskPrioritySet == 1 )
+
+ void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
+ {
+ tskTCB *pxTCB;
+ unsigned portBASE_TYPE uxCurrentPriority;
+ portBASE_TYPE xYieldRequired = pdFALSE;
+
+ configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
+
+ /* Ensure the new priority is valid. */
+ if( uxNewPriority >= configMAX_PRIORITIES )
+ {
+ uxNewPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
+ }
+
+ taskENTER_CRITICAL();
+ {
+ if( pxTask == pxCurrentTCB )
+ {
+ pxTask = NULL;
+ }
+
+ /* If null is passed in here then we are changing the
+ priority of the calling function. */
+ pxTCB = prvGetTCBFromHandle( pxTask );
+
+ traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ uxCurrentPriority = pxTCB->uxBasePriority;
+ }
+ #else
+ {
+ uxCurrentPriority = pxTCB->uxPriority;
+ }
+ #endif
+
+ if( uxCurrentPriority != uxNewPriority )
+ {
+ /* The priority change may have readied a task of higher
+ priority than the calling task. */
+ if( uxNewPriority > uxCurrentPriority )
+ {
+ if( pxTask != NULL )
+ {
+ /* The priority of another task is being raised. If we
+ were raising the priority of the currently running task
+ there would be no need to switch as it must have already
+ been the highest priority task. */
+ xYieldRequired = pdTRUE;
+ }
+ }
+ else if( pxTask == NULL )
+ {
+ /* Setting our own priority down means there may now be another
+ task of higher priority that is ready to execute. */
+ xYieldRequired = pdTRUE;
+ }
+
+
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ /* Only change the priority being used if the task is not
+ currently using an inherited priority. */
+ if( pxTCB->uxBasePriority == pxTCB->uxPriority )
+ {
+ pxTCB->uxPriority = uxNewPriority;
+ }
+
+ /* The base priority gets set whatever. */
+ pxTCB->uxBasePriority = uxNewPriority;
+ }
+ #else
+ {
+ pxTCB->uxPriority = uxNewPriority;
+ }
+ #endif
+
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
+
+ /* If the task is in the blocked or suspended list we need do
+ nothing more than change it's priority variable. However, if
+ the task is in a ready list it needs to be removed and placed
+ in the queue appropriate to its new priority. */
+ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
+ {
+ /* The task is currently in its ready list - remove before adding
+ it to it's new ready list. As we are in a critical section we
+ can do this even if the scheduler is suspended. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+
+ if( xYieldRequired == pdTRUE )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ void vTaskSuspend( xTaskHandle pxTaskToSuspend )
+ {
+ tskTCB *pxTCB;
+
+ taskENTER_CRITICAL();
+ {
+ /* Ensure a yield is performed if the current task is being
+ suspended. */
+ if( pxTaskToSuspend == pxCurrentTCB )
+ {
+ pxTaskToSuspend = NULL;
+ }
+
+ /* If null is passed in here then we are suspending ourselves. */
+ pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
+
+ traceTASK_SUSPEND( pxTCB );
+
+ /* Remove task from the ready/delayed list and place in the suspended list. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Is the task waiting on an event also? */
+ if( pxTCB->xEventListItem.pvContainer )
+ {
+ vListRemove( &( pxTCB->xEventListItem ) );
+ }
+
+ vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
+ }
+ taskEXIT_CRITICAL();
+
+ if( ( void * ) pxTaskToSuspend == NULL )
+ {
+ if( xSchedulerRunning != pdFALSE )
+ {
+ /* We have just suspended the current task. */
+ portYIELD_WITHIN_API();
+ }
+ else
+ {
+ /* The scheduler is not running, but the task that was pointed
+ to by pxCurrentTCB has just been suspended and pxCurrentTCB
+ must be adjusted to point to a different task. */
+ if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
+ {
+ /* No other tasks are ready, so set pxCurrentTCB back to
+ NULL so when the next task is created pxCurrentTCB will
+ be set to point to it no matter what its relative priority
+ is. */
+ pxCurrentTCB = NULL;
+ }
+ else
+ {
+ vTaskSwitchContext();
+ }
+ }
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
+ {
+ portBASE_TYPE xReturn = pdFALSE;
+ const tskTCB * const pxTCB = ( tskTCB * ) xTask;
+
+ /* It does not make sense to check if the calling task is suspended. */
+ configASSERT( xTask );
+
+ /* Is the task we are attempting to resume actually in the
+ suspended list? */
+ if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
+ {
+ /* Has the task already been resumed from within an ISR? */
+ if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
+ {
+ /* Is it in the suspended list because it is in the
+ Suspended state? It is possible to be in the suspended
+ list because it is blocked on a task with no timeout
+ specified. */
+ if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
+ {
+ xReturn = pdTRUE;
+ }
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ void vTaskResume( xTaskHandle pxTaskToResume )
+ {
+ tskTCB *pxTCB;
+
+ /* It does not make sense to resume the calling task. */
+ configASSERT( pxTaskToResume );
+
+ /* Remove the task from whichever list it is currently in, and place
+ it in the ready list. */
+ pxTCB = ( tskTCB * ) pxTaskToResume;
+
+ /* The parameter cannot be NULL as it is impossible to resume the
+ currently executing task. */
+ if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
+ {
+ taskENTER_CRITICAL();
+ {
+ if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
+ {
+ traceTASK_RESUME( pxTCB );
+
+ /* As we are in a critical section we can access the ready
+ lists even if the scheduler is suspended. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+
+ /* We may have just resumed a higher priority task. */
+ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ /* This yield may not cause the task just resumed to run, but
+ will leave the lists in the correct state for the next yield. */
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+ portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
+ {
+ portBASE_TYPE xYieldRequired = pdFALSE;
+ tskTCB *pxTCB;
+
+ configASSERT( pxTaskToResume );
+
+ pxTCB = ( tskTCB * ) pxTaskToResume;
+
+ if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
+ {
+ traceTASK_RESUME_FROM_ISR( pxTCB );
+
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ else
+ {
+ /* We cannot access the delayed or ready lists, so will hold this
+ task pending until the scheduler is resumed, at which point a
+ yield will be performed if necessary. */
+ vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
+ }
+ }
+
+ return xYieldRequired;
+ }
+
+#endif
+
+
+
+
+/*-----------------------------------------------------------
+ * PUBLIC SCHEDULER CONTROL documented in task.h
+ *----------------------------------------------------------*/
+
+
+void vTaskStartScheduler( void )
+{
+portBASE_TYPE xReturn;
+
+ /* Add the idle task at the lowest priority. */
+ xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
+
+ #if ( configUSE_TIMERS == 1 )
+ {
+ if( xReturn == pdPASS )
+ {
+ xReturn = xTimerCreateTimerTask();
+ }
+ }
+ #endif
+
+ if( xReturn == pdPASS )
+ {
+ /* Interrupts are turned off here, to ensure a tick does not occur
+ before or during the call to xPortStartScheduler(). The stacks of
+ the created tasks contain a status word with interrupts switched on
+ so interrupts will automatically get re-enabled when the first task
+ starts to run.
+
+ STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
+ DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
+ portDISABLE_INTERRUPTS();
+
+ xSchedulerRunning = pdTRUE;
+ xTickCount = ( portTickType ) 0;
+
+ /* If configGENERATE_RUN_TIME_STATS is defined then the following
+ macro must be defined to configure the timer/counter used to generate
+ the run time counter time base. */
+ portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
+
+ /* Setting up the timer tick is hardware specific and thus in the
+ portable interface. */
+ if( xPortStartScheduler() )
+ {
+ /* Should not reach here as if the scheduler is running the
+ function will not return. */
+ }
+ else
+ {
+ /* Should only reach here if a task calls xTaskEndScheduler(). */
+ }
+ }
+
+ /* This line will only be reached if the kernel could not be started. */
+ configASSERT( xReturn );
+}
+/*-----------------------------------------------------------*/
+
+void vTaskEndScheduler( void )
+{
+ /* Stop the scheduler interrupts and call the portable scheduler end
+ routine so the original ISRs can be restored if necessary. The port
+ layer must ensure interrupts enable bit is left in the correct state. */
+ portDISABLE_INTERRUPTS();
+ xSchedulerRunning = pdFALSE;
+ vPortEndScheduler();
+}
+/*----------------------------------------------------------*/
+
+void vTaskSuspendAll( void )
+{
+ /* A critical section is not required as the variable is of type
+ portBASE_TYPE. */
+ ++uxSchedulerSuspended;
+}
+/*----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskResumeAll( void )
+{
+register tskTCB *pxTCB;
+signed portBASE_TYPE xAlreadyYielded = pdFALSE;
+
+ /* If uxSchedulerSuspended is zero then this function does not match a
+ previous call to vTaskSuspendAll(). */
+ configASSERT( uxSchedulerSuspended );
+
+ /* It is possible that an ISR caused a task to be removed from an event
+ list while the scheduler was suspended. If this was the case then the
+ removed task will have been added to the xPendingReadyList. Once the
+ scheduler has been resumed it is safe to move all the pending ready
+ tasks from this list into their appropriate ready list. */
+ taskENTER_CRITICAL();
+ {
+ --uxSchedulerSuspended;
+
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ portBASE_TYPE xYieldRequired = pdFALSE;
+
+ /* Move any readied tasks from the pending list into the
+ appropriate ready list. */
+ while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE )
+ {
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) );
+ vListRemove( &( pxTCB->xEventListItem ) );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+
+ /* If we have moved a task that has a priority higher than
+ the current task then we should yield. */
+ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ xYieldRequired = pdTRUE;
+ }
+ }
+
+ /* If any ticks occurred while the scheduler was suspended then
+ they should be processed now. This ensures the tick count does not
+ slip, and that any delayed tasks are resumed at the correct time. */
+ if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ vTaskIncrementTick();
+ --uxMissedTicks;
+ }
+
+ /* As we have processed some ticks it is appropriate to yield
+ to ensure the highest priority task that is ready to run is
+ the task actually running. */
+ #if configUSE_PREEMPTION == 1
+ {
+ xYieldRequired = pdTRUE;
+ }
+ #endif
+ }
+
+ if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
+ {
+ xAlreadyYielded = pdTRUE;
+ xMissedYield = pdFALSE;
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ return xAlreadyYielded;
+}
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * PUBLIC TASK UTILITIES documented in task.h
+ *----------------------------------------------------------*/
+
+
+
+portTickType xTaskGetTickCount( void )
+{
+portTickType xTicks;
+
+ /* Critical section required if running on a 16 bit processor. */
+ taskENTER_CRITICAL();
+ {
+ xTicks = xTickCount;
+ }
+ taskEXIT_CRITICAL();
+
+ return xTicks;
+}
+/*-----------------------------------------------------------*/
+
+portTickType xTaskGetTickCountFromISR( void )
+{
+portTickType xReturn;
+unsigned portBASE_TYPE uxSavedInterruptStatus;
+
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
+ xReturn = xTickCount;
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
+{
+ /* A critical section is not required because the variables are of type
+ portBASE_TYPE. */
+ return uxCurrentNumberOfTasks;
+}
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ void vTaskList( signed char *pcWriteBuffer )
+ {
+ unsigned portBASE_TYPE uxQueue;
+
+ /* This is a VERY costly function that should be used for debug only.
+ It leaves interrupts disabled for a LONG time. */
+
+ vTaskSuspendAll();
+ {
+ /* Run through all the lists that could potentially contain a TCB and
+ report the task name, state and stack high water mark. */
+
+ *pcWriteBuffer = ( signed char ) 0x00;
+ strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
+
+ uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
+
+ do
+ {
+ uxQueue--;
+
+ if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
+ }
+ }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
+
+ if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
+ }
+
+ if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
+ }
+
+ #if( INCLUDE_vTaskDelete == 1 )
+ {
+ if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
+ }
+ }
+ #endif
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
+ }
+ }
+ #endif
+ }
+ xTaskResumeAll();
+ }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configGENERATE_RUN_TIME_STATS == 1 )
+
+ void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
+ {
+ unsigned portBASE_TYPE uxQueue;
+ unsigned long ulTotalRunTime;
+
+ /* This is a VERY costly function that should be used for debug only.
+ It leaves interrupts disabled for a LONG time. */
+
+ vTaskSuspendAll();
+ {
+ #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
+ portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
+ #else
+ ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
+ #endif
+
+ /* Divide ulTotalRunTime by 100 to make the percentage caluclations
+ simpler in the prvGenerateRunTimeStatsForTasksInList() function. */
+ ulTotalRunTime /= 100UL;
+
+ /* Run through all the lists that could potentially contain a TCB,
+ generating a table of run timer percentages in the provided
+ buffer. */
+
+ *pcWriteBuffer = ( signed char ) 0x00;
+ strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
+
+ uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
+
+ do
+ {
+ uxQueue--;
+
+ if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
+ }
+ }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
+
+ if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
+ }
+
+ if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
+ }
+
+ #if ( INCLUDE_vTaskDelete == 1 )
+ {
+ if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
+ }
+ }
+ #endif
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
+ }
+ }
+ #endif
+ }
+ xTaskResumeAll();
+ }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize )
+ {
+ configASSERT( pcBuffer );
+ configASSERT( ulBufferSize );
+
+ taskENTER_CRITICAL();
+ {
+ pcTraceBuffer = ( signed char * )pcBuffer;
+ pcTraceBufferStart = pcBuffer;
+ pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
+ xTracing = pdTRUE;
+ }
+ taskEXIT_CRITICAL();
+ }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ unsigned long ulTaskEndTrace( void )
+ {
+ unsigned long ulBufferLength;
+
+ taskENTER_CRITICAL();
+ xTracing = pdFALSE;
+ taskEXIT_CRITICAL();
+
+ ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart );
+
+ return ulBufferLength;
+ }
+
+#endif
+
+
+
+/*-----------------------------------------------------------
+ * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
+ * documented in task.h
+ *----------------------------------------------------------*/
+
+
+void vTaskIncrementTick( void )
+{
+tskTCB * pxTCB;
+
+ /* Called by the portable layer each time a tick interrupt occurs.
+ Increments the tick then checks to see if the new tick value will cause any
+ tasks to be unblocked. */
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ ++xTickCount;
+ if( xTickCount == ( portTickType ) 0 )
+ {
+ xList *pxTemp;
+
+ /* Tick count has overflowed so we need to swap the delay lists.
+ If there are any items in pxDelayedTaskList here then there is
+ an error! */
+ configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );
+
+ pxTemp = pxDelayedTaskList;
+ pxDelayedTaskList = pxOverflowDelayedTaskList;
+ pxOverflowDelayedTaskList = pxTemp;
+ xNumOfOverflows++;
+
+ if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
+ {
+ /* The new current delayed list is empty. Set
+ xNextTaskUnblockTime to the maximum possible value so it is
+ extremely unlikely that the
+ if( xTickCount >= xNextTaskUnblockTime ) test will pass until
+ there is an item in the delayed list. */
+ xNextTaskUnblockTime = portMAX_DELAY;
+ }
+ else
+ {
+ /* The new current delayed list is not empty, get the value of
+ the item at the head of the delayed list. This is the time at
+ which the task at the head of the delayed list should be removed
+ from the Blocked state. */
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
+ xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );
+ }
+ }
+
+ /* See if this tick has made a timeout expire. */
+ prvCheckDelayedTasks();
+ }
+ else
+ {
+ ++uxMissedTicks;
+
+ /* The tick hook gets called at regular intervals, even if the
+ scheduler is locked. */
+ #if ( configUSE_TICK_HOOK == 1 )
+ {
+ vApplicationTickHook();
+ }
+ #endif
+ }
+
+ #if ( configUSE_TICK_HOOK == 1 )
+ {
+ /* Guard against the tick hook being called when the missed tick
+ count is being unwound (when the scheduler is being unlocked. */
+ if( uxMissedTicks == ( unsigned portBASE_TYPE ) 0U )
+ {
+ vApplicationTickHook();
+ }
+ }
+ #endif
+
+ traceTASK_INCREMENT_TICK( xTickCount );
+}
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+ void vTaskCleanUpResources( void )
+ {
+ unsigned short usQueue;
+ volatile tskTCB *pxTCB;
+
+ usQueue = ( unsigned short ) uxTopUsedPriority + ( unsigned short ) 1;
+
+ /* Remove any TCB's from the ready queues. */
+ do
+ {
+ usQueue--;
+
+ while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) == pdFALSE )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+ }while( usQueue > ( unsigned short ) tskIDLE_PRIORITY );
+
+ /* Remove any TCB's from the delayed queue. */
+ while( listLIST_IS_EMPTY( &xDelayedTaskList1 ) == pdFALSE )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+
+ /* Remove any TCB's from the overflow delayed queue. */
+ while( listLIST_IS_EMPTY( &xDelayedTaskList2 ) == pdFALSE )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+
+ while( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_APPLICATION_TASK_TAG == 1 )
+
+ void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )
+ {
+ tskTCB *xTCB;
+
+ /* If xTask is NULL then we are setting our own task hook. */
+ if( xTask == NULL )
+ {
+ xTCB = ( tskTCB * ) pxCurrentTCB;
+ }
+ else
+ {
+ xTCB = ( tskTCB * ) xTask;
+ }
+
+ /* Save the hook function in the TCB. A critical section is required as
+ the value can be accessed from an interrupt. */
+ taskENTER_CRITICAL();
+ xTCB->pxTaskTag = pxHookFunction;
+ taskEXIT_CRITICAL();
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_APPLICATION_TASK_TAG == 1 )
+
+ pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
+ {
+ tskTCB *xTCB;
+ pdTASK_HOOK_CODE xReturn;
+
+ /* If xTask is NULL then we are setting our own task hook. */
+ if( xTask == NULL )
+ {
+ xTCB = ( tskTCB * ) pxCurrentTCB;
+ }
+ else
+ {
+ xTCB = ( tskTCB * ) xTask;
+ }
+
+ /* Save the hook function in the TCB. A critical section is required as
+ the value can be accessed from an interrupt. */
+ taskENTER_CRITICAL();
+ xReturn = xTCB->pxTaskTag;
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_APPLICATION_TASK_TAG == 1 )
+
+ portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
+ {
+ tskTCB *xTCB;
+ portBASE_TYPE xReturn;
+
+ /* If xTask is NULL then we are calling our own task hook. */
+ if( xTask == NULL )
+ {
+ xTCB = ( tskTCB * ) pxCurrentTCB;
+ }
+ else
+ {
+ xTCB = ( tskTCB * ) xTask;
+ }
+
+ if( xTCB->pxTaskTag != NULL )
+ {
+ xReturn = xTCB->pxTaskTag( pvParameter );
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+void vTaskSwitchContext( void )
+{
+ if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ /* The scheduler is currently suspended - do not allow a context
+ switch. */
+ xMissedYield = pdTRUE;
+ }
+ else
+ {
+ traceTASK_SWITCHED_OUT();
+
+ #if ( configGENERATE_RUN_TIME_STATS == 1 )
+ {
+ unsigned long ulTempCounter;
+
+ #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
+ portALT_GET_RUN_TIME_COUNTER_VALUE( ulTempCounter );
+ #else
+ ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
+ #endif
+
+ /* Add the amount of time the task has been running to the accumulated
+ time so far. The time the task started running was stored in
+ ulTaskSwitchedInTime. Note that there is no overflow protection here
+ so count values are only valid until the timer overflows. Generally
+ this will be about 1 hour assuming a 1uS timer increment. */
+ pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
+ ulTaskSwitchedInTime = ulTempCounter;
+ }
+ #endif
+
+ taskFIRST_CHECK_FOR_STACK_OVERFLOW();
+ taskSECOND_CHECK_FOR_STACK_OVERFLOW();
+
+ /* Find the highest priority queue that contains ready tasks. */
+ while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
+ {
+ configASSERT( uxTopReadyPriority );
+ --uxTopReadyPriority;
+ }
+
+ /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
+ same priority get an equal share of the processor time. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
+
+ traceTASK_SWITCHED_IN();
+ vWriteTraceToBuffer();
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
+{
+portTickType xTimeToWake;
+
+ configASSERT( pxEventList );
+
+ /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
+ SCHEDULER SUSPENDED. */
+
+ /* Place the event list item of the TCB in the appropriate event list.
+ This is placed in the list in priority order so the highest priority task
+ is the first to be woken by the event. */
+ vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
+
+ /* We must remove ourselves from the ready list before adding ourselves
+ to the blocked list as the same list item is used for both lists. We have
+ exclusive access to the ready lists as the scheduler is locked. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ if( xTicksToWait == portMAX_DELAY )
+ {
+ /* Add ourselves to the suspended task list instead of a delayed task
+ list to ensure we are not woken by a timing event. We will block
+ indefinitely. */
+ vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* Calculate the time at which the task should be woken if the event does
+ not occur. This may overflow but this doesn't matter. */
+ xTimeToWake = xTickCount + xTicksToWait;
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+ }
+ #else
+ {
+ /* Calculate the time at which the task should be woken if the event does
+ not occur. This may overflow but this doesn't matter. */
+ xTimeToWake = xTickCount + xTicksToWait;
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+#if configUSE_TIMERS == 1
+
+ void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )
+ {
+ portTickType xTimeToWake;
+
+ configASSERT( pxEventList );
+
+ /* This function should not be called by application code hence the
+ 'Restricted' in its name. It is not part of the public API. It is
+ designed for use by kernel code, and has special calling requirements -
+ it should be called from a critical section. */
+
+
+ /* Place the event list item of the TCB in the appropriate event list.
+ In this case it is assume that this is the only task that is going to
+ be waiting on this event list, so the faster vListInsertEnd() function
+ can be used in place of vListInsert. */
+ vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
+
+ /* We must remove this task from the ready list before adding it to the
+ blocked list as the same list item is used for both lists. This
+ function is called form a critical section. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+ /* Calculate the time at which the task should be woken if the event does
+ not occur. This may overflow but this doesn't matter. */
+ xTimeToWake = xTickCount + xTicksToWait;
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+
+#endif /* configUSE_TIMERS */
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
+{
+tskTCB *pxUnblockedTCB;
+portBASE_TYPE xReturn;
+
+ /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
+ SCHEDULER SUSPENDED. It can also be called from within an ISR. */
+
+ /* The event list is sorted in priority order, so we can remove the
+ first in the list, remove the TCB from the delayed list, and add
+ it to the ready list.
+
+ If an event is for a queue that is locked then this function will never
+ get called - the lock count on the queue will get modified instead. This
+ means we can always expect exclusive access to the event list here.
+
+ This function assumes that a check has already been made to ensure that
+ pxEventList is not empty. */
+ pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
+ configASSERT( pxUnblockedTCB );
+ vListRemove( &( pxUnblockedTCB->xEventListItem ) );
+
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxUnblockedTCB );
+ }
+ else
+ {
+ /* We cannot access the delayed or ready lists, so will hold this
+ task pending until the scheduler is resumed. */
+ vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
+ }
+
+ if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ /* Return true if the task removed from the event list has
+ a higher priority than the calling task. This allows
+ the calling task to know if it should force a context
+ switch now. */
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
+{
+ configASSERT( pxTimeOut );
+ pxTimeOut->xOverflowCount = xNumOfOverflows;
+ pxTimeOut->xTimeOnEntering = xTickCount;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
+{
+portBASE_TYPE xReturn;
+
+ configASSERT( pxTimeOut );
+ configASSERT( pxTicksToWait );
+
+ taskENTER_CRITICAL();
+ {
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
+ the maximum block time then the task should block indefinitely, and
+ therefore never time out. */
+ if( *pxTicksToWait == portMAX_DELAY )
+ {
+ xReturn = pdFALSE;
+ }
+ else /* We are not blocking indefinitely, perform the checks below. */
+ #endif
+
+ if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
+ {
+ /* The tick count is greater than the time at which vTaskSetTimeout()
+ was called, but has also overflowed since vTaskSetTimeOut() was called.
+ It must have wrapped all the way around and gone past us again. This
+ passed since vTaskSetTimeout() was called. */
+ xReturn = pdTRUE;
+ }
+ else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )
+ {
+ /* Not a genuine timeout. Adjust parameters for time remaining. */
+ *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
+ vTaskSetTimeOutState( pxTimeOut );
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vTaskMissedYield( void )
+{
+ xMissedYield = pdTRUE;
+}
+
+/*
+ * -----------------------------------------------------------
+ * The Idle task.
+ * ----------------------------------------------------------
+ *
+ * The portTASK_FUNCTION() macro is used to allow port/compiler specific
+ * language extensions. The equivalent prototype for this function is:
+ *
+ * void prvIdleTask( void *pvParameters );
+ *
+ */
+static portTASK_FUNCTION( prvIdleTask, pvParameters )
+{
+ /* Stop warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* See if any tasks have been deleted. */
+ prvCheckTasksWaitingTermination();
+
+ #if ( configUSE_PREEMPTION == 0 )
+ {
+ /* If we are not using preemption we keep forcing a task switch to
+ see if any other task has become available. If we are using
+ preemption we don't need to do this as any task becoming available
+ will automatically get the processor anyway. */
+ taskYIELD();
+ }
+ #endif
+
+ #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
+ {
+ /* When using preemption tasks of equal priority will be
+ timesliced. If a task that is sharing the idle priority is ready
+ to run then the idle task should yield before the end of the
+ timeslice.
+
+ A critical region is not required here as we are just reading from
+ the list, and an occasional incorrect value will not matter. If
+ the ready list at the idle priority contains more than one task
+ then a task other than the idle task is ready to execute. */
+ if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
+ {
+ taskYIELD();
+ }
+ }
+ #endif
+
+ #if ( configUSE_IDLE_HOOK == 1 )
+ {
+ extern void vApplicationIdleHook( void );
+
+ /* Call the user defined function from within the idle task. This
+ allows the application designer to add background functionality
+ without the overhead of a separate task.
+ NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
+ CALL A FUNCTION THAT MIGHT BLOCK. */
+ vApplicationIdleHook();
+ }
+ #endif
+ }
+} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
+
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * File private functions documented at the top of the file.
+ *----------------------------------------------------------*/
+
+
+
+static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
+{
+ /* Store the function name in the TCB. */
+ #if configMAX_TASK_NAME_LEN > 1
+ {
+ /* Don't bring strncpy into the build unnecessarily. */
+ strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );
+ }
+ #endif
+ pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0';
+
+ /* This is used as an array index so must ensure it's not too large. First
+ remove the privilege bit if one is present. */
+ if( uxPriority >= configMAX_PRIORITIES )
+ {
+ uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
+ }
+
+ pxTCB->uxPriority = uxPriority;
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ pxTCB->uxBasePriority = uxPriority;
+ }
+ #endif
+
+ vListInitialiseItem( &( pxTCB->xGenericListItem ) );
+ vListInitialiseItem( &( pxTCB->xEventListItem ) );
+
+ /* Set the pxTCB as a link back from the xListItem. This is so we can get
+ back to the containing TCB from a generic item in a list. */
+ listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
+
+ /* Event lists are always in priority order. */
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
+ listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
+
+ #if ( portCRITICAL_NESTING_IN_TCB == 1 )
+ {
+ pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
+ }
+ #endif
+
+ #if ( configUSE_APPLICATION_TASK_TAG == 1 )
+ {
+ pxTCB->pxTaskTag = NULL;
+ }
+ #endif
+
+ #if ( configGENERATE_RUN_TIME_STATS == 1 )
+ {
+ pxTCB->ulRunTimeCounter = 0UL;
+ }
+ #endif
+
+ #if ( portUSING_MPU_WRAPPERS == 1 )
+ {
+ vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
+ }
+ #else
+ {
+ ( void ) xRegions;
+ ( void ) usStackDepth;
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+#if ( portUSING_MPU_WRAPPERS == 1 )
+
+ void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
+ {
+ tskTCB *pxTCB;
+
+ if( xTaskToModify == pxCurrentTCB )
+ {
+ xTaskToModify = NULL;
+ }
+
+ /* If null is passed in here then we are deleting ourselves. */
+ pxTCB = prvGetTCBFromHandle( xTaskToModify );
+
+ vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
+ }
+ /*-----------------------------------------------------------*/
+#endif
+
+static void prvInitialiseTaskLists( void )
+{
+unsigned portBASE_TYPE uxPriority;
+
+ for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ )
+ {
+ vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
+ }
+
+ vListInitialise( ( xList * ) &xDelayedTaskList1 );
+ vListInitialise( ( xList * ) &xDelayedTaskList2 );
+ vListInitialise( ( xList * ) &xPendingReadyList );
+
+ #if ( INCLUDE_vTaskDelete == 1 )
+ {
+ vListInitialise( ( xList * ) &xTasksWaitingTermination );
+ }
+ #endif
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ vListInitialise( ( xList * ) &xSuspendedTaskList );
+ }
+ #endif
+
+ /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
+ using list2. */
+ pxDelayedTaskList = &xDelayedTaskList1;
+ pxOverflowDelayedTaskList = &xDelayedTaskList2;
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckTasksWaitingTermination( void )
+{
+ #if ( INCLUDE_vTaskDelete == 1 )
+ {
+ portBASE_TYPE xListIsEmpty;
+
+ /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
+ too often in the idle task. */
+ if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
+ {
+ vTaskSuspendAll();
+ xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
+ xTaskResumeAll();
+
+ if( xListIsEmpty == pdFALSE )
+ {
+ tskTCB *pxTCB;
+
+ taskENTER_CRITICAL();
+ {
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ --uxCurrentNumberOfTasks;
+ --uxTasksDeleted;
+ }
+ taskEXIT_CRITICAL();
+
+ prvDeleteTCB( pxTCB );
+ }
+ }
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )
+{
+ /* The list item will be inserted in wake time order. */
+ listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
+
+ if( xTimeToWake < xTickCount )
+ {
+ /* Wake time has overflowed. Place this item in the overflow list. */
+ vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* The wake time has not overflowed, so we can use the current block list. */
+ vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+ /* If the task entering the blocked state was placed at the head of the
+ list of blocked tasks then xNextTaskUnblockTime needs to be updated
+ too. */
+ if( xTimeToWake < xNextTaskUnblockTime )
+ {
+ xNextTaskUnblockTime = xTimeToWake;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
+{
+tskTCB *pxNewTCB;
+
+ /* Allocate space for the TCB. Where the memory comes from depends on
+ the implementation of the port malloc function. */
+ pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
+
+ if( pxNewTCB != NULL )
+ {
+ /* Allocate space for the stack used by the task being created.
+ The base of the stack memory stored in the TCB so the task can
+ be deleted later if required. */
+ pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
+
+ if( pxNewTCB->pxStack == NULL )
+ {
+ /* Could not allocate the stack. Delete the allocated TCB. */
+ vPortFree( pxNewTCB );
+ pxNewTCB = NULL;
+ }
+ else
+ {
+ /* Just to help debugging. */
+ memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
+ }
+ }
+
+ return pxNewTCB;
+}
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )
+ {
+ volatile tskTCB *pxNextTCB, *pxFirstTCB;
+ unsigned short usStackRemaining;
+
+ /* Write the details of all the TCB's in pxList into the buffer. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
+ do
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
+ #if ( portSTACK_GROWTH > 0 )
+ {
+ usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
+ }
+ #else
+ {
+ usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
+ }
+ #endif
+
+ sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
+ strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );
+
+ } while( pxNextTCB != pxFirstTCB );
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configGENERATE_RUN_TIME_STATS == 1 )
+
+ static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime )
+ {
+ volatile tskTCB *pxNextTCB, *pxFirstTCB;
+ unsigned long ulStatsAsPercentage;
+
+ /* Write the run time stats of all the TCB's in pxList into the buffer. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
+ do
+ {
+ /* Get next TCB in from the list. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
+
+ /* Divide by zero check. */
+ if( ulTotalRunTime > 0UL )
+ {
+ /* Has the task run at all? */
+ if( pxNextTCB->ulRunTimeCounter == 0 )
+ {
+ /* The task has used no CPU time at all. */
+ sprintf( pcStatsString, ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
+ }
+ else
+ {
+ /* What percentage of the total run time has the task used?
+ This will always be rounded down to the nearest integer.
+ ulTotalRunTime has already been divided by 100. */
+ ulStatsAsPercentage = pxNextTCB->ulRunTimeCounter / ulTotalRunTime;
+
+ if( ulStatsAsPercentage > 0UL )
+ {
+ #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
+ {
+ sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage );
+ }
+ #else
+ {
+ /* sizeof( int ) == sizeof( long ) so a smaller
+ printf() library can be used. */
+ sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
+ }
+ #endif
+ }
+ else
+ {
+ /* If the percentage is zero here then the task has
+ consumed less than 1% of the total run time. */
+ #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
+ {
+ sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter );
+ }
+ #else
+ {
+ /* sizeof( int ) == sizeof( long ) so a smaller
+ printf() library can be used. */
+ sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
+ }
+ #endif
+ }
+ }
+
+ strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatsString );
+ }
+
+ } while( pxNextTCB != pxFirstTCB );
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
+
+ static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
+ {
+ register unsigned short usCount = 0;
+
+ while( *pucStackByte == tskSTACK_FILL_BYTE )
+ {
+ pucStackByte -= portSTACK_GROWTH;
+ usCount++;
+ }
+
+ usCount /= sizeof( portSTACK_TYPE );
+
+ return usCount;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
+
+ unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
+ {
+ tskTCB *pxTCB;
+ unsigned char *pcEndOfStack;
+ unsigned portBASE_TYPE uxReturn;
+
+ pxTCB = prvGetTCBFromHandle( xTask );
+
+ #if portSTACK_GROWTH < 0
+ {
+ pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
+ }
+ #else
+ {
+ pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
+ }
+ #endif
+
+ uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
+
+ return uxReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
+
+ static void prvDeleteTCB( tskTCB *pxTCB )
+ {
+ /* Free up the memory allocated by the scheduler for the task. It is up to
+ the task to free any memory allocated at the application level. */
+ vPortFreeAligned( pxTCB->pxStack );
+ vPortFree( pxTCB );
+ }
+
+#endif
+
+
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
+
+ xTaskHandle xTaskGetCurrentTaskHandle( void )
+ {
+ xTaskHandle xReturn;
+
+ /* A critical section is not required as this is not called from
+ an interrupt and the current TCB will always be the same for any
+ individual execution thread. */
+ xReturn = pxCurrentTCB;
+
+ return xReturn;
+ }
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
+
+ portBASE_TYPE xTaskGetSchedulerState( void )
+ {
+ portBASE_TYPE xReturn;
+
+ if( xSchedulerRunning == pdFALSE )
+ {
+ xReturn = taskSCHEDULER_NOT_STARTED;
+ }
+ else
+ {
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ xReturn = taskSCHEDULER_RUNNING;
+ }
+ else
+ {
+ xReturn = taskSCHEDULER_SUSPENDED;
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_MUTEXES == 1 )
+
+ void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
+ {
+ tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
+
+ configASSERT( pxMutexHolder );
+
+ if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
+ {
+ /* Adjust the mutex holder state to account for its new priority. */
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
+
+ /* If the task being modified is in the ready state it will need to
+ be moved in to a new list. */
+ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
+ {
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Inherit the priority before being moved into the new list. */
+ pxTCB->uxPriority = pxCurrentTCB->uxPriority;
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ else
+ {
+ /* Just inherit the priority. */
+ pxTCB->uxPriority = pxCurrentTCB->uxPriority;
+ }
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_MUTEXES == 1 )
+
+ void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
+ {
+ tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
+
+ if( pxMutexHolder != NULL )
+ {
+ if( pxTCB->uxPriority != pxTCB->uxBasePriority )
+ {
+ /* We must be the running task to be able to give the mutex back.
+ Remove ourselves from the ready list we currently appear in. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Disinherit the priority before adding ourselves into the new
+ ready list. */
+ pxTCB->uxPriority = pxTCB->uxBasePriority;
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( portCRITICAL_NESTING_IN_TCB == 1 )
+
+ void vTaskEnterCritical( void )
+ {
+ portDISABLE_INTERRUPTS();
+
+ if( xSchedulerRunning != pdFALSE )
+ {
+ ( pxCurrentTCB->uxCriticalNesting )++;
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( portCRITICAL_NESTING_IN_TCB == 1 )
+
+void vTaskExitCritical( void )
+{
+ if( xSchedulerRunning != pdFALSE )
+ {
+ if( pxCurrentTCB->uxCriticalNesting > 0 )
+ {
+ ( pxCurrentTCB->uxCriticalNesting )--;
+
+ if( pxCurrentTCB->uxCriticalNesting == 0 )
+ {
+ portENABLE_INTERRUPTS();
+ }
+ }
+ }
+}
+
+#endif
+/*-----------------------------------------------------------*/
+
+
+
+
diff --git a/libraries/FreeRTOS/utility/timers.c b/libraries/FreeRTOS/utility/timers.c
new file mode 100755
index 0000000..1dd7555
--- /dev/null
+++ b/libraries/FreeRTOS/utility/timers.c
@@ -0,0 +1,649 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
+all the API functions to use the MPU wrappers. That should only be done when
+task.h is included from an application file. */
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "timers.h"
+
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+/* This entire source file will be skipped if the application is not configured
+to include software timer functionality. This #if is closed at the very bottom
+of this file. If you want to include software timer functionality then ensure
+configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
+#if ( configUSE_TIMERS == 1 )
+
+/* Misc definitions. */
+#define tmrNO_DELAY ( portTickType ) 0U
+
+/* The definition of the timers themselves. */
+typedef struct tmrTimerControl
+{
+ const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */
+ xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
+ portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
+ unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */
+ void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
+ tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */
+} xTIMER;
+
+/* The definition of messages that can be sent and received on the timer
+queue. */
+typedef struct tmrTimerQueueMessage
+{
+ portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */
+ portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
+ xTIMER * pxTimer; /*<< The timer to which the command will be applied. */
+} xTIMER_MESSAGE;
+
+
+/* The list in which active timers are stored. Timers are referenced in expire
+time order, with the nearest expiry time at the front of the list. Only the
+timer service task is allowed to access xActiveTimerList. */
+PRIVILEGED_DATA static xList xActiveTimerList1;
+PRIVILEGED_DATA static xList xActiveTimerList2;
+PRIVILEGED_DATA static xList *pxCurrentTimerList;
+PRIVILEGED_DATA static xList *pxOverflowTimerList;
+
+/* A queue that is used to send commands to the timer service task. */
+PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Initialise the infrastructure used by the timer service task if it has not
+ * been initialised already.
+ */
+static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * The timer service task (daemon). Timer functionality is controlled by this
+ * task. Other tasks communicate with the timer service task using the
+ * xTimerQueue queue.
+ */
+static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
+
+/*
+ * Called by the timer service task to interpret and process a command it
+ * received on the timer queue.
+ */
+static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
+ * depending on if the expire time causes a timer counter overflow.
+ */
+static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;
+
+/*
+ * An active timer has reached its expire time. Reload the timer if it is an
+ * auto reload timer, then call its callback.
+ */
+static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
+
+/*
+ * The tick count has overflowed. Switch the timer lists after ensuring the
+ * current timer list does not still reference some timers.
+ */
+static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;
+
+/*
+ * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
+ * if a tick count overflow occurred since prvSampleTimeNow() was last called.
+ */
+static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
+
+/*
+ * If the timer list contains any active timers then return the expire time of
+ * the timer that will expire first and set *pxListWasEmpty to false. If the
+ * timer list does not contain any timers then return 0 and set *pxListWasEmpty
+ * to pdTRUE.
+ */
+static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
+
+/*
+ * If a timer has expired, process it. Otherwise, block the timer service task
+ * until either a timer does expire or a command is received.
+ */
+static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
+
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTimerCreateTimerTask( void )
+{
+portBASE_TYPE xReturn = pdFAIL;
+
+ /* This function is called when the scheduler is started if
+ configUSE_TIMERS is set to 1. Check that the infrastructure used by the
+ timer service task has been created/initialised. If timers have already
+ been created then the initialisation will already have been performed. */
+ prvCheckForValidListAndQueue();
+
+ if( xTimerQueue != NULL )
+ {
+ xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, NULL);
+ }
+
+ configASSERT( xReturn );
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
+{
+xTIMER *pxNewTimer;
+
+ /* Allocate the timer structure. */
+ if( xTimerPeriodInTicks == ( portTickType ) 0U )
+ {
+ pxNewTimer = NULL;
+ configASSERT( ( xTimerPeriodInTicks > 0 ) );
+ }
+ else
+ {
+ pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
+ if( pxNewTimer != NULL )
+ {
+ /* Ensure the infrastructure used by the timer service task has been
+ created/initialised. */
+ prvCheckForValidListAndQueue();
+
+ /* Initialise the timer structure members using the function parameters. */
+ pxNewTimer->pcTimerName = pcTimerName;
+ pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
+ pxNewTimer->uxAutoReload = uxAutoReload;
+ pxNewTimer->pvTimerID = pvTimerID;
+ pxNewTimer->pxCallbackFunction = pxCallbackFunction;
+ vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
+
+ traceTIMER_CREATE( pxNewTimer );
+ }
+ else
+ {
+ traceTIMER_CREATE_FAILED();
+ }
+ }
+
+ return ( xTimerHandle ) pxNewTimer;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
+{
+portBASE_TYPE xReturn = pdFAIL;
+xTIMER_MESSAGE xMessage;
+
+ /* Send a message to the timer service task to perform a particular action
+ on a particular timer definition. */
+ if( xTimerQueue != NULL )
+ {
+ /* Send a command to the timer service task to start the xTimer timer. */
+ xMessage.xMessageID = xCommandID;
+ xMessage.xMessageValue = xOptionalValue;
+ xMessage.pxTimer = ( xTIMER * ) xTimer;
+
+ if( pxHigherPriorityTaskWoken == NULL )
+ {
+ if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
+ {
+ xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
+ }
+ else
+ {
+ xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
+ }
+ }
+ else
+ {
+ xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
+ }
+
+ traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
+{
+xTIMER *pxTimer;
+portBASE_TYPE xResult;
+
+ /* Remove the timer from the list of active timers. A check has already
+ been performed to ensure the list is not empty. */
+ pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
+ vListRemove( &( pxTimer->xTimerListItem ) );
+ traceTIMER_EXPIRED( pxTimer );
+
+ /* If the timer is an auto reload timer then calculate the next
+ expiry time and re-insert the timer in the list of active timers. */
+ if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
+ {
+ /* This is the only time a timer is inserted into a list using
+ a time relative to anything other than the current time. It
+ will therefore be inserted into the correct list relative to
+ the time this task thinks it is now, even if a command to
+ switch lists due to a tick count overflow is already waiting in
+ the timer queue. */
+ if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
+ {
+ /* The timer expired before it was added to the active timer
+ list. Reload it now. */
+ xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
+ configASSERT( xResult );
+ ( void ) xResult;
+ }
+ }
+
+ /* Call the timer callback. */
+ pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
+}
+/*-----------------------------------------------------------*/
+
+static void prvTimerTask( void *pvParameters )
+{
+portTickType xNextExpireTime;
+portBASE_TYPE xListWasEmpty;
+
+ /* Just to avoid compiler warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* Query the timers list to see if it contains any timers, and if so,
+ obtain the time at which the next timer will expire. */
+ xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
+
+ /* If a timer has expired, process it. Otherwise, block this task
+ until either a timer does expire, or a command is received. */
+ prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
+
+ /* Empty the command queue. */
+ prvProcessReceivedCommands();
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
+{
+portTickType xTimeNow;
+portBASE_TYPE xTimerListsWereSwitched;
+
+ vTaskSuspendAll();
+ {
+ /* Obtain the time now to make an assessment as to whether the timer
+ has expired or not. If obtaining the time causes the lists to switch
+ then don't process this timer as any timers that remained in the list
+ when the lists were switched will have been processed within the
+ prvSampelTimeNow() function. */
+ xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
+ if( xTimerListsWereSwitched == pdFALSE )
+ {
+ /* The tick count has not overflowed, has the timer expired? */
+ if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
+ {
+ xTaskResumeAll();
+ prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
+ }
+ else
+ {
+ /* The tick count has not overflowed, and the next expire
+ time has not been reached yet. This task should therefore
+ block to wait for the next expire time or a command to be
+ received - whichever comes first. The following line cannot
+ be reached unless xNextExpireTime > xTimeNow, except in the
+ case when the current timer list is empty. */
+ vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
+
+ if( xTaskResumeAll() == pdFALSE )
+ {
+ /* Yield to wait for either a command to arrive, or the block time
+ to expire. If a command arrived between the critical section being
+ exited and this yield then the yield will not cause the task
+ to block. */
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ else
+ {
+ xTaskResumeAll();
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )
+{
+portTickType xNextExpireTime;
+
+ /* Timers are listed in expiry time order, with the head of the list
+ referencing the task that will expire first. Obtain the time at which
+ the timer with the nearest expiry time will expire. If there are no
+ active timers then just set the next expire time to 0. That will cause
+ this task to unblock when the tick count overflows, at which point the
+ timer lists will be switched and the next expiry time can be
+ re-assessed. */
+ *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
+ if( *pxListWasEmpty == pdFALSE )
+ {
+ xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
+ }
+ else
+ {
+ /* Ensure the task unblocks when the tick count rolls over. */
+ xNextExpireTime = ( portTickType ) 0U;
+ }
+
+ return xNextExpireTime;
+}
+/*-----------------------------------------------------------*/
+
+static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
+{
+portTickType xTimeNow;
+static portTickType xLastTime = ( portTickType ) 0U;
+
+ xTimeNow = xTaskGetTickCount();
+
+ if( xTimeNow < xLastTime )
+ {
+ prvSwitchTimerLists( xLastTime );
+ *pxTimerListsWereSwitched = pdTRUE;
+ }
+ else
+ {
+ *pxTimerListsWereSwitched = pdFALSE;
+ }
+
+ xLastTime = xTimeNow;
+
+ return xTimeNow;
+}
+/*-----------------------------------------------------------*/
+
+static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )
+{
+portBASE_TYPE xProcessTimerNow = pdFALSE;
+
+ listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
+ listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
+
+ if( xNextExpiryTime <= xTimeNow )
+ {
+ /* Has the expiry time elapsed between the command to start/reset a
+ timer was issued, and the time the command was processed? */
+ if( ( ( portTickType ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks )
+ {
+ /* The time between a command being issued and the command being
+ processed actually exceeds the timers period. */
+ xProcessTimerNow = pdTRUE;
+ }
+ else
+ {
+ vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
+ }
+ }
+ else
+ {
+ if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
+ {
+ /* If, since the command was issued, the tick count has overflowed
+ but the expiry time has not, then the timer must have already passed
+ its expiry time and should be processed immediately. */
+ xProcessTimerNow = pdTRUE;
+ }
+ else
+ {
+ vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
+ }
+ }
+
+ return xProcessTimerNow;
+}
+/*-----------------------------------------------------------*/
+
+static void prvProcessReceivedCommands( void )
+{
+xTIMER_MESSAGE xMessage;
+xTIMER *pxTimer;
+portBASE_TYPE xTimerListsWereSwitched, xResult;
+portTickType xTimeNow;
+
+ /* In this case the xTimerListsWereSwitched parameter is not used, but it
+ must be present in the function call. */
+ xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
+
+ while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
+ {
+ pxTimer = xMessage.pxTimer;
+
+ /* Is the timer already in a list of active timers? When the command
+ is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the
+ command is to the task rather than to an individual timer. */
+ if( pxTimer != NULL )
+ {
+ if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
+ {
+ /* The timer is in a list, remove it. */
+ vListRemove( &( pxTimer->xTimerListItem ) );
+ }
+ }
+
+ traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );
+
+ switch( xMessage.xMessageID )
+ {
+ case tmrCOMMAND_START :
+ /* Start or restart a timer. */
+ if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE )
+ {
+ /* The timer expired before it was added to the active timer
+ list. Process it now. */
+ pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
+
+ if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
+ {
+ xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
+ configASSERT( xResult );
+ ( void ) xResult;
+ }
+ }
+ break;
+
+ case tmrCOMMAND_STOP :
+ /* The timer has already been removed from the active list.
+ There is nothing to do here. */
+ break;
+
+ case tmrCOMMAND_CHANGE_PERIOD :
+ pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
+ configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
+ prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
+ break;
+
+ case tmrCOMMAND_DELETE :
+ /* The timer has already been removed from the active list,
+ just free up the memory. */
+ vPortFree( pxTimer );
+ break;
+
+ default :
+ /* Don't expect to get here. */
+ break;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSwitchTimerLists( portTickType xLastTime )
+{
+portTickType xNextExpireTime, xReloadTime;
+xList *pxTemp;
+xTIMER *pxTimer;
+portBASE_TYPE xResult;
+
+ /* Remove compiler warnings if configASSERT() is not defined. */
+ ( void ) xLastTime;
+
+ /* The tick count has overflowed. The timer lists must be switched.
+ If there are any timers still referenced from the current timer list
+ then they must have expired and should be processed before the lists
+ are switched. */
+ while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
+ {
+ xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
+
+ /* Remove the timer from the list. */
+ pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
+ vListRemove( &( pxTimer->xTimerListItem ) );
+
+ /* Execute its callback, then send a command to restart the timer if
+ it is an auto-reload timer. It cannot be restarted here as the lists
+ have not yet been switched. */
+ pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
+
+ if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
+ {
+ /* Calculate the reload value, and if the reload value results in
+ the timer going into the same timer list then it has already expired
+ and the timer should be re-inserted into the current list so it is
+ processed again within this loop. Otherwise a command should be sent
+ to restart the timer to ensure it is only inserted into a list after
+ the lists have been swapped. */
+ xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
+ if( xReloadTime > xNextExpireTime )
+ {
+ listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
+ listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
+ vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
+ }
+ else
+ {
+ xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
+ configASSERT( xResult );
+ ( void ) xResult;
+ }
+ }
+ }
+
+ pxTemp = pxCurrentTimerList;
+ pxCurrentTimerList = pxOverflowTimerList;
+ pxOverflowTimerList = pxTemp;
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckForValidListAndQueue( void )
+{
+ /* Check that the list from which active timers are referenced, and the
+ queue used to communicate with the timer service, have been
+ initialised. */
+ taskENTER_CRITICAL();
+ {
+ if( xTimerQueue == NULL )
+ {
+ vListInitialise( &xActiveTimerList1 );
+ vListInitialise( &xActiveTimerList2 );
+ pxCurrentTimerList = &xActiveTimerList1;
+ pxOverflowTimerList = &xActiveTimerList2;
+ xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
+ }
+ }
+ taskEXIT_CRITICAL();
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
+{
+portBASE_TYPE xTimerIsInActiveList;
+xTIMER *pxTimer = ( xTIMER * ) xTimer;
+
+ /* Is the timer in the list of active timers? */
+ taskENTER_CRITICAL();
+ {
+ /* Checking to see if it is in the NULL list in effect checks to see if
+ it is referenced from either the current or the overflow timer lists in
+ one go, but the logic has to be reversed, hence the '!'. */
+ xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
+ }
+ taskEXIT_CRITICAL();
+
+ return xTimerIsInActiveList;
+}
+/*-----------------------------------------------------------*/
+
+void *pvTimerGetTimerID( xTimerHandle xTimer )
+{
+xTIMER *pxTimer = ( xTIMER * ) xTimer;
+
+ return pxTimer->pvTimerID;
+}
+/*-----------------------------------------------------------*/
+
+/* This entire source file will be skipped if the application is not configured
+to include software timer functionality. If you want to include software timer
+functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
+#endif /* configUSE_TIMERS == 1 */
diff --git a/libraries/FreeRTOS/utility/timers.h b/libraries/FreeRTOS/utility/timers.h
new file mode 100755
index 0000000..f1bcb0d
--- /dev/null
+++ b/libraries/FreeRTOS/utility/timers.h
@@ -0,0 +1,936 @@
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS 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 General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#ifndef TIMERS_H
+#define TIMERS_H
+
+#ifndef INC_FREERTOS_H
+ #error "include FreeRTOS.h must appear in source files before include timers.h"
+#endif
+
+#include "portable.h"
+#include "list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* IDs for commands that can be sent/received on the timer queue. These are to
+be used solely through the macros that make up the public software timer API,
+as defined below. */
+#define tmrCOMMAND_START 0
+#define tmrCOMMAND_STOP 1
+#define tmrCOMMAND_CHANGE_PERIOD 2
+#define tmrCOMMAND_DELETE 3
+
+/*-----------------------------------------------------------
+ * MACROS AND DEFINITIONS
+ *----------------------------------------------------------*/
+
+ /**
+ * Type by which software timers are referenced. For example, a call to
+ * xTimerCreate() returns an xTimerHandle variable that can then be used to
+ * reference the subject timer in calls to other software timer API functions
+ * (for example, xTimerStart(), xTimerReset(), etc.).
+ */
+typedef void * xTimerHandle;
+
+/* Define the prototype to which timer callback functions must conform. */
+typedef void (*tmrTIMER_CALLBACK)( xTimerHandle xTimer );
+
+/**
+ * xTimerHandle xTimerCreate( const signed char *pcTimerName,
+ * portTickType xTimerPeriod,
+ * unsigned portBASE_TYPE uxAutoReload,
+ * void * pvTimerID,
+ * tmrTIMER_CALLBACK pxCallbackFunction );
+ *
+ * Creates a new software timer instance. This allocates the storage required
+ * by the new timer, initialises the new timers internal state, and returns a
+ * handle by which the new timer can be referenced.
+ *
+ * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
+ * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
+ * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the
+ * active state.
+ *
+ * @param pcTimerName A text name that is assigned to the timer. This is done
+ * purely to assist debugging. The kernel itself only ever references a timer by
+ * its handle, and never by its name.
+ *
+ * @param xTimerPeriod The timer period. The time is defined in tick periods so
+ * the constant portTICK_RATE_MS can be used to convert a time that has been
+ * specified in milliseconds. For example, if the timer must expire after 100
+ * ticks, then xTimerPeriod should be set to 100. Alternatively, if the timer
+ * must expire after 500ms, then xPeriod can be set to ( 500 / portTICK_RATE_MS )
+ * provided configTICK_RATE_HZ is less than or equal to 1000.
+ *
+ * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will
+ * expire repeatedly with a frequency set by the xTimerPeriod parameter. If
+ * uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and
+ * enter the dormant state after it expires.
+ *
+ * @param pvTimerID An identifier that is assigned to the timer being created.
+ * Typically this would be used in the timer callback function to identify which
+ * timer expired when the same callback function is assigned to more than one
+ * timer.
+ *
+ * @param pxCallbackFunction The function to call when the timer expires.
+ * Callback functions must have the prototype defined by tmrTIMER_CALLBACK,
+ * which is "void vCallbackFunction( xTIMER *xTimer );".
+ *
+ * @return If the timer is successfully create then a handle to the newly
+ * created timer is returned. If the timer cannot be created (because either
+ * there is insufficient FreeRTOS heap remaining to allocate the timer
+ * structures, or the timer period was set to 0) then 0 is returned.
+ *
+ * Example usage:
+ *
+ *
+ * #define NUM_TIMERS 5
+ *
+ * // An array to hold handles to the created timers.
+ * xTimerHandle xTimers[ NUM_TIMERS ];
+ *
+ * // An array to hold a count of the number of times each timer expires.
+ * long lExpireCounters[ NUM_TIMERS ] = { 0 };
+ *
+ * // Define a callback function that will be used by multiple timer instances.
+ * // The callback function does nothing but count the number of times the
+ * // associated timer expires, and stop the timer once the timer has expired
+ * // 10 times.
+ * void vTimerCallback( xTIMER *pxTimer )
+ * {
+ * long lArrayIndex;
+ * const long xMaxExpiryCountBeforeStopping = 10;
+ *
+ * // Optionally do something if the pxTimer parameter is NULL.
+ * configASSERT( pxTimer );
+ *
+ * // Which timer expired?
+ * lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer );
+ *
+ * // Increment the number of times that pxTimer has expired.
+ * lExpireCounters[ lArrayIndex ] += 1;
+ *
+ * // If the timer has expired 10 times then stop it from running.
+ * if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping )
+ * {
+ * // Do not use a block time if calling a timer API function from a
+ * // timer callback function, as doing so could cause a deadlock!
+ * xTimerStop( pxTimer, 0 );
+ * }
+ * }
+ *
+ * void main( void )
+ * {
+ * long x;
+ *
+ * // Create then start some timers. Starting the timers before the scheduler
+ * // has been started means the timers will start running immediately that
+ * // the scheduler starts.
+ * for( x = 0; x < NUM_TIMERS; x++ )
+ * {
+ * xTimers[ x ] = xTimerCreate( "Timer", // Just a text name, not used by the kernel.
+ * ( 100 * x ), // The timer period in ticks.
+ * pdTRUE, // The timers will auto-reload themselves when they expire.
+ * ( void * ) x, // Assign each timer a unique id equal to its array index.
+ * vTimerCallback // Each timer calls the same callback when it expires.
+ * );
+ *
+ * if( xTimers[ x ] == NULL )
+ * {
+ * // The timer was not created.
+ * }
+ * else
+ * {
+ * // Start the timer. No block time is specified, and even if one was
+ * // it would be ignored because the scheduler has not yet been
+ * // started.
+ * if( xTimerStart( xTimers[ x ], 0 ) != pdPASS )
+ * {
+ * // The timer could not be set into the Active state.
+ * }
+ * }
+ * }
+ *
+ * // ...
+ * // Create tasks here.
+ * // ...
+ *
+ * // Starting the scheduler will start the timers running as they have already
+ * // been set into the active state.
+ * xTaskStartScheduler();
+ *
+ * // Should not reach here.
+ * for( ;; );
+ * }
+ */
+xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void * pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction ) PRIVILEGED_FUNCTION;
+
+/**
+ * void *pvTimerGetTimerID( xTimerHandle xTimer );
+ *
+ * Returns the ID assigned to the timer.
+ *
+ * IDs are assigned to timers using the pvTimerID parameter of the call to
+ * xTimerCreated() that was used to create the timer.
+ *
+ * If the same callback function is assigned to multiple timers then the timer
+ * ID can be used within the callback function to identify which timer actually
+ * expired.
+ *
+ * @param xTimer The timer being queried.
+ *
+ * @return The ID assigned to the timer being queried.
+ *
+ * Example usage:
+ *
+ * See the xTimerCreate() API function example usage scenario.
+ */
+void *pvTimerGetTimerID( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;
+
+/**
+ * portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer );
+ *
+ * Queries a timer to see if it is active or dormant.
+ *
+ * A timer will be dormant if:
+ * 1) It has been created but not started, or
+ * 2) It is an expired on-shot timer that has not been restarted.
+ *
+ * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
+ * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
+ * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the
+ * active state.
+ *
+ * @param xTimer The timer being queried.
+ *
+ * @return pdFALSE will be returned if the timer is dormant. A value other than
+ * pdFALSE will be returned if the timer is active.
+ *
+ * Example usage:
+ *
+ * // This function assumes xTimer has already been created.
+ * void vAFunction( xTimerHandle xTimer )
+ * {
+ * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"
+ * {
+ * // xTimer is active, do something.
+ * }
+ * else
+ * {
+ * // xTimer is not active, do something else.
+ * }
+ * }
+ */
+portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;
+
+/**
+ * portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerStart() starts a timer that was previously created using the
+ * xTimerCreate() API function. If the timer had already been started and was
+ * already in the active state, then xTimerStart() has equivalent functionality
+ * to the xTimerReset() API function.
+ *
+ * Starting a timer ensures the timer is in the active state. If the timer
+ * is not stopped, deleted, or reset in the mean time, the callback function
+ * associated with the timer will get called 'n' ticks after xTimerStart() was
+ * called, where 'n' is the timers defined period.
+ *
+ * It is valid to call xTimerStart() before the scheduler has been started, but
+ * when this is done the timer will not actually start until the scheduler is
+ * started, and the timers expiry time will be relative to when the scheduler is
+ * started, not relative to when xTimerStart() was called.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStart()
+ * to be available.
+ *
+ * @param xTimer The handle of the timer being started/restarted.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the start command to be successfully
+ * sent to the timer command queue, should the queue already be full when
+ * xTimerStart() was called. xBlockTime is ignored if xTimerStart() is called
+ * before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the start command could not be sent to
+ * the timer command queue even after xBlockTime ticks had passed. pdPASS will
+ * be returned if the command was successfully sent to the timer command queue.
+ * When the command is actually processed will depend on the priority of the
+ * timer service/daemon task relative to other tasks in the system, although the
+ * timers expiry time is relative to when xTimerStart() is actually called. The
+ * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
+ * configuration constant.
+ *
+ * Example usage:
+ *
+ * See the xTimerCreate() API function example usage scenario.
+ *
+ */
+#define xTimerStart( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerStop( xTimerHandle xTimer, portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerStop() stops a timer that was previously started using either of the
+ * The xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(),
+ * xTimerChangePeriod() or xTimerChangePeriodFromISR() API functions.
+ *
+ * Stopping a timer ensures the timer is not in the active state.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStop()
+ * to be available.
+ *
+ * @param xTimer The handle of the timer being stopped.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the stop command to be successfully
+ * sent to the timer command queue, should the queue already be full when
+ * xTimerStop() was called. xBlockTime is ignored if xTimerStop() is called
+ * before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the stop command could not be sent to
+ * the timer command queue even after xBlockTime ticks had passed. pdPASS will
+ * be returned if the command was successfully sent to the timer command queue.
+ * When the command is actually processed will depend on the priority of the
+ * timer service/daemon task relative to other tasks in the system. The timer
+ * service/daemon task priority is set by the configTIMER_TASK_PRIORITY
+ * configuration constant.
+ *
+ * Example usage:
+ *
+ * See the xTimerCreate() API function example usage scenario.
+ *
+ */
+#define xTimerStop( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerChangePeriod( xTimerHandle xTimer,
+ * portTickType xNewPeriod,
+ * portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerChangePeriod() changes the period of a timer that was previously
+ * created using the xTimerCreate() API function.
+ *
+ * xTimerChangePeriod() can be called to change the period of an active or
+ * dormant state timer.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for
+ * xTimerChangePeriod() to be available.
+ *
+ * @param xTimer The handle of the timer that is having its period changed.
+ *
+ * @param xNewPeriod The new period for xTimer. Timer periods are specified in
+ * tick periods, so the constant portTICK_RATE_MS can be used to convert a time
+ * that has been specified in milliseconds. For example, if the timer must
+ * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively,
+ * if the timer must expire after 500ms, then xNewPeriod can be set to
+ * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than
+ * or equal to 1000.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the change period command to be
+ * successfully sent to the timer command queue, should the queue already be
+ * full when xTimerChangePeriod() was called. xBlockTime is ignored if
+ * xTimerChangePeriod() is called before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the change period command could not be
+ * sent to the timer command queue even after xBlockTime ticks had passed.
+ * pdPASS will be returned if the command was successfully sent to the timer
+ * command queue. When the command is actually processed will depend on the
+ * priority of the timer service/daemon task relative to other tasks in the
+ * system. The timer service/daemon task priority is set by the
+ * configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This function assumes xTimer has already been created. If the timer
+ * // referenced by xTimer is already active when it is called, then the timer
+ * // is deleted. If the timer referenced by xTimer is not active when it is
+ * // called, then the period of the timer is set to 500ms and the timer is
+ * // started.
+ * void vAFunction( xTimerHandle xTimer )
+ * {
+ * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"
+ * {
+ * // xTimer is already active - delete it.
+ * xTimerDelete( xTimer );
+ * }
+ * else
+ * {
+ * // xTimer is not active, change its period to 500ms. This will also
+ * // cause the timer to start. Block for a maximum of 100 ticks if the
+ * // change period command cannot immediately be sent to the timer
+ * // command queue.
+ * if( xTimerChangePeriod( xTimer, 500 / portTICK_RATE_MS, 100 ) == pdPASS )
+ * {
+ * // The command was successfully sent.
+ * }
+ * else
+ * {
+ * // The command could not be sent, even after waiting for 100 ticks
+ * // to pass. Take appropriate action here.
+ * }
+ * }
+ * }
+ */
+ #define xTimerChangePeriod( xTimer, xNewPeriod, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerDelete( xTimerHandle xTimer, portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerDelete() deletes a timer that was previously created using the
+ * xTimerCreate() API function.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for
+ * xTimerDelete() to be available.
+ *
+ * @param xTimer The handle of the timer being deleted.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the delete command to be
+ * successfully sent to the timer command queue, should the queue already be
+ * full when xTimerDelete() was called. xBlockTime is ignored if xTimerDelete()
+ * is called before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the delete command could not be sent to
+ * the timer command queue even after xBlockTime ticks had passed. pdPASS will
+ * be returned if the command was successfully sent to the timer command queue.
+ * When the command is actually processed will depend on the priority of the
+ * timer service/daemon task relative to other tasks in the system. The timer
+ * service/daemon task priority is set by the configTIMER_TASK_PRIORITY
+ * configuration constant.
+ *
+ * Example usage:
+ *
+ * See the xTimerChangePeriod() API function example usage scenario.
+ */
+#define xTimerDelete( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerReset( xTimerHandle xTimer, portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerReset() re-starts a timer that was previously created using the
+ * xTimerCreate() API function. If the timer had already been started and was
+ * already in the active state, then xTimerReset() will cause the timer to
+ * re-evaluate its expiry time so that it is relative to when xTimerReset() was
+ * called. If the timer was in the dormant state then xTimerReset() has
+ * equivalent functionality to the xTimerStart() API function.
+ *
+ * Resetting a timer ensures the timer is in the active state. If the timer
+ * is not stopped, deleted, or reset in the mean time, the callback function
+ * associated with the timer will get called 'n' ticks after xTimerReset() was
+ * called, where 'n' is the timers defined period.
+ *
+ * It is valid to call xTimerReset() before the scheduler has been started, but
+ * when this is done the timer will not actually start until the scheduler is
+ * started, and the timers expiry time will be relative to when the scheduler is
+ * started, not relative to when xTimerReset() was called.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for xTimerReset()
+ * to be available.
+ *
+ * @param xTimer The handle of the timer being reset/started/restarted.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the reset command to be successfully
+ * sent to the timer command queue, should the queue already be full when
+ * xTimerReset() was called. xBlockTime is ignored if xTimerReset() is called
+ * before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the reset command could not be sent to
+ * the timer command queue even after xBlockTime ticks had passed. pdPASS will
+ * be returned if the command was successfully sent to the timer command queue.
+ * When the command is actually processed will depend on the priority of the
+ * timer service/daemon task relative to other tasks in the system, although the
+ * timers expiry time is relative to when xTimerStart() is actually called. The
+ * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
+ * configuration constant.
+ *
+ * Example usage:
+ *
+ * // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass
+ * // without a key being pressed, then the LCD back-light is switched off. In
+ * // this case, the timer is a one-shot timer.
+ *
+ * xTimerHandle xBacklightTimer = NULL;
+ *
+ * // The callback function assigned to the one-shot timer. In this case the
+ * // parameter is not used.
+ * void vBacklightTimerCallback( xTIMER *pxTimer )
+ * {
+ * // The timer expired, therefore 5 seconds must have passed since a key
+ * // was pressed. Switch off the LCD back-light.
+ * vSetBacklightState( BACKLIGHT_OFF );
+ * }
+ *
+ * // The key press event handler.
+ * void vKeyPressEventHandler( char cKey )
+ * {
+ * // Ensure the LCD back-light is on, then reset the timer that is
+ * // responsible for turning the back-light off after 5 seconds of
+ * // key inactivity. Wait 10 ticks for the command to be successfully sent
+ * // if it cannot be sent immediately.
+ * vSetBacklightState( BACKLIGHT_ON );
+ * if( xTimerReset( xBacklightTimer, 100 ) != pdPASS )
+ * {
+ * // The reset command was not executed successfully. Take appropriate
+ * // action here.
+ * }
+ *
+ * // Perform the rest of the key processing here.
+ * }
+ *
+ * void main( void )
+ * {
+ * long x;
+ *
+ * // Create then start the one-shot timer that is responsible for turning
+ * // the back-light off if no keys are pressed within a 5 second period.
+ * xBacklightTimer = xTimerCreate( "BacklightTimer", // Just a text name, not used by the kernel.
+ * ( 5000 / portTICK_RATE_MS), // The timer period in ticks.
+ * pdFALSE, // The timer is a one-shot timer.
+ * 0, // The id is not used by the callback so can take any value.
+ * vBacklightTimerCallback // The callback function that switches the LCD back-light off.
+ * );
+ *
+ * if( xBacklightTimer == NULL )
+ * {
+ * // The timer was not created.
+ * }
+ * else
+ * {
+ * // Start the timer. No block time is specified, and even if one was
+ * // it would be ignored because the scheduler has not yet been
+ * // started.
+ * if( xTimerStart( xBacklightTimer, 0 ) != pdPASS )
+ * {
+ * // The timer could not be set into the Active state.
+ * }
+ * }
+ *
+ * // ...
+ * // Create tasks here.
+ * // ...
+ *
+ * // Starting the scheduler will start the timer running as it has already
+ * // been set into the active state.
+ * xTaskStartScheduler();
+ *
+ * // Should not reach here.
+ * for( ;; );
+ * }
+ */
+#define xTimerReset( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerStartFromISR( xTimerHandle xTimer,
+ * portBASE_TYPE *pxHigherPriorityTaskWoken );
+ *
+ * A version of xTimerStart() that can be called from an interrupt service
+ * routine.
+ *
+ * @param xTimer The handle of the timer being started/restarted.
+ *
+ * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
+ * of its time in the Blocked state, waiting for messages to arrive on the timer
+ * command queue. Calling xTimerStartFromISR() writes a message to the timer
+ * command queue, so has the potential to transition the timer service/daemon
+ * task out of the Blocked state. If calling xTimerStartFromISR() causes the
+ * timer service/daemon task to leave the Blocked state, and the timer service/
+ * daemon task has a priority equal to or greater than the currently executing
+ * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
+ * get set to pdTRUE internally within the xTimerStartFromISR() function. If
+ * xTimerStartFromISR() sets this value to pdTRUE then a context switch should
+ * be performed before the interrupt exits.
+ *
+ * @return pdFAIL will be returned if the start command could not be sent to
+ * the timer command queue. pdPASS will be returned if the command was
+ * successfully sent to the timer command queue. When the command is actually
+ * processed will depend on the priority of the timer service/daemon task
+ * relative to other tasks in the system, although the timers expiry time is
+ * relative to when xTimerStartFromISR() is actually called. The timer service/daemon
+ * task priority is set by the configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This scenario assumes xBacklightTimer has already been created. When a
+ * // key is pressed, an LCD back-light is switched on. If 5 seconds pass
+ * // without a key being pressed, then the LCD back-light is switched off. In
+ * // this case, the timer is a one-shot timer, and unlike the example given for
+ * // the xTimerReset() function, the key press event handler is an interrupt
+ * // service routine.
+ *
+ * // The callback function assigned to the one-shot timer. In this case the
+ * // parameter is not used.
+ * void vBacklightTimerCallback( xTIMER *pxTimer )
+ * {
+ * // The timer expired, therefore 5 seconds must have passed since a key
+ * // was pressed. Switch off the LCD back-light.
+ * vSetBacklightState( BACKLIGHT_OFF );
+ * }
+ *
+ * // The key press interrupt service routine.
+ * void vKeyPressEventInterruptHandler( void )
+ * {
+ * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+ *
+ * // Ensure the LCD back-light is on, then restart the timer that is
+ * // responsible for turning the back-light off after 5 seconds of
+ * // key inactivity. This is an interrupt service routine so can only
+ * // call FreeRTOS API functions that end in "FromISR".
+ * vSetBacklightState( BACKLIGHT_ON );
+ *
+ * // xTimerStartFromISR() or xTimerResetFromISR() could be called here
+ * // as both cause the timer to re-calculate its expiry time.
+ * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was
+ * // declared (in this function).
+ * if( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS )
+ * {
+ * // The start command was not executed successfully. Take appropriate
+ * // action here.
+ * }
+ *
+ * // Perform the rest of the key processing here.
+ *
+ * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
+ * // should be performed. The syntax required to perform a context switch
+ * // from inside an ISR varies from port to port, and from compiler to
+ * // compiler. Inspect the demos for the port you are using to find the
+ * // actual syntax required.
+ * if( xHigherPriorityTaskWoken != pdFALSE )
+ * {
+ * // Call the interrupt safe yield function here (actual function
+ * // depends on the FreeRTOS port being used.
+ * }
+ * }
+ */
+#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
+
+/**
+ * portBASE_TYPE xTimerStopFromISR( xTimerHandle xTimer,
+ * portBASE_TYPE *pxHigherPriorityTaskWoken );
+ *
+ * A version of xTimerStop() that can be called from an interrupt service
+ * routine.
+ *
+ * @param xTimer The handle of the timer being stopped.
+ *
+ * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
+ * of its time in the Blocked state, waiting for messages to arrive on the timer
+ * command queue. Calling xTimerStopFromISR() writes a message to the timer
+ * command queue, so has the potential to transition the timer service/daemon
+ * task out of the Blocked state. If calling xTimerStopFromISR() causes the
+ * timer service/daemon task to leave the Blocked state, and the timer service/
+ * daemon task has a priority equal to or greater than the currently executing
+ * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
+ * get set to pdTRUE internally within the xTimerStopFromISR() function. If
+ * xTimerStopFromISR() sets this value to pdTRUE then a context switch should
+ * be performed before the interrupt exits.
+ *
+ * @return pdFAIL will be returned if the stop command could not be sent to
+ * the timer command queue. pdPASS will be returned if the command was
+ * successfully sent to the timer command queue. When the command is actually
+ * processed will depend on the priority of the timer service/daemon task
+ * relative to other tasks in the system. The timer service/daemon task
+ * priority is set by the configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This scenario assumes xTimer has already been created and started. When
+ * // an interrupt occurs, the timer should be simply stopped.
+ *
+ * // The interrupt service routine that stops the timer.
+ * void vAnExampleInterruptServiceRoutine( void )
+ * {
+ * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+ *
+ * // The interrupt has occurred - simply stop the timer.
+ * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined
+ * // (within this function). As this is an interrupt service routine, only
+ * // FreeRTOS API functions that end in "FromISR" can be used.
+ * if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )
+ * {
+ * // The stop command was not executed successfully. Take appropriate
+ * // action here.
+ * }
+ *
+ * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
+ * // should be performed. The syntax required to perform a context switch
+ * // from inside an ISR varies from port to port, and from compiler to
+ * // compiler. Inspect the demos for the port you are using to find the
+ * // actual syntax required.
+ * if( xHigherPriorityTaskWoken != pdFALSE )
+ * {
+ * // Call the interrupt safe yield function here (actual function
+ * // depends on the FreeRTOS port being used.
+ * }
+ * }
+ */
+#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0, ( pxHigherPriorityTaskWoken ), 0U )
+
+/**
+ * portBASE_TYPE xTimerChangePeriodFromISR( xTimerHandle xTimer,
+ * portTickType xNewPeriod,
+ * portBASE_TYPE *pxHigherPriorityTaskWoken );
+ *
+ * A version of xTimerChangePeriod() that can be called from an interrupt
+ * service routine.
+ *
+ * @param xTimer The handle of the timer that is having its period changed.
+ *
+ * @param xNewPeriod The new period for xTimer. Timer periods are specified in
+ * tick periods, so the constant portTICK_RATE_MS can be used to convert a time
+ * that has been specified in milliseconds. For example, if the timer must
+ * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively,
+ * if the timer must expire after 500ms, then xNewPeriod can be set to
+ * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than
+ * or equal to 1000.
+ *
+ * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
+ * of its time in the Blocked state, waiting for messages to arrive on the timer
+ * command queue. Calling xTimerChangePeriodFromISR() writes a message to the
+ * timer command queue, so has the potential to transition the timer service/
+ * daemon task out of the Blocked state. If calling xTimerChangePeriodFromISR()
+ * causes the timer service/daemon task to leave the Blocked state, and the
+ * timer service/daemon task has a priority equal to or greater than the
+ * currently executing task (the task that was interrupted), then
+ * *pxHigherPriorityTaskWoken will get set to pdTRUE internally within the
+ * xTimerChangePeriodFromISR() function. If xTimerChangePeriodFromISR() sets
+ * this value to pdTRUE then a context switch should be performed before the
+ * interrupt exits.
+ *
+ * @return pdFAIL will be returned if the command to change the timers period
+ * could not be sent to the timer command queue. pdPASS will be returned if the
+ * command was successfully sent to the timer command queue. When the command
+ * is actually processed will depend on the priority of the timer service/daemon
+ * task relative to other tasks in the system. The timer service/daemon task
+ * priority is set by the configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This scenario assumes xTimer has already been created and started. When
+ * // an interrupt occurs, the period of xTimer should be changed to 500ms.
+ *
+ * // The interrupt service routine that changes the period of xTimer.
+ * void vAnExampleInterruptServiceRoutine( void )
+ * {
+ * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+ *
+ * // The interrupt has occurred - change the period of xTimer to 500ms.
+ * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined
+ * // (within this function). As this is an interrupt service routine, only
+ * // FreeRTOS API functions that end in "FromISR" can be used.
+ * if( xTimerChangePeriodFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )
+ * {
+ * // The command to change the timers period was not executed
+ * // successfully. Take appropriate action here.
+ * }
+ *
+ * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
+ * // should be performed. The syntax required to perform a context switch
+ * // from inside an ISR varies from port to port, and from compiler to
+ * // compiler. Inspect the demos for the port you are using to find the
+ * // actual syntax required.
+ * if( xHigherPriorityTaskWoken != pdFALSE )
+ * {
+ * // Call the interrupt safe yield function here (actual function
+ * // depends on the FreeRTOS port being used.
+ * }
+ * }
+ */
+#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U )
+
+/**
+ * portBASE_TYPE xTimerResetFromISR( xTimerHandle xTimer,
+ * portBASE_TYPE *pxHigherPriorityTaskWoken );
+ *
+ * A version of xTimerReset() that can be called from an interrupt service
+ * routine.
+ *
+ * @param xTimer The handle of the timer that is to be started, reset, or
+ * restarted.
+ *
+ * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
+ * of its time in the Blocked state, waiting for messages to arrive on the timer
+ * command queue. Calling xTimerResetFromISR() writes a message to the timer
+ * command queue, so has the potential to transition the timer service/daemon
+ * task out of the Blocked state. If calling xTimerResetFromISR() causes the
+ * timer service/daemon task to leave the Blocked state, and the timer service/
+ * daemon task has a priority equal to or greater than the currently executing
+ * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
+ * get set to pdTRUE internally within the xTimerResetFromISR() function. If
+ * xTimerResetFromISR() sets this value to pdTRUE then a context switch should
+ * be performed before the interrupt exits.
+ *
+ * @return pdFAIL will be returned if the reset command could not be sent to
+ * the timer command queue. pdPASS will be returned if the command was
+ * successfully sent to the timer command queue. When the command is actually
+ * processed will depend on the priority of the timer service/daemon task
+ * relative to other tasks in the system, although the timers expiry time is
+ * relative to when xTimerResetFromISR() is actually called. The timer service/daemon
+ * task priority is set by the configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This scenario assumes xBacklightTimer has already been created. When a
+ * // key is pressed, an LCD back-light is switched on. If 5 seconds pass
+ * // without a key being pressed, then the LCD back-light is switched off. In
+ * // this case, the timer is a one-shot timer, and unlike the example given for
+ * // the xTimerReset() function, the key press event handler is an interrupt
+ * // service routine.
+ *
+ * // The callback function assigned to the one-shot timer. In this case the
+ * // parameter is not used.
+ * void vBacklightTimerCallback( xTIMER *pxTimer )
+ * {
+ * // The timer expired, therefore 5 seconds must have passed since a key
+ * // was pressed. Switch off the LCD back-light.
+ * vSetBacklightState( BACKLIGHT_OFF );
+ * }
+ *
+ * // The key press interrupt service routine.
+ * void vKeyPressEventInterruptHandler( void )
+ * {
+ * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+ *
+ * // Ensure the LCD back-light is on, then reset the timer that is
+ * // responsible for turning the back-light off after 5 seconds of
+ * // key inactivity. This is an interrupt service routine so can only
+ * // call FreeRTOS API functions that end in "FromISR".
+ * vSetBacklightState( BACKLIGHT_ON );
+ *
+ * // xTimerStartFromISR() or xTimerResetFromISR() could be called here
+ * // as both cause the timer to re-calculate its expiry time.
+ * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was
+ * // declared (in this function).
+ * if( xTimerResetFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS )
+ * {
+ * // The reset command was not executed successfully. Take appropriate
+ * // action here.
+ * }
+ *
+ * // Perform the rest of the key processing here.
+ *
+ * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
+ * // should be performed. The syntax required to perform a context switch
+ * // from inside an ISR varies from port to port, and from compiler to
+ * // compiler. Inspect the demos for the port you are using to find the
+ * // actual syntax required.
+ * if( xHigherPriorityTaskWoken != pdFALSE )
+ * {
+ * // Call the interrupt safe yield function here (actual function
+ * // depends on the FreeRTOS port being used.
+ * }
+ * }
+ */
+#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
+
+/*
+ * Functions beyond this part are not part of the public API and are intended
+ * for use by the kernel only.
+ */
+portBASE_TYPE xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION;
+portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) PRIVILEGED_FUNCTION;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* TIMERS_H */
+
+
+
diff --git a/libraries/LiquidCrystal/LiquidCrystal.cpp b/libraries/LiquidCrystal/LiquidCrystal.cpp
new file mode 100644
index 0000000..5cfb1ca
--- /dev/null
+++ b/libraries/LiquidCrystal/LiquidCrystal.cpp
@@ -0,0 +1,333 @@
+#include "LiquidCrystal.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <wirish/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;
+
+ for (int i = 0; i < 8 - fourbitmode * 4; i++) {
+ pinMode(_data_pins[i], OUTPUT);
+ }
+
+ 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) {
+ // _enable_pin should already be LOW (unless someone else messed
+ // with it), so don't sit around waiting for long.
+ digitalWrite(_enable_pin, LOW);
+ delayMicroseconds(1);
+
+ // Enable pulse must be > 450 ns. Value chosen here according to
+ // the following threads:
+ // http://forums.leaflabs.com/topic.php?id=640
+ // http://forums.leaflabs.com/topic.php?id=512
+ togglePin(_enable_pin);
+ delayMicroseconds(1);
+ togglePin(_enable_pin);
+
+ // Commands needs > 37us to settle.
+ delayMicroseconds(42);
+}
+
+void LiquidCrystal::write4bits(uint8 value) {
+ for (int i = 0; i < 4; i++) {
+ digitalWrite(_data_pins[i], (value >> i) & 0x01);
+ }
+
+ pulseEnable();
+}
+
+void LiquidCrystal::write8bits(uint8 value) {
+ for (int i = 0; i < 8; i++) {
+ 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..06a159d
--- /dev/null
+++ b/libraries/LiquidCrystal/LiquidCrystal.h
@@ -0,0 +1,105 @@
+#ifndef LiquidCrystal_h
+#define LiquidCrystal_h
+
+//#include <inttypes.h>
+#include <wirish/wirish.h>
+#include <wirish/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..ecb85e6
--- /dev/null
+++ b/libraries/Servo/Servo.cpp
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * 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 <wirish/boards.h>
+#include <wirish/io.h>
+#include <wirish/pwm.h>
+#include <wirish/wirish_math.h>
+
+// 20 millisecond period config. For a 1-based prescaler,
+//
+// (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec
+// => prescaler * overflow = 20 * CYC_MSEC
+//
+// This picks the smallest prescaler that allows an overflow < 2^16.
+#define MAX_OVERFLOW ((1 << 16) - 1)
+#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
+#define TAU_MSEC 20
+#define TAU_USEC (TAU_MSEC * 1000)
+#define TAU_CYC (TAU_MSEC * CYC_MSEC)
+#define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1)
+#define SERVO_OVERFLOW ((uint16)round((double)TAU_CYC / SERVO_PRESCALER))
+
+// Unit conversions
+#define US_TO_COMPARE(us) ((uint16)map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW))
+#define COMPARE_TO_US(c) ((uint32)map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC))
+#define ANGLE_TO_US(a) ((uint16)(map((a), this->minAngle, this->maxAngle, \
+ this->minPW, this->maxPW)))
+#define US_TO_ANGLE(us) ((int16)(map((us), this->minPW, this->maxPW, \
+ this->minAngle, this->maxAngle)))
+
+Servo::Servo() {
+ this->resetFields();
+}
+
+bool Servo::attach(uint8 pin,
+ uint16 minPW,
+ uint16 maxPW,
+ int16 minAngle,
+ int16 maxAngle) {
+ timer_dev *tdev = PIN_MAP[pin].timer_device;
+
+ if (tdev == NULL) {
+ // don't reset any fields or ASSERT(0), to keep driving any
+ // previously attach()ed servo.
+ return false;
+ }
+
+ if (this->attached()) {
+ this->detach();
+ }
+
+ this->pin = pin;
+ this->minPW = minPW;
+ this->maxPW = maxPW;
+ this->minAngle = minAngle;
+ this->maxAngle = maxAngle;
+
+ pinMode(pin, PWM);
+
+ timer_pause(tdev);
+ timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based
+ timer_set_reload(tdev, SERVO_OVERFLOW);
+ timer_generate_update(tdev);
+ timer_resume(tdev);
+
+ return true;
+}
+
+bool Servo::detach() {
+ if (!this->attached()) {
+ return false;
+ }
+
+ timer_dev *tdev = PIN_MAP[this->pin].timer_device;
+ uint8 tchan = PIN_MAP[this->pin].timer_channel;
+ timer_set_mode(tdev, tchan, TIMER_DISABLED);
+
+ this->resetFields();
+
+ return true;
+}
+
+void Servo::write(int degrees) {
+ degrees = constrain(degrees, this->minAngle, this->maxAngle);
+ this->writeMicroseconds(ANGLE_TO_US(degrees));
+}
+
+int Servo::read() const {
+ int a = US_TO_ANGLE(this->readMicroseconds());
+ // map() round-trips in a weird way we mostly correct for here;
+ // the round-trip is still sometimes off-by-one for write(1) and
+ // write(179).
+ return a == this->minAngle || a == this->maxAngle ? a : a + 1;
+}
+
+void Servo::writeMicroseconds(uint16 pulseWidth) {
+ if (!this->attached()) {
+ ASSERT(0);
+ return;
+ }
+
+ pulseWidth = constrain(pulseWidth, this->minPW, this->maxPW);
+ pwmWrite(this->pin, US_TO_COMPARE(pulseWidth));
+}
+
+uint16 Servo::readMicroseconds() const {
+ if (!this->attached()) {
+ ASSERT(0);
+ return 0;
+ }
+
+ stm32_pin_info pin_info = PIN_MAP[this->pin];
+ uint16 compare = timer_get_compare(pin_info.timer_device,
+ pin_info.timer_channel);
+
+ return COMPARE_TO_US(compare);
+}
+
+void Servo::resetFields(void) {
+ this->pin = NOT_ATTACHED;
+ this->minAngle = SERVO_DEFAULT_MIN_ANGLE;
+ this->maxAngle = SERVO_DEFAULT_MAX_ANGLE;
+ this->minPW = SERVO_DEFAULT_MIN_PW;
+ this->maxPW = SERVO_DEFAULT_MAX_PW;
+}
diff --git a/libraries/Servo/Servo.h b/libraries/Servo/Servo.h
new file mode 100644
index 0000000..94e1e00
--- /dev/null
+++ b/libraries/Servo/Servo.h
@@ -0,0 +1,196 @@
+/******************************************************************************
+ * 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 <libmaple/libmaple_types.h>
+#include <libmaple/timer.h>
+
+#include <wirish/wirish_types.h>
+
+/*
+ * 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 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, your board's pin map is your friend.
+ */
+
+// Pin number of unattached pins
+#define NOT_ATTACHED (-1)
+
+// Default min/max pulse widths (in microseconds) and angles (in
+// degrees). Values chosen for Arduino compatibility. These values
+// are part of the public API; DO NOT CHANGE THEM.
+#define SERVO_DEFAULT_MIN_PW 544
+#define SERVO_DEFAULT_MAX_PW 2400
+#define SERVO_DEFAULT_MIN_ANGLE 0
+#define SERVO_DEFAULT_MAX_ANGLE 180
+
+/** Class for interfacing with RC servomotors. */
+class Servo {
+public:
+ /**
+ * @brief Construct a new Servo instance.
+ *
+ * The new instance will not be attached to any pin.
+ */
+ Servo();
+
+ /**
+ * @brief Associate this instance with a servomotor whose input is
+ * connected to pin.
+ *
+ * If this instance is already attached to a pin, it will be
+ * detached before being attached to the new pin. This function
+ * doesn't detach any interrupt attached with the pin's timer
+ * channel.
+ *
+ * @param pin Pin connected to the servo pulse wave input. This
+ * pin must be capable of PWM output.
+ *
+ * @param minPulseWidth Minimum pulse width to write to pin, in
+ * microseconds. This will be associated
+ * with a minAngle degree angle. Defaults to
+ * SERVO_DEFAULT_MIN_PW = 544.
+ *
+ * @param maxPulseWidth Maximum pulse width to write to pin, in
+ * microseconds. This will be associated
+ * with a maxAngle degree angle. Defaults to
+ * SERVO_DEFAULT_MAX_PW = 2400.
+ *
+ * @param minAngle Target angle (in degrees) associated with
+ * minPulseWidth. Defaults to
+ * SERVO_DEFAULT_MIN_ANGLE = 0.
+ *
+ * @param maxAngle Target angle (in degrees) associated with
+ * maxPulseWidth. Defaults to
+ * SERVO_DEFAULT_MAX_ANGLE = 180.
+ *
+ * @sideeffect May set pinMode(pin, PWM).
+ *
+ * @return true if successful, false when pin doesn't support PWM.
+ */
+ bool attach(uint8 pin,
+ uint16 minPulseWidth=SERVO_DEFAULT_MIN_PW,
+ uint16 maxPulseWidth=SERVO_DEFAULT_MAX_PW,
+ int16 minAngle=SERVO_DEFAULT_MIN_ANGLE,
+ int16 maxAngle=SERVO_DEFAULT_MAX_ANGLE);
+
+ /**
+ * @brief Check if this instance is attached to a servo.
+ * @return true if this instance is attached to a servo, false otherwise.
+ * @see Servo::attachedPin()
+ */
+ bool attached() const { return this->pin != NOT_ATTACHED; }
+
+ /**
+ * @brief Get the pin this instance is attached to.
+ * @return Pin number if currently attached to a pin, NOT_ATTACHED
+ * otherwise.
+ * @see Servo::attach()
+ */
+ int attachedPin() const { return this->pin; }
+
+ /**
+ * @brief Stop driving the servo pulse train.
+ *
+ * If not currently attached to a motor, this function has no effect.
+ *
+ * @return true if this call did anything, false otherwise.
+ */
+ bool detach();
+
+ /**
+ * @brief Set the servomotor target angle.
+ *
+ * @param angle Target angle, in degrees. If the target angle is
+ * outside the range specified at attach() time, it
+ * will be clamped to lie in that range.
+ *
+ * @see Servo::attach()
+ */
+ void write(int angle);
+
+
+ /**
+ * Get the servomotor's target angle, in degrees. This will
+ * lie inside the range specified at attach() time.
+ *
+ * @see Servo::attach()
+ */
+ int read() const;
+
+ /**
+ * @brief Set the pulse width, in microseconds.
+ *
+ * @param pulseWidth Pulse width to send to the servomotor, in
+ * microseconds. If outside of the range
+ * specified at attach() time, it is clamped to
+ * lie in that range.
+ *
+ * @see Servo::attach()
+ */
+ void writeMicroseconds(uint16 pulseWidth);
+
+ /**
+ * Get the current pulse width, in microseconds. This will
+ * lie within the range specified at attach() time.
+ *
+ * @see Servo::attach()
+ */
+ uint16 readMicroseconds() const;
+
+private:
+ int16 pin;
+ uint16 minPW;
+ uint16 maxPW;
+ int16 minAngle;
+ int16 maxAngle;
+
+ void resetFields(void);
+};
+
+#endif /* _SERVO_H_ */
diff --git a/libraries/Servo/rules.mk b/libraries/Servo/rules.mk
new file mode 100644
index 0000000..e013754
--- /dev/null
+++ b/libraries/Servo/rules.mk
@@ -0,0 +1,29 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CXXFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+
+# Local rules and targets
+cSRCS_$(d) :=
+
+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_CXXFLAGS := $(CXXFLAGS_$(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/HardWire.cpp b/libraries/Wire/HardWire.cpp
new file mode 100644
index 0000000..c2412f1
--- /dev/null
+++ b/libraries/Wire/HardWire.cpp
@@ -0,0 +1,66 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file HardWire.cpp
+ * @author Trystan Jones <crenn6977@gmail.com>
+ * @brief Wire library, uses the hardware I2C available in the Maple to
+ * interact with I2C slave devices.
+ */
+
+/*
+ * Library created by crenn to use the new WireBase system and allow Arduino
+ * users easy interaction with the I2C Hardware in a familiar method.
+ */
+
+#include <Wire/HardWire.h>
+
+uint8 HardWire::process() {
+ int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0);
+ if (res != 0) {
+ i2c_disable(sel_hard);
+ i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags));
+ }
+ return 0;
+}
+
+// TODO: Add in Error Handling if devsel is out of range for other Maples
+HardWire::HardWire(uint8 dev_sel, uint8 flags) {
+ if (dev_sel == 1) {
+ sel_hard = I2C1;
+ } else if (dev_sel == 2) {
+ sel_hard = I2C2;
+ } else {
+ ASSERT(1);
+ }
+ dev_flags=flags;
+ i2c_master_enable(sel_hard, flags);
+}
+
+HardWire::~HardWire() {
+ i2c_disable(sel_hard);
+ sel_hard = 0;
+}
diff --git a/libraries/Wire/HardWire.h b/libraries/Wire/HardWire.h
new file mode 100644
index 0000000..d6eb54a
--- /dev/null
+++ b/libraries/Wire/HardWire.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file HardWire.h
+ * @author Trystan Jones <crenn6977@gmail.com>
+ * @brief Wire library, uses the hardware I2C available in the Maple to
+ * interact with I2C slave devices.
+ */
+
+/*
+ * Library created by crenn to use the new WireBase system and allow Arduino
+ * users easy interaction with the I2C Hardware in a familiar method.
+ */
+
+#ifndef _HARDWIRE_H_
+#define _HARDWIRE_H_
+
+#include <Wire/WireBase.h>
+#include <wirish/wirish.h>
+#include <libmaple/i2c.h>
+
+class HardWire : public WireBase {
+private:
+ i2c_dev* sel_hard;
+ uint8 dev_flags;
+protected:
+ /*
+ * Processes the incoming I2C message defined by WireBase to the
+ * hardware. If an error occured, restart the I2C device.
+ */
+ uint8 process();
+public:
+ /*
+ * Check if devsel is within range and enable selected I2C interface with
+ * passed flags
+ */
+ HardWire(uint8, uint8 = 0);
+
+ /*
+ * Disables the I2C device and remove the device address.
+ */
+ ~HardWire();
+};
+
+#endif // _HARDWIRE_H_
diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp
new file mode 100644
index 0000000..d646132
--- /dev/null
+++ b/libraries/Wire/Wire.cpp
@@ -0,0 +1,182 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file Wire.cpp
+ * @author Trystan Jones <crenn6977@gmail.com>
+ * @brief Wire library, uses the WireBase to create the primary interface
+ * while keeping low level interactions invisible to the user.
+ */
+
+/*
+ * Library updated by crenn to follow new Wire system.
+ * Code was derived from the original Wire for maple code by leaflabs and the
+ * modifications by gke and ala42.
+ */
+
+#include <Wire/Wire.h>
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+/* low level conventions:
+ * - SDA/SCL idle high (expected high)
+ * - always start with i2c_delay rather than end
+ */
+
+void TwoWire::set_scl(bool state) {
+ I2C_DELAY(this->i2c_delay);
+ digitalWrite(this->scl_pin,state);
+ //Allow for clock stretching - dangerous currently
+ if (state == HIGH) {
+ while(digitalRead(this->scl_pin) == 0);
+ }
+}
+
+void TwoWire::set_sda(bool state) {
+ I2C_DELAY(this->i2c_delay);
+ digitalWrite(this->sda_pin, state);
+}
+
+void TwoWire::i2c_start() {
+ set_sda(LOW);
+ set_scl(LOW);
+}
+
+void TwoWire::i2c_stop() {
+ set_sda(LOW);
+ set_scl(HIGH);
+ set_sda(HIGH);
+}
+
+bool TwoWire::i2c_get_ack() {
+ set_scl(LOW);
+ set_sda(HIGH);
+ set_scl(HIGH);
+
+ bool ret = !digitalRead(this->sda_pin);
+ set_scl(LOW);
+ return ret;
+}
+
+void TwoWire::i2c_send_ack() {
+ set_sda(LOW);
+ set_scl(HIGH);
+ set_scl(LOW);
+}
+
+void TwoWire::i2c_send_nack() {
+ set_sda(HIGH);
+ set_scl(HIGH);
+ set_scl(LOW);
+}
+
+uint8 TwoWire::i2c_shift_in() {
+ uint8 data = 0;
+ set_sda(HIGH);
+
+ int i;
+ for (i = 0; i < 8; i++) {
+ set_scl(HIGH);
+ data |= digitalRead(this->sda_pin) << (7-i);
+ set_scl(LOW);
+ }
+
+ return data;
+}
+
+void TwoWire::i2c_shift_out(uint8 val) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ set_sda(!!(val & (1 << (7 - i)) ) );
+ set_scl(HIGH);
+ set_scl(LOW);
+ }
+}
+
+uint8 TwoWire::process() {
+ itc_msg.xferred = 0;
+
+ uint8 sla_addr = (itc_msg.addr << 1);
+ if (itc_msg.flags == I2C_MSG_READ) {
+ sla_addr |= I2C_READ;
+ }
+ i2c_start();
+ // shift out the address we're transmitting to
+ i2c_shift_out(sla_addr);
+ if (!i2c_get_ack()) {
+ return ENACKADDR;
+ }
+ // Recieving
+ if (itc_msg.flags == I2C_MSG_READ) {
+ while (itc_msg.xferred < itc_msg.length) {
+ itc_msg.data[itc_msg.xferred++] = i2c_shift_in();
+ if (itc_msg.xferred < itc_msg.length) {
+ i2c_send_ack();
+ } else {
+ i2c_send_nack();
+ }
+ }
+ }
+ // Sending
+ else {
+ for (uint8 i = 0; i < itc_msg.length; i++) {
+ i2c_shift_out(itc_msg.data[i]);
+ if (!i2c_get_ack()) {
+ return ENACKTRNS;
+ }
+ itc_msg.xferred++;
+ }
+ }
+ i2c_stop();
+ return SUCCESS;
+}
+
+// TODO: Add in Error Handling if pins is out of range for other Maples
+// TODO: Make delays more capable
+TwoWire::TwoWire(uint8 scl, uint8 sda, uint8 delay) : i2c_delay(delay) {
+ this->scl_pin=scl;
+ this->sda_pin=sda;
+}
+
+void TwoWire::begin(uint8 self_addr) {
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+ pinMode(this->scl_pin, OUTPUT_OPEN_DRAIN);
+ pinMode(this->sda_pin, OUTPUT_OPEN_DRAIN);
+ set_scl(HIGH);
+ set_sda(HIGH);
+}
+
+TwoWire::~TwoWire() {
+ this->scl_pin=0;
+ this->sda_pin=0;
+}
+
+// Declare the instance that the users of the library can use
+TwoWire Wire(SCL, SDA, SOFT_STANDARD);
diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h
new file mode 100644
index 0000000..d455b11
--- /dev/null
+++ b/libraries/Wire/Wire.h
@@ -0,0 +1,136 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file Wire.h
+ * @author Trystan Jones <crenn6977@gmail.com>
+ * @brief Wire library, uses the WireBase to create the primary interface
+ * while keeping low level interactions invisible to the user.
+ */
+
+/*
+ * Library updated by crenn to follow new Wire system.
+ * Code was derived from the original Wire for maple code by leaflabs and the
+ * modifications by gke and ala42.
+ */
+
+#ifndef _WIRE_H_
+#define _WIRE_H_
+
+#include <Wire/WireBase.h>
+#include <wirish/wirish.h>
+
+/*
+ * On the Maple, let the default pins be in the same location as the Arduino
+ * pins
+ */
+#define SDA 19
+#define SCL 20
+
+//#define I2C_DELAY(x) {uint32 time=micros(); while(time>(micros()+x));}
+#define I2C_DELAY(x) do{for(int i=0;i<x;i++) {asm volatile("nop");}}while(0)
+#define SOFT_STANDARD 25
+#define SOFT_FAST 7
+
+class TwoWire : public WireBase {
+ private:
+ const uint8 i2c_delay;
+ uint8 scl_pin;
+ uint8 sda_pin;
+
+ /*
+ * Sets the SCL line to HIGH/LOW and allow for clock stretching by slave
+ * devices
+ */
+ void set_scl(bool);
+
+ /*
+ * Sets the SDA line to HIGH/LOW
+ */
+ void set_sda(bool);
+
+ /*
+ * Creates a Start condition on the bus
+ */
+ void i2c_start();
+
+ /*
+ * Creates a Stop condition on the bus
+ */
+ void i2c_stop();
+
+ /*
+ * Gets an ACK condition from a slave device on the bus
+ */
+ bool i2c_get_ack();
+
+ /*
+ * Creates a ACK condition on the bus
+ */
+ void i2c_send_ack();
+
+ /*
+ * Creates a NACK condition on the bus
+ */
+ void i2c_send_nack();
+
+ /*
+ * Shifts in the data through SDA and clocks SCL for the slave device
+ */
+ uint8 i2c_shift_in();
+
+ /*
+ * Shifts out the data through SDA and clocks SCL for the slave device
+ */
+ void i2c_shift_out(uint8);
+ protected:
+ /*
+ * Processes the incoming I2C message defined by WireBase
+ */
+ uint8 process();
+ public:
+ /*
+ * Accept pin numbers for SCL and SDA lines. Set the delay needed
+ * to create the timing for I2C's Standard Mode and Fast Mode.
+ */
+ TwoWire(uint8 scl=SCL, uint8 sda=SDA, uint8 delay=SOFT_STANDARD);
+
+ /*
+ * Sets pins SDA and SCL to OUPTUT_OPEN_DRAIN, joining I2C bus as
+ * master. This function overwrites the default behaviour of
+ * .begin(uint8) in WireBase
+ */
+ void begin(uint8 = 0x00);
+
+ /*
+ * If object is destroyed, set pin numbers to 0.
+ */
+ ~TwoWire();
+};
+
+extern TwoWire Wire;
+
+#endif // _WIRE_H_
diff --git a/libraries/Wire/WireBase.cpp b/libraries/Wire/WireBase.cpp
new file mode 100644
index 0000000..3cb0174
--- /dev/null
+++ b/libraries/Wire/WireBase.cpp
@@ -0,0 +1,140 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file WireBase.cpp
+ * @author Trystan Jones <crenn6977@gmail.com>
+ * @brief Wire library, following the majority of the interface from Arduino.
+ * Provides a 'standard' interface to I2C (two-wire) communication for
+ * derived classes.
+ */
+
+/*
+ * Library created by crenn to allow a system which would provide users the
+ * 'standardised' Arduino method for interfacing with I2C devices regardless of
+ * whether it is I2C hardware or emulating software.
+ */
+
+#include <Wire/WireBase.h>
+#include <wirish/wirish.h>
+
+void WireBase::begin(uint8 self_addr) {
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+}
+
+void WireBase::beginTransmission(uint8 slave_address) {
+ itc_msg.addr = slave_address;
+ itc_msg.data = &tx_buf[tx_buf_idx];
+ itc_msg.length = 0;
+ itc_msg.flags = 0;
+}
+
+void WireBase::beginTransmission(int slave_address) {
+ beginTransmission((uint8)slave_address);
+}
+
+uint8 WireBase::endTransmission(void) {
+ if (tx_buf_overflow) {
+ return EDATA;
+ }
+ process();
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+ return SUCCESS;
+}
+
+//TODO: Add the ability to queue messages (adding a boolean to end of function
+// call, allows for the Arduino style to stay while also giving the flexibility
+// to bulk send
+uint8 WireBase::requestFrom(uint8 address, int num_bytes) {
+ if (num_bytes > WIRE_BUFSIZ) {
+ num_bytes = WIRE_BUFSIZ;
+ }
+ itc_msg.addr = address;
+ itc_msg.flags = I2C_MSG_READ;
+ itc_msg.length = num_bytes;
+ itc_msg.data = &rx_buf[rx_buf_idx];
+ process();
+ rx_buf_len += itc_msg.xferred;
+ itc_msg.flags = 0;
+ return rx_buf_len;
+}
+
+uint8 WireBase::requestFrom(int address, int numBytes) {
+ return WireBase::requestFrom((uint8)address, numBytes);
+}
+
+void WireBase::send(uint8 value) {
+ if (tx_buf_idx == WIRE_BUFSIZ) {
+ tx_buf_overflow = true;
+ return;
+ }
+ tx_buf[tx_buf_idx++] = value;
+ itc_msg.length++;
+}
+
+void WireBase::send(uint8* buf, int len) {
+ for (uint8 i = 0; i < len; i++) {
+ send(buf[i]);
+ }
+}
+
+void WireBase::send(int value) {
+ send((uint8)value);
+}
+
+void WireBase::send(int* buf, int len) {
+ send((uint8*)buf, (uint8)len);
+}
+
+void WireBase::send(char* buf) {
+ uint8 *ptr = (uint8*)buf;
+ while (*ptr) {
+ send(*ptr);
+ ptr++;
+ }
+}
+
+uint8 WireBase::available() {
+ return rx_buf_len - rx_buf_idx;
+}
+
+uint8 WireBase::receive() {
+ if (rx_buf_idx == rx_buf_len) {
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+ return 0;
+ } else if (rx_buf_idx == (rx_buf_len-1)) {
+ uint8 temp = rx_buf[rx_buf_idx];
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+ return temp;
+ }
+ return rx_buf[rx_buf_idx++];
+}
diff --git a/libraries/Wire/WireBase.h b/libraries/Wire/WireBase.h
new file mode 100644
index 0000000..e154476
--- /dev/null
+++ b/libraries/Wire/WireBase.h
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file WireBase.h
+ * @author Trystan Jones <crenn6977@gmail.com>
+ * @brief Wire library, following the majority of the interface from Arduino.
+ * Provides a 'standard' interface to I2C (two-wire) communication for
+ * derived classes.
+ */
+
+/*
+ * Library created by crenn to allow a system which would provide users the
+ * 'standardised' Arduino method for interfacing with I2C devices regardless of
+ * whether it is I2C hardware or emulating software.
+ */
+
+#ifndef _WIREBASE_H_
+#define _WIREBASE_H_
+
+#include <wirish/wirish.h>
+#include <libmaple/i2c.h>
+
+#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 */
+
+class WireBase { // Abstraction is awesome!
+protected:
+ i2c_msg itc_msg;
+ 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_buf[WIRE_BUFSIZ]; /* transmit buffer */
+ uint8 tx_buf_idx; // next idx available in tx_buf, -1 overflow
+ boolean tx_buf_overflow;
+
+ // Force derived classes to define process function
+ virtual uint8 process() = 0;
+public:
+ WireBase() {}
+ ~WireBase() {}
+
+ /*
+ * Initialises the class interface
+ */
+ // Allow derived classes to overwrite begin function
+ virtual void begin(uint8 = 0x00);
+
+ /*
+ * Sets up the transmission message to be processed
+ */
+ void beginTransmission(uint8);
+
+ /*
+ * Allow only 8 bit addresses to be used
+ */
+ void beginTransmission(int);
+
+ /*
+ * Call the process function to process the message if the TX
+ * buffer has not overflowed.
+ */
+ uint8 endTransmission(void);
+
+ /*
+ * Request bytes from a slave device and process the request,
+ * storing into the receiving buffer.
+ */
+ uint8 requestFrom(uint8, int);
+
+ /*
+ * Allow only 8 bit addresses to be used when requesting bytes
+ */
+ uint8 requestFrom(int, int);
+
+ /*
+ * Stack up bytes to be sent when transmitting
+ */
+ void send(uint8);
+
+ /*
+ * Stack up bytes from the array to be sent when transmitting
+ */
+ void send(uint8*, int);
+
+ /*
+ * Ensure that a sending data will only be 8-bit bytes
+ */
+ void send(int);
+
+ /*
+ * Ensure that an array sending data will only be 8-bit bytes
+ */
+ void send(int*, int);
+
+ /*
+ * Stack up bytes from a string to be sent when transmitting
+ */
+ void send(char*);
+
+ /*
+ * Return the amount of bytes that is currently in the receiving buffer
+ */
+ uint8 available();
+
+ /*
+ * Return the value of byte in the receiving buffer that is currently being
+ * pointed to
+ */
+ uint8 receive();
+};
+
+#endif // _WIREBASE_H_
diff --git a/libraries/Wire/rules.mk b/libraries/Wire/rules.mk
new file mode 100644
index 0000000..e16f4db
--- /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) := WireBase.cpp HardWire.cpp 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
new file mode 100644
index 0000000..4e44489
--- /dev/null
+++ b/main.cpp.example
@@ -0,0 +1,43 @@
+// Sample main.cpp file. Blinks the built-in LED, sends a message out
+// USART2, and turns on PWM on pin 2.
+
+#include <wirish/wirish.h>
+
+#define PWM_PIN 2
+
+void setup() {
+ /* Set up the LED to blink */
+ 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);
+ Serial2.println("Hello world!");
+
+ /* Send a message out the usb virtual serial port */
+ SerialUSB.println("Hello!");
+}
+
+void loop() {
+ toggleLED();
+ delay(100);
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+
+ return 0;
+}
diff --git a/notes/dac.txt b/notes/dac.txt
new file mode 100644
index 0000000..3292936
--- /dev/null
+++ b/notes/dac.txt
@@ -0,0 +1,67 @@
+DAC
+-------------------------------------------------------------------------------
+
+There is an ST application note for the DACs; it provides a lot of
+context but doesn't help setup the peripheral very much.
+
+For the first code iteration we'll just use 12-bit right-aligned
+single writes, or DAC_DHR12Rx.
+
+Once data is loaded into the digital registers, there are a number of
+possible triggers to start conversion to analog output: external
+interrupts, software control, and timer events. We'll just use
+software triggering for now.
+
+There is (obviously) DMA support for DAC output.
+
+There are noise (via LFSR) output and triangle wave output features
+with variable amplitude.
+
+There are eleven modes to trigger output to both channels at the same
+time, as follows:
+
+ - Independent trigger:
+ (1) No wave generation
+ (2) Same LFSR
+ (3) Different LFSR
+ (4) Same triangle
+ (5) Different triangle
+ - (6) Simultaneous software start
+ - Simultaneous trigger:
+ (7) Without wave generation
+ (8) Same LFSR
+ (9) Different LFSR
+ (10) Same triangle
+ (11) Different triangle
+
+Buffering is enabled by default.
+
+Triangle Wave HOWTO
+-------------------------------------------------------------------------------
+
+In order to generate a full-amplitude triangle wave:
+
+ - Make the following settings in DAC_BASE->CR, for the DAC channel you
+ want: set MAMP to 1011 (amplitude 4095), WAVE to 10 (triangle),
+ TSEL to 111 (software trigger), TEN to 1 (trigger enabled), and
+ EN to 1 (chanel enabled).
+
+ - Set dac->DHR12Rx to 0 (where x is your channel). This gets added
+ to the triangle wave value at each trigger step.
+
+ - Now, forever: set DAC_SWTRIGR_SWTRIGx in dac->SWTRIGR, and wait
+ for it to get cleared by hardware.
+
+You can do something similar for noise (by setting WAVE to 01
+instead). You can also cause the waves to advance due to timer events
+or external line 9, by making appropriate settings to TSEL.
+
+TODO
+-------------------------------------------------------------------------------
+
+- Sine wave demo (using timer interrupts?)
+- Wirish implementation
+- Official docs
+- Higher performance modes?
+- Signal quality testing
+- DMA output
diff --git a/notes/dma-stm32f1.txt b/notes/dma-stm32f1.txt
new file mode 100644
index 0000000..97b23a0
--- /dev/null
+++ b/notes/dma-stm32f1.txt
@@ -0,0 +1,99 @@
+DMA Notes
+=========
+
+Medium-density devices have one DMA controller, DMA1. High-density
+devices and up also have DMA2. DMA1 has 7 channels; DMA2 has 5. Each
+channel multiplexes DMA requests from various peripherals, like so:
+
+Channel Capabilities
+--------------------
+
+DMA1:
+
+ * Channel 1: ADC1, TIM2_CH3, TIM4_CH1
+ * Channel 2: USART3_TX, TIM1_CH1, TIM2_UP, TIM3_CH3, SPI1_RX
+ * Channel 3: USART3_RX, TIM1_CH2, TIM3_CH4, TIM3_UP, SPI1_TX
+ * Channel 4: USART1_TX, TIM1_CH4, TIM1_TRIG, TIM1_COM, TIM4_CH2,
+ SPI2/I2S2_RX, I2C2_TX
+ * Channel 5: USART1_RX, TIM1_UP, TIM2_CH1, TIM4_CH3,
+ SPI2/I2S2_TX, I2C2_RX
+ * Channel 6: USART2_RX, TIM1_CH3, TIM3_CH1, TIM3_TRIG, I2C1_TX
+ * Channel 7: USART2_TX, TIM2_CH2, TIM2_CH4, TIM4_UP, I2C1_RX
+
+DMA2:
+
+ * Channel 1: TIM5_CH4, TIM5_TRIG, TIM8_CH3, TIM8_UP, SPI/I2S3_RX
+ * Channel 2: TIM8_CH4, TIM8_TRIG, TIM8_COM, TIM5_CH3, TIM5_UP, SPI/I2S3_TX
+ * Channel 3: TIM8_CH1, UART4_RX, TIM6_UP/DAC_CH1
+ * Channel 4: TIM5_CH2, SDIO, TIM7_UP/DAC_CH2
+ * Channel 5: ADC3, TIM8_CH2, TIM5_CH1, UART4_TX
+
+An example usage: via DMA1, channel 1, you can have ADC1 periodically
+dump converted data into an array in memory. The DMA controller can
+then interrupt you when the array is half-full and full, and if any
+error occurred.
+
+Since channels are multiplexed in hardware, you can't simultaneously
+use the same DMA channel to serve requests from two of its peripherals
+at the same time. For example, if you are using DMA 1 channel 1 to
+serve DMA requests from ADC1, you can't also serve requests from Timer
+2 channel 3.
+
+Channel Priority
+----------------
+
+An arbiter prioritizes simultaneous channel DMA requests. Channel
+priority levels are configurable (4 levels of priority). Ties within
+a DMA controller are broken by choosing the lower channel number;
+between the controllers, DMA1 has higher priority than DMA2.
+
+Interrupts
+----------
+
+You can cause an interrupt to fire once half the transfers are
+complete, when all the transfers are complete, if an error occurs
+during transfer, or any combination of the three.
+
+If an error occurs, the transfer is automatically disabled.
+
+Configuration
+-------------
+
+In order to configure a DMA transfer for DMA controller n, channel x,
+ST RM0008 says you should do the following:
+
+ A. Set the peripheral register address in DMAn_BASE->CPARx.
+ B. Set the memory address in DMAn_BASE->CMARx.
+ C. Set the number of data to be transferred in DMAn_BASE->CNDTRx.
+ D. Set the channel priority via the PL bits in DMAn_BASE->CCRx.
+ E. Configure various other things (e.g. data transfer sizes, what
+ events cause channel interrupts) in DMAn_BASE->CCRx as desired.
+ F. Activate the channel by setting ENABLE bit in DMAn_BASE->CCRx.
+
+The channel will start serving DMA requests as soon as it's activated.
+
+The DMA library lets you accomplish these tasks as follows:
+
+ **Setup transfer**
+
+ Do (A), (B), and (E) using dma_setup_transfer().
+
+ This also does (D), but chooses the lowest priority by default.
+
+ **Perform any other desired configuration**
+
+ You can do (C) using dma_set_num_transfers().
+
+ You can do (D) using dma_set_priority().
+
+ You can attach interrupt handlers with dma_attach_interrupt().
+
+ **Activate the channel**
+
+ Do (F) with dma_enable().
+
+Once you're all done, you can dma_disable() the channel. If you
+dma_detach_interrupt() an interrupt handler, the channel interrupts
+will stop firing, but the transfer itself won't stop until it's done
+(which never happens if you set the DMA_CIRC_MODE flag when you called
+dma_setup_transfer()).
diff --git a/notes/exti.txt b/notes/exti.txt
new file mode 100644
index 0000000..df930e5
--- /dev/null
+++ b/notes/exti.txt
@@ -0,0 +1,41 @@
+External interrupt notes.
+
+To generate the interrupt, the interrupt line should be configured
+and enabled. This is done by programming the two trigger registers
+with the desired edge detection and by enabling the interrupt
+request by writing a '1' to the corresponding bit in the interrupt
+mask register. When the selected edge occurs on the external
+interrupt line, an interrupt request is generated. The pending bit
+corresponding to the interrupt line is also set. This request is
+reset by writing a '1' in the pending register.
+
+Hardware interrupt selection:
+
+To configure the 20 lines as interrupt sources, use the following
+procedure:
+
+1) Configure AFIO_EXTICR[y] to select the source input for EXTIx
+ external interrupt
+2) Configure the mask bits of the 20 interrupt lines (EXTI_IMR)
+3) Configure the trigger selection bits of the interrupt lines
+ (EXTI_RTSR and EXTI_FTSR)
+4) Configure the enable and mask bits that control the NVIC_IRQ
+ channel mapped to the External Interrupt Controller (EXTI) so
+ that an inerrupt coming from one of the 20 lines can be
+ correctly acknowledged.
+
+AFIO clock must be on.
+
+RM0008, page 107: "PD0, PD1 cannot be used for external
+interrupt/event generation on 36, 48, 64-bin packages."
+
+The 16 EXTI interrupts are mapped to 7 interrupt handlers.
+
+EXTI Lines to Interrupt Mapping:
+EXTI0 -> EXTI0
+EXTI1 -> EXTI1
+EXTI2 -> EXTI2
+EXTI3 -> EXTI3
+EXTI4 -> EXTI4
+EXTI[5-9] -> EXT9_5
+EXTI[10-15] -> EXT15_10
diff --git a/notes/fsmc.txt b/notes/fsmc.txt
new file mode 100644
index 0000000..1f70760
--- /dev/null
+++ b/notes/fsmc.txt
@@ -0,0 +1,64 @@
+
+FSMC notes (for maple native and other "high density" STM32 devices)
+-------------------------------------------------------------------------------
+
+There is an application note for all this which is helpful; see the ST website.
+
+SRAM chip details
+ IS62WV51216BLL
+ 512k x 16
+ 19 address input
+ 16 data inputs
+ t_wc (write cycle) = 55ns
+ t_rc (write cycle) = 55ns
+ t_pwe1 (write enable low pulse) = 40ns
+ t_aa (address access) = 55ns
+
+
+The FSMC nomenclature is very confusing. There are three separate
+"banks" (which I will call "peripheral banks") each specialized for
+different types of external memory (NOR flash, NAND flash, SRAM,
+etc). We use the one for "PSRAM" with our SRAM chip; it's bank #1. The
+SRAM peripheral bank is further split into 4 "banks" (which I will
+call "channels") to support multiple external devices with chip select
+pins. I think what's going on is that there are 4 hardware peripherals
+and many sections of RAM; the docs are confusing about what's a "block
+of memeory" and what's an "FSMC block".
+
+Anyways, this all takes place on the AHB memory bus.
+
+I'm going to use not-extended mode 1 for read/write.
+
+Steps from application note:
+
+- enable bank3: BCR3_MBKEN = '1'
+- memory type is SRAM: BCR3_MTYP = '00'
+- databuse weidth is 16bits: BCR3_MWID = '01'
+- memory is nonmultiplexed: BCR3_MEXEN is reset (= '0')
+- everything else is cleared
+
+But not true! Actually write enable needs to be set.
+
+Using the application note, which is based around a very similar chip (with
+faster timing), I calculated an ADDSET (address setup) value of 0x0 and a
+DATAST (data setup) value of 0x3.
+
+Using channel1, NOR/PSRAM1 memory starts at 0x60000000.
+
+Have to turn on the RCC clock for all those GPIO pins, but don't need to use
+any interrupts.
+
+Not-super-helpful-link:
+http://www.keil.com/support/man/docs/mcbstm32e/mcbstm32e_to_xmemory.htm
+
+Note the possible confusion with address spaces, bitwidths, rollovers, etc.
+
+
+TODO
+-------------------------------------------------------------------------------
+- more rigorous testing: throughput, latency, bounds checking, bitwidth, data
+ resiliance, etc.
+- update .ld scripts to transparently make use of this external memory
+- test/demo using a seperate external SRAM chip or screen
+- write up documentation
+
diff --git a/notes/interrupts.txt b/notes/interrupts.txt
new file mode 100644
index 0000000..7434513
--- /dev/null
+++ b/notes/interrupts.txt
@@ -0,0 +1,346 @@
+Interrupt (IRQ) Handling in libmaple
+====================================
+
+There have been various threads asking about interrupt handling in
+libmaple. This file explains the libmaple interrupt handling
+interfaces, how libmaple organizes its interrupt handlers, and how to
+write new interrupt handlers.
+
+If you know the Cortex M3 and the libmaple sources pretty well, you
+can skip to the end to read how to add a new interrupt
+handler. Otherwise, read on.
+
+1. Interrupts in Wirish
+-----------------------
+
+There are very few Wirish-level convenience functions for handling
+interrupts. The most obvious one is attachInterrupt(), which is used
+for external interrupt handlers:
+
+http://leaflabs.com/docs/lang/api/attachinterrupt.html
+
+Another example is HardwareTimer::attachInterrupt(); a usage example is here:
+
+http://leaflabs.com/docs/lang/api/hardwaretimer.html#using-timer-interrupts
+
+What these have in common is that they take a pointer to the function
+the user wants to use as an interrupt handler, and pass it down to the
+libmaple proper interface for the subsystem. For example,
+attachInterrupt() calls exti_attach_interrupt(), and
+HardwareTimer::attachInterrupt() calls timer_attach_interrupt().
+
+So, as usual, the Wirish functions are just thin wrappers around the
+libmaple proper interfaces.
+
+2. Interrupts in libmaple proper
+--------------------------------
+
+The libmaple proper interfaces all use functions named
+foo_attach_interrupt(). So there's the exti_attach_interrupt() and
+timer_attach_interrupt() routines that have already been mentioned,
+but there are also some others which (at time of writing) don't have
+Wirish equivalents, like dma_attach_interrupt().
+
+These functions all behave the same way: they take a particular
+peripheral interrupt and a pointer to a user function, and they do
+whatever is necessary to turn on the interrupt line and ensure that
+the user's function gets called exactly when that interrupt occurs.
+
+This in itself is a useful abstraction above the hardware. To
+understand why, here's a bullet-point primer on how interrupts work on
+STM32/Cortex M3 (read about the NVIC in a Cortex M3 book to understand
+all the details; these are just the basics):
+
+- Each series of STM32 microcontroller (STM32F1, STM32F2, etc.)
+ specifies a certain number of IRQs (the libmaple type which
+ enumerates the IRQs is nvic_irq_num; see the libmaple/nvic.h
+ documentation for all the details).
+
+- Each IRQ has a number, which corresponds to a real, physical
+ interrupt line inside the processor. When you talk about an "IRQ",
+ you usually mean one of these interrupt lines.
+
+- The interrupt hardware can be configured to call a single function
+ per IRQ line when an interrupt associated with the IRQ has happened
+ (e.g. when a pin changes from low to high for an external
+ interrupt).
+
+- However, sometimes, various interrupts share an IRQ line. For
+ example, on Maple, external interrupts 5 through 9 all share a
+ single IRQ line (which has nvic_irq_num NVIC_EXTI_9_5). That means
+ that when any one (or any subset!) of those interrupts occurs, the
+ _same_ function (the IRQ handler for NVIC_EXTI_9_5) gets called.
+
+ When that happens, your IRQ handler has to figure out which
+ interrupt(s) it needs to handle (usually by looking at bitfields in
+ some sort of status register), do the right thing to handle them,
+ and then sometimes perform cleanup actions after finishing
+ (e.g. external interrupts need to clear pending masks, or the
+ interrupts will fire over and over again).
+
+So now it should make sense why libmaple's foo_attach_interrupt()
+handlers are convenient: they let you pretend that each interrupt has
+its own IRQ line, even though that's often not true. They also take
+care of set-up and clean-up tasks for you. This means a performance
+hit, but the convenience is usually worth it.
+
+3. Where libmaple keeps its IRQ Handlers
+----------------------------------------
+
+As noted above, for each nvic_irq_num, there's an IRQ line, and for
+each IRQ line, you can set up a single function to call. This section
+explains where libmaple keeps these functions and what they're called.
+
+You typically will only need the information in this section if
+there's no foo_attach_interrupt() routine for the kind of interrupt
+you're interested in. The discussion is at the hardware level, and
+assumes you know how the NVIC works. You can try looking in the
+(freely available) Cortex M3 Technical Reference Manual for the
+details, but Joseph Yiu's book, "The Definitive Guide to the Cortex
+M3" is a much more beginner-friendly resource, and covers everything
+you need to know.
+
+3.1: The vector table files (vector_table.S)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+While they don't contain interrupt handlers themselves, vector table
+files are where to look for what they're named.
+
+You can find the names libmaple expects for IRQ handlers by looking in
+the vector table file for the microcontroller you're interested
+in. This file is always named vector_table.S, but there are multiple
+such files throughout the libmaple source tree. This is because the
+different STM32 series and even lines and densities within a series
+(like the value and performance lines and low/medium/high/XL-densities
+for STM32F1) each have different sets of IRQs.
+
+For portability, then, the vector table files must live somewhere
+where nonportable code goes, namely, under libmaple/stm32f1/,
+libmaple/stm32f2/, etc. as appropriate. The libmaple build system
+knows which one to use for each board.
+
+For example, the vector table file for the microcontroller on the
+Maple (STM32F103RB, a medium-density performance line F1 -- whew!) is
+libmaple/stm32f1/performance/vector_table.S. Here's a snippet:
+
+ .globl __stm32_vector_table
+ .type __stm32_vector_table, %object
+
+ __stm32_vector_table:
+ /* CM3 core interrupts */
+ .long __msp_init
+ .long __exc_reset
+ .long __exc_nmi
+ .long __exc_hardfault
+ .long __exc_memmanage
+ .long __exc_busfault
+ .long __exc_usagefault
+[...]
+ .long __irq_exti0
+ .long __irq_exti1
+ .long __irq_exti2
+ .long __irq_exti3
+ .long __irq_exti4
+
+The names of the interrupt handlers appear one per line, after the
+.long. The names are chosen to make it pretty obvious what IRQ line is
+associated with the function. Additionally, since this is the actual
+vector table for the chip, the names appear in NVIC order, so you can
+check the interrupts and events chapter in the chip reference manual
+to make sure which IRQ line a function is associated with.
+
+3.2: Interrupts handled by libmaple
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The vector table file is just an assembly stub which defines the
+actual vector table (i.e., the initial stack pointer and table of
+function pointers that go at address 0x0), but it doesn't define the
+interrupts themselves. It leaves that up to the rest of libmaple.
+
+Though it doesn't handle them all, libmaple does provide many
+interrupt handlers when it can provide some useful default
+behavior. For example, it defines USART interrupt handlers that store
+received bytes in a ring buffer. It defines EXTI interrupt handlers
+that figure out which external interrupt actually fired, and call the
+corresponding user interrupt handler (which was set either with
+attachInterrupt() or exti_attach_interrupt()).
+
+When there is a default IRQ handler, it lives in a .c file for the
+peripheral the interrupt is related to. Again, usually for reasons of
+portability, these usually live somewhere series-specific. For
+instance, the USART IRQ handlers for Maple live in
+libmaple/stm32f1/usart.c. More rarely, they'll be in some top-level
+file under libmaple/ if the same interrupt is available on all
+supported series (e.g. at time of writing, the EXTI interrupts in
+libmaple/exti.c).
+
+Use the vector table file and grep to find IRQ handlers for the MCU
+you're interested in.
+
+3.3: Interrupts not handled by libmaple (isrs.S)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Though libmaple does provide some IRQ handlers, it doesn't define one
+for every available interrupt. This is true for various reasons: maybe
+the peripheral or interrupt isn't supported yet, maybe there's no
+useful default behavior, etc.
+
+In this case, it would be wasteful to have a separate function for
+each unhandled interrupt. To handle this, there's a single file that
+deals with all unhandled interrupts. Its name is isrs.S, and it lives
+in the same directory as the corresponding vector_table.S. For
+example, for Maple, the file is libmaple/stm32f1/performance/isrs.S.
+
+These aren't complicated; read the source to see how they work.
+
+4. Adding your own interrupt handlers
+-------------------------------------
+
+When adding an interrupt handler (or overriding a default one), you
+need to decide whether you want it for a particular program, or if
+what you're writing is general-purpose enough that it should live in
+libmaple itself.
+
+4.1 Adding a special-purpose interrupt handler
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you're just writing a one-off IRQ handler for your own use, your
+job isn't too complicated, provided you know the peripheral you're
+interested in well enough.
+
+You need to:
+
+1. Define an IRQ handler with the right name
+2. Turn on the IRQ line with nvic_irq_enable()
+3. Set any relevant interrupt enable bits in peripheral registers
+
+You first need to define a function with the right name. Look up the
+name in the vector table file for your board (see above). For example,
+to define your own SDIO interrupt handler for Maple, define a function
+named __irq_sdio():
+
+ void __irq_sdio(void) {
+ // Your handler goes here.
+ }
+
+The libmaple linker scripts are smart enough to notice that you've
+done this and put a pointer to this function in the appropriate place
+in the vector table.
+
+IMPORTANT: the function you define MUST HAVE C LINKAGE. C++ name
+mangling will confuse the linker, and it won't find your function. So
+if you're writing your IRQ handler in a C++ file, you need to define
+it like this:
+
+ extern "C" void __irq_sdio(void) {
+ // etc.
+ }
+
+To enable the interrupt, you need to call nvic_irq_enable() with the
+nvic_irq_num you want to enable. For SDIO, that looks like this:
+
+ nvic_irq_enable(NVIC_SDIO);
+
+This line typically goes in your setup code. Check the docs for
+<libmaple/nvic.h> to find the nvic_irq_num you need.
+
+Beyond that, you also sometimes need to set some interrupt enable bits
+in a register associated with the peripheral. These bits vary by
+peripheral; consult the reference manual for your chip for the
+details. For example, SDIO interupts are enabled using bits in the
+SDIO_MASK register.
+
+4.2 Adding a general-purpose interrupt handler
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Take this route only when you're sure your handler will be generally
+useful enough to ship with every copy of libmaple. Since the vector
+table is always present, your interrupt handler will consume every
+user's Flash. Normally, this is only worth it when defining some sort
+of foo_attach_interrupt() routine for a commonly used interrupt,
+though there are exceptions (e.g. the USART handlers).
+
+To add an interrupt handler, you need to define interrupt handlers
+with the appropriate names as described in the previous section. These
+will live under the series directory for the microcontroller you're
+using. For example, for Maple, they'd live under libmaple/stm32f1.
+
+DO NOT PUT THEM IN THE TOP-LEVEL LIBMAPLE DIRECTORY UNLESS THE
+INTERRUPT IS AVAILABLE ON ALL SUPPORTED SERIES, AND YOU CAN TEST IT ON
+MCUs FROM DIFFERENT SERIES.
+
+Just because an IRQ is available and purports to work the same way on
+multiple STM32 series doesn't mean that it in fact does. For example,
+there are silicon bugs related to I2C interrupt handling on STM32F1
+that require special-purpose workarounds. When in doubt, leave your
+handler in the series directory you can test. It can always be moved
+later.
+
+After you've added the handler, you need to add IRQ enable and disable
+routines for the peripheral. At the very least, this needs to take a
+pointer to the peripheral's device and an argument specifying which
+IRQ or IRQs to enable. For example, here are some timer IRQ
+enable/disable routines present in <libmaple/timer.h>:
+
+ /**
+ * @brief Enable a timer interrupt.
+ * @param dev Timer device.
+ * @param interrupt Interrupt number to enable; this may be any
+ * timer_interrupt_id value appropriate for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+ void timer_enable_irq(timer_dev *dev, uint8 interrupt);
+
+ /**
+ * @brief Disable a timer interrupt.
+ * @param dev Timer device.
+ * @param interrupt Interrupt number to disable; this may be any
+ * timer_interrupt_id value appropriate for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+ void timer_disable_irq(timer_dev *dev, uint8 interrupt);
+
+It's OK to take a flags argument for enabling/disabling multiple IRQs
+at once.
+
+If you're adding a foo_attach_interrupt(), it needs to work similarly,
+except it will also take a pointer to the user function to call when
+the interrupt occurs. When called, it must enable the correct NVIC
+line (which is usually available via the device pointer), as well as
+set any interrupt-enable bits in the appropriate peripheral register
+necessary to turn the interrupt on. Here's a timer example:
+
+ /**
+ * @brief Attach a timer interrupt.
+ * @param dev Timer device
+ * @param interrupt Interrupt number to attach to; this may be any
+ * timer_interrupt_id or timer_channel value appropriate
+ * for the timer.
+ * @param handler Handler to attach to the given interrupt.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+ void timer_attach_interrupt(timer_dev *dev,
+ uint8 interrupt,
+ voidFuncPtr handler) {
+ dev->handlers[interrupt] = handler;
+ timer_enable_irq(dev, interrupt);
+ enable_irq(dev, interrupt);
+ }
+
+You also need a corresponding foo_detach_interrupt() routine.
+
+In the case of IRQs for which a foo_attach_interrupt() routine is
+available, the IRQ handler needs to do any register inspection
+necessary to ensure the user handler is called only when the
+corresponding interrupt has occurred (for example, don't call timer
+capture/compare interrupt handlers due to an update event). How this
+works will depend on the peripheral.
+
+The IRQ handler must also perform any cleanup actions that are
+necessary. For example, various interrupts will cause the IRQ to fire
+until you clear some bits in a peripheral register. Users get confused
+and annoyed when their handlers get called forever. Clean up after
+them, so they don't need to worry about the details.
diff --git a/notes/pin-definitions.txt b/notes/pin-definitions.txt
new file mode 100644
index 0000000..2f462ea
--- /dev/null
+++ b/notes/pin-definitions.txt
@@ -0,0 +1,226 @@
+Pin definitions by GPIO bank.
+
+Source: ST DOC ID 14611, Datasheet for STM32F103xC, STM32F103xD,
+STM32F103xE, Table 5, pp. 30--35.
+
+Some additional peripheral GPIO information is given in the "Other"
+section following each bank's main table.
+
+This document was prepared carefully and is believed to be correct,
+but the final arbiter of truth is the ST datasheet.
+
+*** NB: UART 4 and 5 are NOT USART (columns are labeled appropriately).
+
+---------------------------------------------------------------------------
+GPIO 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)
+
+-------------------------------------------------------------------------------
+GPIO 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)
+
+-------------------------------------------------------------------------------
+GPIO 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
+
+-------------------------------------------------------------------------------
+GPIO 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)
+
+---------------------------------------------------------------------------
+GPIO 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
+
+---------------------------------------------------------------------------
+GPIO 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
+---------------------------------------------------------------------------
+
+---------------------------------------------------------------------------
+GPIO 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/portable.txt b/notes/portable.txt
new file mode 100644
index 0000000..549f4fb
--- /dev/null
+++ b/notes/portable.txt
@@ -0,0 +1,33 @@
+libmaple was previously very restricted to LeafLabs boards. However,
+the contents of libmaple proper are now fairly portable across medium-
+and high-density STM32F1xx chips (though there are some caveats). The
+current design is expected to accomodate new chips straightforwardly
+and well into the future.
+
+The library's configuration is based around the files wirish/boards.h
+(and .cpp), wirish/boards/*, and libmaple/stm32.h, as well as some
+#defines it expects the environment to handle during compilation.
+
+If you want to use libmaple proper, you must define one of
+STM32_MEDIUM_DENSITY or STM32_HIGH_DENSITY during compilation.
+Defining one of these allows libmaple to decide what processor
+features to expose to you (e.g., definitions related to ADC3 aren't
+compiled in when STM32_MEDIUM_DENSITY is defined). There's no support
+for low-density chips. XL-density is planned but not done (we don't
+have one to test on); patches (and samples) are welcome! See:
+
+ http://leaflabs.com/docs/libmaple/contributing.html
+
+There are some other useful #defines the environment can provide when
+compiling libmaple. They aren't as crucial, though. See the Makefile
+for more information.
+
+If you want to use Wirish, you'll need to define a BOARD_foo
+(e.g. BOARD_maple, BOARD_maple_mini, etc.). This determines which
+board files get loaded from wirish/boards/. See /wirish/boards.h and
+/wirish/boards.cpp for more details. See /wirish/boards/maple.h and
+/wirish/boards/maple.cpp for well-commented examples on how to add a
+new board configuration.
+
+The code in libmaple/usb/ is not very portable at all right now;
+expect this to change in the future.
diff --git a/notes/stm32.txt b/notes/stm32.txt
new file mode 100644
index 0000000..106b369
--- /dev/null
+++ b/notes/stm32.txt
@@ -0,0 +1,63 @@
+STM32 platform notes.
+
+Most of this information comes from ST AN3427 (Migrating a
+microcontroller application from STM32F1 to STM32F2 series) and ST
+AN3364 (How to migrate across STM32 series).
+
+The STM32 series of MCUs is divided into series. At time of writing,
+the available series are:
+
+- F1 series (STM32F1)
+- L1 series (STM32L1)
+- F2 series (STM32F2)
+- F4 series (STM32F4)
+
+Some notes on the characteristics of, and differences between, the
+series follow.
+
+F1 Series
+---------
+
+The STM32F1 series is further subdivided into a variety of somewhat
+compatible "lines". Performance, value, and connectivity line MCUs are
+available. (There's also an access line, which is ignored in these
+notes).
+
+At time of writing, libmaple supports medium- and high-density
+performance line MCUs. work to port it to other series is ongoing.
+
+Performance line MCU part numbers begin with STM32F101 or
+STM32F103. The performance line is further subdivided into
+"densities": low, medium, high, and XL.
+
+Value line MCU part numbers begin with STM32F100. Similarly to the
+performance line, the value line is subdivided into medium and high
+densities.
+
+Connectivity line MCU part numbers begin with STM32F105 or
+STM32F107. Mercifully, these are not further subdivided by density.
+
+F2 Series
+---------
+
+A revamp of the F1 series, The F2 series address a number of the
+STM32F1's deficiencies (both silicon bugs and unfortunate design
+decisions), while maintaining a fair amount of software and pin
+compatibility.
+
+The F2 series is most similar to the F1 connectivity line. Like the
+connectivity line, STM32F2s come with a USB on-the-go full speed
+peripheral (like the connectivity line), instead of USB full speed
+device (like the performance line).
+
+F4 Series
+---------
+
+The F4 series MCUs are essentially equivalent to those in the F2
+series, except they have an ARM Cortex M4 core, an FPU, and support a
+higher clock frequencies (168 MHz instead of 120 MHz).
+
+L1 Series
+---------
+
+This series is intended for low-power applications.
diff --git a/notes/timers.txt b/notes/timers.txt
new file mode 100644
index 0000000..647e92e
--- /dev/null
+++ b/notes/timers.txt
@@ -0,0 +1,96 @@
+Timers
+======
+
+Medium-density chips have timers 1 through 4. High- and XL-density
+chips additionally have timers 5 through 8. XL-density chips
+additionally have timers 9--14, which we don't support yet.
+
+Timer Capabilities
+------------------
+
+Each of timers 1--4 has 4 capture/compare (C/C) channels (also numbered
+1--4). These are directly used by PWM, but may serve other purposes as
+well (including handling user-specified periodic interrupts). The
+STM32 implementation is particularly featureful, with, e.g., the
+ability to chain together timers.
+
+Timers 1 and 8 are an advanced timers, with many more features.
+Wirish just uses just their capture/compare interrupts and enables MOE
+during initialization, essentially treating them as general purpose
+timers (like timers 2--5). Advanced timers also have separate break,
+update, and trigger interrupts that we only provide low-level
+(i.e. libmaple proper) support for.
+
+Timers 6 and 7 are basic timers, without C/C channels. They are still
+useful for interrupts (via NVIC_TIMER6, NVIC_TIMER7 IRQs, which can
+fire upon an update event), but they're most useful for controlling
+periodic DAC output.
+
+Known Issues and Other Caveats
+------------------------------
+
+There are some conflicts between timer C/C outputs and USART 1 and 2
+TX/RX. Wirish tries to handle this gracefully, but (as of 7 April
+2011) not all the bugs are sorted yet. In particular, if you call
+HardwareSerial::disable(), then try to use PWM, the USART TX pins
+don't cooperate.
+
+Resetting the prescaler or reload value only takes effect at the next
+update event. You can use timer_generate_update() to generate an
+update event via software.
+
+Other interrupts (SysTick, USB, Serial, etc.) can interfere with
+timing-critical applications. If your program requires precise
+timing, you should probably at least disable USB and SysTick. Note
+that this also disables the bootloader and stops millis()/micros()
+from counting.
+
+Getting really good timing is a bit of an art. If things don't work
+at first, you need to fiddle with an oscilloscope and the exact
+overflow/compare numbers to get precise behavior.
+
+TODO
+----
+
+- Document more carefully (e.g., determine clock-wise and
+ overflow-wise behavior for each function).
+
+- Track down and handle pin conflicts.
+
+- Input capture interface. DON'T WRITE pulseIn() IN TERMS OF THIS.
+ Do that as a simple, Arduino style implementation that just
+ busy-waits and uses micros(), to allow a pulseIn() on arbitrary
+ pins. Eventually, expose the more precise/harder to use timer-based
+ API via a convenience library.
+
+- Complementary outputs, with convenient break/dead time interface.
+
+- Additional modes (center-aligned PWM, one pulse mode, etc.) and
+ count configuration (down, up/down).
+
+Alternative Wirish Implementations
+----------------------------------
+
+The current Wirish API is big and clunky. Its inclusion by default
+also threatens making everyone's sketches bigger unnecessarily. We
+need to deprecate the parts of it that are bad for 0.0.10, and remove
+them when 0.1.0 comes out.
+
+Current implementation was inspired by Timer1 Library for Arduino:
+
+http://arduino.cc/pipermail/developers_arduino.cc/2010-June/002845.html
+
+Here's one of the more standard libaries out there:
+
+http://www.arduino.cc/playground/Code/Timer1
+
+ void initialize(long microseconds=1000000);
+ void start();
+ void stop();
+ void restart();
+ void setPeriod(long microseconds);
+ void pwm(char pin, int duty, long microseconds=-1);
+ void setPwmDuty(char pin, int duty);
+ void disablePwm(char pin);
+ void attachInterrupt(void (*isr)(), long microseconds=-1);
+ void detachInterrupt();
diff --git a/notes/usb.txt b/notes/usb.txt
new file mode 100644
index 0000000..9552b9f
--- /dev/null
+++ b/notes/usb.txt
@@ -0,0 +1,72 @@
+XXX
+XXX This file may be out of date!
+XXX
+
+[NOTE: this is a long term proposal. The current implementation just does a
+2ms TIMEOUT]
+
+SerialUSB Implementation
+-------------------------------------------------------------------------------
+The low-level serial USB implementation (in libmaple, written in C) is always
+non-blocking. A blocking implementation which polls with an optional timeout
+is in wirish (written in C++).
+
+begin() sets mode (and timeout if appropriate)
+end() disables the endpoint and hardware peripheral
+flush() clears the RX and TX buffers
+available() gives # of bytes in RX buffer
+pending() gives # of bytes in TX buffer
+read() gets one byte from RX buffer (or ??? if empty)
+getRTS()/getDTR() return control line status
+write(), print(), println(), see below
+
+there is nothing preventing the implementation of setTimeout(),
+flushTX/flushRX, etc, except for code size.
+
+NONBLOCKING (-1)
+ print() returns immediately with information about how much data was
+ transmitted. 64 bytes is the maximum that can be sent at a time, and
+ possibly less if buffer isn't empty. it's up to usercode to chunk up
+ larger datablocks, see if the buffer is full, etc
+
+ returns pending (max 64) if bytes got put in the TX buffer
+ returns 0 if buffer was full
+
+BLOCKING (0)
+ print() will block INDEFINATELY waiting for an open connection to send
+ an arbitrarily long array of bytes through with up to 64 bytes per packet.
+
+ returns sent (# of bytes added to the TX buffer successfully; all but the
+ last 64 or so will have been fully transmitted)
+
+TIMEOUT (the default, with 10ms. timeout period in ms)
+ print() will behave as in BLOCKING mode, except that it will timeout after
+ a given number of milliseconds. the timeout is not reset after every packet
+ is sent, so the device should be set with a large timeout if many packets
+ are going to be sent in one go, or the transmission will get cut off.
+
+ returns sent (# of bytes added to the TX buffer successfully; all but the
+ last 64 or so will have been fully transmitted)
+ returns 0 if buffer was full
+
+SerialUSB Design Decisions
+-------------------------------------------------------------------------------
+The USB port behaves differently from other serial interfaces, making a clean
+and simple "println()" implementation difficult. Data to be sent to the host is
+written into a small 64byte endpoint buffer, which the host may (or may not!)
+read from at any time. The RTS and DTR control lines /should/ indicate whether
+the host will empty out the endpoint buffer in a reasonable amount of time,
+but this is not reliable.
+
+From the usercode side, we want the println() function to accept strings up to
+hundreds of characters long (longer than the buffer) and get them sent out as
+quickly as possible, returning to code execution as quickly as possible. At the
+same time we don't want want to generate a large buffer because this will
+quickly eat up RAM. When the host device is not connected or not recieving
+bytes, the behavior of println can be undefined; it should return quickly and
+usercode should be able to determine if bytes were queued or not, but it isn't
+important what happens to the bytes. On the other hand, when the device /is/
+connected, we want to guarentee that bytes get sent in the appropriate order
+and none are missed.
+
+
diff --git a/notes/vga.txt b/notes/vga.txt
new file mode 100644
index 0000000..43b6830
--- /dev/null
+++ b/notes/vga.txt
@@ -0,0 +1,35 @@
+
+Notes on GPIO Writing
+------------------------------------------------------------------------------
+Classic digitalWrite() gives ~500ns pulse time (2MHz)
+
+gpio_write_bit() is about 360ns (2.78MHz)
+
+Writing to GPIO?_BASE is about 60ns (16.6MHz -> 18MHz)
+
+PWM write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!)
+
+VGA Timing
+------------------------------------------------------------------------------
+1/25.125MHz = 39.72ns (640x480 pixel clock)
+
+Crude 640x480 directions:
+ From www.epanorama.net/documents/pc/vga_timing.html
+ 480 lines
+ 31.77 us horizontal line length -> 2287.44 clock cycles -> 2287
+ 3.77 us sync period -> 271 clocks -> 271
+ 1.89 us front porch? -> 136 clocks -> 136
+ 25.17 us video -> 1812.24 clocks -> 1812
+
+ So...
+ 2287 reload
+ 271 1: Hsync high
+ 407 2: Video on
+ 2219 3: Video off
+ 2287 4: Hsync low
+
+ Vertically, it's
+ 480 lines active video
+ 11 lines front porch
+ 2 lines Vsync (low)
+ 31 lines back porch
diff --git a/support/doxygen/Doxyfile b/support/doxygen/Doxyfile
new file mode 100644
index 0000000..170cff4
--- /dev/null
+++ b/support/doxygen/Doxyfile
@@ -0,0 +1,1648 @@
+# 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 = YES
+
+# 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 = NO
+
+# 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 = YES
+
+# 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 = NO
+
+# 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 = NO
+
+# 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/ \
+ ./libraries/
+
+# 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 *.c
+
+# 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.
+
+# We include the FreeRTOS sources. That's probably a mistake. Oh well.
+EXCLUDE = ./libraries/FreeRTOS/
+
+# 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.
+
+# Trick Doxygen into thinking series headers are in separate
+# namespaces; see the Evil Mangler source for more information.
+FILTER_PATTERNS = */libmaple/stm32*/include/series/*.h=./support/doxygen/evil_mangler.awk
+
+# 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 = NO
+
+# 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 = __attribute__()= \
+ __deprecated= \
+ __always_inline= \
+ __packed = \
+ __weak = \
+ __cplusplus \
+ STM32_MEDIUM_DENSITY \
+ STM32_HIGH_DENSITY \
+ STM32_XL_DENSITY \
+ PCLK1=0 STM32_PCLK1=0 \
+ PCLK2=0 STM32_PCLK2=0 \
+ STM32_HAVE_TIMER(x)=1 \
+ __DOXYGEN__
+
+# 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/support/doxygen/evil_mangler.awk b/support/doxygen/evil_mangler.awk
new file mode 100755
index 0000000..b07da72
--- /dev/null
+++ b/support/doxygen/evil_mangler.awk
@@ -0,0 +1,38 @@
+#!/usr/bin/awk -f
+
+# libmaple's own Evil Mangler
+#
+# Input filter hack to trick Doxygen into thinking that a series
+# header is in a separate namespace. This is necessary because Doxygen
+# doesn't know how to cope with two data structures with the same name
+# in different places in the project. (We do that all the time,
+# e.g. for foo_reg_map structs.)
+#
+# E.g., an STM32F1 header gets transformed into:
+#
+# namespace stm32f1 {
+# <contents of header>
+# }
+
+BEGIN {
+ # For extracting series component from header FILENAME.
+ series_regex = "/stm32[flw][0-9]*/";
+ # Holds header FILENAME. Cargo-culted; not sure why it's necessary.
+ f = "";
+ # Holds series component.
+ series = "";
+}
+{
+ if (f != FILENAME) {
+ f = FILENAME;
+ match(f, series_regex);
+ series = substr(f, RSTART + 1, RLENGTH - 2);
+ printf("namespace %s {\n", series);
+ }
+ print;
+}
+END {
+ if (series != "") {
+ print "}"
+ }
+}
diff --git a/support/gdb/gpio/gpio.gdb b/support/gdb/gpio/gpio.gdb
new file mode 100644
index 0000000..4376cfd
--- /dev/null
+++ b/support/gdb/gpio/gpio.gdb
@@ -0,0 +1,12 @@
+set print pretty on
+
+print "GPIOA registers:"
+p/x *GPIOA->regs
+print "GPIOB registers:"
+p/x *GPIOB->regs
+print "GPIOC registers:"
+p/x *GPIOC->regs
+print "GPIOD registers:"
+p/x *GPIOD->regs
+print "AFIO registers:"
+p/x *(struct afio_reg_map*)0x40010000
diff --git a/support/gdb/i2c/test.gdb b/support/gdb/i2c/test.gdb
new file mode 100644
index 0000000..8b71320
--- /dev/null
+++ b/support/gdb/i2c/test.gdb
@@ -0,0 +1,112 @@
+define i2c_sr1_flags
+set $s = $arg0
+printf "SR1: "
+
+if (($s & (1 << 15)))
+ printf "SMBALERT "
+end
+
+if (($s & (1 << 14)))
+ printf "TIMEOUT "
+end
+
+if (($s & (1 << 12)))
+ printf "PECERR "
+end
+
+if (($s & (1 << 11)))
+ printf "OVR "
+end
+
+if (($s & (1 << 10)))
+ printf "AF "
+end
+
+if (($s & (1 << 9)))
+ printf "ARLO "
+end
+
+if (($s & (1 << 8)))
+ printf "BERR "
+end
+
+if (($s & (1 << 7)))
+ printf "TXE "
+end
+
+if (($s & (1 << 6)))
+ printf "RXNE "
+end
+
+if (($s & (1 << 4)))
+ printf "STOPF "
+end
+
+if (($s & (1 << 3)))
+ printf "ADD10 "
+end
+
+if (($s & (1 << 2)))
+ printf "BTF "
+end
+
+if (($s & (1 << 1)))
+ printf "ADDR "
+end
+
+if (($s & (1 << 0)))
+ printf "SB "
+end
+end
+
+define i2c_sr2_flags
+set $s = $arg0
+printf "SR2: "
+
+if (($s & (1 << 7)))
+ printf "DUALF "
+end
+
+if (($s & (1 << 6)))
+ printf "SMBHOST "
+end
+
+if (($s & (1 << 5)))
+ printf "SMBDEFAULT "
+end
+
+if (($s & (1 << 4)))
+ printf "GENCALL "
+end
+
+
+if (($s & (1 << 2)))
+ printf "TRA "
+end
+
+if (($s & (1 << 1)))
+ printf "BUSY "
+end
+
+if (($s & (1 << 0)))
+ printf "MSL "
+end
+
+end
+
+define pbc
+set $c = crumbs
+while ($c->event)
+ if ($c->event != 0)
+ printf "Event: %d ", $c->event
+ if ($c->event == 1)
+ i2c_sr1_flags $c->sr1
+ printf "\t"
+ i2c_sr2_flags $c->sr2
+ end
+ printf "\n"
+ end
+ set $c = $c + 1
+end
+
+
diff --git a/support/ld/common.inc b/support/ld/common.inc
new file mode 100644
index 0000000..f5a0f5b
--- /dev/null
+++ b/support/ld/common.inc
@@ -0,0 +1,219 @@
+/*
+ * Linker script for libmaple.
+ *
+ * Original author "lanchon" from ST forums, with modifications by LeafLabs.
+ */
+
+OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+
+/*
+ * Configure other libraries we want in the link.
+ *
+ * libgcc, libc, and libm are common across supported toolchains.
+ * However, some toolchains require additional archives which aren't
+ * present everywhere (e.g. ARM's gcc-arm-embedded releases).
+ *
+ * To hack around this, we let the build system specify additional
+ * archives by putting the right extra_libs.inc (in a directory under
+ * toolchains/) in our search path.
+ */
+GROUP(libgcc.a libc.a libm.a)
+INCLUDE extra_libs.inc
+
+/*
+ * These force the linker to search for vector table symbols.
+ *
+ * These symbols vary by STM32 family (and also within families).
+ * It's up to the build system to configure the link's search path
+ * properly for the target MCU.
+ */
+INCLUDE vector_symbols.inc
+
+/* STM32 vector table. */
+EXTERN(__stm32_vector_table)
+
+/* C runtime initialization function. */
+EXTERN(start_c)
+
+/* main entry point */
+EXTERN(main)
+
+/* Initial stack pointer value. */
+EXTERN(__msp_init)
+PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram));
+
+/* Reset vector and chip reset entry point */
+EXTERN(__start__)
+ENTRY(__start__)
+PROVIDE(__exc_reset = __start__);
+
+/* Heap boundaries, for libmaple */
+EXTERN(_lm_heap_start);
+EXTERN(_lm_heap_end);
+
+SECTIONS
+{
+ .text :
+ {
+ __text_start__ = .;
+ /*
+ * STM32 vector table. Leave this here. Yes, really.
+ */
+ *(.stm32.interrupt_vector)
+
+ /*
+ * Program code and vague linking
+ */
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.plt)
+ *(.gnu.warning)
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer)
+
+ *(.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))
+ } > REGION_TEXT
+
+ /*
+ * End of text
+ */
+ .text.align :
+ {
+ . = ALIGN(8);
+ __text_end__ = .;
+ } > REGION_TEXT
+
+ /*
+ * .ARM.exidx exception unwinding; mandated by ARM's C++ ABI
+ */
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > REGION_RODATA
+ __exidx_end = .;
+
+ /*
+ * .data
+ */
+ .data :
+ {
+ . = ALIGN(8);
+ __data_start__ = .;
+
+ *(.got.plt) *(.got)
+ *(.data .data.* .gnu.linkonce.d.*)
+
+ . = ALIGN(8);
+ __data_end__ = .;
+ } > REGION_DATA AT> REGION_RODATA
+
+ /*
+ * Read-only data
+ */
+ .rodata :
+ {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ /* .USER_FLASH: We allow users to allocate into Flash here */
+ *(.USER_FLASH)
+ /* ROM image configuration; for C startup */
+ . = ALIGN(4);
+ _lm_rom_img_cfgp = .;
+ LONG(LOADADDR(.data));
+ /*
+ * Heap: Linker scripts may choose a custom heap by overriding
+ * _lm_heap_start and _lm_heap_end. Otherwise, the heap is in
+ * internal SRAM, beginning after .bss, and growing towards
+ * the stack.
+ *
+ * I'm shoving these here naively; there's probably a cleaner way
+ * to go about this. [mbolivar]
+ */
+ _lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end;
+ _lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init;
+ } > REGION_RODATA
+
+ /*
+ * .bss
+ */
+ .bss :
+ {
+ . = ALIGN(8);
+ __bss_start__ = .;
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN (8);
+ __bss_end__ = .;
+ _end = __bss_end__;
+ } > REGION_BSS
+
+ /*
+ * Debugging sections
+ */
+ .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/flash.ld b/support/ld/flash.ld
new file mode 100644
index 0000000..9e250cd
--- /dev/null
+++ b/support/ld/flash.ld
@@ -0,0 +1,26 @@
+/*
+ * libmaple linker script for "Flash" builds.
+ *
+ * A Flash build puts .text (and .rodata) in Flash, and
+ * .data/.bss/heap (of course) in SRAM, but offsets the sections by
+ * enough space to store the Maple bootloader, which lives in low
+ * Flash and uses low memory.
+ */
+
+/*
+ * This pulls in the appropriate MEMORY declaration from the right
+ * subdirectory of stm32/mem/ (the environment must call ld with the
+ * right include directory flags to make this happen). Boards can also
+ * use this file to use any of libmaple's memory-related hooks (like
+ * where the heap should live).
+ */
+INCLUDE mem-flash.inc
+
+/* Provide memory region aliases for common.inc */
+REGION_ALIAS("REGION_TEXT", rom);
+REGION_ALIAS("REGION_DATA", ram);
+REGION_ALIAS("REGION_BSS", ram);
+REGION_ALIAS("REGION_RODATA", rom);
+
+/* Let common.inc handle the real work. */
+INCLUDE common.inc
diff --git a/support/ld/jtag.ld b/support/ld/jtag.ld
new file mode 100644
index 0000000..0612f95
--- /dev/null
+++ b/support/ld/jtag.ld
@@ -0,0 +1,31 @@
+/*
+ * libmaple linker script for "JTAG" builds.
+ *
+ * A "JTAG" build puts .text (and .rodata) in Flash, and
+ * .data/.bss/heap (of course) in SRAM, but links starting at the
+ * Flash and SRAM starting addresses (0x08000000 and 0x20000000
+ * respectively). This will wipe out a Maple bootloader if there's one
+ * on the board, so only use this if you know what you're doing.
+ *
+ * Of course, a "JTAG" build is perfectly usable for upload over SWD,
+ * the system memory bootloader, etc. The name is just a historical
+ * artifact.
+ */
+
+/*
+ * This pulls in the appropriate MEMORY declaration from the right
+ * subdirectory of stm32/mem/ (the environment must call ld with the
+ * right include directory flags to make this happen). Boards can also
+ * use this file to use any of libmaple's memory-related hooks (like
+ * where the heap should live).
+ */
+INCLUDE mem-jtag.inc
+
+/* Provide memory region aliases for common.inc */
+REGION_ALIAS("REGION_TEXT", rom);
+REGION_ALIAS("REGION_DATA", ram);
+REGION_ALIAS("REGION_BSS", ram);
+REGION_ALIAS("REGION_RODATA", rom);
+
+/* Let common.inc handle the real work. */
+INCLUDE common.inc
diff --git a/support/ld/ram.ld b/support/ld/ram.ld
new file mode 100644
index 0000000..34b468e
--- /dev/null
+++ b/support/ld/ram.ld
@@ -0,0 +1,25 @@
+/*
+ * libmaple linker script for RAM builds.
+ *
+ * A Flash build puts .text, .rodata, and .data/.bss/heap (of course)
+ * in SRAM, but offsets the sections by enough space to store the
+ * Maple bootloader, which uses low memory.
+ */
+
+/*
+ * This pulls in the appropriate MEMORY declaration from the right
+ * subdirectory of stm32/mem/ (the environment must call ld with the
+ * right include directory flags to make this happen). Boards can also
+ * use this file to use any of libmaple's memory-related hooks (like
+ * where the heap should live).
+ */
+INCLUDE mem-ram.inc
+
+/* Provide memory region aliases for common.inc */
+REGION_ALIAS("REGION_TEXT", ram);
+REGION_ALIAS("REGION_DATA", ram);
+REGION_ALIAS("REGION_BSS", ram);
+REGION_ALIAS("REGION_RODATA", ram);
+
+/* Let common.inc handle the real work. */
+INCLUDE common.inc
diff --git a/support/ld/stm32/mem/maple_native/maple_native_heap.inc b/support/ld/stm32/mem/maple_native/maple_native_heap.inc
new file mode 100644
index 0000000..34b5a2d
--- /dev/null
+++ b/support/ld/stm32/mem/maple_native/maple_native_heap.inc
@@ -0,0 +1,3 @@
+/* Specify heap boundary addresses on the external SRAM chip */
+_lm_heap_start = 0x60000000;
+_lm_heap_end = 0x60100000;
diff --git a/support/ld/stm32/mem/maple_native/mem-flash.inc b/support/ld/stm32/mem/maple_native/mem-flash.inc
new file mode 100644
index 0000000..bae4f39
--- /dev/null
+++ b/support/ld/stm32/mem/maple_native/mem-flash.inc
@@ -0,0 +1,7 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 492K
+}
+
+INCLUDE maple_native_heap.inc
diff --git a/support/ld/stm32/mem/maple_native/mem-jtag.inc b/support/ld/stm32/mem/maple_native/mem-jtag.inc
new file mode 100644
index 0000000..508ed44
--- /dev/null
+++ b/support/ld/stm32/mem/maple_native/mem-jtag.inc
@@ -0,0 +1,7 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
+}
+
+INCLUDE maple_native_heap.inc
diff --git a/support/ld/stm32/mem/maple_native/mem-ram.inc b/support/ld/stm32/mem/maple_native/mem-ram.inc
new file mode 100644
index 0000000..6ae11ef
--- /dev/null
+++ b/support/ld/stm32/mem/maple_native/mem-ram.inc
@@ -0,0 +1,7 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
+}
+
+INCLUDE maple_native_heap.inc
diff --git a/support/ld/stm32/mem/sram_112k_flash_1024k/mem-jtag.inc b/support/ld/stm32/mem/sram_112k_flash_1024k/mem-jtag.inc
new file mode 100644
index 0000000..e0d2da1
--- /dev/null
+++ b/support/ld/stm32/mem/sram_112k_flash_1024k/mem-jtag.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 112K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+}
diff --git a/support/ld/stm32/mem/sram_112k_flash_1024k/mem-ram.inc b/support/ld/stm32/mem/sram_112k_flash_1024k/mem-ram.inc
new file mode 100644
index 0000000..d21f17c
--- /dev/null
+++ b/support/ld/stm32/mem/sram_112k_flash_1024k/mem-ram.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 112K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 0K
+}
diff --git a/support/ld/stm32/mem/sram_20k_flash_128k/mem-flash.inc b/support/ld/stm32/mem/sram_20k_flash_128k/mem-flash.inc
new file mode 100644
index 0000000..a9091ca
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k/mem-flash.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K
+}
diff --git a/support/ld/stm32/mem/sram_20k_flash_128k/mem-jtag.inc b/support/ld/stm32/mem/sram_20k_flash_128k/mem-jtag.inc
new file mode 100644
index 0000000..20fbec0
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k/mem-jtag.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+}
diff --git a/support/ld/stm32/mem/sram_20k_flash_128k/mem-ram.inc b/support/ld/stm32/mem/sram_20k_flash_128k/mem-ram.inc
new file mode 100644
index 0000000..f02453b
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k/mem-ram.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
+}
diff --git a/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc
new file mode 100644
index 0000000..2c03ea9
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
+ rom (rx) : ORIGIN = 0x08003000, LENGTH = 108K
+}
diff --git a/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc
new file mode 100644
index 0000000..20fbec0
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+}
diff --git a/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc
new file mode 100644
index 0000000..f02453b
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
+}
diff --git a/support/ld/stm32/mem/sram_64k_flash_512k/mem-flash.inc b/support/ld/stm32/mem/sram_64k_flash_512k/mem-flash.inc
new file mode 100644
index 0000000..ddb8876
--- /dev/null
+++ b/support/ld/stm32/mem/sram_64k_flash_512k/mem-flash.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 492K
+}
diff --git a/support/ld/stm32/mem/sram_64k_flash_512k/mem-jtag.inc b/support/ld/stm32/mem/sram_64k_flash_512k/mem-jtag.inc
new file mode 100644
index 0000000..d3ed992
--- /dev/null
+++ b/support/ld/stm32/mem/sram_64k_flash_512k/mem-jtag.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
+}
diff --git a/support/ld/stm32/mem/sram_64k_flash_512k/mem-ram.inc b/support/ld/stm32/mem/sram_64k_flash_512k/mem-ram.inc
new file mode 100644
index 0000000..360beaf
--- /dev/null
+++ b/support/ld/stm32/mem/sram_64k_flash_512k/mem-ram.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
+}
diff --git a/support/ld/stm32/mem/sram_8k_flash_128k/mem-flash.inc b/support/ld/stm32/mem/sram_8k_flash_128k/mem-flash.inc
new file mode 100644
index 0000000..19372b7
--- /dev/null
+++ b/support/ld/stm32/mem/sram_8k_flash_128k/mem-flash.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+}
diff --git a/support/ld/stm32/mem/sram_8k_flash_128k/mem-jtag.inc b/support/ld/stm32/mem/sram_8k_flash_128k/mem-jtag.inc
new file mode 100644
index 0000000..19372b7
--- /dev/null
+++ b/support/ld/stm32/mem/sram_8k_flash_128k/mem-jtag.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+}
diff --git a/support/ld/stm32/mem/sram_8k_flash_128k/mem-ram.inc b/support/ld/stm32/mem/sram_8k_flash_128k/mem-ram.inc
new file mode 100644
index 0000000..4063ab4
--- /dev/null
+++ b/support/ld/stm32/mem/sram_8k_flash_128k/mem-ram.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 0K
+}
diff --git a/support/ld/stm32/series/stm32f1/performance/vector_symbols.inc b/support/ld/stm32/series/stm32f1/performance/vector_symbols.inc
new file mode 100644
index 0000000..f8519bb
--- /dev/null
+++ b/support/ld/stm32/series/stm32f1/performance/vector_symbols.inc
@@ -0,0 +1,78 @@
+EXTERN(__msp_init)
+EXTERN(__exc_reset)
+EXTERN(__exc_nmi)
+EXTERN(__exc_hardfault)
+EXTERN(__exc_memmanage)
+EXTERN(__exc_busfault)
+EXTERN(__exc_usagefault)
+EXTERN(__stm32reservedexception7)
+EXTERN(__stm32reservedexception8)
+EXTERN(__stm32reservedexception9)
+EXTERN(__stm32reservedexception10)
+EXTERN(__exc_svc)
+EXTERN(__exc_debug_monitor)
+EXTERN(__stm32reservedexception13)
+EXTERN(__exc_pendsv)
+EXTERN(__exc_systick)
+
+EXTERN(__irq_wwdg)
+EXTERN(__irq_pvd)
+EXTERN(__irq_tamper)
+EXTERN(__irq_rtc)
+EXTERN(__irq_flash)
+EXTERN(__irq_rcc)
+EXTERN(__irq_exti0)
+EXTERN(__irq_exti1)
+EXTERN(__irq_exti2)
+EXTERN(__irq_exti3)
+EXTERN(__irq_exti4)
+EXTERN(__irq_dma1_channel1)
+EXTERN(__irq_dma1_channel2)
+EXTERN(__irq_dma1_channel3)
+EXTERN(__irq_dma1_channel4)
+EXTERN(__irq_dma1_channel5)
+EXTERN(__irq_dma1_channel6)
+EXTERN(__irq_dma1_channel7)
+EXTERN(__irq_adc)
+EXTERN(__irq_usb_hp_can_tx)
+EXTERN(__irq_usb_lp_can_rx0)
+EXTERN(__irq_can_rx1)
+EXTERN(__irq_can_sce)
+EXTERN(__irq_exti9_5)
+EXTERN(__irq_tim1_brk)
+EXTERN(__irq_tim1_up)
+EXTERN(__irq_tim1_trg_com)
+EXTERN(__irq_tim1_cc)
+EXTERN(__irq_tim2)
+EXTERN(__irq_tim3)
+EXTERN(__irq_tim4)
+EXTERN(__irq_i2c1_ev)
+EXTERN(__irq_i2c1_er)
+EXTERN(__irq_i2c2_ev)
+EXTERN(__irq_i2c2_er)
+EXTERN(__irq_spi1)
+EXTERN(__irq_spi2)
+EXTERN(__irq_usart1)
+EXTERN(__irq_usart2)
+EXTERN(__irq_usart3)
+EXTERN(__irq_exti15_10)
+EXTERN(__irq_rtcalarm)
+EXTERN(__irq_usbwakeup)
+
+EXTERN(__irq_tim8_brk)
+EXTERN(__irq_tim8_up)
+EXTERN(__irq_tim8_trg_com)
+EXTERN(__irq_tim8_cc)
+EXTERN(__irq_adc3)
+EXTERN(__irq_fsmc)
+EXTERN(__irq_sdio)
+EXTERN(__irq_tim5)
+EXTERN(__irq_spi3)
+EXTERN(__irq_uart4)
+EXTERN(__irq_uart5)
+EXTERN(__irq_tim6)
+EXTERN(__irq_tim7)
+EXTERN(__irq_dma2_channel1)
+EXTERN(__irq_dma2_channel2)
+EXTERN(__irq_dma2_channel3)
+EXTERN(__irq_dma2_channel4_5)
diff --git a/support/ld/stm32/series/stm32f1/value/vector_symbols.inc b/support/ld/stm32/series/stm32f1/value/vector_symbols.inc
new file mode 100644
index 0000000..f8726f9
--- /dev/null
+++ b/support/ld/stm32/series/stm32f1/value/vector_symbols.inc
@@ -0,0 +1,78 @@
+EXTERN(__msp_init)
+EXTERN(__exc_reset)
+EXTERN(__exc_nmi)
+EXTERN(__exc_hardfault)
+EXTERN(__exc_memmanage)
+EXTERN(__exc_busfault)
+EXTERN(__exc_usagefault)
+EXTERN(__stm32reservedexception7)
+EXTERN(__stm32reservedexception8)
+EXTERN(__stm32reservedexception9)
+EXTERN(__stm32reservedexception10)
+EXTERN(__exc_svc)
+EXTERN(__exc_debug_monitor)
+EXTERN(__stm32reservedexception13)
+EXTERN(__exc_pendsv)
+EXTERN(__exc_systick)
+
+EXTERN(__irq_wwdg)
+EXTERN(__irq_pvd)
+EXTERN(__irq_tamper)
+EXTERN(__irq_rtc)
+EXTERN(__irq_flash)
+EXTERN(__irq_rcc)
+EXTERN(__irq_exti0)
+EXTERN(__irq_exti1)
+EXTERN(__irq_exti2)
+EXTERN(__irq_exti3)
+EXTERN(__irq_exti4)
+EXTERN(__irq_dma1_channel1)
+EXTERN(__irq_dma1_channel2)
+EXTERN(__irq_dma1_channel3)
+EXTERN(__irq_dma1_channel4)
+EXTERN(__irq_dma1_channel5)
+EXTERN(__irq_dma1_channel6)
+EXTERN(__irq_dma1_channel7)
+EXTERN(__irq_adc1)
+EXTERN(__stm32reservedexception14)
+EXTERN(__stm32reservedexception15)
+EXTERN(__stm32reservedexception16)
+EXTERN(__stm32reservedexception17)
+EXTERN(__irq_exti9_5)
+EXTERN(__irq_tim1_brk)
+EXTERN(__irq_tim1_up)
+EXTERN(__irq_tim1_trg_com)
+EXTERN(__irq_tim1_cc)
+EXTERN(__irq_tim2)
+EXTERN(__irq_tim3)
+EXTERN(__irq_tim4)
+EXTERN(__irq_i2c1_ev)
+EXTERN(__irq_i2c1_er)
+EXTERN(__irq_i2c2_ev)
+EXTERN(__irq_i2c2_er)
+EXTERN(__irq_spi1)
+EXTERN(__irq_spi2)
+EXTERN(__irq_usart1)
+EXTERN(__irq_usart2)
+EXTERN(__irq_usart3)
+EXTERN(__irq_exti15_10)
+EXTERN(__irq_rtcalarm)
+EXTERN(__irq_cec)
+EXTERN(__irq_tim12)
+EXTERN(__irq_tim13)
+EXTERN(__irq_tim14)
+EXTERN(__stm32reservedexception18)
+EXTERN(__stm32reservedexception19)
+EXTERN(__irq_fsmc)
+EXTERN(__stm32reservedexception20)
+EXTERN(__irq_tim5)
+EXTERN(__irq_spi3)
+EXTERN(__irq_uart4)
+EXTERN(__irq_uart5)
+EXTERN(__irq_tim6)
+EXTERN(__irq_tim7)
+EXTERN(__irq_dma2_channel1)
+EXTERN(__irq_dma2_channel2)
+EXTERN(__irq_dma2_channel3)
+EXTERN(__irq_dma2_channel4_5)
+EXTERN(__irq_dma2_channel5) /* on remap only */
diff --git a/support/ld/stm32/series/stm32f2/vector_symbols.inc b/support/ld/stm32/series/stm32f2/vector_symbols.inc
new file mode 100644
index 0000000..d275ec3
--- /dev/null
+++ b/support/ld/stm32/series/stm32f2/vector_symbols.inc
@@ -0,0 +1,98 @@
+EXTERN(__msp_init)
+EXTERN(__exc_reset)
+EXTERN(__exc_nmi)
+EXTERN(__exc_hardfault)
+EXTERN(__exc_memmanage)
+EXTERN(__exc_busfault)
+EXTERN(__exc_usagefault)
+EXTERN(__stm32reservedexception7)
+EXTERN(__stm32reservedexception8)
+EXTERN(__stm32reservedexception9)
+EXTERN(__stm32reservedexception10)
+EXTERN(__exc_svc)
+EXTERN(__exc_debug_monitor)
+EXTERN(__stm32reservedexception13)
+EXTERN(__exc_pendsv)
+EXTERN(__exc_systick)
+
+EXTERN(__irq_wwdg)
+EXTERN(__irq_pvd)
+EXTERN(__irq_tamp_stamp)
+EXTERN(__irq_rtc_wkup)
+EXTERN(__irq_flash)
+EXTERN(__irq_rcc)
+EXTERN(__irq_exti0)
+EXTERN(__irq_exti1)
+EXTERN(__irq_exti2)
+EXTERN(__irq_exti3)
+EXTERN(__irq_exti4)
+EXTERN(__irq_dma1_stream0)
+EXTERN(__irq_dma1_stream1)
+EXTERN(__irq_dma1_stream2)
+EXTERN(__irq_dma1_stream3)
+EXTERN(__irq_dma1_stream4)
+EXTERN(__irq_dma1_stream5)
+EXTERN(__irq_dma1_stream6)
+EXTERN(__irq_adc)
+EXTERN(__irq_can1_tx)
+EXTERN(__irq_can1_rx0)
+EXTERN(__irq_can1_rx1)
+EXTERN(__irq_can1_sce)
+EXTERN(__irq_exti9_5)
+EXTERN(__irq_tim1_brk_tim9)
+EXTERN(__irq_tim1_up_tim10)
+EXTERN(__irq_tim1_trg_com_tim11)
+EXTERN(__irq_tim1_cc)
+EXTERN(__irq_tim2)
+EXTERN(__irq_tim3)
+EXTERN(__irq_tim4)
+EXTERN(__irq_i2c1_ev)
+EXTERN(__irq_i2c1_er)
+EXTERN(__irq_i2c2_ev)
+EXTERN(__irq_i2c2_er)
+EXTERN(__irq_spi1)
+EXTERN(__irq_spi2)
+EXTERN(__irq_usart1)
+EXTERN(__irq_usart2)
+EXTERN(__irq_usart3)
+EXTERN(__irq_exti15_10)
+EXTERN(__irq_rtc_alarm)
+EXTERN(__irq_otg_fs_wkup)
+EXTERN(__irq_tim8_brk_tim12)
+EXTERN(__irq_tim8_up_tim13)
+EXTERN(__irq_tim8_trg_com_tim14)
+EXTERN(__irq_tim8_cc)
+EXTERN(__irq_dma1_stream7)
+EXTERN(__irq_fsmc)
+EXTERN(__irq_sdio)
+EXTERN(__irq_tim5)
+EXTERN(__irq_spi3)
+EXTERN(__irq_uart4)
+EXTERN(__irq_uart5)
+EXTERN(__irq_tim6_dac)
+EXTERN(__irq_tim7)
+EXTERN(__irq_dma2_stream0)
+EXTERN(__irq_dma2_stream1)
+EXTERN(__irq_dma2_stream2)
+EXTERN(__irq_dma2_stream3)
+EXTERN(__irq_dma2_stream4)
+EXTERN(__irq_eth)
+EXTERN(__irq_eth_wkup)
+EXTERN(__irq_can2_tx)
+EXTERN(__irq_can2_rx0)
+EXTERN(__irq_can2_rx1)
+EXTERN(__irq_can2_sce)
+EXTERN(__irq_otg_fs)
+EXTERN(__irq_dma2_stream5)
+EXTERN(__irq_dma2_stream6)
+EXTERN(__irq_dma2_stream7)
+EXTERN(__irq_usart6)
+EXTERN(__irq_i2c3_ev)
+EXTERN(__irq_i2c3_er)
+EXTERN(__irq_otg_hs_ep1_out)
+EXTERN(__irq_otg_hs_ep1_in)
+EXTERN(__irq_otg_hs_wkup)
+EXTERN(__irq_otg_hs)
+EXTERN(__irq_dcmi)
+EXTERN(__irq_cryp)
+EXTERN(__irq_hash_rng)
diff --git a/support/ld/toolchains/gcc-arm-embedded/extra_libs.inc b/support/ld/toolchains/gcc-arm-embedded/extra_libs.inc
new file mode 100644
index 0000000..dd2c84f
--- /dev/null
+++ b/support/ld/toolchains/gcc-arm-embedded/extra_libs.inc
@@ -0,0 +1,7 @@
+/*
+ * Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi-
+ * releases (https://launchpad.net/gcc-arm-embedded/).
+ */
+
+/* This is for the provided newlib. */
+GROUP(libnosys.a)
diff --git a/support/ld/toolchains/generic/extra_libs.inc b/support/ld/toolchains/generic/extra_libs.inc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/support/ld/toolchains/generic/extra_libs.inc
diff --git a/support/make/board-includes/VLDiscovery.mk b/support/make/board-includes/VLDiscovery.mk
new file mode 100644
index 0000000..76cd85a
--- /dev/null
+++ b/support/make/board-includes/VLDiscovery.mk
@@ -0,0 +1,7 @@
+MCU := STM32F100RB
+PRODUCT_ID := 0003
+ERROR_LED_PORT := GPIOC
+ERROR_LED_PIN := 9
+MCU_SERIES := stm32f1
+MCU_F1_LINE := value
+LD_MEM_DIR := sram_8k_flash_128k
diff --git a/support/make/board-includes/cm900.mk b/support/make/board-includes/cm900.mk
new file mode 100644
index 0000000..9f70a1b
--- /dev/null
+++ b/support/make/board-includes/cm900.mk
@@ -0,0 +1,15 @@
+MCU := STM32F103C8
+PRODUCT_ID := 0003
+ERROR_LED_PORT := GPIOB
+ERROR_LED_PIN := 2
+MCU_SERIES := stm32f1
+MCU_F1_LINE := performance
+# This crap is due to ld-script limitations. If you know of a better
+# way to go about this (like some magic ld switches to specify MEMORY
+# at the command line), please tell us!
+ifeq ($(BOOTLOADER),maple)
+LD_MEM_DIR := sram_20k_flash_128k
+endif
+ifeq ($(BOOTLOADER),robotis)
+LD_MEM_DIR := sram_20k_flash_128k_robotis
+endif
diff --git a/support/make/board-includes/maple.mk b/support/make/board-includes/maple.mk
new file mode 100644
index 0000000..a2943ce
--- /dev/null
+++ b/support/make/board-includes/maple.mk
@@ -0,0 +1,10 @@
+MCU := STM32F103RB
+PRODUCT_ID := 0003
+ERROR_LED_PORT := GPIOA
+ERROR_LED_PIN := 5
+MCU_SERIES := stm32f1
+MCU_F1_LINE := performance
+# This crap is due to ld-script limitations. If you know of a better
+# way to go about this (like some magic ld switches to specify MEMORY
+# at the command line), please tell us!
+LD_MEM_DIR := sram_20k_flash_128k
diff --git a/support/make/board-includes/maple_RET6.mk b/support/make/board-includes/maple_RET6.mk
new file mode 100644
index 0000000..138722f
--- /dev/null
+++ b/support/make/board-includes/maple_RET6.mk
@@ -0,0 +1,7 @@
+MCU := STM32F103RE
+PRODUCT_ID := 0003
+ERROR_LED_PORT := GPIOA
+ERROR_LED_PIN := 5
+MCU_SERIES := stm32f1
+MCU_F1_LINE := performance
+LD_MEM_DIR := sram_64k_flash_512k
diff --git a/support/make/board-includes/maple_mini.mk b/support/make/board-includes/maple_mini.mk
new file mode 100644
index 0000000..b022537
--- /dev/null
+++ b/support/make/board-includes/maple_mini.mk
@@ -0,0 +1,7 @@
+MCU := STM32F103CB
+PRODUCT_ID := 0003
+ERROR_LED_PORT := GPIOB
+ERROR_LED_PIN := 1
+MCU_SERIES := stm32f1
+MCU_F1_LINE := performance
+LD_MEM_DIR := sram_20k_flash_128k
diff --git a/support/make/board-includes/maple_native.mk b/support/make/board-includes/maple_native.mk
new file mode 100644
index 0000000..87e58e3
--- /dev/null
+++ b/support/make/board-includes/maple_native.mk
@@ -0,0 +1,7 @@
+MCU := STM32F103ZE
+PRODUCT_ID := 0003
+ERROR_LED_PORT := GPIOC
+ERROR_LED_PIN := 15
+MCU_SERIES := stm32f1
+MCU_F1_LINE := performance
+LD_MEM_DIR := maple_native # The SRAM chip makes this board special
diff --git a/support/make/board-includes/olimex_stm32_h103.mk b/support/make/board-includes/olimex_stm32_h103.mk
new file mode 100644
index 0000000..a3304a1
--- /dev/null
+++ b/support/make/board-includes/olimex_stm32_h103.mk
@@ -0,0 +1,7 @@
+MCU := STM32F103RB
+PRODUCT_ID := 0003
+ERROR_LED_PORT := GPIOC
+ERROR_LED_PIN := 12
+MCU_SERIES := stm32f1
+MCU_F1_LINE := performance
+LD_MEM_DIR := sram_20k_flash_128k
diff --git a/support/make/board-includes/opencm904.mk b/support/make/board-includes/opencm904.mk
new file mode 100644
index 0000000..64d3351
--- /dev/null
+++ b/support/make/board-includes/opencm904.mk
@@ -0,0 +1,15 @@
+MCU := STM32F103CB
+PRODUCT_ID := 0003
+ERROR_LED_PORT := GPIOB
+ERROR_LED_PIN := 9
+MCU_SERIES := stm32f1
+MCU_F1_LINE := performance
+# This crap is due to ld-script limitations. If you know of a better
+# way to go about this (like some magic ld switches to specify MEMORY
+# at the command line), please tell us!
+ifeq ($(BOOTLOADER),maple)
+LD_MEM_DIR := sram_20k_flash_128k
+endif
+ifeq ($(BOOTLOADER),robotis)
+LD_MEM_DIR := sram_20k_flash_128k_robotis
+endif
diff --git a/support/make/board-includes/st_stm3220g_eval.mk b/support/make/board-includes/st_stm3220g_eval.mk
new file mode 100644
index 0000000..8aaefc9
--- /dev/null
+++ b/support/make/board-includes/st_stm3220g_eval.mk
@@ -0,0 +1,5 @@
+MCU := STM32F207IG
+ERROR_LED_PORT := GPIOG
+ERROR_LED_PIN := 6
+MCU_SERIES := stm32f2
+LD_MEM_DIR := sram_112k_flash_1024k
diff --git a/support/make/build-rules.mk b/support/make/build-rules.mk
new file mode 100644
index 0000000..7c918d8
--- /dev/null
+++ b/support/make/build-rules.mk
@@ -0,0 +1,59 @@
+# Useful tools
+CROSS_COMPILE ?= arm-none-eabi-
+
+CC := $(CROSS_COMPILE)gcc
+CXX := $(CROSS_COMPILE)g++
+LD := $(CROSS_COMPILE)ld -v
+AR := $(CROSS_COMPILE)ar
+AS := $(CROSS_COMPILE)gcc
+OBJCOPY := $(CROSS_COMPILE)objcopy
+DISAS := $(CROSS_COMPILE)objdump
+OBJDUMP := $(CROSS_COMPILE)objdump
+SIZE := $(CROSS_COMPILE)size
+DFU ?= dfu-util
+
+# Suppress annoying output unless V is set
+ifndef V
+ SILENT_CC = @echo ' [CC] ' $(@:$(BUILD_PATH)/%.o=%.c);
+ SILENT_AS = @echo ' [AS] ' $(@:$(BUILD_PATH)/%.o=%.S);
+ SILENT_CXX = @echo ' [CXX] ' $(@:$(BUILD_PATH)/%.o=%.cpp);
+ SILENT_LD = @echo ' [LD] ' $(@F);
+ SILENT_AR = @echo ' [AR] '
+ SILENT_OBJCOPY = @echo ' [OBJCOPY] ' $(@F);
+ SILENT_DISAS = @echo ' [DISAS] ' $(@:$(BUILD_PATH)/%.bin=%).disas;
+ SILENT_OBJDUMP = @echo ' [OBJDUMP] ' $(OBJDUMP);
+endif
+
+# Extra build configuration
+
+BUILDDIRS :=
+TGT_BIN :=
+
+CFLAGS = $(GLOBAL_CFLAGS) $(TGT_CFLAGS)
+CXXFLAGS = $(GLOBAL_CXXFLAGS) $(TGT_CXXFLAGS)
+ASFLAGS = $(GLOBAL_ASFLAGS) $(TGT_ASFLAGS)
+
+# Hacks to determine extra libraries we need to link against based on
+# the toolchain. The default specifies no extra libraries, but it can
+# be overridden.
+LD_TOOLCHAIN_PATH := $(LDDIR)/toolchains/generic
+ifneq ($(findstring ARM/embedded,$(shell $(CC) --version)),)
+# GCC ARM Embedded, https://launchpad.net/gcc-arm-embedded/
+LD_TOOLCHAIN_PATH := $(LDDIR)/toolchains/gcc-arm-embedded
+endif
+ifneq ($(findstring Linaro GCC,$(shell $(CC) --version)),)
+# Summon/Linaro GCC ARM Embedded, https://github.com/esden/summon-arm-toolchain
+LD_TOOLCHAIN_PATH := $(LDDIR)/toolchains/gcc-arm-embedded
+endif
+# Add toolchain directory to LD search path
+TOOLCHAIN_LDFLAGS := -L $(LD_TOOLCHAIN_PATH)
+
+# General directory independent build rules, generate dependency information
+$(BUILD_PATH)/%.o: %.c
+ $(SILENT_CC) $(CC) $(CFLAGS) -MMD -MP -MF $(@:%.o=%.d) -MT $@ -o $@ -c $<
+
+$(BUILD_PATH)/%.o: %.cpp
+ $(SILENT_CXX) $(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:%.o=%.d) -MT $@ -o $@ -c $<
+
+$(BUILD_PATH)/%.o: %.S
+ $(SILENT_AS) $(AS) $(ASFLAGS) -MMD -MP -MF $(@:%.o=%.d) -MT $@ -o $@ -c $<
diff --git a/support/make/build-templates.mk b/support/make/build-templates.mk
new file mode 100644
index 0000000..4371f13
--- /dev/null
+++ b/support/make/build-templates.mk
@@ -0,0 +1,5 @@
+define LIBMAPLE_MODULE_template
+dir := $(1)
+include $$(dir)/rules.mk
+endef
+
diff --git a/support/make/footer.mk b/support/make/footer.mk
new file mode 100644
index 0000000..2242416
--- /dev/null
+++ b/support/make/footer.mk
@@ -0,0 +1,18 @@
+sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
+ $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
+ $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+$(OBJS_$(d)): TGT_CXXFLAGS := $(CXXFLAGS_$(d))
+$(OBJS_$(d)): TGT_ASFLAGS := $(ASFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp))
diff --git a/support/make/header.mk b/support/make/header.mk
new file mode 100644
index 0000000..c85594a
--- /dev/null
+++ b/support/make/header.mk
@@ -0,0 +1,4 @@
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
diff --git a/support/make/target-config.mk b/support/make/target-config.mk
new file mode 100644
index 0000000..0e3a2c2
--- /dev/null
+++ b/support/make/target-config.mk
@@ -0,0 +1,54 @@
+# TARGET_FLAGS are to be passed while compiling, assembling, linking.
+TARGET_FLAGS :=
+# TARGET_LDFLAGS go to the linker
+TARGET_LDFLAGS :=
+
+# Configuration derived from $(MEMORY_TARGET)
+
+LD_SCRIPT_PATH := $(LDDIR)/$(MEMORY_TARGET).ld
+
+ifeq ($(MEMORY_TARGET), ram)
+VECT_BASE_ADDR := VECT_TAB_RAM
+endif
+ifeq ($(MEMORY_TARGET), flash)
+VECT_BASE_ADDR := VECT_TAB_FLASH
+endif
+ifeq ($(MEMORY_TARGET), jtag)
+VECT_BASE_ADDR := VECT_TAB_BASE
+endif
+
+# Pull in the board configuration file here, so it can override the
+# above.
+
+include $(BOARD_INCLUDE_DIR)/$(BOARD).mk
+
+# Configuration derived from $(BOARD).mk
+
+LD_SERIES_PATH := $(LDDIR)/stm32/series/$(MCU_SERIES)
+LD_MEM_PATH := $(LDDIR)/stm32/mem/$(LD_MEM_DIR)
+ifeq ($(MCU_SERIES), stm32f1)
+# Due to the Balkanization on F1, we need to specify the line when
+# making linker decisions.
+LD_SERIES_PATH := $(LD_SERIES_PATH)/$(MCU_F1_LINE)
+endif
+
+ifeq ($(MCU_SERIES), stm32f1)
+TARGET_FLAGS += -mcpu=cortex-m3 -march=armv7-m
+endif
+ifeq ($(MCU_SERIES), stm32f2)
+TARGET_FLAGS += -mcpu=cortex-m3 -march=armv7-m
+endif
+ifeq ($(MCU_SERIES), stm32f4)
+TARGET_FLAGS += -mcpu=cortex-m4 -march=armv7e-m -mfloat-abi=hard -mfpu=fpv4-sp-d16
+endif
+
+TARGET_LDFLAGS += -Xlinker -T$(LD_SCRIPT_PATH) \
+ -L $(LD_SERIES_PATH) \
+ -L $(LD_MEM_PATH) \
+ -L $(LDDIR)
+TARGET_FLAGS += -mthumb -DBOARD_$(BOARD) -DMCU_$(MCU) \
+ -DERROR_LED_PORT=$(ERROR_LED_PORT) \
+ -DERROR_LED_PIN=$(ERROR_LED_PIN) \
+ -D$(VECT_BASE_ADDR)
+
+LIBMAPLE_MODULE_SERIES := $(LIBMAPLE_PATH)/$(MCU_SERIES)
diff --git a/support/scripts/45-maple.rules b/support/scripts/45-maple.rules
new file mode 100644
index 0000000..d1bda5f
--- /dev/null
+++ b/support/scripts/45-maple.rules
@@ -0,0 +1,5 @@
+ATTRS{idProduct}=="1001", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
+ATTRS{idProduct}=="1002", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
+ATTRS{idProduct}=="0003", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple"
+ATTRS{idProduct}=="0004", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple"
+
diff --git a/support/scripts/copy-to-ide b/support/scripts/copy-to-ide
new file mode 100755
index 0000000..e68abca
--- /dev/null
+++ b/support/scripts/copy-to-ide
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# This hack copies libmaple's source, linker scripts, and support
+# libraries into the Maple IDE repository (which is expected as its
+# first argument).
+
+DEST=$1
+
+DEST_CORES=$DEST/hardware/leaflabs/cores/maple
+DEST_LIBS=$DEST/libraries
+
+LMAPLE_SRC="LICENSE
+ ./libmaple/*.h
+ ./libmaple/*.c
+ ./libmaple/*.S
+ ./libmaple/usb/*.h
+ ./libmaple/usb/*.c
+ ./libmaple/usb/usb_lib/*.h
+ ./libmaple/usb/usb_lib/*.c
+ ./wirish/*.h
+ ./wirish/main.cxx
+ ./wirish/*.cpp
+ ./wirish/comm/*.cpp
+ ./wirish/comm/*.h
+ ./wirish/boards/*.h
+ ./wirish/boards/*.cpp
+ ./support/ld/common.inc
+ ./support/ld/maple
+ ./support/ld/maple_mini
+ ./support/ld/maple_native
+ ./support/ld/maple_RET6
+ ./support/ld/names.inc"
+
+echo "First make sure DEST exists: $DEST"
+if !(test -d $DEST)
+then
+ echo "Nope! Make sure you're doing this right?"
+ exit -1
+fi
+
+# source
+echo Copying libmaple source
+rm -rf $DEST_CORES/*.c $DEST_CORES/*.cpp $DEST_CORES/*.h $DEST_CORES/*.cxx $DEST_CORES/*.S
+rm -rf $DEST_CORES/*.inc $DEST_CORES/*.a $DEST_CORES/maple $DEST_CORES/maple_*
+cp -R $LMAPLE_SRC $DEST_CORES
+
+echo Copying over libraries
+cp -R libraries/* $DEST_LIBS
+
+# libmaple version
+echo Creating libmaple-version.txt
+git show-ref HEAD | cut -c 1-10 > $DEST/libmaple-version.txt
+
+echo Done.
diff --git a/support/scripts/reset.py b/support/scripts/reset.py
new file mode 100755
index 0000000..67a72c1
--- /dev/null
+++ b/support/scripts/reset.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import serial
+import os
+import platform
+import sys
+import time
+from struct import pack
+
+def unix_get_maple_path(file_prefix, dev_is_maple=lambda dev: True):
+ """Try to find the device file for the Maple on *nix.
+
+ This function works assuming that the device file globs like
+ '/dev/<file_prefix>*'. The caller may pass an additional
+ dev_is_maple predicate if the platform supports additional tests
+ to determine if a device is a Maple.
+
+ If there are multiple possibilities, ask the user what to do. If
+ the user chooses not to say, returns None."""
+ possible_paths = [os.path.join('/dev', x) for x in os.listdir('/dev') \
+ if x.startswith(file_prefix) and dev_is_maple(x)]
+ return choose_path(possible_paths)
+
+def linux_get_maple_path(file_prefix='ttyACM'):
+ """Specialized unix_get_maple_path() for Linux.
+
+ Attempts to check that a candidate device has the correct ID in
+ the /sys tree when deciding if it's a Maple."""
+ return unix_get_maple_path(file_prefix, linux_tty_is_maple)
+
+def linux_tty_is_maple(device):
+ try:
+ sysfile = open("/sys/class/tty/%s/device/uevent" % device, "r")
+ text = "".join(sysfile.readlines())
+ return "PRODUCT=1eaf/4" in text
+ except IOError: # no udev info available
+ return True
+
+def windows_get_maple_path():
+ """Similar to unix_get_maple_path(), but on Windows."""
+ import _winreg as reg
+ p = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
+ k = reg.OpenKey(reg.HKEY_LOCAL_MACHINE, p)
+ possible_paths = []
+ i = 0
+ while True:
+ try:
+ possible_paths.append(reg.EnumValue(k, i)[1])
+ i += 1
+ except WindowsError:
+ break
+ return choose_path(possible_paths)
+
+def choose_path(possible_paths):
+ if len(possible_paths) == 0:
+ return None
+ elif len(possible_paths) == 1:
+ return possible_paths[0]
+ else:
+ print('Found multiple candidates for the Maple device:')
+ return choose_among_options(possible_paths)
+
+def choose_among_options(options):
+ for (i,p) in enumerate(options):
+ print('\t%d. %s' % (i+1, p))
+
+ prompt = 'Enter a number to select one, or q to quit: '
+ while True:
+ resp = raw_input(prompt).strip().lower()
+ if resp == 'q': sys.exit()
+
+ try:
+ i = int(resp, 10)
+ except ValueError:
+ pass
+ else:
+ if 0 <= i-1 < len(options):
+ return options[i-1]
+
+ prompt = 'Please enter a number from the list, or q to quit: '
+
+plat_sys = platform.system()
+plat_bits = platform.architecture()[0]
+if plat_sys == 'Linux':
+ maple_path = linux_get_maple_path()
+ # fall back on /dev/maple if that doesn't work
+ if maple_path is None:
+ maple_path = '/dev/maple'
+ print('Could not find Maple serial port; defaulting to /dev/maple.')
+elif plat_sys == 'Darwin':
+ maple_path = unix_get_maple_path('tty.usbmodem')
+elif plat_sys == 'Windows':
+ maple_path = windows_get_maple_path()
+else:
+ maple_path = raw_input('Unrecognized platform. Please enter '
+ "the path to the Maple's serial port device file:")
+
+if maple_path is None:
+ print('Could not find the Maple serial port for reset.',
+ 'Perhaps this is your first upload, or the board is already',
+ 'in bootloader mode.')
+ print()
+ print("If your sketch doesn't upload, try putting your Maple",
+ 'into bootloader mode manually by pressing the RESET button',
+ 'then letting it go and quickly pressing button BUT',
+ '(hold for several seconds).')
+ sys.exit()
+
+print('Using %s as Maple serial port' % maple_path)
+
+try:
+ ser = serial.Serial(maple_path, baudrate=115200, xonxoff=1)
+
+ try:
+ # try to toggle DTR/RTS (old scheme)
+ ser.setRTS(0)
+ time.sleep(0.01)
+ ser.setDTR(0)
+ time.sleep(0.01)
+ ser.setDTR(1)
+ time.sleep(0.01)
+ ser.setDTR(0)
+
+ # try magic number
+ ser.setRTS(1)
+ time.sleep(0.01)
+ ser.setDTR(1)
+ time.sleep(0.01)
+ ser.setDTR(0)
+ time.sleep(0.01)
+ ser.write("1EAF".encode("ascii"))
+ ser.flush()
+
+ # Delay a bit before proceeding
+ time.sleep(0.1)
+ finally:
+ # ok we're done here
+ ser.close()
+
+except Exception as e:
+ print('Failed to open serial port %s for reset' % maple_path)
+ sys.exit()
+
diff --git a/support/scripts/robotis-loader.py b/support/scripts/robotis-loader.py
new file mode 100755
index 0000000..95d4e71
--- /dev/null
+++ b/support/scripts/robotis-loader.py
@@ -0,0 +1,94 @@
+#!/usr/bin/python
+
+# This script sends a program on a robotis board (OpenCM9.04 or CM900)
+# using the robotis bootloader (used in OpenCM IDE)
+#
+# Usage:
+# python robotis-loader.py <serial port> <binary>
+#
+# Example:
+# python robotis-loader.py /dev/ttyACM0 firmware.bin
+#
+# https://github.com/Gregwar/robotis-loader
+
+import serial, sys, os, time
+
+print('~~ Robotis loader ~~')
+print('')
+
+# Reading command line
+if len(sys.argv) != 3:
+ exit('! Usage: robotis-loader.py <serial-port> <binary>')
+pgm, port, binary = sys.argv
+
+# Helper to prints a progress bar
+def progressBar(percent, precision=65):
+ threshold=precision*percent/100.0
+ sys.stdout.write('[ ')
+ for x in xrange(0, precision):
+ if x < threshold: sys.stdout.write('#')
+ else: sys.stdout.write(' ')
+ sys.stdout.write(' ] ')
+ sys.stdout.flush()
+
+# Opening the firmware file
+try:
+ stat = os.stat(binary)
+ size = stat.st_size
+ firmware = file(binary, 'rb')
+ print('* Opening %s, size=%d' % (binary, size))
+except:
+ exit('! Unable to open file %s' % binary)
+
+# Opening serial port
+try:
+ s = serial.Serial(port, baudrate=115200)
+except:
+ exit('! Unable to open serial port %s' % port)
+
+print('* Resetting the board')
+s.setRTS(True)
+s.setDTR(False)
+time.sleep(0.1)
+s.setRTS(False)
+s.write('CM9X')
+s.close()
+time.sleep(1.0);
+
+print('* Connecting...')
+s = serial.Serial(port, baudrate=115200)
+s.write('AT&LD')
+print('* Download signal transmitted, waiting...')
+
+# Entering bootloader sequence
+while True:
+ line = s.readline().strip()
+ if line.endswith('Ready..'):
+ print('* Board ready, sending data')
+ cs = 0
+ pos = 0
+ while True:
+ c = firmware.read(2048)
+ if len(c):
+ pos += len(c)
+ sys.stdout.write("\r")
+ progressBar(100*float(pos)/float(size))
+ s.write(c)
+ for k in range(0,len(c)):
+ cs = (cs+ord(c[k]))%256
+ else:
+ break
+ print('')
+ s.setDTR(True)
+ print('* Checksum: %d' % (cs))
+ s.write(chr(cs))
+ print('* Firmware was sent')
+ else:
+ if line == 'Success..':
+ print('* Success, running the code')
+ print('')
+ s.write('AT&RST')
+ s.close()
+ exit()
+ else:
+ print('Board -> '+line)
diff --git a/support/scripts/win-list-com-ports.py b/support/scripts/win-list-com-ports.py
new file mode 100644
index 0000000..3e6ecb8
--- /dev/null
+++ b/support/scripts/win-list-com-ports.py
@@ -0,0 +1,29 @@
+# Windows program for listing COM (serial) ports.
+#
+# enumerate_serial_ports() is by Eli Bendersky:
+#
+# http://eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/
+
+import _winreg as winreg
+import itertools
+
+def enumerate_serial_ports():
+ """ Uses the Win32 registry to return an
+ iterator of serial (COM) ports
+ existing on this computer.
+ """
+ path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
+ try:
+ key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
+ except WindowsError:
+ raise IterationError
+
+ for i in itertools.count():
+ try:
+ val = winreg.EnumValue(key, i)
+ yield str(val[1])
+ except EnvironmentError:
+ break
+
+for com in enumerate_serial_ports():
+ print com
diff --git a/support/stm32loader.py b/support/stm32loader.py
new file mode 100755
index 0000000..50686bf
--- /dev/null
+++ b/support/stm32loader.py
@@ -0,0 +1,532 @@
+#!/usr/bin/env python
+
+# -*- coding: utf-8 -*-
+# vim: sw=4:ts=4:si:et:enc=utf-8
+
+# Author: Ivan A-R <ivan@tuxotronic.org>
+# Project page: http://tuxotronic.org/wiki/projects/stm32loader
+#
+# This file is part of stm32loader.
+#
+# stm32loader is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3, or (at your option) any later
+# version.
+#
+# stm32loader 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 General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with stm32loader; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+from __future__ import print_function
+
+import sys, getopt
+import serial
+import time
+import glob
+import time
+import tempfile
+import os
+import subprocess
+
+try:
+ from progressbar import *
+ usepbar = 1
+except:
+ usepbar = 0
+
+# Verbose level
+QUIET = 5
+
+def mdebug(level, message):
+ if QUIET >= level:
+ print(message, file=sys.stderr)
+
+# Takes chip IDs (obtained via Get ID command) to human-readable names
+CHIP_ID_STRS = {0x410: 'STM32F1, performance, medium-density',
+ 0x411: 'STM32F2',
+ 0x412: 'STM32F1, performance, low-density',
+ 0x413: 'STM32F4',
+ 0x414: 'STM32F1, performance, high-density',
+ 0x416: 'STM32L1, performance, medium-density',
+ 0x418: 'STM32F1, connectivity',
+ 0x420: 'STM32F1, value, medium-density',
+ 0x428: 'STM32F1, value, high-density',
+ 0x430: 'STM32F1, performance, XL-density'}
+
+class CmdException(Exception):
+ pass
+
+class CommandInterface(object):
+ def open(self, aport='/dev/tty.usbserial-FTD3TMCH', abaudrate=115200) :
+ self.sp = serial.Serial(
+ port=aport,
+ baudrate=abaudrate, # baudrate
+ bytesize=8, # number of databits
+ parity=serial.PARITY_EVEN,
+ stopbits=1,
+ xonxoff=0, # enable software flow control
+ rtscts=0, # disable RTS/CTS flow control
+ timeout=0.5 # set a timeout value, None for waiting forever
+ )
+
+
+ def _wait_for_ack(self, info="", timeout=0):
+ stop = time.time() + timeout
+ got = None
+ while not got:
+ got = self.sp.read(1)
+ if time.time() > stop:
+ break
+
+ if not got:
+ raise CmdException("No response to %s" % info)
+
+ # wait for ask
+ ask = ord(got)
+
+ if ask == 0x79:
+ # ACK
+ return 1
+ 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)
+ time.sleep(0.1)
+ self.sp.setDTR(1)
+ time.sleep(0.5)
+
+ def initChip(self):
+ # Set boot
+ self.sp.setRTS(0)
+ self.reset()
+
+ # Be a bit more persistent when trying to initialise the chip
+ stop = time.time() + 5.0
+
+ while time.time() <= stop:
+ self.sp.write('\x7f')
+
+ got = self.sp.read()
+
+ # The chip will ACK a sync the very first time and
+ # NACK it every time afterwards
+ if got and got in '\x79\x1f':
+ # Synced up
+ return
+
+ raise CmdException('No response while trying to sync')
+
+ def releaseChip(self):
+ self.sp.setRTS(1)
+ self.reset()
+
+ def cmdGeneric(self, cmd):
+ self.sp.write(chr(cmd))
+ self.sp.write(chr(cmd ^ 0xFF)) # Control byte
+ return self._wait_for_ack(hex(cmd))
+
+ def cmdGet(self):
+ if self.cmdGeneric(0x00):
+ mdebug(10, "*** Get command");
+ len = ord(self.sp.read())
+ version = ord(self.sp.read())
+ mdebug(10, " Bootloader version: "+hex(version))
+ dat = map(lambda c: hex(ord(c)), self.sp.read(len))
+ mdebug(10, " Available commands: "+str(dat))
+ self._wait_for_ack("0x00 end")
+ return version
+ else:
+ raise CmdException("Get (0x00) failed")
+
+ def cmdGetVersion(self):
+ if self.cmdGeneric(0x01):
+ mdebug(10, "*** GetVersion command")
+ version = ord(self.sp.read())
+ self.sp.read(2)
+ self._wait_for_ack("0x01 end")
+ mdebug(10, " Bootloader version: "+hex(version))
+ return version
+ else:
+ raise CmdException("GetVersion (0x01) failed")
+
+ def cmdGetID(self):
+ if self.cmdGeneric(0x02):
+ mdebug(10, "*** GetID command")
+ len = ord(self.sp.read())
+ id = self.sp.read(len+1)
+ self._wait_for_ack("0x02 end")
+ return id
+ else:
+ raise CmdException("GetID (0x02) failed")
+
+
+ def _encode_addr(self, addr):
+ byte3 = (addr >> 0) & 0xFF
+ byte2 = (addr >> 8) & 0xFF
+ byte1 = (addr >> 16) & 0xFF
+ byte0 = (addr >> 24) & 0xFF
+ crc = byte0 ^ byte1 ^ byte2 ^ byte3
+ return (chr(byte0) + chr(byte1) + chr(byte2) + chr(byte3) + chr(crc))
+
+
+ def cmdReadMemory(self, addr, lng):
+ assert(lng <= 256)
+ if self.cmdGeneric(0x11):
+ mdebug(10, "*** ReadMemory command")
+ self.sp.write(self._encode_addr(addr))
+ self._wait_for_ack("0x11 address failed")
+ N = (lng - 1) & 0xFF
+ crc = N ^ 0xFF
+ self.sp.write(chr(N) + chr(crc))
+ self._wait_for_ack("0x11 length failed")
+ return map(lambda c: ord(c), self.sp.read(lng))
+ else:
+ raise CmdException("ReadMemory (0x11) failed")
+
+
+ def cmdGo(self, addr):
+ if self.cmdGeneric(0x21):
+ mdebug(10, "*** Go command")
+ self.sp.write(self._encode_addr(addr))
+ self._wait_for_ack("0x21 go failed")
+ else:
+ raise CmdException("Go (0x21) failed")
+
+
+ def cmdWriteMemory(self, addr, data):
+ assert(len(data) <= 256)
+ if self.cmdGeneric(0x31):
+ mdebug(10, "*** Write memory command")
+ self.sp.write(self._encode_addr(addr))
+ self._wait_for_ack("0x31 address failed")
+ #map(lambda c: hex(ord(c)), data)
+ lng = (len(data)-1) & 0xFF
+ mdebug(10, " %s bytes to write" % [lng+1]);
+ self.sp.write(chr(lng)) # len really
+ crc = 0xFF
+ for c in data:
+ crc = crc ^ c
+ self.sp.write(chr(c))
+ self.sp.write(chr(crc))
+ self._wait_for_ack("0x31 programming failed")
+ mdebug(10, " Write memory done")
+ else:
+ raise CmdException("Write memory (0x31) failed")
+
+
+ def cmdEraseMemory(self, sectors = None):
+ if self.cmdGeneric(0x43):
+ mdebug(10, "*** Erase memory command")
+ if sectors is None:
+ # Global erase
+ self.sp.write(chr(0xFF))
+ self.sp.write(chr(0x00))
+ else:
+ # Sectors erase
+ self.sp.write(chr((len(sectors)-1) & 0xFF))
+ crc = 0xFF
+ for c in sectors:
+ crc = crc ^ c
+ self.sp.write(chr(c))
+ self.sp.write(chr(crc))
+ self._wait_for_ack("0x43 erasing failed")
+ mdebug(10, " Erase memory done")
+ else:
+ raise CmdException("Erase memory (0x43) failed")
+
+
+ # TODO support for non-global mass erase
+ GLOBAL_ERASE_TIMEOUT_SECONDS = 20 # This takes a while
+ def cmdExtendedEraseMemory(self):
+ if self.cmdGeneric(0x44):
+ mdebug(10, "*** Extended erase memory command")
+ # Global mass erase
+ mdebug(5, "Global mass erase; this may take a while")
+ self.sp.write(chr(0xFF))
+ self.sp.write(chr(0xFF))
+ # Checksum
+ self.sp.write(chr(0x00))
+ self._wait_for_ack("0x44 extended erase failed",
+ timeout=self.GLOBAL_ERASE_TIMEOUT_SECONDS)
+ mdebug(10, " Extended erase memory done")
+ else:
+ raise CmdException("Extended erase memory (0x44) failed")
+
+
+ def cmdWriteProtect(self, sectors):
+ if self.cmdGeneric(0x63):
+ mdebug(10, "*** Write protect command")
+ self.sp.write(chr((len(sectors)-1) & 0xFF))
+ crc = 0xFF
+ for c in sectors:
+ crc = crc ^ c
+ self.sp.write(chr(c))
+ self.sp.write(chr(crc))
+ self._wait_for_ack("0x63 write protect failed")
+ mdebug(10, " Write protect done")
+ else:
+ raise CmdException("Write Protect memory (0x63) failed")
+
+ def cmdWriteUnprotect(self):
+ if self.cmdGeneric(0x73):
+ mdebug(10, "*** Write Unprotect command")
+ self._wait_for_ack("0x73 write unprotect failed")
+ self._wait_for_ack("0x73 write unprotect 2 failed")
+ mdebug(10, " Write Unprotect done")
+ else:
+ raise CmdException("Write Unprotect (0x73) failed")
+
+ def cmdReadoutProtect(self):
+ if self.cmdGeneric(0x82):
+ mdebug(10, "*** Readout protect command")
+ self._wait_for_ack("0x82 readout protect failed")
+ self._wait_for_ack("0x82 readout protect 2 failed")
+ mdebug(10, " Read protect done")
+ else:
+ raise CmdException("Readout protect (0x82) failed")
+
+ def cmdReadoutUnprotect(self):
+ if self.cmdGeneric(0x92):
+ mdebug(10, "*** Readout Unprotect command")
+ self._wait_for_ack("0x92 readout unprotect failed")
+ self._wait_for_ack("0x92 readout unprotect 2 failed")
+ mdebug(10, " Read Unprotect done")
+ else:
+ raise CmdException("Readout unprotect (0x92) failed")
+
+
+# Complex commands section
+
+ def readMemory(self, addr, lng):
+ data = []
+ 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)
+ else:
+ mdebug(5, "Read %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
+ data = data + self.cmdReadMemory(addr, 256)
+ addr = addr + 256
+ lng = lng - 256
+ if usepbar:
+ pbar.update(pbar.maxval-lng)
+ pbar.finish()
+ else:
+ mdebug(5, "Read %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
+ data = data + self.cmdReadMemory(addr, lng)
+ return data
+
+ def writeMemory(self, addr, data):
+ lng = len(data)
+
+ mdebug(5, "Writing %(lng)d bytes to start address 0x%(addr)X" %
+ { 'lng': lng, 'addr': addr})
+
+ if usepbar:
+ widgets = ['Writing: ', Percentage(),' ', ETA(), ' ', Bar()]
+ pbar = ProgressBar(widgets=widgets, maxval=lng, term_width=79).start()
+
+ offs = 0
+ while lng > 256:
+ if usepbar:
+ pbar.update(pbar.maxval-lng)
+ else:
+ mdebug(5, "Write %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
+ self.cmdWriteMemory(addr, data[offs:offs+256])
+ offs = offs + 256
+ addr = addr + 256
+ lng = lng - 256
+ if usepbar:
+ pbar.update(pbar.maxval-lng)
+ pbar.finish()
+ else:
+ mdebug(5, "Write %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
+ self.cmdWriteMemory(addr, data[offs:offs+lng] + ([0xFF] * (256-lng)) )
+
+
+def usage():
+ print("""Usage: %s [-hqVewvr] [-l length] [-p port] [-b baud] [-a addr] [file.bin]
+ -h This help
+ -q Quiet
+ -V Verbose
+ -e Erase
+ -w Write
+ -v Verify
+ -r Read
+ -l length Length of read
+ -p port Serial port (default: first USB-like port in /dev)
+ -b baud Baud speed (default: 115200)
+ -a addr Target address
+
+ ./stm32loader.py -e -w -v example/main.bin
+
+ """ % sys.argv[0])
+
+def read(filename):
+ """Read the file to be programmed and turn it into a binary"""
+ with open(filename, 'rb') as f:
+ bytes = f.read()
+
+ if bytes.startswith('\x7FELF'):
+ # Actually an ELF file. Convert to binary
+ handle, path = tempfile.mkstemp(suffix='.bin', prefix='stm32loader')
+
+ try:
+ os.close(handle)
+
+ # Try a couple of options for objcopy
+ for name in ['arm-none-eabi-objcopy', 'arm-linux-gnueabi-objcopy']:
+ try:
+ code = subprocess.call([name, '-Obinary', filename, path])
+
+ if code == 0:
+ return read(path)
+ except OSError:
+ pass
+ else:
+ raise Exception('Error %d while converting to a binary file' % code)
+ finally:
+ # Remove the temporary file
+ os.unlink(path)
+ else:
+ return [ord(x) for x in bytes]
+
+if __name__ == "__main__":
+
+ conf = {
+ 'port': 'auto',
+ 'baud': 115200,
+ 'address': 0x08000000,
+ 'erase': 0,
+ 'write': 0,
+ 'verify': 0,
+ 'read': 0,
+ 'len': 1000,
+ 'fname':'',
+ }
+
+# http://www.python.org/doc/2.5.2/lib/module-getopt.html
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "hqVewvrp:b:a:l:")
+ except getopt.GetoptError as err:
+ # print help information and exit:
+ print(str(err)) # will print something like "option -a not recognized"
+ usage()
+ sys.exit(2)
+
+ for o, a in opts:
+ if o == '-V':
+ QUIET = 10
+ elif o == '-q':
+ QUIET = 0
+ elif o == '-h':
+ usage()
+ sys.exit(0)
+ elif o == '-e':
+ conf['erase'] = 1
+ elif o == '-w':
+ conf['write'] = 1
+ elif o == '-v':
+ conf['verify'] = 1
+ elif o == '-r':
+ conf['read'] = 1
+ elif o == '-p':
+ conf['port'] = a
+ elif o == '-b':
+ conf['baud'] = eval(a)
+ elif o == '-a':
+ conf['address'] = eval(a)
+ elif o == '-l':
+ conf['len'] = eval(a)
+ else:
+ assert False, "unhandled option"
+
+ # Try and find the port automatically
+ if conf['port'] == 'auto':
+ ports = []
+
+ # Get a list of all USB-like names in /dev
+ for name in ['tty.usbserial', 'ttyUSB']:
+ ports.extend(glob.glob('/dev/%s*' % name))
+
+ ports = sorted(ports)
+
+ if ports:
+ # Found something - take it
+ conf['port'] = ports[0]
+
+ cmd = CommandInterface()
+ cmd.open(conf['port'], conf['baud'])
+ mdebug(10, "Open port %(port)s, baud %(baud)d" % {'port':conf['port'],
+ 'baud':conf['baud']})
+ try:
+ if (conf['write'] or conf['verify']):
+ mdebug(5, "Reading data from %s" % args[0])
+ data = read(args[0])
+
+ try:
+ cmd.initChip()
+ except CmdException:
+ print("Can't init. Ensure BOOT0=1, BOOT1=0, and reset device")
+
+ bootversion = cmd.cmdGet()
+
+ mdebug(0, "Bootloader version 0x%X" % bootversion)
+
+ if bootversion < 20 or bootversion >= 100:
+ raise Exception('Unreasonable bootloader version %d' % bootversion)
+
+ chip_id = cmd.cmdGetID()
+ assert len(chip_id) == 2, "Unreasonable chip id: %s" % repr(chip_id)
+ chip_id_num = (ord(chip_id[0]) << 8) | ord(chip_id[1])
+ chip_id_str = CHIP_ID_STRS.get(chip_id_num, None)
+
+ if chip_id_str is None:
+ mdebug(0, 'Warning: unrecognised chip ID 0x%x' % chip_id_num)
+ else:
+ mdebug(0, "Chip id 0x%x, %s" % (chip_id_num, chip_id_str))
+
+ if conf['erase']:
+ # Pre-3.0 bootloaders use the erase memory
+ # command. Starting with 3.0, extended erase memory
+ # replaced this command.
+ if bootversion < 0x30:
+ cmd.cmdEraseMemory()
+ else:
+ cmd.cmdExtendedEraseMemory()
+
+ if conf['write']:
+ cmd.writeMemory(conf['address'], data)
+
+ if conf['verify']:
+ verify = cmd.readMemory(conf['address'], len(data))
+ if(data == verify):
+ print("Verification OK")
+ else:
+ print("Verification FAILED")
+ print(str(len(data)) + ' vs ' + str(len(verify)))
+ for i in xrange(0, len(data)):
+ if data[i] != verify[i]:
+ print(hex(i) + ': ' + hex(data[i]) + ' vs ' + hex(verify[i]))
+
+ if not conf['write'] and conf['read']:
+ rdata = cmd.readMemory(conf['address'], conf['len'])
+ file(args[0], 'wb').write(''.join(map(chr,rdata)))
+
+ finally:
+ cmd.releaseChip()
+
diff --git a/wirish/HardwareSPI.cpp b/wirish/HardwareSPI.cpp
new file mode 100644
index 0000000..94985eb
--- /dev/null
+++ b/wirish/HardwareSPI.cpp
@@ -0,0 +1,320 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Wirish SPI implementation.
+ */
+
+#include <wirish/HardwareSPI.h>
+
+#include <libmaple/timer.h>
+#include <libmaple/util.h>
+#include <libmaple/rcc.h>
+
+#include <wirish/wirish.h>
+#include <wirish/boards.h>
+
+#if CYCLES_PER_MICROSECOND != 72
+/* TODO [0.2.0?] something smarter than this */
+#warning "Unexpected clock speed; SPI frequency calculation will be incorrect"
+#endif
+
+struct spi_pins {
+ uint8 nss;
+ uint8 sck;
+ uint8 miso;
+ uint8 mosi;
+};
+
+static const spi_pins* dev_to_spi_pins(spi_dev *dev);
+
+static void enable_device(spi_dev *dev,
+ bool as_master,
+ SPIFrequency frequency,
+ spi_cfg_flag endianness,
+ spi_mode mode);
+
+static const spi_pins board_spi_pins[] __FLASH__ = {
+ {BOARD_SPI1_NSS_PIN,
+ BOARD_SPI1_SCK_PIN,
+ BOARD_SPI1_MISO_PIN,
+ BOARD_SPI1_MOSI_PIN},
+ {BOARD_SPI2_NSS_PIN,
+ BOARD_SPI2_SCK_PIN,
+ BOARD_SPI2_MISO_PIN,
+ BOARD_SPI2_MOSI_PIN},
+#ifdef STM32_HIGH_DENSITY
+ {BOARD_SPI3_NSS_PIN,
+ BOARD_SPI3_SCK_PIN,
+ BOARD_SPI3_MISO_PIN,
+ BOARD_SPI3_MOSI_PIN},
+#endif
+};
+
+
+/*
+ * Constructor
+ */
+
+HardwareSPI::HardwareSPI(uint32 spi_num) {
+ switch (spi_num) {
+ case 1:
+ this->spi_d = SPI1;
+ break;
+ case 2:
+ this->spi_d = SPI2;
+ break;
+#ifdef STM32_HIGH_DENSITY
+ case 3:
+ this->spi_d = SPI3;
+ break;
+#endif
+ default:
+ ASSERT(0);
+ }
+}
+
+/*
+ * Set up/tear down
+ */
+
+void HardwareSPI::begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode) {
+ if (mode >= 4) {
+ ASSERT(0);
+ return;
+ }
+ spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB;
+ spi_mode m = (spi_mode)mode;
+ enable_device(this->spi_d, true, frequency, end, m);
+}
+
+void HardwareSPI::begin(void) {
+ this->begin(SPI_1_125MHZ, MSBFIRST, 0);
+}
+
+void HardwareSPI::beginSlave(uint32 bitOrder, uint32 mode) {
+ if (mode >= 4) {
+ ASSERT(0);
+ return;
+ }
+ spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB;
+ spi_mode m = (spi_mode)mode;
+ enable_device(this->spi_d, false, (SPIFrequency)0, end, m);
+}
+
+void HardwareSPI::beginSlave(void) {
+ this->beginSlave(MSBFIRST, 0);
+}
+
+void HardwareSPI::end(void) {
+ if (!spi_is_enabled(this->spi_d)) {
+ return;
+ }
+
+ // Follows RM0008's sequence for disabling a SPI in master/slave
+ // full duplex mode.
+ while (spi_is_rx_nonempty(this->spi_d)) {
+ // FIXME [0.1.0] remove this once you have an interrupt based driver
+ volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d);
+ }
+ while (!spi_is_tx_empty(this->spi_d))
+ ;
+ while (spi_is_busy(this->spi_d))
+ ;
+ spi_peripheral_disable(this->spi_d);
+}
+
+/*
+ * I/O
+ */
+
+uint8 HardwareSPI::read(void) {
+ uint8 buf[1];
+ this->read(buf, 1);
+ return buf[0];
+}
+
+void HardwareSPI::read(uint8 *buf, uint32 len) {
+ uint32 rxed = 0;
+ while (rxed < len) {
+ while (!spi_is_rx_nonempty(this->spi_d))
+ ;
+ buf[rxed++] = (uint8)spi_rx_reg(this->spi_d);
+ }
+}
+
+void HardwareSPI::write(uint8 byte) {
+ this->write(&byte, 1);
+}
+
+void HardwareSPI::write(const uint8 *data, uint32 length) {
+ uint32 txed = 0;
+ while (txed < length) {
+ txed += spi_tx(this->spi_d, data + txed, length - txed);
+ }
+}
+
+uint8 HardwareSPI::transfer(uint8 byte) {
+ this->write(byte);
+ return this->read();
+}
+
+/*
+ * Pin accessors
+ */
+
+uint8 HardwareSPI::misoPin(void) {
+ return dev_to_spi_pins(this->spi_d)->miso;
+}
+
+uint8 HardwareSPI::mosiPin(void) {
+ return dev_to_spi_pins(this->spi_d)->mosi;
+}
+
+uint8 HardwareSPI::sckPin(void) {
+ return dev_to_spi_pins(this->spi_d)->sck;
+}
+
+uint8 HardwareSPI::nssPin(void) {
+ return dev_to_spi_pins(this->spi_d)->nss;
+}
+
+/*
+ * Deprecated functions
+ */
+
+uint8 HardwareSPI::send(uint8 data) {
+ uint8 buf[] = {data};
+ return this->send(buf, 1);
+}
+
+uint8 HardwareSPI::send(uint8 *buf, uint32 len) {
+ uint32 txed = 0;
+ uint8 ret = 0;
+ while (txed < len) {
+ this->write(buf[txed++]);
+ ret = this->read();
+ }
+ return ret;
+}
+
+uint8 HardwareSPI::recv(void) {
+ return this->read();
+}
+
+/*
+ * Auxiliary functions
+ */
+
+static void configure_gpios(spi_dev *dev, bool as_master);
+static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq);
+
+static const spi_pins* dev_to_spi_pins(spi_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_SPI1: return board_spi_pins;
+ case RCC_SPI2: return board_spi_pins + 1;
+#ifdef STM32_HIGH_DENSITY
+ case RCC_SPI3: return board_spi_pins + 2;
+#endif
+ default: return NULL;
+ }
+}
+
+/* Enables the device in master or slave full duplex mode. If you
+ * change this code, you must ensure that appropriate changes are made
+ * to HardwareSPI::end(). */
+static void enable_device(spi_dev *dev,
+ bool as_master,
+ SPIFrequency freq,
+ spi_cfg_flag endianness,
+ spi_mode mode) {
+ spi_baud_rate baud = determine_baud_rate(dev, freq);
+ uint32 cfg_flags = (endianness | SPI_DFF_8_BIT | SPI_SW_SLAVE |
+ (as_master ? SPI_SOFT_SS : 0));
+
+ spi_init(dev);
+ configure_gpios(dev, as_master);
+ if (as_master) {
+ spi_master_enable(dev, baud, mode, cfg_flags);
+ } else {
+ spi_slave_enable(dev, mode, cfg_flags);
+ }
+}
+
+static void disable_pwm(const stm32_pin_info *i) {
+ if (i->timer_device) {
+ timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED);
+ }
+}
+
+static void configure_gpios(spi_dev *dev, bool as_master) {
+ const spi_pins *pins = dev_to_spi_pins(dev);
+
+ if (!pins) {
+ return;
+ }
+
+ const stm32_pin_info *nssi = &PIN_MAP[pins->nss];
+ const stm32_pin_info *scki = &PIN_MAP[pins->sck];
+ const stm32_pin_info *misoi = &PIN_MAP[pins->miso];
+ const stm32_pin_info *mosii = &PIN_MAP[pins->mosi];
+
+ disable_pwm(nssi);
+ disable_pwm(scki);
+ disable_pwm(misoi);
+ disable_pwm(mosii);
+
+ spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit,
+ scki->gpio_device, scki->gpio_bit, misoi->gpio_bit,
+ mosii->gpio_bit);
+}
+
+static const spi_baud_rate baud_rates[MAX_SPI_FREQS] __FLASH__ = {
+ SPI_BAUD_PCLK_DIV_2,
+ SPI_BAUD_PCLK_DIV_4,
+ SPI_BAUD_PCLK_DIV_8,
+ SPI_BAUD_PCLK_DIV_16,
+ SPI_BAUD_PCLK_DIV_32,
+ SPI_BAUD_PCLK_DIV_64,
+ SPI_BAUD_PCLK_DIV_128,
+ SPI_BAUD_PCLK_DIV_256,
+};
+
+/*
+ * Note: This assumes you're on a LeafLabs-style board
+ * (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz).
+ */
+static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq) {
+ if (rcc_dev_clk(dev->clk_id) == RCC_APB2 && freq == SPI_140_625KHZ) {
+ /* APB2 peripherals are too fast for 140.625 KHz */
+ ASSERT(0);
+ return (spi_baud_rate)~0;
+ }
+ return (rcc_dev_clk(dev->clk_id) == RCC_APB2 ?
+ baud_rates[freq + 1] :
+ baud_rates[freq]);
+}
diff --git a/wirish/HardwareSerial.cpp b/wirish/HardwareSerial.cpp
new file mode 100644
index 0000000..3036983
--- /dev/null
+++ b/wirish/HardwareSerial.cpp
@@ -0,0 +1,137 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/HardwareSerial.cpp
+ * @brief Wirish serial port implementation.
+ */
+
+#include <wirish/HardwareSerial.h>
+
+#include <libmaple/libmaple.h>
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+#include <libmaple/usart.h>
+
+#define DEFINE_HWSERIAL(name, n) \
+ HardwareSerial name(USART##n, \
+ BOARD_USART##n##_TX_PIN, \
+ BOARD_USART##n##_RX_PIN)
+
+#if BOARD_HAVE_USART1
+DEFINE_HWSERIAL(Serial1, 1);
+#endif
+#if BOARD_HAVE_USART2
+DEFINE_HWSERIAL(Serial2, 2);
+#endif
+#if BOARD_HAVE_USART3
+DEFINE_HWSERIAL(Serial3, 3);
+#endif
+#if BOARD_HAVE_UART4
+DEFINE_HWSERIAL(Serial4, 4);
+#endif
+#if BOARD_HAVE_UART5
+DEFINE_HWSERIAL(Serial5, 5);
+#endif
+#if BOARD_HAVE_USART6
+DEFINE_HWSERIAL(Serial6, 6);
+#endif
+
+HardwareSerial::HardwareSerial(usart_dev *usart_device,
+ uint8 tx_pin,
+ uint8 rx_pin) {
+ this->usart_device = usart_device;
+ this->tx_pin = tx_pin;
+ this->rx_pin = rx_pin;
+}
+
+/*
+ * Set up/tear down
+ */
+
+#if STM32_MCU_SERIES == STM32_SERIES_F1
+/* F1 MCUs have no GPIO_AFR[HL], so turn off PWM if there's a conflict
+ * on this GPIO bit. */
+static void disable_timer_if_necessary(timer_dev *dev, uint8 ch) {
+ if (dev != NULL) {
+ timer_set_mode(dev, ch, TIMER_DISABLED);
+ }
+}
+#elif (STM32_MCU_SERIES == STM32_SERIES_F2) || \
+ (STM32_MCU_SERIES == STM32_SERIES_F4)
+#define disable_timer_if_necessary(dev, ch) ((void)0)
+#else
+#warning "Unsupported STM32 series; timer conflicts are possible"
+#endif
+
+void HardwareSerial::begin(uint32 baud) {
+ ASSERT(baud <= this->usart_device->max_baud);
+
+ if (baud > this->usart_device->max_baud) {
+ return;
+ }
+
+ const stm32_pin_info *txi = &PIN_MAP[this->tx_pin];
+ const stm32_pin_info *rxi = &PIN_MAP[this->rx_pin];
+
+ disable_timer_if_necessary(txi->timer_device, txi->timer_channel);
+
+ usart_config_gpios_async(this->usart_device,
+ rxi->gpio_device, rxi->gpio_bit,
+ txi->gpio_device, txi->gpio_bit,
+ 0);
+ usart_init(this->usart_device);
+ usart_set_baud_rate(this->usart_device, USART_USE_PCLK, baud);
+ usart_enable(this->usart_device);
+}
+
+void HardwareSerial::end(void) {
+ usart_disable(this->usart_device);
+}
+
+/*
+ * I/O
+ */
+
+uint8 HardwareSerial::read(void) {
+ // Block until a byte becomes available, to save user confusion.
+ while (!this->available())
+ ;
+ return usart_getc(this->usart_device);
+}
+
+uint32 HardwareSerial::available(void) {
+ return usart_data_available(this->usart_device);
+}
+
+void HardwareSerial::write(unsigned char ch) {
+ usart_putc(this->usart_device, ch);
+}
+
+void HardwareSerial::flush(void) {
+ usart_reset_rx(this->usart_device);
+}
diff --git a/wirish/HardwareTimer.cpp b/wirish/HardwareTimer.cpp
new file mode 100644
index 0000000..4f68ad7
--- /dev/null
+++ b/wirish/HardwareTimer.cpp
@@ -0,0 +1,156 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Bryan Newbold.
+ *
+ * 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 <wirish/HardwareTimer.h>
+
+#include <libmaple/rcc.h>
+#include <wirish/ext_interrupts.h> // for noInterrupts(), interrupts()
+#include <wirish/wirish_math.h>
+#include <board/board.h> // for CYCLES_PER_MICROSECOND
+
+// TODO [0.1.0] Remove deprecated pieces
+
+/*
+ * Evil hack to infer this->dev from timerNum in the HardwareTimer
+ * constructor. See:
+ *
+ * http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
+ * http://yosefk.com/c++fqa/function.html#fqa-33.2
+ */
+
+extern "C" {
+ static timer_dev **this_devp;
+ static rcc_clk_id this_id;
+ static void set_this_dev(timer_dev *dev) {
+ if (dev->clk_id == this_id) {
+ *this_devp = dev;
+ }
+ }
+}
+
+/*
+ * HardwareTimer routines
+ */
+
+HardwareTimer::HardwareTimer(uint8 timerNum) {
+ rcc_clk_id timerID = (rcc_clk_id)(RCC_TIMER1 + (timerNum - 1));
+ this->dev = NULL;
+ noInterrupts(); // Hack to ensure we're the only ones using
+ // set_this_dev() and friends. TODO: use a lock.
+ this_id = timerID;
+ this_devp = &this->dev;
+ timer_foreach(set_this_dev);
+ interrupts();
+ ASSERT(this->dev != NULL);
+}
+
+void HardwareTimer::pause(void) {
+ timer_pause(this->dev);
+}
+
+void HardwareTimer::resume(void) {
+ timer_resume(this->dev);
+}
+
+uint32 HardwareTimer::getPrescaleFactor(void) {
+ return timer_get_prescaler(this->dev) + 1;
+}
+
+void HardwareTimer::setPrescaleFactor(uint32 factor) {
+ timer_set_prescaler(this->dev, (uint16)(factor - 1));
+}
+
+uint16 HardwareTimer::getOverflow() {
+ return timer_get_reload(this->dev);
+}
+
+void HardwareTimer::setOverflow(uint16 val) {
+ timer_set_reload(this->dev, val);
+}
+
+uint16 HardwareTimer::getCount(void) {
+ return timer_get_count(this->dev);
+}
+
+void HardwareTimer::setCount(uint16 val) {
+ uint16 ovf = this->getOverflow();
+ timer_set_count(this->dev, min(val, ovf));
+}
+
+#define MAX_RELOAD ((1 << 16) - 1)
+uint16 HardwareTimer::setPeriod(uint32 microseconds) {
+ // Not the best way to handle this edge case?
+ if (!microseconds) {
+ this->setPrescaleFactor(1);
+ this->setOverflow(1);
+ return this->getOverflow();
+ }
+
+ uint32 period_cyc = microseconds * CYCLES_PER_MICROSECOND;
+ uint16 prescaler = (uint16)(period_cyc / MAX_RELOAD + 1);
+ uint16 overflow = (uint16)((period_cyc + (prescaler / 2)) / prescaler);
+ this->setPrescaleFactor(prescaler);
+ this->setOverflow(overflow);
+ return overflow;
+}
+
+void HardwareTimer::setMode(int channel, timer_mode mode) {
+ timer_set_mode(this->dev, (uint8)channel, (timer_mode)mode);
+}
+
+uint16 HardwareTimer::getCompare(int channel) {
+ return timer_get_compare(this->dev, (uint8)channel);
+}
+
+void HardwareTimer::setCompare(int channel, uint16 val) {
+ uint16 ovf = this->getOverflow();
+ timer_set_compare(this->dev, (uint8)channel, min(val, ovf));
+}
+
+void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) {
+ timer_attach_interrupt(this->dev, (uint8)channel, handler);
+}
+
+void HardwareTimer::detachInterrupt(int channel) {
+ timer_detach_interrupt(this->dev, (uint8)channel);
+}
+
+void HardwareTimer::refresh(void) {
+ timer_generate_update(this->dev);
+}
+
+/* -- Deprecated predefined instances -------------------------------------- */
+
+HardwareTimer Timer1(1);
+HardwareTimer Timer2(2);
+HardwareTimer Timer3(3);
+HardwareTimer Timer4(4);
+#ifdef STM32_HIGH_DENSITY
+HardwareTimer Timer5(5);
+HardwareTimer Timer6(6);
+HardwareTimer Timer7(7);
+HardwareTimer Timer8(8);
+#endif
diff --git a/wirish/Print.cpp b/wirish/Print.cpp
new file mode 100644
index 0000000..f6bc0c6
--- /dev/null
+++ b/wirish/Print.cpp
@@ -0,0 +1,252 @@
+/*
+ * Print.cpp - Base class that provides print() and println()
+ * Copyright (c) 2008 David A. Mellis. All right reserved.
+ * Copyright (c) 2011 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.
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Modified 23 November 2006 by David A. Mellis
+ * Modified 12 April 2011 by Marti Bolivar <mbolivar@leaflabs.com>
+ */
+
+#include <wirish/Print.h>
+
+#include <wirish/wirish_math.h>
+#include <limits.h>
+
+#ifndef LLONG_MAX
+/*
+ * Note:
+ *
+ * At time of writing (12 April 2011), the limits.h that came with the
+ * newlib we distributed didn't include LLONG_MAX. Because we're
+ * staying away from using templates (see /notes/coding_standard.rst,
+ * "Language Features and Compiler Extensions"), this value was
+ * copy-pasted from a println() of the value
+ *
+ * std::numeric_limits<long long>::max().
+ */
+#define LLONG_MAX 9223372036854775807LL
+#endif
+
+/*
+ * Public methods
+ */
+
+void Print::write(const char *str) {
+ while (*str) {
+ write(*str++);
+ }
+}
+
+void Print::write(const void *buffer, uint32 size) {
+ uint8 *ch = (uint8*)buffer;
+ while (size--) {
+ write(*ch++);
+ }
+}
+
+void Print::print(uint8 b, int base) {
+ print((uint64)b, base);
+}
+
+void Print::print(char c) {
+ write(c);
+}
+
+void Print::print(const char str[]) {
+ write(str);
+}
+
+void Print::print(int n, int base) {
+ print((long long)n, base);
+}
+
+void Print::print(unsigned int n, int base) {
+ print((unsigned long long)n, base);
+}
+
+void Print::print(long n, int base) {
+ print((long long)n, base);
+}
+
+void Print::print(unsigned long n, int base) {
+ print((unsigned long long)n, base);
+}
+
+void Print::print(long long n, int base) {
+ if (base == BYTE) {
+ write((uint8)n);
+ return;
+ }
+ if (n < 0) {
+ print('-');
+ n = -n;
+ }
+ printNumber(n, base);
+}
+
+void Print::print(unsigned long long n, int base) {
+ if (base == BYTE) {
+ write((uint8)n);
+ } else {
+ printNumber(n, base);
+ }
+}
+
+void Print::print(double n, int digits) {
+ printFloat(n, digits);
+}
+
+void Print::println(void) {
+ print('\r');
+ print('\n');
+}
+
+void Print::println(char c) {
+ print(c);
+ println();
+}
+
+void Print::println(const char c[]) {
+ print(c);
+ println();
+}
+
+void Print::println(uint8 b, int base) {
+ print(b, base);
+ println();
+}
+
+void Print::println(int n, int base) {
+ print(n, base);
+ println();
+}
+
+void Print::println(unsigned int n, int base) {
+ print(n, base);
+ println();
+}
+
+void Print::println(long n, int base) {
+ print((long long)n, base);
+ println();
+}
+
+void Print::println(unsigned long n, int base) {
+ print((unsigned long long)n, base);
+ println();
+}
+
+void Print::println(long long n, int base) {
+ print(n, base);
+ println();
+}
+
+void Print::println(unsigned long long n, int base) {
+ print(n, base);
+ println();
+}
+
+void Print::println(double n, int digits) {
+ print(n, digits);
+ println();
+}
+
+/*
+ * Private methods
+ */
+
+void Print::printNumber(unsigned long long n, uint8 base) {
+ unsigned char buf[CHAR_BIT * sizeof(long long)];
+ unsigned long i = 0;
+
+ if (n == 0) {
+ print('0');
+ return;
+ }
+
+ while (n > 0) {
+ buf[i++] = n % base;
+ n /= base;
+ }
+
+ for (; i > 0; i--) {
+ print((char)(buf[i - 1] < 10 ?
+ '0' + buf[i - 1] :
+ 'A' + buf[i - 1] - 10));
+ }
+}
+
+/* According to snprintf(),
+ *
+ * nextafter((double)numeric_limits<long long>::max(), 0.0) ~= 9.22337e+18
+ *
+ * This slightly smaller value was picked semi-arbitrarily. */
+#define LARGE_DOUBLE_TRESHOLD (9.1e18)
+
+/* THIS FUNCTION SHOULDN'T BE USED IF YOU NEED ACCURATE RESULTS.
+ *
+ * This implementation is meant to be simple and not occupy too much
+ * code size. However, printing floating point values accurately is a
+ * subtle task, best left to a well-tested library function.
+ *
+ * See Steele and White 2003 for more details:
+ *
+ * http://kurtstephens.com/files/p372-steele.pdf
+ */
+void Print::printFloat(double number, uint8 digits) {
+ // Hackish fail-fast behavior for large-magnitude doubles
+ if (abs(number) >= LARGE_DOUBLE_TRESHOLD) {
+ if (number < 0.0) {
+ print('-');
+ }
+ print("<large double>");
+ return;
+ }
+
+ // Handle negative numbers
+ if (number < 0.0) {
+ print('-');
+ number = -number;
+ }
+
+ // Simplistic rounding strategy so that e.g. print(1.999, 2)
+ // prints as "2.00"
+ double rounding = 0.5;
+ for (uint8 i = 0; i < digits; i++) {
+ rounding /= 10.0;
+ }
+ number += rounding;
+
+ // Extract the integer part of the number and print it
+ long long int_part = (long long)number;
+ double remainder = number - int_part;
+ print(int_part);
+
+ // Print the decimal point, but only if there are digits beyond
+ if (digits > 0) {
+ print(".");
+ }
+
+ // Extract digits from the remainder one at a time
+ while (digits-- > 0) {
+ remainder *= 10.0;
+ int to_print = (int)remainder;
+ print(to_print);
+ remainder -= to_print;
+ }
+}
diff --git a/wirish/boards.cpp b/wirish/boards.cpp
new file mode 100644
index 0000000..77a05de
--- /dev/null
+++ b/wirish/boards.cpp
@@ -0,0 +1,219 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards.cpp
+ * @brief init() and board routines.
+ *
+ * This file is mostly interesting for the init() function, which
+ * configures Flash, the core clocks, and a variety of other available
+ * peripherals on the board so the rest of Wirish doesn't have to turn
+ * things on before using them.
+ *
+ * Prior to returning, init() calls boardInit(), which allows boards
+ * to perform any initialization they need to. This file includes a
+ * weak no-op definition of boardInit(), so boards that don't need any
+ * special initialization don't have to define their own.
+ *
+ * How init() works is chip-specific. See the boards_setup.cpp files
+ * under e.g. wirish/stm32f1/, wirish/stmf32f2 for the details, but be
+ * advised: their contents are unstable, and can/will change without
+ * notice.
+ */
+
+#include <wirish/boards.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/flash.h>
+#include <libmaple/nvic.h>
+#include <libmaple/systick.h>
+#include "boards_private.h"
+
+static void setup_flash(void);
+static void setup_clocks(void);
+static void setup_nvic(void);
+static void setup_adcs(void);
+static void setup_timers(void);
+
+/*
+ * Exported functions
+ */
+
+void init(void) {
+ setup_flash();
+ setup_clocks();
+ setup_nvic();
+ systick_init(SYSTICK_RELOAD_VAL);
+ wirish::priv::board_setup_gpio();
+ setup_adcs();
+ setup_timers();
+ wirish::priv::board_setup_usb();
+ wirish::priv::series_init();
+ boardInit();
+}
+
+/* Provide a default no-op boardInit(). */
+__weak void boardInit(void) {
+}
+
+/* You could farm this out to the files in boards/ if e.g. it takes
+ * too long to test on boards with lots of pins. */
+bool boardUsesPin(uint8 pin) {
+ for (int i = 0; i < BOARD_NR_USED_PINS; i++) {
+ if (pin == boardUsedPins[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * Auxiliary routines
+ */
+
+static void setup_flash(void) {
+ // Turn on as many Flash "go faster" features as
+ // possible. flash_enable_features() just ignores any flags it
+ // can't support.
+ flash_enable_features(FLASH_PREFETCH | FLASH_ICACHE | FLASH_DCACHE);
+ // Configure the wait states, assuming we're operating at "close
+ // enough" to 3.3V.
+ flash_set_latency(FLASH_SAFE_WAIT_STATES);
+}
+
+static void setup_clocks(void) {
+ // Turn on HSI. We'll switch to and run off of this while we're
+ // setting up the main PLL.
+ rcc_turn_on_clk(RCC_CLK_HSI);
+
+ // Turn off and reset the clock subsystems we'll be using, as well
+ // as the clock security subsystem (CSS). Note that resetting CFGR
+ // to its default value of 0 implies a switch to HSI for SYSCLK.
+ RCC_BASE->CFGR = 0x00000000;
+ rcc_disable_css();
+ rcc_turn_off_clk(RCC_CLK_PLL);
+ rcc_turn_off_clk(RCC_CLK_HSE);
+ wirish::priv::board_reset_pll();
+ // Clear clock readiness interrupt flags and turn off clock
+ // readiness interrupts.
+ RCC_BASE->CIR = 0x00000000;
+
+ // Enable HSE, and wait until it's ready.
+ rcc_turn_on_clk(RCC_CLK_HSE);
+ while (!rcc_is_clk_ready(RCC_CLK_HSE))
+ ;
+
+ // Configure AHBx, APBx, etc. prescalers and the main PLL.
+ wirish::priv::board_setup_clock_prescalers();
+ rcc_configure_pll(&wirish::priv::w_board_pll_cfg);
+
+ // Enable the PLL, and wait until it's ready.
+ rcc_turn_on_clk(RCC_CLK_PLL);
+ while(!rcc_is_clk_ready(RCC_CLK_PLL))
+ ;
+
+ // Finally, switch to the now-ready PLL as the main clock source.
+ rcc_switch_sysclk(RCC_CLKSRC_PLL);
+}
+
+/*
+ * These addresses are where usercode starts when a bootloader is
+ * present. If no bootloader is present, the user NVIC usually starts
+ * at the Flash base address, 0x08000000.
+ */
+#if defined(BOOTLOADER_maple)
+#define USER_ADDR_ROM 0x08005000
+#elif defined(BOOTLOADER_robotis)
+#define USER_ADDR_ROM 0x08003000
+#endif
+#define USER_ADDR_RAM 0x20000C00
+extern char __text_start__;
+
+static void setup_nvic(void) {
+#ifdef VECT_TAB_FLASH
+ nvic_init(USER_ADDR_ROM, 0);
+#elif defined VECT_TAB_RAM
+ nvic_init(USER_ADDR_RAM, 0);
+#elif defined VECT_TAB_BASE
+ nvic_init((uint32)0x08000000, 0);
+#elif defined VECT_TAB_ADDR
+ // A numerically supplied value
+ nvic_init((uint32)VECT_TAB_ADDR, 0);
+#else
+ // Use the __text_start__ value from the linker script; this
+ // should be the start of the vector table.
+ nvic_init((uint32)&__text_start__, 0);
+#endif
+}
+
+static void adc_default_config(const adc_dev *dev) {
+ adc_enable_single_swstart(dev);
+ adc_set_sample_rate(dev, wirish::priv::w_adc_smp);
+}
+
+static void setup_adcs(void) {
+ adc_set_prescaler(wirish::priv::w_adc_pre);
+ adc_foreach(adc_default_config);
+}
+
+static void timer_default_config(timer_dev *dev) {
+ timer_adv_reg_map *regs = (dev->regs).adv;
+ const uint16 full_overflow = 0xFFFF;
+ const uint16 half_duty = 0x8FFF;
+
+ timer_init(dev);
+ timer_pause(dev);
+
+ regs->CR1 = TIMER_CR1_ARPE;
+ regs->PSC = 1;
+ regs->SR = 0;
+ regs->DIER = 0;
+ regs->EGR = TIMER_EGR_UG;
+ switch (dev->type) {
+ case TIMER_ADVANCED:
+ regs->BDTR = TIMER_BDTR_MOE | TIMER_BDTR_LOCK_OFF;
+ // fall-through
+ case TIMER_GENERAL:
+ timer_set_reload(dev, full_overflow);
+ for (uint8 channel = 1; channel <= 4; channel++) {
+ if (timer_has_cc_channel(dev, channel)) {
+ timer_set_compare(dev, channel, half_duty);
+ timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1,
+ TIMER_OC_PE);
+ }
+ }
+ // fall-through
+ case TIMER_BASIC:
+ break;
+ }
+
+ timer_generate_update(dev);
+ timer_resume(dev);
+}
+
+static void setup_timers(void) {
+ timer_foreach(timer_default_config);
+}
diff --git a/wirish/boards/VLDiscovery/board.cpp b/wirish/boards/VLDiscovery/board.cpp
new file mode 100644
index 0000000..c86204d
--- /dev/null
+++ b/wirish/boards/VLDiscovery/board.cpp
@@ -0,0 +1,104 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/VLDiscovery/board.cpp
+ * @author Anton Eltchaninov <anton.eltchaninov@gmail.com>
+ * @brief VLDiscovery board file.
+ */
+
+#include <board/board.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+#include <wirish/wirish_types.h>
+
+void boardInit(void) {
+ afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY);
+}
+
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+
+ {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D0/PA3 */
+ {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D1/PA2 */
+ {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D2/PA0 (BUT) */
+ {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D3/PA1 */
+ {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D4/PB5 */
+ {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D5/PB6 */
+ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D6/PA8 */
+ {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D7/PA9 */
+ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D8/PA10 */
+ {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D9/PB7 */
+ {GPIOA, NULL, ADC1, 4, 0, 4}, /* D10/PA4 */
+ {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D11/PA7 */
+ {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D12/PA6 */
+ {GPIOA, NULL, ADC1, 5, 0, 5}, /* D13/PA5 */
+ {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D14/PB8 */
+ {GPIOC, NULL, ADC1, 0, 0, 10}, /* D15/PC0 */
+ {GPIOC, NULL, ADC1, 1, 0, 11}, /* D16/PC1 */
+ {GPIOC, NULL, ADC1, 2, 0, 12}, /* D17/PC2 */
+ {GPIOC, NULL, ADC1, 3, 0, 13}, /* D18/PC3 */
+ {GPIOC, NULL, ADC1, 4, 0, 14}, /* D19/PC4 */
+ {GPIOC, NULL, ADC1, 5, 0, 15}, /* D20/PC5 */
+ {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D21/PC13 */
+ {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D22/PC14 */
+ {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D23/PC15 */
+ {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D24/PB9 */
+ {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D25/PD2 */
+ {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D26/PC10 */
+ {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D27/PB0 */
+ {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D28/PB1 */
+ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D29/PB10 */
+ {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D30/PB11 */
+ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D31/PB12 */
+ {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D32/PB13 */
+ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D33/PB14 */
+ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D34/PB15 */
+ {GPIOC, NULL, NULL, 6, 0, ADCx}, /* D35/PC6 */
+ {GPIOC, NULL, NULL, 7, 0, ADCx}, /* D36/PC7 */
+ {GPIOC, NULL, NULL, 8, 0, ADCx}, /* D37/PC8 (Blue led) */
+ {GPIOC, NULL, NULL, 9, 0, ADCx}, /* D38/PC9 (Green led) */
+ {GPIOA, TIMER1, NULL, 11, 4, ADCx}, /* D39/PA11 */
+ {GPIOA, NULL, NULL, 12, 0, ADCx}, /* D40/PA12 */
+ {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D41/PA15 */
+ {GPIOB, NULL, NULL, 2, 0, ADCx}, /* D42/PB2 */
+ {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D43/PB3 */
+ {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D44/PB4 */
+ {GPIOC, NULL, NULL, 11, 0, ADCx}, /* D45/PC11 */
+ {GPIOC, NULL, NULL, 12, 0, ADCx} /* D46/PC12 */
+};
+
+extern const uint8 boardPWMPins[] __FLASH__ = {
+ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 27, 28
+};
+
+extern const uint8 boardADCPins[] __FLASH__ = {
+ 0, 1, 2, 3, 10, 11, 12, 15, 16, 17, 18, 19, 20, 27, 28
+};
+
+extern const uint8 boardUsedPins[] __FLASH__ = {
+ BOARD_BLUE_LED_PIN, BOARD_GREEN_LED_PIN, BOARD_BUTTON_PIN
+};
diff --git a/wirish/boards/VLDiscovery/include/board/board.h b/wirish/boards/VLDiscovery/include/board/board.h
new file mode 100644
index 0000000..04d21c7
--- /dev/null
+++ b/wirish/boards/VLDiscovery/include/board/board.h
@@ -0,0 +1,91 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/VLDiscovery/include/board/board.h
+ * @author Anton Eltchaninov <anton.eltchaninov@gmail.com>
+ * @brief VLDiscovery board header.
+ */
+
+#ifndef _BOARD_VLDISCOVERY_H_
+#define _BOARD_VLDISCOVERY_H_
+
+#define BOARD_RCC_PLLMUL RCC_PLLMUL_3
+
+#define CYCLES_PER_MICROSECOND 24
+#define SYSTICK_RELOAD_VAL 23999 /* takes a cycle to reload */
+
+#define BOARD_BUTTON_PIN 2 /* PA0 USER */
+#define BOARD_BLUE_LED_PIN 37 /* blue led LD4 */
+#define BOARD_GREEN_LED_PIN 38 /* green led LD3 */
+#define BOARD_LED_PIN BOARD_BLUE_LED_PIN
+
+/* Number of USARTs/UARTs whose pins are broken out to headers */
+#define BOARD_NR_USARTS 3
+
+/* Default USART pin numbers (not considering AFIO remap) */
+#define BOARD_USART1_TX_PIN 7
+#define BOARD_USART1_RX_PIN 8
+#define BOARD_USART2_TX_PIN 1
+#define BOARD_USART2_RX_PIN 0
+#define BOARD_USART3_TX_PIN 29
+#define BOARD_USART3_RX_PIN 30
+
+/* Number of SPI ports */
+#define BOARD_NR_SPI 2
+
+/* Default SPI pin numbers (not considering AFIO remap) */
+#define BOARD_SPI1_NSS_PIN 10
+#define BOARD_SPI1_MOSI_PIN 11
+#define BOARD_SPI1_MISO_PIN 12
+#define BOARD_SPI1_SCK_PIN 13
+#define BOARD_SPI2_NSS_PIN 31
+#define BOARD_SPI2_MOSI_PIN 34
+#define BOARD_SPI2_MISO_PIN 33
+#define BOARD_SPI2_SCK_PIN 32
+
+/* Total number of GPIO pins that are broken out to headers and
+ * intended for general use. */
+#define BOARD_NR_GPIO_PINS 47
+
+/* Number of pins capable of PWM output */
+#define BOARD_NR_PWM_PINS 15
+
+/* Number of pins capable of ADC conversion */
+#define BOARD_NR_ADC_PINS 15
+
+/* Number of pins already connected to external hardware. */
+#define BOARD_NR_USED_PINS 3
+
+/* Save Maple pin order and define aliases */
+enum {
+PA3, PA2, PA0, PA1, PB5, PB6, PA8, PA9, PA10, PB7, PA4, PA7, PA6, PA5,
+PB8, PC0, PC1, PC2, PC3, PC4, PC5, PC13, PC14, PC15, PB9, PD2, PC10,
+PB0, PB1, PB10, PB11, PB12, PB13, PB14, PB15, PC6, PC7, PC8, PC9,
+PA11, PA12, PA15, PB2, PB3, PB4, PC11, PC12 };
+
+
+#endif
diff --git a/wirish/boards/cm900/board.cpp b/wirish/boards/cm900/board.cpp
new file mode 100644
index 0000000..ec747b3
--- /dev/null
+++ b/wirish/boards/cm900/board.cpp
@@ -0,0 +1,117 @@
+/*
+ * cm900.cpp
+ *
+ * Created on: 2012. 10. 14.
+ * Author: in2storm
+ */
+
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file maple.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple PIN_MAP and boardInit().
+ */
+
+#include <board/board.h> // For this board's header file
+
+#include <wirish/wirish_types.h> // For stm32_pin_info and its contents
+ // (these go into PIN_MAP).
+
+#include "boards_private.h" // For PMAP_ROW(), which makes
+ // PIN_MAP easier to read.
+
+
+
+void boardInit(void) {
+ afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY); //[ROBOTIS] 2013-07-17
+ //[ROBOTIS][CHANGE] add here if you want to initialize something
+ gpio_set_mode(GPIOB, 2, GPIO_OUTPUT_PP);
+ gpio_write_bit(GPIOB, 2,1); //LED off when start board
+}
+
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+
+ /* Top header */
+ {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D0/PA0 */
+ {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D1/PA1 */
+ {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D2/PA2 */
+ {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D3/PA3 */
+ {GPIOA, NULL, ADC1, 4, 0, 4}, /* D4/PA4 */
+ {GPIOA, NULL, ADC1, 5, 0, 5}, /* D5/PA5 */
+ {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D6/PA6 */
+ {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D7/PA7 */
+ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D8/PA8 */
+ {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D9/PA9 */
+
+ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D10/PA10 */
+ {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D11/PA13 */
+ {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D12/PA14 */
+ {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D13/PA15 */
+ {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D14/PB0 */
+ {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D15/PB1 */
+ {GPIOB, NULL, NULL, 2, 0, ADCx}, /* D16/PB2 (LED)*/
+ {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D17/PB3 */
+ {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D18/PB4 */
+ {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D19/PB5 DIR_485 */
+
+ {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D20/PB6 DXL_TX (Writing to dynamixel bus) */
+ {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D21/PB7 DXL_RX (Receiving from dynamixel bus) */
+ {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D22/PB8 */
+ {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D23/PB9 */
+ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D24/PB10 */
+ {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D25/PB11 */
+ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D26/PB12 */
+ {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D27/PB13 */
+ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D28/PB14 */
+ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D29/PB15 */
+
+ //{GPIOC, NULL, NULL, 13, 0, ADCx}, /* --/PC13 */
+ {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D30/PC14 */
+ {GPIOC, NULL, NULL, 15, 0, ADCx} /* D31/PC15 */
+
+
+ /* JTAG header */
+
+ //{GPIOA, NULL, NULL, 13, 0, ADCx}, /* D13/PA13 */
+ //{GPIOA, NULL, NULL, 14, 0, ADCx}, /* D14/PA14 */
+ //{GPIOA, NULL, NULL, 15, 0, ADCx}, /* D15/PA15 */
+ //{GPIOB, NULL, NULL, 3, 0, ADCx}, /* D17/PB3 */
+ //{GPIOB, NULL, NULL, 4, 0, ADCx}, /* D18/PB4 */
+};
+
+extern const uint8 boardPWMPins[] __FLASH__ = {
+ 0, 1, 2, 3, 6, 7, 8, 9, 10, 14, 15, 20, 21, 22, 23
+};
+
+extern const uint8 boardADCPins[] __FLASH__ = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 14, 15
+};
+
+extern const uint8 boardUsedPins[] __FLASH__ = {
+ BOARD_LED_PIN
+};
diff --git a/wirish/boards/cm900/include/board/board.h b/wirish/boards/cm900/include/board/board.h
new file mode 100644
index 0000000..fed1a1b
--- /dev/null
+++ b/wirish/boards/cm900/include/board/board.h
@@ -0,0 +1,107 @@
+
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+
+/*
+ * CM900.h
+ *
+ * Created on: 2012. 10. 14.
+ * Author: ROBOTIS[sm6787@robotis.com]
+ * ported from maple.h(leaflabs.com)
+ * @brief Private include file for cm-900 in boards.h
+ */
+
+#ifndef CM_900_H_
+#define CM_900_H_
+
+//#include "gpio.h"
+
+
+#define CYCLES_PER_MICROSECOND 72
+#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
+/*
+ * [ROBOTIS][CHANGE] CM-900 Do not have built-in button.
+ * 2013-04-22
+ * */
+#define BOARD_BUTTON_PIN 23//38
+#define BOARD_LED_PIN 16
+
+/* Number of USARTs/UARTs whose pins are broken out to headers */
+//#define BOARD_NR_USARTS 3
+
+/* Default USART pin numbers (not considering AFIO remap) */
+#define BOARD_USART1_TX_PIN 9 //D9(PA9)
+#define BOARD_USART1_RX_PIN 10 //D10(PA10)
+#define BOARD_USART2_TX_PIN 2 //D2 (PA2)
+#define BOARD_USART2_RX_PIN 3 //D3 (PA3)
+#define BOARD_USART3_TX_PIN 24 //D24 (PB10)
+#define BOARD_USART3_RX_PIN 25 //D25 (PB11)
+
+/* Number of SPI ports */
+//#define BOARD_NR_SPI 2
+
+/* Default SPI pin numbers (not considering AFIO remap) */
+#define BOARD_SPI1_NSS_PIN 10 //D10 (PA4)
+#define BOARD_SPI1_MOSI_PIN 11 //D11 PA7
+#define BOARD_SPI1_MISO_PIN 12 //D12 PA6
+#define BOARD_SPI1_SCK_PIN 13 //D13 PA5
+#define BOARD_SPI2_NSS_PIN 26 //D26 PB12
+#define BOARD_SPI2_MOSI_PIN 29 //D29 PB15
+#define BOARD_SPI2_MISO_PIN 28 //D28 PB14
+#define BOARD_SPI2_SCK_PIN 27 //D27 PB13
+
+/* Total number of GPIO pins that are broken out to headers and
+ * intended for general use. */
+#define BOARD_NR_GPIO_PINS 32//44
+
+/* Number of pins capable of PWM output */
+#define BOARD_NR_PWM_PINS 15
+
+/* Number of pins capable of ADC conversion */
+#define BOARD_NR_ADC_PINS 10
+
+/* Number of pins already connected to external hardware. For Maple,
+ * these are just BOARD_LED_PIN and BOARD_BUTTON_PIN. */
+#define BOARD_NR_USED_PINS 1
+
+/* Debug port pins */
+#define BOARD_JTMS_SWDIO_PIN 11
+#define BOARD_JTCK_SWCLK_PIN 12
+#define BOARD_JTDI_PIN 13
+#define BOARD_JTDO_PIN 17
+#define BOARD_NJTRST_PIN 18
+
+#define BOARD_USB_DISC_DEV GPIOC
+#define BOARD_USB_DISC_BIT 13
+
+void boardInit(void);
+
+#define BOARD_DYNAMIXEL_DIR 19
+#define BOARD_DYNAMIXEL_TX 20
+#define BOARD_DYNAMIXEL_RX 21
+
+#endif /* CM_900_H_ */
diff --git a/wirish/boards/maple/board.cpp b/wirish/boards/maple/board.cpp
new file mode 100644
index 0000000..a585ea1
--- /dev/null
+++ b/wirish/boards/maple/board.cpp
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/maple/board.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple board file.
+ */
+
+#include <board/board.h> // For this board's header file
+
+#include <wirish/wirish_types.h> // For stm32_pin_info and its contents
+ // (these go into PIN_MAP).
+
+#include "boards_private.h" // For PMAP_ROW(), which makes
+ // PIN_MAP easier to read.
+
+// boardInit(): nothing special to do for Maple.
+//
+// When defining your own board.cpp, you can put extra code in this
+// function if you have anything you want done on reset, before main()
+// or setup() are called.
+//
+// If there's nothing special you need done, feel free to leave this
+// function out, as we do here.
+/*
+void boardInit(void) {
+}
+*/
+
+// Pin map: this lets the basic I/O functions (digitalWrite(),
+// analogRead(), pwmWrite()) translate from pin numbers to STM32
+// peripherals.
+//
+// PMAP_ROW() lets us specify a row (really a struct stm32_pin_info)
+// in the pin map. Its arguments are:
+//
+// - GPIO device for the pin (GPIOA, etc.)
+// - GPIO bit for the pin (0 through 15)
+// - Timer device, or NULL if none
+// - Timer channel (1 to 4, for PWM), or 0 if none
+// - ADC device, or NULL if none
+// - ADC channel, or ADCx if none
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+
+ /* Top header */
+
+ PMAP_ROW(GPIOA, 3, TIMER2, 4, ADC1, 3), /* D0/PA3 */
+ PMAP_ROW(GPIOA, 2, TIMER2, 3, ADC1, 2), /* D1/PA2 */
+ PMAP_ROW(GPIOA, 0, TIMER2, 1, ADC1, 0), /* D2/PA0 */
+ PMAP_ROW(GPIOA, 1, TIMER2, 2, ADC1, 1), /* D3/PA1 */
+ PMAP_ROW(GPIOB, 5, NULL, 0, NULL, ADCx), /* D4/PB5 */
+ PMAP_ROW(GPIOB, 6, TIMER4, 1, NULL, ADCx), /* D5/PB6 */
+ PMAP_ROW(GPIOA, 8, TIMER1, 1, NULL, ADCx), /* D6/PA8 */
+ PMAP_ROW(GPIOA, 9, TIMER1, 2, NULL, ADCx), /* D7/PA9 */
+ PMAP_ROW(GPIOA, 10, TIMER1, 3, NULL, ADCx), /* D8/PA10 */
+ PMAP_ROW(GPIOB, 7, TIMER4, 2, NULL, ADCx), /* D9/PB7 */
+ PMAP_ROW(GPIOA, 4, NULL, 0, ADC1, 4), /* D10/PA4 */
+ PMAP_ROW(GPIOA, 7, TIMER3, 2, ADC1, 7), /* D11/PA7 */
+ PMAP_ROW(GPIOA, 6, TIMER3, 1, ADC1, 6), /* D12/PA6 */
+ PMAP_ROW(GPIOA, 5, NULL, 0, ADC1, 5), /* D13/PA5 (LED) */
+ PMAP_ROW(GPIOB, 8, TIMER4, 3, NULL, ADCx), /* D14/PB8 */
+
+ /* Little header */
+
+ PMAP_ROW(GPIOC, 0, NULL, 0, ADC1, 10), /* D15/PC0 */
+ PMAP_ROW(GPIOC, 1, NULL, 0, ADC1, 11), /* D16/PC1 */
+ PMAP_ROW(GPIOC, 2, NULL, 0, ADC1, 12), /* D17/PC2 */
+ PMAP_ROW(GPIOC, 3, NULL, 0, ADC1, 13), /* D18/PC3 */
+ PMAP_ROW(GPIOC, 4, NULL, 0, ADC1, 14), /* D19/PC4 */
+ PMAP_ROW(GPIOC, 5, NULL, 0, ADC1, 15), /* D20/PC5 */
+
+ /* External header */
+
+ PMAP_ROW(GPIOC, 13, NULL, 0, NULL, ADCx), /* D21/PC13 */
+ PMAP_ROW(GPIOC, 14, NULL, 0, NULL, ADCx), /* D22/PC14 */
+ PMAP_ROW(GPIOC, 15, NULL, 0, NULL, ADCx), /* D23/PC15 */
+ PMAP_ROW(GPIOB, 9, TIMER4, 4, NULL, ADCx), /* D24/PB9 */
+ PMAP_ROW(GPIOD, 2, NULL, 0, NULL, ADCx), /* D25/PD2 */
+ PMAP_ROW(GPIOC, 10, NULL, 0, NULL, ADCx), /* D26/PC10 */
+ PMAP_ROW(GPIOB, 0, TIMER3, 3, ADC1, 8), /* D27/PB0 */
+ PMAP_ROW(GPIOB, 1, TIMER3, 4, ADC1, 9), /* D28/PB1 */
+ PMAP_ROW(GPIOB, 10, NULL, 0, NULL, ADCx), /* D29/PB10 */
+ PMAP_ROW(GPIOB, 11, NULL, 0, NULL, ADCx), /* D30/PB11 */
+ PMAP_ROW(GPIOB, 12, NULL, 0, NULL, ADCx), /* D31/PB12 */
+ PMAP_ROW(GPIOB, 13, NULL, 0, NULL, ADCx), /* D32/PB13 */
+ PMAP_ROW(GPIOB, 14, NULL, 0, NULL, ADCx), /* D33/PB14 */
+ PMAP_ROW(GPIOB, 15, NULL, 0, NULL, ADCx), /* D34/PB15 */
+ PMAP_ROW(GPIOC, 6, NULL, 0, NULL, ADCx), /* D35/PC6 */
+ PMAP_ROW(GPIOC, 7, NULL, 0, NULL, ADCx), /* D36/PC7 */
+ PMAP_ROW(GPIOC, 8, NULL, 0, NULL, ADCx), /* D37/PC8 */
+ PMAP_ROW(GPIOC, 9, NULL, 0, NULL, ADCx), /* D38/PC9 (BUT) */
+
+ /* JTAG header */
+
+ PMAP_ROW(GPIOA, 13, NULL, 0, NULL, ADCx), /* D39/PA13 */
+ PMAP_ROW(GPIOA, 14, NULL, 0, NULL, ADCx), /* D40/PA14 */
+ PMAP_ROW(GPIOA, 15, NULL, 0, NULL, ADCx), /* D41/PA15 */
+ PMAP_ROW(GPIOB, 3, NULL, 0, NULL, ADCx), /* D42/PB3 */
+ PMAP_ROW(GPIOB, 4, NULL, 0, NULL, ADCx), /* D43/PB4 */
+};
+
+// Array of pins you can use for pwmWrite(). Keep it in Flash because
+// it doesn't change, and so we don't waste RAM.
+extern const uint8 boardPWMPins[] __FLASH__ = {
+ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 27, 28
+};
+
+// Array of pins you can use for analogRead().
+extern const uint8 boardADCPins[] __FLASH__ = {
+ 0, 1, 2, 3, 10, 11, 12, 15, 16, 17, 18, 19, 20, 27, 28
+};
+
+// Array of pins that the board uses for something special. Other than
+// the button and the LED, it's usually best to leave these pins alone
+// unless you know what you're doing.
+extern const uint8 boardUsedPins[] __FLASH__ = {
+ BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN,
+ BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN
+};
diff --git a/wirish/boards/maple/include/board/board.h b/wirish/boards/maple/include/board/board.h
new file mode 100644
index 0000000..e675806
--- /dev/null
+++ b/wirish/boards/maple/include/board/board.h
@@ -0,0 +1,107 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/maple/include/board/board.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple board header.
+ */
+
+#ifndef _BOARD_MAPLE_H_
+#define _BOARD_MAPLE_H_
+
+/* 72 MHz -> 72 cycles per microsecond. */
+#define CYCLES_PER_MICROSECOND 72
+
+/* Pin number for the built-in button. */
+#define BOARD_BUTTON_PIN 38
+
+/* Pin number for the built-in LED. */
+#define BOARD_LED_PIN 13
+
+/* Number of USARTs/UARTs whose pins are broken out to headers. */
+#define BOARD_NR_USARTS 3
+
+/* USART pin numbers. */
+#define BOARD_USART1_TX_PIN 7
+#define BOARD_USART1_RX_PIN 8
+#define BOARD_USART2_TX_PIN 1
+#define BOARD_USART2_RX_PIN 0
+#define BOARD_USART3_TX_PIN 29
+#define BOARD_USART3_RX_PIN 30
+
+/* Number of SPI ports broken out to headers. */
+#define BOARD_NR_SPI 2
+
+/* SPI pin numbers. */
+#define BOARD_SPI1_NSS_PIN 10
+#define BOARD_SPI1_MOSI_PIN 11
+#define BOARD_SPI1_MISO_PIN 12
+#define BOARD_SPI1_SCK_PIN 13
+#define BOARD_SPI2_NSS_PIN 31
+#define BOARD_SPI2_MOSI_PIN 34
+#define BOARD_SPI2_MISO_PIN 33
+#define BOARD_SPI2_SCK_PIN 32
+
+/* Total number of GPIO pins that are broken out to headers and
+ * intended for use. This includes pins like the LED, button, and
+ * debug port (JTAG/SWD) pins. */
+#define BOARD_NR_GPIO_PINS 44
+
+/* Number of pins capable of PWM output. */
+#define BOARD_NR_PWM_PINS 15
+
+/* Number of pins capable of ADC conversion. */
+#define BOARD_NR_ADC_PINS 15
+
+/* Number of pins already connected to external hardware. For Maple,
+ * these are just BOARD_LED_PIN, BOARD_BUTTON_PIN, and the debug port
+ * pins (see below). */
+#define BOARD_NR_USED_PINS 7
+
+/* Debug port pins. */
+#define BOARD_JTMS_SWDIO_PIN 39
+#define BOARD_JTCK_SWCLK_PIN 40
+#define BOARD_JTDI_PIN 41
+#define BOARD_JTDO_PIN 42
+#define BOARD_NJTRST_PIN 43
+
+/* USB configuration. BOARD_USB_DISC_DEV is the GPIO port containing
+ * the USB_DISC pin, and BOARD_USB_DISC_BIT is that pin's bit. */
+#define BOARD_USB_DISC_DEV GPIOC
+#define BOARD_USB_DISC_BIT 12
+
+/* Pin aliases: these give the GPIO port/bit for each pin as an
+ * enum. These are optional, but recommended. They make it easier to
+ * write code using low-level GPIO functionality. */
+enum {
+ PA3, PA2, PA0, PA1, PB5, PB6, PA8, PA9, PA10, PB7, PA4, PA7, PA6, PA5, PB8,
+ PC0, PC1, PC2, PC3, PC4, PC5, PC13, PC14, PC15, PB9, PD2, PC10, PB0, PB1,
+ PB10, PB11, PB12, PB13, PB14, PB15, PC6, PC7, PC8, PC9, PA13, PA14, PA15,
+ PB3, PB4
+};
+
+#endif
diff --git a/wirish/boards/maple_RET6/board.cpp b/wirish/boards/maple_RET6/board.cpp
new file mode 100644
index 0000000..2ef7de7
--- /dev/null
+++ b/wirish/boards/maple_RET6/board.cpp
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/maple_RET6/board.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple RET6 Edition board file
+ */
+
+#include <board/board.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+
+#include <wirish/wirish_types.h>
+
+void boardInit(void) {
+}
+
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+
+ /* Top header */
+
+ {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D0/PA3 */
+ {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D1/PA2 */
+ {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D2/PA0 */
+ {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D3/PA1 */
+ {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D4/PB5 */
+ {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D5/PB6 */
+ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D6/PA8 */
+ {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D7/PA9 */
+ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D8/PA10 */
+ {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D9/PB7 */
+ {GPIOA, NULL, ADC1, 4, 0, 4}, /* D10/PA4 */
+ {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D11/PA7 */
+ {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D12/PA6 */
+ {GPIOA, NULL, ADC1, 5, 0, 5}, /* D13/PA5 (LED) */
+ {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D14/PB8 */
+
+ /* Little header */
+
+ {GPIOC, NULL, ADC1, 0, 0, 10}, /* D15/PC0 */
+ {GPIOC, NULL, ADC1, 1, 0, 11}, /* D16/PC1 */
+ {GPIOC, NULL, ADC1, 2, 0, 12}, /* D17/PC2 */
+ {GPIOC, NULL, ADC1, 3, 0, 13}, /* D18/PC3 */
+ {GPIOC, NULL, ADC1, 4, 0, 14}, /* D19/PC4 */
+ {GPIOC, NULL, ADC1, 5, 0, 15}, /* D20/PC5 */
+
+ /* External header */
+
+ {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D21/PC13 */
+ {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D22/PC14 */
+ {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D23/PC15 */
+ {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D24/PB9 */
+ {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D25/PD2 */
+ {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D26/PC10 */
+ {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D27/PB0 */
+ {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D28/PB1 */
+ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D29/PB10 */
+ {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D30/PB11 */
+ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D31/PB12 */
+ {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D32/PB13 */
+ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D33/PB14 */
+ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D34/PB15 */
+ {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* D35/PC6 */
+ {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* D36/PC7 */
+ {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* D37/PC8 */
+ {GPIOC, TIMER8, NULL, 9, 4, ADCx}, /* D38/PC9 (BUT) */
+
+ /* JTAG header */
+
+ {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D39/PA13 */
+ {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D40/PA14 */
+ {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D41/PA15 */
+ {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D42/PB3 */
+ {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D43/PB4 */
+};
+
+/* Note: Do NOT include pin 38 (TIM8_CH4), as that's BOARD_BUTTON_PIN
+ * and thus not broken out to a header. */
+extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = {
+ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 27, 28, 35, 36, 37
+};
+
+extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
+ 0, 1, 2, 3, 10, 11, 12, 15, 16, 17, 18, 19, 20, 27, 28
+};
+
+extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
+ BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN,
+ BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN
+};
diff --git a/wirish/boards/maple_RET6/include/board/board.h b/wirish/boards/maple_RET6/include/board/board.h
new file mode 100644
index 0000000..7c6851b
--- /dev/null
+++ b/wirish/boards/maple_RET6/include/board/board.h
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/maple_RET6/include/board/board.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple RET6 Edition board header.
+ *
+ * See wirish/boards/maple/include/board/board.h for more information
+ * on these definitions.
+ */
+
+#ifndef _BOARDS_MAPLE_RET6_H_
+#define _BOARDS_MAPLE_RET6_H_
+
+#define CYCLES_PER_MICROSECOND 72
+#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
+
+#define BOARD_BUTTON_PIN 38
+#define BOARD_LED_PIN 13
+
+/* UART4 and UART5 have pins which aren't broken out :( */
+#define BOARD_NR_USARTS 3
+#define BOARD_USART1_TX_PIN 7
+#define BOARD_USART1_RX_PIN 8
+#define BOARD_USART2_TX_PIN 1
+#define BOARD_USART2_RX_PIN 0
+#define BOARD_USART3_TX_PIN 29
+#define BOARD_USART3_RX_PIN 30
+
+/* Note:
+ *
+ * SPI3 is unusable due to pin 43 (PB4) and NRST tie-together :(, but
+ * leave the definitions so as not to clutter things up. This is only
+ * OK since RET6 Ed. is specifically advertised as a beta board. */
+#define BOARD_NR_SPI 2
+#define BOARD_SPI1_NSS_PIN 10
+#define BOARD_SPI1_MOSI_PIN 11
+#define BOARD_SPI1_MISO_PIN 12
+#define BOARD_SPI1_SCK_PIN 13
+#define BOARD_SPI2_NSS_PIN 31
+#define BOARD_SPI2_MOSI_PIN 34
+#define BOARD_SPI2_MISO_PIN 33
+#define BOARD_SPI2_SCK_PIN 32
+#define BOARD_SPI3_NSS_PIN 41
+#define BOARD_SPI3_MOSI_PIN 4
+#define BOARD_SPI3_MISO_PIN 43
+#define BOARD_SPI3_SCK_PIN 42
+
+#define BOARD_NR_GPIO_PINS 44
+/* Note: NOT 19. The missing one is D38 a.k.a. BOARD_BUTTON_PIN, which
+ * isn't broken out to a header and is thus unusable for PWM. */
+#define BOARD_NR_PWM_PINS 18
+#define BOARD_NR_ADC_PINS 15
+#define BOARD_NR_USED_PINS 7
+
+#define BOARD_JTMS_SWDIO_PIN 39
+#define BOARD_JTCK_SWCLK_PIN 40
+#define BOARD_JTDI_PIN 41
+#define BOARD_JTDO_PIN 42
+#define BOARD_NJTRST_PIN 43
+
+#define BOARD_USB_DISC_DEV GPIOC
+#define BOARD_USB_DISC_BIT 12
+
+enum {
+ PA3, PA2, PA0, PA1, PB5, PB6, PA8, PA9, PA10, PB7, PA4, PA7, PA6, PA5, PB8,
+ PC0, PC1, PC2, PC3, PC4, PC5, PC13, PC14, PC15, PB9, PD2, PC10, PB0, PB1,
+ PB10, PB11, PB12, PB13, PB14, PB15, PC6, PC7, PC8, PC9, PA13, PA14, PA15,
+ PB3, PB4
+};
+
+#endif
diff --git a/wirish/boards/maple_mini/board.cpp b/wirish/boards/maple_mini/board.cpp
new file mode 100644
index 0000000..009ec51
--- /dev/null
+++ b/wirish/boards/maple_mini/board.cpp
@@ -0,0 +1,105 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/maple_mini/board.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple Mini board file.
+ */
+
+#include <board/board.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+
+#include <wirish/wirish_debug.h>
+#include <wirish/wirish_types.h>
+
+/* Since we want the Serial Wire/JTAG pins as GPIOs, disable both SW
+ * and JTAG debug support, unless configured otherwise. */
+void boardInit(void) {
+#ifndef CONFIG_MAPLE_MINI_NO_DISABLE_DEBUG
+ disableDebugPorts();
+#endif
+}
+
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+
+ /* Top header */
+
+ {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D0/PB11 */
+ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D1/PB10 */
+ {GPIOB, NULL, NULL, 2, 0, ADCx}, /* D2/PB2 */
+ {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D3/PB0 */
+ {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D4/PA7 */
+ {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D5/PA6 */
+ {GPIOA, NULL, ADC1, 5, 0, 5}, /* D6/PA5 */
+ {GPIOA, NULL, ADC1, 4, 0, 4}, /* D7/PA4 */
+ {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D8/PA3 */
+ {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D9/PA2 */
+ {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D10/PA1 */
+ {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D11/PA0 */
+ {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D12/PC15 */
+ {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D13/PC14 */
+ {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D14/PC13 */
+
+ /* Bottom header */
+
+ {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D15/PB7 */
+ {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D16/PB6 */
+ {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D17/PB5 */
+ {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D18/PB4 */
+ {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D19/PB3 */
+ {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D20/PA15 */
+ {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D21/PA14 */
+ {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D22/PA13 */
+ {GPIOA, NULL, NULL, 12, 0, ADCx}, /* D23/PA12 */
+ {GPIOA, TIMER1, NULL, 11, 4, ADCx}, /* D24/PA11 */
+ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D25/PA10 */
+ {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D26/PA9 */
+ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D27/PA8 */
+ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D28/PB15 */
+ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D29/PB14 */
+ {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D30/PB13 */
+ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D31/PB12 */
+ {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D32/PB8 */
+ {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D33/PB1 */
+};
+
+extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = {
+ 3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27
+};
+
+extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
+ 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+#define USB_DP 23
+#define USB_DM 24
+
+extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
+ BOARD_LED_PIN, BOARD_BUTTON_PIN, USB_DP, USB_DM
+};
diff --git a/wirish/boards/maple_mini/include/board/board.h b/wirish/boards/maple_mini/include/board/board.h
new file mode 100644
index 0000000..ac2e5e5
--- /dev/null
+++ b/wirish/boards/maple_mini/include/board/board.h
@@ -0,0 +1,83 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/maple_mini/include/board/board.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple Mini board header.
+ *
+ * See wirish/boards/maple/include/board/board.h for more information
+ * on these definitions.
+ */
+
+#ifndef _BOARD_MAPLE_MINI_H_
+#define _BOARD_MAPLE_MINI_H_
+
+#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
+
+#define BOARD_NR_USARTS 3
+#define BOARD_USART1_TX_PIN 26
+#define BOARD_USART1_RX_PIN 25
+#define BOARD_USART2_TX_PIN 9
+#define BOARD_USART2_RX_PIN 8
+#define BOARD_USART3_TX_PIN 1
+#define BOARD_USART3_RX_PIN 0
+
+#define BOARD_NR_SPI 2
+#define BOARD_SPI1_NSS_PIN 7
+#define BOARD_SPI1_MOSI_PIN 4
+#define BOARD_SPI1_MISO_PIN 5
+#define BOARD_SPI1_SCK_PIN 6
+#define BOARD_SPI2_NSS_PIN 31
+#define BOARD_SPI2_MOSI_PIN 28
+#define BOARD_SPI2_MISO_PIN 29
+#define BOARD_SPI2_SCK_PIN 30
+
+#define BOARD_NR_GPIO_PINS 34
+#define BOARD_NR_PWM_PINS 12
+#define BOARD_NR_ADC_PINS 9
+#define BOARD_NR_USED_PINS 4
+
+#define BOARD_JTMS_SWDIO_PIN 22
+#define BOARD_JTCK_SWCLK_PIN 21
+#define BOARD_JTDI_PIN 20
+#define BOARD_JTDO_PIN 19
+#define BOARD_NJTRST_PIN 18
+
+#define BOARD_USB_DISC_DEV GPIOB
+#define BOARD_USB_DISC_BIT 9
+
+enum {
+ PB11, PB10, PB2, PB0, PA7, PA6, PA5, PA4, PA3, PA2, PA1, PA0, PC15, PC14,
+ PC13, PB7, PB6, PB5, PB4, PB3, PA15, PA14, PA13, PA12, PA11, PA10, PA9,
+ PA8, PB15, PB14, PB13, PB12, PB8, PB1
+};
+
+#endif
diff --git a/wirish/boards/maple_native/board.cpp b/wirish/boards/maple_native/board.cpp
new file mode 100644
index 0000000..515cf5b
--- /dev/null
+++ b/wirish/boards/maple_native/board.cpp
@@ -0,0 +1,197 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/maple_native/board.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple Native board file.
+ */
+
+#include <board/board.h>
+
+#include <libmaple/fsmc.h>
+#include <libmaple/gpio.h>
+#include <libmaple/rcc.h>
+#include <libmaple/timer.h>
+
+#include <wirish/wirish_types.h>
+
+static void initSRAMChip(void);
+
+void boardInit(void) {
+ initSRAMChip();
+}
+
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+
+ /* Top header */
+
+ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D0/PB10 */
+ {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D1/PB11 */
+ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D2/PB12 */
+ {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D3/PB13 */
+ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D4/PB14 */
+ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D5/PB15 */
+ {GPIOG, NULL, NULL, 15, 0, ADCx}, /* D6/PG15 (BUT) */
+ {GPIOC, NULL, ADC1, 0, 0, 10}, /* D7/PC0 */
+ {GPIOC, NULL, ADC1, 1, 0, 11}, /* D8/PC1 */
+ {GPIOC, NULL, ADC1, 2, 0, 12}, /* D9/PC2 */
+ {GPIOC, NULL, ADC1, 3, 0, 13}, /* D10/PC3 */
+ {GPIOC, NULL, ADC1, 4, 0, 14}, /* D11/PC4 */
+ {GPIOC, NULL, ADC1, 5, 0, 15}, /* D12/PC5 */
+ {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* D13/PC6 */
+ {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* D14/PC7 */
+ {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* D15/PC8 */
+ {GPIOC, TIMER8, NULL, 9, 4, ADCx}, /* D16/PC9 */
+ {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D17/PC10 */
+ {GPIOC, NULL, NULL, 11, 0, ADCx}, /* D18/PC11 */
+ {GPIOC, NULL, NULL, 12, 0, ADCx}, /* D19/PC12 */
+ {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D20/PC13 */
+ {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D21/PC14 */
+ {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D22/PC15 (LED) */
+ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D23/PA8 */
+ {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D24/PA9 */
+ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D25/PA10 */
+ {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D26/PB9 */
+
+ /* Bottom header */
+ /* Note: D{48, 49, 50, 51} are also TIMER2_CH{1, 2, 3, 4}, respectively. */
+ /* TODO remap timer 2 in boardInit(); make the appropriate changes here */
+
+ {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D27/PD2 */
+ {GPIOD, NULL, NULL, 3, 0, ADCx}, /* D28/PD3 */
+ {GPIOD, NULL, NULL, 6, 0, ADCx}, /* D29/PD6 */
+ {GPIOG, NULL, NULL, 11, 0, ADCx}, /* D30/PG11 */
+ {GPIOG, NULL, NULL, 12, 0, ADCx}, /* D31/PG12 */
+ {GPIOG, NULL, NULL, 13, 0, ADCx}, /* D32/PG13 */
+ {GPIOG, NULL, NULL, 14, 0, ADCx}, /* D33/PG14 */
+ {GPIOG, NULL, NULL, 8, 0, ADCx}, /* D34/PG8 */
+ {GPIOG, NULL, NULL, 7, 0, ADCx}, /* D35/PG7 */
+ {GPIOG, NULL, NULL, 6, 0, ADCx}, /* D36/PG6 */
+ {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D37/PB5 */
+ {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D38/PB6 */
+ {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D39/PB7 */
+ {GPIOF, NULL, NULL, 11, 0, ADCx}, /* D40/PF11 */
+ {GPIOF, NULL, ADC3, 6, 0, 4}, /* D41/PF6 */
+ {GPIOF, NULL, ADC3, 7, 0, 5}, /* D42/PF7 */
+ {GPIOF, NULL, ADC3, 8, 0, 6}, /* D43/PF8 */
+ {GPIOF, NULL, ADC3, 9, 0, 7}, /* D44/PF9 */
+ {GPIOF, NULL, ADC3, 10, 0, 8}, /* D45/PF10 */
+ {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D46/PB1 */
+ {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D47/PB0 */
+ {GPIOA, TIMER5, ADC1, 0, 1, 0}, /* D48/PA0 */
+ {GPIOA, TIMER5, ADC1, 1, 2, 1}, /* D49/PA1 */
+ {GPIOA, TIMER5, ADC1, 2, 3, 2}, /* D50/PA2 */
+ {GPIOA, TIMER5, ADC1, 3, 4, 3}, /* D51/PA3 */
+ {GPIOA, NULL, ADC1, 4, 0, 4}, /* D52/PA4 */
+ {GPIOA, NULL, ADC1, 5, 0, 5}, /* D53/PA5 */
+ {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D54/PA6 */
+ {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D55/PA7 */
+
+ /* FSMC (triple) header */
+
+ {GPIOF, NULL, NULL, 0, 0, ADCx}, /* D56/PF0 */
+ {GPIOD, NULL, NULL, 11, 0, ADCx}, /* D57/PD11 */
+ {GPIOD, NULL, NULL, 14, 0, ADCx}, /* D58/PD14 */
+ {GPIOF, NULL, NULL, 1, 0, ADCx}, /* D59/PF1 */
+ {GPIOD, NULL, NULL, 12, 0, ADCx}, /* D60/PD12 */
+ {GPIOD, NULL, NULL, 15, 0, ADCx}, /* D61/PD15 */
+ {GPIOF, NULL, NULL, 2, 0, ADCx}, /* D62/PF2 */
+ {GPIOD, NULL, NULL, 13, 0, ADCx}, /* D63/PD13 */
+ {GPIOD, NULL, NULL, 0, 0, ADCx}, /* D64/PD0 */
+ {GPIOF, NULL, NULL, 3, 0, ADCx}, /* D65/PF3 */
+ {GPIOE, NULL, NULL, 3, 0, ADCx}, /* D66/PE3 */
+ {GPIOD, NULL, NULL, 1, 0, ADCx}, /* D67/PD1 */
+ {GPIOF, NULL, NULL, 4, 0, ADCx}, /* D68/PF4 */
+ {GPIOE, NULL, NULL, 4, 0, ADCx}, /* D69/PE4 */
+ {GPIOE, NULL, NULL, 7, 0, ADCx}, /* D70/PE7 */
+ {GPIOF, NULL, NULL, 5, 0, ADCx}, /* D71/PF5 */
+ {GPIOE, NULL, NULL, 5, 0, ADCx}, /* D72/PE5 */
+ {GPIOE, NULL, NULL, 8, 0, ADCx}, /* D73/PE8 */
+ {GPIOF, NULL, NULL, 12, 0, ADCx}, /* D74/PF12 */
+ {GPIOE, NULL, NULL, 6, 0, ADCx}, /* D75/PE6 */
+ {GPIOE, NULL, NULL, 9, 0, ADCx}, /* D76/PE9 */
+ {GPIOF, NULL, NULL, 13, 0, ADCx}, /* D77/PF13 */
+ {GPIOE, NULL, NULL, 10, 0, ADCx}, /* D78/PE10 */
+ {GPIOF, NULL, NULL, 14, 0, ADCx}, /* D79/PF14 */
+ {GPIOG, NULL, NULL, 9, 0, ADCx}, /* D80/PG9 */
+ {GPIOE, NULL, NULL, 11, 0, ADCx}, /* D81/PE11 */
+ {GPIOF, NULL, NULL, 15, 0, ADCx}, /* D82/PF15 */
+ {GPIOG, NULL, NULL, 10, 0, ADCx}, /* D83/PG10 */
+ {GPIOE, NULL, NULL, 12, 0, ADCx}, /* D84/PE12 */
+ {GPIOG, NULL, NULL, 0, 0, ADCx}, /* D85/PG0 */
+ {GPIOD, NULL, NULL, 5, 0, ADCx}, /* D86/PD5 */
+ {GPIOE, NULL, NULL, 13, 0, ADCx}, /* D87/PE13 */
+ {GPIOG, NULL, NULL, 1, 0, ADCx}, /* D88/PG1 */
+ {GPIOD, NULL, NULL, 4, 0, ADCx}, /* D89/PD4 */
+ {GPIOE, NULL, NULL, 14, 0, ADCx}, /* D90/PE14 */
+ {GPIOG, NULL, NULL, 2, 0, ADCx}, /* D91/PG2 */
+ {GPIOE, NULL, NULL, 1, 0, ADCx}, /* D92/PE1 */
+ {GPIOE, NULL, NULL, 15, 0, ADCx}, /* D93/PE15 */
+ {GPIOG, NULL, NULL, 3, 0, ADCx}, /* D94/PG3 */
+ {GPIOE, NULL, NULL, 0, 0, ADCx}, /* D95/PE0 */
+ {GPIOD, NULL, NULL, 8, 0, ADCx}, /* D96/PD8 */
+ {GPIOG, NULL, NULL, 4, 0, ADCx}, /* D97/PG4 */
+ {GPIOD, NULL, NULL, 9, 0, ADCx}, /* D98/PD9 */
+ {GPIOG, NULL, NULL, 5, 0, ADCx}, /* D99/PG5 */
+ {GPIOD, NULL, NULL, 10, 0, ADCx}, /* D100/PD10 */
+
+ /* JTAG header */
+
+ {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D101/PA13 */
+ {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D102/PA14 */
+ {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D103/PA15 */
+ {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D104/PB3 */
+ {GPIOB, NULL, NULL, 4, 0, ADCx} /* D105/PB4 */
+};
+
+extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = {
+ 13, 14, 15, 16, 23, 24, 25, 26, 38, 39, 46, 47, 48, 49, 50, 51, 54, 55
+};
+
+extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
+ 7, 8, 9, 10, 11, 12, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55
+};
+
+extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
+ BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN,
+ BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN,
+ 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 78, 79, 81,
+ 82, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100
+};
+
+static void initSRAMChip(void) {
+ fsmc_nor_psram_reg_map *regs = FSMC_NOR_PSRAM1_BASE;
+
+ fsmc_sram_init_gpios();
+ rcc_clk_enable(RCC_FSMC);
+
+ regs->BCR = (FSMC_BCR_WREN | FSMC_BCR_MWID_16BITS | FSMC_BCR_MTYP_SRAM |
+ FSMC_BCR_MBKEN);
+ fsmc_nor_psram_set_addset(regs, 0);
+ fsmc_nor_psram_set_datast(regs, 3);
+}
diff --git a/wirish/boards/maple_native/include/board/board.h b/wirish/boards/maple_native/include/board/board.h
new file mode 100644
index 0000000..b63aace
--- /dev/null
+++ b/wirish/boards/maple_native/include/board/board.h
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/maple_native/include/board/board.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple Native board header file.
+ *
+ * See wirish/boards/maple/include/board/board.h for more information
+ * on these definitions.
+ */
+
+#ifndef _BOARD_MAPLE_NATIVE_H_
+#define _BOARD_MAPLE_NATIVE_H_
+
+#define CYCLES_PER_MICROSECOND 72
+#define SYSTICK_RELOAD_VAL 71999
+
+#define BOARD_LED_PIN 22
+#define BOARD_BUTTON_PIN 6
+
+#define BOARD_NR_USARTS 5
+#define BOARD_USART1_TX_PIN 24
+#define BOARD_USART1_RX_PIN 25
+#define BOARD_USART2_TX_PIN 50
+#define BOARD_USART2_RX_PIN 51
+#define BOARD_USART3_TX_PIN 0
+#define BOARD_USART3_RX_PIN 1
+#define BOARD_UART4_TX_PIN 17
+#define BOARD_UART4_RX_PIN 18
+#define BOARD_UART5_TX_PIN 19
+#define BOARD_UART5_RX_PIN 27
+
+#define BOARD_NR_SPI 3
+#define BOARD_SPI1_NSS_PIN 52
+#define BOARD_SPI1_MOSI_PIN 55
+#define BOARD_SPI1_MISO_PIN 54
+#define BOARD_SPI1_SCK_PIN 53
+#define BOARD_SPI2_NSS_PIN 2
+#define BOARD_SPI2_MOSI_PIN 5
+#define BOARD_SPI2_MISO_PIN 4
+#define BOARD_SPI2_SCK_PIN 3
+#define BOARD_SPI3_NSS_PIN 103
+#define BOARD_SPI3_MOSI_PIN 37
+#define BOARD_SPI3_MISO_PIN 105
+#define BOARD_SPI3_SCK_PIN 104
+
+#define BOARD_NR_GPIO_PINS 106
+#define BOARD_NR_PWM_PINS 18
+#define BOARD_NR_ADC_PINS 21
+#define BOARD_NR_USED_PINS 43
+#define BOARD_JTMS_SWDIO_PIN 101
+#define BOARD_JTCK_SWCLK_PIN 102
+#define BOARD_JTDI_PIN 103
+#define BOARD_JTDO_PIN 104
+#define BOARD_NJTRST_PIN 105
+
+#define BOARD_USB_DISC_DEV GPIOB
+#define BOARD_USB_DISC_BIT 8
+
+enum {
+ PB10, PB11, PB12, PB13, PB14, PB15, PG15, PC0, PC1, PC2, PC3, PC4, PC5,
+ PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15, PA8, PA9, PA10,
+ PB9, PD2, PD3, PD6, PG11, PG12, PG13, PG14, PG8, PG7, PG6, PB5, PB6, PB7,
+ PF11, PF6, PF7, PF8, PF9, PF10, PB1, PB0, PA0, PA1, PA2, PA3, PA4, PA5,
+ PA6, PA7, PF0, PD11, PD14, PF1, PD12, PD15, PF2, PD13, PD0, PF3, PE3, PD1,
+ PF4, PE4, PE7, PF5, PE5, PE8, PF12, PE6, PE9, PF13, PE10, PF14, PG9, PE11,
+ PF15, PG10, PE12, PG0, PD5, PE13, PG1, PD4, PE14, PG2, PE1, PE15, PG3, PE0,
+ PD8, PG4, PD9, PG5, PD10, PA13, PA14, PA15, PB3, PB4
+};
+
+#endif
diff --git a/wirish/boards/olimex_stm32_h103/board.cpp b/wirish/boards/olimex_stm32_h103/board.cpp
new file mode 100644
index 0000000..d9b8033
--- /dev/null
+++ b/wirish/boards/olimex_stm32_h103/board.cpp
@@ -0,0 +1,119 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs, LLC.
+ * Copyright (c) 2011 David Kiliani.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/olimex_stm32_h103/board.cpp
+ * @author David Kiliani <mail@davidkiliani.de>
+ * @brief Olimex STM32_H103 board file.
+ */
+
+#include <board/board.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+
+#include <wirish/wirish_types.h>
+
+void boardInit(void) {
+}
+
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+
+ /* Header EXT1 */
+
+ {GPIOA, TIMER1, NULL, 11, 4, ADCx}, /* D0/EXT1_1/PA11 (USBDM) */
+ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D1/EXT1_2/PA8 */
+ {GPIOA, NULL, NULL, 12, 0, ADCx}, /* D2/EXT1_3/PA12 (USBDP) */
+ {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D3/EXT1_4/PA9 */
+
+ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D4/EXT1_7/PA10 */
+ {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D5/EXT1_8/PC10 */
+ {GPIOC, NULL, NULL, 11, 0, ADCx}, /* D6/EXT1_9/PC11 (USBpull) */
+ {GPIOC, NULL, NULL, 12, 0, ADCx}, /* D7/EXT1_10/PC12 (LED) */
+ {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D8/EXT1_11/PD2 */
+ {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D9/EXT1_12/PB5 */
+ {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D10/EXT1_13/PB6 */
+ {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D11/EXT1_14/PA6 */
+ {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D12/EXT1_15/PB7 */
+ {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D13/EXT1_16/PB8 */
+ {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D14/EXT1_17/PB9 */
+ {GPIOA, NULL, ADC1, 5, 0, 5}, /* D15/EXT1_18/PA5 */
+ {GPIOC, NULL, ADC1, 0, 0, 10}, /* D16/EXT1_19/PC0 */
+ {GPIOC, NULL, ADC1, 1, 0, 11}, /* D17/EXT1_20/PC1 */
+ {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D18/EXT1_21/PB0 */
+ {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D19/EXT1_22/PA7 */
+
+ {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D20/EXT1_24/PC13 */
+
+ {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D21/EXT1_26/PB1 */
+
+ /* Header EXT2 */
+
+ {GPIOC, NULL, ADC1, 2, 0, 12}, /* D22/EXT2_2/PC2 */
+
+ {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D23/EXT2_4/PA0 (BUT) */
+
+ {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D24/EXT2_7/PA2 */
+ {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D25/EXT2_8/PA1 */
+ {GPIOC, NULL, ADC1, 3, 0, 13}, /* D26/EXT2_9/PC3 */
+ {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D27/EXT2_10/PA3 */
+ {GPIOA, NULL, ADC1, 4, 0, 4}, /* D28/EXT2_11/PA4 */
+ {GPIOC, NULL, ADC1, 4, 0, 14}, /* D29/EXT2_12/PC4 (USB-P) */
+ {GPIOC, NULL, ADC1, 5, 0, 15}, /* D30/EXT2_13/PC5 */
+ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D31/EXT2_14/PB10 */
+ {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D32/EXT2_15/PB11 */
+ {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D33/EXT2_16/PB13 */
+ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D34/EXT2_17/PB12 */
+ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D35/EXT2_18/PB14 */
+ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D36/EXT2_19/PB15 */
+ {GPIOC, NULL, NULL, 6, 0, ADCx}, /* D37/EXT2_20/PC6 */
+ {GPIOC, NULL, NULL, 7, 0, ADCx}, /* D38/EXT2_21/PC7 */
+ {GPIOC, NULL, NULL, 8, 0, ADCx}, /* D39/EXT2_22/PC8 */
+
+ {GPIOC, NULL, NULL, 9, 0, ADCx}, /* D40/EXT2_24/PC9 */
+
+ /* JTAG header */
+
+ {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D41/JTAG7/PA13 */
+ {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D42/JTAG9/PA14 */
+ {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D43/JTAG5/PA15 */
+ {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D44/JTAG13/PB3 */
+ {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D45/JTAG3/PB4 */
+};
+
+extern const uint8 boardPWMPins[] __FLASH__ = {
+ 0, 1, 3, 4, 10, 11, 12, 13, 14, 18, 19, 21, 23, 24, 25, 27
+};
+
+extern const uint8 boardADCPins[] __FLASH__ = {
+ 11, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30
+};
+
+extern const uint8 boardUsedPins[] __FLASH__ = {
+ BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN,
+ BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN
+};
diff --git a/wirish/boards/olimex_stm32_h103/include/board/board.h b/wirish/boards/olimex_stm32_h103/include/board/board.h
new file mode 100644
index 0000000..a9f0e7b
--- /dev/null
+++ b/wirish/boards/olimex_stm32_h103/include/board/board.h
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs, LLC.
+ * Copyright (c) 2011 David Kiliani.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/olimex_stm32_h103/include/board/board.h
+ * @author David Kiliani <mail@davidkiliani.de>
+ * @brief Olimex STM32_H103 board header.
+ */
+
+#ifndef _BOARD_OLIMEX_STM32_H103_H_
+#define _BOARD_OLIMEX_STM32_H103_H_
+
+#define CYCLES_PER_MICROSECOND 72
+#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
+
+#define BOARD_BUTTON_PIN 23
+#define BOARD_LED_PIN 7
+
+/* Number of USARTs/UARTs whose pins are broken out to headers */
+#define BOARD_NR_USARTS 3
+
+/* Default USART pin numbers (not considering AFIO remap) */
+#define BOARD_USART1_TX_PIN 3
+#define BOARD_USART1_RX_PIN 4
+#define BOARD_USART2_TX_PIN 24
+#define BOARD_USART2_RX_PIN 27
+#define BOARD_USART3_TX_PIN 31
+#define BOARD_USART3_RX_PIN 32
+
+/* Number of SPI ports */
+#define BOARD_NR_SPI 2
+
+/* Default SPI pin numbers (not considering AFIO remap) */
+#define BOARD_SPI1_NSS_PIN 28
+#define BOARD_SPI1_MOSI_PIN 19
+#define BOARD_SPI1_MISO_PIN 11
+#define BOARD_SPI1_SCK_PIN 15
+#define BOARD_SPI2_NSS_PIN 34
+#define BOARD_SPI2_MOSI_PIN 36
+#define BOARD_SPI2_MISO_PIN 35
+#define BOARD_SPI2_SCK_PIN 33
+
+/* Total number of GPIO pins that are broken out to headers and
+ * intended for general use. */
+#define BOARD_NR_GPIO_PINS 46
+
+/* Number of pins capable of PWM output */
+#define BOARD_NR_PWM_PINS 16
+
+/* Number of pins capable of ADC conversion */
+#define BOARD_NR_ADC_PINS 16
+
+/* Number of pins already connected to external hardware. For Maple,
+ * these are just BOARD_LED_PIN and BOARD_BUTTON_PIN. */
+#define BOARD_NR_USED_PINS 7
+
+/* Debug port pins */
+#define BOARD_JTMS_SWDIO_PIN 41
+#define BOARD_JTCK_SWCLK_PIN 42
+#define BOARD_JTDI_PIN 43
+#define BOARD_JTDO_PIN 44
+#define BOARD_NJTRST_PIN 45
+
+/* USB configuration */
+#define BOARD_USB_DISC_DEV GPIOC
+#define BOARD_USB_DISC_BIT 11
+
+enum {
+ PA11, PA8, PA12, PA9, PA10, PC10, PC11, PC12, PD2, PB5, PB6, PA6, PB7, PB8,
+ PB9, PA5, PC0, PC1, PB0, PA7, PC13, PB1, PC2, PA0, PA2, PA1, PC3, PA3, PA4,
+ PC4, PC5, PB10, PB11, PB13, PB12, PB14, PB15, PC6, PC7, PC8, PC9, PA13,
+ PA14, PA15, PB3, PB4
+};
+
+#endif
diff --git a/wirish/boards/opencm904/board.cpp b/wirish/boards/opencm904/board.cpp
new file mode 100644
index 0000000..b3c600b
--- /dev/null
+++ b/wirish/boards/opencm904/board.cpp
@@ -0,0 +1,112 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file maple.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Maple PIN_MAP and boardInit().
+ */
+/*
+ * CM904.cpp ported from CM900.cpp
+ *
+ * Created on: 2013. 5. 22.
+ * Author: in2storm
+ */
+
+#include <board/board.h> // For this board's header file
+
+#include <wirish/wirish_types.h> // For stm32_pin_info and its contents
+ // (these go into PIN_MAP).
+
+#include "boards_private.h" // For PMAP_ROW(), which makes
+
+
+void boardInit(void) {
+
+ afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY); //[ROBOTIS] 2013-07-17
+
+ //[ROBOTIS][CHANGE] add here if you want to initialize something
+ gpio_set_mode(GPIOB, 9, GPIO_OUTPUT_PP);
+ gpio_write_bit(GPIOB, 9,1); //LED off when start board
+}
+
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+ /* Top header */
+ {GPIOA, NULL, ADC1, 4, 0, 4}, /* D0/PA4 */
+ {GPIOA, NULL, ADC1, 5, 0, 5}, /* D1/PA5 */
+ {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D2/PA0 */
+ {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D3/PA1 */
+ {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D4/PA2 */
+ {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D5/PA3 */
+ {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D6/PA6 */
+ {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D7/PA7 */
+ {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D8/PB0 */
+ {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D9/PB1 */
+
+ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D10/PA8 */
+ {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D11/PA9 */
+ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D12/PA10 */
+ {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D13/PB8 */
+ {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D14/PB9 (LED)*/
+// {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D15/PA13 */
+// {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D16/PA14 */
+ {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D15/PA15 */
+ {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D16/PB3 */
+ {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D17/PB4 */
+ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D18/PB12 */
+ {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D19/PB13 */
+
+ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D20/PB14 */
+ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D21/PB15 */
+ {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D22/PC14 */
+ {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D23/PC15 (User Button)*/
+ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D24/PB10 */
+ {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D25/PB11 */
+/*
+ * Hidden pin map
+ * the below pins are used carefully, need to check schematic of OpenCM9.04
+ * */
+ {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D26/PA13 JTAG SWDIO*/
+ {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D27/PA14 JTAG SWDCLK*/
+ {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D28/PB5 DXL DIR*/
+ {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D29/PB6 DXL TXD*/
+ {GPIOB, TIMER4, NULL, 7, 2, ADCx} /* D30/PB7 DXL RXD -> dont work as output and input*/
+
+};
+
+extern const uint8 boardPWMPins[] __FLASH__ = {
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 27, 28
+};
+
+extern const uint8 boardADCPins[] __FLASH__ = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+};
+
+extern const uint8 boardUsedPins[] __FLASH__ = {
+ BOARD_LED_PIN, BOARD_BUTTON_PIN
+};
+
+
diff --git a/wirish/boards/opencm904/include/board/board.h b/wirish/boards/opencm904/include/board/board.h
new file mode 100644
index 0000000..274a2a7
--- /dev/null
+++ b/wirish/boards/opencm904/include/board/board.h
@@ -0,0 +1,105 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+
+/*
+ * CM904.h
+ *
+ * Created on: 2013. 05. 22.
+ * Author: ROBOTIS[sm6787@robotis.com]
+ * ported from maple.h(leaflabs.com)
+ * @brief Private include file for cm-904 in boards.h
+ */
+#ifndef CM904_H_
+#define CM904_H_
+
+//#include "gpio.h"
+
+
+#define CYCLES_PER_MICROSECOND 72
+#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
+/*
+ * [ROBOTIS][CHANGE]2013-04-22 CM-900 Do not have built-in button.
+ * 2013-08-03 CM-9.04 has built-in button -> inserted it again.
+ * */
+#define BOARD_BUTTON_PIN 23//PC15
+#define BOARD_LED_PIN 14//PB9
+//#define BOOT1_PIN 28// added
+
+/* Total number of GPIO pins that are broken out to headers and
+ * intended for general use. */
+#define BOARD_NR_GPIO_PINS 31
+
+/* Number of pins capable of PWM output */
+#define BOARD_NR_PWM_PINS 15
+
+/* Number of pins capable of ADC conversion */
+#define BOARD_NR_ADC_PINS 10
+
+/* Number of pins already connected to external hardware. For Maple,
+ * these are just BOARD_LED_PIN and BOARD_BUTTON_PIN. */
+#define BOARD_NR_USED_PINS 2
+
+/* Number of USARTs/UARTs whose pins are broken out to headers */
+//#define BOARD_NR_USARTS 3
+
+/* Default USART pin numbers (not considering AFIO remap) */
+#define BOARD_USART1_TX_PIN 11 //D9(PA9)
+#define BOARD_USART1_RX_PIN 12 //D10(PA10)
+#define BOARD_USART2_TX_PIN 4 //D2 (PA2)
+#define BOARD_USART2_RX_PIN 5 //D3 (PA3)
+#define BOARD_USART3_TX_PIN 24 //D24 (PB10)
+#define BOARD_USART3_RX_PIN 25 //D25 (PB11)
+
+/* Number of SPI ports */
+//#define BOARD_NR_SPI 2
+
+/* Default SPI pin numbers (not considering AFIO remap) */
+#define BOARD_SPI1_NSS_PIN 0 //D10 (PA4)
+#define BOARD_SPI1_MOSI_PIN 7 //D11 PA7
+#define BOARD_SPI1_MISO_PIN 6 //D12 PA6
+#define BOARD_SPI1_SCK_PIN 1 //D13 PA5
+#define BOARD_SPI2_NSS_PIN 18 //D26 PB12
+#define BOARD_SPI2_MOSI_PIN 21 //D29 PB15
+#define BOARD_SPI2_MISO_PIN 20 //D28 PB14
+#define BOARD_SPI2_SCK_PIN 19 //D27 PB13
+
+#define BOARD_USB_DISC_DEV GPIOC
+#define BOARD_USB_DISC_BIT 13
+
+void boardInit(void);
+
+#define BOARD_DYNAMIXEL_DIR 28
+#define BOARD_DYNAMIXEL_TX 29
+#define BOARD_DYNAMIXEL_RX 30
+
+#define BOARD_JTMS_SWDIO_PIN 26
+#define BOARD_JTCK_SWCLK_PIN 27
+#define BOARD_JTDI_PIN 15
+#define BOARD_JTDO_PIN 16
+#define BOARD_NJTRST_PIN 17
+
+#endif /* CM904_H_ */
diff --git a/wirish/boards/st_stm3220g_eval/board.cpp b/wirish/boards/st_stm3220g_eval/board.cpp
new file mode 100644
index 0000000..674fc67
--- /dev/null
+++ b/wirish/boards/st_stm3220g_eval/board.cpp
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/st_stm3220g_eval/board.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM3220G-EVAL board file.
+ */
+
+#include <board/board.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+#include <wirish/wirish_types.h>
+
+/* Board initialization. Unused. */
+void boardInit(void) {
+}
+
+/* Pin map. Current restrictions:
+ * - LEDs and user button only
+ * - GPIO devices only (no timers etc. yet)
+ */
+#define pmap_row(dev, bit) {dev, NULL, NULL, bit, 0, ADCx}
+extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
+ pmap_row(GPIOG, 6), /* D0/PG6 (LED1) */
+ pmap_row(GPIOG, 8), /* D1/PG8 (LED2) */
+ pmap_row(GPIOI, 9), /* D2/PI9 (LED3) */
+ pmap_row(GPIOC, 7), /* D4/PC7 (LED4) */
+ pmap_row(GPIOG, 15), /* D5/PG15 (BUT) */
+};
+#undef pmap_row
+
+/* Special pin arrays. Unused. */
+extern const uint8 boardPWMPins[] __FLASH__ = {};
+extern const uint8 boardADCPins[] __FLASH__ = {};
+extern const uint8 boardUsedPins[] __FLASH__ = {};
diff --git a/wirish/boards/st_stm3220g_eval/include/board/board.h b/wirish/boards/st_stm3220g_eval/include/board/board.h
new file mode 100644
index 0000000..fe9658a
--- /dev/null
+++ b/wirish/boards/st_stm3220g_eval/include/board/board.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards/st_stm3220g_eval/include/board/board.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM3220G-EVAL board stub header.
+ *
+ * This (and the corresponding board.cpp) needs to be fixed and
+ * fleshed out. Do it later? Maybe someone who wants support for this
+ * board will do it.
+ */
+
+#ifndef _BOARD_ST_STM3220G_EVAL_H_
+#define _BOARD_ST_STM3220G_EVAL_H_
+
+#define CYCLES_PER_MICROSECOND 120
+#define SYSTICK_RELOAD_VAL 119999 /* takes a cycle to reload */
+
+#define BOARD_BUTTON_PIN 5
+#define BOARD_LED_PIN 0
+
+#define BOARD_NR_USARTS 0
+#define BOARD_NR_SPI 0
+#define BOARD_NR_GPIO_PINS 6
+#define BOARD_NR_PWM_PINS 0
+#define BOARD_NR_ADC_PINS 0
+#define BOARD_NR_USED_PINS 6
+
+#endif
diff --git a/wirish/boards_private.h b/wirish/boards_private.h
new file mode 100644
index 0000000..49867ca
--- /dev/null
+++ b/wirish/boards_private.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/boards_private.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Private board support header.
+ *
+ * This file declares chip-specific variables and functions which
+ * determine how init() behaves. It is not part of the public Wirish
+ * API, and can change without notice.
+ */
+
+#ifndef _WIRISH_BOARDS_PRIVATE_H_
+#define _WIRISH_BOARDS_PRIVATE_H_
+
+#include <libmaple/rcc.h>
+#include <libmaple/adc.h>
+
+/* Makes the PIN_MAP rows more human-readable. */
+#define PMAP_ROW(gpio_dev, gpio_bit, timer_dev, timer_ch, adc_dev, adc_ch) \
+ { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch }
+
+namespace wirish {
+ namespace priv {
+
+ /*
+ * Chip-specific initialization data
+ */
+
+ extern rcc_pll_cfg w_board_pll_cfg;
+ extern adc_prescaler w_adc_pre;
+ extern adc_smp_rate w_adc_smp;
+
+ /*
+ * Chip-specific initialization routines and helper functions.
+ */
+
+ void board_reset_pll(void);
+ void board_setup_clock_prescalers(void);
+ void board_setup_gpio(void);
+ void board_setup_usb(void);
+ void series_init(void);
+
+ }
+}
+
+#endif
diff --git a/wirish/cxxabi-compat.cpp b/wirish/cxxabi-compat.cpp
new file mode 100644
index 0000000..516b112
--- /dev/null
+++ b/wirish/cxxabi-compat.cpp
@@ -0,0 +1,6 @@
+/* We compile with nodefaultlibs, so we need to provide an error
+ * handler for an empty pure virtual function */
+extern "C" void __cxa_pure_virtual(void) {
+ while(1)
+ ;
+}
diff --git a/wirish/ext_interrupts.cpp b/wirish/ext_interrupts.cpp
new file mode 100644
index 0000000..1195ea9
--- /dev/null
+++ b/wirish/ext_interrupts.cpp
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/ext_interrupts.cpp
+ * @brief Wiring-like interface for external interrupts
+ */
+
+#include <wirish/ext_interrupts.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/exti.h>
+
+#include <wirish/boards.h>
+
+static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode);
+
+void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) {
+ if (pin >= BOARD_NR_GPIO_PINS || !handler) {
+ return;
+ }
+
+ exti_trigger_mode outMode = exti_out_mode(mode);
+
+ exti_attach_interrupt((exti_num)(PIN_MAP[pin].gpio_bit),
+ gpio_exti_port(PIN_MAP[pin].gpio_device),
+ handler,
+ outMode);
+}
+
+void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg,
+ ExtIntTriggerMode mode) {
+ if (pin >= BOARD_NR_GPIO_PINS || !handler) {
+ return;
+ }
+
+ exti_trigger_mode outMode = exti_out_mode(mode);
+
+ exti_attach_callback((exti_num)(PIN_MAP[pin].gpio_bit),
+ gpio_exti_port(PIN_MAP[pin].gpio_device),
+ handler,
+ arg,
+ outMode);
+}
+
+void detachInterrupt(uint8 pin) {
+ if (pin >= BOARD_NR_GPIO_PINS) {
+ return;
+ }
+
+ exti_detach_interrupt((exti_num)(PIN_MAP[pin].gpio_bit));
+}
+
+static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode) {
+ switch (mode) {
+ case RISING:
+ return EXTI_RISING;
+ case FALLING:
+ return EXTI_FALLING;
+ case CHANGE:
+ return EXTI_RISING_FALLING;
+ }
+ // Can't happen
+ ASSERT(0);
+ return (exti_trigger_mode)0;
+}
diff --git a/wirish/include/wirish/HardwareSPI.h b/wirish/include/wirish/HardwareSPI.h
new file mode 100644
index 0000000..4b61b58
--- /dev/null
+++ b/wirish/include/wirish/HardwareSPI.h
@@ -0,0 +1,225 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/HardwareSPI.h
+ * @brief High-level SPI interface
+ *
+ * This is a "bare essentials" polling driver for now.
+ */
+
+/* TODO [0.1.0] Remove deprecated methods. */
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/spi.h>
+
+#include <wirish/boards.h>
+
+#ifndef _WIRISH_HARDWARESPI_H_
+#define _WIRISH_HARDWARESPI_H_
+
+/**
+ * @brief Defines the possible SPI communication speeds.
+ */
+typedef enum SPIFrequency {
+ 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 */
+} SPIFrequency;
+
+#define MAX_SPI_FREQS 8
+
+/**
+ * @brief Wirish SPI interface.
+ *
+ * This implementation uses software slave management, so the caller
+ * is responsible for controlling the slave select line.
+ */
+class HardwareSPI {
+public:
+ /**
+ * @param spiPortNumber Number of the SPI port to manage.
+ */
+ HardwareSPI(uint32 spiPortNumber);
+
+ /*
+ * Set up/tear down
+ */
+
+ /**
+ * @brief Turn on a SPI port and set its GPIO pin modes for use as master.
+ *
+ * SPI port is enabled in full duplex mode, with software slave management.
+ *
+ * @param frequency Communication frequency
+ * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST (big-endian)
+ * @param mode SPI mode to use, one of SPI_MODE_0, SPI_MODE_1,
+ * SPI_MODE_2, and SPI_MODE_3.
+ */
+ void begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode);
+
+ /**
+ * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0).
+ */
+ void begin(void);
+
+ /**
+ * @brief Turn on a SPI port and set its GPIO pin modes for use as a slave.
+ *
+ * SPI port is enabled in full duplex mode, with software slave management.
+ *
+ * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST(big-endian)
+ * @param mode SPI mode to use
+ */
+ void beginSlave(uint32 bitOrder, uint32 mode);
+
+ /**
+ * @brief Equivalent to beginSlave(MSBFIRST, 0).
+ */
+ void beginSlave(void);
+
+ /**
+ * @brief Disables the SPI port, but leaves its GPIO pin modes unchanged.
+ */
+ void end(void);
+
+ /*
+ * I/O
+ */
+
+ /**
+ * @brief Return the next unread byte.
+ *
+ * If there is no unread byte waiting, this function will block
+ * until one is received.
+ */
+ uint8 read(void);
+
+ /**
+ * @brief Read length bytes, storing them into buffer.
+ * @param buffer Buffer to store received bytes into.
+ * @param length Number of bytes to store in buffer. This
+ * function will block until the desired number of
+ * bytes have been read.
+ */
+ void read(uint8 *buffer, uint32 length);
+
+ /**
+ * @brief Transmit a byte.
+ * @param data Byte to transmit.
+ */
+ void write(uint8 data);
+
+ /**
+ * @brief Transmit multiple bytes.
+ * @param buffer Bytes to transmit.
+ * @param length Number of bytes in buffer to transmit.
+ */
+ void write(const uint8 *buffer, uint32 length);
+
+ /**
+ * @brief Transmit a byte, then return the next unread byte.
+ *
+ * This function transmits before receiving.
+ *
+ * @param data Byte to transmit.
+ * @return Next unread byte.
+ */
+ uint8 transfer(uint8 data);
+
+ /*
+ * Pin accessors
+ */
+
+ /**
+ * @brief Return the number of the MISO (master in, slave out) pin
+ */
+ uint8 misoPin(void);
+
+ /**
+ * @brief Return the number of the MOSI (master out, slave in) pin
+ */
+ uint8 mosiPin(void);
+
+ /**
+ * @brief Return the number of the SCK (serial clock) pin
+ */
+ uint8 sckPin(void);
+
+ /**
+ * @brief Return the number of the NSS (slave select) pin
+ */
+ uint8 nssPin(void);
+
+ /* Escape hatch */
+
+ /**
+ * @brief Get a pointer to the underlying libmaple spi_dev for
+ * this HardwareSPI instance.
+ */
+ spi_dev* c_dev(void) { return this->spi_d; }
+
+ /* -- The following methods are deprecated --------------------------- */
+
+ /**
+ * @brief Deprecated.
+ *
+ * Use HardwareSPI::transfer() instead.
+ *
+ * @see HardwareSPI::transfer()
+ */
+ uint8 send(uint8 data);
+
+ /**
+ * @brief Deprecated.
+ *
+ * Use HardwareSPI::write() in combination with
+ * HardwareSPI::read() (or HardwareSPI::transfer()) instead.
+ *
+ * @see HardwareSPI::write()
+ * @see HardwareSPI::read()
+ * @see HardwareSPI::transfer()
+ */
+ uint8 send(uint8 *data, uint32 length);
+
+ /**
+ * @brief Deprecated.
+ *
+ * Use HardwareSPI::read() instead.
+ *
+ * @see HardwareSPI::read()
+ */
+ uint8 recv(void);
+private:
+ spi_dev *spi_d;
+};
+
+#endif
diff --git a/wirish/include/wirish/HardwareSerial.h b/wirish/include/wirish/HardwareSerial.h
new file mode 100644
index 0000000..f25362b
--- /dev/null
+++ b/wirish/include/wirish/HardwareSerial.h
@@ -0,0 +1,102 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/HardwareSerial.h
+ * @brief Wirish serial port interface.
+ */
+
+#ifndef _WIRISH_HARDWARESERIAL_H_
+#define _WIRISH_HARDWARESERIAL_H_
+
+#include <libmaple/libmaple_types.h>
+
+#include <wirish/Print.h>
+#include <wirish/boards.h>
+
+/*
+ * IMPORTANT:
+ *
+ * This class documented "by hand" (i.e., not using Doxygen) in the
+ * leaflabs-docs/ repository.
+ *
+ * If you alter the public HardwareSerial interface, you MUST update
+ * the documentation accordingly.
+ */
+
+struct usart_dev;
+
+class HardwareSerial : public Print {
+public:
+ HardwareSerial(struct usart_dev *usart_device,
+ uint8 tx_pin,
+ uint8 rx_pin);
+
+ /* Set up/tear down */
+ void begin(uint32 baud);
+ void end(void);
+
+ /* I/O */
+ uint32 available(void);
+ uint8 read(void);
+ void flush(void);
+ virtual void write(unsigned char);
+ using Print::write;
+
+ /* Pin accessors */
+ int txPin(void) { return this->tx_pin; }
+ int rxPin(void) { return this->rx_pin; }
+
+ /* Escape hatch into libmaple */
+ /* FIXME [0.0.13] documentation */
+ struct usart_dev* c_dev(void) { return this->usart_device; }
+private:
+ struct usart_dev *usart_device;
+ uint8 tx_pin;
+ uint8 rx_pin;
+};
+
+#if BOARD_HAVE_USART1
+extern HardwareSerial Serial1;
+#endif
+#if BOARD_HAVE_USART2
+extern HardwareSerial Serial2;
+#endif
+#if BOARD_HAVE_USART3
+extern HardwareSerial Serial3;
+#endif
+#if BOARD_HAVE_UART4
+extern HardwareSerial Serial4;
+#endif
+#if BOARD_HAVE_UART5
+extern HardwareSerial Serial5;
+#endif
+#if BOARD_HAVE_USART6
+extern HardwareSerial Serial6;
+#endif
+
+#endif
diff --git a/wirish/include/wirish/HardwareTimer.h b/wirish/include/wirish/HardwareTimer.h
new file mode 100644
index 0000000..22aa010
--- /dev/null
+++ b/wirish/include/wirish/HardwareTimer.h
@@ -0,0 +1,337 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Bryan Newbold.
+ *
+ * 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 Wirish timer class.
+ */
+
+#ifndef _WIRISH_HARDWARETIMER_H_
+#define _WIRISH_HARDWARETIMER_H_
+
+// TODO [0.1.0] Remove deprecated pieces, pick a better API
+
+#include <libmaple/timer.h>
+
+/** Timer mode. */
+typedef timer_mode TimerMode;
+
+/**
+ * @brief Interface to one of the 16-bit timer peripherals.
+ */
+class HardwareTimer {
+private:
+ timer_dev *dev;
+
+public:
+ /**
+ * @brief Construct a new HardwareTimer instance.
+ * @param timerNum number of the timer to control.
+ */
+ HardwareTimer(uint8 timerNum);
+
+ /**
+ * @brief Stop the counter, without affecting its configuration.
+ *
+ * @see HardwareTimer::resume()
+ */
+ void pause(void);
+
+ /**
+ * @brief 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);
+
+ /**
+ * @brief Get the timer's prescale factor.
+ * @return Timer prescaler, from 1 to 65,536.
+ * @see HardwareTimer::setPrescaleFactor()
+ */
+ uint32 getPrescaleFactor();
+
+ /**
+ * @brief Set the timer's prescale factor.
+ *
+ * The new value won't take effect until the next time the counter
+ * overflows. You can force the counter to reset using
+ * HardwareTimer::refresh().
+ *
+ * @param factor The new prescale value to set, from 1 to 65,536.
+ * @see HardwareTimer::refresh()
+ */
+ void setPrescaleFactor(uint32 factor);
+
+ /**
+ * @brief Get the timer overflow value.
+ * @see HardwareTimer::setOverflow()
+ */
+ uint16 getOverflow();
+
+ /**
+ * @brief Set the timer overflow (or "reload") value.
+ *
+ * The new value won't take effect until the next time the counter
+ * overflows. You can force the counter to reset using
+ * HardwareTimer::refresh().
+ *
+ * @param val The new overflow value to set
+ * @see HardwareTimer::refresh()
+ */
+ void setOverflow(uint16 val);
+
+ /**
+ * @brief Get the current timer count.
+ *
+ * @return The timer's current count value
+ */
+ uint16 getCount(void);
+
+ /**
+ * @brief Set the current timer count.
+ *
+ * @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);
+
+ /**
+ * @brief Set the timer's period in microseconds.
+ *
+ * Configures the prescaler and overflow values to generate a timer
+ * reload with a period as close to the given number of
+ * microseconds as possible.
+ *
+ * @param microseconds The desired period of the timer. This must be
+ * greater than zero.
+ * @return The new overflow value.
+ */
+ uint16 setPeriod(uint32 microseconds);
+
+ /**
+ * @brief Configure a timer channel's mode.
+ * @param channel Timer channel, from 1 to 4
+ * @param mode Mode to set
+ */
+ void setMode(int channel, timer_mode mode);
+
+ /**
+ * @brief Get the compare value for the given channel.
+ * @see HardwareTimer::setCompare()
+ */
+ uint16 getCompare(int channel);
+
+ /**
+ * @brief Set the compare value for the given channel.
+ *
+ * @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 timer_mode
+ * @see HardwareTimer::setMode()
+ * @see HardwareTimer::attachInterrupt()
+ */
+ void setCompare(int channel, uint16 compare);
+
+ /**
+ * @brief 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.
+ *
+ * @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);
+
+ /**
+ * @brief 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);
+
+ /**
+ * @brief Reset the counter, and update the prescaler and overflow
+ * values.
+ *
+ * This will reset the counter to 0 in upcounting mode (the
+ * default). It will also update the timer's prescaler and
+ * overflow, if you have set them up to be changed using
+ * HardwareTimer::setPrescaleFactor() or
+ * HardwareTimer::setOverflow().
+ *
+ * @see HardwareTimer::setPrescaleFactor()
+ * @see HardwareTimer::setOverflow()
+ */
+ void refresh(void);
+
+ /* Escape hatch */
+
+ /**
+ * @brief Get a pointer to the underlying libmaple timer_dev for
+ * this HardwareTimer instance.
+ */
+ timer_dev* c_dev(void) { return this->dev; }
+
+/* -- The rest of this file is deprecated. --------------------------------- */
+
+ /** @brief Deprecated; use setMode(channel, mode) instead. */
+ void setChannelMode(int channel, timer_mode mode) {
+ setMode(channel, mode);
+ }
+
+ /** @brief Deprecated; use setMode(TIMER_CH1, mode) instead. */
+ void setChannel1Mode(timer_mode mode) { setMode(TIMER_CH1, mode); }
+
+ /** @brief Deprecated; use setMode(TIMER_CH2, mode) instead. */
+ void setChannel2Mode(timer_mode mode) { setMode(TIMER_CH2, mode); }
+
+ /** @brief Deprecated; use setMode(TIMER_CH3, mode) instead. */
+ void setChannel3Mode(timer_mode mode) { setMode(TIMER_CH3, mode); }
+
+ /** @brief Deprecated; use setMode(TIMER_CH4, mode) instead. */
+ void setChannel4Mode(timer_mode mode) { setMode(TIMER_CH4, mode); }
+
+ /** @brief Deprecated; use return getCompare(TIMER_CH1) instead. */
+ uint16 getCompare1() { return getCompare(TIMER_CH1); }
+
+ /** @brief Deprecated; use return getCompare(TIMER_CH2) instead. */
+ uint16 getCompare2() { return getCompare(TIMER_CH2); }
+
+ /** @brief Deprecated; use return getCompare(TIMER_CH3) instead. */
+ uint16 getCompare3() { return getCompare(TIMER_CH3); }
+
+ /** @brief Deprecated; use return getCompare(TIMER_CH4) instead. */
+ uint16 getCompare4() { return getCompare(TIMER_CH4); }
+
+ /** @brief Deprecated; use setCompare(TIMER_CH1, compare) instead. */
+ void setCompare1(uint16 compare) { setCompare(TIMER_CH1, compare); }
+
+ /** @brief Deprecated; use setCompare(TIMER_CH2, compare) instead. */
+ void setCompare2(uint16 compare) { setCompare(TIMER_CH2, compare); }
+
+ /** @brief Deprecated; use setCompare(TIMER_CH3, compare) instead. */
+ void setCompare3(uint16 compare) { setCompare(TIMER_CH3, compare); }
+
+ /** @brief Deprecated; use setCompare(TIMER_CH4, compare) instead. */
+ void setCompare4(uint16 compare) { setCompare(TIMER_CH4, compare); }
+
+ /** @brief Deprecated; use attachInterrupt(TIMER_CH1, handler) instead. */
+ void attachCompare1Interrupt(voidFuncPtr handler) {
+ attachInterrupt(TIMER_CH1, handler);
+ }
+
+ /** @brief Deprecated; use attachInterrupt(TIMER_CH2, handler) instead. */
+ void attachCompare2Interrupt(voidFuncPtr handler) {
+ attachInterrupt(TIMER_CH2, handler);
+ }
+
+ /** @brief Deprecated; use attachInterrupt(TIMER_CH3, handler) instead. */
+ void attachCompare3Interrupt(voidFuncPtr handler) {
+ attachInterrupt(TIMER_CH3, handler);
+ }
+
+ /** @brief Deprecated; use attachInterrupt(TIMER_CH4, handler) instead. */
+ void attachCompare4Interrupt(voidFuncPtr handler) {
+ attachInterrupt(TIMER_CH4, handler);
+ }
+
+ /** @brief Deprecated; use detachInterrupt(TIMER_CH1) instead. */
+ void detachCompare1Interrupt(void) { detachInterrupt(TIMER_CH1); }
+
+ /** @brief Deprecated; use detachInterrupt(TIMER_CH2) instead. */
+ void detachCompare2Interrupt(void) { detachInterrupt(TIMER_CH2); }
+
+ /** @brief Deprecated; use detachInterrupt(TIMER_CH3) instead. */
+ void detachCompare3Interrupt(void) { detachInterrupt(TIMER_CH3); }
+
+ /** @brief Deprecated; use detachInterrupt(TIMER_CH4) instead. */
+ void detachCompare4Interrupt(void) { detachInterrupt(TIMER_CH4); }
+
+ /** @brief Deprecated; use refresh() instead. */
+ void generateUpdate(void) { refresh(); }
+};
+
+/** @brief Deprecated; use TIMER_OUTPUT_COMPARE instead. */
+#define TIMER_OUTPUTCOMPARE TIMER_OUTPUT_COMPARE
+
+/**
+ * @brief Deprecated.
+ *
+ * Pre-instantiated timer.
+ */
+extern HardwareTimer Timer1;
+/**
+ * @brief Deprecated.
+ *
+ * Pre-instantiated timer.
+ */
+extern HardwareTimer Timer2;
+/**
+ * @brief Deprecated.
+ *
+ * Pre-instantiated timer.
+ */
+extern HardwareTimer Timer3;
+/**
+ * @brief Deprecated.
+ *
+ * Pre-instantiated timer.
+ */
+extern HardwareTimer Timer4;
+#if (STM32_MCU_SERIES == STM32_SERIES_F1) && defined(STM32_HIGH_DENSITY)
+/**
+ * @brief Deprecated.
+ *
+ * Pre-instantiated timer.
+ */
+extern HardwareTimer Timer5;
+/**
+ * @brief Deprecated.
+ *
+ * Pre-instantiated timer.
+ */
+extern HardwareTimer Timer8;
+#endif
+
+#endif
diff --git a/wirish/include/wirish/Print.h b/wirish/include/wirish/Print.h
new file mode 100644
index 0000000..5fd0b7a
--- /dev/null
+++ b/wirish/include/wirish/Print.h
@@ -0,0 +1,67 @@
+/*
+ * Print.h - Base class that provides print() and println()
+ * Copyright (c) 2008 David A. Mellis. All right reserved.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ *
+ * Modified 12 April 2011 by Marti Bolivar <mbolivar@leaflabs.com>
+ */
+
+#ifndef _WIRISH_PRINT_H_
+#define _WIRISH_PRINT_H_
+
+#include <libmaple/libmaple_types.h>
+
+enum {
+ BYTE = 0,
+ BIN = 2,
+ OCT = 8,
+ DEC = 10,
+ HEX = 16
+};
+
+class Print {
+public:
+ virtual void write(uint8 ch) = 0;
+ virtual void write(const char *str);
+ virtual void write(const void *buf, uint32 len);
+ void print(char);
+ void print(const char[]);
+ void print(uint8, int=DEC);
+ void print(int, int=DEC);
+ void print(unsigned int, int=DEC);
+ void print(long, int=DEC);
+ void print(unsigned long, int=DEC);
+ void print(long long, int=DEC);
+ void print(unsigned long long, int=DEC);
+ void print(double, int=2);
+ void println(void);
+ void println(char);
+ void println(const char[]);
+ void println(uint8, int=DEC);
+ void println(int, int=DEC);
+ void println(unsigned int, int=DEC);
+ void println(long, int=DEC);
+ void println(unsigned long, int=DEC);
+ void println(long long, int=DEC);
+ void println(unsigned long long, int=DEC);
+ void println(double, int=2);
+private:
+ void printNumber(unsigned long long, uint8);
+ void printFloat(double, uint8);
+};
+
+#endif
diff --git a/wirish/include/wirish/WProgram.h b/wirish/include/wirish/WProgram.h
new file mode 100644
index 0000000..b24ec2a
--- /dev/null
+++ b/wirish/include/wirish/WProgram.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ * 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 _WIRISH_WPROGRAM_H_
+#define _WIRISH_WPROGRAM_H_
+
+#include <wirish/wirish.h>
+
+void setup();
+void loop();
+
+#endif
diff --git a/wirish/include/wirish/bit_constants.h b/wirish/include/wirish/bit_constants.h
new file mode 100644
index 0000000..4638f76
--- /dev/null
+++ b/wirish/include/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 _WIRISH_BIT_CONSTANTS_H_
+#define _WIRISH_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/include/wirish/bits.h b/wirish/include/wirish/bits.h
new file mode 100644
index 0000000..0a63c58
--- /dev/null
+++ b/wirish/include/wirish/bits.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/* Note: Use of this header file is deprecated. Use bit_constants.h
+ instead. */
+
+#ifndef _WIRISH_BITS_H_
+#define _WIRISH_BITS_H_
+
+#include <wirish/bit_constants.h>
+
+#endif
diff --git a/wirish/include/wirish/boards.h b/wirish/include/wirish/boards.h
new file mode 100644
index 0000000..6676a02
--- /dev/null
+++ b/wirish/include/wirish/boards.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Bryan Newbold.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/boards.h
+ * @author Bryan Newbold <bnewbold@leaflabs.com>,
+ * Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief init() and board-specific pin information.
+ */
+
+#ifndef _WIRISH_BOARDS_H_
+#define _WIRISH_BOARDS_H_
+
+#include <libmaple/libmaple_types.h>
+#include <wirish/wirish_types.h>
+#include <board/board.h>
+
+/* Set of all possible pin names; not all boards have all these (note
+ * that we use the Dx convention since all of the Maple's pins are
+ * "digital" pins (e.g. can be used with digitalRead() and
+ * digitalWrite()), but not all of them are connected to ADCs. */
+enum {
+ D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16,
+ D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31,
+ D32, D33, D34, D35, D36, D37, D38, D39, D40, D41, D42, D43, D44, D45, D46,
+ D47, D48, D49, D50, D51, D52, D53, D54, D55, D56, D57, D58, D59, D60, D61,
+ D62, D63, D64, D65, D66, D67, D68, D69, D70, D71, D72, D73, D74, D75, D76,
+ D77, D78, D79, D80, D81, D82, D83, D84, D85, D86, D87, D88, D89, D90, D91,
+ D92, D93, D94, D95, D96, D97, D98, D99, D100, D101, D102, D103, D104, D105,
+ D106, D107, D108, D109, D110, D111, };
+
+/**
+ * @brief Maps each Maple pin to a corresponding stm32_pin_info.
+ * @see stm32_pin_info
+ */
+extern const stm32_pin_info PIN_MAP[];
+
+/**
+ * @brief Pins capable of PWM output.
+ *
+ * Its length is BOARD_NR_PWM_PINS.
+ */
+extern const uint8 boardPWMPins[];
+
+/**
+ * @brief Array of pins capable of analog input.
+ *
+ * Its length is BOARD_NR_ADC_PINS.
+ */
+extern const uint8 boardADCPins[];
+
+/**
+ * @brief Pins which are connected to external hardware.
+ *
+ * For example, on Maple boards, it always at least includes
+ * BOARD_LED_PIN. Its length is BOARD_NR_USED_PINS.
+ */
+extern const uint8 boardUsedPins[];
+
+/**
+ * @brief Generic board initialization function.
+ *
+ * This function is called before main(). It ensures that the clocks
+ * and peripherals are configured properly for use with wirish, then
+ * calls boardInit().
+ *
+ * @see boardInit()
+ */
+void init(void);
+
+/**
+ * @brief Board-specific initialization function.
+ *
+ * This function is called from init() after all generic board
+ * initialization has been performed. Each board is required to
+ * define its own.
+ *
+ * @see init()
+ */
+extern void boardInit(void);
+
+/**
+ * @brief Test if a pin is used for a special purpose on your board.
+ * @param pin Pin to test
+ * @return true if the given pin is in boardUsedPins, and false otherwise.
+ * @see boardUsedPins
+ */
+bool boardUsesPin(uint8 pin);
+
+/*
+ * Derived and default board definitions
+ */
+
+#define CLOCK_SPEED_MHZ CYCLES_PER_MICROSECOND
+#define CLOCK_SPEED_HZ (CLOCK_SPEED_MHZ * 1000000UL)
+
+#ifndef SYSTICK_RELOAD_VAL
+#define SYSTICK_RELOAD_VAL (1000 * CYCLES_PER_MICROSECOND - 1)
+#endif
+
+#ifndef BOARD_BUTTON_PRESSED_LEVEL
+#define BOARD_BUTTON_PRESSED_LEVEL HIGH
+#endif
+
+/**
+ * @brief Does the board break out a USART/UART's RX and TX pins?
+ *
+ * BOARD_HAVE_USART(n) is nonzero iff USARTn is available (n must be
+ * an integer literal, 1 through 6). Also see BOARD_HAVE_USART1, ...,
+ * BOARD_HAVE_UART4 (sic), etc.
+ */
+#define BOARD_HAVE_USART(n) (defined(BOARD_USART##n##_TX_PIN) && \
+ defined(BOARD_USART##n##_RX_PIN))
+/** Feature test: nonzero iff the board has USART1. */
+#define BOARD_HAVE_USART1 BOARD_HAVE_USART(1)
+/** Feature test: nonzero iff the board has USART2, 0 otherwise. */
+#define BOARD_HAVE_USART2 BOARD_HAVE_USART(2)
+/** Feature test: nonzero iff the board has USART3, 0 otherwise. */
+#define BOARD_HAVE_USART3 BOARD_HAVE_USART(3)
+/** Feature test: nonzero iff the board has UART4, 0 otherwise. */
+#define BOARD_HAVE_UART4 BOARD_HAVE_USART(4)
+/** Feature test: nonzero iff the board has UART5, 0 otherwise. */
+#define BOARD_HAVE_UART5 BOARD_HAVE_USART(5)
+/** Feature test: nonzero iff the board has USART6, 0 otherwise. */
+#define BOARD_HAVE_USART6 BOARD_HAVE_USART(6)
+
+/**
+ * @brief Does the board break out a SPI peripheral's pins?
+ *
+ * BOARD_HAVE_SPI(n) is nonzero iff SPIn is available (n must be an
+ * integer literal: 1, 2, or 3). Also see BOARD_HAVE_SPI1,
+ * BOARD_HAVE_SPI2, BOARD_HAVE_SPI3. */
+#define BOARD_HAVE_SPI(n) (defined(BOARD_SPI##n##_NSS_PIN) && \
+ defined(BOARD_SPI##n##_SCK_PIN) && \
+ defined(BOARD_SPI##n##_MISO_PIN) && \
+ defined(BOARD_SPI##n##_MOSI_PIN))
+/** Feature test: nonzero iff the board has SPI1. */
+#define BOARD_HAVE_SPI1 BOARD_HAVE_SPI(1)
+/** Feature test: nonzero iff the board has SPI2. */
+#define BOARD_HAVE_SPI2 BOARD_HAVE_SPI(2)
+/** Feature test: nonzero iff the board has SPI3. */
+#define BOARD_HAVE_SPI3 BOARD_HAVE_SPI(3)
+
+/**
+ * @brief Feature test: nonzero iff the board has SerialUSB.
+ */
+#define BOARD_HAVE_SERIALUSB (defined(BOARD_USB_DISC_DEV) && \
+ defined(BOARD_USB_DISC_BIT))
+
+#endif
diff --git a/wirish/include/wirish/ext_interrupts.h b/wirish/include/wirish/ext_interrupts.h
new file mode 100644
index 0000000..ce1ca03
--- /dev/null
+++ b/wirish/include/wirish/ext_interrupts.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/ext_interrupts.h
+ * @brief Wiring-like external interrupt prototypes and types.
+ */
+
+#ifndef _WIRISH_EXT_INTERRUPTS_H_
+#define _WIRISH_EXT_INTERRUPTS_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/nvic.h>
+
+/**
+ * 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;
+
+/**
+ * @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 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 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 Pin number
+ * @param handler Static class member function to run upon external interrupt
+ * trigger. The handler should take 1 argument and return void
+ * @param arg Argument that the handler will be passed when it's called. One
+ * use of this is to pass the specific instance of the class that
+ * will handle the interrupt.
+ * @param mode Type of transition to trigger on, e.g. falling, rising, etc.
+ *
+ * @sideeffect Registers a handler
+ * @see detachInterrupt()
+ */
+void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg,
+ 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();
+}
+
+#endif
+
diff --git a/wirish/include/wirish/io.h b/wirish/include/wirish/io.h
new file mode 100644
index 0000000..08bbc06
--- /dev/null
+++ b/wirish/include/wirish/io.h
@@ -0,0 +1,222 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/io.h
+ * @brief Wiring-style pin I/O interface.
+ */
+
+#ifndef _WIRISH_IO_H_
+#define _WIRISH_IO_H_
+
+#include <libmaple/libmaple_types.h>
+#include <wirish/boards.h>
+
+/**
+ * Specifies a GPIO pin behavior.
+ * @see pinMode()
+ */
+typedef enum WiringPinMode {
+ 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 Number of pin to configure.
+ * @param mode Mode corresponding to desired pin behavior.
+ * @see WiringPinMode
+ */
+void pinMode(uint8 pin, WiringPinMode mode);
+
+#define HIGH 0x1
+#define LOW 0x0
+
+/**
+ * Writes a (digital) value to a pin. The pin must have its
+ * mode set to OUTPUT or OUTPUT_OPEN_DRAIN.
+ *
+ * @param pin Pin to write to.
+ * @param value Either LOW (write a 0) or HIGH (write a 1).
+ * @see pinMode()
+ */
+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.
+ * @return LOW or HIGH.
+ * @see pinMode()
+ */
+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.
+ *
+ * @param pin Pin to read from.
+ * @return Converted voltage, in the range 0--4095, (i.e. a 12-bit ADC
+ * conversion).
+ * @see pinMode()
+ */
+uint16 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(uint8 pin=BOARD_BUTTON_PIN,
+ uint32 pressedLevel=BOARD_BUTTON_PRESSED_LEVEL);
+
+/**
+ * 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 left out (or 0), wait
+ * forever.
+ *
+ * @return true, if the button was pressed; false, if the timeout was
+ * reached.
+ *
+ * @see pinMode()
+ */
+uint8 waitForButtonPress(uint32 timeout_millis=0);
+
+/**
+ * Shift out a byte of data, one bit at a time.
+ *
+ * This function starts at either the most significant or least
+ * significant bit in a byte value, and shifts out each byte in order
+ * onto a data pin. After each bit is written to the data pin, a
+ * separate clock pin is pulsed to indicate that the new bit is
+ * available.
+ *
+ * @param dataPin Pin to shift data out on
+ * @param clockPin Pin to pulse after each bit is shifted out
+ * @param bitOrder Either MSBFIRST (big-endian) or LSBFIRST (little-endian).
+ * @param value Value to shift out
+ */
+void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, uint8 value);
+
+#endif
diff --git a/wirish/include/wirish/pwm.h b/wirish/include/wirish/pwm.h
new file mode 100644
index 0000000..6631d42
--- /dev/null
+++ b/wirish/include/wirish/pwm.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/pwm.h
+ * @brief Wiring-style PWM interface.
+ */
+
+#ifndef _WIRISH_PWM_H_
+#define _WIRISH_PWM_H_
+
+#include <libmaple/libmaple_types.h>
+
+/**
+ * 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
+
+/**
+ * Set the PWM duty on the given pin.
+ *
+ * User code is expected to determine and honor the maximum value
+ * (based on the configured period).
+ *
+ * @param pin PWM output pin
+ * @param duty_cycle Duty cycle to set.
+ */
+void pwmWrite(uint8 pin, uint16 duty_cycle);
+
+#endif
+
diff --git a/wirish/include/wirish/usb_serial.h b/wirish/include/wirish/usb_serial.h
new file mode 100644
index 0000000..f36671b
--- /dev/null
+++ b/wirish/include/wirish/usb_serial.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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 Wirish USB virtual serial port (SerialUSB).
+ */
+
+#ifndef _WIRISH_USB_SERIAL_H_
+#define _WIRISH_USB_SERIAL_H_
+
+#include <wirish/Print.h>
+#include <wirish/boards.h>
+
+/**
+ * @brief Virtual serial terminal.
+ */
+class USBSerial : public Print {
+public:
+ USBSerial(void);
+
+ void begin(void);
+ void end(void);
+
+ uint32 available(void);
+
+ uint32 read(void *buf, uint32 len);
+ uint8 read(void);
+
+ void write(uint8);
+ void write(const char *str);
+ void write(const void*, uint32);
+
+ uint8 getRTS();
+ uint8 getDTR();
+ uint8 isConnected();
+ uint8 pending();
+};
+
+#if BOARD_HAVE_SERIALUSB
+extern USBSerial SerialUSB;
+#endif
+
+#endif
+
diff --git a/wirish/include/wirish/wirish.h b/wirish/include/wirish/wirish.h
new file mode 100644
index 0000000..610aa3f
--- /dev/null
+++ b/wirish/include/wirish/wirish.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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 Main include file for the Wirish core.
+ *
+ * Includes most of Wirish, and (transitively or otherwise)
+ * substantial pieces of libmaple proper.
+ */
+
+#ifndef _WIRISH_WIRISH_H_
+#define _WIRISH_WIRISH_H_
+
+#include <libmaple/stm32.h>
+
+#include <wirish/boards.h>
+#include <wirish/io.h>
+#include <wirish/bit_constants.h>
+#include <wirish/pwm.h>
+#include <wirish/ext_interrupts.h>
+#include <wirish/wirish_debug.h>
+#include <wirish/wirish_math.h>
+#include <wirish/wirish_time.h>
+#if STM32_MCU_SERIES == STM32_SERIES_F1 /* FIXME [0.0.13?] port to F2 */
+#include <wirish/HardwareSPI.h>
+#endif
+#include <wirish/HardwareSerial.h>
+#include <wirish/HardwareTimer.h>
+#include <wirish/usb_serial.h>
+#include <wirish/wirish_types.h>
+
+#include <libmaple/libmaple.h>
+
+#include <stdint.h>
+
+/* Wiring macros and bit defines */
+
+#define true 0x1
+#define false 0x0
+
+#define LSBFIRST 0
+#define MSBFIRST 1
+
+#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)))
+#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : \
+ bitClear(value, bit))
+#define bit(b) (1UL << (b))
+
+#endif
+
diff --git a/wirish/include/wirish/wirish_debug.h b/wirish/include/wirish/wirish_debug.h
new file mode 100644
index 0000000..4edfd27
--- /dev/null
+++ b/wirish/include/wirish/wirish_debug.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/wirish_debug.h
+ * @brief High level debug port configuration
+ */
+
+#ifndef _WIRISH_WIRISH_DEBUG_H_
+#define _WIRISH_WIRISH_DEBUG_H_
+
+#include <libmaple/gpio.h>
+
+/**
+ * @brief Disable the JTAG and Serial Wire (SW) debug ports.
+ *
+ * You can call this function in order to use the JTAG and SW debug
+ * pins as ordinary GPIOs.
+ *
+ * @see enableDebugPorts()
+ */
+void disableDebugPorts(void);
+
+/**
+ * @brief Enable the JTAG and Serial Wire (SW) debug ports.
+ *
+ * After you call this function, the JTAG and SW debug pins will no
+ * longer be usable as GPIOs.
+ *
+ * @see disableDebugPorts()
+ */
+void enableDebugPorts(void);
+
+#endif
diff --git a/wirish/include/wirish/wirish_math.h b/wirish/include/wirish/wirish_math.h
new file mode 100644
index 0000000..39f16a0
--- /dev/null
+++ b/wirish/include/wirish/wirish_math.h
@@ -0,0 +1,151 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/wirish_math.h
+ * @brief Includes <math.h>; provides Wiring-compatible math routines.
+ */
+
+#ifndef _WIRISH_WIRISH_MATH_H_
+#define _WIRISH_WIRISH_MATH_H_
+
+#include <math.h>
+
+/**
+ * @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.
+ */
+static 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
+#define TWO_PI 6.283185307179586476925286766559
+#define DEG_TO_RAD 0.017453292519943295769236907684886
+#define RAD_TO_DEG 57.295779513082320876798154814105
+
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
+#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
+#define radians(deg) ((deg)*DEG_TO_RAD)
+#define degrees(rad) ((rad)*RAD_TO_DEG)
+#define sq(x) ((x)*(x))
+
+/* undefine stdlib's abs if encountered */
+#ifdef abs
+#undef abs
+#endif
+#define abs(x) (((x) > 0) ? (x) : -(x))
+
+/* 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
diff --git a/wirish/include/wirish/wirish_time.h b/wirish/include/wirish/wirish_time.h
new file mode 100644
index 0000000..eb6c68f
--- /dev/null
+++ b/wirish/include/wirish/wirish_time.h
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/wirish_time.h
+ * @brief Timing and delay functions.
+ */
+
+#ifndef _WIRISH_WIRISH_TIME_H_
+#define _WIRISH_WIRISH_TIME_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/systick.h>
+
+#include <wirish/boards.h>
+
+/**
+ * Returns time (in milliseconds) since the beginning of program
+ * execution. On overflow, restarts at 0.
+ * @see micros()
+ */
+static inline uint32 millis(void) {
+ return systick_uptime();
+}
+
+/**
+ * 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;
+
+ do {
+ ms = millis();
+ cycle_cnt = systick_get_count();
+ } while (ms != millis());
+
+#define US_PER_MS 1000
+ /* SYSTICK_RELOAD_VAL is 1 less than the number of cycles it
+ * actually takes to complete a SysTick reload */
+ return ((ms * US_PER_MS) +
+ (SYSTICK_RELOAD_VAL + 1 - cycle_cnt) / CYCLES_PER_MICROSECOND);
+#undef US_PER_MS
+}
+
+/**
+ * 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);
+
+#endif
diff --git a/wirish/include/wirish/wirish_types.h b/wirish/include/wirish/wirish_types.h
new file mode 100644
index 0000000..fce895e
--- /dev/null
+++ b/wirish/include/wirish/wirish_types.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/include/wirish/wirish_types.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Wirish library type definitions.
+ */
+
+#ifndef _WIRISH_WIRISH_TYPES_H_
+#define _WIRISH_WIRISH_TYPES_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+#include <libmaple/adc.h>
+
+/**
+ * Invalid stm32_pin_info adc_channel value.
+ * @see stm32_pin_info
+ */
+#define ADCx 0xFF
+
+/**
+ * @brief Stores STM32-specific information related to a given Maple pin.
+ * @see PIN_MAP
+ */
+typedef struct stm32_pin_info {
+ gpio_dev *gpio_device; /**< Maple pin's GPIO device */
+ timer_dev *timer_device; /**< Pin's timer device, if any. */
+ const adc_dev *adc_device; /**< ADC device, if any. */
+ uint8 gpio_bit; /**< Pin's GPIO port bit. */
+ uint8 timer_channel; /**< Timer channel, or 0 if none. */
+ uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */
+} stm32_pin_info;
+
+/**
+ * Variable attribute, instructs the linker to place the marked
+ * variable in Flash instead of RAM. */
+#define __FLASH__ __attr_flash
+
+typedef uint8 boolean;
+typedef uint8 byte;
+
+#endif
diff --git a/wirish/main.cxx b/wirish/main.cxx
new file mode 100644
index 0000000..9c0b9cc
--- /dev/null
+++ b/wirish/main.cxx
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+ __attribute__(( constructor )) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
diff --git a/wirish/pwm.cpp b/wirish/pwm.cpp
new file mode 100644
index 0000000..44884cd
--- /dev/null
+++ b/wirish/pwm.cpp
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/pwm.cpp
+ * @brief Wiring-style pwmWrite().
+ */
+
+#include <wirish/pwm.h>
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/timer.h>
+
+#include <wirish/boards.h>
+
+void pwmWrite(uint8 pin, uint16 duty_cycle) {
+ if (pin >= BOARD_NR_GPIO_PINS) {
+ return;
+ }
+ timer_dev *dev = PIN_MAP[pin].timer_device;
+ uint8 cc_channel = PIN_MAP[pin].timer_channel;
+ ASSERT(dev && cc_channel);
+ timer_set_compare(dev, cc_channel, duty_cycle);
+}
diff --git a/wirish/rules.mk b/wirish/rules.mk
new file mode 100644
index 0000000..1cac74a
--- /dev/null
+++ b/wirish/rules.mk
@@ -0,0 +1,62 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Add board directory and MCU-specific directory to BUILDDIRS. These
+# are in subdirectories, but they're logically part of the Wirish
+# submodule.
+WIRISH_BOARD_PATH := boards/$(BOARD)
+BUILDDIRS += $(BUILD_PATH)/$(d)/$(WIRISH_BOARD_PATH)
+BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_SERIES)
+
+# Safe includes for Wirish.
+WIRISH_INCLUDES := -I$(d)/include -I$(d)/$(WIRISH_BOARD_PATH)/include
+
+# Local flags. Add -I$(d) to allow for private includes.
+CFLAGS_$(d) := $(LIBMAPLE_INCLUDES) $(WIRISH_INCLUDES) -I$(d)
+
+# Local rules and targets
+sSRCS_$(d) := start.S
+cSRCS_$(d) := start_c.c
+cSRCS_$(d) += syscalls.c
+cSRCS_$(d) += $(MCU_SERIES)/util_hooks.c
+cppSRCS_$(d) := boards.cpp
+cppSRCS_$(d) += cxxabi-compat.cpp
+cppSRCS_$(d) += ext_interrupts.cpp
+cppSRCS_$(d) += HardwareSerial.cpp
+cppSRCS_$(d) += HardwareTimer.cpp
+cppSRCS_$(d) += Print.cpp
+cppSRCS_$(d) += pwm.cpp
+ifeq ($(MCU_SERIES), stm32f1)
+cppSRCS_$(d) += usb_serial.cpp # HACK: this is currently STM32F1 only.
+cppSRCS_$(d) += HardwareSPI.cpp # FIXME: port to F2 and fix wirish.h
+endif
+cppSRCS_$(d) += wirish_analog.cpp
+cppSRCS_$(d) += wirish_digital.cpp
+cppSRCS_$(d) += wirish_math.cpp
+cppSRCS_$(d) += wirish_shift.cpp
+cppSRCS_$(d) += wirish_time.cpp
+cppSRCS_$(d) += $(MCU_SERIES)/boards_setup.cpp
+cppSRCS_$(d) += $(MCU_SERIES)/wirish_digital.cpp
+cppSRCS_$(d) += $(MCU_SERIES)/wirish_debug.cpp
+cppSRCS_$(d) += $(WIRISH_BOARD_PATH)/board.cpp
+
+sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
+ $(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))
diff --git a/wirish/start.S b/wirish/start.S
new file mode 100644
index 0000000..8b181aa
--- /dev/null
+++ b/wirish/start.S
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/*
+ * This file is a modified version of a file obtained from
+ * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the
+ * following text appeared:
+ *
+ * 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.
+ */
+
+ .text
+ .code 16
+ .thumb_func
+
+ .globl __start__
+ .type __start__, %function
+__start__:
+ .fnstart
+ ldr r1,=__msp_init
+ mov sp,r1
+ ldr r1,=start_c
+ bx r1
+ .pool
+ .cantunwind
+ .fnend
diff --git a/wirish/start_c.c b/wirish/start_c.c
new file mode 100644
index 0000000..655fefb
--- /dev/null
+++ b/wirish/start_c.c
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/*
+ * This file is a modified version of a file obtained from
+ * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the
+ * following text appeared:
+ *
+ * Copyright (c) 2006, 2007 CodeSourcery Inc
+ *
+ * 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.
+ */
+
+#include <stddef.h>
+
+extern void __libc_init_array(void);
+
+extern int main(int, char**, char**);
+
+extern void exit(int) __attribute__((noreturn, weak));
+
+/* The linker must ensure that these are at least 4-byte aligned. */
+extern char __data_start__, __data_end__;
+extern char __bss_start__, __bss_end__;
+
+struct rom_img_cfg {
+ int *img_start;
+};
+
+extern char _lm_rom_img_cfgp;
+
+void __attribute__((noreturn)) start_c(void) {
+ struct rom_img_cfg *img_cfg = (struct rom_img_cfg*)&_lm_rom_img_cfgp;
+ int *src = img_cfg->img_start;
+ int *dst = (int*)&__data_start__;
+ int exit_code;
+
+ /* Initialize .data, if necessary. */
+ if (src != dst) {
+ int *end = (int*)&__data_end__;
+ while (dst < end) {
+ *dst++ = *src++;
+ }
+ }
+
+ /* Zero .bss. */
+ dst = (int*)&__bss_start__;
+ while (dst < (int*)&__bss_end__) {
+ *dst++ = 0;
+ }
+
+ /* Run initializers. */
+ __libc_init_array();
+
+ /* Jump to main. */
+ exit_code = main(0, 0, 0);
+ if (exit) {
+ exit(exit_code);
+ }
+
+ /* If exit is NULL, make sure we don't return. */
+ for (;;)
+ continue;
+}
diff --git a/wirish/stm32f1/boards_setup.cpp b/wirish/stm32f1/boards_setup.cpp
new file mode 100644
index 0000000..11872d5
--- /dev/null
+++ b/wirish/stm32f1/boards_setup.cpp
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+*****************************************************************************/
+
+/**
+ * @file wirish/stm32f1/boards_setup.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 chip setup.
+ *
+ * This file controls how init() behaves on the STM32F1. Be very
+ * careful when changing anything here. Many of these values depend
+ * upon each other.
+ */
+
+#include "boards_private.h"
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+
+#include <wirish/boards.h>
+#include <wirish/usb_serial.h>
+
+// Allow boards to provide a PLL multiplier. This is useful for
+// e.g. STM32F100 value line MCUs, which use slower multipliers.
+// (We're leaving the default to RCC_PLLMUL_9 for now, since that
+// works for F103 performance line MCUs, which is all that LeafLabs
+// currently officially supports).
+#ifndef BOARD_RCC_PLLMUL
+#define BOARD_RCC_PLLMUL RCC_PLLMUL_9
+#endif
+
+namespace wirish {
+ namespace priv {
+
+ static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL};
+ __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data};
+ __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6;
+ __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5;
+
+ __weak void board_reset_pll(void) {
+ // TODO
+ }
+
+ __weak void board_setup_clock_prescalers(void) {
+ rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1);
+ rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2);
+ rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1);
+ }
+
+ __weak void board_setup_gpio(void) {
+ gpio_init_all();
+ }
+
+ __weak void board_setup_usb(void) {
+#if BOARD_HAVE_SERIALUSB
+ SerialUSB.begin();
+#endif
+ }
+
+ __weak void series_init(void) {
+ // Initialize AFIO here, too, so peripheral remaps and external
+ // interrupts work out of the box.
+ afio_init();
+ }
+
+ }
+}
diff --git a/wirish/stm32f1/util_hooks.c b/wirish/stm32f1/util_hooks.c
new file mode 100644
index 0000000..8f798a1
--- /dev/null
+++ b/wirish/stm32f1/util_hooks.c
@@ -0,0 +1,83 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung (from libmaple/util.c).
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/*
+ * STM32F1 implementations for libmaple/util.c hooks
+ *
+ * These need more love and attention before being made public API
+ * (this includes being easily overridable by user code).
+ */
+
+#include <libmaple/nvic.h>
+#include <libmaple/gpio.h>
+#include <libmaple/stm32.h>
+#include <libmaple/timer.h>
+#include <libmaple/adc.h>
+#include <libmaple/usart.h>
+
+/* Failed ASSERT()s send out a message using this USART config. */
+#ifndef ERROR_USART
+#define ERROR_USART USART2
+#define ERROR_USART_BAUD 9600
+#define ERROR_TX_PORT GPIOA
+#define ERROR_TX_PIN 2
+#endif
+
+/*
+ * Disables all peripheral interrupts except USB (when available),
+ * turns off commonly-used peripherals. Called by __error() with
+ * global interrupts disabled.
+ */
+void __lm_error(void) {
+ /* Turn off peripheral interrupts */
+ nvic_irq_disable_all();
+
+ /* Turn off timers */
+ timer_disable_all();
+
+ /* Turn off ADC */
+ adc_disable_all();
+
+ /* Turn off all USARTs */
+ usart_disable_all();
+
+#if STM32_HAVE_USB
+ /* Turn the USB interrupt back on so the bootloader keeps on functioning */
+ nvic_irq_enable(NVIC_USB_HP_CAN_TX);
+ nvic_irq_enable(NVIC_USB_LP_CAN_RX0);
+#endif
+}
+
+/*
+ * Enable the error USART for writing.
+ */
+usart_dev* __lm_enable_error_usart() {
+ gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_AF_OUTPUT_PP);
+ usart_init(ERROR_USART);
+ usart_set_baud_rate(ERROR_USART, USART_USE_PCLK, ERROR_USART_BAUD);
+ return ERROR_USART;
+}
diff --git a/wirish/stm32f1/wirish_debug.cpp b/wirish/stm32f1/wirish_debug.cpp
new file mode 100644
index 0000000..28de96d
--- /dev/null
+++ b/wirish/stm32f1/wirish_debug.cpp
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/stm32f1/wirish_debug.cpp
+ * @brief High level debug port configuration
+ */
+
+#include <wirish/wirish_debug.h>
+#include <libmaple/gpio.h>
+
+void disableDebugPorts(void) {
+ afio_cfg_debug_ports(AFIO_DEBUG_NONE);
+}
+
+void enableDebugPorts(void) {
+ afio_cfg_debug_ports(AFIO_DEBUG_FULL_SWJ);
+}
diff --git a/wirish/stm32f1/wirish_digital.cpp b/wirish/stm32f1/wirish_digital.cpp
new file mode 100644
index 0000000..8371b0e
--- /dev/null
+++ b/wirish/stm32f1/wirish_digital.cpp
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/*
+ * STM32F1 implementations for basic GPIO functionality.
+ */
+
+#include <wirish/io.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+
+#include <wirish/boards.h>
+
+void pinMode(uint8 pin, WiringPinMode mode) {
+ gpio_pin_mode outputMode;
+ bool pwm = false;
+
+ if (pin >= BOARD_NR_GPIO_PINS) {
+ return;
+ }
+
+ switch(mode) {
+ case OUTPUT:
+ outputMode = GPIO_OUTPUT_PP;
+ break;
+ case OUTPUT_OPEN_DRAIN:
+ outputMode = GPIO_OUTPUT_OD;
+ break;
+ case INPUT:
+ case INPUT_FLOATING:
+ outputMode = GPIO_INPUT_FLOATING;
+ break;
+ case INPUT_ANALOG:
+ outputMode = GPIO_INPUT_ANALOG;
+ break;
+ case INPUT_PULLUP:
+ outputMode = GPIO_INPUT_PU;
+ break;
+ case INPUT_PULLDOWN:
+ outputMode = GPIO_INPUT_PD;
+ break;
+ case PWM:
+ outputMode = GPIO_AF_OUTPUT_PP;
+ pwm = true;
+ break;
+ case PWM_OPEN_DRAIN:
+ outputMode = GPIO_AF_OUTPUT_OD;
+ pwm = true;
+ break;
+ default:
+ ASSERT(0);
+ return;
+ }
+
+ gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode);
+
+ if (PIN_MAP[pin].timer_device != NULL) {
+ /* Enable/disable timer channels if we're switching into or
+ * out of PWM. */
+ timer_set_mode(PIN_MAP[pin].timer_device,
+ PIN_MAP[pin].timer_channel,
+ pwm ? TIMER_PWM : TIMER_DISABLED);
+ }
+}
diff --git a/wirish/stm32f2/boards_setup.cpp b/wirish/stm32f2/boards_setup.cpp
new file mode 100644
index 0000000..5764dd0
--- /dev/null
+++ b/wirish/stm32f2/boards_setup.cpp
@@ -0,0 +1,120 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/stm32f2/boards_setup.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 chip setup.
+ *
+ * This file controls how init() behaves on the STM32F2. Be very
+ * careful when changing anything here. Many of these values depend
+ * upon each other.
+ */
+
+#include "boards_private.h"
+
+#include <libmaple/gpio.h>
+#include <libmaple/syscfg.h>
+#include <libmaple/libmaple_types.h>
+#include <wirish/wirish_types.h>
+#include <board/board.h>
+
+// PLL config for 25 MHz external crystal --> 120 MHz SYSCLK, with
+// 48 MHz PLL48CK.
+#ifndef BOARD_PLL_Q
+#define BOARD_PLL_Q 5
+#endif
+#ifndef BOARD_PLL_P
+#define BOARD_PLL_P 2
+#endif
+#ifndef BOARD_PLL_N
+#define BOARD_PLL_N 240
+#endif
+#ifndef BOARD_PLL_M
+#define BOARD_PLL_M 25
+#endif
+
+static stm32f2_rcc_pll_data pll_data = {BOARD_PLL_Q,
+ BOARD_PLL_P,
+ BOARD_PLL_N,
+ BOARD_PLL_M};
+
+namespace wirish {
+ namespace priv {
+ // PLL clocked off of HSE, with above configuration data.
+ __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data};
+
+ // Global ADC prescaler
+ //
+ // On F2, with f_APB2 = 60 MHz, we need f_ADC = f_PCLK2 / 2 to
+ // get the (maximum) f_ADC = 30 MHz.
+ __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_2;
+
+ // Conservative ADC sample rate. Goal is error less than 1/4
+ // LSB with 50 KOhm input impedance.
+ //
+ // On F2, with f_ADC = 30 MHz, error is acceptable assuming an
+ // internal sample and hold capacitance C_ADC at most 8.8 pF
+ // (ST doesn't specify the maximum C_ADC, so we had to take a
+ // guess). See Equation 1 and Table 61 in the F2 datasheet for
+ // more details.
+ __weak adc_smp_rate w_adc_smp = ADC_SMPR_144;
+
+ __weak void board_reset_pll(void) {
+ // Set PLLCFGR to its reset value.
+ RCC_BASE->PLLCFGR = 0x24003010; // FIXME lose the magic number.
+ }
+
+ __weak void board_setup_clock_prescalers(void) {
+ // On F2, with f_SYSCLK = 120 MHz (as determined by
+ // board_pll_cfg),
+ //
+ // f_AHB = f_SYSCLK / 1 = 120 MHz
+ // f_APB1 = f_AHB / 4 = 30 MHz
+ // f_APB2 = f_AHB / 2 = 60 MHz
+ rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1);
+ rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_4);
+ rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_2);
+ }
+
+ __weak void board_setup_gpio(void) {
+ gpio_init_all();
+ }
+
+ __weak void board_setup_usb(void) {
+ // Nothing to do.
+ }
+
+ __weak void series_init(void) {
+ // We need SYSCFG for external interrupts
+ syscfg_init();
+ // Turn on the I/O compensation cell, since we drive the
+ // GPIOs quickly by default.
+ syscfg_enable_io_compensation();
+ }
+
+ }
+}
diff --git a/wirish/stm32f2/util_hooks.c b/wirish/stm32f2/util_hooks.c
new file mode 100644
index 0000000..1b519ab
--- /dev/null
+++ b/wirish/stm32f2/util_hooks.c
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/*
+ * STM32F2 implementations for libmaple util.c hooks
+ * FIXME these are just minimal stubs
+ */
+
+#include <libmaple/nvic.h>
+
+/*
+ * Disables all peripheral interrupts. Called by __error() with global
+ * interrupts disabled.
+ */
+void __lm_error(void) {
+ nvic_irq_disable_all();
+}
+
+/*
+ * Enable the error USART for writing.
+ */
+/* usart_dev* __lm_enable_error_usart(void) { (TODO) } */
diff --git a/wirish/stm32f2/wirish_debug.cpp b/wirish/stm32f2/wirish_debug.cpp
new file mode 100644
index 0000000..af6c78b
--- /dev/null
+++ b/wirish/stm32f2/wirish_debug.cpp
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/stm32f2/wirish_debug.cpp
+ * @brief High level debug port configuration
+ */
+
+#include <wirish/wirish_debug.h>
+#include <libmaple/gpio.h>
+
+// TODO is it worth optimizing these into raw MODER and AFR[LH] writes?
+
+void disableDebugPorts(void) {
+ // PA13-PA15 and PB3-PB4 are in system alternate function mode on
+ // reset, to support JTAG. Just put them in input mode to release
+ // them.
+ gpio_set_mode(GPIOA, 13, GPIO_MODE_INPUT);
+ gpio_set_mode(GPIOA, 14, GPIO_MODE_INPUT);
+ gpio_set_mode(GPIOA, 15, GPIO_MODE_INPUT);
+ gpio_set_mode(GPIOB, 3, GPIO_MODE_INPUT);
+ gpio_set_mode(GPIOB, 4, GPIO_MODE_INPUT);
+}
+
+void enableDebugPorts(void) {
+ // Put PA13-PA15 and PB3-PB4 back in system AF mode.
+ gpio_set_mode(GPIOA, 13, GPIO_MODE_AF);
+ gpio_set_mode(GPIOA, 14, GPIO_MODE_AF);
+ gpio_set_mode(GPIOA, 15, GPIO_MODE_AF);
+ gpio_set_mode(GPIOB, 3, GPIO_MODE_AF);
+ gpio_set_mode(GPIOB, 4, GPIO_MODE_AF);
+ gpio_set_af(GPIOA, 13, GPIO_AF_SYS);
+ gpio_set_af(GPIOA, 14, GPIO_AF_SYS);
+ gpio_set_af(GPIOA, 15, GPIO_AF_SYS);
+ gpio_set_af(GPIOB, 3, GPIO_AF_SYS);
+ gpio_set_af(GPIOB, 4, GPIO_AF_SYS);
+}
diff --git a/wirish/stm32f2/wirish_digital.cpp b/wirish/stm32f2/wirish_digital.cpp
new file mode 100644
index 0000000..4d46f1c
--- /dev/null
+++ b/wirish/stm32f2/wirish_digital.cpp
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/*
+ * STM32F2 implementations for basic GPIO functionality.
+ */
+
+#include <wirish/io.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+
+#include <wirish/boards.h>
+
+void pinMode(uint8 pin, WiringPinMode w_mode) {
+ if (pin >= BOARD_NR_GPIO_PINS) {
+ return;
+ }
+
+ gpio_pin_mode mode;
+ // People always do the silly pin-toggle speed benchmark, so let's
+ // accomodate them:
+ unsigned flags = GPIO_MODEF_SPEED_HIGH;
+ bool pwm = false;
+ switch(w_mode) {
+ case OUTPUT:
+ mode = GPIO_MODE_OUTPUT;
+ break;
+ case OUTPUT_OPEN_DRAIN:
+ mode = GPIO_MODE_OUTPUT;
+ flags |= GPIO_MODEF_TYPE_OD;
+ break;
+ case INPUT:
+ case INPUT_FLOATING:
+ mode = GPIO_MODE_INPUT;
+ break;
+ case INPUT_ANALOG:
+ mode = GPIO_MODE_ANALOG;
+ break;
+ case INPUT_PULLUP:
+ mode = GPIO_MODE_INPUT;
+ flags |= GPIO_MODEF_PUPD_PU;
+ break;
+ case INPUT_PULLDOWN:
+ mode = GPIO_MODE_INPUT;
+ flags |= GPIO_MODEF_PUPD_PD;
+ break;
+ case PWM:
+ mode = GPIO_MODE_AF;
+ pwm = true;
+ break;
+ case PWM_OPEN_DRAIN:
+ mode = GPIO_MODE_AF;
+ flags |= GPIO_MODEF_TYPE_OD;
+ pwm = true;
+ break;
+ default:
+ ASSERT(0); // Can't happen
+ return;
+ }
+
+ const stm32_pin_info *info = &PIN_MAP[pin];
+
+ if (pwm) {
+ /* If enabling PWM, tell the timer to do PWM, and tell the pin
+ * to listen to the right timer. */
+ ASSERT(info->timer_device != NULL);
+ if (info->timer_device == NULL) {
+ return;
+ }
+ gpio_af timer_af = timer_get_af(info->timer_device);
+ timer_set_mode(info->timer_device, info->timer_channel, TIMER_PWM);
+ gpio_set_af(info->gpio_device, info->gpio_bit, timer_af);
+ }
+ gpio_set_modef(info->gpio_device, info->gpio_bit, mode, flags);
+}
diff --git a/wirish/syscalls.c b/wirish/syscalls.c
new file mode 100644
index 0000000..d5f2d9f
--- /dev/null
+++ b/wirish/syscalls.c
@@ -0,0 +1,176 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/syscalls.c
+ * @brief newlib stubs
+ *
+ * Low level system routines used by newlib for basic I/O and memory
+ * allocation. You can override most of these.
+ */
+
+#include <libmaple/libmaple.h>
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stddef.h>
+
+/* If CONFIG_HEAP_START (or CONFIG_HEAP_END) isn't defined, then
+ * assume _lm_heap_start (resp. _lm_heap_end) is appropriately set by
+ * the linker */
+#ifndef CONFIG_HEAP_START
+extern char _lm_heap_start;
+#define CONFIG_HEAP_START ((void *)&_lm_heap_start)
+#endif
+#ifndef CONFIG_HEAP_END
+extern char _lm_heap_end;
+#define CONFIG_HEAP_END ((void *)&_lm_heap_end)
+#endif
+
+/*
+ * _sbrk -- Increment the program break.
+ *
+ * Get incr bytes more RAM (for use by the heap). malloc() and
+ * friends call this function behind the scenes.
+ */
+void *_sbrk(int incr) {
+ static void * pbreak = NULL; /* current program break */
+ void * ret;
+
+ if (pbreak == NULL) {
+ pbreak = CONFIG_HEAP_START;
+ }
+
+ if ((CONFIG_HEAP_END - pbreak < incr) ||
+ (pbreak - CONFIG_HEAP_START < -incr)) {
+ errno = ENOMEM;
+ return (void *)-1;
+ }
+
+ ret = pbreak;
+ pbreak += incr;
+ return ret;
+}
+
+__weak int _open(const char *path, int flags, ...) {
+ return 1;
+}
+
+__weak int _close(int fd) {
+ return 0;
+}
+
+__weak int _fstat(int fd, struct stat *st) {
+ st->st_mode = S_IFCHR;
+ return 0;
+}
+
+__weak int _isatty(int fd) {
+ return 1;
+}
+
+__weak int isatty(int fd) {
+ return 1;
+}
+
+__weak int _lseek(int fd, off_t pos, int whence) {
+ return -1;
+}
+
+__weak unsigned char getch(void) {
+ return 0;
+}
+
+
+__weak int _read(int fd, char *buf, size_t cnt) {
+ *buf = getch();
+
+ return 1;
+}
+
+__weak void putch(unsigned char c) {
+}
+
+__weak void cgets(char *s, int bufsize) {
+ char *p;
+ int c;
+ int i;
+
+ for (i = 0; i < bufsize; i++) {
+ *(s+i) = 0;
+ }
+// memset(s, 0, bufsize);
+
+ p = s;
+
+ for (p = s; p < s + bufsize-1;) {
+ c = getch();
+ switch (c) {
+ case '\r' :
+ case '\n' :
+ putch('\r');
+ putch('\n');
+ *p = '\n';
+ return;
+
+ case '\b' :
+ if (p > s) {
+ *p-- = 0;
+ putch('\b');
+ putch(' ');
+ putch('\b');
+ }
+ break;
+
+ default :
+ putch(c);
+ *p++ = c;
+ break;
+ }
+ }
+ return;
+}
+
+__weak int _write(int fd, const char *buf, size_t cnt) {
+ int i;
+
+ for (i = 0; i < cnt; i++)
+ putch(buf[i]);
+
+ return cnt;
+}
+
+/* Override fgets() in newlib with a version that does line editing */
+__weak char *fgets(char *s, int bufsize, void *f) {
+ cgets(s, bufsize);
+ return s;
+}
+
+__weak void _exit(int exitcode) {
+ while (1)
+ ;
+}
diff --git a/wirish/usb_serial.cpp b/wirish/usb_serial.cpp
new file mode 100644
index 0000000..3bb1923
--- /dev/null
+++ b/wirish/usb_serial.cpp
@@ -0,0 +1,286 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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 USB virtual serial terminal
+ */
+
+#include <wirish/usb_serial.h>
+
+#include <string.h>
+#include <stdint.h>
+
+#include <libmaple/nvic.h>
+#include <libmaple/usb_cdcacm.h>
+#include <libmaple/usb.h>
+#include <libmaple/iwdg.h>
+
+#include <wirish/wirish.h>
+
+/*
+ * Hooks used for bootloader reset signalling
+ */
+
+#if BOARD_HAVE_SERIALUSB
+static void rxHook(unsigned, void*);
+static void ifaceSetupHook(unsigned, void*);
+#endif
+
+/*
+ * USBSerial interface
+ */
+
+#define USB_TIMEOUT 50
+
+USBSerial::USBSerial(void) {
+#if !BOARD_HAVE_SERIALUSB
+ ASSERT(0);
+#endif
+}
+
+void USBSerial::begin(void) {
+#if BOARD_HAVE_SERIALUSB
+ usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT);
+ usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook);
+ usb_cdcacm_set_hooks(USB_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook);
+#endif
+}
+
+void USBSerial::end(void) {
+#if BOARD_HAVE_SERIALUSB
+ usb_cdcacm_disable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT);
+ usb_cdcacm_remove_hooks(USB_CDCACM_HOOK_RX | USB_CDCACM_HOOK_IFACE_SETUP);
+#endif
+}
+
+void USBSerial::write(uint8 ch) {
+ this->write(&ch, 1);
+}
+
+void USBSerial::write(const char *str) {
+ this->write(str, strlen(str));
+}
+
+void USBSerial::write(const void *buf, uint32 len) {
+ if (!this->isConnected() || !buf) {
+ return;
+ }
+
+ uint32 txed = 0;
+ uint32 old_txed = 0;
+ uint32 start = millis();
+
+ uint32 sent = 0;
+
+ while (txed < len && (millis() - start < USB_TIMEOUT)) {
+ sent = usb_cdcacm_tx((const uint8*)buf + txed, len - txed);
+ txed += sent;
+ if (old_txed != txed) {
+ start = millis();
+ }
+ old_txed = txed;
+ }
+
+
+ if (sent == USB_CDCACM_TX_EPSIZE) {
+ while (usb_cdcacm_is_transmitting() != 0) {
+ }
+ /* flush out to avoid having the pc wait for more data */
+ usb_cdcacm_tx(NULL, 0);
+ }
+}
+
+uint32 USBSerial::available(void) {
+ return usb_cdcacm_data_available();
+}
+
+uint32 USBSerial::read(void *buf, uint32 len) {
+ if (!buf) {
+ return 0;
+ }
+
+ uint32 rxed = 0;
+ while (rxed < len) {
+ rxed += usb_cdcacm_rx((uint8*)buf + rxed, len - rxed);
+ }
+
+ return rxed;
+}
+
+/* Blocks forever until 1 byte is received */
+uint8 USBSerial::read(void) {
+ uint8 b;
+ this->read(&b, 1);
+ return b;
+}
+
+uint8 USBSerial::pending(void) {
+ return usb_cdcacm_get_pending();
+}
+
+uint8 USBSerial::isConnected(void) {
+ return usb_is_connected(USBLIB) && usb_is_configured(USBLIB);
+}
+
+uint8 USBSerial::getDTR(void) {
+ return usb_cdcacm_get_dtr();
+}
+
+uint8 USBSerial::getRTS(void) {
+ return usb_cdcacm_get_rts();
+}
+
+#if BOARD_HAVE_SERIALUSB
+USBSerial SerialUSB;
+#endif
+
+/*
+ * Bootloader hook implementations
+ */
+
+#if BOARD_HAVE_SERIALUSB
+
+enum reset_state_t {
+ DTR_UNSET,
+ DTR_HIGH,
+ DTR_NEGEDGE,
+ DTR_LOW
+};
+
+static reset_state_t reset_state = DTR_UNSET;
+
+static void ifaceSetupHook(unsigned hook, void *requestvp) {
+ uint8 request = *(uint8*)requestvp;
+
+ // Ignore requests we're not interested in.
+ if (request != USB_CDCACM_SET_CONTROL_LINE_STATE) {
+ return;
+ }
+
+#if defined(BOOTLOADER_maple)
+ // We need to see a negative edge on DTR before we start looking
+ // for the in-band magic reset byte sequence.
+ uint8 dtr = usb_cdcacm_get_dtr();
+ switch (reset_state) {
+ case DTR_UNSET:
+ reset_state = dtr ? DTR_HIGH : DTR_LOW;
+ break;
+ case DTR_HIGH:
+ reset_state = dtr ? DTR_HIGH : DTR_NEGEDGE;
+ break;
+ case DTR_NEGEDGE:
+ reset_state = dtr ? DTR_HIGH : DTR_LOW;
+ break;
+ case DTR_LOW:
+ reset_state = dtr ? DTR_HIGH : DTR_LOW;
+ break;
+ }
+#endif
+
+#if defined(BOOTLOADER_robotis)
+ uint8 dtr = usb_cdcacm_get_dtr();
+ uint8 rts = usb_cdcacm_get_rts();
+
+ if (rts && !dtr) {
+ reset_state = DTR_NEGEDGE;
+ }
+#endif
+}
+
+#define RESET_DELAY 100000
+#if defined(BOOTLOADER_maple)
+static void wait_reset(void) {
+ delay_us(RESET_DELAY);
+ nvic_sys_reset();
+}
+#endif
+
+#define STACK_TOP 0x20000800
+#define EXC_RETURN 0xFFFFFFF9
+#define DEFAULT_CPSR 0x61000000
+static void rxHook(unsigned hook, void *ignored) {
+ /* FIXME this is mad buggy; we need a new reset sequence. E.g. NAK
+ * after each RX means you can't reset if any bytes are waiting. */
+ if (reset_state == DTR_NEGEDGE) {
+ reset_state = DTR_LOW;
+
+ if (usb_cdcacm_data_available() >= 4) {
+ // The magic reset sequence is "1EAF".
+#if defined(BOOTLOADER_maple)
+ static const uint8 magic[4] = {'1', 'E', 'A', 'F'};
+#endif
+#if defined(BOOTLOADER_robotis)
+ static const uint8 magic[4] = {'C', 'M', '9', 'X'};
+#endif
+ uint8 chkBuf[4];
+
+ // Peek at the waiting bytes, looking for reset sequence,
+ // bailing on mismatch.
+ usb_cdcacm_peek(chkBuf, 4);
+ for (unsigned i = 0; i < sizeof(magic); i++) {
+ if (chkBuf[i] != magic[i]) {
+ return;
+ }
+ }
+
+#if defined(BOOTLOADER_maple)
+ // Got the magic sequence -> reset, presumably into the bootloader.
+ // Return address is wait_reset, but we must set the thumb bit.
+ uintptr_t target = (uintptr_t)wait_reset | 0x1;
+ asm volatile("mov r0, %[stack_top] \n\t" // Reset 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" // PC target addr
+ "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");
+#endif
+
+#if defined(BOOTLOADER_robotis)
+ iwdg_init(IWDG_PRE_4, 10);
+#endif
+
+ /* Can't happen. */
+ ASSERT_FAULT(0);
+ }
+ }
+}
+
+#endif // BOARD_HAVE_SERIALUSB
diff --git a/wirish/wirish_analog.cpp b/wirish/wirish_analog.cpp
new file mode 100644
index 0000000..91ca0e2
--- /dev/null
+++ b/wirish/wirish_analog.cpp
@@ -0,0 +1,47 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 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.
+ *****************************************************************************/
+
+/**
+ * @file wirish/wirish_analog.cpp
+ * @brief Wiring-style analogRead() implementation.
+ */
+
+#include <wirish/io.h>
+#include <libmaple/adc.h>
+#include <wirish/boards.h>
+
+/* Unlike Wiring and Arduino, this assumes that the pin's mode is set
+ * to INPUT_ANALOG. That's faster, but it does require some extra work
+ * on the user's part. Not too much, we think ;). */
+uint16 analogRead(uint8 pin) {
+ const adc_dev *dev = PIN_MAP[pin].adc_device;
+ if (dev == NULL) {
+ return 0;
+ }
+
+ return adc_read(dev, PIN_MAP[pin].adc_channel);
+}
diff --git a/wirish/wirish_digital.cpp b/wirish/wirish_digital.cpp
new file mode 100644
index 0000000..2711a33
--- /dev/null
+++ b/wirish/wirish_digital.cpp
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2012 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.
+ *****************************************************************************/
+
+/*
+ * Arduino-compatible digital I/O implementation.
+ */
+
+#include <wirish/io.h>
+
+#include <libmaple/gpio.h>
+#include <libmaple/timer.h>
+
+#include <wirish/wirish_time.h>
+#include <wirish/boards.h>
+
+uint32 digitalRead(uint8 pin) {
+ if (pin >= BOARD_NR_GPIO_PINS) {
+ return 0;
+ }
+
+ return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit) ?
+ HIGH : LOW;
+}
+
+void digitalWrite(uint8 pin, uint8 val) {
+ if (pin >= BOARD_NR_GPIO_PINS) {
+ return;
+ }
+
+ gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val);
+}
+
+void togglePin(uint8 pin) {
+ if (pin >= BOARD_NR_GPIO_PINS) {
+ return;
+ }
+
+ gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit);
+}
+
+#define BUTTON_DEBOUNCE_DELAY 1
+
+uint8 isButtonPressed(uint8 pin, uint32 pressedLevel) {
+ if (digitalRead(pin) == pressedLevel) {
+ delay(BUTTON_DEBOUNCE_DELAY);
+ while (digitalRead(pin) == pressedLevel)
+ ;
+ 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
new file mode 100644
index 0000000..1443b3c
--- /dev/null
+++ b/wirish/wirish_math.cpp
@@ -0,0 +1,49 @@
+/*
+ * Modified by LeafLabs, LLC.
+ *
+ * Part of the Wiring project - http://wiring.org.co Copyright (c)
+ * 2004-06 Hernando Barragan Modified 13 August 2006, David A. Mellis
+ * for Arduino - http://www.arduino.cc/
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <wirish/wirish_math.h>
+
+void randomSeed(unsigned int seed) {
+ if (seed != 0) {
+ srand(seed);
+ }
+}
+
+long random(long howbig) {
+ if (howbig == 0) {
+ return 0;
+ }
+
+ return rand() % howbig;
+}
+
+long random(long howsmall, long howbig) {
+ if (howsmall >= howbig) {
+ return howsmall;
+ }
+
+ long diff = howbig - howsmall;
+ return random(diff) + howsmall;
+}
+
diff --git a/wirish/wirish_shift.cpp b/wirish/wirish_shift.cpp
new file mode 100644
index 0000000..a032d50
--- /dev/null
+++ b/wirish/wirish_shift.cpp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2012 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 <wirish/wirish.h>
+
+void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, uint8 value) {
+ digitalWrite(clockPin, LOW);
+ for (int i = 0; i < 8; i++) {
+ int bit = bitOrder == LSBFIRST ? i : (7 - i);
+ digitalWrite(dataPin, (value >> bit) & 0x1);
+ togglePin(clockPin);
+ togglePin(clockPin);
+ }
+}
diff --git a/wirish/wirish_time.cpp b/wirish/wirish_time.cpp
new file mode 100644
index 0000000..9ce934b
--- /dev/null
+++ b/wirish/wirish_time.cpp
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ *
+ * 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 Delay implementation.
+ */
+
+#include <wirish/wirish_time.h>
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/delay.h>
+
+void delay(unsigned long ms) {
+ uint32 i;
+ for (i = 0; i < ms; i++) {
+ delayMicroseconds(1000);
+ }
+}
+
+void delayMicroseconds(uint32 us) {
+ delay_us(us);
+}