diff options
-rw-r--r-- | .dir-locals.el | 6 | ||||
-rw-r--r-- | .gitignore | 10 | ||||
-rw-r--r-- | CREDITS | 83 | ||||
-rw-r--r-- | HACKING | 18 | ||||
-rw-r--r-- | LICENSE | 100 | ||||
-rw-r--r-- | Makefile | 325 | ||||
-rw-r--r-- | README | 132 | ||||
-rw-r--r-- | build-targets.mk | 42 | ||||
-rw-r--r-- | contrib/astylerc | 22 | ||||
-rw-r--r-- | contrib/automake/Makefile.am | 138 | ||||
-rw-r--r-- | contrib/automake/configure.ac | 8 | ||||
-rw-r--r-- | contrib/openocd/debug_0.3.cfg | 75 | ||||
-rw-r--r-- | contrib/openocd/debug_0.4.cfg | 75 | ||||
-rw-r--r-- | contrib/openocd/flash_0.3.cfg | 89 | ||||
-rw-r--r-- | contrib/openocd/flash_0.4.cfg | 95 | ||||
-rwxr-xr-x | contrib/openocd/openocd-wrapper.sh | 16 | ||||
-rw-r--r-- | docs/.gitignore | 2 | ||||
-rw-r--r-- | docs/Makefile | 134 | ||||
-rw-r--r-- | docs/README | 24 | ||||
-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-x | docs/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) | bin | 22657 -> 22657 bytes | |||
-rw-r--r-- | docs/source/_static/img/blinky.png (renamed from source/_static/img/blinky.png) | bin | 21042 -> 21042 bytes | |||
-rw-r--r-- | docs/source/_static/img/button-new.png (renamed from source/_static/img/button-new.png) | bin | 234 -> 234 bytes | |||
-rw-r--r-- | docs/source/_static/img/button-open.png (renamed from source/_static/img/button-open.png) | bin | 259 -> 259 bytes | |||
-rw-r--r-- | docs/source/_static/img/button-save.png (renamed from source/_static/img/button-save.png) | bin | 253 -> 253 bytes | |||
-rw-r--r-- | docs/source/_static/img/button-serial-monitor.png (renamed from source/_static/img/button-serial-monitor.png) | bin | 249 -> 249 bytes | |||
-rw-r--r-- | docs/source/_static/img/button-stop.png (renamed from source/_static/img/button-stop.png) | bin | 294 -> 294 bytes | |||
-rw-r--r-- | docs/source/_static/img/button-upload.png (renamed from source/_static/img/button-upload.png) | bin | 291 -> 291 bytes | |||
-rw-r--r-- | docs/source/_static/img/button-verify.png (renamed from source/_static/img/button-verify.png) | bin | 326 -> 326 bytes | |||
-rw-r--r-- | docs/source/_static/img/codeblocks_build.png (renamed from source/_static/img/codeblocks_build.png) | bin | 112088 -> 112088 bytes | |||
-rw-r--r-- | docs/source/_static/img/codeblocks_makefile.png (renamed from source/_static/img/codeblocks_makefile.png) | bin | 75653 -> 75653 bytes | |||
-rw-r--r-- | docs/source/_static/img/codeblocks_maketargets.png (renamed from source/_static/img/codeblocks_maketargets.png) | bin | 56250 -> 56250 bytes | |||
-rw-r--r-- | docs/source/_static/img/codeblocks_newproject.png (renamed from source/_static/img/codeblocks_newproject.png) | bin | 45930 -> 45930 bytes | |||
-rw-r--r-- | docs/source/_static/img/github-clone-in-windows.png (renamed from source/_static/img/github-clone-in-windows.png) | bin | 3899 -> 3899 bytes | |||
-rw-r--r-- | docs/source/_static/img/ide-blinky.png (renamed from source/_static/img/ide-blinky.png) | bin | 29213 -> 29213 bytes | |||
-rw-r--r-- | docs/source/_static/img/jtag-wiring.png (renamed from source/_static/img/jtag-wiring.png) | bin | 33637 -> 33637 bytes | |||
-rw-r--r-- | docs/source/_static/img/osx-network-prefs-unconfigured.png (renamed from source/_static/img/osx-network-prefs-unconfigured.png) | bin | 81770 -> 81770 bytes | |||
-rw-r--r-- | docs/source/_static/img/osx-unconfigured-popup.png (renamed from source/_static/img/osx-unconfigured-popup.png) | bin | 28359 -> 28359 bytes | |||
-rw-r--r-- | docs/source/_static/img/round_logo_32x32.ico (renamed from source/_static/img/round_logo_32x32.ico) | bin | 4286 -> 4286 bytes | |||
-rw-r--r-- | docs/source/_static/img/round_logo_60x60.png (renamed from source/_static/img/round_logo_60x60.png) | bin | 5552 -> 5552 bytes | |||
-rw-r--r-- | docs/source/_static/img/serial-monitor.png (renamed from source/_static/img/serial-monitor.png) | bin | 55975 -> 55975 bytes | |||
-rw-r--r-- | docs/source/_static/img/serial-port-mac.png (renamed from source/_static/img/serial-port-mac.png) | bin | 64284 -> 64284 bytes | |||
-rw-r--r-- | docs/source/_static/img/serial-port-ubuntu.png (renamed from source/_static/img/serial-port-ubuntu.png) | bin | 46629 -> 46629 bytes | |||
-rw-r--r-- | docs/source/_static/img/serial-port-win.png (renamed from source/_static/img/serial-port-win.png) | bin | 15183 -> 15183 bytes | |||
-rw-r--r-- | docs/source/_static/img/upload-button.png (renamed from source/_static/img/upload-button.png) | bin | 9993 -> 9993 bytes | |||
-rw-r--r-- | docs/source/_static/img/verify-success.png (renamed from source/_static/img/verify-success.png) | bin | 26460 -> 26460 bytes | |||
-rw-r--r-- | docs/source/_static/img/verify_button.png (renamed from source/_static/img/verify_button.png) | bin | 1800 -> 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) | bin | 31648 -> 31648 bytes | |||
-rw-r--r-- | docs/source/_static/img/win7-copy-python-address.png (renamed from source/_static/img/win7-copy-python-address.png) | bin | 20500 -> 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) | bin | 29280 -> 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) | bin | 8196 -> 8196 bytes | |||
-rw-r--r-- | docs/source/_static/img/win7-python-path.png (renamed from source/_static/img/win7-python-path.png) | bin | 6912 -> 6912 bytes | |||
-rw-r--r-- | docs/source/_static/img/win7-python-prompt.png (renamed from source/_static/img/win7-python-prompt.png) | bin | 9796 -> 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.cpp | 25 | ||||
-rw-r--r-- | examples/debug-dtrrts.cpp | 38 | ||||
-rw-r--r-- | examples/exti-interrupt-callback.cpp | 87 | ||||
-rw-r--r-- | examples/exti-interrupt.cpp | 50 | ||||
-rw-r--r-- | examples/freertos-blinky.cpp | 43 | ||||
-rw-r--r-- | examples/fsmc-stress-test.cpp | 229 | ||||
-rw-r--r-- | examples/i2c-mcp4725-dac.cpp | 145 | ||||
-rw-r--r-- | examples/mini-exti-test.cpp | 251 | ||||
-rw-r--r-- | examples/qa-slave-shield.cpp | 66 | ||||
-rw-r--r-- | examples/serial-echo.cpp | 30 | ||||
-rw-r--r-- | examples/spi_master.cpp | 77 | ||||
-rw-r--r-- | examples/test-bkp.cpp | 80 | ||||
-rw-r--r-- | examples/test-dac.cpp | 51 | ||||
-rw-r--r-- | examples/test-fsmc.cpp | 122 | ||||
-rw-r--r-- | examples/test-print.cpp | 184 | ||||
-rw-r--r-- | examples/test-ring-buffer-insertion.cpp | 114 | ||||
-rw-r--r-- | examples/test-serial-flush.cpp | 38 | ||||
-rw-r--r-- | examples/test-serialusb.cpp | 126 | ||||
-rw-r--r-- | examples/test-servo.cpp | 152 | ||||
-rw-r--r-- | examples/test-session.cpp | 938 | ||||
-rw-r--r-- | examples/test-spi-roundtrip.cpp | 192 | ||||
-rw-r--r-- | examples/test-systick.cpp | 49 | ||||
-rw-r--r-- | examples/test-timers.cpp | 537 | ||||
-rw-r--r-- | examples/test-usart-dma.cpp | 211 | ||||
-rw-r--r-- | examples/vga-leaf.cpp | 244 | ||||
-rw-r--r-- | examples/vga-scope.cpp | 205 | ||||
-rw-r--r-- | libmaple/adc.c | 109 | ||||
-rw-r--r-- | libmaple/dac.c | 120 | ||||
-rw-r--r-- | libmaple/dma.c | 82 | ||||
-rw-r--r-- | libmaple/dma_private.h | 61 | ||||
-rw-r--r-- | libmaple/exc.S | 101 | ||||
-rw-r--r-- | libmaple/exti.c | 292 | ||||
-rw-r--r-- | libmaple/exti_private.h | 34 | ||||
-rw-r--r-- | libmaple/flash.c | 55 | ||||
-rw-r--r-- | libmaple/gpio.c | 50 | ||||
-rw-r--r-- | libmaple/i2c.c | 509 | ||||
-rw-r--r-- | libmaple/i2c_private.h | 79 | ||||
-rw-r--r-- | libmaple/include/libmaple/adc.h | 329 | ||||
-rw-r--r-- | libmaple/include/libmaple/bitband.h | 128 | ||||
-rw-r--r-- | libmaple/include/libmaple/bkp.h | 166 | ||||
-rw-r--r-- | libmaple/include/libmaple/dac.h | 158 | ||||
-rw-r--r-- | libmaple/include/libmaple/delay.h | 65 | ||||
-rw-r--r-- | libmaple/include/libmaple/dma.h | 444 | ||||
-rw-r--r-- | libmaple/include/libmaple/dma_common.h | 112 | ||||
-rw-r--r-- | libmaple/include/libmaple/exti.h | 143 | ||||
-rw-r--r-- | libmaple/include/libmaple/flash.h | 106 | ||||
-rw-r--r-- | libmaple/include/libmaple/fsmc.h | 340 | ||||
-rw-r--r-- | libmaple/include/libmaple/gpio.h | 121 | ||||
-rw-r--r-- | libmaple/include/libmaple/i2c.h | 413 | ||||
-rw-r--r-- | libmaple/include/libmaple/i2c_common.h | 93 | ||||
-rw-r--r-- | libmaple/include/libmaple/iwdg.h | 115 | ||||
-rw-r--r-- | libmaple/include/libmaple/libmaple.h | 48 | ||||
-rw-r--r-- | libmaple/include/libmaple/libmaple_types.h | 73 | ||||
-rw-r--r-- | libmaple/include/libmaple/nvic.h | 155 | ||||
-rw-r--r-- | libmaple/include/libmaple/pwr.h | 115 | ||||
-rw-r--r-- | libmaple/include/libmaple/rcc.h | 175 | ||||
-rw-r--r-- | libmaple/include/libmaple/ring_buffer.h | 188 | ||||
-rw-r--r-- | libmaple/include/libmaple/scb.h | 214 | ||||
-rw-r--r-- | libmaple/include/libmaple/spi.h | 470 | ||||
-rw-r--r-- | libmaple/include/libmaple/stm32.h | 237 | ||||
-rw-r--r-- | libmaple/include/libmaple/syscfg.h | 151 | ||||
-rw-r--r-- | libmaple/include/libmaple/systick.h | 115 | ||||
-rw-r--r-- | libmaple/include/libmaple/timer.h | 1110 | ||||
-rw-r--r-- | libmaple/include/libmaple/usart.h | 495 | ||||
-rw-r--r-- | libmaple/include/libmaple/usb.h | 176 | ||||
-rw-r--r-- | libmaple/include/libmaple/usb_cdcacm.h | 179 | ||||
-rw-r--r-- | libmaple/include/libmaple/util.h | 111 | ||||
-rw-r--r-- | libmaple/iwdg.c | 62 | ||||
-rw-r--r-- | libmaple/nvic.c | 103 | ||||
-rw-r--r-- | libmaple/pwr.c | 41 | ||||
-rw-r--r-- | libmaple/rcc.c | 169 | ||||
-rw-r--r-- | libmaple/rcc_private.h | 67 | ||||
-rw-r--r-- | libmaple/rules.mk | 50 | ||||
-rw-r--r-- | libmaple/spi.c | 164 | ||||
-rw-r--r-- | libmaple/spi_private.h | 37 | ||||
-rw-r--r-- | libmaple/stm32_private.h | 45 | ||||
-rw-r--r-- | libmaple/stm32f1/adc.c | 115 | ||||
-rw-r--r-- | libmaple/stm32f1/bkp.c | 129 | ||||
-rw-r--r-- | libmaple/stm32f1/dma.c | 413 | ||||
-rw-r--r-- | libmaple/stm32f1/exti.c | 32 | ||||
-rw-r--r-- | libmaple/stm32f1/fsmc.c | 95 | ||||
-rw-r--r-- | libmaple/stm32f1/gpio.c | 166 | ||||
-rw-r--r-- | libmaple/stm32f1/i2c.c | 129 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/adc.h | 253 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/dac.h | 71 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/dma.h | 575 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/exti.h | 46 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/flash.h | 149 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/gpio.h | 493 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/i2c.h | 85 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/nvic.h | 173 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/pwr.h | 52 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/rcc.h | 599 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/spi.h | 99 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/stm32.h | 219 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/timer.h | 128 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/usart.h | 76 | ||||
-rw-r--r-- | libmaple/stm32f1/performance/isrs.S | 263 | ||||
-rw-r--r-- | libmaple/stm32f1/performance/vector_table.S | 118 | ||||
-rw-r--r-- | libmaple/stm32f1/rcc.c | 164 | ||||
-rw-r--r-- | libmaple/stm32f1/rules.mk | 45 | ||||
-rw-r--r-- | libmaple/stm32f1/spi.c | 84 | ||||
-rw-r--r-- | libmaple/stm32f1/timer.c | 124 | ||||
-rw-r--r-- | libmaple/stm32f1/usart.c | 170 | ||||
-rw-r--r-- | libmaple/stm32f1/value/isrs.S | 270 | ||||
-rw-r--r-- | libmaple/stm32f1/value/vector_table.S | 116 | ||||
-rw-r--r-- | libmaple/stm32f2/adc.c | 84 | ||||
-rw-r--r-- | libmaple/stm32f2/dma.c | 504 | ||||
-rw-r--r-- | libmaple/stm32f2/exti.c | 33 | ||||
-rw-r--r-- | libmaple/stm32f2/fsmc.c | 90 | ||||
-rw-r--r-- | libmaple/stm32f2/gpio.c | 194 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/adc.h | 335 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/dac.h | 94 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/dma.h | 810 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/exti.h | 46 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/flash.h | 202 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/gpio.h | 264 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/nvic.h | 160 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/pwr.h | 73 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/rcc.h | 951 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/spi.h | 88 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/stm32.h | 77 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/timer.h | 176 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/usart.h | 111 | ||||
-rw-r--r-- | libmaple/stm32f2/isrs.S | 322 | ||||
-rw-r--r-- | libmaple/stm32f2/rcc.c | 175 | ||||
-rw-r--r-- | libmaple/stm32f2/rules.mk | 40 | ||||
-rw-r--r-- | libmaple/stm32f2/spi.c | 88 | ||||
-rw-r--r-- | libmaple/stm32f2/syscfg.c | 78 | ||||
-rw-r--r-- | libmaple/stm32f2/timer.c | 148 | ||||
-rw-r--r-- | libmaple/stm32f2/usart.c | 204 | ||||
-rw-r--r-- | libmaple/stm32f2/vector_table.S | 135 | ||||
-rw-r--r-- | libmaple/systick.c | 88 | ||||
-rw-r--r-- | libmaple/timer.c | 412 | ||||
-rw-r--r-- | libmaple/timer_private.h | 235 | ||||
-rw-r--r-- | libmaple/usart.c | 138 | ||||
-rw-r--r-- | libmaple/usart_private.c | 41 | ||||
-rw-r--r-- | libmaple/usart_private.h | 53 | ||||
-rw-r--r-- | libmaple/usb/README | 63 | ||||
-rw-r--r-- | libmaple/usb/rules.mk | 45 | ||||
-rw-r--r-- | libmaple/usb/stm32f1/usb.c | 387 | ||||
-rw-r--r-- | libmaple/usb/stm32f1/usb_cdcacm.c | 709 | ||||
-rw-r--r-- | libmaple/usb/stm32f1/usb_lib_globals.h | 55 | ||||
-rw-r--r-- | libmaple/usb/stm32f1/usb_reg_map.c | 88 | ||||
-rw-r--r-- | libmaple/usb/stm32f1/usb_reg_map.h | 617 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_core.c | 1013 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_core.h | 251 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_def.h | 88 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_init.c | 64 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_init.h | 57 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_lib.h | 36 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_mem.c | 73 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_mem.h | 40 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_regs.c | 748 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_regs.h | 627 | ||||
-rw-r--r-- | libmaple/usb/usb_lib/usb_type.h | 77 | ||||
-rw-r--r-- | libmaple/util.c | 150 | ||||
-rw-r--r-- | libraries/FreeRTOS/MapleFreeRTOS.cpp | 44 | ||||
-rw-r--r-- | libraries/FreeRTOS/MapleFreeRTOS.h | 40 | ||||
-rw-r--r-- | libraries/FreeRTOS/keywords.txt | 27 | ||||
-rw-r--r-- | libraries/FreeRTOS/rules.mk | 38 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/FreeRTOS.h | 468 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/FreeRTOSConfig.h | 126 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/StackMacros.h | 174 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/croutine.c | 380 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/croutine.h | 752 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/heap_2.c | 278 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/list.c | 197 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/list.h | 314 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/mpu_wrappers.h | 141 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/port.c | 292 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/portable.h | 396 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/portmacro.h | 156 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/projdefs.h | 83 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/queue.c | 1539 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/queue.h | 1270 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/semphr.h | 717 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/task.h | 1307 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/tasks.c | 2522 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/timers.c | 649 | ||||
-rwxr-xr-x | libraries/FreeRTOS/utility/timers.h | 936 | ||||
-rw-r--r-- | libraries/LiquidCrystal/LiquidCrystal.cpp | 333 | ||||
-rw-r--r-- | libraries/LiquidCrystal/LiquidCrystal.h | 105 | ||||
-rw-r--r-- | libraries/LiquidCrystal/rules.mk | 29 | ||||
-rw-r--r-- | libraries/Servo/Servo.cpp | 150 | ||||
-rw-r--r-- | libraries/Servo/Servo.h | 196 | ||||
-rw-r--r-- | libraries/Servo/rules.mk | 29 | ||||
-rw-r--r-- | libraries/Wire/HardWire.cpp | 66 | ||||
-rw-r--r-- | libraries/Wire/HardWire.h | 69 | ||||
-rw-r--r-- | libraries/Wire/Wire.cpp | 182 | ||||
-rw-r--r-- | libraries/Wire/Wire.h | 136 | ||||
-rw-r--r-- | libraries/Wire/WireBase.cpp | 140 | ||||
-rw-r--r-- | libraries/Wire/WireBase.h | 143 | ||||
-rw-r--r-- | libraries/Wire/rules.mk | 29 | ||||
-rw-r--r-- | main.cpp.example | 43 | ||||
-rw-r--r-- | notes/dac.txt | 67 | ||||
-rw-r--r-- | notes/dma-stm32f1.txt | 99 | ||||
-rw-r--r-- | notes/exti.txt | 41 | ||||
-rw-r--r-- | notes/fsmc.txt | 64 | ||||
-rw-r--r-- | notes/interrupts.txt | 346 | ||||
-rw-r--r-- | notes/pin-definitions.txt | 226 | ||||
-rw-r--r-- | notes/portable.txt | 33 | ||||
-rw-r--r-- | notes/stm32.txt | 63 | ||||
-rw-r--r-- | notes/timers.txt | 96 | ||||
-rw-r--r-- | notes/usb.txt | 72 | ||||
-rw-r--r-- | notes/vga.txt | 35 | ||||
-rw-r--r-- | support/doxygen/Doxyfile | 1648 | ||||
-rwxr-xr-x | support/doxygen/evil_mangler.awk | 38 | ||||
-rw-r--r-- | support/gdb/gpio/gpio.gdb | 12 | ||||
-rw-r--r-- | support/gdb/i2c/test.gdb | 112 | ||||
-rw-r--r-- | support/ld/common.inc | 219 | ||||
-rw-r--r-- | support/ld/flash.ld | 26 | ||||
-rw-r--r-- | support/ld/jtag.ld | 31 | ||||
-rw-r--r-- | support/ld/ram.ld | 25 | ||||
-rw-r--r-- | support/ld/stm32/mem/maple_native/maple_native_heap.inc | 3 | ||||
-rw-r--r-- | support/ld/stm32/mem/maple_native/mem-flash.inc | 7 | ||||
-rw-r--r-- | support/ld/stm32/mem/maple_native/mem-jtag.inc | 7 | ||||
-rw-r--r-- | support/ld/stm32/mem/maple_native/mem-ram.inc | 7 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_112k_flash_1024k/mem-jtag.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_112k_flash_1024k/mem-ram.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_20k_flash_128k/mem-flash.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_20k_flash_128k/mem-jtag.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_20k_flash_128k/mem-ram.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_64k_flash_512k/mem-flash.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_64k_flash_512k/mem-jtag.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_64k_flash_512k/mem-ram.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_8k_flash_128k/mem-flash.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_8k_flash_128k/mem-jtag.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/mem/sram_8k_flash_128k/mem-ram.inc | 5 | ||||
-rw-r--r-- | support/ld/stm32/series/stm32f1/performance/vector_symbols.inc | 78 | ||||
-rw-r--r-- | support/ld/stm32/series/stm32f1/value/vector_symbols.inc | 78 | ||||
-rw-r--r-- | support/ld/stm32/series/stm32f2/vector_symbols.inc | 98 | ||||
-rw-r--r-- | support/ld/toolchains/gcc-arm-embedded/extra_libs.inc | 7 | ||||
-rw-r--r-- | support/ld/toolchains/generic/extra_libs.inc | 0 | ||||
-rw-r--r-- | support/make/board-includes/VLDiscovery.mk | 7 | ||||
-rw-r--r-- | support/make/board-includes/cm900.mk | 15 | ||||
-rw-r--r-- | support/make/board-includes/maple.mk | 10 | ||||
-rw-r--r-- | support/make/board-includes/maple_RET6.mk | 7 | ||||
-rw-r--r-- | support/make/board-includes/maple_mini.mk | 7 | ||||
-rw-r--r-- | support/make/board-includes/maple_native.mk | 7 | ||||
-rw-r--r-- | support/make/board-includes/olimex_stm32_h103.mk | 7 | ||||
-rw-r--r-- | support/make/board-includes/opencm904.mk | 15 | ||||
-rw-r--r-- | support/make/board-includes/st_stm3220g_eval.mk | 5 | ||||
-rw-r--r-- | support/make/build-rules.mk | 59 | ||||
-rw-r--r-- | support/make/build-templates.mk | 5 | ||||
-rw-r--r-- | support/make/footer.mk | 18 | ||||
-rw-r--r-- | support/make/header.mk | 4 | ||||
-rw-r--r-- | support/make/target-config.mk | 54 | ||||
-rw-r--r-- | support/scripts/45-maple.rules | 5 | ||||
-rwxr-xr-x | support/scripts/copy-to-ide | 54 | ||||
-rwxr-xr-x | support/scripts/reset.py | 145 | ||||
-rwxr-xr-x | support/scripts/robotis-loader.py | 94 | ||||
-rw-r--r-- | support/scripts/win-list-com-ports.py | 29 | ||||
-rwxr-xr-x | support/stm32loader.py | 532 | ||||
-rw-r--r-- | wirish/HardwareSPI.cpp | 320 | ||||
-rw-r--r-- | wirish/HardwareSerial.cpp | 137 | ||||
-rw-r--r-- | wirish/HardwareTimer.cpp | 156 | ||||
-rw-r--r-- | wirish/Print.cpp | 252 | ||||
-rw-r--r-- | wirish/boards.cpp | 219 | ||||
-rw-r--r-- | wirish/boards/VLDiscovery/board.cpp | 104 | ||||
-rw-r--r-- | wirish/boards/VLDiscovery/include/board/board.h | 91 | ||||
-rw-r--r-- | wirish/boards/cm900/board.cpp | 117 | ||||
-rw-r--r-- | wirish/boards/cm900/include/board/board.h | 107 | ||||
-rw-r--r-- | wirish/boards/maple/board.cpp | 143 | ||||
-rw-r--r-- | wirish/boards/maple/include/board/board.h | 107 | ||||
-rw-r--r-- | wirish/boards/maple_RET6/board.cpp | 115 | ||||
-rw-r--r-- | wirish/boards/maple_RET6/include/board/board.h | 96 | ||||
-rw-r--r-- | wirish/boards/maple_mini/board.cpp | 105 | ||||
-rw-r--r-- | wirish/boards/maple_mini/include/board/board.h | 83 | ||||
-rw-r--r-- | wirish/boards/maple_native/board.cpp | 197 | ||||
-rw-r--r-- | wirish/boards/maple_native/include/board/board.h | 95 | ||||
-rw-r--r-- | wirish/boards/olimex_stm32_h103/board.cpp | 119 | ||||
-rw-r--r-- | wirish/boards/olimex_stm32_h103/include/board/board.h | 99 | ||||
-rw-r--r-- | wirish/boards/opencm904/board.cpp | 112 | ||||
-rw-r--r-- | wirish/boards/opencm904/include/board/board.h | 105 | ||||
-rw-r--r-- | wirish/boards/st_stm3220g_eval/board.cpp | 60 | ||||
-rw-r--r-- | wirish/boards/st_stm3220g_eval/include/board/board.h | 53 | ||||
-rw-r--r-- | wirish/boards_private.h | 71 | ||||
-rw-r--r-- | wirish/cxxabi-compat.cpp | 6 | ||||
-rw-r--r-- | wirish/ext_interrupts.cpp | 90 | ||||
-rw-r--r-- | wirish/include/wirish/HardwareSPI.h | 225 | ||||
-rw-r--r-- | wirish/include/wirish/HardwareSerial.h | 102 | ||||
-rw-r--r-- | wirish/include/wirish/HardwareTimer.h | 337 | ||||
-rw-r--r-- | wirish/include/wirish/Print.h | 67 | ||||
-rw-r--r-- | wirish/include/wirish/WProgram.h | 35 | ||||
-rw-r--r-- | wirish/include/wirish/bit_constants.h | 579 | ||||
-rw-r--r-- | wirish/include/wirish/bits.h | 35 | ||||
-rw-r--r-- | wirish/include/wirish/boards.h | 173 | ||||
-rw-r--r-- | wirish/include/wirish/ext_interrupts.h | 128 | ||||
-rw-r--r-- | wirish/include/wirish/io.h | 222 | ||||
-rw-r--r-- | wirish/include/wirish/pwm.h | 56 | ||||
-rw-r--r-- | wirish/include/wirish/usb_serial.h | 67 | ||||
-rw-r--r-- | wirish/include/wirish/wirish.h | 77 | ||||
-rw-r--r-- | wirish/include/wirish/wirish_debug.h | 57 | ||||
-rw-r--r-- | wirish/include/wirish/wirish_math.h | 151 | ||||
-rw-r--r-- | wirish/include/wirish/wirish_time.h | 95 | ||||
-rw-r--r-- | wirish/include/wirish/wirish_types.h | 68 | ||||
-rw-r--r-- | wirish/main.cxx | 40 | ||||
-rw-r--r-- | wirish/pwm.cpp | 48 | ||||
-rw-r--r-- | wirish/rules.mk | 62 | ||||
-rw-r--r-- | wirish/start.S | 57 | ||||
-rw-r--r-- | wirish/start_c.c | 95 | ||||
-rw-r--r-- | wirish/stm32f1/boards_setup.cpp | 89 | ||||
-rw-r--r-- | wirish/stm32f1/util_hooks.c | 83 | ||||
-rw-r--r-- | wirish/stm32f1/wirish_debug.cpp | 41 | ||||
-rw-r--r-- | wirish/stm32f1/wirish_digital.cpp | 89 | ||||
-rw-r--r-- | wirish/stm32f2/boards_setup.cpp | 120 | ||||
-rw-r--r-- | wirish/stm32f2/util_hooks.c | 45 | ||||
-rw-r--r-- | wirish/stm32f2/wirish_debug.cpp | 60 | ||||
-rw-r--r-- | wirish/stm32f2/wirish_digital.cpp | 99 | ||||
-rw-r--r-- | wirish/syscalls.c | 176 | ||||
-rw-r--r-- | wirish/usb_serial.cpp | 286 | ||||
-rw-r--r-- | wirish/wirish_analog.cpp | 47 | ||||
-rw-r--r-- | wirish/wirish_digital.cpp | 94 | ||||
-rw-r--r-- | wirish/wirish_math.cpp | 49 | ||||
-rw-r--r-- | wirish/wirish_shift.cpp | 37 | ||||
-rw-r--r-- | wirish/wirish_time.cpp | 45 |
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 @@ -1,2 +1,12 @@ build/ +doxygen/xml/ +doxygen/html/ +main.cpp +libmaple.layout +tags +TAGS *~ +*.swp +arm +cscope* +.gdbinit @@ -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 @@ -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. @@ -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¤tviews=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. @@ -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))))" @@ -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/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 Binary files differindex 0320c5b..0320c5b 100644 --- a/source/_static/img/blinky-to-flash.png +++ b/docs/source/_static/img/blinky-to-flash.png diff --git a/source/_static/img/blinky.png b/docs/source/_static/img/blinky.png Binary files differindex bda4cee..bda4cee 100644 --- a/source/_static/img/blinky.png +++ b/docs/source/_static/img/blinky.png diff --git a/source/_static/img/button-new.png b/docs/source/_static/img/button-new.png Binary files differindex 3fd98be..3fd98be 100644 --- a/source/_static/img/button-new.png +++ b/docs/source/_static/img/button-new.png diff --git a/source/_static/img/button-open.png b/docs/source/_static/img/button-open.png Binary files differindex 466fc10..466fc10 100644 --- a/source/_static/img/button-open.png +++ b/docs/source/_static/img/button-open.png diff --git a/source/_static/img/button-save.png b/docs/source/_static/img/button-save.png Binary files differindex 7eba286..7eba286 100644 --- a/source/_static/img/button-save.png +++ b/docs/source/_static/img/button-save.png diff --git a/source/_static/img/button-serial-monitor.png b/docs/source/_static/img/button-serial-monitor.png Binary files differindex aec9741..aec9741 100644 --- a/source/_static/img/button-serial-monitor.png +++ b/docs/source/_static/img/button-serial-monitor.png diff --git a/source/_static/img/button-stop.png b/docs/source/_static/img/button-stop.png Binary files differindex 4812ae9..4812ae9 100644 --- a/source/_static/img/button-stop.png +++ b/docs/source/_static/img/button-stop.png diff --git a/source/_static/img/button-upload.png b/docs/source/_static/img/button-upload.png Binary files differindex 0f41eeb..0f41eeb 100644 --- a/source/_static/img/button-upload.png +++ b/docs/source/_static/img/button-upload.png diff --git a/source/_static/img/button-verify.png b/docs/source/_static/img/button-verify.png Binary files differindex 95abeb8..95abeb8 100644 --- a/source/_static/img/button-verify.png +++ b/docs/source/_static/img/button-verify.png diff --git a/source/_static/img/codeblocks_build.png b/docs/source/_static/img/codeblocks_build.png Binary files differindex c98bcdc..c98bcdc 100644 --- a/source/_static/img/codeblocks_build.png +++ b/docs/source/_static/img/codeblocks_build.png diff --git a/source/_static/img/codeblocks_makefile.png b/docs/source/_static/img/codeblocks_makefile.png Binary files differindex a0ef21f..a0ef21f 100644 --- a/source/_static/img/codeblocks_makefile.png +++ b/docs/source/_static/img/codeblocks_makefile.png diff --git a/source/_static/img/codeblocks_maketargets.png b/docs/source/_static/img/codeblocks_maketargets.png Binary files differindex bbb68cb..bbb68cb 100644 --- a/source/_static/img/codeblocks_maketargets.png +++ b/docs/source/_static/img/codeblocks_maketargets.png diff --git a/source/_static/img/codeblocks_newproject.png b/docs/source/_static/img/codeblocks_newproject.png Binary files differindex 8d08d1f..8d08d1f 100644 --- a/source/_static/img/codeblocks_newproject.png +++ b/docs/source/_static/img/codeblocks_newproject.png diff --git a/source/_static/img/github-clone-in-windows.png b/docs/source/_static/img/github-clone-in-windows.png Binary files differindex 41d76d1..41d76d1 100644 --- a/source/_static/img/github-clone-in-windows.png +++ b/docs/source/_static/img/github-clone-in-windows.png diff --git a/source/_static/img/ide-blinky.png b/docs/source/_static/img/ide-blinky.png Binary files differindex 3cccdb4..3cccdb4 100644 --- a/source/_static/img/ide-blinky.png +++ b/docs/source/_static/img/ide-blinky.png diff --git a/source/_static/img/jtag-wiring.png b/docs/source/_static/img/jtag-wiring.png Binary files differindex 8f31f99..8f31f99 100644 --- a/source/_static/img/jtag-wiring.png +++ b/docs/source/_static/img/jtag-wiring.png diff --git a/source/_static/img/osx-network-prefs-unconfigured.png b/docs/source/_static/img/osx-network-prefs-unconfigured.png Binary files differindex 70d2fa0..70d2fa0 100644 --- a/source/_static/img/osx-network-prefs-unconfigured.png +++ b/docs/source/_static/img/osx-network-prefs-unconfigured.png diff --git a/source/_static/img/osx-unconfigured-popup.png b/docs/source/_static/img/osx-unconfigured-popup.png Binary files differindex a43ad57..a43ad57 100644 --- a/source/_static/img/osx-unconfigured-popup.png +++ b/docs/source/_static/img/osx-unconfigured-popup.png diff --git a/source/_static/img/round_logo_32x32.ico b/docs/source/_static/img/round_logo_32x32.ico Binary files differindex 29fb2bf..29fb2bf 100644 --- a/source/_static/img/round_logo_32x32.ico +++ b/docs/source/_static/img/round_logo_32x32.ico diff --git a/source/_static/img/round_logo_60x60.png b/docs/source/_static/img/round_logo_60x60.png Binary files differindex dacd36a..dacd36a 100644 --- a/source/_static/img/round_logo_60x60.png +++ b/docs/source/_static/img/round_logo_60x60.png diff --git a/source/_static/img/serial-monitor.png b/docs/source/_static/img/serial-monitor.png Binary files differindex 6162dab..6162dab 100644 --- a/source/_static/img/serial-monitor.png +++ b/docs/source/_static/img/serial-monitor.png diff --git a/source/_static/img/serial-port-mac.png b/docs/source/_static/img/serial-port-mac.png Binary files differindex b3a1989..b3a1989 100644 --- a/source/_static/img/serial-port-mac.png +++ b/docs/source/_static/img/serial-port-mac.png diff --git a/source/_static/img/serial-port-ubuntu.png b/docs/source/_static/img/serial-port-ubuntu.png Binary files differindex 8038e41..8038e41 100644 --- a/source/_static/img/serial-port-ubuntu.png +++ b/docs/source/_static/img/serial-port-ubuntu.png diff --git a/source/_static/img/serial-port-win.png b/docs/source/_static/img/serial-port-win.png Binary files differindex 90dc1c4..90dc1c4 100644 --- a/source/_static/img/serial-port-win.png +++ b/docs/source/_static/img/serial-port-win.png diff --git a/source/_static/img/upload-button.png b/docs/source/_static/img/upload-button.png Binary files differindex 20a663f..20a663f 100644 --- a/source/_static/img/upload-button.png +++ b/docs/source/_static/img/upload-button.png diff --git a/source/_static/img/verify-success.png b/docs/source/_static/img/verify-success.png Binary files differindex 6928674..6928674 100644 --- a/source/_static/img/verify-success.png +++ b/docs/source/_static/img/verify-success.png diff --git a/source/_static/img/verify_button.png b/docs/source/_static/img/verify_button.png Binary files differindex 37100db..37100db 100644 --- a/source/_static/img/verify_button.png +++ b/docs/source/_static/img/verify_button.png diff --git a/source/_static/img/win7-copy-arm-bin-address.png b/docs/source/_static/img/win7-copy-arm-bin-address.png Binary files differindex a3886d1..a3886d1 100644 --- a/source/_static/img/win7-copy-arm-bin-address.png +++ b/docs/source/_static/img/win7-copy-arm-bin-address.png diff --git a/source/_static/img/win7-copy-python-address.png b/docs/source/_static/img/win7-copy-python-address.png Binary files differindex 34d3022..34d3022 100644 --- a/source/_static/img/win7-copy-python-address.png +++ b/docs/source/_static/img/win7-copy-python-address.png diff --git a/source/_static/img/win7-github-open-in-explorer.png b/docs/source/_static/img/win7-github-open-in-explorer.png Binary files differindex 8320a90..8320a90 100644 --- a/source/_static/img/win7-github-open-in-explorer.png +++ b/docs/source/_static/img/win7-github-open-in-explorer.png diff --git a/source/_static/img/win7-python-arm-bin-path.png b/docs/source/_static/img/win7-python-arm-bin-path.png Binary files differindex 8dcc8ed..8dcc8ed 100644 --- a/source/_static/img/win7-python-arm-bin-path.png +++ b/docs/source/_static/img/win7-python-arm-bin-path.png diff --git a/source/_static/img/win7-python-path.png b/docs/source/_static/img/win7-python-path.png Binary files differindex 8898a9e..8898a9e 100644 --- a/source/_static/img/win7-python-path.png +++ b/docs/source/_static/img/win7-python-path.png diff --git a/source/_static/img/win7-python-prompt.png b/docs/source/_static/img/win7-python-prompt.png Binary files differindex 27ae62a..27ae62a 100644 --- a/source/_static/img/win7-python-prompt.png +++ b/docs/source/_static/img/win7-python-prompt.png 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 = ®s->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(®s->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 ? ®s->HISR : ®s->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 ? ®s->HIFCR : ®s->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); +} |