diff --git a/.gitattributes b/.gitattributes index fdd31021f72c8..e6d31d6aa31fc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,7 @@ *.bat text eol=crlf # These are binary so should never be modified by git. +*.a binary *.png binary *.jpg binary *.dxf binary diff --git a/.gitignore b/.gitignore index 5e841a89c059d..50bd30e877e87 100644 --- a/.gitignore +++ b/.gitignore @@ -20,9 +20,10 @@ ###################### *.swp -# Build directory +# Build directories ###################### build/ +build-*/ # Test failure outputs ###################### diff --git a/.gitmodules b/.gitmodules index c986704caa416..c152e9e7747fa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,3 +18,21 @@ [submodule "lib/nrfx"] path = lib/nrfx url = https://github.com/NordicSemiconductor/nrfx.git +[submodule "lib/mbedtls"] + path = lib/mbedtls + url = https://github.com/ARMmbed/mbedtls.git +[submodule "lib/asf4"] + path = lib/asf4 + url = https://github.com/adafruit/asf4 +[submodule "lib/tinyusb"] + path = lib/tinyusb + url = https://github.com/hathach/tinyusb +[submodule "lib/mynewt-nimble"] + path = lib/mynewt-nimble + url = https://github.com/apache/mynewt-nimble.git +[submodule "lib/btstack"] + path = lib/btstack + url = https://github.com/bluekitchen/btstack.git +[submodule "lib/nxp_driver"] + path = lib/nxp_driver + url = https://github.com/hathach/nxp_driver.git diff --git a/.travis.yml b/.travis.yml index 0ba9a002233fe..414fe2b59d108 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,150 +10,350 @@ cache: env: global: - MAKEOPTS="-j4" +git: + submodules: false # define the successive stages stages: - name: test # define the jobs for the stages -# order of the jobs has longest running first to optimise total time +# approx order of the jobs has longest running first to optimise total time jobs: include: + # check code formatting + - stage: test + os: linux + dist: bionic + name: "code formatting" + before_install: + - sudo apt-add-repository --yes --update ppa:pybricks/ppa + install: + - sudo apt-get install uncrustify python3-pip + - uncrustify --version + - pip3 install --user black + - black --version + script: + - tools/codeformat.py + - git diff --exit-code + + # unix port on OSX (first in list because the build VM takes a long time to start) + - stage: test + os: osx + osx_image: xcode11.3 + name: "unix port build with clang on OSX" + env: + - PKG_CONFIG_PATH=/usr/local/opt/libffi/lib/pkgconfig + script: + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/unix submodules + - make ${MAKEOPTS} -C ports/unix deplibs + - make ${MAKEOPTS} -C ports/unix + # OSX has poor time resolution and the following tests do not have the correct output + - (cd tests && ./run-tests --exclude 'uasyncio_(basic|heaplock|lock|wait_task)') + # check for additional compiler errors/warnings + - make ${MAKEOPTS} -C ports/unix VARIANT=coverage submodules + - make ${MAKEOPTS} -C ports/unix VARIANT=coverage + after_failure: + - tests/run-tests --print-failures + # stm32 port - stage: test - env: NAME="stm32 port build" + name: "stm32 port build" install: # need newer gcc version for Cortex-M7 support - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa - sudo apt-get update -qq || true - - sudo apt-get install gcc-arm-embedded - - sudo apt-get install libnewlib-arm-none-eabi + - sudo apt-get install gcc-arm-embedded libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: - make ${MAKEOPTS} -C mpy-cross - - make ${MAKEOPTS} -C ports/stm32 + - make ${MAKEOPTS} -C ports/stm32 submodules + - git submodule update --init lib/btstack + - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 - - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC + - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 + - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF6 NANBOX=1 MICROPY_BLUETOOTH_NIMBLE=0 MICROPY_BLUETOOTH_BTSTACK=1 + - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' + - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L073RZ - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC + - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_WB55 + - make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBD_SF6 # qemu-arm port - stage: test - env: NAME="qemu-arm port build and tests" + dist: bionic # needed for more recent version of qemu-system-arm with mps2-an385 target + name: "qemu-arm port build and tests" install: - - sudo apt-get install gcc-arm-none-eabi - - sudo apt-get install libnewlib-arm-none-eabi - - sudo apt-get install qemu-system + - sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi qemu-system - arm-none-eabi-gcc --version - qemu-system-arm --version script: - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test test after_failure: - - grep "FAIL" ports/qemu-arm/build/console.out + - grep --text "FAIL" ports/qemu-arm/build/console.out # unix coverage - stage: test - env: NAME="unix coverage build and tests" + name: "unix coverage build and tests" install: + - sudo apt-get install python3-pip - sudo pip install cpp-coveralls + - sudo pip3 install setuptools + - sudo pip3 install pyelftools - gcc --version - python3 --version script: - make ${MAKEOPTS} -C mpy-cross - - make ${MAKEOPTS} -C ports/unix deplibs - - make ${MAKEOPTS} -C ports/unix coverage + - make ${MAKEOPTS} -C ports/unix VARIANT=coverage submodules + - make ${MAKEOPTS} -C ports/unix VARIANT=coverage deplibs + - make ${MAKEOPTS} -C ports/unix VARIANT=coverage # run the main test suite - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float micropython) - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy --emit native -d basics float micropython) - # test when input script comes from stdin - - cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc' + - make -C ports/unix VARIANT=coverage test_full + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-multitests.py multi_net/*.py) || travis_terminate 1 + # test building native mpy modules + - make -C examples/natmod/features1 ARCH=x64 + - make -C examples/natmod/features2 ARCH=x64 + - make -C examples/natmod/btree ARCH=x64 + - make -C examples/natmod/framebuf ARCH=x64 + - make -C examples/natmod/uheapq ARCH=x64 + - make -C examples/natmod/urandom ARCH=x64 + - make -C examples/natmod/ure ARCH=x64 + - make -C examples/natmod/uzlib ARCH=x64 + # test importing .mpy generated by mpy_ld.py + - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython-coverage -m features2 + - (cd tests && ./run-natmodtests.py extmod/{btree*,framebuf*,uheapq*,ure*,uzlib*}.py) # run coveralls coverage analysis (try to, even if some builds/tests failed) - (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod) after_failure: - - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) + - tests/run-tests --print-failures + + # unix coverage 32-bit + - stage: test + name: "unix coverage 32-bit build and tests" + install: + - sudo apt-get install gcc-multilib libffi-dev:i386 + - sudo apt-get install python3-pip + - sudo pip3 install setuptools + - sudo pip3 install pyelftools + - gcc --version + - python3 --version + script: + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/unix MICROPY_FORCE_32BIT=1 VARIANT=coverage submodules + - make ${MAKEOPTS} -C ports/unix MICROPY_FORCE_32BIT=1 VARIANT=coverage deplibs + - make ${MAKEOPTS} -C ports/unix MICROPY_FORCE_32BIT=1 VARIANT=coverage + # run the main test suite + - make -C ports/unix MICROPY_FORCE_32BIT=1 VARIANT=coverage test_full || travis_terminate 1 + # test building native mpy modules + - make -C examples/natmod/features1 ARCH=x86 + - make -C examples/natmod/features2 ARCH=x86 + - make -C examples/natmod/btree ARCH=x86 + - make -C examples/natmod/framebuf ARCH=x86 + - make -C examples/natmod/uheapq ARCH=x86 + - make -C examples/natmod/urandom ARCH=x86 + - make -C examples/natmod/ure ARCH=x86 + - make -C examples/natmod/uzlib ARCH=x86 + # test importing .mpy generated by mpy_ld.py + - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython-coverage -m features2 + - (cd tests && ./run-natmodtests.py --arch x86 extmod/{btree*,framebuf*,uheapq*,ure*,uzlib*}.py) + after_failure: + - tests/run-tests --print-failures # standard unix port - stage: test - env: NAME="unix port build and tests" + name: "unix port build and tests" script: - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix deplibs - make ${MAKEOPTS} -C ports/unix - make ${MAKEOPTS} -C ports/unix test + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-perfbench.py 1000 1000) + after_failure: + - tests/run-tests --print-failures - # unix nanbox + # unix nanbox/float (and using Python 2 to check it can run the build scripts) - stage: test - env: NAME="unix nanbox port build and tests" + name: "unix nanbox/float port build and tests" install: - sudo apt-get install gcc-multilib libffi-dev:i386 script: - - make ${MAKEOPTS} -C mpy-cross - - make ${MAKEOPTS} -C ports/unix deplibs - - make ${MAKEOPTS} -C ports/unix nanbox - - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython_nanbox ./run-tests) + - make ${MAKEOPTS} -C mpy-cross PYTHON=python2 + - make ${MAKEOPTS} -C ports/unix VARIANT=nanbox submodules + - make ${MAKEOPTS} -C ports/unix PYTHON=python2 VARIANT=nanbox deplibs + - make ${MAKEOPTS} -C ports/unix PYTHON=python2 VARIANT=nanbox + - make ${MAKEOPTS} -C ports/unix PYTHON=python2 VARIANT=nanbox test_full || travis_terminate 1 + - make ${MAKEOPTS} -C ports/unix clean + - make ${MAKEOPTS} -C ports/unix CFLAGS_EXTRA="-DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT" + - make ${MAKEOPTS} -C ports/unix test + after_failure: + - tests/run-tests --print-failures - # unix stackless + # unix stackless/float with clang - stage: test - env: NAME="unix stackless port build and tests" + name: "unix stackless/float port build and tests with clang" + install: + - sudo apt-get install clang + script: + - make ${MAKEOPTS} -C mpy-cross CC=clang + - make ${MAKEOPTS} -C ports/unix submodules + - make ${MAKEOPTS} -C ports/unix CC=clang CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" + - make ${MAKEOPTS} -C ports/unix CC=clang test || travis_terminate 1 + - make ${MAKEOPTS} -C ports/unix clean + - make ${MAKEOPTS} -C ports/unix CC=clang CFLAGS_EXTRA="-DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT" + - make ${MAKEOPTS} -C ports/unix CC=clang test + after_failure: + - tests/run-tests --print-failures + + # unix with sys.settrace + - stage: test + name: "unix port with sys.settrace build and tests" script: - make ${MAKEOPTS} -C mpy-cross - - make ${MAKEOPTS} -C ports/unix deplibs - - make ${MAKEOPTS} -C ports/unix CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" - - make ${MAKEOPTS} -C ports/unix test + - make ${MAKEOPTS} -C ports/unix MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-DMICROPY_PY_SYS_SETTRACE=1" test || travis_terminate 1 + - make ${MAKEOPTS} -C ports/unix clean + - make ${MAKEOPTS} -C ports/unix MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1 -DMICROPY_PY_SYS_SETTRACE=1" test + after_failure: + - tests/run-tests --print-failures + + # minimal unix port with tests + - stage: test + name: "minimal unix port build and tests" + script: + - make ${MAKEOPTS} -C ports/unix VARIANT=minimal + - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/micropython-minimal ./run-tests -e exception_chain -e self_type_check -e subclass_native_init -d basics) + after_failure: + - tests/run-tests --print-failures # windows port via mingw - stage: test - env: NAME="windows port build via mingw" + name: "windows port build via mingw" install: - sudo apt-get install gcc-mingw-w64 script: - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32- + # esp32 w/ESP-IDFv3 port + - stage: test + name: "esp32 ESP-IDFv3 port build" + install: + - sudo apt-get install python3-pip + - sudo pip3 install 'pyparsing<2.4' + - curl -L https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz | tar zxf - + - export PATH=$(pwd)/xtensa-esp32-elf/bin:$PATH + - git clone https://github.com/espressif/esp-idf.git + - export IDF_PATH=$(pwd)/esp-idf + script: + - make ${MAKEOPTS} -C mpy-cross + - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V3 :=" ports/esp32/Makefile | cut -d " " -f 3) + - git -C esp-idf submodule update --init components/json/cJSON components/esp32/lib components/esptool_py/esptool components/expat/expat components/lwip/lwip components/mbedtls/mbedtls components/micro-ecc/micro-ecc components/nghttp/nghttp2 components/nimble components/bt + - make ${MAKEOPTS} -C ports/esp32 submodules + - make ${MAKEOPTS} -C ports/esp32 + + # esp32 w/ESP-IDFv4 port + - stage: test + name: "esp32 ESP-IDFv4 port build" + install: + - sudo apt-get install python3-pip + - sudo pip3 install 'pyparsing<2.4' + - curl -L https://dl.espressif.com/dl/xtensa-esp32-elf-gcc8_2_0-esp-2019r2-linux-amd64.tar.gz | tar zxf - + - export PATH=$(pwd)/xtensa-esp32-elf/bin:$PATH + - git clone https://github.com/espressif/esp-idf.git + - export IDF_PATH=$(pwd)/esp-idf + script: + - make ${MAKEOPTS} -C mpy-cross + - git -C esp-idf checkout $(grep "ESPIDF_SUPHASH_V4 :=" ports/esp32/Makefile | cut -d " " -f 3) + - git -C esp-idf submodule update --init components/bt/controller/lib components/bt/host/nimble/nimble components/esp_wifi/lib_esp32 components/esptool_py/esptool components/lwip/lwip components/mbedtls/mbedtls + - make ${MAKEOPTS} -C ports/esp32 submodules + - make ${MAKEOPTS} -C ports/esp32 + + # esp8266 port + - stage: test + name: "esp8266 port build" + install: + - wget https://github.com/jepler/esp-open-sdk/releases/download/2018-06-10/xtensa-lx106-elf-standalone.tar.gz + - zcat xtensa-lx106-elf-standalone.tar.gz | tar x + - export PATH=$(pwd)/xtensa-lx106-elf/bin:$PATH + script: + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/esp8266 submodules + - make ${MAKEOPTS} -C ports/esp8266 + - make ${MAKEOPTS} -C ports/esp8266 BOARD=GENERIC_512K + - make ${MAKEOPTS} -C ports/esp8266 BOARD=GENERIC_1M + # nrf port - stage: test - env: NAME="nrf port build" + name: "nrf port build" install: - sudo apt-get install gcc-arm-none-eabi - sudo apt-get install libnewlib-arm-none-eabi - arm-none-eabi-gcc --version script: - - make ${MAKEOPTS} -C ports/nrf + - make ${MAKEOPTS} -C ports/nrf submodules + - make ${MAKEOPTS} -C ports/nrf BOARD=pca10040 + - make ${MAKEOPTS} -C ports/nrf BOARD=microbit + - make ${MAKEOPTS} -C ports/nrf BOARD=pca10056 - # bare-arm and minimal ports + # bare-arm and minimal ports, with size-diff check - stage: test - env: NAME="bare-arm and minimal ports build" + name: "bare-arm and minimal ports build and size-diff check" install: - - sudo apt-get install gcc-arm-none-eabi - - sudo apt-get install libnewlib-arm-none-eabi + - sudo apt-get install gcc-multilib libffi-dev:i386 gcc-arm-none-eabi libnewlib-arm-none-eabi + - gcc --version - arm-none-eabi-gcc --version script: - - make ${MAKEOPTS} -C ports/bare-arm - - make ${MAKEOPTS} -C ports/minimal CROSS=1 build/firmware.bin - - ls -l ports/minimal/build/firmware.bin - - tools/check_code_size.sh - - mkdir -p ${HOME}/persist - # Save new firmware for reference, but only if building a main branch, not a pull request - - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp ports/minimal/build/firmware.bin ${HOME}/persist/; fi' + # starts off at either the ref/pull/N/merge FETCH_HEAD, or the current branch HEAD + - git checkout -b pull_request # save the current location + - git remote add upstream https://github.com/micropython/micropython.git + - git fetch --depth=100 upstream + # build reference, save to size0 + # ignore any errors with this build, in case master is failing + - git checkout `git merge-base --fork-point upstream/master pull_request` + - git show -s + - tools/metrics.py clean bm + - tools/metrics.py build bm | tee ~/size0 || true + # build PR/branch, save to size1 + - git checkout pull_request + - git log upstream/master..HEAD + - tools/metrics.py clean bm + - tools/metrics.py build bm | tee ~/size1 || travis_terminate 1 + # compute diff of the code sizes + - tools/metrics.py diff --error-threshold 0 ~/size0 ~/size1 # cc3200 port - stage: test - env: NAME="cc3200 port build" + name: "cc3200 port build" install: - - sudo apt-get install gcc-arm-none-eabi - - sudo apt-get install libnewlib-arm-none-eabi + - sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi script: - make ${MAKEOPTS} -C ports/cc3200 BTARGET=application BTYPE=release - make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release + # samd port + - stage: test + name: "samd port build" + install: + - sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi + script: + - make ${MAKEOPTS} -C ports/samd submodules + - make ${MAKEOPTS} -C ports/samd + # teensy port - stage: test - env: NAME="teensy port build" + name: "teensy port build" install: - - sudo apt-get install gcc-arm-none-eabi - - sudo apt-get install libnewlib-arm-none-eabi + - sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi script: - make ${MAKEOPTS} -C ports/teensy + + # powerpc port + - stage: test + name: "powerpc port build" + install: + - sudo apt-get install gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross + script: + - make ${MAKEOPTS} -C ports/powerpc UART=potato + - make ${MAKEOPTS} -C ports/powerpc UART=lpc_serial diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS index 65f731b1fffed..41ed6bf24b5a0 100644 --- a/ACKNOWLEDGEMENTS +++ b/ACKNOWLEDGEMENTS @@ -762,7 +762,6 @@ today. The names appear in order of pledging. 1642 Udine 1643 Simon Critchley 1644 Sven Haiges, Germany - 1645 Yi Qing Sim 1646 "silicium" ("silicium_one", if "silicium" is busy) 1648 Andy O'Malia, @andyomalia 1650 RedCamelApps.com diff --git a/CODECONVENTIONS.md b/CODECONVENTIONS.md index 982b958313166..b18c9818ade25 100644 --- a/CODECONVENTIONS.md +++ b/CODECONVENTIONS.md @@ -11,7 +11,7 @@ It's also ok to drop file extensions. Besides prefix, first line of a commit message should describe a change clearly and to the point, and be a grammatical sentence with -final full stop. First line should fit within 78 characters. Examples +final full stop. First line should fit within 72 characters. Examples of good first line of commit messages: py/objstr: Add splitlines() method. @@ -19,9 +19,10 @@ of good first line of commit messages: docs/machine: Fix typo in reset() description. ports: Switch to use lib/foo instead of duplicated code. -After the first line, add an empty line and in following lines describe -a change in a detail, if needed. Any change beyond 5 lines would likely -require such detailed description. +After the first line add an empty line and in the following lines describe +the change in a detail, if needed, with lines fitting within 75 characters +(with an exception for long items like URLs which cannot be broken). Any +change beyond 5 lines would likely require such detailed description. To get good practical examples of good commits and their messages, browse the `git log` of the project. @@ -47,14 +48,27 @@ address on it construes your sign-off of the following: a valid and active email address by which you can be contacted in the foreseeable future. +Code auto-formatting +==================== + +Both C and Python code are auto-formatted using the `tools/codeformat.py` +script. This uses [uncrustify](https://github.com/uncrustify/uncrustify) to +format C code and [black](https://github.com/psf/black) to format Python code. +After making changes, and before committing, run this tool to reformat your +changes to the correct style. Without arguments this tool will reformat all +source code (and may take some time to run). Otherwise pass as arguments to +the tool the files that changed and it will only reformat those. + Python code conventions ======================= -Python code follows [PEP 8](http://legacy.python.org/dev/peps/pep-0008/). +Python code follows [PEP 8](https://legacy.python.org/dev/peps/pep-0008/) and +is auto-formatted using [black](https://github.com/psf/black) with a line-length +of 99 characters. Naming conventions: - Module names are short and all lowercase; eg pyb, stm. -- Class names are CamelCase, with abreviations all uppercase; eg I2C, not +- Class names are CamelCase, with abbreviations all uppercase; eg I2C, not I2c. - Function and method names are all lowercase with words separated by a single underscore as necessary to improve readability; eg mem_read. @@ -64,7 +78,12 @@ Naming conventions: C code conventions ================== -When writing new C code, please adhere to the following conventions. +C code is auto-formatted using [uncrustify](https://github.com/uncrustify/uncrustify) +and the corresponding configuration file `tools/uncrustify.cfg`, with a few +minor fix-ups applied by `tools/codeformat.py`. When writing new C code please +adhere to the existing style and use `tools/codeformat.py` to check any changes. +The main conventions, and things not enforceable via the auto-formatter, are +described below. White space: - Expand tabs to 4 spaces. @@ -125,7 +144,7 @@ Braces, spaces, names and comments: foo(x + TO_ADD, some_value - 1); } - for (int my_counter = 0; my_counter < x; my_counter++) { + for (int my_counter = 0; my_counter < x; ++my_counter) { } } diff --git a/CODEOFCONDUCT.md b/CODEOFCONDUCT.md new file mode 100644 index 0000000000000..07cf87713bd86 --- /dev/null +++ b/CODEOFCONDUCT.md @@ -0,0 +1,53 @@ +MicroPython Code of Conduct +=========================== + +The MicroPython community is made up of members from around the globe with a +diverse set of skills, personalities, and experiences. It is through these +differences that our community experiences great successes and continued growth. +When you're working with members of the community, this Code of Conduct will +help steer your interactions and keep MicroPython a positive, successful, and +growing community. + +Members of the MicroPython community are open, considerate, and respectful. +Behaviours that reinforce these values contribute to a positive environment, and +include: acknowledging time and effort, being respectful of differing viewpoints +and experiences, gracefully accepting constructive criticism, and using +welcoming and inclusive language. + +Every member of our community has the right to have their identity respected. +The MicroPython community is dedicated to providing a positive experience for +everyone, regardless of age, gender identity and expression, sexual orientation, +disability, physical appearance, body size, ethnicity, nationality, race, or +religion (or lack thereof), education, or socio-economic status. + +Unacceptable behaviour includes: harassment, trolling, deliberate intimidation, +violent threats or language directed against another person; insults, put downs, +or jokes that are based upon stereotypes, that are exclusionary, or that hold +others up for ridicule; unwelcome sexual attention or advances; sustained +disruption of community discussions; publishing others' private information +without explicit permission; and other conduct that is inappropriate for a +professional audience including people of many different backgrounds. + +This code of conduct covers all online and offline presence related to the +MicroPython project, including GitHub and the forum. If a participant engages +in behaviour that violates this code of conduct, the MicroPython team may take +action as they deem appropriate, including warning the offender or expulsion +from the community. Community members asked to stop any inappropriate behaviour +are expected to comply immediately. + +Thank you for helping make this a welcoming, friendly community for everyone. + +If you believe that someone is violating the code of conduct, or have any other +concerns, please contact a member of the MicroPython team by emailing +contact@micropython.org. + +License +------- + +This Code of Conduct is licensed under the Creative Commons +Attribution-ShareAlike 3.0 Unported License. + +Attributions +------------ + +Based on the Python code of conduct found at https://www.python.org/psf/conduct/ diff --git a/LICENSE b/LICENSE index e3474e33dd81a..e6a54cf269947 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013, 2014 Damien P. George +Copyright (c) 2013-2019 Damien P. George Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 843511a60b79e..57daebf87263b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/micropython/micropython.png?branch=master)](https://travis-ci.org/micropython/micropython) [![Coverage Status](https://coveralls.io/repos/micropython/micropython/badge.png?branch=master)](https://coveralls.io/r/micropython/micropython?branch=master) +[![Build Status](https://travis-ci.com/micropython/micropython.png?branch=master)](https://travis-ci.com/micropython/micropython) [![Coverage Status](https://coveralls.io/repos/micropython/micropython/badge.png?branch=master)](https://coveralls.io/r/micropython/micropython?branch=master) The MicroPython project ======================= @@ -64,6 +64,17 @@ You will also need bash, gcc, and Python 3.3+ available as the command `python3` (if your system only has Python 2.7 then invoke make with the additional option `PYTHON=python2`). +The MicroPython cross-compiler, mpy-cross +----------------------------------------- + +Most ports require the MicroPython cross-compiler to be built first. This +program, called mpy-cross, is used to pre-compile Python scripts to .mpy +files which can then be included (frozen) into the firmware/executable for +a port. To build mpy-cross use: + + $ cd mpy-cross + $ make + The Unix version ---------------- @@ -75,8 +86,8 @@ Alternatively, fallback implementation based on setjmp/longjmp can be used. To build (see section below for required dependencies): - $ git submodule update --init $ cd ports/unix + $ make submodules $ make Then to give it a try: @@ -88,7 +99,7 @@ Use `CTRL-D` (i.e. EOF) to exit the shell. Learn about command-line options (in particular, how to increase heap size which may be needed for larger applications): - $ ./micropython --help + $ ./micropython -h Run complete testsuite: @@ -116,13 +127,14 @@ Debian/Ubuntu/Mint derivative Linux distros, install `build-essential` Other dependencies can be built together with MicroPython. This may be required to enable extra features or capabilities, and in recent versions of MicroPython, these may be enabled by default. To build -these additional dependencies, first fetch git submodules for them: +these additional dependencies, in the port directory you're +interested in (e.g. `ports/unix/`) first execute: - $ git submodule update --init + $ make submodules -Use the same command to get the latest versions of dependencies, as -they are updated from time to time. After that, in the port directory -(e.g. `ports/unix/`), execute: +This will fetch all the relevant git submodules (sub repositories) that +the port needs. Use the same command to get the latest versions of +submodules as they are updated from time to time. After that execute: $ make deplibs @@ -132,11 +144,11 @@ options (like cross-compiling), the same set of options should be passed to `make deplibs`. To actually enable/disable use of dependencies, edit `ports/unix/mpconfigport.mk` file, which has inline descriptions of the options. For example, to build SSL module (required for `upip` tool described above, -and so enabled by dfeault), `MICROPY_PY_USSL` should be set to 1. +and so enabled by default), `MICROPY_PY_USSL` should be set to 1. For some ports, building required dependences is transparent, and happens -automatically. They still need to be fetched with the git submodule command -above. +automatically. But they still need to be fetched with the `make submodules` +command. The STM32 version ----------------- @@ -148,8 +160,8 @@ https://launchpad.net/gcc-arm-embedded To build: - $ git submodule update --init $ cd ports/stm32 + $ make submodules $ make You then need to get your board into DFU mode. On the pyboard, connect the diff --git a/docs/README.md b/docs/README.md index d524f4b67e4c8..1591911c34560 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,6 +25,21 @@ In `micropython/docs`, build the docs: You'll find the index page at `micropython/docs/build/html/index.html`. +Having readthedocs.org build the documentation +---------------------------------------------- + +If you would like to have docs for forks/branches hosted on GitHub, GitLab or +BitBucket an alternative to building the docs locally is to sign up for a free +https://readthedocs.org account. The rough steps to follow are: +1. sign-up for an account, unless you already have one +2. in your account settings: add GitHub as a connected service (assuming +you have forked this repo on github) +3. in your account projects: import your forked/cloned micropython repository +into readthedocs +4. in the project's versions: add the branches you are developing on or +for which you'd like readthedocs to auto-generate docs whenever you +push a change + PDF manual generation --------------------- diff --git a/docs/conf.py b/docs/conf.py index 61c660aa667ce..36f99cd2c441b 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,7 +74,7 @@ # # We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags" # breakdown, so use the same version identifier for both to avoid confusion. -version = release = '1.10' +version = release = '1.12' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -159,7 +159,7 @@ # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = 'favicon.ico' +html_favicon = 'static/favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index 919f518242bc9..e616adad03353 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -1,3 +1,5 @@ +.. _cmodules: + MicroPython external C modules ============================== @@ -17,6 +19,10 @@ more sense to keep this external to the main MicroPython repository. This chapter describes how to compile such external modules into the MicroPython executable or firmware image. +An alternative approach is to use :ref:`natmod` which allows writing custom C +code that is placed in a .mpy file, which can be imported dynamically in to +a running MicroPython system without the need to recompile the main firmware. + Structure of an external C module --------------------------------- @@ -48,7 +54,7 @@ A MicroPython user C module is a directory with the following files: See below for full usage example. -Basic Example +Basic example ------------- This simple module named ``example`` provides a single function @@ -71,8 +77,6 @@ Directory:: #include "py/runtime.h" #include "py/builtin.h" - #define MODULE_EXAMPLE_ENABLED (1) - // This is the function which will be called from Python as example.add_ints(a, b). STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) { // Extract the ints from the micropython input objects @@ -119,6 +123,19 @@ Directory:: # This is not actually needed in this example. CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR) +Finally you will need to define ``MODULE_EXAMPLE_ENABLED`` to 1. This +can be done by adding ``CFLAGS_EXTRA=-DMODULE_EXAMPLE_ENABLED=1`` to +the ``make`` command, or editing ``mpconfigport.h`` or +``mpconfigboard.h`` to add + +.. code-block:: c + + #define MODULE_EXAMPLE_ENABLED (1) + +Note that the exact method depends on the port as they have different +structures. If not done correctly it will compile but importing will +fail to find the module. + Compiling the cmodule into MicroPython -------------------------------------- @@ -146,7 +163,7 @@ Building for stm32 port: .. code-block:: bash cd my_project/micropython/ports/stm32 - make USER_C_MODULES=../../../modules all + make USER_C_MODULES=../../../modules CFLAGS_EXTRA=-DMODULE_EXAMPLE_ENABLED=1 all Module usage in MicroPython diff --git a/docs/develop/index.rst b/docs/develop/index.rst index 64dbc4661382e..f1fd0692ec9e1 100644 --- a/docs/develop/index.rst +++ b/docs/develop/index.rst @@ -10,3 +10,5 @@ See the `getting started guide :maxdepth: 1 cmodules.rst + qstr.rst + natmod.rst diff --git a/docs/develop/natmod.rst b/docs/develop/natmod.rst new file mode 100644 index 0000000000000..dc9f82e773874 --- /dev/null +++ b/docs/develop/natmod.rst @@ -0,0 +1,215 @@ +.. _natmod: + +Native machine code in .mpy files +================================= + +This section describes how to build and work with .mpy files that contain native +machine code from a language other than Python. This allows you to +write code in a language like C, compile and link it into a .mpy file, and then +import this file like a normal Python module. This can be used for implementing +functionality which is performance critical, or for including an existing +library written in another language. + +One of the main advantages of using native .mpy files is that native machine code +can be imported by a script dynamically, without the need to rebuild the main +MicroPython firmware. This is in contrast to :ref:`cmodules` which also allows +defining custom modules in C but they must be compiled into the main firmware image. + +The focus here is on using C to build native modules, but in principle any +language which can be compiled to stand-alone machine code can be put into a +.mpy file. + +A native .mpy module is built using the ``mpy_ld.py`` tool, which is found in the +``tools/`` directory of the project. This tool takes a set of object files +(.o files) and links them together to create a native .mpy files. + +Supported features and limitations +---------------------------------- + +A .mpy file can contain MicroPython bytecode and/or native machine code. If it +contains native machine code then the .mpy file has a specific architecture +associated with it. Current supported architectures are (these are the valid +options for the ``ARCH`` variable, see below): + +* ``x86`` (32 bit) +* ``x64`` (64 bit x86) +* ``armv7m`` (ARM Thumb 2, eg Cortex-M3) +* ``armv7emsp`` (ARM Thumb 2, single precision float, eg Cortex-M4F, Cortex-M7) +* ``armv7emdp`` (ARM Thumb 2, double precision float, eg Cortex-M7) +* ``xtensa`` (non-windowed, eg ESP8266) +* ``xtensawin`` (windowed with window size 8, eg ESP32) + +When compiling and linking the native .mpy file the architecture must be chosen +and the corresponding file can only be imported on that architecture. For more +details about .mpy files see :ref:`mpy_files`. + +Native code must be compiled as position independent code (PIC) and use a global +offset table (GOT), although the details of this varies from architecture to +architecture. When importing .mpy files with native code the import machinery +is able to do some basic relocation of the native code. This includes +relocating text, rodata and BSS sections. + +Supported features of the linker and dynamic loader are: + +* executable code (text) +* read-only data (rodata), including strings and constant data (arrays, structs, etc) +* zeroed data (BSS) +* pointers in text to text, rodata and BSS +* pointers in rodata to text, rodata and BSS + +The known limitations are: + +* data sections are not supported; workaround: use BSS data and initialise the + data values explicitly + +* static BSS variables are not supported; workaround: use global BSS variables + +So, if your C code has writable data, make sure the data is defined globally, +without an initialiser, and only written to within functions. + +Linker limitation: the native module is not linked against the symbol table of the +full MicroPython firmware. Rather, it is linked against an explicit table of exported +symbols found in ``mp_fun_table`` (in ``py/nativeglue.h``), that is fixed at firmware +build time. It is thus not possible to simply call some arbitrary HAL/OS/RTOS/system +function, for example. + +New symbols can be added to the end of the table and the firmware rebuilt. +The symbols also need to be added to ``tools/mpy_ld.py``'s ``fun_table`` dict in the +same location. This allows ``mpy_ld.py`` to be able to pick the new symbols up and +provide relocations for them when the mpy is imported. Finally, if the symbol is a +function, a macro or stub should be added to ``py/dynruntime.h`` to make it easy to +call the function. + +Defining a native module +------------------------ + +A native .mpy module is defined by a set of files that are used to build the .mpy. +The filesystem layout consists of two main parts, the source files and the Makefile: + +* In the simplest case only a single C source file is required, which contains all + the code that will be compiled into the .mpy module. This C source code must + include the ``py/dynruntime.h`` file to access the MicroPython dynamic API, and + must at least define a function called ``mpy_init``. This function will be the + entry point of the module, called when the module is imported. + + The module can be split into multiple C source files if desired. Parts of the + module can also be implemented in Python. All source files should be listed in + the Makefile, by adding them to the ``SRC`` variable (see below). This includes + both C source files as well as any Python files which will be included in the + resulting .mpy file. + +* The ``Makefile`` contains the build configuration for the module and list the + source files used to build the .mpy module. It should define ``MPY_DIR`` as the + location of the MicroPython repository (to find header files, the relevant Makefile + fragment, and the ``mpy_ld.py`` tool), ``MOD`` as the name of the module, ``SRC`` + as the list of source files, optionally specify the machine architecture via ``ARCH``, + and then include ``py/dynruntime.mk``. + +Minimal example +--------------- + +This section provides a fully working example of a simple module named ``factorial``. +This module provides a single function ``factorial.factorial(x)`` which computes the +factorial of the input and returns the result. + +Directory layout:: + + factorial/ + ├── factorial.c + └── Makefile + +The file ``factorial.c`` contains: + +.. code-block:: c + + // Include the header file to get access to the MicroPython API + #include "py/dynruntime.h" + + // Helper function to compute factorial + STATIC mp_int_t factorial_helper(mp_int_t x) { + if (x == 0) { + return 1; + } + return x * factorial_helper(x - 1); + } + + // This is the function which will be called from Python, as factorial(x) + STATIC mp_obj_t factorial(mp_obj_t x_obj) { + // Extract the integer from the MicroPython input object + mp_int_t x = mp_obj_get_int(x_obj); + // Calculate the factorial + mp_int_t result = factorial_helper(x); + // Convert the result to a MicroPython integer object and return it + return mp_obj_new_int(result); + } + // Define a Python reference to the function above + STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial); + + // This is the entry point and is called when the module is imported + mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the function available in the module's namespace + mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT + } + +The file ``Makefile`` contains: + +.. code-block:: make + + # Location of top-level MicroPython directory + MPY_DIR = ../../.. + + # Name of module + MOD = factorial + + # Source files (.c or .py) + SRC = factorial.c + + # Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) + ARCH = x64 + + # Include to get the rules for compiling and linking the module + include $(MPY_DIR)/py/dynruntime.mk + +Compiling the module +-------------------- + +Be sure to select the correct ``ARCH`` for the target you are going to run on. +Then build with:: + + $ make + +Without modifying the Makefile you can specify the target architecture via:: + + $ make ARCH=armv7m + +Module usage in MicroPython +--------------------------- + +Once the module is built there should be a file called ``factorial.mpy``. Copy +this so it is accessible on the filesystem of your MicroPython system and can be +found in the import path. The module con now be accessed in Python just like any +other module, for example:: + + import factorial + print(factorial.factorial(10)) + # should display 3628800 + +Further examples +---------------- + +See ``examples/natmod/`` for further examples which show many of the available +features of native .mpy modules. Such features include: + +* using multiple C source files +* including Python code alongside C code +* rodata and BSS data +* memory allocation +* use of floating point +* exception handling +* including external C libraries diff --git a/docs/develop/qstr.rst b/docs/develop/qstr.rst new file mode 100644 index 0000000000000..1b3b9f903bc91 --- /dev/null +++ b/docs/develop/qstr.rst @@ -0,0 +1,112 @@ +MicroPython string interning +============================ + +MicroPython uses `string interning`_ to save both RAM and ROM. This avoids +having to store duplicate copies of the same string. Primarily, this applies to +identifiers in your code, as something like a function or variable name is very +likely to appear in multiple places in the code. In MicroPython an interned +string is called a QSTR (uniQue STRing). + +A QSTR value (with type ``qstr``) is a index into a linked list of QSTR pools. +QSTRs store their length and a hash of their contents for fast comparison during +the de-duplication process. All bytecode operations that work with strings use +a QSTR argument. + +Compile-time QSTR generation +---------------------------- + +In the MicroPython C code, any strings that should be interned in the final +firmware are written as ``MP_QSTR_Foo``. At compile time this will evaluate to +a ``qstr`` value that points to the index of ``"Foo"`` in the QSTR pool. + +A multi-step process in the ``Makefile`` makes this work. In summary this +process has three parts: + +1. Find all ``MP_QSTR_Foo`` tokens in the code. + +2. Generate a static QSTR pool containing all the string data (including lengths + and hashes). + +3. Replace all ``MP_QSTR_Foo`` (via the preprocessor) with their corresponding + index. + +``MP_QSTR_Foo`` tokens are searched for in two sources: + +1. All files referenced in ``$(SRC_QSTR)``. This is all C code (i.e. ``py``, + ``extmod``, ``ports/stm32``) but not including third-party code such as + ``lib``. + +2. Additional ``$(QSTR_GLOBAL_DEPENDENCIES)`` (which includes ``mpconfig*.h``). + +*Note:* ``frozen_mpy.c`` (generated by mpy-tool.py) has its own QSTR generation +and pool. + +Some additional strings that can't be expressed using the ``MP_QSTR_Foo`` syntax +(e.g. they contain non-alphanumeric characters) are explicitly provided in +``qstrdefs.h`` and ``qstrdefsport.h`` via the ``$(QSTR_DEFS)`` variable. + +Processing happens in the following stages: + +1. ``qstr.i.last`` is the concatenation of putting every single input file + through the C pre-processor. This means that any conditionally disabled code + will be removed, and macros expanded. This means we don't add strings to the + pool that won't be used in the final firmware. Because at this stage (thanks + to the ``NO_QSTR`` macro added by ``QSTR_GEN_EXTRA_CFLAGS``) there is no + definition for ``MP_QSTR_Foo`` it passes through this stage unaffected. This + file also includes comments from the preprocessor that include line number + information. Note that this step only uses files that have changed, which + means that ``qstr.i.last`` will only contain data from files that have + changed since the last compile. +2. ``qstr.split`` is an empty file created after running ``makeqstrdefs.py split`` + on qstr.i.last. It's just used as a dependency to indicate that the step ran. + This script outputs one file per input C file, ``genhdr/qstr/...file.c.qstr``, + which contains only the matched QSTRs. Each QSTR is printed as ``Q(Foo)``. + This step is necessary to combine the existing files with the new data + generated from the incremental update in ``qstr.i.last``. + +3. ``qstrdefs.collected.h`` is the output of concatenating ``genhdr/qstr/*`` + using ``makeqstrdefs.py cat``. This is now the full set of ``MP_QSTR_Foo``'s + found in the code, now formatted as ``Q(Foo)``, one-per-line, with duplicates. + This file is only updated if the set of qstrs has changed. A hash of the QSTR + data is written to another file (``qstrdefs.collected.h.hash``) which allows + it to track changes across builds. + +4. ``qstrdefs.preprocessed.h`` adds in the QSTRs from qstrdefs*. It + concatenates ``qstrdefs.collected.h`` with ``qstrdefs*.h``, then it transforms + each line from ``Q(Foo)`` to ``"Q(Foo)"`` so they pass through the preprocessor + unchanged. Then the preprocessor is used to deal with any conditional + compilation in ``qstrdefs*.h``. Then the transformation is undone back to + ``Q(Foo)``, and saved as ``qstrdefs.preprocessed.h``. + +5. ``qstrdefs.generated.h`` is the output of ``makeqstrdata.py``. For each + ``Q(Foo)`` in qstrdefs.preprocessed.h (plus some extra hard-coded ones), it outputs + ``QDEF(MP_QSTR_Foo, (const byte*)"hash" "Foo")``. + +Then in the main compile, two things happen with ``qstrdefs.generated.h``: + +1. In qstr.h, each QDEF becomes an entry in an enum, which makes ``MP_QSTR_Foo`` + available to code and equal to the index of that string in the QSTR table. + +2. In qstr.c, the actual QSTR data table is generated as elements of the + ``mp_qstr_const_pool->qstrs``. + +.. _`string interning`: https://en.wikipedia.org/wiki/String_interning + +Run-time QSTR generation +------------------------ + +Additional QSTR pools can be created at runtime so that strings can be added to +them. For example, the code:: + + foo[x] = 3 + +Will need to create a QSTR for the value of ``x`` so it can be used by the +"load attr" bytecode. + +Also, when compiling Python code, identifiers and literals need to have QSTRs +created. Note: only literals shorter than 10 characters become QSTRs. This is +because a regular string on the heap always takes up a minimum of 16 bytes (one +GC block), whereas QSTRs allow them to be packed more efficiently into the pool. + +QSTR pools (and the underlying "chunks" that store the string data) are allocated +on-demand on the heap with a minimum size. diff --git a/docs/esp32/general.rst b/docs/esp32/general.rst index 51918d4e183ea..8137c042d9214 100644 --- a/docs/esp32/general.rst +++ b/docs/esp32/general.rst @@ -52,6 +52,7 @@ For your convenience, some of technical specifications are provided below: * I2S: 2 * ADC: 12-bit SAR ADC up to 18 channels * DAC: 2 8-bit DACs +* RMT: 8 channels allowing accurate pulse transmit/receive * Programming: using BootROM bootloader from UART - due to external FlashROM and always-available BootROM bootloader, the ESP32 is not brickable diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 5ac8aa3b2ff92..8861ca4ac87ed 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -77,11 +77,12 @@ The :mod:`network` module:: wlan.scan() # scan for access points wlan.isconnected() # check if the station is connected to an AP wlan.connect('essid', 'password') # connect to an AP - wlan.config('mac') # get the interface's MAC adddress + wlan.config('mac') # get the interface's MAC address wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses ap = network.WLAN(network.AP_IF) # create access-point interface ap.config(essid='ESP-AP') # set the ESSID of the access point + ap.config(max_clients=10) # set how many clients can connect to the network ap.active(True) # activate the interface A useful function for connecting to your local WiFi network is:: @@ -128,6 +129,8 @@ with timer ID of -1:: The period is in milliseconds. +.. _Pins_and_GPIO: + Pins and GPIO ------------- @@ -201,7 +204,7 @@ Use the :ref:`machine.ADC ` class:: adc = ADC(Pin(32)) # create ADC object on ADC pin adc.read() # read value, 0-4095 across voltage range 0.0v - 1.0v - adc.atten(ADC.ATTN_11DB) # set 11dB input attentuation (voltage range roughly 0.0v - 3.6v) + adc.atten(ADC.ATTN_11DB) # set 11dB input attenuation (voltage range roughly 0.0v - 3.6v) adc.width(ADC.WIDTH_9BIT) # set 9 bit return values (returned range 0-511) adc.read() # read value using the newly configured attenuation and width @@ -255,7 +258,7 @@ class:: spi.init(baudrate=200000) # set the baudrate spi.read(10) # read 10 bytes on MISO - spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI + spi.read(10, 0xff) # read 10 bytes while outputting 0xff on MOSI buf = bytearray(50) # create a buffer spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case) @@ -274,8 +277,13 @@ class:: Hardware SPI bus ---------------- -There are two hardware SPI channels that allow faster (up to 80Mhz) -transmission rates, but are only supported on a subset of pins. +There are two hardware SPI channels that allow faster transmission +rates (up to 80Mhz). These may be used on any IO pins that support the +required direction and are otherwise unused (see :ref:`Pins_and_GPIO`) +but if they are not configured to their default pins then they need to +pass through an extra layer of GPIO multiplexing, which can impact +their reliability at high speeds. Hardware SPI channels are limited +to 40MHz when used on pins other than the default ones listed below. ===== =========== ============ \ HSPI (id=1) VSPI (id=2) @@ -296,14 +304,22 @@ Hardware SPI has the same methods as Software SPI above:: I2C bus ------- -The I2C driver is implemented in software and works on all pins, -and is accessed via the :ref:`machine.I2C ` class:: +The I2C driver has both software and hardware implementations, and the two +hardware peripherals have identifiers 0 and 1. Any available output-capable +pins can be used for SCL and SDA. The driver is accessed via the +:ref:`machine.I2C ` class:: from machine import Pin, I2C - # construct an I2C bus + # construct a software I2C bus i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000) + # construct a hardware I2C bus + i2c = I2C(0) + i2c = I2C(1, scl=Pin(5), sda=Pin(4), freq=400000) + + i2c.scan() # scan for slave devices + i2c.readfrom(0x3a, 4) # read 4 bytes from slave device with address 0x3a i2c.writeto(0x3a, '12') # write '12' to slave device with address 0x3a @@ -344,12 +360,26 @@ Notes: To further reduce power consumption it is possible to disable the internal pullups:: p1 = Pin(4, Pin.IN, Pin.PULL_HOLD) - + After leaving deepsleep it may be necessary to un-hold the pin explicitly (e.g. if it is an output pin) via:: - + p1 = Pin(4, Pin.OUT, None) +RMT +--- + +The RMT is ESP32-specific and allows generation of accurate digital pulses with +12.5ns resolution. See :ref:`esp32.RMT ` for details. Usage is:: + + import esp32 + from machine import Pin + + r = esp32.RMT(0, pin=Pin(18), clock_div=8) + r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8) + # The channel resolution is 100ns (1/(source_freq/clock_div)). + r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns + OneWire driver -------------- @@ -406,7 +436,7 @@ For low-level driving of a NeoPixel:: ``NeoPixel`` object. -Capacitive Touch +Capacitive touch ---------------- Use the ``TouchPad`` class in the ``machine`` module:: diff --git a/docs/esp8266/general.rst b/docs/esp8266/general.rst index 020e21df62d09..fbe8fe1c3cabd 100644 --- a/docs/esp8266/general.rst +++ b/docs/esp8266/general.rst @@ -140,7 +140,7 @@ The above may also happen after an application terminates and quits to the REPL for any reason including an exception. Subsequent arrival of data provokes the failure with the above error message repeatedly issued. So, sockets should be closed in any case, regardless whether an application terminates successfully -or by an exeption, for example using try/finally:: +or by an exception, for example using try/finally:: sock = socket(...) try: diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index 95ae55b570682..9c7db3205a7e6 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -188,7 +188,7 @@ class:: spi.init(baudrate=200000) # set the baudrate spi.read(10) # read 10 bytes on MISO - spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI + spi.read(10, 0xff) # read 10 bytes while outputting 0xff on MOSI buf = bytearray(50) # create a buffer spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case) @@ -243,6 +243,16 @@ See :ref:`machine.RTC ` :: rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time rtc.datetime() # get date and time + # synchronize with ntp + # need to be connected to wifi + import ntptime + ntptime.settime() # set the rtc datetime from the remote server + rtc.datetime() # get the date and time in UTC + +.. note:: Not all methods are implemented: `RTC.now()`, `RTC.irq(handler=*) ` + (using a custom handler), `RTC.init()` and `RTC.deinit()` are + currently not supported. + Deep-sleep mode --------------- diff --git a/docs/esp8266/tutorial/apa102.rst b/docs/esp8266/tutorial/apa102.rst new file mode 100644 index 0000000000000..1c775daae30ce --- /dev/null +++ b/docs/esp8266/tutorial/apa102.rst @@ -0,0 +1,91 @@ +Controlling APA102 LEDs +======================= + +APA102 LEDs, also known as DotStar LEDs, are individually addressable +full-colour RGB LEDs, generally in a string formation. They differ from +NeoPixels in that they require two pins to control - both a Clock and Data pin. +They can operate at a much higher data and PWM frequencies than NeoPixels and +are more suitable for persistence-of-vision effects. + +To create an APA102 object do the following:: + + >>> import machine, apa102 + >>> strip = apa102.APA102(machine.Pin(5), machine.Pin(4), 60) + +This configures an 60 pixel APA102 strip with clock on GPIO5 and data on GPIO4. +You can adjust the pin numbers and the number of pixels to suit your needs. + +The RGB colour data, as well as a brightness level, is sent to the APA102 in a +certain order. Usually this is ``(Red, Green, Blue, Brightness)``. +If you are using one of the newer APA102C LEDs the green and blue are swapped, +so the order is ``(Red, Blue, Green, Brightness)``. +The APA102 has more of a square lens while the APA102C has more of a round one. +If you are using a APA102C strip and would prefer to provide colours in RGB +order instead of RBG, you can customise the tuple colour order like so:: + + >>> strip.ORDER = (0, 2, 1, 3) + +To set the colour of pixels use:: + + >>> strip[0] = (255, 255, 255, 31) # set to white, full brightness + >>> strip[1] = (255, 0, 0, 31) # set to red, full brightness + >>> strip[2] = (0, 255, 0, 15) # set to green, half brightness + >>> strip[3] = (0, 0, 255, 7) # set to blue, quarter brightness + +Use the ``write()`` method to output the colours to the LEDs:: + + >>> strip.write() + +Demonstration:: + + import time + import machine, apa102 + + # 1M strip with 60 LEDs + strip = apa102.APA102(machine.Pin(5), machine.Pin(4), 60) + + brightness = 1 # 0 is off, 1 is dim, 31 is max + + # Helper for converting 0-255 offset to a colour tuple + def wheel(offset, brightness): + # The colours are a transition r - g - b - back to r + offset = 255 - offset + if offset < 85: + return (255 - offset * 3, 0, offset * 3, brightness) + if offset < 170: + offset -= 85 + return (0, offset * 3, 255 - offset * 3, brightness) + offset -= 170 + return (offset * 3, 255 - offset * 3, 0, brightness) + + # Demo 1: RGB RGB RGB + red = 0xff0000 + green = red >> 8 + blue = red >> 16 + for i in range(strip.n): + colour = red >> (i % 3) * 8 + strip[i] = ((colour & red) >> 16, (colour & green) >> 8, (colour & blue), brightness) + strip.write() + + # Demo 2: Show all colours of the rainbow + for i in range(strip.n): + strip[i] = wheel((i * 256 // strip.n) % 255, brightness) + strip.write() + + # Demo 3: Fade all pixels together through rainbow colours, offset each pixel + for r in range(5): + for n in range(256): + for i in range(strip.n): + strip[i] = wheel(((i * 256 // strip.n) + n) & 255, brightness) + strip.write() + time.sleep_ms(25) + + # Demo 4: Same colour, different brightness levels + for b in range(31,-1,-1): + strip[0] = (255, 153, 0, b) + strip.write() + time.sleep_ms(250) + + # End: Turn off all the LEDs + strip.fill((0, 0, 0, 0)) + strip.write() diff --git a/docs/esp8266/tutorial/index.rst b/docs/esp8266/tutorial/index.rst index 0a4b5f2a6688a..4ba211a4b2d8b 100644 --- a/docs/esp8266/tutorial/index.rst +++ b/docs/esp8266/tutorial/index.rst @@ -29,5 +29,6 @@ to ``__. powerctrl.rst onewire.rst neopixel.rst + apa102.rst dht.rst nextsteps.rst diff --git a/docs/esp8266/tutorial/network_tcp.rst b/docs/esp8266/tutorial/network_tcp.rst index 26a2f469ce190..18916884e45fb 100644 --- a/docs/esp8266/tutorial/network_tcp.rst +++ b/docs/esp8266/tutorial/network_tcp.rst @@ -44,7 +44,7 @@ Now that we are connected we can download and display the data:: ... data = s.recv(500) ... print(str(data, 'utf8'), end='') ... - + When this loop executes it should start showing the animation (use ctrl-C to interrupt it). @@ -61,6 +61,7 @@ of the request you need to specify the page to retrieve. Let's define a function that can download and print a URL:: def http_get(url): + import socket _, _, host, path = url.split('/', 3) addr = socket.getaddrinfo(host, 80)[0][-1] s = socket.socket() @@ -74,8 +75,7 @@ Let's define a function that can download and print a URL:: break s.close() -Make sure that you import the socket module before running this function. Then -you can try:: +Then you can try:: >>> http_get('http://micropython.org/ks/test.html') @@ -118,5 +118,6 @@ that contains a table with the state of all the GPIO pins:: break rows = ['%s%d' % (str(p), p.value()) for p in pins] response = html % '\n'.join(rows) + cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') cl.send(response) cl.close() diff --git a/docs/index.rst b/docs/index.rst index c0417c227cbad..f760fa12a080a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,3 +12,4 @@ MicroPython documentation and references esp8266/quickref.rst esp32/quickref.rst wipy/quickref.rst + unix/quickref.rst diff --git a/docs/library/btree.rst b/docs/library/btree.rst index 3578acd8fd42c..a1f7a5420f15e 100644 --- a/docs/library/btree.rst +++ b/docs/library/btree.rst @@ -116,7 +116,7 @@ Methods Flush any data in cache to the underlying stream. .. method:: btree.__getitem__(key) - btree.get(key, default=None) + btree.get(key, default=None, /) btree.__setitem__(key, val) btree.__detitem__(key) btree.__contains__(key) diff --git a/docs/library/esp.rst b/docs/library/esp.rst index 867182be9945c..cb2bc7af8d538 100644 --- a/docs/library/esp.rst +++ b/docs/library/esp.rst @@ -31,7 +31,7 @@ Functions The system enters the set sleep mode automatically when possible. -.. function:: deepsleep(time=0) +.. function:: deepsleep(time=0, /) **Note**: ESP8266 only - use `machine.deepsleep()` on ESP32 diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index c934ef0954872..f3be3692e3267 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -1,3 +1,5 @@ +.. currentmodule:: esp32 + :mod:`esp32` --- functionality specific to the ESP32 ==================================================== @@ -36,9 +38,190 @@ Functions Read the raw value of the internal Hall sensor, returning an integer. +.. function:: idf_heap_info(capabilities) + + Returns information about the ESP-IDF heap memory regions. One of them contains + the MicroPython heap and the others are used by ESP-IDF, e.g., for network + buffers and other data. This data is useful to get a sense of how much memory + is available to ESP-IDF and the networking stack in particular. It may shed + some light on situations where ESP-IDF operations fail due to allocation failures. + The information returned is *not* useful to troubleshoot Python allocation failures, + use `micropython.mem_info()` instead. + + The capabilities parameter corresponds to ESP-IDF's ``MALLOC_CAP_XXX`` values but the + two most useful ones are predefined as `esp32.HEAP_DATA` for data heap regions and + `esp32.HEAP_EXEC` for executable regions as used by the native code emitter. + + The return value is a list of 4-tuples, where each 4-tuple corresponds to one heap + and contains: the total bytes, the free bytes, the largest free block, and + the minimum free seen over time. + + Example after booting:: + + >>> import esp32; esp32.idf_heap_info(esp32.HEAP_DATA) + [(240, 0, 0, 0), (7288, 0, 0, 0), (16648, 4, 4, 4), (79912, 35712, 35512, 35108), + (15072, 15036, 15036, 15036), (113840, 0, 0, 0)] + +Flash partitions +---------------- + +This class gives access to the partitions in the device's flash memory and includes +methods to enable over-the-air (OTA) updates. + +.. class:: Partition(id) + + Create an object representing a partition. *id* can be a string which is the label + of the partition to retrieve, or one of the constants: ``BOOT`` or ``RUNNING``. + +.. classmethod:: Partition.find(type=TYPE_APP, subtype=0xff, label=None) + + Find a partition specified by *type*, *subtype* and *label*. Returns a + (possibly empty) list of Partition objects. Note: ``subtype=0xff`` matches any subtype + and ``label=None`` matches any label. + +.. method:: Partition.info() + + Returns a 6-tuple ``(type, subtype, addr, size, label, encrypted)``. + +.. method:: Partition.readblocks(block_num, buf) +.. method:: Partition.readblocks(block_num, buf, offset) +.. method:: Partition.writeblocks(block_num, buf) +.. method:: Partition.writeblocks(block_num, buf, offset) +.. method:: Partition.ioctl(cmd, arg) + + These methods implement the simple and :ref:`extended + ` block protocol defined by + :class:`uos.AbstractBlockDev`. + +.. method:: Partition.set_boot() + + Sets the partition as the boot partition. + +.. method:: Partition.get_next_update() + + Gets the next update partition after this one, and returns a new Partition object. + Typical usage is ``Partition(Partition.RUNNING).get_next_update()`` + which returns the next partition to update given the current running one. + +.. classmethod:: Partition.mark_app_valid_cancel_rollback() + + Signals that the current boot is considered successful. + Calling ``mark_app_valid_cancel_rollback`` is required on the first boot of a new + partition to avoid an automatic rollback at the next boot. + This uses the ESP-IDF "app rollback" feature with "CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE" + and an ``OSError(-261)`` is raised if called on firmware that doesn't have the + feature enabled. + It is OK to call ``mark_app_valid_cancel_rollback`` on every boot and it is not + necessary when booting firmare that was loaded using esptool. + +Constants +~~~~~~~~~ + +.. data:: Partition.BOOT + Partition.RUNNING + + Used in the `Partition` constructor to fetch various partitions: ``BOOT`` is the + partition that will be booted at the next reset and ``RUNNING`` is the currently + running partition. + +.. data:: Partition.TYPE_APP + Partition.TYPE_DATA + + Used in `Partition.find` to specify the partition type: ``APP`` is for bootable + firmware partitions (typically labelled ``factory``, ``ota_0``, ``ota_1``), and + ``DATA`` is for other partitions, e.g. ``nvs``, ``otadata``, ``phy_init``, ``vfs``. + +.. data:: HEAP_DATA + HEAP_EXEC + + Used in `idf_heap_info`. + +.. _esp32.RMT: + +RMT +--- + +The RMT (Remote Control) module, specific to the ESP32, was originally designed +to send and receive infrared remote control signals. However, due to a flexible +design and very accurate (as low as 12.5ns) pulse generation, it can also be +used to transmit or receive many other types of digital signals:: + + import esp32 + from machine import Pin + + r = esp32.RMT(0, pin=Pin(18), clock_div=8) + r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8) + # The channel resolution is 100ns (1/(source_freq/clock_div)). + r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns + +The input to the RMT module is an 80MHz clock (in the future it may be able to +configure the input clock but, for now, it's fixed). ``clock_div`` *divides* +the clock input which determines the resolution of the RMT channel. The +numbers specificed in ``write_pulses`` are multiplied by the resolution to +define the pulses. + +``clock_div`` is an 8-bit divider (0-255) and each pulse can be defined by +multiplying the resolution by a 15-bit (0-32,768) number. There are eight +channels (0-7) and each can have a different clock divider. + +So, in the example above, the 80MHz clock is divided by 8. Thus the +resolution is (1/(80Mhz/8)) 100ns. Since the ``start`` level is 0 and toggles +with each number, the bitstream is ``0101`` with durations of [100ns, 2000ns, +100ns, 4000ns]. + +For more details see Espressif's `ESP-IDF RMT documentation. +`_. + +.. Warning:: + The current MicroPython RMT implementation lacks some features, most notably + receiving pulses and carrier transmit. RMT should be considered a + *beta feature* and the interface may change in the future. + + +.. class:: RMT(channel, \*, pin=None, clock_div=8) + + This class provides access to one of the eight RMT channels. *channel* is + required and identifies which RMT channel (0-7) will be configured. *pin*, + also required, configures which Pin is bound to the RMT channel. *clock_div* + is an 8-bit clock divider that divides the source clock (80MHz) to the RMT + channel allowing the resolution to be specified. + +.. method:: RMT.source_freq() + + Returns the source clock frequency. Currently the source clock is not + configurable so this will always return 80MHz. + +.. method:: RMT.clock_div() + + Return the clock divider. Note that the channel resolution is + ``1 / (source_freq / clock_div)``. + +.. method:: RMT.wait_done(timeout=0) + + Returns True if `RMT.write_pulses` has completed. + + If *timeout* (defined in ticks of ``source_freq / clock_div``) is specified + the method will wait for *timeout* or until `RMT.write_pulses` is complete, + returning ``False`` if the channel continues to transmit. + +.. Warning:: + Avoid using ``wait_done()`` if looping is enabled. + +.. method:: RMT.loop(enable_loop) + + Configure looping on the channel, allowing a stream of pulses to be + indefinitely repeated. *enable_loop* is bool, set to True to enable looping. + +.. method:: RMT.write_pulses(pulses, start) + + Begin sending *pulses*, a list or tuple defining the stream of pulses. The + length of each pulse is defined by a number to be multiplied by the channel + resolution ``(1 / (source_freq / clock_div))``. *start* defines whether the + stream starts at 0 or 1. + -The Ultra-Low-Power co-processor --------------------------------- +Ultra-Low-Power co-processor +---------------------------- .. class:: ULP() diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index ed4b78ab14625..0073ba708d8a3 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -1,4 +1,4 @@ -:mod:`framebuf` --- Frame buffer manipulation +:mod:`framebuf` --- frame buffer manipulation ============================================= .. module:: framebuf @@ -19,7 +19,7 @@ For example:: import framebuf # FrameBuffer needs 2 bytes for every RGB565 pixel - fbuf = FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565) + fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565) fbuf.fill(0) fbuf.text('MicroPython!', 0, 0, 0xffff) @@ -28,7 +28,7 @@ For example:: Constructors ------------ -.. class:: FrameBuffer(buffer, width, height, format, stride=width) +.. class:: FrameBuffer(buffer, width, height, format, stride=width, /) Construct a FrameBuffer object. The parameters are: @@ -130,7 +130,7 @@ Constants Monochrome (1-bit) color format This defines a mapping where the bits in a byte are horizontally mapped. - Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. + Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. Subsequent bytes appear at successive horizontal locations until the rightmost edge is reached. Further bytes are rendered on the next row, one pixel lower. @@ -139,7 +139,7 @@ Constants Monochrome (1-bit) color format This defines a mapping where the bits in a byte are horizontally mapped. - Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. + Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. Subsequent bytes appear at successive horizontal locations until the rightmost edge is reached. Further bytes are rendered on the next row, one pixel lower. diff --git a/docs/library/index.rst b/docs/library/index.rst index b464e85fa2f73..7b1636ce61b33 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -74,11 +74,12 @@ it will fallback to loading the built-in ``ujson`` module. :maxdepth: 1 builtins.rst - array.rst cmath.rst gc.rst math.rst sys.rst + uarray.rst + uasyncio.rst ubinascii.rst ucollections.rst uerrno.rst @@ -111,10 +112,24 @@ the following libraries. machine.rst micropython.rst network.rst + ubluetooth.rst ucryptolib.rst uctypes.rst +Port-specific libraries +----------------------- + +In some cases the following port/board-specific libraries have functions or +classes similar to those in the :mod:`machine` library. Where this occurs, the +entry in the port specific library exposes hardware functionality unique to +that platform. + +To write portable code use functions and classes from the :mod:`machine` module. +To access platform-specific hardware use the appropriate library, e.g. +:mod:`pyb` in the case of the Pyboard. + + Libraries specific to the pyboard --------------------------------- @@ -136,6 +151,7 @@ The following libraries and classes are specific to the WiPy. :maxdepth: 2 wipy.rst + machine.ADCWiPy.rst machine.TimerWiPy.rst diff --git a/docs/library/lcd160cr.rst b/docs/library/lcd160cr.rst index bb8e6da22ce5e..e31ed94651ca5 100644 --- a/docs/library/lcd160cr.rst +++ b/docs/library/lcd160cr.rst @@ -340,7 +340,7 @@ Advanced commands .. method:: LCD160CR.set_scroll_win_param(win, param, value) Set a single parameter of a scrolling window region: - + - *win* is the window id, 0..8. - *param* is the parameter number to configure, 0..7, and corresponds to the parameters in the `set_scroll_win` method. diff --git a/docs/library/machine.ADC.rst b/docs/library/machine.ADC.rst index 4c7a04d74f07f..1404b454ae7f5 100644 --- a/docs/library/machine.ADC.rst +++ b/docs/library/machine.ADC.rst @@ -4,71 +4,32 @@ class ADC -- analog to digital conversion ========================================= -Usage:: +The ADC class provides an interface to analog-to-digital convertors, and +represents a single endpoint that can sample a continuous voltage and +convert it to a discretised value. + +Example usage:: import machine - adc = machine.ADC() # create an ADC object - apin = adc.channel(pin='GP3') # create an analog pin on GP3 - val = apin() # read an analog value + adc = machine.ADC(pin) # create an ADC object acting on a pin + val = adc.read_u16() # read a raw analog value in the range 0-65535 Constructors ------------ -.. class:: ADC(id=0, \*, bits=12) - - Create an ADC object associated with the given pin. - This allows you to then read analog values on that pin. - For more info check the `pinout and alternate functions - table. `_ - - .. warning:: +.. class:: ADC(id) - ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it - can withstand). When GP2, GP3, GP4 or GP5 are remapped to the - ADC block, 1.8 V is the maximum. If these pins are used in digital mode, - then the maximum allowed input is 3.6V. + Access the ADC associated with a source identified by *id*. This + *id* may be an integer (usually specifying a channel number), a + :ref:`Pin ` object, or other value supported by the + underlying machine. Methods ------- -.. method:: ADC.channel(id, \*, pin) - - Create an analog pin. If only channel ID is given, the correct pin will - be selected. Alternatively, only the pin can be passed and the correct - channel will be selected. Examples:: - - # all of these are equivalent and enable ADC channel 1 on GP3 - apin = adc.channel(1) - apin = adc.channel(pin='GP3') - apin = adc.channel(id=1, pin='GP3') - -.. method:: ADC.init() - - Enable the ADC block. - -.. method:: ADC.deinit() - - Disable the ADC block. - -class ADCChannel --- read analog values from internal or external sources -========================================================================= - -ADC channels can be connected to internal points of the MCU or to GPIO pins. -ADC channels are created using the ADC.channel method. - -.. method:: adcchannel() - - Fast method to read the channel value. - -.. method:: adcchannel.value() - - Read the channel value. - -.. method:: adcchannel.init() - - Re-init (and effectively enable) the ADC channel. - -.. method:: adcchannel.deinit() +.. method:: ADC.read_u16() - Disable the ADC channel. + Take an analog reading and return an integer in the range 0-65535. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 65535. diff --git a/docs/library/machine.ADCWiPy.rst b/docs/library/machine.ADCWiPy.rst new file mode 100644 index 0000000000000..4a4f0524c8f0b --- /dev/null +++ b/docs/library/machine.ADCWiPy.rst @@ -0,0 +1,81 @@ +.. currentmodule:: machine +.. _machine.ADCWiPy: + +class ADCWiPy -- analog to digital conversion +============================================= + +.. note:: + + This class is a non-standard ADC implementation for the WiPy. + It is available simply as ``machine.ADC`` on the WiPy but is named in the + documentation below as ``machine.ADCWiPy`` to distinguish it from the + more general :ref:`machine.ADC ` class. + +Usage:: + + import machine + + adc = machine.ADC() # create an ADC object + apin = adc.channel(pin='GP3') # create an analog pin on GP3 + val = apin() # read an analog value + +Constructors +------------ + +.. class:: ADCWiPy(id=0, \*, bits=12) + + Create an ADC object associated with the given pin. + This allows you to then read analog values on that pin. + For more info check the `pinout and alternate functions + table. `_ + + .. warning:: + + ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it + can withstand). When GP2, GP3, GP4 or GP5 are remapped to the + ADC block, 1.8 V is the maximum. If these pins are used in digital mode, + then the maximum allowed input is 3.6V. + +Methods +------- + +.. method:: ADCWiPy.channel(id, \*, pin) + + Create an analog pin. If only channel ID is given, the correct pin will + be selected. Alternatively, only the pin can be passed and the correct + channel will be selected. Examples:: + + # all of these are equivalent and enable ADC channel 1 on GP3 + apin = adc.channel(1) + apin = adc.channel(pin='GP3') + apin = adc.channel(id=1, pin='GP3') + +.. method:: ADCWiPy.init() + + Enable the ADC block. + +.. method:: ADCWiPy.deinit() + + Disable the ADC block. + +class ADCChannel --- read analog values from internal or external sources +========================================================================= + +ADC channels can be connected to internal points of the MCU or to GPIO pins. +ADC channels are created using the ADC.channel method. + +.. method:: adcchannel() + + Fast method to read the channel value. + +.. method:: adcchannel.value() + + Read the channel value. + +.. method:: adcchannel.init() + + Re-init (and effectively enable) the ADC channel. + +.. method:: adcchannel.deinit() + + Disable the ADC channel. diff --git a/docs/library/machine.I2C.rst b/docs/library/machine.I2C.rst index 71ca9b0d3b2c8..2cbfec1ba83bf 100644 --- a/docs/library/machine.I2C.rst +++ b/docs/library/machine.I2C.rst @@ -89,7 +89,7 @@ These methods are available on software I2C only. Generate a STOP condition on the bus (SDA transitions to high while SCL is high). -.. method:: I2C.readinto(buf, nack=True) +.. method:: I2C.readinto(buf, nack=True, /) Reads bytes from the bus and stores them into *buf*. The number of bytes read is the length of *buf*. An ACK will be sent on the bus after @@ -109,13 +109,13 @@ Standard bus operations The following methods implement the standard I2C master read and write operations that target a given slave device. -.. method:: I2C.readfrom(addr, nbytes, stop=True) +.. method:: I2C.readfrom(addr, nbytes, stop=True, /) Read *nbytes* from the slave specified by *addr*. If *stop* is true then a STOP condition is generated at the end of the transfer. Returns a `bytes` object with the data read. -.. method:: I2C.readfrom_into(addr, buf, stop=True) +.. method:: I2C.readfrom_into(addr, buf, stop=True, /) Read into *buf* from the slave specified by *addr*. The number of bytes read will be the length of *buf*. @@ -123,7 +123,7 @@ operations that target a given slave device. The method returns ``None``. -.. method:: I2C.writeto(addr, buf, stop=True) +.. method:: I2C.writeto(addr, buf, stop=True, /) Write the bytes from *buf* to the slave specified by *addr*. If a NACK is received following the write of a byte from *buf* then the @@ -131,6 +131,20 @@ operations that target a given slave device. generated at the end of the transfer, even if a NACK is received. The function returns the number of ACKs that were received. +.. method:: I2C.writevto(addr, vector, stop=True, /) + + Write the bytes contained in *vector* to the slave specified by *addr*. + *vector* should be a tuple or list of objects with the buffer protocol. + The *addr* is sent once and then the bytes from each object in *vector* + are written out sequentially. The objects in *vector* may be zero bytes + in length in which case they don't contribute to the output. + + If a NACK is received following the write of a byte from one of the + objects in *vector* then the remaining bytes, and any remaining objects, + are not sent. If *stop* is true then a STOP condition is generated at + the end of the transfer, even if a NACK is received. The function + returns the number of ACKs that were received. + Memory operations ----------------- diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index 5254e163c02a3..3055491ebbba8 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -216,6 +216,7 @@ Methods - ``hard`` if true a hardware interrupt is used. This reduces the delay between the pin change and the handler being called. Hard interrupt handlers may not allocate memory; see :ref:`isr_rules`. + Not all ports support this argument. This method returns a callback object. diff --git a/docs/library/machine.RTC.rst b/docs/library/machine.RTC.rst index 95fa2b4ce6094..548ad007e0dc3 100644 --- a/docs/library/machine.RTC.rst +++ b/docs/library/machine.RTC.rst @@ -27,7 +27,7 @@ Methods .. method:: RTC.init(datetime) Initialise the RTC. Datetime is a tuple of the form: - + ``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])`` .. method:: RTC.now() diff --git a/docs/library/machine.SD.rst b/docs/library/machine.SD.rst index 9c58e73545edd..d985db231aa44 100644 --- a/docs/library/machine.SD.rst +++ b/docs/library/machine.SD.rst @@ -1,8 +1,8 @@ .. currentmodule:: machine .. _machine.SD: -class SD -- secure digital memory card -====================================== +class SD -- secure digital memory card (cc3200 port only) +========================================================= .. warning:: diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst new file mode 100644 index 0000000000000..b1cf42ec0285b --- /dev/null +++ b/docs/library/machine.SDCard.rst @@ -0,0 +1,124 @@ +.. currentmodule:: machine +.. _machine.SDCard: + +class SDCard -- secure digital memory card +========================================== + +SD cards are one of the most common small form factor removable storage media. +SD cards come in a variety of sizes and physical form factors. MMC cards are +similar removable storage devices while eMMC devices are electrically similar +storage devices designed to be embedded into other systems. All three form +share a common protocol for communication with their host system and high-level +support looks the same for them all. As such in MicroPython they are implemented +in a single class called :class:`machine.SDCard` . + +Both SD and MMC interfaces support being accessed with a variety of bus widths. +When being accessed with a 1-bit wide interface they can be accessed using the +SPI protocol. Different MicroPython hardware platforms support different widths +and pin configurations but for most platforms there is a standard configuration +for any given hardware. In general constructing an ``SDCard`` object with without +passing any parameters will initialise the interface to the default card slot +for the current hardware. The arguments listed below represent the common +arguments that might need to be set in order to use either a non-standard slot +or a non-standard pin assignment. The exact subset of arguments supported will +vary from platform to platform. + +.. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None, freq=20000000) + + This class provides access to SD or MMC storage cards using either + a dedicated SD/MMC interface hardware or through an SPI channel. + The class implements the block protocol defined by :class:`uos.AbstractBlockDev`. + This allows the mounting of an SD card to be as simple as:: + + uos.mount(machine.SDCard(), "/sd") + + The constructor takes the following parameters: + + - *slot* selects which of the available interfaces to use. Leaving this + unset will select the default interface. + + - *width* selects the bus width for the SD/MMC interface. + + - *cd* can be used to specify a card-detect pin. + + - *wp* can be used to specify a write-protect pin. + + - *sck* can be used to specify an SPI clock pin. + + - *miso* can be used to specify an SPI miso pin. + + - *mosi* can be used to specify an SPI mosi pin. + + - *cs* can be used to specify an SPI chip select pin. + + - *freq* selects the SD/MMC interface frequency in Hz (only supported on the ESP32). + +Implementation-specific details +------------------------------- + +Different implementations of the ``SDCard`` class on different hardware support +varying subsets of the options above. + +PyBoard +``````` + +The standard PyBoard has just one slot. No arguments are necessary or supported. + +ESP32 +````` + +The ESP32 provides two channels of SD/MMC hardware and also supports +access to SD Cards through either of the two SPI ports that are +generally available to the user. As a result the *slot* argument can +take a value between 0 and 3, inclusive. Slots 0 and 1 use the +built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0 +supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit +access; the SPI slots only support 1-bit access. + + .. note:: Slot 0 is used to communicate with on-board flash memory + on most ESP32 modules and so will be unavailable to the + user. + + .. note:: Most ESP32 modules that provide an SD card slot using the + dedicated hardware only wire up 1 data pin, so the default + value for *width* is 1. + +The pins used by the dedicated SD/MMC hardware are fixed. The pins +used by the SPI hardware can be reassigned. + + .. note:: If any of the SPI signals are remapped then all of the SPI + signals will pass through a GPIO multiplexer unit which + can limit the performance of high frequency signals. Since + the normal operating speed for SD cards is 40MHz this can + cause problems on some cards. + +The default (and preferred) pin assignment are as follows: + + ====== ====== ====== ====== ====== + Slot 0 1 2 3 + ------ ------ ------ ------ ------ + Signal Pin Pin Pin Pin + ====== ====== ====== ====== ====== + sck 6 14 18 14 + cmd 11 15 + cs 5 15 + miso 19 12 + mosi 23 13 + D0 7 2 + D1 8 4 + D2 9 12 + D3 10 13 + D4 16 + D5 17 + D6 5 + D7 18 + ====== ====== ====== ====== ====== + +cc3200 +`````` + +You can set the pins used for SPI access by passing a tuple as the +*pins* argument. + +*Note:* The current cc3200 SD card implementation names the this class +:class:`machine.SD` rather than :class:`machine.SDCard` . diff --git a/docs/library/machine.TimerWiPy.rst b/docs/library/machine.TimerWiPy.rst index abbcc28ff7ce8..904a958c69b16 100644 --- a/docs/library/machine.TimerWiPy.rst +++ b/docs/library/machine.TimerWiPy.rst @@ -47,9 +47,9 @@ Methods tim.init(Timer.ONE_SHOT, width=32) # one shot 32-bit timer Keyword arguments: - + - ``mode`` can be one of: - + - ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured period of the channel expires. - ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured @@ -70,7 +70,7 @@ Methods object is returned (or ``None`` if there is no previous channel). Otherwise, a TimerChannel object is initialized and returned. - + The operating mode is is the one configured to the Timer object that was used to create the channel. diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index 5fcdc2758e0ff..70984dfb2fff1 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -58,6 +58,9 @@ Methods - *rx* specifies the RX pin to use. - *txbuf* specifies the length in characters of the TX buffer. - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. On the WiPy only the following keyword-only parameter is supported: @@ -87,7 +90,8 @@ Methods .. method:: UART.read([nbytes]) Read characters. If ``nbytes`` is specified then read at most that many bytes, - otherwise read as much data as possible. + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. Return value: a bytes object containing the bytes read in. Returns ``None`` on timeout. @@ -95,14 +99,16 @@ Methods .. method:: UART.readinto(buf[, nbytes]) Read bytes into the ``buf``. If ``nbytes`` is specified then read at most - that many bytes. Otherwise, read at most ``len(buf)`` bytes. + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. Return value: number of bytes read and stored into ``buf`` or ``None`` on timeout. .. method:: UART.readline() - Read a line, ending in a newline character. + Read a line, ending in a newline character. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. Return value: the line read or ``None`` on timeout. diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst index 5ca6dce45d576..612f23ba38620 100644 --- a/docs/library/machine.WDT.rst +++ b/docs/library/machine.WDT.rst @@ -15,16 +15,18 @@ Example usage:: wdt = WDT(timeout=2000) # enable it with a timeout of 2s wdt.feed() -Availability of this class: pyboard, WiPy. +Availability of this class: pyboard, WiPy, esp8266, esp32. Constructors ------------ .. class:: WDT(id=0, timeout=5000) - Create a WDT object and start it. The timeout must be given in seconds and - the minimum value that is accepted is 1 second. Once it is running the timeout - cannot be changed and the WDT cannot be stopped either. + Create a WDT object and start it. The timeout must be given in milliseconds. + Once it is running the timeout cannot be changed and the WDT cannot be stopped either. + + Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout + cannot be specified, it is determined by the underlying system. Methods ------- diff --git a/docs/library/machine.rst b/docs/library/machine.rst index a7b59577610be..b580353d6b564 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -27,6 +27,12 @@ Reset related functions Resets the device in a manner similar to pushing the external RESET button. +.. function:: soft_reset() + + Performs a soft reset of the interpreter, deleting all Python objects and + resetting the Python heap. It tries to retain the method by which the user + is connected to the MicroPython REPL (eg serial, USB, Wifi). + .. function:: reset_cause() Get the reset cause. See :ref:`constants ` for the possible return values. @@ -105,7 +111,7 @@ Miscellaneous functions varies by hardware (so use substring of a full value if you expect a short ID). In some MicroPython ports, ID corresponds to the network MAC address. -.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000) +.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000, /) Time a pulse on the given *pin*, and return the duration of the pulse in microseconds. The *pulse_level* argument should be 0 to time a low pulse @@ -168,3 +174,4 @@ Classes machine.Timer.rst machine.WDT.rst machine.SD.rst + machine.SDCard.rst diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index d9f913bffdad5..ded52deb0d268 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -82,17 +82,26 @@ Functions .. function:: heap_lock() .. function:: heap_unlock() +.. function:: heap_locked() Lock or unlock the heap. When locked no memory allocation can occur and a `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. These functions can be nested, ie `heap_lock()` can be called multiple times in a row and the lock-depth will increase, and then `heap_unlock()` must be called the same number of times to make the heap available again. + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + If the REPL becomes active with the heap locked then it will be forcefully unlocked. + Note: `heap_locked()` is not enabled on most ports by default, + requires `MICROPY_PY_MICROPYTHON_HEAP_LOCKED`. + .. function:: kbd_intr(chr) Set the character that will raise a `KeyboardInterrupt` exception. By @@ -136,5 +145,5 @@ Functions :ref:`reference documentation ` under "Creation of Python objects". - There is a finite stack to hold the scheduled functions and `schedule()` - will raise a `RuntimeError` if the stack is full. + There is a finite queue to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the queue is full. diff --git a/docs/library/network.rst b/docs/library/network.rst index 0c5659244c607..01e6f61369a40 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -68,7 +68,7 @@ parameter should be `id`. (password) required to access said service. There can be further arbitrary keyword-only parameters, depending on the networking medium type and/or particular device. Parameters can be used to: a) - specify alternative service identifer types; b) provide additional + specify alternative service identifier types; b) provide additional connection parameters. For various medium types, there are different sets of predefined/recommended parameters, among them: diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index a95f2d537c33f..1b16e0c2fcccb 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -19,7 +19,7 @@ Usage:: val = adc.read_core_vref() # read MCU VREF val = adc.read_vref() # read MCU supply voltage - + Constructors ------------ diff --git a/docs/library/pyb.Accel.rst b/docs/library/pyb.Accel.rst index 9ade5c5c81523..d5c0ca8634598 100644 --- a/docs/library/pyb.Accel.rst +++ b/docs/library/pyb.Accel.rst @@ -19,7 +19,7 @@ Constructors .. class:: pyb.Accel() Create and return an accelerometer object. - + Methods ------- diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 09b97a187c696..ba935abfd5c4e 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -92,7 +92,7 @@ Methods Force a software restart of the CAN controller without resetting its configuration. - + If the controller enters the bus-off state then it will no longer participate in bus activity. If the controller is not configured to automatically restart (see :meth:`~CAN.init()`) then this method can be used to trigger a restart, diff --git a/docs/library/pyb.DAC.rst b/docs/library/pyb.DAC.rst index c67603a710fc3..9a465b9ce25d8 100644 --- a/docs/library/pyb.DAC.rst +++ b/docs/library/pyb.DAC.rst @@ -93,9 +93,9 @@ Methods .. method:: DAC.triangle(freq) - Generate a triangle wave. The value on the DAC output changes at - the given frequency, and the frequency of the repeating triangle wave - itself is 2048 times smaller. + Generate a triangle wave. The value on the DAC output changes at the given + frequency and ramps through the full 12-bit range (up and down). Therefore + the frequency of the repeating triangle wave itself is 8192 times smaller. .. method:: DAC.write(value) diff --git a/docs/library/pyb.ExtInt.rst b/docs/library/pyb.ExtInt.rst index 814217cef0863..7741cc51e2381 100644 --- a/docs/library/pyb.ExtInt.rst +++ b/docs/library/pyb.ExtInt.rst @@ -54,7 +54,7 @@ Constructors .. class:: pyb.ExtInt(pin, mode, pull, callback) Create an ExtInt object: - + - ``pin`` is the pin on which to enable the interrupt (can be a pin object or any valid pin name). - ``mode`` can be one of: - ``ExtInt.IRQ_RISING`` - trigger on a rising edge; diff --git a/docs/library/pyb.Flash.rst b/docs/library/pyb.Flash.rst new file mode 100644 index 0000000000000..2d2f83da1c6ad --- /dev/null +++ b/docs/library/pyb.Flash.rst @@ -0,0 +1,52 @@ +.. currentmodule:: pyb +.. _pyb.Flash: + +class Flash -- access to built-in flash storage +=============================================== + +The Flash class allows direct access to the primary flash device on the pyboard. + +In most cases, to store persistent data on the device, you'll want to use a +higher-level abstraction, for example the filesystem via Python's standard file +API, but this interface is useful to :ref:`customise the filesystem +configuration ` or implement a low-level storage system for your +application. + +Constructors +------------ + +.. class:: pyb.Flash() + + Create and return a block device that represents the flash device presented + to the USB mass storage interface. + + It includes a virtual partition table at the start, and the actual flash + starts at block ``0x100``. + + This constructor is deprecated and will be removed in a future version of MicroPython. + +.. class:: pyb.Flash(\*, start=-1, len=-1) + + Create and return a block device that accesses the flash at the specified offset. The length defaults to the remaining size of the device. + + The *start* and *len* offsets are in bytes, and must be a multiple of the block size (typically 512 for internal flash). + +Methods +------- + +.. method:: Flash.readblocks(block_num, buf) +.. method:: Flash.readblocks(block_num, buf, offset) +.. method:: Flash.writeblocks(block_num, buf) +.. method:: Flash.writeblocks(block_num, buf, offset) +.. method:: Flash.ioctl(cmd, arg) + + These methods implement the simple and :ref:`extended + ` block protocol defined by + :class:`uos.AbstractBlockDev`. + +Hardware Note +------------- + +On boards with external spiflash (e.g. Pyboard D), the MicroPython firmware will +be configured to use that as the primary flash storage. On all other boards, the +internal flash inside the :term:`MCU` will be used. diff --git a/docs/library/pyb.LCD.rst b/docs/library/pyb.LCD.rst index 5ab127edcda0e..018902ca6896a 100644 --- a/docs/library/pyb.LCD.rst +++ b/docs/library/pyb.LCD.rst @@ -63,13 +63,13 @@ Methods .. method:: LCD.fill(colour) Fill the screen with the given colour (0 or 1 for white or black). - + This method writes to the hidden buffer. Use ``show()`` to show the buffer. .. method:: LCD.get(x, y) Get the pixel at the position ``(x, y)``. Returns 0 or 1. - + This method reads from the visible buffer. .. method:: LCD.light(value) @@ -79,7 +79,7 @@ Methods .. method:: LCD.pixel(x, y, colour) Set the pixel at ``(x, y)`` to the given colour (0 or 1). - + This method writes to the hidden buffer. Use ``show()`` to show the buffer. .. method:: LCD.show() @@ -89,7 +89,7 @@ Methods .. method:: LCD.text(str, x, y, colour) Draw the given text to the position ``(x, y)`` using the given colour (0 or 1). - + This method writes to the hidden buffer. Use ``show()`` to show the buffer. .. method:: LCD.write(str) diff --git a/docs/library/pyb.LED.rst b/docs/library/pyb.LED.rst index 1ab73a69c9aa0..d3ab965e7e7c8 100644 --- a/docs/library/pyb.LED.rst +++ b/docs/library/pyb.LED.rst @@ -13,7 +13,7 @@ Constructors .. class:: pyb.LED(id) Create an LED object associated with the given LED: - + - ``id`` is the LED number, 1-4. diff --git a/docs/library/pyb.RTC.rst b/docs/library/pyb.RTC.rst index 286268655e686..4c736597cf8db 100644 --- a/docs/library/pyb.RTC.rst +++ b/docs/library/pyb.RTC.rst @@ -28,13 +28,13 @@ Methods .. method:: RTC.datetime([datetimetuple]) Get or set the date and time of the RTC. - + With no arguments, this method returns an 8-tuple with the current date and time. With 1 argument (being an 8-tuple) it sets the date and time (and ``subseconds`` is reset to 255). - + The 8-tuple has the following format: - + (year, month, day, weekday, hours, minutes, seconds, subseconds) ``weekday`` is 1-7 for Monday through Sunday. diff --git a/docs/library/pyb.Timer.rst b/docs/library/pyb.Timer.rst index 977ba8890d7de..bb7e7e52d5648 100644 --- a/docs/library/pyb.Timer.rst +++ b/docs/library/pyb.Timer.rst @@ -112,7 +112,7 @@ Methods .. method:: Timer.deinit() Deinitialises the timer. - + Disables the callback (and the associated irq). Disables any channel callbacks (and the associated irq). @@ -191,7 +191,7 @@ Methods - Read the encoder value using the timer.counter() method. - Only works on CH1 and CH2 (and not on CH1N or CH2N) - The channel number is ignored when setting the encoder mode. - + PWM Example:: timer = pyb.Timer(2, freq=1000) diff --git a/docs/library/pyb.UART.rst b/docs/library/pyb.UART.rst index 4359f1d9d67c0..ab7ab2fb882a4 100644 --- a/docs/library/pyb.UART.rst +++ b/docs/library/pyb.UART.rst @@ -69,7 +69,7 @@ Constructors Methods ------- -.. method:: UART.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, flow=0, timeout_char=0, read_buf_len=64) +.. method:: UART.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=0, flow=0, timeout_char=0, read_buf_len=64) Initialise the UART bus with the given parameters: diff --git a/docs/library/pyb.USB_HID.rst b/docs/library/pyb.USB_HID.rst index 70270443548d9..649dc3df4a605 100644 --- a/docs/library/pyb.USB_HID.rst +++ b/docs/library/pyb.USB_HID.rst @@ -24,11 +24,11 @@ Methods .. method:: USB_HID.recv(data, \*, timeout=5000) Receive data on the bus: - + - ``data`` can be an integer, which is the number of bytes to receive, or a mutable buffer, which will be filled with received bytes. - ``timeout`` is the timeout in milliseconds to wait for the receive. - + Return value: if ``data`` is an integer then a new buffer of the bytes received, otherwise the number of bytes read into ``data`` is returned. diff --git a/docs/library/pyb.USB_VCP.rst b/docs/library/pyb.USB_VCP.rst index 3bc6c749ceddd..b16924cf60b2e 100644 --- a/docs/library/pyb.USB_VCP.rst +++ b/docs/library/pyb.USB_VCP.rst @@ -12,14 +12,21 @@ the connected host. Constructors ------------ -.. class:: pyb.USB_VCP() +.. class:: pyb.USB_VCP(id=0) - Create a new USB_VCP object. + Create a new USB_VCP object. The *id* argument specifies which USB VCP port to + use. Methods ------- +.. method:: USB_VCP.init(\*, flow=-1) + + Configure the USB VCP port. If the *flow* argument is not -1 then the value sets + the flow control, which can be a bitwise-or of ``USB_VCP.RTS`` and ``USB_VCP.CTS``. + RTS is used to control read behaviour and CTS, to control write behaviour. + .. method:: USB_VCP.setinterrupt(chr) Set the character which interrupts running Python code. This is set @@ -85,19 +92,28 @@ Methods .. method:: USB_VCP.recv(data, \*, timeout=5000) Receive data on the bus: - + - ``data`` can be an integer, which is the number of bytes to receive, or a mutable buffer, which will be filled with received bytes. - ``timeout`` is the timeout in milliseconds to wait for the receive. - + Return value: if ``data`` is an integer then a new buffer of the bytes received, otherwise the number of bytes read into ``data`` is returned. .. method:: USB_VCP.send(data, \*, timeout=5000) Send data over the USB VCP: - + - ``data`` is the data to send (an integer to send, or a buffer object). - ``timeout`` is the timeout in milliseconds to wait for the send. - + Return value: number of bytes sent. + + +Constants +--------- + +.. data:: USB_VCP.RTS + USB_VCP.CTS + + to select the flow control type. diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 1e1e9ffaab58f..34103195ddd1c 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -20,7 +20,7 @@ Time related functions .. function:: millis() Returns the number of milliseconds since the board was last reset. - + The result is always a MicroPython smallint (31-bit signed number), so after 2^30 milliseconds (about 12.4 days) this will start to return negative numbers. @@ -32,7 +32,7 @@ Time related functions .. function:: micros() Returns the number of microseconds since the board was last reset. - + The result is always a MicroPython smallint (31-bit signed number), so after 2^30 microseconds (about 17.8 minutes) this will start to return negative numbers. @@ -44,10 +44,10 @@ Time related functions .. function:: elapsed_millis(start) Returns the number of milliseconds which have elapsed since ``start``. - + This function takes care of counter wrap, and always returns a positive number. This means it can be used to measure periods up to about 12.4 days. - + Example:: start = pyb.millis() @@ -57,10 +57,10 @@ Time related functions .. function:: elapsed_micros(start) Returns the number of microseconds which have elapsed since ``start``. - + This function takes care of counter wrap, and always returns a positive number. This means it can be used to measure periods up to about 17.8 minutes. - + Example:: start = pyb.micros() @@ -259,34 +259,45 @@ Miscellaneous functions Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU. -.. function:: usb_mode([modestr], vid=0xf055, pid=0x9801, hid=pyb.hid_mouse) +.. function:: usb_mode([modestr], port=-1, vid=0xf055, pid=-1, msc=(), hid=pyb.hid_mouse, high_speed=False) If called with no arguments, return the current USB mode as a string. - If called with ``modestr`` provided, attempts to set USB mode. - This can only be done when called from ``boot.py`` before - :meth:`pyb.main()` has been called. The following values of - ``modestr`` are understood: + If called with *modestr* provided, attempts to configure the USB mode. + The following values of *modestr* are understood: - ``None``: disables USB - ``'VCP'``: enable with VCP (Virtual COM Port) interface - ``'MSC'``: enable with MSC (mass storage device class) interface - ``'VCP+MSC'``: enable with VCP and MSC - ``'VCP+HID'``: enable with VCP and HID (human interface device) + - ``'VCP+MSC+HID'``: enabled with VCP, MSC and HID (only available on PYBD boards) For backwards compatibility, ``'CDC'`` is understood to mean ``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``). - The ``vid`` and ``pid`` parameters allow you to specify the VID - (vendor id) and PID (product id). + The *port* parameter should be an integer (0, 1, ...) and selects which + USB port to use if the board supports multiple ports. A value of -1 uses + the default or automatically selected port. + + The *vid* and *pid* parameters allow you to specify the VID (vendor id) + and PID (product id). A *pid* value of -1 will select a PID based on the + value of *modestr*. + + If enabling MSC mode, the *msc* parameter can be used to specify a list + of SCSI LUNs to expose on the mass storage interface. For example + ``msc=(pyb.Flash(), pyb.SDCard())``. If enabling HID mode, you may also specify the HID details by - passing the ``hid`` keyword parameter. It takes a tuple of + passing the *hid* keyword parameter. It takes a tuple of (subclass, protocol, max packet length, polling interval, report descriptor). By default it will set appropriate values for a USB mouse. There is also a ``pyb.hid_keyboard`` constant, which is an appropriate tuple for a USB keyboard. + The *high_speed* parameter, when set to ``True``, enables USB HS mode if + it is supported by the hardware. + Classes ------- @@ -298,6 +309,7 @@ Classes pyb.CAN.rst pyb.DAC.rst pyb.ExtInt.rst + pyb.Flash.rst pyb.I2C.rst pyb.LCD.rst pyb.LED.rst diff --git a/docs/library/sys.rst b/docs/library/sys.rst index f2d96cb8cc85d..24f9e353bb006 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -9,13 +9,26 @@ Functions --------- -.. function:: exit(retval=0) +.. function:: exit(retval=0, /) Terminate current program with a given exit code. Underlyingly, this function raise as `SystemExit` exception. If an argument is given, its value given as an argument to `SystemExit`. -.. function:: print_exception(exc, file=sys.stdout) +.. function:: atexit(func) + + Register *func* to be called upon termination. *func* must be a callable + that takes no arguments, or ``None`` to disable the call. The ``atexit`` + function will return the previous value set by this function, which is + initially ``None``. + + .. admonition:: Difference to CPython + :class: attention + + This function is a MicroPython extension intended to provide similar + functionality to the :mod:`atexit` module in CPython. + +.. function:: print_exception(exc, file=sys.stdout, /) Print exception with a traceback to a file-like object *file* (or `sys.stdout` by default). @@ -121,3 +134,9 @@ Constants .. data:: version_info Python language version that this implementation conforms to, as a tuple of ints. + + .. admonition:: Difference to CPython + :class: attention + + Only the first three version numbers (major, minor, micro) are supported and + they can be referenced only by index, not by name. diff --git a/docs/library/array.rst b/docs/library/uarray.rst similarity index 82% rename from docs/library/array.rst rename to docs/library/uarray.rst index f837b034369b6..9fa82ff31b5c9 100644 --- a/docs/library/array.rst +++ b/docs/library/uarray.rst @@ -1,7 +1,7 @@ -:mod:`array` -- arrays of numeric data -====================================== +:mod:`uarray` -- arrays of numeric data +======================================= -.. module:: array +.. module:: uarray :synopsis: efficient arrays of numeric data |see_cpython_module| :mod:`python:array`. @@ -13,7 +13,7 @@ floating-point support). Classes ------- -.. class:: array.array(typecode, [iterable]) +.. class:: array(typecode, [iterable]) Create array with elements of given type. Initial contents of the array are given by *iterable*. If it is not provided, an empty diff --git a/docs/library/uasyncio.rst b/docs/library/uasyncio.rst new file mode 100644 index 0000000000000..0f363a076ea3b --- /dev/null +++ b/docs/library/uasyncio.rst @@ -0,0 +1,297 @@ +:mod:`uasyncio` --- asynchronous I/O scheduler +============================================== + +.. module:: uasyncio + :synopsis: asynchronous I/O scheduler for writing concurrent code + +|see_cpython_module| +`asyncio `_ + +Example:: + + import uasyncio + + async def blink(led, period_ms): + while True: + led.on() + await uasyncio.sleep_ms(5) + led.off() + await uasyncio.sleep_ms(period_ms) + + async def main(led1, led2): + uasyncio.create_task(blink(led1, 700)) + uasyncio.create_task(blink(led2, 400)) + await uasyncio.sleep_ms(10_000) + + # Running on a pyboard + from pyb import LED + uasyncio.run(main(LED(1), LED(2))) + + # Running on a generic board + from machine import Pin + uasyncio.run(main(Pin(1), Pin(2))) + +Core functions +-------------- + +.. function:: create_task(coro) + + Create a new task from the given coroutine and schedule it to run. + + Returns the corresponding `Task` object. + +.. function:: run(coro) + + Create a new task from the given coroutine and run it until it completes. + + Returns the value returned by *coro*. + +.. function:: sleep(t) + + Sleep for *t* seconds (can be a float). + + This is a coroutine. + +.. function:: sleep_ms(t) + + Sleep for *t* milliseconds. + + This is a coroutine, and a MicroPython extension. + +Additional functions +-------------------- + +.. function:: wait_for(awaitable, timeout) + + Wait for the *awaitable* to complete, but cancel it if it takes longer + that *timeout* seconds. If *awaitable* is not a task then a task will be + created from it. + + If a timeout occurs, it cancels the task and raises ``asyncio.TimeoutError``: + this should be trapped by the caller. + + Returns the return value of *awaitable*. + + This is a coroutine. + +.. function:: gather(\*awaitables, return_exceptions=False) + + Run all *awaitables* concurrently. Any *awaitables* that are not tasks are + promoted to tasks. + + Returns a list of return values of all *awaitables*. + + This is a coroutine. + +class Task +---------- + +.. class:: Task() + + This object wraps a coroutine into a running task. Tasks can be waited on + using ``await task``, which will wait for the task to complete and return + the return value of the task. + + Tasks should not be created directly, rather use `create_task` to create them. + +.. method:: Task.cancel() + + Cancel the task by injecting a ``CancelledError`` into it. The task may + or may not ignore this exception. + +class Event +----------- + +.. class:: Event() + + Create a new event which can be used to synchronise tasks. Events start + in the cleared state. + +.. method:: Event.is_set() + + Returns ``True`` if the event is set, ``False`` otherwise. + +.. method:: Event.set() + + Set the event. Any tasks waiting on the event will be scheduled to run. + +.. method:: Event.clear() + + Clear the event. + +.. method:: Event.wait() + + Wait for the event to be set. If the event is already set then it returns + immediately. + + This is a coroutine. + +class Lock +---------- + +.. class:: Lock() + + Create a new lock which can be used to coordinate tasks. Locks start in + the unlocked state. + + In addition to the methods below, locks can be used in an ``async with`` statement. + +.. method:: Lock.locked() + + Returns ``True`` if the lock is locked, otherwise ``False``. + +.. method:: Lock.acquire() + + Wait for the lock to be in the unlocked state and then lock it in an atomic + way. Only one task can acquire the lock at any one time. + + This is a coroutine. + +.. method:: Lock.release() + + Release the lock. If any tasks are waiting on the lock then the next one in the + queue is scheduled to run and the lock remains locked. Otherwise, no tasks are + waiting an the lock becomes unlocked. + +TCP stream connections +---------------------- + +.. function:: open_connection(host, port) + + Open a TCP connection to the given *host* and *port*. The *host* address will be + resolved using `socket.getaddrinfo`, which is currently a blocking call. + + Returns a pair of streams: a reader and a writer stream. + Will raise a socket-specific ``OSError`` if the host could not be resolved or if + the connection could not be made. + + This is a coroutine. + +.. function:: start_server(callback, host, port, backlog=5) + + Start a TCP server on the given *host* and *port*. The *callback* will be + called with incoming, accepted connections, and be passed 2 arguments: reader + and writer streams for the connection. + + Returns a `Server` object. + + This is a coroutine. + +.. class:: Stream() + + This represents a TCP stream connection. To minimise code this class implements + both a reader and a writer, and both ``StreamReader`` and ``StreamWriter`` alias to + this class. + +.. method:: Stream.get_extra_info(v) + + Get extra information about the stream, given by *v*. The valid values for *v* are: + ``peername``. + +.. method:: Stream.close() + + Close the stream. + +.. method:: Stream.wait_closed() + + Wait for the stream to close. + + This is a coroutine. + +.. method:: Stream.read(n) + + Read up to *n* bytes and return them. + + This is a coroutine. + +.. method:: Stream.readline() + + Read a line and return it. + + This is a coroutine. + +.. method:: Stream.write(buf) + + Accumulated *buf* to the output buffer. The data is only flushed when + `Stream.drain` is called. It is recommended to call `Stream.drain` immediately + after calling this function. + +.. method:: Stream.drain() + + Drain (write) all buffered output data out to the stream. + + This is a coroutine. + +.. class:: Server() + + This represents the server class returned from `start_server`. It can be used + in an ``async with`` statement to close the server upon exit. + +.. method:: Server.close() + + Close the server. + +.. method:: Server.wait_closed() + + Wait for the server to close. + + This is a coroutine. + +Event Loop +---------- + +.. function:: get_event_loop() + + Return the event loop used to schedule and run tasks. See `Loop`. + +.. function:: new_event_loop() + + Reset the event loop and return it. + + Note: since MicroPython only has a single event loop this function just + resets the loop's state, it does not create a new one. + +.. class:: Loop() + + This represents the object which schedules and runs tasks. It cannot be + created, use `get_event_loop` instead. + +.. method:: Loop.create_task(coro) + + Create a task from the given *coro* and return the new `Task` object. + +.. method:: Loop.run_forever() + + Run the event loop until `stop()` is called. + +.. method:: Loop.run_until_complete(awaitable) + + Run the given *awaitable* until it completes. If *awaitable* is not a task + then it will be promoted to one. + +.. method:: Loop.stop() + + Stop the event loop. + +.. method:: Loop.close() + + Close the event loop. + +.. method:: Loop.set_exception_handler(handler) + + Set the exception handler to call when a Task raises an exception that is not + caught. The *handler* should accept two arguments: ``(loop, context)``. + +.. method:: Loop.get_exception_handler() + + Get the current exception handler. Returns the handler, or ``None`` if no + custom handler is set. + +.. method:: Loop.default_exception_handler(context) + + The default exception handler that is called. + +.. method:: Loop.call_exception_handler(context) + + Call the current exception handler. The argument *context* is passed through and + is a dictionary containing keys: ``'message'``, ``'exception'``, ``'future'``. diff --git a/docs/library/ubluetooth.rst b/docs/library/ubluetooth.rst new file mode 100644 index 0000000000000..fd2efe87d913f --- /dev/null +++ b/docs/library/ubluetooth.rst @@ -0,0 +1,385 @@ +:mod:`ubluetooth` --- low-level Bluetooth +========================================= + +.. module:: ubluetooth + :synopsis: Low-level Bluetooth radio functionality + +This module provides an interface to a Bluetooth controller on a board. +Currently this supports Bluetooth Low Energy (BLE) in Central, Peripheral, +Broadcaster, and Observer roles, and a device may operate in multiple +roles concurrently. + +This API is intended to match the low-level Bluetooth protocol and provide +building-blocks for higher-level abstractions such as specific device types. + +.. note:: This module is still under development and its classes, functions, + methods and constants are subject to change. + +class BLE +--------- + +Constructor +----------- + +.. class:: BLE() + + Returns the singleton BLE object. + +Configuration +------------- + +.. method:: BLE.active([active]) + + Optionally changes the active state of the BLE radio, and returns the + current state. + + The radio must be made active before using any other methods on this class. + +.. method:: BLE.config('param') + BLE.config(param=value, ...) + + Get or set configuration values of the BLE interface. To get a value the + parameter name should be quoted as a string, and just one parameter is + queried at a time. To set values use the keyword syntax, and one ore more + parameter can be set at a time. + + Currently supported values are: + + - ``'mac'``: Returns the device MAC address. If a device has a fixed address + (e.g. PYBD) then it will be returned. Otherwise (e.g. ESP32) a random + address will be generated when the BLE interface is made active. + Note: on some ports, accessing this value requires that the interface is + active (so that the MAC address can be queried from the controller). + + - ``'gap_name'``: Get/set the GAP device name used by service 0x1800, + characteristic 0x2a00. This can be set at any time and changed multiple + times. + + - ``'rxbuf'``: Get/set the size in bytes of the internal buffer used to store + incoming events. This buffer is global to the entire BLE driver and so + handles incoming data for all events, including all characteristics. + Increasing this allows better handling of bursty incoming data (for + example scan results) and the ability for a central role to receive + larger characteristic values. + +Event Handling +-------------- + +.. method:: BLE.irq(handler, trigger=0xffff) + + Registers a callback for events from the BLE stack. The *handler* takes two + arguments, ``event`` (which will be one of the codes below) and ``data`` + (which is an event-specific tuple of values). + + The optional *trigger* parameter allows you to set a mask of events that + your program is interested in. The default is all events. + + Note: the ``addr``, ``adv_data``, ``char_data``, ``notify_data``, and + ``uuid`` entries in the tuples are + references to data managed by the :mod:`ubluetooth` module (i.e. the same + instance will be re-used across multiple calls to the event handler). If + your program wants to use this data outside of the handler, then it must + copy them first, e.g. by using ``bytes(addr)`` or ``bluetooth.UUID(uuid)``. + + An event handler showing all possible events:: + + def bt_irq(event, data): + if event == _IRQ_CENTRAL_CONNECT: + # A central has connected to this peripheral. + conn_handle, addr_type, addr = data + elif event == _IRQ_CENTRAL_DISCONNECT: + # A central has disconnected from this peripheral. + conn_handle, addr_type, addr = data + elif event == _IRQ_GATTS_WRITE: + # A central has written to this characteristic or descriptor. + conn_handle, attr_handle = data + elif event == _IRQ_GATTS_READ_REQUEST: + # A central has issued a read. Note: this is a hard IRQ. + # Return None to deny the read. + # Note: This event is not supported on ESP32. + conn_handle, attr_handle = data + elif event == _IRQ_SCAN_RESULT: + # A single scan result. + addr_type, addr, adv_type, rssi, adv_data = data + elif event == _IRQ_SCAN_COMPLETE: + # Scan duration finished or manually stopped. + pass + elif event == _IRQ_PERIPHERAL_CONNECT: + # A successful gap_connect(). + conn_handle, addr_type, addr = data + elif event == _IRQ_PERIPHERAL_DISCONNECT: + # Connected peripheral has disconnected. + conn_handle, addr_type, addr = data + elif event == _IRQ_GATTC_SERVICE_RESULT: + # Called for each service found by gattc_discover_services(). + conn_handle, start_handle, end_handle, uuid = data + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + # Called for each characteristic found by gattc_discover_services(). + conn_handle, def_handle, value_handle, properties, uuid = data + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + # Called for each descriptor found by gattc_discover_descriptors(). + conn_handle, dsc_handle, uuid = data + elif event == _IRQ_GATTC_READ_RESULT: + # A gattc_read() has completed. + conn_handle, value_handle, char_data = data + elif event == _IRQ_GATTC_WRITE_STATUS: + # A gattc_write() has completed. + conn_handle, value_handle, status = data + elif event == _IRQ_GATTC_NOTIFY: + # A peripheral has sent a notify request. + conn_handle, value_handle, notify_data = data + elif event == _IRQ_GATTC_INDICATE: + # A peripheral has sent an indicate request. + conn_handle, value_handle, notify_data = data + +The event codes are:: + + from micropython import const + _IRQ_CENTRAL_CONNECT = const(1 << 0) + _IRQ_CENTRAL_DISCONNECT = const(1 << 1) + _IRQ_GATTS_WRITE = const(1 << 2) + _IRQ_GATTS_READ_REQUEST = const(1 << 3) + _IRQ_SCAN_RESULT = const(1 << 4) + _IRQ_SCAN_COMPLETE = const(1 << 5) + _IRQ_PERIPHERAL_CONNECT = const(1 << 6) + _IRQ_PERIPHERAL_DISCONNECT = const(1 << 7) + _IRQ_GATTC_SERVICE_RESULT = const(1 << 8) + _IRQ_GATTC_CHARACTERISTIC_RESULT = const(1 << 9) + _IRQ_GATTC_DESCRIPTOR_RESULT = const(1 << 10) + _IRQ_GATTC_READ_RESULT = const(1 << 11) + _IRQ_GATTC_WRITE_STATUS = const(1 << 12) + _IRQ_GATTC_NOTIFY = const(1 << 13) + _IRQ_GATTC_INDICATE = const(1 << 14) + +In order to save space in the firmware, these constants are not included on the +:mod:`ubluetooth` module. Add the ones that you need from the list above to your +program. + + +Broadcaster Role (Advertiser) +----------------------------- + +.. method:: BLE.gap_advertise(interval_us, adv_data=None, resp_data=None, connectable=True) + + Starts advertising at the specified interval (in **micro**\ seconds). This + interval will be rounded down to the nearest 625us. To stop advertising, set + *interval_us* to ``None``. + + *adv_data* and *resp_data* can be any type that implements the buffer + protocol (e.g. ``bytes``, ``bytearray``, ``str``). *adv_data* is included + in all broadcasts, and *resp_data* is send in reply to an active scan. + + Note: if *adv_data* (or *resp_data*) is ``None``, then the data passed + to the previous call to ``gap_advertise`` will be re-used. This allows a + broadcaster to resume advertising with just ``gap_advertise(interval_us)``. + To clear the advertising payload pass an empty ``bytes``, i.e. ``b''``. + + +Observer Role (Scanner) +----------------------- + +.. method:: BLE.gap_scan(duration_ms, [interval_us], [window_us]) + + Run a scan operation lasting for the specified duration (in **milli**\ seconds). + + To scan indefinitely, set *duration_ms* to ``0``. + + To stop scanning, set *duration_ms* to ``None``. + + Use *interval_us* and *window_us* to optionally configure the duty cycle. + The scanner will run for *window_us* **micro**\ seconds every *interval_us* + **micro**\ seconds for a total of *duration_ms* **milli**\ seconds. The default + interval and window are 1.28 seconds and 11.25 milliseconds respectively + (background scanning). + + For each scan result the ``_IRQ_SCAN_RESULT`` event will be raised, with event + data ``(addr_type, addr, adv_type, rssi, adv_data)``. ``adv_type`` values correspond + to the Bluetooth Specification: + + * 0x00 - ADV_IND - connectable and scannable undirected advertising + * 0x01 - ADV_DIRECT_IND - connectable directed advertising + * 0x02 - ADV_SCAN_IND - scannable undirected advertising + * 0x03 - ADV_NONCONN_IND - non-connectable undirected advertising + * 0x04 - SCAN_RSP - scan response + + When scanning is stopped (either due to the duration finishing or when + explicitly stopped), the ``_IRQ_SCAN_COMPLETE`` event will be raised. + + +Peripheral Role (GATT Server) +----------------------------- + +A BLE peripheral has a set of registered services. Each service may contain +characteristics, which each have a value. Characteristics can also contain +descriptors, which themselves have values. + +These values are stored locally, and are accessed by their "value handle" which +is generated during service registration. They can also be read from or written +to by a remote central device. Additionally, a peripheral can "notify" a +characteristic to a connected central via a connection handle. + +Characteristics and descriptors have a default maximum size of 20 bytes. +Anything written to them by a central will be truncated to this length. However, +any local write will increase the maximum size, so if you want to allow larger +writes from a central to a given characteristic, use +:meth:`gatts_write` after registration. e.g. +``gatts_write(char_handle, bytes(100))``. + +.. method:: BLE.gatts_register_services(services_definition) + + Configures the peripheral with the specified services, replacing any + existing services. + + *services_definition* is a list of **services**, where each **service** is a + two-element tuple containing a UUID and a list of **characteristics**. + + Each **characteristic** is a two-or-three-element tuple containing a UUID, a + **flags** value, and optionally a list of *descriptors*. + + Each **descriptor** is a two-element tuple containing a UUID and a **flags** + value. + + The **flags** are a bitwise-OR combination of the + :data:`ubluetooth.FLAG_READ`, :data:`ubluetooth.FLAG_WRITE` and + :data:`ubluetooth.FLAG_NOTIFY` values defined below. + + The return value is a list (one element per service) of tuples (each element + is a value handle). Characteristics and descriptor handles are flattened + into the same tuple, in the order that they are defined. + + The following example registers two services (Heart Rate, and Nordic UART):: + + HR_UUID = bluetooth.UUID(0x180D) + HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) + HR_SERVICE = (HR_UUID, (HR_CHAR,),) + UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E') + UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) + UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,) + UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),) + SERVICES = (HR_SERVICE, UART_SERVICE,) + ( (hr,), (tx, rx,), ) = bt.gatts_register_services(SERVICES) + + The three value handles (``hr``, ``tx``, ``rx``) can be used with + :meth:`gatts_read `, :meth:`gatts_write `, + and :meth:`gatts_notify `. + + **Note:** Advertising must be stopped before registering services. + +.. method:: BLE.gatts_read(value_handle) + + Reads the local value for this handle (which has either been written by + :meth:`gatts_write ` or by a remote central). + +.. method:: BLE.gatts_write(value_handle, data) + + Writes the local value for this handle, which can be read by a central. + +.. method:: BLE.gatts_notify(conn_handle, value_handle, [data]) + + Notifies a connected central that this value has changed and that it should + issue a read of the current value from this peripheral. + + If *data* is specified, then the that value is sent to the central as part + of the notification, avoiding the need for a separate read request. Note + that this will not update the local value stored. + +.. method:: BLE.gatts_set_buffer(value_handle, len, append=False, /) + + Sets the internal buffer size for a value in bytes. This will limit the + largest possible write that can be received. The default is 20. + + Setting *append* to ``True`` will make all remote writes append to, rather + than replace, the current value. At most *len* bytes can be buffered in + this way. When you use :meth:`gatts_read `, the value will + be cleared after reading. This feature is useful when implementing something + like the Nordic UART Service. + + +Central Role (GATT Client) +-------------------------- + +.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, /) + + Connect to a peripheral. + + On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised. + +.. method:: BLE.gap_disconnect(conn_handle) + + Disconnect the specified connection handle. + + On success, the ``_IRQ_PERIPHERAL_DISCONNECT`` event will be raised. + + Returns ``False`` if the connection handle wasn't connected, and ``True`` + otherwise. + +.. method:: BLE.gattc_discover_services(conn_handle) + + Query a connected peripheral for its services. + + For each service discovered, the ``_IRQ_GATTC_SERVICE_RESULT`` event will be + raised. + +.. method:: BLE.gattc_discover_characteristics(conn_handle, start_handle, end_handle) + + Query a connected peripheral for characteristics in the specified range. + + For each characteristic discovered, the ``_IRQ_GATTC_CHARACTERISTIC_RESULT`` + event will be raised. + +.. method:: BLE.gattc_discover_descriptors(conn_handle, start_handle, end_handle) + + Query a connected peripheral for descriptors in the specified range. + + For each descriptor discovered, the ``_IRQ_GATTC_DESCRIPTOR_RESULT`` event + will be raised. + +.. method:: BLE.gattc_read(conn_handle, value_handle) + + Issue a remote read to a connected peripheral for the specified + characteristic or descriptor handle. + + On success, the ``_IRQ_GATTC_READ_RESULT`` event will be raised. + +.. method:: BLE.gattc_write(conn_handle, value_handle, data, mode=0, /) + + Issue a remote write to a connected peripheral for the specified + characteristic or descriptor handle. + + The argument *mode* specifies the write behaviour, with the currently + supported values being: + + * ``mode=0`` (default) is a write-without-response: the write will + be sent to the remote peripheral but no confirmation will be + returned, and no event will be raised. + * ``mode=1`` is a write-with-response: the remote peripheral is + requested to send a response/acknowledgement that it received the + data. + + If a response is received from the remote peripheral the + ``_IRQ_GATTC_WRITE_STATUS`` event will be raised. + + +class UUID +---------- + + +Constructor +----------- + +.. class:: UUID(value) + + Creates a UUID instance with the specified **value**. + + The **value** can be either: + + - A 16-bit integer. e.g. ``0x2908``. + - A 128-bit UUID string. e.g. ``'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'``. + + +Constants +--------- + +.. data:: ubluetooth.FLAG_READ + ubluetooth.FLAG_WRITE + ubluetooth.FLAG_NOTIFY diff --git a/docs/library/ucryptolib.rst b/docs/library/ucryptolib.rst index c9e0bb71f7ae0..79471c2e90ccc 100644 --- a/docs/library/ucryptolib.rst +++ b/docs/library/ucryptolib.rst @@ -22,9 +22,11 @@ Classes * *mode* is: * ``1`` (or ``ucryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). - * ``2`` (or ``ucryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC) + * ``2`` (or ``ucryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``ucryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. .. method:: encrypt(in_buf, [out_buf]) diff --git a/docs/library/uctypes.rst b/docs/library/uctypes.rst index dce8caecb6e09..0fdc40e4840b4 100644 --- a/docs/library/uctypes.rst +++ b/docs/library/uctypes.rst @@ -180,7 +180,7 @@ Following are encoding examples for various field types: Module contents --------------- -.. class:: struct(addr, descriptor, layout_type=NATIVE) +.. class:: struct(addr, descriptor, layout_type=NATIVE, /) Instantiate a "foreign data structure" object based on structure address in memory, descriptor (encoded as a dictionary), and layout type (see below). @@ -200,7 +200,7 @@ Module contents Layout type for a native structure - with data endianness and alignment conforming to the ABI of the system on which MicroPython runs. -.. function:: sizeof(struct, layout_type=NATIVE) +.. function:: sizeof(struct, layout_type=NATIVE, /) Return size of data structure in bytes. The *struct* argument can be either a structure class or a specific instantiated structure object diff --git a/docs/library/uhashlib.rst b/docs/library/uhashlib.rst index 50ed658cc1039..e1eddd2b7131f 100644 --- a/docs/library/uhashlib.rst +++ b/docs/library/uhashlib.rst @@ -18,10 +18,10 @@ be implemented: * SHA1 - A previous generation algorithm. Not recommended for new usages, but SHA1 is a part of number of Internet standards and existing applications, so boards targeting network connectivity and - interoperatiability will try to provide this. + interoperability will try to provide this. * MD5 - A legacy algorithm, not considered cryptographically secure. Only - selected boards, targeting interoperatibility with legacy applications, + selected boards, targeting interoperability with legacy applications, will offer this. Constructors diff --git a/docs/library/uos.rst b/docs/library/uos.rst index c7460134b1339..c49b13a5f5bca 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -94,10 +94,10 @@ Filesystem access * ``f_frsize`` -- fragment size * ``f_blocks`` -- size of fs in f_frsize units * ``f_bfree`` -- number of free blocks - * ``f_bavail`` -- number of free blocks for unpriviliged users + * ``f_bavail`` -- number of free blocks for unprivileged users * ``f_files`` -- number of inodes * ``f_ffree`` -- number of free inodes - * ``f_favail`` -- number of free inodes for unpriviliged users + * ``f_favail`` -- number of free inodes for unprivileged users * ``f_flag`` -- mount flags * ``f_namemax`` -- maximum filename length @@ -112,7 +112,7 @@ Filesystem access Terminal redirection and duplication ------------------------------------ -.. function:: dupterm(stream_object, index=0) +.. function:: dupterm(stream_object, index=0, /) Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like object. The *stream_object* argument must be a native stream object, or derive @@ -178,14 +178,73 @@ represented by VFS classes. Build a FAT filesystem on *block_dev*. +.. class:: VfsLfs1(block_dev) + + Create a filesystem object that uses the `littlefs v1 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + See :ref:`filesystem` for more information. + + .. staticmethod:: mkfs(block_dev) + + Build a Lfs1 filesystem on *block_dev*. + + .. note:: There are reports of littlefs v1 failing in certain situations, + for details see `littlefs issue 347`_. + +.. class:: VfsLfs2(block_dev) + + Create a filesystem object that uses the `littlefs v2 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + See :ref:`filesystem` for more information. + + .. staticmethod:: mkfs(block_dev) + + Build a Lfs2 filesystem on *block_dev*. + + .. note:: There are reports of littlefs v2 failing in certain situations, + for details see `littlefs issue 295`_. + +.. _littlefs v1 filesystem format: https://github.com/ARMmbed/littlefs/tree/v1 +.. _littlefs v2 filesystem format: https://github.com/ARMmbed/littlefs +.. _littlefs issue 295: https://github.com/ARMmbed/littlefs/issues/295 +.. _littlefs issue 347: https://github.com/ARMmbed/littlefs/issues/347 + Block devices ------------- -A block device is an object which implements the block protocol, which is a set -of methods described below by the :class:`AbstractBlockDev` class. A concrete -implementation of this class will usually allow access to the memory-like -functionality a piece of hardware (like flash memory). A block device can be -used by a particular filesystem driver to store the data for its filesystem. +A block device is an object which implements the block protocol. This enables a +device to support MicroPython filesystems. The physical hardware is represented +by a user defined class. The :class:`AbstractBlockDev` class is a template for +the design of such a class: MicroPython does not actually provide that class, +but an actual block device class must implement the methods described below. + +A concrete implementation of this class will usually allow access to the +memory-like functionality of a piece of hardware (like flash memory). A block +device can be formatted to any supported filesystem and mounted using ``uos`` +methods. + +See :ref:`filesystem` for example implementations of block devices using the +two variants of the block protocol described below. + +.. _block-device-interface: + +Simple and extended interface +............................. + +There are two compatible signatures for the ``readblocks`` and ``writeblocks`` +methods (see below), in order to support a variety of use cases. A given block +device may implement one form or the other, or both at the same time. The second +form (with the offset parameter) is referred to as the "extended interface". + +Some filesystems (such as littlefs) that require more control over write +operations, for example writing to sub-block regions without erasing, may require +that the block device supports the extended interface. .. class:: AbstractBlockDev(...) @@ -193,19 +252,41 @@ used by a particular filesystem driver to store the data for its filesystem. dependent on the specific block device. .. method:: readblocks(block_num, buf) + .. method:: readblocks(block_num, buf, offset) + The first form reads aligned, multiples of blocks. Starting at the block given by the index *block_num*, read blocks from the device into *buf* (an array of bytes). The number of blocks to read is given by the length of *buf*, which will be a multiple of the block size. + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + .. method:: writeblocks(block_num, buf) + .. method:: writeblocks(block_num, buf, offset) + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. Starting at the block given by the index *block_num*, write blocks from *buf* (an array of bytes) to the device. The number of blocks to write is given by the length of *buf*, which will be a multiple of the block size. + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + .. method:: ioctl(op, arg) Control the block device and query its parameters. The operation to @@ -219,34 +300,14 @@ used by a particular filesystem driver to store the data for its filesystem. - 5 -- get the number of bytes in a block, should return an integer, or ``None`` in which case the default value of 512 is used (*arg* is unused) + - 6 -- erase a block, *arg* is the block number to erase -By way of example, the following class will implement a block device that stores -its data in RAM using a ``bytearray``:: - - class RAMBlockDev: - def __init__(self, block_size, num_blocks): - self.block_size = block_size - self.data = bytearray(block_size * num_blocks) - - def readblocks(self, block_num, buf): - for i in range(len(buf)): - buf[i] = self.data[block_num * self.block_size + i] - - def writeblocks(self, block_num, buf): - for i in range(len(buf)): - self.data[block_num * self.block_size + i] = buf[i] - - def ioctl(self, op, arg): - if op == 4: # get number of blocks - return len(self.data) // self.block_size - if op == 5: # get block size - return self.block_size - -It can be used as follows:: - - import uos + As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs + ``ioctl(6, ...)`` must also be intercepted. The need for others is + hardware dependent. - bdev = RAMBlockDev(512, 50) - uos.VfsFat.mkfs(bdev) - vfs = uos.VfsFat(bdev) - uos.mount(vfs, '/ramdisk') + Unless otherwise stated ``ioctl(op, arg)`` can return ``None``. + Consequently an implementation can ignore unused values of ``op``. Where + ``op`` is intercepted, the return value for operations 4 and 5 are as + detailed above. Other operations should return 0 on success and non-zero + for failure, with the value returned being an ``OSError`` errno code. diff --git a/docs/library/ure.rst b/docs/library/ure.rst index ac5f02f9e81a0..ca5f35b70302c 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -124,7 +124,7 @@ Functions string for first position which matches regex (which still may be 0 if regex is anchored). -.. function:: sub(regex_str, replace, string, count=0, flags=0) +.. function:: sub(regex_str, replace, string, count=0, flags=0, /) Compile *regex_str* and search for it in *string*, replacing all matches with *replace*, and returning the new string. @@ -156,14 +156,14 @@ Compiled regular expression. Instances of this class are created using .. method:: regex.match(string) regex.search(string) - regex.sub(replace, string, count=0, flags=0) + regex.sub(replace, string, count=0, flags=0, /) Similar to the module-level functions :meth:`match`, :meth:`search` and :meth:`sub`. Using methods is (much) more efficient if the same regex is applied to multiple strings. -.. method:: regex.split(string, max_split=-1) +.. method:: regex.split(string, max_split=-1, /) Split a *string* using regex. If *max_split* is given, it specifies maximum number of splits to perform. Returns list of strings (there diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index e1becc60ea410..0c3bdfdfd9360 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -58,7 +58,7 @@ Methods Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` is raised with error of ENOENT. -.. method:: poll.poll(timeout=-1) +.. method:: poll.poll(timeout=-1, /) Wait for at least one of the registered objects to become ready or have an exceptional condition, with optional timeout in milliseconds (if *timeout* @@ -81,7 +81,7 @@ Methods Tuples returned may contain more than 2 elements as described above. -.. method:: poll.ipoll(timeout=-1, flags=0) +.. method:: poll.ipoll(timeout=-1, flags=0, /) Like :meth:`poll.poll`, but instead returns an iterator which yields a `callee-owned tuple`. This function provides an efficient, allocation-free diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index 461e37b353920..e3b9d279a051e 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -66,7 +66,7 @@ Tuple address format for ``socket`` module: Functions --------- -.. function:: socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP) +.. function:: socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, /) Create a new socket using the given address family, socket type and protocol number. Note that specifying *proto* in most cases is not @@ -79,7 +79,7 @@ Functions # Create DGRAM UDP socket socket(AF_INET, SOCK_DGRAM) -.. function:: getaddrinfo(host, port, af=0, type=0, proto=0, flags=0) +.. function:: getaddrinfo(host, port, af=0, type=0, proto=0, flags=0, /) Translate the host/port argument into a sequence of 5-tuples that contain all the necessary arguments for creating a socket connected to that service. Arguments @@ -293,7 +293,7 @@ Methods * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)`` -.. method:: socket.makefile(mode='rb', buffering=0) +.. method:: socket.makefile(mode='rb', buffering=0, /) Return a file object associated with the socket. The exact returned type depends on the arguments given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). diff --git a/docs/library/ustruct.rst b/docs/library/ustruct.rst index 81915d0a8d01c..357d622b2b88a 100644 --- a/docs/library/ustruct.rst +++ b/docs/library/ustruct.rst @@ -35,7 +35,7 @@ Functions Unpack from the *data* according to the format string *fmt*. The return value is a tuple of the unpacked values. -.. function:: unpack_from(fmt, data, offset=0) +.. function:: unpack_from(fmt, data, offset=0, /) Unpack from the *data* starting at *offset* according to the format string *fmt*. *offset* may be negative to count from the end of *buffer*. The return diff --git a/docs/library/uzlib.rst b/docs/library/uzlib.rst index 0b399f228ac4f..d40c46145ace9 100644 --- a/docs/library/uzlib.rst +++ b/docs/library/uzlib.rst @@ -14,7 +14,7 @@ is not yet implemented. Functions --------- -.. function:: decompress(data, wbits=0, bufsize=0) +.. function:: decompress(data, wbits=0, bufsize=0, /) Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window size used during compression (8-15, the dictionary size is power of 2 of @@ -23,7 +23,7 @@ Functions to be raw DEFLATE stream. *bufsize* parameter is for compatibility with CPython and is ignored. -.. class:: DecompIO(stream, wbits=0) +.. class:: DecompIO(stream, wbits=0, /) Create a `stream` wrapper which allows transparent decompression of compressed data in another *stream*. This allows to process compressed diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index 5d4985f5879db..3dbd0930436f4 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -66,7 +66,7 @@ See :ref:`pyb.LED `. :: led.toggle() led.on() led.off() - + # LEDs 3 and 4 support PWM intensity (0-255) LED(4).intensity() # get intensity LED(4).intensity(128) # set intensity to half @@ -199,16 +199,25 @@ See :ref:`pyb.SPI `. :: I2C bus ------- -See :ref:`pyb.I2C `. :: +Hardware I2C is available on the X and Y halves of the pyboard via ``I2C('X')`` +and ``I2C('Y')``. Alternatively pass in the integer identifier of the peripheral, +eg ``I2C(1)``. Software I2C is also available by explicitly specifying the +``scl`` and ``sda`` pins instead of the bus name. For more details see +:ref:`machine.I2C `. :: + + from machine import I2C + + i2c = I2C('X', freq=400000) # create hardware I2c object + i2c = I2C(scl='X1', sda='X2', freq=100000) # create software I2C object + + i2c.scan() # returns list of slave addresses + i2c.writeto(0x42, 'hello') # write 5 bytes to slave with address 0x42 + i2c.readfrom(0x42, 5) # read 5 bytes from slave - from pyb import I2C + i2c.readfrom_mem(0x42, 0x10, 2) # read 2 bytes from slave 0x42, slave memory 0x10 + i2c.writeto_mem(0x42, 0x10, 'xy') # write 2 bytes to slave 0x42, slave memory 0x10 - i2c = I2C(1, I2C.MASTER, baudrate=100000) - i2c.scan() # returns list of slave addresses - i2c.send('hello', 0x42) # send 5 bytes to slave with address 0x42 - i2c.recv(5, 0x42) # receive 5 bytes from slave - i2c.mem_read(2, 0x42, 0x10) # read 2 bytes from slave 0x42, slave memory 0x10 - i2c.mem_write('xy', 0x42, 0x10) # write 2 bytes to slave 0x42, slave memory 0x10 +Note: for legacy I2C support see :ref:`pyb.I2C `. CAN bus (controller area network) --------------------------------- diff --git a/docs/pyboard/tutorial/amp_skin.rst b/docs/pyboard/tutorial/amp_skin.rst index 697637f9d2b31..bcb583261381c 100644 --- a/docs/pyboard/tutorial/amp_skin.rst +++ b/docs/pyboard/tutorial/amp_skin.rst @@ -60,7 +60,7 @@ on your pyboard (either on the flash or the SD card in the top-level directory). or to convert any file you have with the command:: avconv -i original.wav -ar 22050 -codec pcm_u8 test.wav - + Then you can do:: >>> import wave diff --git a/docs/pyboard/tutorial/fading_led.rst b/docs/pyboard/tutorial/fading_led.rst index 8303c96030ddf..79648bee1ad41 100644 --- a/docs/pyboard/tutorial/fading_led.rst +++ b/docs/pyboard/tutorial/fading_led.rst @@ -27,10 +27,10 @@ For this tutorial, we will use the ``X1`` pin. Connect one end of the resistor t Code ---- By examining the :ref:`pyboard_quickref`, we see that ``X1`` is connected to channel 1 of timer 5 (``TIM5 CH1``). Therefore we will first create a ``Timer`` object for timer 5, then create a ``TimerChannel`` object for channel 1:: - + from pyb import Timer from time import sleep - + # timer 5 will be created with a frequency of 100 Hz tim = pyb.Timer(5, freq=100) tchannel = tim.channel(1, Timer.PWM, pin=pyb.Pin.board.X1, pulse_width=0) @@ -47,16 +47,16 @@ To achieve the fading effect shown at the beginning of this tutorial, we want to # how much to change the pulse-width by each step wstep = 1500 cur_width = min_width - + while True: tchannel.pulse_width(cur_width) - + # this determines how often we change the pulse-width. It is # analogous to frames-per-second sleep(0.01) - + cur_width += wstep - + if cur_width > max_width: cur_width = min_width @@ -67,11 +67,11 @@ If we want to have a breathing effect, where the LED fades from dim to bright th while True: tchannel.pulse_width(cur_width) - + sleep(0.01) - + cur_width += wstep - + if cur_width > max_width: cur_width = max_width wstep *= -1 diff --git a/docs/pyboard/tutorial/leds.rst b/docs/pyboard/tutorial/leds.rst index 6b05f5db05042..05f3b619e398e 100644 --- a/docs/pyboard/tutorial/leds.rst +++ b/docs/pyboard/tutorial/leds.rst @@ -17,10 +17,10 @@ This is all very well but we would like this process to be automated. Open the f pyb.delay(1000) When you save, the red light on the pyboard should turn on for about a second. To run the script, do a soft reset (CTRL-D). The pyboard will then restart and you should see a green light continuously flashing on and off. Success, the first step on your path to building an army of evil robots! When you are bored of the annoying flashing light then press CTRL-C at your terminal to stop it running. - + So what does this code do? First we need some terminology. Python is an object-oriented language, almost everything in python is a *class* and when you create an instance of a class you get an *object*. Classes have *methods* associated to them. A method (also called a member function) is used to interact with or control the object. -The first line of code creates an LED object which we have then called led. When we create the object, it takes a single parameter which must be between 1 and 4, corresponding to the 4 LEDs on the board. The pyb.LED class has three important member functions that we will use: on(), off() and toggle(). The other function that we use is pyb.delay() this simply waits for a given time in miliseconds. Once we have created the LED object, the statement while True: creates an infinite loop which toggles the led between on and off and waits for 1 second. +The first line of code creates an LED object which we have then called led. When we create the object, it takes a single parameter which must be between 1 and 4, corresponding to the 4 LEDs on the board. The pyb.LED class has three important member functions that we will use: on(), off() and toggle(). The other function that we use is pyb.delay() this simply waits for a given time in milliseconds. Once we have created the LED object, the statement while True: creates an infinite loop which toggles the led between on and off and waits for 1 second. **Exercise: Try changing the time between toggling the led and turning on a different LED.** diff --git a/docs/pyboard/tutorial/repl.rst b/docs/pyboard/tutorial/repl.rst index 3853b1578567b..973d1846a0f0e 100644 --- a/docs/pyboard/tutorial/repl.rst +++ b/docs/pyboard/tutorial/repl.rst @@ -41,7 +41,7 @@ Mac OS X Open a terminal and run:: screen /dev/tty.usbmodem* - + When you are finished and want to exit screen, type CTRL-A CTRL-\\. Linux @@ -50,7 +50,7 @@ Linux Open a terminal and run:: screen /dev/ttyACM0 - + You can also try ``picocom`` or ``minicom`` instead of screen. You may have to use ``/dev/ttyACM1`` or a higher number for ``ttyACM``. And, you may need to give yourself the correct permissions to access this devices (eg group ``uucp`` or ``dialout``, diff --git a/docs/pyboard/tutorial/script.rst b/docs/pyboard/tutorial/script.rst index 75dd324e3ca40..2d44bbc885055 100644 --- a/docs/pyboard/tutorial/script.rst +++ b/docs/pyboard/tutorial/script.rst @@ -31,7 +31,7 @@ have as to what happens next: We will get the serial device working in the next tutorial. - **Mac**: Your pyboard will appear on the desktop as a removable disc. - It will probably be called "NONAME". Click on it to open the pyboard folder. + It will probably be called ``PYBFLASH``. Click on it to open the pyboard folder. - **Linux**: Your pyboard will appear as a removable medium. On Ubuntu it will mount automatically and pop-up a window with the pyboard folder. @@ -46,17 +46,17 @@ a window (or command line) should be showing the files on the pyboard drive. The drive you are looking at is known as ``/flash`` by the pyboard, and should contain the following 4 files: -* `boot.py `_ -- this script is executed when the pyboard boots up. It sets - up various configuration options for the pyboard. +* `boot.py `_ -- the various configuration options for the pyboard. + It is executed when the pyboard boots up. -* `main.py `_ -- this is the main script that will contain your Python program. +* `main.py `_ -- the Python program to be run. It is executed after ``boot.py``. -* `README.txt `_ -- this contains some very basic information about getting - started with the pyboard. +* `README.txt `_ -- basic information about getting started with the pyboard. + This provides pointers for new users and can be safely deleted. -* `pybcdc.inf `_ -- this is a Windows driver file to configure the serial USB - device. More about this in the next tutorial. +* `pybcdc.inf `_ -- the Windows driver file to configure the serial USB device. + More about this in the next tutorial. Editing ``main.py`` ------------------- diff --git a/docs/pyboard/tutorial/switch.rst b/docs/pyboard/tutorial/switch.rst index e2a5eae884819..96bb3784e9f8c 100644 --- a/docs/pyboard/tutorial/switch.rst +++ b/docs/pyboard/tutorial/switch.rst @@ -1,7 +1,7 @@ .. _pyboard_tutorial_switch: -The Switch, callbacks and interrupts -==================================== +Switches, callbacks and interrupts +================================== The pyboard has 2 small switches, labelled USR and RST. The RST switch is a hard-reset switch, and if you press it then it restarts the pyboard diff --git a/docs/pyboard/tutorial/usb_mouse.rst b/docs/pyboard/tutorial/usb_mouse.rst index 6f8831edb465e..8166946ecd9e1 100644 --- a/docs/pyboard/tutorial/usb_mouse.rst +++ b/docs/pyboard/tutorial/usb_mouse.rst @@ -39,14 +39,15 @@ Sending mouse events by hand To get the py-mouse to do anything we need to send mouse events to the PC. We will first do this manually using the REPL prompt. Connect to your -pyboard using your serial program and type the following:: +pyboard using your serial program and type the following (no need to type +the ``#`` and text following it):: >>> hid = pyb.USB_HID() - >>> hid.send((0, 10, 0, 0)) + >>> hid.send((0, 100, 0, 0)) # (button status, x-direction, y-direction, scroll) -Your mouse should move 10 pixels to the right! In the command above you -are sending 4 pieces of information: button status, x, y and scroll. The -number 10 is telling the PC that the mouse moved 10 pixels in the x direction. +Your mouse should move 100 pixels to the right! In the command above you +are sending 4 pieces of information: **button status**, **x-direction**, **y-direction**, and **scroll**. The +number 100 is telling the PC that the mouse moved 100 pixels in the x direction. Let's make the mouse oscillate left and right:: diff --git a/docs/reference/asm_thumb2_directives.rst b/docs/reference/asm_thumb2_directives.rst index 95acd7781fdd1..6e3ddaa16dfd8 100644 --- a/docs/reference/asm_thumb2_directives.rst +++ b/docs/reference/asm_thumb2_directives.rst @@ -1,4 +1,4 @@ -Assembler Directives +Assembler directives ==================== Labels diff --git a/docs/reference/asm_thumb2_float.rst b/docs/reference/asm_thumb2_float.rst index 4acb734eeb44c..4672c4b275041 100644 --- a/docs/reference/asm_thumb2_float.rst +++ b/docs/reference/asm_thumb2_float.rst @@ -1,5 +1,5 @@ -Floating Point instructions -============================== +Floating point instructions +=========================== These instructions support the use of the ARM floating point coprocessor (on platforms such as the Pyboard which are equipped with one). The FPU @@ -31,7 +31,7 @@ Arithmetic * vsqrt(Sd, Sm) ``Sd = sqrt(Sm)`` Registers may be identical: ``vmul(S0, S0, S0)`` will execute ``S0 = S0*S0`` - + Move between ARM core and FPU registers --------------------------------------- @@ -40,7 +40,7 @@ Move between ARM core and FPU registers The FPU has a register known as FPSCR, similar to the ARM core's APSR, which stores condition codes plus other data. The following instructions provide access to this. - + * vmrs(APSR\_nzcv, FPSCR) Move the floating-point N, Z, C, and V flags to the APSR N, Z, C, and V flags. @@ -61,7 +61,7 @@ Where ``[Rn + offset]`` denotes the memory address obtained by adding Rn to the is specified in bytes. Since each float value occupies a 32 bit word, when accessing arrays of floats the offset must always be a multiple of four bytes. -Data Comparison +Data comparison --------------- * vcmp(Sd, Sm) diff --git a/docs/reference/asm_thumb2_index.rst b/docs/reference/asm_thumb2_index.rst index f066e6acec500..ccf0201489a5e 100644 --- a/docs/reference/asm_thumb2_index.rst +++ b/docs/reference/asm_thumb2_index.rst @@ -1,6 +1,6 @@ .. _asm_thumb2_index: -Inline Assembler for Thumb2 architectures +Inline assembler for Thumb2 architectures ========================================= This document assumes some familiarity with assembly language programming and should be read after studying @@ -25,7 +25,7 @@ This enables the effect of instructions to be demonstrated in Python. In certain because Python doesn't support concepts such as indirection. The pseudocode employed in such cases is described on the relevant page. -Instruction Categories +Instruction categories ---------------------- The following sections details the subset of the ARM Thumb-2 instruction set supported by MicroPython. diff --git a/docs/reference/asm_thumb2_logical_bit.rst b/docs/reference/asm_thumb2_logical_bit.rst index 8c51feaf45f95..c57bfa8470f81 100644 --- a/docs/reference/asm_thumb2_logical_bit.rst +++ b/docs/reference/asm_thumb2_logical_bit.rst @@ -1,4 +1,4 @@ -Logical & Bitwise instructions +Logical & bitwise instructions ============================== Document conventions diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index edac0ae681bba..9c68bab9a13e0 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -1,6 +1,6 @@ .. _constrained: -MicroPython on Microcontrollers +MicroPython on microcontrollers =============================== MicroPython is designed to be capable of running on microcontrollers. These @@ -12,7 +12,7 @@ based on a variety of architectures, the methods presented are generic: in some cases it will be necessary to obtain detailed information from platform specific documentation. -Flash Memory +Flash memory ------------ On the Pyboard the simple way to address the limited capacity is to fit a micro @@ -58,7 +58,7 @@ heap fragmentation. In general terms it is best to minimise the repeated creation and destruction of objects. The reason for this is covered in the section covering the `heap`_. -Compilation Phase +Compilation phase ~~~~~~~~~~~~~~~~~ When a module is imported, MicroPython compiles the code to bytecode which is @@ -85,7 +85,7 @@ imported in the usual way. Alternatively some or all modules may be implemented as frozen bytecode: on most platforms this saves even more RAM as the bytecode is run directly from flash rather than being stored in RAM. -Execution Phase +Execution phase ~~~~~~~~~~~~~~~ There are a number of coding techniques for reducing RAM usage. @@ -292,7 +292,7 @@ The Q(xxx) lines should be gone. .. _heap: -The Heap +The heap -------- When a running program instantiates an object the necessary RAM is allocated @@ -391,7 +391,7 @@ Symbol Meaning Each letter represents a single block of memory, a block being 16 bytes. So each line of the heap dump represents 0x400 bytes or 1KiB of RAM. -Control of Garbage Collection +Control of garbage collection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A GC can be demanded at any time by issuing `gc.collect()`. It is advantageous @@ -420,7 +420,7 @@ initialisation the compiler may be starved of RAM when subsequent modules are imported. If modules do instantiate data on import then `gc.collect()` issued after the import will ameliorate the problem. -String Operations +String operations ----------------- MicroPython handles strings in an efficient manner and understanding this can diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst new file mode 100644 index 0000000000000..9e7e6212dc679 --- /dev/null +++ b/docs/reference/filesystem.rst @@ -0,0 +1,291 @@ +.. _filesystem: + +Working with filesystems +======================== + +.. contents:: + +This tutorial describes how MicroPython provides an on-device filesystem, +allowing standard Python file I/O methods to be used with persistent storage. + +MicroPython automatically creates a default configuration and auto-detects the +primary filesystem, so this tutorial will be mostly useful if you want to modify +the partitioning, filesystem type, or use custom block devices. + +The filesystem is typically backed by internal flash memory on the device, but +can also use external flash, RAM, or a custom block device. + +On some ports (e.g. STM32), the filesystem may also be available over USB MSC to +a host PC. :ref:`pyboard_py` also provides a way for the host PC to access to +the filesystem on all ports. + +Note: This is mainly for use on bare-metal ports like STM32 and ESP32. On ports +with an operating system (e.g. the Unix port) the filesystem is provided by the +host OS. + +VFS +--- + +MicroPython implements a Unix-like Virtual File System (VFS) layer. All mounted +filesystems are combined into a single virtual filesystem, starting at the root +``/``. Filesystems are mounted into directories in this structure, and at +startup the working directory is changed to where the primary filesystem is +mounted. + +On STM32 / Pyboard, the internal flash is mounted at ``/flash``, and optionally +the SDCard at ``/sd``. On ESP8266/ESP32, the primary filesystem is mounted at +``/``. + +Block devices +------------- + +A block device is an instance of a class that implements the +:class:`uos.AbstractBlockDev` protocol. + +Built-in block devices +~~~~~~~~~~~~~~~~~~~~~~ + +Ports provide built-in block devices to access their primary flash. + +On power-on, MicroPython will attempt to detect the filesystem on the default +flash and configure and mount it automatically. If no filesystem is found, +MicroPython will attempt to create a FAT filesystem spanning the entire flash. +Ports can also provide a mechanism to "factory reset" the primary flash, usually +by some combination of button presses at power on. + +STM32 / Pyboard +............... + +The :ref:`pyb.Flash ` class provides access to the internal flash. On some +boards which have larger external flash (e.g. Pyboard D), it will use that +instead. The ``start`` kwarg should always be specified, i.e. +``pyb.Flash(start=0)``. + +Note: For backwards compatibility, when constructed with no arguments (i.e. +``pyb.Flash()``), it only implements the simple block interface and reflects the +virtual device presented to USB MSC (i.e. it includes a virtual partition table +at the start). + +ESP8266 +....... + +The internal flash is exposed as a block device object which is created in the +``flashbdev`` module on start up. This object is by default added as a global +variable so it can usually be accessed simply as ``bdev``. This implements the +extended interface. + +ESP32 +..... + +The :class:`esp32.Partition` class implements a block device for partitions +defined for the board. Like ESP8266, there is a global variable ``bdev`` which +points to the default partition. This implements the extended interface. + +Custom block devices +~~~~~~~~~~~~~~~~~~~~ + +The following class implements a simple block device that stores its data in +RAM using a ``bytearray``:: + + class RAMBlockDev: + def __init__(self, block_size, num_blocks): + self.block_size = block_size + self.data = bytearray(block_size * num_blocks) + + def readblocks(self, block_num, buf): + for i in range(len(buf)): + buf[i] = self.data[block_num * self.block_size + i] + + def writeblocks(self, block_num, buf): + for i in range(len(buf)): + self.data[block_num * self.block_size + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return len(self.data) // self.block_size + if op == 5: # get block size + return self.block_size + +It can be used as follows:: + + import os + + bdev = RAMBlockDev(512, 50) + os.VfsFat.mkfs(bdev) + os.mount(bdev, '/ramdisk') + +An example of a block device that supports both the simple and extended +interface (i.e. both signatures and behaviours of the +:meth:`uos.AbstractBlockDev.readblocks` and +:meth:`uos.AbstractBlockDev.writeblocks` methods) is:: + + class RAMBlockDev: + def __init__(self, block_size, num_blocks): + self.block_size = block_size + self.data = bytearray(block_size * num_blocks) + + def readblocks(self, block_num, buf, offset=0): + addr = block_num * self.block_size + offset + for i in range(len(buf)): + buf[i] = self.data[addr + i] + + def writeblocks(self, block_num, buf, offset=None): + if offset is None: + # do erase, then write + for i in range(len(buf) // self.block_size): + self.ioctl(6, block_num + i) + offset = 0 + addr = block_num * self.block_size + offset + for i in range(len(buf)): + self.data[addr + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.block_size + if op == 5: # block size + return self.block_size + if op == 6: # block erase + return 0 + +As it supports the extended interface, it can be used with :class:`littlefs +`:: + + import os + + bdev = RAMBlockDev(512, 50) + os.VfsLfs2.mkfs(bdev) + os.mount(bdev, '/ramdisk') + +Once mounted, the filesystem (regardless of its type) can be used as it +normally would be used from Python code, for example:: + + with open('/ramdisk/hello.txt', 'w') as f: + f.write('Hello world') + print(open('/ramdisk/hello.txt').read()) + +Filesystems +----------- + +MicroPython ports can provide implementations of :class:`FAT `, +:class:`littlefs v1 ` and :class:`littlefs v2 `. + +The following table shows which filesystems are included in the firmware by +default for given port/board combinations, however they can be optionally +enabled in a custom firmware build. + +==================== ===== =========== =========== +Board FAT littlefs v1 littlefs v2 +==================== ===== =========== =========== +pyboard 1.0, 1.1, D Yes No Yes +Other STM32 Yes No No +ESP8266 (1M) No No Yes +ESP8266 (2M+) Yes No Yes +ESP32 Yes No Yes +==================== ===== =========== =========== + +FAT +~~~ + +The main advantage of the FAT filesystem is that it can be accessed over USB MSC +on supported boards (e.g. STM32) without any additional drivers required on the +host PC. + +However, FAT is not tolerant to power failure during writes and this can lead to +filesystem corruption. For applications that do not require USB MSC, it is +recommended to use littlefs instead. + +To format the entire flash using FAT:: + + # ESP8266 and ESP32 + import os + os.umount('/') + os.VfsFat.mkfs(bdev) + os.mount(bdev, '/') + + # STM32 + import os, pyb + os.umount('/flash') + os.VfsFat.mkfs(pyb.Flash(start=0)) + os.mount(pyb.Flash(start=0), '/flash') + os.chdir('/flash') + +Littlefs +~~~~~~~~ + +Littlefs_ is a filesystem designed for flash-based devices, and is much more +resistant to filesystem corruption. + +.. note:: There are reports of littlefs v1 and v2 failing in certain + situations, for details see `littlefs issue 347`_ and + `littlefs issue 295`_. + +Note: It can be still be accessed over USB MSC using the `littlefs FUSE +driver`_. Note that you must use the ``-b=4096`` option to override the block +size. + +.. _littlefs FUSE driver: https://github.com/ARMmbed/littlefs-fuse/tree/master/littlefs +.. _Littlefs: https://github.com/ARMmbed/littlefs +.. _littlefs issue 295: https://github.com/ARMmbed/littlefs/issues/295 +.. _littlefs issue 347: https://github.com/ARMmbed/littlefs/issues/347 + +To format the entire flash using littlefs v2:: + + # ESP8266 and ESP32 + import os + os.umount('/') + os.VfsLfs2.mkfs(bdev) + os.mount(bdev, '/') + + # STM32 + import os, pyb + os.umount('/flash') + os.VfsLfs2.mkfs(pyb.Flash(start=0)) + os.mount(pyb.Flash(start=0), '/flash') + os.chdir('/flash') + +Hybrid (STM32) +~~~~~~~~~~~~~~ + +By using the ``start`` and ``len`` kwargs to :class:`pyb.Flash`, you can create +block devices spanning a subset of the flash device. + +For example, to configure the first 256kiB as FAT (and available over USB MSC), +and the remainder as littlefs:: + + import os, pyb + os.umount('/flash') + p1 = pyb.Flash(start=0, len=256*1024) + p2 = pyb.Flash(start=256*1024) + os.VfsFat.mkfs(p1) + os.VfsLfs2.mkfs(p2) + os.mount(p1, '/flash') + os.mount(p2, '/data') + os.chdir('/flash') + +This might be useful to make your Python files, configuration and other +rarely-modified content available over USB MSC, but allowing for frequently +changing application data to reside on littlefs with better resilience to power +failure, etc. + +The partition at offset ``0`` will be mounted automatically (and the filesystem +type automatically detected), but you can add:: + + import os, pyb + p2 = pyb.Flash(start=256*1024) + os.mount(p2, '/data') + +to ``boot.py`` to mount the data partition. + +Hybrid (ESP32) +~~~~~~~~~~~~~~ + +On ESP32, if you build custom firmware, you can modify ``partitions.csv`` to +define an arbitrary partition layout. + +At boot, the partition named "vfs" will be mounted at ``/`` by default, but any +additional partitions can be mounted in your ``boot.py`` using:: + + import esp32, os + p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo') + os.mount(p, '/foo') + diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index a6abc8b9da410..d63f372298f9e 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -4,152 +4,197 @@ Glossary .. glossary:: baremetal - A system without a (full-fledged) OS, for example an + A system without a (full-fledged) operating system, for example an :term:`MCU`-based system. When running on a baremetal system, - MicroPython effectively becomes its user-facing OS with a command - interpreter (REPL). + MicroPython effectively functions like a small operating system, + running user programs and providing a command interpreter + (:term:`REPL`). + + buffer protocol + Any Python object that can be automatically converted into bytes, such + as ``bytes``, ``bytearray``, ``memoryview`` and ``str`` objects, which + all implement the "buffer protocol". board - A PCB board. Oftentimes, the term is used to denote a particular - model of an :term:`MCU` system. Sometimes, it is used to actually - refer to :term:`MicroPython port` to a particular board (and then - may also refer to "boardless" ports like - :term:`Unix port `). + Typically this refers to a printed circuit board (PCB) containing a + :term:`microcontroller ` and supporting components. + MicroPython firmware is typically provided per-board, as the firmware + contains both MCU-specific functionality but also board-level + functionality such as drivers or pin names. + + bytecode + A compact representation of a Python program that generated by + compiling the Python source code. This is what the VM actually + executes. Bytecode is typically generated automatically at runtime and + is invisible to the user. Note that while :term:`CPython` and + MicroPython both use bytecode, the format is different. You can also + pre-compile source code offline using the :term:`cross-compiler`. callee-owned tuple - A tuple returned by some builtin function/method, containing data - which is valid for a limited time, usually until next call to the - same function (or a group of related functions). After next call, - data in the tuple may be changed. This leads to the following - restriction on the usage of callee-owned tuples - references to - them cannot be stored. The only valid operation is extracting - values from them (including making a copy). Callee-owned tuples - is a MicroPython-specific construct (not available in the general - Python language), introduced for memory allocation optimization. - The idea is that callee-owned tuple is allocated once and stored - on the callee side. Subsequent calls don't require allocation, - allowing to return multiple values when allocation is not possible - (e.g. in interrupt context) or not desirable (because allocation - inherently leads to memory fragmentation). Note that callee-owned - tuples are effectively mutable tuples, making an exception to - Python's rule that tuples are immutable. (It may be interesting - why tuples were used for such a purpose then, instead of mutable - lists - the reason for that is that lists are mutable from user - application side too, so a user could do things to a callee-owned - list which the callee doesn't expect and could lead to problems; - a tuple is protected from this.) + This is a MicroPython-specific construct where, for efficiency + reasons, some built-in functions or methods may re-use the same + underlying tuple object to return data. This avoids having to allocate + a new tuple for every call, and reduces heap fragmentation. Programs + should not hold references to callee-owned tuples and instead only + extract data from them (or make a copy). + + CircuitPython + A variant of MicroPython developed by `Adafruit Industries + `_. CPython - CPython is the reference implementation of Python programming - language, and the most well-known one, which most of the people - run. It is however one of many implementations (among which - Jython, IronPython, PyPy, and many more, including MicroPython). - As there is no formal specification of the Python language, only - CPython documentation, it is not always easy to draw a line - between Python the language and CPython its particular - implementation. This however leaves more freedom for other - implementations. For example, MicroPython does a lot of things - differently than CPython, while still aspiring to be a Python - language implementation. + CPython is the reference implementation of the Python programming + language, and the most well-known one. It is, however, one of many + implementations (including Jython, IronPython, PyPy, and MicroPython). + While MicroPython's implementation differs substantially from CPython, + it aims to maintain as much compatibility as possible. + + cross-compiler + Also known as ``mpy-cross``. This tool runs on your PC and converts a + :term:`.py file` containing MicroPython code into a :term:`.mpy file` + containing MicroPython bytecode. This means it loads faster (the board + doesn't have to compile the code), and uses less space on flash (the + bytecode is more space efficient). + + driver + A MicroPython library that implements support for a particular + component, such as a sensor or display. + + FFI + Acronym for Foreign Function Interface. A mechanism used by the + :term:`MicroPython Unix port` to access operating system functionality. + This is not available on :term:`baremetal` ports. + + filesystem + Most MicroPython ports and boards provide a filesystem stored in flash + that is available to user code via the standard Python file APIs such + as ``open()``. Some boards also make this internal filesystem + accessible to the host via USB mass-storage. + + frozen module + A Python module that has been cross compiled and bundled into the + firmware image. This reduces RAM requirements as the code is executed + directly from flash. + + Garbage Collector + A background process that runs in Python (and MicroPython) to reclaim + unused memory in the :term:`heap`. GPIO - General-purpose input/output. The simplest means to control - electrical signals. With GPIO, user can configure hardware - signal pin to be either input or output, and set or get - its digital signal value (logical "0" or "1"). MicroPython - abstracts GPIO access using :class:`machine.Pin` and :class:`machine.Signal` + General-purpose input/output. The simplest means to control electrical + signals (commonly referred to as "pins") on a microcontroller. GPIO + typically allows pins to be either input or output, and to set or get + their digital value (logical "0" or "1"). MicroPython abstracts GPIO + access using the :class:`machine.Pin` and :class:`machine.Signal` classes. GPIO port - A group of :term:`GPIO` pins, usually based on hardware - properties of these pins (e.g. controllable by the same - register). + A group of :term:`GPIO` pins, usually based on hardware properties of + these pins (e.g. controllable by the same register). + + heap + A region of RAM where MicroPython stores dynamic data. It is managed + automatically by the :term:`Garbage Collector`. Different MCUs and + boards have vastly different amounts of RAM available for the heap, so + this will affect how complex your program can be. interned string - A string referenced by its (unique) identity rather than its - address. Interned strings are thus can be quickly compared just - by their identifiers, instead of comparing by content. The - drawbacks of interned strings are that interning operation takes - time (proportional to the number of existing interned strings, - i.e. becoming slower and slower over time) and that the space - used for interned strings is not reclaimable. String interning - is done automatically by MicroPython compiler and runtimer when - it's either required by the implementation (e.g. function keyword - arguments are represented by interned string id's) or deemed - beneficial (e.g. for short enough strings, which have a chance - to be repeated, and thus interning them would save memory on - copies). Most of string and I/O operations don't produce interned - strings due to drawbacks described above. + An optimisation used by MicroPython to improve the efficiency of + working with strings. An interned string is referenced by its (unique) + identity rather than its address and can therefore be quickly compared + just by its identifier. It also means that identical strings can be + de-duplicated in memory. String interning is almost always invisible to + the user. MCU Microcontroller. Microcontrollers usually have much less resources - than a full-fledged computing system, but smaller, cheaper and + than a desktop, laptop, or phone, but are smaller, cheaper and require much less power. MicroPython is designed to be small and optimized enough to run on an average modern microcontroller. micropython-lib MicroPython is (usually) distributed as a single executable/binary file with just few builtin modules. There is no extensive standard - library comparable with :term:`CPython`. Instead, there is a related, but - separate project - `micropython-lib `_ - which provides implementations for many modules from CPython's - standard library. However, large subset of these modules require - POSIX-like environment (Linux, FreeBSD, MacOS, etc.; Windows may be - partially supported), and thus would work or make sense only with - `MicroPython Unix port`. Some subset of modules is however usable - for `baremetal` ports too. - - Unlike monolithic :term:`CPython` stdlib, micropython-lib modules - are intended to be installed individually - either using manual - copying or using :term:`upip`. + library comparable with :term:`CPython`'s. Instead, there is a related, + but separate project `micropython-lib + `_ which provides + implementations for many modules from CPython's standard library. + + Some of the modules are are implemented in pure Python, and are able to + be used on all ports. However, the majority of these modules use + :term:`FFI` to access operating system functionality, and as such can + only be used on the :term:`MicroPython Unix port` (with limited support + for Windows). + + Unlike the :term:`CPython` stdlib, micropython-lib modules are + intended to be installed individually - either using manual copying or + using :term:`upip`. MicroPython port - MicroPython supports different :term:`boards `, RTOSes, - and OSes, and can be relatively easily adapted to new systems. - MicroPython with support for a particular system is called a - "port" to that system. Different ports may have widely different - functionality. This documentation is intended to be a reference - of the generic APIs available across different ports ("MicroPython - core"). Note that some ports may still omit some APIs described - here (e.g. due to resource constraints). Any such differences, - and port-specific extensions beyond MicroPython core functionality, - would be described in the separate port-specific documentation. + MicroPython supports different :term:`boards `, RTOSes, and + OSes, and can be relatively easily adapted to new systems. MicroPython + with support for a particular system is called a "port" to that + system. Different ports may have widely different functionality. This + documentation is intended to be a reference of the generic APIs + available across different ports ("MicroPython core"). Note that some + ports may still omit some APIs described here (e.g. due to resource + constraints). Any such differences, and port-specific extensions + beyond the MicroPython core functionality, would be described in the + separate port-specific documentation. MicroPython Unix port - Unix port is one of the major :term:`MicroPython ports `. - It is intended to run on POSIX-compatible operating systems, like - Linux, MacOS, FreeBSD, Solaris, etc. It also serves as the basis - of Windows port. The importance of Unix port lies in the fact - that while there are many different :term:`boards `, so - two random users unlikely have the same board, almost all modern - OSes have some level of POSIX compatibility, so Unix port serves - as a kind of "common ground" to which any user can have access. - So, Unix port is used for initial prototyping, different kinds - of testing, development of machine-independent features, etc. - All users of MicroPython, even those which are interested only - in running MicroPython on :term:`MCU` systems, are recommended - to be familiar with Unix (or Windows) port, as it is important - productivity helper and a part of normal MicroPython workflow. + The unix port is one of the major :term:`MicroPython ports + `. It is intended to run on POSIX-compatible + operating systems, like Linux, MacOS, FreeBSD, Solaris, etc. It also + serves as the basis of Windows port. The Unix port is very useful for + quick development and testing of the MicroPython language and + machine-independent features. It can also function in a similar way to + :term:`CPython`'s ``python`` executable. + + .mpy file + The output of the :term:`cross-compiler`. A compiled form of a + :term:`.py file` that contains MicroPython bytecode instead of Python + source code. + + native + Usually refers to "native code", i.e. machine code for the target + microcontroller (such as ARM Thumb, Xtensa, x86/x64). The ``@native`` + decorator can be applied to a MicroPython function to generate native + code instead of bytecode for that function, which will likely be + faster but use more RAM. port - Either :term:`MicroPython port` or :term:`GPIO port`. If not clear - from context, it's recommended to use full specification like one - of the above. + Usually short for :term:`MicroPython port`, but could also refer to + :term:`GPIO port`. + + .py file + A file containing Python source code. + + REPL + An acronym for "Read, Eval, Print, Loop". This is the interactive + Python prompt, useful for debugging or testing short snippets of code. + Most MicroPython boards make a REPL available over a UART, and this is + typically accessible on a host PC via USB. stream - Also known as a "file-like object". An object which provides sequential - read-write access to the underlying data. A stream object implements - a corresponding interface, which consists of methods like ``read()``, - ``write()``, ``readinto()``, ``seek()``, ``flush()``, ``close()``, etc. - A stream is an important concept in MicroPython, many I/O objects - implement the stream interface, and thus can be used consistently and - interchangeably in different contexts. For more information on - streams in MicroPython, see `uio` module. + Also known as a "file-like object". An Python object which provides + sequential read-write access to the underlying data. A stream object + implements a corresponding interface, which consists of methods like + ``read()``, ``write()``, ``readinto()``, ``seek()``, ``flush()``, + ``close()``, etc. A stream is an important concept in MicroPython; + many I/O objects implement the stream interface, and thus can be used + consistently and interchangeably in different contexts. For more + information on streams in MicroPython, see the `uio` module. + + UART + Acronym for "Universal Asynchronous Receiver/Transmitter". This is a + peripheral that sends data over a pair of pins (TX & RX). Many boards + include a way to make at least one of the UARTs available to a host PC + as a serial port over USB. upip - (Literally, "micro pip"). A package manage for MicroPython, inspired - by :term:`CPython`'s pip, but much smaller and with reduced functionality. - upip runs both on :term:`Unix port ` and on - :term:`baremetal` ports (those which offer filesystem and networking - support). + (Literally, "micro pip"). A package manager for MicroPython, inspired + by :term:`CPython`'s pip, but much smaller and with reduced + functionality. + upip runs both on the :term:`Unix port ` and on + :term:`baremetal` ports which offer filesystem and networking support. diff --git a/docs/reference/index.rst b/docs/reference/index.rst index d0c7f69de9561..8cd5f03df48fc 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -1,5 +1,5 @@ -The MicroPython language -======================== +MicroPython language and implementation +======================================= MicroPython aims to implement the Python 3.4 standard (with selected features from later versions) with respect to language syntax, and most @@ -21,8 +21,11 @@ implementation and the best practices to use them. glossary.rst repl.rst + mpyfiles.rst isr_rules.rst speed_python.rst constrained.rst packages.rst asm_thumb2_index.rst + filesystem.rst + pyboard.py.rst diff --git a/docs/reference/isr_rules.rst b/docs/reference/isr_rules.rst index dfdee048c1310..57690ac212c64 100644 --- a/docs/reference/isr_rules.rst +++ b/docs/reference/isr_rules.rst @@ -29,7 +29,7 @@ This summarises the points detailed below and lists the principal recommendation * Allocate an emergency exception buffer (see below). -MicroPython Issues +MicroPython issues ------------------ The emergency exception buffer @@ -214,7 +214,7 @@ Exceptions If an ISR raises an exception it will not propagate to the main loop. The interrupt will be disabled unless the exception is handled by the ISR code. -General Issues +General issues -------------- This is merely a brief introduction to the subject of real time programming. Beginners should note @@ -225,7 +225,7 @@ with an appreciation of the following issues. .. _ISR: -Interrupt Handler Design +Interrupt handler design ~~~~~~~~~~~~~~~~~~~~~~~~ As mentioned above, ISR's should be designed to be as simple as possible. They should always return in a short, @@ -276,7 +276,7 @@ advanced topic beyond the scope of this tutorial. .. _Critical: -Critical Sections +Critical sections ~~~~~~~~~~~~~~~~~ An example of a critical section of code is one which accesses more than one variable which can be affected by an ISR. If diff --git a/docs/reference/mpyfiles.rst b/docs/reference/mpyfiles.rst new file mode 100644 index 0000000000000..4791784ac3a2e --- /dev/null +++ b/docs/reference/mpyfiles.rst @@ -0,0 +1,178 @@ +.. _mpy_files: + +MicroPython .mpy files +====================== + +MicroPython defines the concept of an .mpy file which is a binary container +file format that holds precompiled code, and which can be imported like a +normal .py module. The file ``foo.mpy`` can be imported via ``import foo``, +as long as ``foo.mpy`` can be found in the usual way by the import machinery. +Usually, each directory listed in ``sys.path`` is searched in order. When +searching a particular directory ``foo.py`` is looked for first and if that +is not found then ``foo.mpy`` is looked for, then the search continues in the +next directory if neither is found. As such, ``foo.py`` will take precedence +over ``foo.mpy``. + +These .mpy files can contain bytecode which is usually generated from Python +source files (.py files) via the ``mpy-cross`` program. For some architectures +an .mpy file can also contain native machine code, which can be generated in +a variety of ways, most notably from C source code. + +Versioning and compatibility of .mpy files +------------------------------------------ + +A given .mpy file may or may not be compatible with a given MicroPython system. +Compatibility is based on the following: + +* Version of the .mpy file: the version of the file must match the version + supported by the system loading it. + +* Bytecode features used in the .mpy file: there are two bytecode features + which must match between the file and the system: unicode support and + inline caching of map lookups in the bytecode. + +* Small integer bits: the .mpy file will require a minimum number of bits in + a small integer and the system loading it must support at least this many + bits. + +* Qstr compression window size: the .mpy file will require a minimum window + size for qstr decompression and the system loading it must have a window + greater or equal to this size. + +* Native architecture: if the .mpy file contains native machine code then + it will specify the architecture of that machine code and the system + loading it must support execution of that architecture's code. + +If a MicroPython system supports importing .mpy files then the +``sys.implementation.mpy`` field will exist and return an integer which +encodes the version (lower 8 bits), features and native architecture. + +Trying to import an .mpy file that fails one of the first four tests will +raise ``ValueError('incompatible .mpy file')``. Trying to import an .mpy +file that fails the native architecture test (if it contains native machine +code) will raise ``ValueError('incompatible .mpy arch')``. + +If importing an .mpy file fails then try the following: + +* Determine the .mpy version and flags supported by your MicroPython system + by executing:: + + import sys + sys_mpy = sys.implementation.mpy + arch = [None, 'x86', 'x64', + 'armv6', 'armv6m', 'armv7m', 'armv7em', 'armv7emsp', 'armv7emdp', + 'xtensa', 'xtensawin'][sys_mpy >> 10] + print('mpy version:', sys_mpy & 0xff) + print('mpy flags:', end='') + if arch: + print(' -march=' + arch, end='') + if sys_mpy & 0x100: + print(' -mcache-lookup-bc', end='') + if not sys_mpy & 0x200: + print(' -mno-unicode', end='') + print() + +* Check the validity of the .mpy file by inspecting the first two bytes of + the file. The first byte should be an uppercase 'M' and the second byte + will be the version number, which should match the system version from above. + If it doesn't match then rebuild the .mpy file. + +* Check if the system .mpy version matches the version emitted by ``mpy-cross`` + that was used to build the .mpy file, found by ``mpy-cross --version``. + If it doesn't match then recompile ``mpy-cross`` from the Git repository + checked out at the tag (or hash) reported by ``mpy-cross --version``. + +* Make sure you are using the correct ``mpy-cross`` flags, found by the code + above, or by inspecting the ``MPY_CROSS_FLAGS`` Makefile variable for the + port that you are using. + +The following table shows the correspondence between MicroPython release +and .mpy version. + +=================== ============ +MicroPython release .mpy version +=================== ============ +v1.12 and up 5 +v1.11 4 +v1.9.3 - v1.10 3 +v1.9 - v1.9.2 2 +v1.5.1 - v1.8.7 0 +=================== ============ + +For completeness, the next table shows the Git commit of the main +MicroPython repository at which the .mpy version was changed. + +=================== ======================================== +.mpy version change Git commit +=================== ======================================== +4 to 5 5716c5cf65e9b2cb46c2906f40302401bdd27517 +3 to 4 9a5f92ea72754c01cc03e5efcdfe94021120531e +2 to 3 ff93fd4f50321c6190e1659b19e64fef3045a484 +1 to 2 dd11af209d226b7d18d5148b239662e30ed60bad +0 to 1 6a11048af1d01c78bdacddadd1b72dc7ba7c6478 +initial version 0 d8c834c95d506db979ec871417de90b7951edc30 +=================== ======================================== + +Binary encoding of .mpy files +----------------------------- + +MicroPython .mpy files are a binary container format with code objects +stored internally in a nested hierarchy. To keep files small while still +providing a large range of possible values it uses the concept of a +variably-encoded-unsigned-integer (vuint) in many places. Similar to utf-8 +encoding, this encoding stores 7 bits per byte with the 8th bit (MSB) set +if one or more bytes follow. The bits of the unsigned integer are stored +in the vuint in LSB form. + +The top-level of an .mpy file consists of two parts: + +* The header. + +* The raw-code for the outer scope of the module. + This outer scope is executed when the .mpy file is imported. + +The header +~~~~~~~~~~ + +The .mpy header is: + +====== ================================ +size field +====== ================================ +byte value 0x4d (ASCII 'M') +byte .mpy version number +byte feature flags +byte number of bits in a small int +vuint size of qstr window +====== ================================ + +Raw code elements +~~~~~~~~~~~~~~~~~ + +A raw-code element contains code, either bytecode or native machine code. Its +contents are: + +====== ================================ +size field +====== ================================ +vuint type and size +... code (bytecode or machine code) +vuint number of constant objects +vuint number of sub-raw-code elements +... constant objects +... sub-raw-code elements +====== ================================ + +The first vuint in a raw-code element encodes the type of code stored in this +element (the two least-significant bits), and the decompressed length of the code +(the amount of RAM to allocate for it). + +Following the vuint comes the code itself. In the case of bytecode it also contains +compressed qstr values. + +Following the code comes a vuint counting the number of constant objects, and +another vuint counting the number of sub-raw-code elements. + +The constant objects are then stored next. + +Finally any sub-raw-code elements are stored, recursively. diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index 8be2461c2dbc0..43217493e52a4 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -39,7 +39,7 @@ The MicroPython distribution package format is a well-known tar.gz format, with some adaptations however. The Gzip compressor, used as an external wrapper for TAR archives, by default uses 32KB dictionary size, which means that to uncompress a compressed stream, 32KB of -contguous memory needs to be allocated. This requirement may be not +contiguous memory needs to be allocated. This requirement may be not satisfiable on low-memory devices, which may have total memory available less than that amount, and even if not, a contiguous block like that may be hard to allocate due to memory fragmentation. To accommodate @@ -132,7 +132,7 @@ Installing to a directory image involves using ``-p`` switch to `upip`:: micropython -m upip install -p install_dir micropython-pystone_lowmem -After this command, the package content (and contents of every depenency +After this command, the package content (and contents of every dependency packages) will be available in the ``install_dir/`` subdirectory. You would need to transfer contents of this directory (without the ``install_dir/`` prefix) to the device, at the suitable location, where diff --git a/docs/reference/pyboard.py.rst b/docs/reference/pyboard.py.rst new file mode 100644 index 0000000000000..d404c738f1d26 --- /dev/null +++ b/docs/reference/pyboard.py.rst @@ -0,0 +1,144 @@ +.. _pyboard_py: + +The pyboard.py tool +=================== + +This is a standalone Python tool that runs on your PC that provides a way to: + +* Quickly run a Python script or command on a MicroPython device. This is useful + while developing MicroPython programs to quickly test code without needing to + copy files to/from the device. + +* Access the filesystem on a device. This allows you to deploy your code to the + device (even if the board doesn't support USB MSC). + +Despite the name, ``pyboard.py`` works on all MicroPython ports that support the +raw REPL (including STM32, ESP32, ESP8266, NRF). + +You can download the latest version from `GitHub +`_. The +only dependency is the ``pyserial`` library which can be installed from PiPy or +your system package manager. + +Running ``pyboard.py --help`` gives the following output: + +.. code-block:: text + + usage: pyboard [-h] [-d DEVICE] [-b BAUDRATE] [-u USER] [-p PASSWORD] + [-c COMMAND] [-w WAIT] [--follow | --no-follow] [-f] + [files [files ...]] + + Run scripts on the pyboard. + + positional arguments: + files input files + + optional arguments: + -h, --help show this help message and exit + -d DEVICE, --device DEVICE + the serial device or the IP address of the pyboard + -b BAUDRATE, --baudrate BAUDRATE + the baud rate of the serial device + -u USER, --user USER the telnet login username + -p PASSWORD, --password PASSWORD + the telnet login password + -c COMMAND, --command COMMAND + program passed in as string + -w WAIT, --wait WAIT seconds to wait for USB connected board to become + available + --follow follow the output after running the scripts + [default if no scripts given] + -f, --filesystem perform a filesystem action + +Running a command on the device +------------------------------- + +This is useful for testing short snippets of code, or to script an interaction +with the device.:: + + $ pyboard.py --device /dev/ttyACM0 -c 'print(1+1)' + 2 + +If you are often interacting with the same device, you can set the environment +variable ``PYBOARD_DEVICE`` as an alternative to using the ``--device`` +command line option. For example, the following is equivalent to the previous +example:: + + $ export PYBOARD_DEVICE=/dev/ttyACM0 + $ pyboard.py -c 'print(1+1)' + +Similarly, the ``PYBOARD_BAUDRATE`` environment variable can be used +to set the default for the `--baudrate` option. + +Running a script on the device +------------------------------ + +If you have a script, ``app.py`` that you want to run on a device, then use:: + + $ pyboard.py --device /dev/ttyACM0 app.py + +Note that this doesn't actually copy app.py to the device's filesystem, it just +loads the code into RAM and executes it. Any output generated by the program +will be displayed. + +If the program app.py does not finish then you'll need to stop ``pyboard.py``, +eg with Ctrl-C. The program ``app.py`` will still continue to run on the +MicroPython device. + +Filesystem access +----------------- + +Using the ``-f`` flag, the following filesystem operations are supported: + +* ``cp src [src...] dest`` Copy files to/from the device. +* ``cat path`` Print the contents of a file on the device. +* ``ls [path]`` List contents of a directory (defaults to current working directory). +* ``rm path`` Remove a file. +* ``mkdir path`` Create a directory. +* ``rmdir path`` Remove a directory. + +The ``cp`` command uses a ``ssh``-like convention for referring to local and +remote files. Any path starting with a ``:`` will be interpreted as on the +device, otherwise it will be local. So:: + + $ pyboard.py --device /dev/ttyACM0 -f cp main.py :main.py + +will copy main.py from the current directory on the PC to a file named main.py +on the device. The filename can be omitted, e.g.:: + + $ pyboard.py --device /dev/ttyACM0 -f cp main.py : + +is equivalent to the above. + +Some more examples:: + + # Copy main.py from the device to the local PC. + $ pyboard.py --device /dev/ttyACM0 -f cp :main.py main.py + # Same, but using . instead. + $ pyboard.py --device /dev/ttyACM0 -f cp :main.py . + + # Copy three files to the device, keeping their names + # and paths (note: `lib` must exist on the device) + $ pyboard.py --device /dev/ttyACM0 -f cp main.py app.py lib/foo.py : + + # Remove a file from the device. + $ pyboard.py --device /dev/ttyACM0 -f rm util.py + + # Print the contents of a file on the device. + $ pyboard.py --device /dev/ttyACM0 -f cat boot.py + ...contents of boot.py... + +Using the pyboard library +------------------------- + +You can also use ``pyboard.py`` as a library for scripting interactions with a +MicroPython board. + +.. code-block:: python + + import pyboard + pyb = pyboard.Pyboard('/dev/ttyACM0', 115200) + pyb.enter_raw_repl() + ret = pyb.exec('print(1+1)') + print(ret) + pyb.exit_raw_repl() diff --git a/docs/reference/repl.rst b/docs/reference/repl.rst index 0c6f04b7c5090..06ba918117f33 100644 --- a/docs/reference/repl.rst +++ b/docs/reference/repl.rst @@ -103,7 +103,7 @@ For example: KeyboardInterrupt: >>> -Paste Mode +Paste mode ---------- If you want to paste some code into your terminal window, the auto-indent feature @@ -143,7 +143,7 @@ the auto-indent feature, and changes the prompt from ``>>>`` to ``===``. For exa Paste Mode allows blank lines to be pasted. The pasted text is compiled as if it were a file. Pressing Ctrl-D exits paste mode and initiates the compilation. -Soft Reset +Soft reset ---------- A soft reset will reset the python interpreter, but tries not to reset the @@ -196,7 +196,7 @@ So you can use the underscore to save the result in a variable. For example: 15 >>> -Raw Mode +Raw mode -------- Raw mode is not something that a person would normally use. It is intended for diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index c5aa80c6e1841..aa9777859242f 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -1,6 +1,6 @@ .. _speed_python: -Maximising MicroPython Speed +Maximising MicroPython speed ============================ .. contents:: @@ -40,7 +40,7 @@ the best algorithm is employed. This is a topic for textbooks rather than for a MicroPython guide but spectacular performance gains can sometimes be achieved by adopting algorithms known for their efficiency. -RAM Allocation +RAM allocation ~~~~~~~~~~~~~~ To design efficient MicroPython code it is necessary to have an understanding of the @@ -69,7 +69,7 @@ example, objects which support stream interface (e.g., file or UART) provide ``r method which allocates new buffer for read data, but also a ``readinto()`` method to read data into an existing buffer. -Floating Point +Floating point ~~~~~~~~~~~~~~ Some MicroPython ports allocate floating point numbers on heap. Some other ports @@ -165,7 +165,7 @@ by caching the object in a local variable: class foo(object): def __init__(self): - ba = bytearray(100) + self.ba = bytearray(100) def bar(self, obj_display): ba_ref = self.ba fb = obj_display.framebuffer @@ -214,7 +214,7 @@ There are certain limitations in the current implementation of the native code e * Generators are not supported. * If ``raise`` is used an argument must be supplied. -The trade-off for the improved performance (roughly twices as fast as bytecode) is an +The trade-off for the improved performance (roughly twice as fast as bytecode) is an increase in compiled code size. The Viper code emitter @@ -293,10 +293,12 @@ microseconds. The rules for casting are as follows: * The argument to a bool cast must be integral type (boolean or integer); when used as a return type the viper function will return True or False objects. * If the argument is a Python object and the cast is ``ptr``, ``ptr``, ``ptr16`` or ``ptr32``, - then the Python object must either have the buffer protocol with read-write capabilities - (in which case a pointer to the start of the buffer is returned) or it must be of integral - type (in which case the value of that integral object is returned). - + then the Python object must either have the buffer protocol (in which case a pointer to the + start of the buffer is returned) or it must be of integral type (in which case the value of + that integral object is returned). + +Writing to a pointer which points to a read-only object will lead to undefined behaviour. + The following example illustrates the use of a ``ptr16`` cast to toggle pin X1 ``n`` times: .. code:: python diff --git a/docs/templates/topindex.html b/docs/templates/topindex.html index 08bf4c73e7923..ff766b0cf2ff0 100644 --- a/docs/templates/topindex.html +++ b/docs/templates/topindex.html @@ -1,4 +1,5 @@ -{% extends "defindex.html" %} +{% extends "layout.html" %} +{% set title = _('Overview') %} {% block body %}

MicroPython documentation

diff --git a/docs/unix/quickref.rst b/docs/unix/quickref.rst new file mode 100644 index 0000000000000..ec5312a53515b --- /dev/null +++ b/docs/unix/quickref.rst @@ -0,0 +1,94 @@ +.. _unix_quickref: + +Quick reference for the UNIX and Windows ports +============================================== + +Command line options +-------------------- + +Usage:: + + micropython [ -h ] [ -i ] [ -O ] [ -v ] [ -X