diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 7b63f7549d46d..195e1e06eea46 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,3 +1,21 @@ +# all: Prune trailing whitespace. +dda9b9c6da5d3c31fa8769e581a753e95a270803 + +# all: Remove the "STATIC" macro and just use "static" instead. +decf8e6a8bb940d5829ca3296790631fcece7b21 + +# renesas-ra: Fix spelling mistakes found by codespell. +b3f2f18f927fa2fad10daf63d8c391331f5edf58 + +# all: Update Python formatting to ruff-format. +bbd8760bd9a2302e5abee29db279102bb11d7732 + +# all: Fix various spelling mistakes found by codespell 2.2.6. +cf490a70917a1b2d38ba9b58e763e0837d0f7ca7 + +# all: Fix spelling mistakes based on codespell check. +b1229efbd1509654dec6053865ab828d769e29db + # top: Update Python formatting to black "2023 stable style". 8b2748269244304854b3462cb8902952b4dcb892 diff --git a/.gitattributes b/.gitattributes index e6d31d6aa31fc..2d8496db50488 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,10 +8,12 @@ # These are binary so should never be modified by git. *.a binary +*.ico binary *.png binary *.jpg binary *.dxf binary *.mpy binary +*.der binary # These should also not be modified by git. tests/basics/string_cr_conversion.py -text diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 7bad9562964af..0000000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: Bug report -about: Report an issue -title: '' -labels: bug -assignees: '' - ---- - -* Please search existing issues before raising a new issue. For questions about MicroPython or for help using MicroPython, or any sort of "how do I?" requests, please use the Discussions tab or raise a documentation request instead. - -* In your issue, please include a clear and concise description of what the bug is, the expected output, and how to replicate it. - -* If this issue involves external hardware, please include links to relevant datasheets and schematics. - -* If you are seeing code being executed incorrectly, please provide a minimal example and expected output (e.g. comparison to CPython). - -* For build issues, please include full details of your environment, compiler versions, command lines, and build output. - -* Please provide as much information as possible about the version of MicroPython you're running, such as: - - firmware file name - - git commit hash and port/board - - version information shown in the REPL (hit Ctrl-B to see the startup message) - -* Remove all placeholder text above before submitting. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000000..1ec6c7067f9cd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,109 @@ +name: Bug report +description: Report a bug or unexpected behaviour +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Please provide as much detail as you can, it really helps us find and fix bugs faster. + + #### Not a bug report? + + * If you have a question \"How Do I ...?\", please post it on [GitHub Discussions](https://github.com/orgs/micropython/discussions/) or [Discord](https://discord.gg/RB8HZSAExQ) instead of here. + * For missing or incorrect documentation, or feature requests, then please [choose a different issue type](https://github.com/micropython/micropython/issues/new/choose). + + #### Existing issue? + + * Please search for [existing issues](https://github.com/micropython/micropython/issues) matching this bug before reporting. + - type: input + id: port-board-hw + attributes: + label: Port, board and/or hardware + description: | + Which MicroPython port(s) and board(s) are you using? + placeholder: | + esp32 port, ESP32-Fantastic board. + validations: + required: true + - type: textarea + id: version + attributes: + label: MicroPython version + description: | + To find the version: + + 1. Open a serial REPL. + 2. Type Ctrl-B to see the startup message. + 3. Copy-paste that output here. + + If the issue is about building MicroPython, please provide output of `git describe --dirty` and as much information as possible about the build environment. + + If the version or configuration is modified from the official MicroPython releases or the master branch, please tell us the details of this as well. + placeholder: | + MicroPython v6.28.3 on 2029-01-23; PyBoard 9 with STM32F9 + validations: + required: true + - type: textarea + id: steps-reproduce + attributes: + label: Reproduction + description: | + What steps will reproduce the problem? Please include all details that could be relevant about the environment, configuration, etc. + + If there is Python code to reproduce this issue then please either: + a. Type it into a code block below ([code block guide](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks)), or + b. Post longer code to a [GitHub gist](https://gist.github.com/), or + c. Create a sample project on GitHub. + + For build issues, please provide the exact build commands that you ran. + placeholder: | + 1. Copy paste the code provided below into a new file + 2. Use `mpremote run` to execute it on the board. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behaviour + description: | + What did you expect MicroPython to do? If comparing output with CPython or a different MicroPython port/version then please provide that output here. + placeholder: | + Expected to print "Hello World". + + Here is the correct output, seen with previous MicroPython version v3.14.159: + + > [...] + - type: textarea + id: what-happened + attributes: + label: Observed behaviour + description: | + What actually happened? Where possible please paste exact output, or the complete build log, etc. Very long output can be linked in a [GitHub gist](https://gist.github.com/). + placeholder: | + This unexpected exception appears: + + > [...] + validations: + required: true + - type: textarea + id: additional + attributes: + label: Additional Information + description: | + Is there anything else that might help to resolve this issue? + value: No, I've provided everything above. + - type: dropdown + id: code-of-conduct + attributes: + label: Code of Conduct + description: | + Do you agree to follow the MicroPython [Code of Conduct](https://github.com/micropython/micropython/blob/master/CODEOFCONDUCT.md) to ensure a safe and respectful space for everyone? + options: + - "Yes, I agree" + multiple: true + validations: + required: true + - type: markdown + attributes: + value: | + Thanks for taking the time to help improve MicroPython. diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md deleted file mode 100644 index e36fa62ac29a4..0000000000000 --- a/.github/ISSUE_TEMPLATE/documentation.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Documentation issue -about: Report areas of the documentation or examples that need improvement -title: 'docs: ' -labels: documentation -assignees: '' - ---- - -* Please search existing issues before raising a new issue. For questions about MicroPython or for help using MicroPython, or any sort of "how do I?" requests, please use the Discussions tab instead. - -* Describe what was missing from the documentation and/or what was incorrect/incomplete. - -* If possible, please link to the relevant page on https://docs.micropython.org/ - -* Remove all placeholder text above before submitting. diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 0000000000000..93051e51c80c7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,46 @@ +name: Documentation issue +description: Report areas of the documentation or examples that need improvement +title: "docs: " +labels: ["documentation"] +body: + - type: markdown + attributes: + value: | + This form is for reporting issues with the documentation or examples provided with MicroPython. + + If you have a general question \"How Do I ...?\", please post it on [GitHub Discussions](https://github.com/orgs/micropython/discussions/) or [Discord](https://discord.gg/RB8HZSAExQ) instead of here. + + #### Existing issue? + + * Please search for [existing issues](https://github.com/micropython/micropython/issues) before reporting a new one. + - type: input + id: page + attributes: + label: Documentation URL + description: | + Does this issue relate to a particular page in the [online documentation](https://docs.micropython.org/en/latest/)? If yes, please paste the URL of the page: + placeholder: | + https://docs.micropython.org/en/latest/ + - type: textarea + id: version + attributes: + label: Description + description: | + Please describe what was missing from the documentation and/or what was incorrect/incomplete. + validations: + required: true + - type: dropdown + id: code-of-conduct + attributes: + label: Code of Conduct + description: | + Do you agree to follow the MicroPython [Code of Conduct](https://github.com/micropython/micropython/blob/master/CODEOFCONDUCT.md) to ensure a safe and respectful space for everyone? + options: + - "Yes, I agree" + multiple: true + validations: + required: true + - type: markdown + attributes: + value: | + Thanks for taking the time to help improve MicroPython. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 81b55d98e0da8..0000000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -name: Feature request -about: Request a feature or improvement -title: '' -labels: enhancement -assignees: '' - ---- - -* Please search existing issues before raising a new issue. For questions about MicroPython or for help using MicroPython, or any sort of "how do I?" requests, please use the Discussions tab or raise a documentation request instead. - -* Describe the feature you'd like to see added to MicroPython. In particular, what does this feature enable and why is it useful. MicroPython aims to strike a balance between functionality and code size, so please consider whether this feature can be optionally enabled and whether it can be provided in other ways (e.g. pure-Python library). - -* For core Python features, where possible please include a link to the relevant PEP. - -* For new architectures / ports / boards, please provide links to relevant documentation, specifications, and toolchains. Any information about the popularity and unique features about this hardware would also be useful. - -* For features for existing ports (e.g. new peripherals or microcontroller features), please describe which port(s) it applies too, and whether this is could be an extension to the machine API or a port-specific module? - -* For drivers (e.g. for external hardware), please link to datasheets and/or existing drivers from other sources. - -* Who do you expect will implement the feature you are requesting? Would you be willing to sponsor this work? - -* Remove all placeholder text above before submitting. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000000000..7d5162a32a4af --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,74 @@ +name: Feature request +description: Request a feature or improvement +labels: ['enhancement'] +body: + - type: markdown + attributes: + value: | + This form is for requesting features or improvements in MicroPython. + + #### Get feedback first + + Before submitting a new feature idea here, suggest starting a discussion on [Discord](https://discord.gg/RB8HZSAExQ) or [GitHub Discussions](https://github.com/orgs/micropython/discussions/) to get early feedback from the community and maintainers. + + #### Not a MicroPython core feature? + + * If you have a question \"How Do I ...?\", please post it on GitHub Discussions or Discord instead of here. + * Could this feature be implemented as a pure Python library? If so, please open the request on the [micropython-lib repository](https://github.com/micropython/micropython-lib/issues) instead. + + #### Existing issue? + + * Please search for [existing issues](https://github.com/micropython/micropython/issues) before opening a new one. + - type: textarea + id: feature + attributes: + label: Description + description: | + Describe the feature you'd like to see added to MicroPython. What does this feature enable and why is it useful? + + * For core Python features, where possible please include a link to the relevant PEP or CPython documentation. + * For new architectures / ports / boards, please provide links to relevant documentation, specifications, and toolchains. Any information about the popularity and unique features about this hardware would also be useful. + * For features for existing ports (e.g. new peripherals or microcontroller features), please describe which port(s) it applies to, and whether this is could be an extension to the machine API or a port-specific module? + * For drivers (e.g. for external hardware), please link to datasheets and/or existing drivers from other sources. + + If there is an existing discussion somewhere about this feature, please add a link to it as well. + validations: + required: true + - type: textarea + id: size + attributes: + label: Code Size + description: | + MicroPython aims to strike a balance between functionality and code size. Can this feature be optionally enabled? + + If you believe the usefulness of this feature would outweigh the additional code size, please explain. (It's OK to say you're unsure here, we're happy to discuss this with you.) + - type: dropdown + id: implementation + attributes: + label: Implementation + description: | + What is your suggestion for implementing this feature? + + (See also: [How to sponsor](https://github.com/sponsors/micropython#sponsors), [How to submit a Pull Request](https://github.com/micropython/micropython/wiki/ContributorGuidelines).) + options: + - I hope the MicroPython maintainers or community will implement this feature + - I intend to implement this feature and would submit a Pull Request if desirable + - I would like to sponsor development of this feature + multiple: true + validations: + required: true + - type: dropdown + id: code-of-conduct + attributes: + label: Code of Conduct + description: | + Do you agree to follow the MicroPython [Code of Conduct](https://github.com/micropython/micropython/blob/master/CODEOFCONDUCT.md) to ensure a safe and respectful space for everyone? + options: + - "Yes, I agree" + multiple: true + validations: + required: true + - type: markdown + attributes: + value: | + Thanks for taking the time to suggest improvements for MicroPython. diff --git a/.github/ISSUE_TEMPLATE/security.md b/.github/ISSUE_TEMPLATE/security.md deleted file mode 100644 index 2bbfede6ce069..0000000000000 --- a/.github/ISSUE_TEMPLATE/security.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Security report -about: Report a security issue or vunerability in MicroPython -title: '' -labels: security -assignees: '' - ---- - -* If you need to raise this issue privately with the MicroPython team, please email contact@micropython.org instead. - -* Include a clear and concise description of what the security issue is. - -* What does this issue allow an attacker to do? - -* Remove all placeholder text above before submitting. diff --git a/.github/ISSUE_TEMPLATE/security.yml b/.github/ISSUE_TEMPLATE/security.yml new file mode 100644 index 0000000000000..57c2a5885ed85 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security.yml @@ -0,0 +1,60 @@ +name: Security report +description: Report a security issue or vulnerability in MicroPython +labels: ["security"] +body: + - type: markdown + attributes: + value: | + This form is for reporting security issues in MicroPython that are not readily exploitable. + + 1. For issues that are readily exploitable or have high impact, please email contact@micropython.org instead. + 1. If this is a question about security, please ask it in [Discussions](https://github.com/orgs/micropython/discussions/) or [Discord](https://discord.gg/RB8HZSAExQ) instead. + + #### Existing issue? + + * Please search for [existing issues](https://github.com/micropython/micropython/issues) before reporting a new one. + + - type: input + id: port-board-hw + attributes: + label: Port, board and/or hardware + description: | + Which MicroPython port(s) and board(s) are you using? + placeholder: | + esp32 port, ESP32-Duper board. + - type: textarea + id: version + attributes: + label: MicroPython version + description: | + To find the version: + + 1. Open a serial REPL. + 2. Type Ctrl-B to see the startup message. + 3. Copy-paste that output here. + + If the version or configuration is modified from the official MicroPython releases or the master branch, please tell us the details of this as well. + placeholder: | + MicroPython v6.28.3 on 2029-01-23; PyBoard 9 with STM32F9 + - type: textarea + id: report + attributes: + label: Issue Report + description: | + Please provide a clear and concise description of the security issue. + + * What does this issue allow an attacker to do? + * How does the attacker exploit this issue? + validations: + required: true + - type: dropdown + id: code-of-conduct + attributes: + label: Code of Conduct + description: | + Do you agree to follow the MicroPython [Code of Conduct](https://github.com/micropython/micropython/blob/master/CODEOFCONDUCT.md) to ensure a safe and respectful space for everyone? + options: + - "Yes, I agree" + multiple: true + validations: + required: true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000000..e11cebddb3710 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,33 @@ + + +### Summary + + + + +### Testing + + + + +### Trade-offs and Alternatives + + + diff --git a/.github/workflows/biome.yml b/.github/workflows/biome.yml new file mode 100644 index 0000000000000..88744f16ca7d6 --- /dev/null +++ b/.github/workflows/biome.yml @@ -0,0 +1,16 @@ +name: JavaScript code lint and formatting with Biome + +on: [push, pull_request] + +jobs: + eslint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Biome + uses: biomejs/setup-biome@v2 + with: + version: 1.5.3 + - name: Run Biome + run: biome ci --indent-style=space --indent-width=4 tests/ ports/webassembly diff --git a/.github/workflows/code_formatting.yml b/.github/workflows/code_formatting.yml index 542edd46cfa20..9f30f048cfdbe 100644 --- a/.github/workflows/code_formatting.yml +++ b/.github/workflows/code_formatting.yml @@ -7,14 +7,14 @@ concurrency: cancel-in-progress: true jobs: - build: + code-formatting: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 - name: Install packages - run: source tools/ci.sh && ci_code_formatting_setup + run: source tools/ci.sh && ci_c_code_formatting_setup - name: Run code formatting - run: source tools/ci.sh && ci_code_formatting_run + run: source tools/ci.sh && ci_c_code_formatting_run - name: Check code formatting run: git diff --exit-code diff --git a/.github/workflows/code_size.yml b/.github/workflows/code_size.yml index 5d955703b666a..67261933798cb 100644 --- a/.github/workflows/code_size.yml +++ b/.github/workflows/code_size.yml @@ -1,16 +1,21 @@ name: Check code size on: - push: pull_request: paths: - '.github/workflows/*.yml' - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'ports/bare-arm/**' + - 'ports/mimxrt/**' - 'ports/minimal/**' + - 'ports/rp2/**' + - 'ports/samd/**' + - 'ports/stm32/**' + - 'ports/unix/**' concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -18,9 +23,9 @@ concurrency: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 100 - name: Install packages @@ -36,7 +41,7 @@ jobs: run: echo $PR_NUMBER > pr_number - name: Upload diff if: github.event_name == 'pull_request' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: code-size-report path: | diff --git a/.github/workflows/code_size_comment.yml b/.github/workflows/code_size_comment.yml index 8baf76a47a7f6..521afad709d17 100644 --- a/.github/workflows/code_size_comment.yml +++ b/.github/workflows/code_size_comment.yml @@ -11,11 +11,11 @@ concurrency: jobs: comment: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: 'Download artifact' id: download-artifact - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: result-encoding: string script: | @@ -56,7 +56,7 @@ jobs: run: unzip code-size-report.zip - name: Post comment to pull request if: steps.download-artifact.outputs.result == 'ok' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml new file mode 100644 index 0000000000000..1d6b1dc9d2b27 --- /dev/null +++ b/.github/workflows/codespell.yml @@ -0,0 +1,13 @@ +name: Check spelling with codespell + +on: [push, pull_request] + +jobs: + codespell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # codespell version should be kept in sync with .pre-commit-config.yml + - run: pip install --user codespell==2.4.1 tomli + - run: codespell + diff --git a/.github/workflows/commit_formatting.yml b/.github/workflows/commit_formatting.yml index 0b27038f2d264..fcbcaa7092ee2 100644 --- a/.github/workflows/commit_formatting.yml +++ b/.github/workflows/commit_formatting.yml @@ -1,6 +1,6 @@ name: Check commit message formatting -on: [push, pull_request] +on: [pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -10,9 +10,9 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - fetch-depth: '100' - - uses: actions/setup-python@v4 + fetch-depth: 100 + - uses: actions/setup-python@v5 - name: Check commit message formatting run: source tools/ci.sh && ci_commit_formatting_run diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e9b17007476c1..d01a4b50c9810 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,6 +1,7 @@ name: Build docs on: + push: pull_request: paths: - docs/** @@ -14,9 +15,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 - name: Install Python packages - run: pip install Sphinx + run: pip install -r docs/requirements.txt - name: Build docs run: make -C docs/ html diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 450805a6bde41..6613f106625a2 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -18,7 +18,7 @@ jobs: embedding: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: make -C examples/embedding -f micropython_embed.mk && make -C examples/embedding - name: Run diff --git a/.github/workflows/mpremote.yml b/.github/workflows/mpremote.yml index 3cfb9d47d39f2..ee91b6360b9b4 100644 --- a/.github/workflows/mpremote.yml +++ b/.github/workflows/mpremote.yml @@ -11,20 +11,18 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - # Version is determined from git, - # should be deep enough to get to latest tag - fetch-depth: '1000' - - run: | - git fetch --prune --unshallow --tags - - uses: actions/setup-python@v4 + # Setting this to zero means fetch all history and tags, + # which hatch-vcs can use to discover the version tag. + fetch-depth: 0 + - uses: actions/setup-python@v5 - name: Install build tools run: pip install build - name: Build mpremote wheel run: cd tools/mpremote && python -m build --wheel - name: Archive mpremote wheel - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: mpremote path: | diff --git a/.github/workflows/mpy_format.yml b/.github/workflows/mpy_format.yml index 66abb19b81a46..b6768a46c3cdc 100644 --- a/.github/workflows/mpy_format.yml +++ b/.github/workflows/mpy_format.yml @@ -15,9 +15,9 @@ concurrency: jobs: test: - runs-on: ubuntu-20.04 # use 20.04 to get python2 + runs-on: ubuntu-22.04 # use 22.04 to get python2 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_mpy_format_setup - name: Test mpy-tool.py diff --git a/.github/workflows/ports.yml b/.github/workflows/ports.yml index fb574ad981908..1f262b0ba4bee 100644 --- a/.github/workflows/ports.yml +++ b/.github/workflows/ports.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build ports download metadata run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards diff --git a/.github/workflows/ports_alif.yml b/.github/workflows/ports_alif.yml new file mode 100644 index 0000000000000..0e96e7d816e50 --- /dev/null +++ b/.github/workflows/ports_alif.yml @@ -0,0 +1,33 @@ +name: alif port + +on: + push: + pull_request: + paths: + - '.github/workflows/*.yml' + - 'tools/**' + - 'py/**' + - 'extmod/**' + - 'shared/**' + - 'lib/**' + - 'drivers/**' + - 'ports/alif/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_alif: + strategy: + fail-fast: false + matrix: + ci_func: # names are functions in ci.sh + - alif_ae3_build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install packages + run: source tools/ci.sh && ci_alif_setup + - name: Build ci_${{matrix.ci_func }} + run: source tools/ci.sh && ci_${{ matrix.ci_func }} diff --git a/.github/workflows/ports_cc3200.yml b/.github/workflows/ports_cc3200.yml index b58bc24b58b0a..f178a140587db 100644 --- a/.github/workflows/ports_cc3200.yml +++ b/.github/workflows/ports_cc3200.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_cc3200_setup - name: Build diff --git a/.github/workflows/ports_esp32.yml b/.github/workflows/ports_esp32.yml index 6fc009d4fee83..4c07f89437757 100644 --- a/.github/workflows/ports_esp32.yml +++ b/.github/workflows/ports_esp32.yml @@ -18,20 +18,40 @@ concurrency: cancel-in-progress: true jobs: - build_idf402: - runs-on: ubuntu-20.04 + build_idf: + strategy: + fail-fast: false + matrix: + ci_func: # names are functions in ci.sh + - esp32_build_cmod_spiram_s2 + - esp32_build_s3_c3 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Install packages - run: source tools/ci.sh && ci_esp32_idf402_setup - - name: Build - run: source tools/ci.sh && ci_esp32_build - - build_idf44: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - name: Install packages - run: source tools/ci.sh && ci_esp32_idf44_setup - - name: Build - run: source tools/ci.sh && ci_esp32_build + - uses: actions/checkout@v4 + + - id: idf_ver + name: Read the ESP-IDF version (including Python version) + run: source tools/ci.sh && echo "IDF_VER=${IDF_VER}-py${PYTHON_VER}" | tee "$GITHUB_OUTPUT" + + - name: Cached ESP-IDF install + id: cache_esp_idf + uses: actions/cache@v4 + with: + path: | + ./esp-idf/ + ~/.espressif/ + !~/.espressif/dist/ + ~/.cache/pip/ + key: esp-idf-${{ steps.idf_ver.outputs.IDF_VER }} + + - name: Install ESP-IDF packages + if: steps.cache_esp_idf.outputs.cache-hit != 'true' + run: source tools/ci.sh && ci_esp32_idf_setup + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: esp32-${{ matrix.ci_func }} + + - name: Build ci_${{matrix.ci_func }} + run: source tools/ci.sh && ci_${{ matrix.ci_func }} diff --git a/.github/workflows/ports_esp8266.yml b/.github/workflows/ports_esp8266.yml index ba89d5e9529eb..5236edf40b959 100644 --- a/.github/workflows/ports_esp8266.yml +++ b/.github/workflows/ports_esp8266.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_esp8266_setup && ci_esp8266_path >> $GITHUB_PATH - name: Build diff --git a/.github/workflows/ports_mimxrt.yml b/.github/workflows/ports_mimxrt.yml index d91562534188a..7743e036ab377 100644 --- a/.github/workflows/ports_mimxrt.yml +++ b/.github/workflows/ports_mimxrt.yml @@ -19,9 +19,14 @@ concurrency: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest + defaults: + run: + working-directory: 'micropython repo' # test build with space in path steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + path: 'micropython repo' - name: Install packages run: source tools/ci.sh && ci_mimxrt_setup - name: Build diff --git a/.github/workflows/ports_nrf.yml b/.github/workflows/ports_nrf.yml index 89211217800b0..76727c9d1f6bd 100644 --- a/.github/workflows/ports_nrf.yml +++ b/.github/workflows/ports_nrf.yml @@ -19,9 +19,9 @@ concurrency: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_nrf_setup - name: Build diff --git a/.github/workflows/ports_powerpc.yml b/.github/workflows/ports_powerpc.yml index a15c4da97fa6a..c41b13e5ddffe 100644 --- a/.github/workflows/ports_powerpc.yml +++ b/.github/workflows/ports_powerpc.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_powerpc_setup - name: Build diff --git a/.github/workflows/ports_qemu-arm.yml b/.github/workflows/ports_qemu-arm.yml deleted file mode 100644 index 93ec4da76700e..0000000000000 --- a/.github/workflows/ports_qemu-arm.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: qemu-arm port - -on: - push: - pull_request: - paths: - - '.github/workflows/*.yml' - - 'tools/**' - - 'py/**' - - 'extmod/**' - - 'shared/**' - - 'lib/**' - - 'drivers/**' - - 'ports/qemu-arm/**' - - 'tests/**' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build_and_test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Install packages - run: source tools/ci.sh && ci_qemu_arm_setup - - name: Build and run test suite - run: source tools/ci.sh && ci_qemu_arm_build - - name: Print failures - if: failure() - run: grep --before-context=100 --text "FAIL" ports/qemu-arm/build/console.out diff --git a/.github/workflows/ports_qemu.yml b/.github/workflows/ports_qemu.yml new file mode 100644 index 0000000000000..57192c43936e5 --- /dev/null +++ b/.github/workflows/ports_qemu.yml @@ -0,0 +1,44 @@ +name: qemu port + +on: + push: + pull_request: + paths: + - '.github/workflows/*.yml' + - 'tools/**' + - 'py/**' + - 'extmod/**' + - 'shared/**' + - 'lib/**' + - 'drivers/**' + - 'ports/qemu/**' + - 'tests/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_and_test_arm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install packages + run: source tools/ci.sh && ci_qemu_setup_arm + - name: Build and run test suite + run: source tools/ci.sh && ci_qemu_build_arm + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures + + build_and_test_rv32: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install packages + run: source tools/ci.sh && ci_qemu_setup_rv32 + - name: Build and run test suite + run: source tools/ci.sh && ci_qemu_build_rv32 + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures diff --git a/.github/workflows/ports_renesas-ra.yml b/.github/workflows/ports_renesas-ra.yml index 33e17a385a1e3..b9fa74331dc0b 100644 --- a/.github/workflows/ports_renesas-ra.yml +++ b/.github/workflows/ports_renesas-ra.yml @@ -19,9 +19,9 @@ concurrency: jobs: build_renesas_ra_board: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_renesas_ra_setup - name: Build diff --git a/.github/workflows/ports_rp2.yml b/.github/workflows/ports_rp2.yml index f042ff1151ab1..748f38e143893 100644 --- a/.github/workflows/ports_rp2.yml +++ b/.github/workflows/ports_rp2.yml @@ -20,8 +20,13 @@ concurrency: jobs: build: runs-on: ubuntu-latest + defaults: + run: + working-directory: 'micropython repo' # test build with space in path steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + path: 'micropython repo' - name: Install packages run: source tools/ci.sh && ci_rp2_setup - name: Build diff --git a/.github/workflows/ports_samd.yml b/.github/workflows/ports_samd.yml index 9833a2fae2ef9..5bf1826cd17bb 100644 --- a/.github/workflows/ports_samd.yml +++ b/.github/workflows/ports_samd.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_samd_setup - name: Build diff --git a/.github/workflows/ports_stm32.yml b/.github/workflows/ports_stm32.yml index b278ea862ce61..8800f145189b8 100644 --- a/.github/workflows/ports_stm32.yml +++ b/.github/workflows/ports_stm32.yml @@ -18,20 +18,19 @@ concurrency: cancel-in-progress: true jobs: - build_pyb: - runs-on: ubuntu-20.04 + build_stm32: + strategy: + fail-fast: false + matrix: + ci_func: # names are functions in ci.sh + - stm32_pyb_build + - stm32_nucleo_build + - stm32_misc_build + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_stm32_setup - - name: Build - run: source tools/ci.sh && ci_stm32_pyb_build + - name: Build ci_${{matrix.ci_func }} + run: source tools/ci.sh && ci_${{ matrix.ci_func }} - build_nucleo: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - name: Install packages - run: source tools/ci.sh && ci_stm32_setup - - name: Build - run: source tools/ci.sh && ci_stm32_nucleo_build diff --git a/.github/workflows/ports_teensy.yml b/.github/workflows/ports_teensy.yml deleted file mode 100644 index f1299603259a6..0000000000000 --- a/.github/workflows/ports_teensy.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: teensy port - -on: - push: - pull_request: - paths: - - '.github/workflows/*.yml' - - 'tools/**' - - 'py/**' - - 'extmod/**' - - 'shared/**' - - 'lib/**' - - 'drivers/**' - - 'ports/teensy/**' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Install packages - run: source tools/ci.sh && ci_teensy_setup - - name: Build - run: source tools/ci.sh && ci_teensy_build diff --git a/.github/workflows/ports_unix.yml b/.github/workflows/ports_unix.yml index fe25deb4ad51d..2547015038e4d 100644 --- a/.github/workflows/ports_unix.yml +++ b/.github/workflows/ports_unix.yml @@ -23,7 +23,7 @@ jobs: minimal: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: source tools/ci.sh && ci_unix_minimal_build - name: Run main test suite @@ -35,7 +35,7 @@ jobs: reproducible: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build with reproducible date run: source tools/ci.sh && ci_unix_minimal_build env: @@ -46,7 +46,7 @@ jobs: standard: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: source tools/ci.sh && ci_unix_standard_build - name: Run main test suite @@ -55,10 +55,22 @@ jobs: if: failure() run: tests/run-tests.py --print-failures + standard_v2: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build + run: source tools/ci.sh && ci_unix_standard_v2_build + - name: Run main test suite + run: source tools/ci.sh && ci_unix_standard_v2_run_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures + coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_coverage_setup - name: Build @@ -76,18 +88,19 @@ jobs: (cd ports/unix && gcov -o build-coverage/py ../../py/*.c || true) (cd ports/unix && gcov -o build-coverage/extmod ../../extmod/*.c || true) - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v5 with: fail_ci_if_error: true verbose: true + token: ${{ secrets.CODECOV_TOKEN }} - name: Print failures if: failure() run: tests/run-tests.py --print-failures coverage_32bit: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 # use 22.04 to get libffi-dev:i386 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_32bit_setup - name: Build @@ -103,9 +116,9 @@ jobs: run: tests/run-tests.py --print-failures nanbox: - runs-on: ubuntu-20.04 # use 20.04 to get python2 + runs-on: ubuntu-22.04 # use 22.04 to get python2, and libffi-dev:i386 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_32bit_setup - name: Build @@ -119,7 +132,7 @@ jobs: float: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: source tools/ci.sh && ci_unix_float_build - name: Run main test suite @@ -129,9 +142,9 @@ jobs: run: tests/run-tests.py --print-failures stackless_clang: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_clang_setup - name: Build @@ -143,9 +156,9 @@ jobs: run: tests/run-tests.py --print-failures float_clang: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_clang_setup - name: Build @@ -159,7 +172,12 @@ jobs: settrace: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. + # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. + with: + python-version: '3.11' - name: Build run: source tools/ci.sh && ci_unix_settrace_build - name: Run main test suite @@ -171,7 +189,12 @@ jobs: settrace_stackless: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. + # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. + with: + python-version: '3.11' - name: Build run: source tools/ci.sh && ci_unix_settrace_stackless_build - name: Run main test suite @@ -181,10 +204,10 @@ jobs: run: tests/run-tests.py --print-failures macos: - runs-on: macos-11.0 + runs-on: macos-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: '3.8' - name: Build @@ -196,9 +219,10 @@ jobs: run: tests/run-tests.py --print-failures qemu_mips: - runs-on: ubuntu-latest + # ubuntu-22.04 is needed for older libffi. + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_qemu_mips_setup - name: Build @@ -210,9 +234,10 @@ jobs: run: tests/run-tests.py --print-failures qemu_arm: - runs-on: ubuntu-latest + # ubuntu-22.04 is needed for older libffi. + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_qemu_arm_setup - name: Build @@ -222,3 +247,18 @@ jobs: - name: Print failures if: failure() run: tests/run-tests.py --print-failures + + qemu_riscv64: + # ubuntu-22.04 is needed for older libffi. + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Install packages + run: source tools/ci.sh && ci_unix_qemu_riscv64_setup + - name: Build + run: source tools/ci.sh && ci_unix_qemu_riscv64_build + - name: Run main test suite + run: source tools/ci.sh && ci_unix_qemu_riscv64_run_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures diff --git a/.github/workflows/ports_webassembly.yml b/.github/workflows/ports_webassembly.yml index 2e0865662f061..880f15ab34469 100644 --- a/.github/workflows/ports_webassembly.yml +++ b/.github/workflows/ports_webassembly.yml @@ -20,7 +20,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_webassembly_setup - name: Build diff --git a/.github/workflows/ports_windows.yml b/.github/workflows/ports_windows.yml index b31718c591402..84e018ba15d16 100644 --- a/.github/workflows/ports_windows.yml +++ b/.github/workflows/ports_windows.yml @@ -18,10 +18,133 @@ concurrency: cancel-in-progress: true jobs: - build: + build-vs: + strategy: + fail-fast: false + matrix: + platform: [x86, x64] + configuration: [Debug, Release] + variant: [dev, standard] + visualstudio: ['2017', '2019', '2022'] + include: + - visualstudio: '2017' + runner: windows-latest + vs_version: '[15, 16)' + - visualstudio: '2019' + runner: windows-2019 + vs_version: '[16, 17)' + - visualstudio: '2022' + runner: windows-2022 + vs_version: '[17, 18)' + # trim down the number of jobs in the matrix + exclude: + - variant: standard + configuration: Debug + - visualstudio: '2019' + configuration: Debug + env: + CI_BUILD_CONFIGURATION: ${{ matrix.configuration }} + runs-on: ${{ matrix.runner }} + steps: + - name: Install Visual Studio 2017 + if: matrix.visualstudio == '2017' + run: | + choco install visualstudio2017buildtools + choco install visualstudio2017-workload-vctools + choco install windows-sdk-8.1 + - uses: microsoft/setup-msbuild@v2 + with: + vs-version: ${{ matrix.vs_version }} + - uses: actions/setup-python@v5 + if: matrix.runner == 'windows-2019' + with: + python-version: '3.9' + - uses: actions/checkout@v4 + - name: Build mpy-cross.exe + run: msbuild mpy-cross\mpy-cross.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} + - name: Update submodules + run: git submodule update --init lib/micropython-lib + - name: Build micropython.exe + run: msbuild ports\windows\micropython.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} -property:PyVariant=${{ matrix.variant }} + - name: Get micropython.exe path + id: get_path + run: | + $exePath="$(msbuild ports\windows\micropython.vcxproj -nologo -v:m -t:ShowTargetPath -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} -property:PyVariant=${{ matrix.variant }})" + echo ("micropython=" + $exePath.Trim()) >> $env:GITHUB_OUTPUT + - name: Run tests + id: test + env: + MICROPY_MICROPYTHON: ${{ steps.get_path.outputs.micropython }} + working-directory: tests + run: python run-tests.py + - name: Print failures + if: failure() && steps.test.conclusion == 'failure' + working-directory: tests + run: python run-tests.py --print-failures + - name: Run mpy tests + id: test_mpy + env: + MICROPY_MICROPYTHON: ${{ steps.get_path.outputs.micropython }} + working-directory: tests + run: python run-tests.py --via-mpy -d basics float micropython + - name: Print mpy failures + if: failure() && steps.test_mpy.conclusion == 'failure' + working-directory: tests + run: python run-tests.py --print-failures + + build-mingw: + strategy: + fail-fast: false + matrix: + variant: [dev, standard] + sys: [mingw32, mingw64] + include: + - sys: mingw32 + env: i686 + - sys: mingw64 + env: x86_64 + runs-on: windows-2022 + env: + CHERE_INVOKING: enabled_from_arguments + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/setup-python@v5 + # note: can go back to installing mingw-w64-${{ matrix.env }}-python after + # MSYS2 updates to Python >3.12 (due to settrace compatibility issue) + with: + python-version: '3.11' + - uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.sys }} + update: true + install: >- + make + mingw-w64-${{ matrix.env }}-gcc + pkg-config + git + diffutils + path-type: inherit # Remove when setup-python is removed + - uses: actions/checkout@v4 + - name: Build mpy-cross.exe + run: make -C mpy-cross -j2 + - name: Update submodules + run: make -C ports/windows VARIANT=${{ matrix.variant }} submodules + - name: Build micropython.exe + run: make -C ports/windows -j2 VARIANT=${{ matrix.variant }} + - name: Run tests + id: test + run: make -C ports/windows test_full VARIANT=${{ matrix.variant }} + - name: Print failures + if: failure() && steps.test.conclusion == 'failure' + working-directory: tests + run: python run-tests.py --print-failures + + cross-build-on-linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_windows_setup - name: Build diff --git a/.github/workflows/ports_zephyr.yml b/.github/workflows/ports_zephyr.yml index f64401b316a5b..eb85af6a36154 100644 --- a/.github/workflows/ports_zephyr.yml +++ b/.github/workflows/ports_zephyr.yml @@ -20,10 +20,41 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: jlumbroso/free-disk-space@main + with: + # Only free up a few things so this step runs quickly. + android: false + dotnet: true + haskell: true + large-packages: false + docker-images: false + swap-storage: false + - uses: actions/checkout@v4 + - id: versions + name: Read Zephyr version + run: source tools/ci.sh && echo "ZEPHYR=$ZEPHYR_VERSION" | tee "$GITHUB_OUTPUT" + - name: Cached Zephyr Workspace + id: cache_workspace + uses: actions/cache@v4 + with: + # note that the Zephyr CI docker image is 15GB. At time of writing + # GitHub caches are limited to 10GB total for a project. So we only + # cache the "workspace" + path: ./zephyrproject + key: zephyr-workspace-${{ steps.versions.outputs.ZEPHYR }} + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: zephyr - name: Install packages run: source tools/ci.sh && ci_zephyr_setup - name: Install Zephyr + if: steps.cache_workspace.outputs.cache-hit != 'true' run: source tools/ci.sh && ci_zephyr_install - name: Build run: source tools/ci.sh && ci_zephyr_build + - name: Run main test suite + run: source tools/ci.sh && ci_zephyr_run_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 0000000000000..4c4a2a3162ed6 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,13 @@ +name: Python code lint and formatting with ruff + +on: [push, pull_request] + +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # ruff version should be kept in sync with .pre-commit-config.yaml & also micropython-lib + - run: pipx install ruff==0.11.6 + - run: ruff check --output-format=github . + - run: ruff format --diff . diff --git a/.gitignore b/.gitignore index 2d20cb18970e8..b5010dfd14db6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,9 @@ build/ build-*/ docs/genrst/ -# Test failure outputs +# Test failure outputs and intermediate artefacts tests/results/* +tests/ports/unix/ffi_lib.so # Python cache files __pycache__/ diff --git a/.gitmodules b/.gitmodules index 992fec3d1836f..02849ec9bdd11 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,13 +3,13 @@ url = https://github.com/micropython/axtls.git [submodule "lib/libffi"] path = lib/libffi - url = https://github.com/atgreen/libffi + url = https://github.com/libffi/libffi [submodule "lib/lwip"] path = lib/lwip url = https://github.com/lwip-tcpip/lwip.git [submodule "lib/berkeley-db-1.xx"] path = lib/berkeley-db-1.xx - url = https://github.com/pfalcon/berkeley-db-1.xx + url = https://github.com/micropython/berkeley-db-1.xx [submodule "lib/stm32lib"] path = lib/stm32lib url = https://github.com/micropython/stm32lib @@ -56,3 +56,21 @@ [submodule "lib/micropython-lib"] path = lib/micropython-lib url = https://github.com/micropython/micropython-lib.git +[submodule "lib/protobuf-c"] + path = lib/protobuf-c + url = https://github.com/protobuf-c/protobuf-c.git +[submodule "lib/open-amp"] + path = lib/open-amp + url = https://github.com/OpenAMP/open-amp.git +[submodule "lib/libmetal"] + path = lib/libmetal + url = https://github.com/OpenAMP/libmetal.git +[submodule "lib/arduino-lib"] + path = lib/arduino-lib + url = https://github.com/arduino/arduino-lib-mpy.git +[submodule "lib/alif_ensemble-cmsis-dfp"] + path = lib/alif_ensemble-cmsis-dfp + url = https://github.com/alifsemi/alif_ensemble-cmsis-dfp.git +[submodule "lib/alif-security-toolkit"] + path = lib/alif-security-toolkit + url = https://github.com/micropython/alif-security-toolkit.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 12f3d79c93533..ac9785bb59232 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,8 +2,8 @@ repos: - repo: local hooks: - id: codeformat - name: MicroPython codeformat.py for changed files - entry: tools/codeformat.py -v -f + name: MicroPython codeformat.py for changed C files + entry: tools/codeformat.py -v -c -f language: python - id: verifygitlog name: MicroPython git commit message format checker @@ -11,3 +11,17 @@ repos: language: python verbose: true stages: [commit-msg] + - repo: https://github.com/charliermarsh/ruff-pre-commit + # Version should be kept in sync with .github/workflows/ruff.yml & also micropython-lib + rev: v0.11.6 + hooks: + - id: ruff + - id: ruff-format + - repo: https://github.com/codespell-project/codespell + # Version should be kept in sync with .github/workflows/codespell.yml + rev: v2.4.1 + hooks: + - id: codespell + name: Spellcheck for changed files (codespell) + additional_dependencies: + - tomli diff --git a/CODECONVENTIONS.md b/CODECONVENTIONS.md index 3b678bfeb800b..d3f71cb083deb 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 72 characters. Examples +final full stop. First line must fit within 72 characters. Examples of good first line of commit messages: py/objstr: Add splitlines() method. @@ -27,12 +27,9 @@ 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. -When committing you are encouraged to sign-off your commit by adding -"Signed-off-by" lines and similar, eg using "git commit -s". If you don't -explicitly sign-off in this way then the commit message, which includes your -name and email address in the "Author" line, implies your sign-off. In either -case, of explicit or implicit sign-off, you are certifying and signing off -against the following: +When committing you must sign-off your commit by adding "Signed-off-by:" +line(s) at the end of the commit message, e.g. using `git commit -s`. You +are then certifying and signing off against the following: * That you wrote the change yourself, or took it from a project with a compatible license (in the latter case the commit message, and possibly @@ -49,21 +46,23 @@ against the following: * Your contribution including commit message will be publicly and indefinitely available for anyone to access, including redistribution under the terms of the project's license. -* Your signature for all of the above, which is the "Signed-off-by" line - or the "Author" line in the commit message, includes your full real name and - a valid and active email address by which you can be contacted in the - foreseeable future. +* Your signature for all of the above, which is the "Signed-off-by" line, + includes your full real name and 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. +Both C and Python code formatting are controlled for consistency across the +MicroPython codebase. C code is formatted using the `tools/codeformat.py` +script which uses [uncrustify](https://github.com/uncrustify/uncrustify). +Python code is linted and formatted using +[ruff & ruff format](https://github.com/astral-sh/ruff). +After making changes, and before committing, run `tools/codeformat.py` to +reformat your C code and `ruff format` for any Python code. 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. uncrustify ========== @@ -105,6 +104,22 @@ This command may work, please raise a new Issue if it doesn't: curl -L https://github.com/Homebrew/homebrew-core/raw/2b07d8192623365078a8b855a164ebcdf81494a6/Formula/uncrustify.rb > uncrustify.rb && brew install uncrustify.rb && rm uncrustify.rb ``` +Code spell checking +=================== + +Code spell checking is done using [codespell](https://github.com/codespell-project/codespell#codespell) +and runs in a GitHub action in CI. Codespell is configured via `pyproject.toml` +to avoid false positives. It is recommended run codespell before submitting a +PR. To simplify this, codespell is configured as a pre-commit hook and will be +installed if you run `pre-commit install` (see below). + +If you want to install and run codespell manually, you can do so by running: + +``` +$ pip install codespell tomli +$ codespell +``` + Automatic Pre-Commit Hooks ========================== @@ -155,12 +170,22 @@ Tips: * To ignore the pre-commit message format check temporarily, start the commit message subject line with "WIP" (for "Work In Progress"). +Running pre-commit manually +=========================== + +Once pre-commit is installed as per the previous section it can be manually +run against the MicroPython python codebase to update file formatting on +demand, with either: +* `pre-commit run --all-files` to fix all files in the MicroPython codebase +* `pre-commit run --file ./path/to/my/file` to fix just one file +* `pre-commit run --file ./path/to/my/folder/*` to fix just one folder + Python code conventions ======================= 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. +is auto-formatted using [ruff format](https://docs.astral.sh/ruff/formatter) +with a line-length of 99 characters. Naming conventions: - Module names are short and all lowercase; eg pyb, stm. @@ -181,14 +206,21 @@ 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: +As the MicroPython code base is over ten years old, not every source file +conforms fully to these conventions. If making small changes to existing code, +then it's usually acceptable to follow the existing code's style. New code or +major changes should follow the conventions described here. + +## White space + - Expand tabs to 4 spaces. - Don't leave trailing whitespace at the end of a line. - For control blocks (if, for, while), put 1 space between the keyword and the opening parenthesis. - Put 1 space after a comma, and 1 space around operators. -Braces: +## Braces + - Use braces for all blocks, even no-line and single-line pieces of code. - Put opening braces on the end of the line it belongs to, not on @@ -196,18 +228,43 @@ Braces: - For else-statements, put the else on the same line as the previous closing brace. -Header files: +## Header files + - Header files should be protected from multiple inclusion with #if directives. See an existing header for naming convention. -Names: +## Names + - Use underscore_case, not camelCase for all names. - Use CAPS_WITH_UNDERSCORE for enums and macros. - When defining a type use underscore_case and put '_t' after it. -Integer types: MicroPython runs on 16, 32, and 64 bit machines, so it's -important to use the correctly-sized (and signed) integer types. The -general guidelines are: +### Public names (declared in headers) + +- MicroPython-specific names (especially any declared in `py/` and `extmod/` + directories) should generally start with `mp_` or `MP_`. +- Functions and variables declared in a header should generally share a longer + common prefix. Usually the prefix matches the file name (i.e. items defined in + `py/obj.c` are declared in `py/obj.h` and should be prefixed `mp_obj_`). There + are exceptions, for example where one header file contains declarations + implemented in multiple source files for expediency. + +### Private names (specific to a single .c file) + +- For static functions and variables exposed to Python (i.e. a static C function + that is wrapped in `MP_DEFINE_CONST_FUN_...` and attached to a module), use + the file-level shared common prefix, i.e. name them as if the function or + variable was not static. +- Other static definitions in source files (i.e. functions or variables defined + in a .c file that are only used within that .c file) don't need any prefix + (specifically: no `s_` or `_` prefix, and generally avoid adding the + file-level common prefix). + +## Integer types + +MicroPython runs on 16, 32, and 64 bit machines, so it's important to use the +correctly-sized (and signed) integer types. The general guidelines are: + - For most cases use mp_int_t for signed and mp_uint_t for unsigned integer values. These are guaranteed to be machine-word sized and therefore big enough to hold the value from a MicroPython small-int @@ -216,11 +273,13 @@ general guidelines are: - You can use int/uint, but remember that they may be 16-bits wide. - If in doubt, use mp_int_t/mp_uint_t. -Comments: +## Comments + - Be concise and only write comments for things that are not obvious. - Use `// ` prefix, NOT `/* ... */`. No extra fluff. -Memory allocation: +## Memory allocation + - Use m_new, m_renew, m_del (and friends) to allocate and free heap memory. These macros are defined in py/misc.h. @@ -255,7 +314,7 @@ Documentation conventions ========================= MicroPython generally follows CPython in documentation process and -conventions. reStructuredText syntax is used for the documention. +conventions. reStructuredText syntax is used for the documentation. Specific conventions/suggestions: diff --git a/LICENSE b/LICENSE index 3a2f15d1f41be..929a2e97de7bf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2023 Damien P. George +Copyright (c) 2013-2025 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 @@ -36,7 +36,6 @@ used during the build process and is not part of the compiled source code. / (MIT) /drivers /cc3100 (BSD-3-clause) - /wiznet5k (BSD-3-clause) /lib /asf4 (Apache-2.0) /axtls (BSD-3-clause) @@ -49,24 +48,31 @@ used during the build process and is not part of the compiled source code. /cmsis (BSD-3-clause) /crypto-algorithms (NONE) /libhydrogen (ISC) + /libmetal (BSD-3-clause) /littlefs (BSD-3-clause) /lwip (BSD-3-clause) /mynewt-nimble (Apache-2.0) /nrfx (BSD-3-clause) /nxp_driver (BSD-3-Clause) /oofatfs (BSD-1-clause) + /open-amp (BSD-3-clause) /pico-sdk (BSD-3-clause) /re15 (BSD-3-clause) /stm32lib (BSD-3-clause) - /tinytest (BSD-3-clause) /tinyusb (MIT) /uzlib (Zlib) + /wiznet5k (MIT) /logo (uses OFL-1.1) /ports /cc3200 /hal (BSD-3-clause) /simplelink (BSD-3-clause) /FreeRTOS (GPL-2.0 with FreeRTOS exception) + /esp32 + /ppp_set_auth.* (Apache-2.0) + /rp2 + /mutex_extra.c (BSD-3-clause) + /clocks_extra.c (BSD-3-clause) /stm32 /usbd*.c (MCD-ST Liberty SW License Agreement V2) /stm32_it.* (MIT + BSD-3-clause) @@ -76,8 +82,6 @@ used during the build process and is not part of the compiled source code. /*/stm32*.h (BSD-3-clause) /usbdev (MCD-ST Liberty SW License Agreement V2) /usbhost (MCD-ST Liberty SW License Agreement V2) - /teensy - /core (PJRC.COM) /zephyr /src (Apache-2.0) /tools diff --git a/README.md b/README.md index 6482899b251d9..c78a2384604fe 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![CI badge](https://github.com/micropython/micropython/workflows/unix%20port/badge.svg)](https://github.com/micropython/micropython/actions?query=branch%3Amaster+event%3Apush) [![codecov](https://codecov.io/gh/micropython/micropython/branch/master/graph/badge.svg?token=I92PfD05sD)](https://codecov.io/gh/micropython/micropython) +[![Unix CI badge](https://github.com/micropython/micropython/actions/workflows/ports_unix.yml/badge.svg)](https://github.com/micropython/micropython/actions?query=branch%3Amaster+event%3Apush) [![STM32 CI badge](https://github.com/micropython/micropython/actions/workflows/ports_stm32.yml/badge.svg)](https://github.com/micropython/micropython/actions?query=branch%3Amaster+event%3Apush) [![Docs CI badge](https://github.com/micropython/micropython/actions/workflows/docs.yml/badge.svg)](https://docs.micropython.org/) [![codecov](https://codecov.io/gh/micropython/micropython/branch/master/graph/badge.svg?token=I92PfD05sD)](https://codecov.io/gh/micropython/micropython) The MicroPython project ======================= @@ -19,7 +19,7 @@ Python 3.5 and some select features from later versions). The following core datatypes are provided: `str`(including basic Unicode support), `bytes`, `bytearray`, `tuple`, `list`, `dict`, `set`, `frozenset`, `array.array`, `collections.namedtuple`, classes and instances. Builtin modules include -`os`, `sys`, `time`, `re`, and `struct`, etc. Select ports have support for +`os`, `sys`, `time`, `re`, and `struct`, etc. Some ports have support for `_thread` module (multithreading), `socket` and `ssl` for networking, and `asyncio`. Note that only a subset of Python 3 functionality is implemented for the data types and modules. @@ -35,8 +35,8 @@ DAC, PWM, SPI, I2C, CAN, Bluetooth, and USB. Getting started --------------- -See the [online documentation](https://docs.micropython.org/) for API -references and information about using MicroPython and information about how +See the [online documentation](https://docs.micropython.org/) for the API +reference and information about using MicroPython and information about how it is implemented. We use [GitHub Discussions](https://github.com/micropython/micropython/discussions) @@ -108,18 +108,17 @@ track of the code size of the core runtime and VM. In addition, the following ports are provided in this repository: - [cc3200](ports/cc3200) -- Texas Instruments CC3200 (including PyCom WiPy). - - [esp32](ports/esp32) -- Espressif ESP32 SoC (including ESP32S2, ESP32S3, ESP32C3). + - [esp32](ports/esp32) -- Espressif ESP32 SoC (including ESP32S2, ESP32S3, ESP32C3, ESP32C6). - [esp8266](ports/esp8266) -- Espressif ESP8266 SoC. - [mimxrt](ports/mimxrt) -- NXP m.iMX RT (including Teensy 4.x). - [nrf](ports/nrf) -- Nordic Semiconductor nRF51 and nRF52. - [pic16bit](ports/pic16bit) -- Microchip PIC 16-bit. - [powerpc](ports/powerpc) -- IBM PowerPC (including Microwatt) - - [qemu-arm](ports/qemu-arm) -- QEMU-based emulated target, for testing) + - [qemu](ports/qemu) -- QEMU-based emulated target (for testing) - [renesas-ra](ports/renesas-ra) -- Renesas RA family. - [rp2](ports/rp2) -- Raspberry Pi RP2040 (including Pico and Pico W). - [samd](ports/samd) -- Microchip (formerly Atmel) SAMD21 and SAMD51. - [stm32](ports/stm32) -- STMicroelectronics STM32 family (including F0, F4, F7, G0, G4, H7, L0, L4, WB) - - [teensy](ports/teensy) -- Teensy 3.x. - [webassembly](ports/webassembly) -- Emscripten port targeting browsers and NodeJS. - [zephyr](ports/zephyr) -- Zephyr RTOS. diff --git a/docs/conf.py b/docs/conf.py index 933e7b34b2741..eb61487582024 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,55 +19,59 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(".")) + +# The MICROPY_VERSION env var should be "vX.Y.Z" (or unset). +micropy_version = os.getenv("MICROPY_VERSION") or "latest" +micropy_all_versions = (os.getenv("MICROPY_ALL_VERSIONS") or "latest").split(",") +url_pattern = "%s/en/%%s" % (os.getenv("MICROPY_URL_PREFIX") or "/",) # The members of the html_context dict are available inside topindex.html -micropy_version = os.getenv('MICROPY_VERSION') or 'latest' -micropy_all_versions = (os.getenv('MICROPY_ALL_VERSIONS') or 'latest').split(',') -url_pattern = '%s/en/%%s' % (os.getenv('MICROPY_URL_PREFIX') or '/',) html_context = { - 'cur_version':micropy_version, - 'all_versions':[ - (ver, url_pattern % ver) for ver in micropy_all_versions - ], - 'downloads':[ - ('PDF', url_pattern % micropy_version + '/micropython-docs.pdf'), + "cur_version": micropy_version, + "all_versions": [(ver, url_pattern % ver) for ver in micropy_all_versions], + "downloads": [ + ("PDF", url_pattern % micropy_version + "/micropython-docs.pdf"), ], - 'is_release': micropy_version != 'latest', + "is_release": micropy_version != "latest", } +# Authors used in various parts of the documentation. +micropy_authors = "MicroPython authors and contributors" + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.coverage", + "sphinxcontrib.jquery", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['templates'] +templates_path = ["templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'MicroPython' -copyright = '- The MicroPython Documentation is Copyright © 2014-2023, Damien P. George, Paul Sokolovsky, and contributors' +project = "MicroPython" +copyright = "- The MicroPython Documentation is Copyright © 2014-2025, " + micropy_authors # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -79,41 +83,41 @@ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['build', '.venv'] +exclude_patterns = ["build", ".venv"] # The reST default role (used for this markup: `text`) to use for all # documents. -default_role = 'any' +default_role = "any" # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# keep_warnings = False # Global include files. Sphinx docs suggest using rst_epilog in preference # of rst_prolog, so we follow. Absolute paths below mean "from the base @@ -125,144 +129,148 @@ # -- Options for HTML output ---------------------------------------------- # on_rtd is whether we are on readthedocs.org -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" if not on_rtd: # only import and set the theme if we're building docs locally try: import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.'] + + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] except: - html_theme = 'default' - html_theme_path = ['.'] + html_theme = "default" + html_theme_path = ["."] else: - html_theme_path = ['.'] + html_theme_path = ["."] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = ['.'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = '../../logo/trans-logo.png' +# html_logo = '../../logo/trans-logo.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = 'static/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, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['static'] +html_static_path = ["static"] # Add a custom CSS file for HTML generation html_css_files = [ - 'custom.css', + "custom.css", ] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. -#html_extra_path = [] +# html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -html_last_updated_fmt = '%d %b %Y' +html_last_updated_fmt = "%d %b %Y" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. html_additional_pages = {"index": "topindex.html"} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'MicroPythondoc' +htmlhelp_basename = "MicroPythondoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -# Include 3 levels of headers in PDF ToC -'preamble': '\setcounter{tocdepth}{2}', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', + # Include 3 levels of headers in PDF ToC + "preamble": r"\setcounter{tocdepth}{2}", } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'MicroPython.tex', 'MicroPython Documentation', - 'Damien P. George, Paul Sokolovsky, and contributors', 'manual'), + ( + master_doc, + "MicroPython.tex", + "MicroPython Documentation", + micropy_authors, + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # Enable better Unicode support so that `make latexpdf` doesn't fail latex_engine = "xelatex" @@ -272,12 +280,17 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'micropython', 'MicroPython Documentation', - ['Damien P. George, Paul Sokolovsky, and contributors'], 1), + ( + "index", + "micropython", + "MicroPython Documentation", + [micropy_authors], + 1, + ), ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------- @@ -286,23 +299,29 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'MicroPython', 'MicroPython Documentation', - 'Damien P. George, Paul Sokolovsky, and contributors', 'MicroPython', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "MicroPython", + "MicroPython Documentation", + micropy_authors, + "MicroPython", + "One line description of project.", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'python': ('https://docs.python.org/3.5', None)} +intersphinx_mapping = {"python": ("https://docs.python.org/3.5", None)} diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index 6bc2f62ab4d5a..c5aa919b7645a 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -53,13 +53,13 @@ A MicroPython user C module is a directory with the following files: ``SRC_USERMOD_C`` or ``SRC_USERMOD_LIB_C`` variables. The former will be processed for ``MP_QSTR_`` and ``MP_REGISTER_MODULE`` definitions, the latter will not (e.g. helpers and library code that isn't MicroPython-specific). - These paths should include your expaned copy of ``$(USERMOD_DIR)``, e.g.:: + These paths should include your expanded copy of ``$(USERMOD_DIR)``, e.g.:: SRC_USERMOD_C += $(EXAMPLE_MOD_DIR)/modexample.c SRC_USERMOD_LIB_C += $(EXAMPLE_MOD_DIR)/utils/algorithm.c Similarly, use ``SRC_USERMOD_CXX`` and ``SRC_USERMOD_LIB_CXX`` for C++ - source files. + source files. If you want to include assembly files use ``SRC_USERMOD_LIB_ASM``. If you have custom compiler options (like ``-I`` to add directories to search for header files), these should be added to ``CFLAGS_USERMOD`` for C code diff --git a/docs/develop/compiler.rst b/docs/develop/compiler.rst index cac92585ff4ee..0c25ad3a01ef1 100644 --- a/docs/develop/compiler.rst +++ b/docs/develop/compiler.rst @@ -98,7 +98,7 @@ Then also edit ``py/lexer.c`` to add the new keyword literal text: .. code-block:: c :emphasize-lines: 12 - STATIC const char *const tok_kw[] = { + static const char *const tok_kw[] = { ... "or", "pass", @@ -157,7 +157,7 @@ The most relevant method you should know about is this: mp_compile_to_raw_code(parse_tree, source_file, is_repl, &cm); // Create and return a function object that executes the outer module. - return mp_make_function_from_raw_code(cm.rc, cm.context, NULL); + return mp_make_function_from_proto_fun(cm.rc, cm.context, NULL); } The compiler compiles the code in four passes: scope, stack size, code size and emit. @@ -301,7 +301,7 @@ code statement: .. code-block:: c - STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { + static void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_2); if (vtype == VTYPE_PYOBJ) { diff --git a/docs/develop/gettingstarted.rst b/docs/develop/gettingstarted.rst index c2d3816d425a4..fed632ea1ac15 100644 --- a/docs/develop/gettingstarted.rst +++ b/docs/develop/gettingstarted.rst @@ -100,7 +100,7 @@ For the stm32 port, the ARM cross-compiler is required: .. code-block:: bash - $ sudo apt-get install arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-newlib + $ sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi See the `ARM GCC toolchain `_ @@ -112,7 +112,7 @@ Check that you have Python available on your system: .. code-block:: bash $ python3 - Python 3.5.0 (default, Jul 17 2020, 14:04:10) + Python 3.5.0 (default, Jul 17 2020, 14:04:10) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> @@ -228,7 +228,7 @@ You can also specify which board to use: .. code-block:: bash $ cd ports/stm32 - $ make submodules + $ make BOARD= submodules $ make BOARD= See `ports/stm32/boards `_ @@ -245,7 +245,7 @@ that you use a virtual environment: $ python3 -m venv env $ source env/bin/activate - $ pip install sphinx + $ pip install -r docs/requirements.txt Navigate to the ``docs`` directory: @@ -278,7 +278,7 @@ To run a selection of tests on a board/device connected over USB use: .. code-block:: bash $ cd tests - $ ./run-tests.py --target minimal --device /dev/ttyACM0 + $ ./run-tests.py -t /dev/ttyACM0 See also :ref:`writingtests`. diff --git a/docs/develop/library.rst b/docs/develop/library.rst index c2a86ea1699bc..830211d81c862 100644 --- a/docs/develop/library.rst +++ b/docs/develop/library.rst @@ -48,16 +48,16 @@ hypothetical new module ``subsystem`` in the file ``modsubsystem.c``: #if MICROPY_PY_SUBSYSTEM // info() - STATIC mp_obj_t py_subsystem_info(void) { + static mp_obj_t py_subsystem_info(void) { return MP_OBJ_NEW_SMALL_INT(42); } MP_DEFINE_CONST_FUN_OBJ_0(subsystem_info_obj, py_subsystem_info); - STATIC const mp_rom_map_elem_t mp_module_subsystem_globals_table[] = { + static const mp_rom_map_elem_t mp_module_subsystem_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_subsystem) }, { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&subsystem_info_obj) }, }; - STATIC MP_DEFINE_CONST_DICT(mp_module_subsystem_globals, mp_module_subsystem_globals_table); + static MP_DEFINE_CONST_DICT(mp_module_subsystem_globals, mp_module_subsystem_globals_table); const mp_obj_module_t mp_module_subsystem = { .base = { &mp_type_module }, diff --git a/docs/develop/natmod.rst b/docs/develop/natmod.rst index 6d15f867bcfe8..18678eaefbf11 100644 --- a/docs/develop/natmod.rst +++ b/docs/develop/natmod.rst @@ -39,7 +39,8 @@ options for the ``ARCH`` variable, see below): * ``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) +* ``xtensawin`` (windowed with window size 8, eg ESP32, ESP32S3) +* ``rv32imc`` (RISC-V 32 bits with compressed instructions, eg ESP32C3, ESP32C6) 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 @@ -69,6 +70,13 @@ The known limitations are: So, if your C code has writable data, make sure the data is defined globally, without an initialiser, and only written to within functions. +The native module is not automatically linked against the standard static libraries +like ``libm.a`` and ``libgcc.a``, which can lead to ``undefined symbol`` errors. +You can link the runtime libraries by setting ``LINK_RUNTIME = 1`` +in your Makefile. Custom static libraries can also be linked by adding +``MPY_LD_FLAGS += -l path/to/library.a``. Note that these are linked into +the native module and will not be shared with other modules or the system. + 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 @@ -128,7 +136,7 @@ The file ``factorial.c`` contains: #include "py/dynruntime.h" // Helper function to compute factorial - STATIC mp_int_t factorial_helper(mp_int_t x) { + static mp_int_t factorial_helper(mp_int_t x) { if (x == 0) { return 1; } @@ -136,7 +144,7 @@ The file ``factorial.c`` contains: } // This is the function which will be called from Python, as factorial(x) - STATIC mp_obj_t factorial(mp_obj_t x_obj) { + 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 @@ -145,7 +153,7 @@ The file ``factorial.c`` contains: return mp_obj_new_int(result); } // Define a Python reference to the function above - STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial); + 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) { @@ -172,7 +180,7 @@ The file ``Makefile`` contains: # Source files (.c or .py) SRC = factorial.c - # Architecture to build for (x86, x64, armv6m, armv7m, xtensa, xtensawin) + # Architecture to build for (x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/docs/develop/optimizations.rst b/docs/develop/optimizations.rst index 7f2c8cbe7282c..533dd64116f03 100644 --- a/docs/develop/optimizations.rst +++ b/docs/develop/optimizations.rst @@ -33,7 +33,7 @@ Variables MicroPython processes local and global variables differently. Global variables are stored and looked up from a global dictionary that is allocated on the heap (note that each module has its own separate dict, so separate namespace). -Local variables on the other hand are are stored on the Python value stack, which may +Local variables on the other hand are stored on the Python value stack, which may live on the C stack or on the heap. They are accessed directly by their offset within the Python stack, which is more efficient than a global lookup in a dict. diff --git a/docs/develop/porting.rst b/docs/develop/porting.rst index 74974a39e1b4d..99725e1000bef 100644 --- a/docs/develop/porting.rst +++ b/docs/develop/porting.rst @@ -38,6 +38,7 @@ The basic MicroPython firmware is implemented in the main port file, e.g ``main. .. code-block:: c + #include "py/builtin.h" #include "py/compile.h" #include "py/gc.h" #include "py/mperrno.h" @@ -82,7 +83,7 @@ The basic MicroPython firmware is implemented in the main port file, e.g ``main. } // There is no filesystem so opening a file raises an exception. - mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_lexer_t *mp_lexer_new_from_file(qstr filename) { mp_raise_OSError(MP_ENOENT); } @@ -110,6 +111,9 @@ We also need a Makefile at this point for the port: shared/runtime/pyexec.c \ shared/runtime/stdout_helpers.c \ + # Define source files containung qstrs. + SRC_QSTR += shared/readline/readline.c shared/runtime/pyexec.c + # Define the required object files. OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) @@ -147,9 +151,6 @@ The following is an example of an ``mpconfigport.h`` file: #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) - // Enable u-modules to be imported with their standard name, like sys. - #define MICROPY_MODULE_WEAK_LINKS (1) - // Fine control over Python builtins, classes, modules, etc. #define MICROPY_PY_ASYNC_AWAIT (0) #define MICROPY_PY_BUILTINS_SET (0) @@ -261,17 +262,17 @@ To add a custom module like ``myport``, first add the module definition in a fil #include "py/runtime.h" - STATIC mp_obj_t myport_info(void) { + static mp_obj_t myport_info(void) { mp_printf(&mp_plat_print, "info about my port\n"); return mp_const_none; } - STATIC MP_DEFINE_CONST_FUN_OBJ_0(myport_info_obj, myport_info); + static MP_DEFINE_CONST_FUN_OBJ_0(myport_info_obj, myport_info); - STATIC const mp_rom_map_elem_t myport_module_globals_table[] = { + static const mp_rom_map_elem_t myport_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_myport) }, { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&myport_info_obj) }, }; - STATIC MP_DEFINE_CONST_DICT(myport_module_globals, myport_module_globals_table); + static MP_DEFINE_CONST_DICT(myport_module_globals, myport_module_globals_table); const mp_obj_module_t myport_module = { .base = { &mp_type_module }, diff --git a/docs/develop/writingtests.rst b/docs/develop/writingtests.rst index 9bb5178f55f22..a7d033f17e9b9 100644 --- a/docs/develop/writingtests.rst +++ b/docs/develop/writingtests.rst @@ -60,7 +60,7 @@ Then to run on a board: .. code-block:: bash - $ ./run-tests.py --target minimal --device /dev/ttyACM0 + $ ./run-tests.py -t /dev/ttyACM0 And to run only a certain set of tests (eg a directory): diff --git a/docs/differences/modules_preamble.txt b/docs/differences/modules_preamble.txt new file mode 100644 index 0000000000000..1958f0084d2db --- /dev/null +++ b/docs/differences/modules_preamble.txt @@ -0,0 +1,33 @@ +.. Preamble section inserted into generated output + +Positional-only Parameters +-------------------------- + +To save code size, many functions that accept keyword arguments in CPython only accept positional arguments in MicroPython. + +MicroPython marks positional-only parameters in the same way as CPython, by inserting a ``/`` to mark the end of the positional parameters. Any function whose signature ends in ``/`` takes *only* positional arguments. For more details, see `PEP 570 `_. + +Example +~~~~~~~ + +For example, in CPython 3.4 this is the signature of the constructor ``socket.socket``:: + + socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) + +However, the signature documented in :func:`MicroPython` is:: + + socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, /) + +The ``/`` at the end of the parameters indicates that they are all positional-only in MicroPython. The following code works in CPython but not in most MicroPython ports:: + + import socket + s = socket.socket(type=socket.SOCK_DGRAM) + +MicroPython will raise an exception:: + + TypeError: function doesn't take keyword arguments + +The following code will work in both CPython and MicroPython:: + + import socket + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) diff --git a/docs/differences/python_37.rst b/docs/differences/python_37.rst index 86d1b6e81f96d..2b9a089217f6d 100644 --- a/docs/differences/python_37.rst +++ b/docs/differences/python_37.rst @@ -105,4 +105,4 @@ Changes to built-in modules: .. rubric:: Notes -.. [#ftimenanosec] Only :func:`time.time_ns` is implemented. +.. [#ftimenanosec] Only :func:`time.time_ns` is implemented. diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index f74926c374602..ccc01099d17f9 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -18,6 +18,9 @@ working with this board it may be useful to get an overview of the microcontroll general.rst tutorial/index.rst +Note that there are several varieties of ESP32 -- ESP32, ESP32C3, ESP32C6, ESP32S2, ESP32S3 -- +supported by MicroPython, with some differences in functionality between them. + Installing MicroPython ---------------------- @@ -57,52 +60,57 @@ The :mod:`esp32` module:: import esp32 - esp32.hall_sensor() # read the internal hall sensor esp32.raw_temperature() # read the internal temperature of the MCU, in Fahrenheit - esp32.ULP() # access to the Ultra-Low-Power Co-processor + esp32.ULP() # access to the Ultra-Low-Power Co-processor, not on ESP32C3/C6 Note that the temperature sensor in the ESP32 will typically read higher than ambient due to the IC getting warm while it runs. This effect can be minimised by reading the temperature sensor immediately after waking up from sleep. +ESP32C3, ESP32C6, ESP32S2, and ESP32S3 also have an internal temperature sensor available. +It is implemented a bit differently to the ESP32 and returns the temperature in +Celsius:: + + esp32.mcu_temperature() # read the internal temperature of the MCU, in Celsius + Networking ---------- WLAN ^^^^ -The :mod:`network` module:: +The :class:`network.WLAN` class in the :mod:`network` module:: import network - wlan = network.WLAN(network.STA_IF) # create station interface - wlan.active(True) # activate the interface - wlan.scan() # scan for access points - wlan.isconnected() # check if the station is connected to an AP + wlan = network.WLAN() # create station interface (the default, see below for an access point interface) + wlan.active(True) # activate the interface + wlan.scan() # scan for access points + wlan.isconnected() # check if the station is connected to an AP wlan.connect('ssid', 'key') # connect to an AP - wlan.config('mac') # get the interface's MAC address - wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses + wlan.config('mac') # get the interface's MAC address + wlan.ipconfig('addr4') # get the interface's IPv4 addresses - ap = network.WLAN(network.AP_IF) # create access-point interface - ap.config(ssid='ESP-AP') # set the SSID of the access point - ap.config(max_clients=10) # set how many clients can connect to the network - ap.active(True) # activate the interface + ap = network.WLAN(network.WLAN.IF_AP) # create access-point interface + ap.config(ssid='ESP-AP') # set the SSID 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:: def do_connect(): - import network - wlan = network.WLAN(network.STA_IF) + import machine, network + wlan = network.WLAN() wlan.active(True) if not wlan.isconnected(): print('connecting to network...') wlan.connect('ssid', 'key') while not wlan.isconnected(): - pass - print('network config:', wlan.ifconfig()) + machine.idle() + print('network config:', wlan.ipconfig('addr4')) Once the network is established the :mod:`socket ` module can be used -to create and use TCP/UDP sockets as usual, and the ``urequests`` module for +to create and use TCP/UDP sockets as usual, and the ``requests`` module for convenient HTTP requests. After a call to ``wlan.connect()``, the device will by default retry to connect @@ -113,44 +121,60 @@ calling ``wlan.config(reconnects=n)``, where n are the number of desired reconne attempts (0 means it won't retry, -1 will restore the default behaviour of trying to reconnect forever). +.. _esp32_network_lan: + LAN ^^^ -To use the wired interfaces one has to specify the pins and mode :: +Built-in MAC (original ESP32) +""""""""""""""""""""""""""""" + +The original ESP32 SoC has a built-in Ethernet MAC. Using this MAC requires an +external Ethernet PHY to be wired to the chip's EMAC pins. Most of the EMAC pin +assignments are fixed, consult the ESP32 datasheet for details. + +If the PHY is connected, the internal Ethernet MAC can be configured via +the :class:`network.LAN` constructor:: import network lan = network.LAN(mdc=PIN_MDC, ...) # Set the pin and mode configuration lan.active(True) # activate the interface - lan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses + lan.ipconfig('addr4') # get the interface's IPv4 addresses + +Required keyword arguments for the constructor: -The keyword arguments for the constructor defining the PHY type and interface are: +- ``mdc`` and ``mdio`` - :class:`machine.Pin` objects (or integers) specifying + the MDC and MDIO pins. +- ``phy_type`` - Select the PHY device type. Supported devices are + ``PHY_LAN8710``, ``PHY_LAN8720``, ``PHY_IP101``, ``PHY_RTL8201``, + ``PHY_DP83848``, ``PHY_KSZ8041`` and ``PHY_KSZ8081``. These values are all + constants defined in the ``network`` module. +- ``phy_addr`` - The address number of the PHY device. Must be an integer in the + range 0x00 to 0x1f, inclusive. Common values are ``0`` and ``1``. -- mdc=pin-object # set the mdc and mdio pins. -- mdio=pin-object -- power=pin-object # set the pin which switches the power of the PHY device. -- phy_type= # Select the PHY device type. Supported devices are PHY_LAN8710, - PHY_LAN8720, PH_IP101, PHY_RTL8201, PHY_DP83848 and PHY_KSZ8041 -- phy_addr=number # The address number of the PHY device. -- ref_clk_mode=mode # Defines, whether the ref_clk at the ESP32 is an input - or output. Suitable values are Pin.IN and Pin.OUT. -- ref_clk=pin-object # defines the Pin used for ref_clk. +All of the above keyword arguments must be present to configure the interface. -The options ref_clk_mode and ref_clk require at least esp-idf version 4.4. For -earlier esp-idf versions, these parameters must be defined by kconfig board options. +Optional keyword arguments: -These are working configurations for LAN interfaces of popular boards:: +- ``reset`` - :class:`machine.Pin` object (or integer) specifying the PHY reset pin. +- ``power`` - :class:`machine.Pin` object (or integer) specifying a pin which + switches the power of the PHY device. +- ``ref_clk`` - :class:`machine.Pin` object (or integer) specifying the pin used + for the EMAC ``ref_clk`` signal. If not specified, the board default is used + (typically GPIO 0, but may be different if a particular board has Ethernet.) +- ``ref_clk_mode`` - Defines whether the EMAC ``ref_clk`` pin of the ESP32 + should be an input or an output. Suitable values are ``machine.Pin.IN`` and + ``machine.Pin.OUT``. If not specified, the board default is used + (typically input, but may be different if a particular board has Ethernet.) + +These are working configurations for LAN interfaces of some popular ESP32 boards:: # Olimex ESP32-GATEWAY: power controlled by Pin(5) # Olimex ESP32 PoE and ESP32-PoE ISO: power controlled by Pin(12) lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5), - phy_type=network.PHY_LAN8720, phy_addr=0) - - # or with dynamic ref_clk pin configuration - - lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5), phy_type=network.PHY_LAN8720, phy_addr=0, ref_clk=machine.Pin(17), ref_clk_mode=machine.Pin.OUT) @@ -159,20 +183,76 @@ These are working configurations for LAN interfaces of popular boards:: lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), phy_type=network.PHY_LAN8720, phy_addr=1, power=None) + # Wireless-Tag's WT32-ETH01 v1.4 + + lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), + phy_type=network.PHY_LAN8720, phy_addr=1, + power=machine.Pin(16)) + # Espressif ESP32-Ethernet-Kit_A_V1.2 lan = network.LAN(id=0, mdc=Pin(23), mdio=Pin(18), power=Pin(5), phy_type=network.PHY_IP101, phy_addr=1) -A suitable definition of the PHY interface in a sdkconfig.board file is:: - CONFIG_ETH_PHY_INTERFACE_RMII=y - CONFIG_ETH_RMII_CLK_OUTPUT=y - CONFIG_ETH_RMII_CLK_OUT_GPIO=17 - CONFIG_LWIP_LOCAL_HOSTNAME="ESP32_POE" +.. _esp32_spi_ethernet: + +SPI Ethernet Interface +"""""""""""""""""""""" + +All ESP32 SoCs support external SPI Ethernet interface chips. These are Ethernet +interfaces that connect via a SPI bus, rather than an Ethernet RMII interface. + +.. note:: The only exception is the ESP32 ``d2wd`` variant, where this feature is disabled + to save code size. + +SPI Ethernet uses the same :class:`network.LAN` constructor, with a different +set of keyword arguments:: + + import machine, network -The value assigned to CONFIG_ETH_RMII_CLK_OUT_GPIO may vary depending on the -board's wiring. + spi = machine.SPI(1, sck=SCK_PIN, mosi=MOSI_PIN, miso=MISO_PIN) + lan = network.LAN(spi=spi, cs=CS_PIN, ...) # Set the pin and mode configuration + lan.active(True) # activate the interface + lan.ipconfig('addr4') # get the interface's IPv4 addresses + +Required keyword arguments for the constructor: + +- ``spi`` - Should be a :class:`machine.SPI` object configured for this + connection. Note that any clock speed configured on the SPI object is ignored, + the SPI Ethernet clock speed is configured at compile time. +- ``cs`` - :class:`machine.Pin` object (or integer) specifying the CS pin + connected to the interface. +- ``int`` - :class:`machine.Pin` object (or integer) specifying the INT pin + connected to the interface. +- ``phy_type`` - Select the SPI Ethernet interface type. Supported devices are + ``PHY_KSZ8851SNL``, ``PHY_DM9051``, ``PHY_W5500``. These values are all + constants defined in the ``network`` module. +- ``phy_addr`` - The address number of the PHY device. Must be an integer in the + range 0x00 to 0x1f, inclusive. This is usually ``0`` for SPI Ethernet devices. + +All of the above keyword arguments must be present to configure the interface. + +Optional keyword arguments for the constructor: + +- ``reset`` - :class:`machine.Pin` object (or integer) specifying the SPI Ethernet + interface reset pin. +- ``power`` - :class:`machine.Pin` object (or integer) specifying a pin which + switches the power of the SPI Ethernet interface. + +Here is a sample configuration for a WIZNet W5500 chip connected to pins on +an ESP32-S3 development board:: + + import machine, network + from machine import Pin, SPI + + spi = SPI(1, sck=Pin(12), mosi=Pin(13), miso=Pin(14)) + lan = network.LAN(spi=spi, phy_type=network.PHY_W5500, phy_addr=0, + cs=Pin(10), int=Pin(11)) + +.. note:: WIZnet W5500 Ethernet is also supported on some other MicroPython + ports, but using a :ref:`different software interface + `. Delay and timing ---------------- @@ -305,8 +385,8 @@ Use the :ref:`machine.PWM ` class:: from machine import Pin, PWM - pwm0 = PWM(Pin(0)) # create PWM object from a pin - freq = pwm0.freq() # get current frequency (default 5kHz) + pwm0 = PWM(Pin(0), freq=5000, duty_u16=32768) # create PWM object from a pin + freq = pwm0.freq() # get current frequency pwm0.freq(1000) # set PWM frequency from 1Hz to 40MHz duty = pwm0.duty() # get current duty cycle, range 0-1023 (default 512, 50%) @@ -343,6 +423,19 @@ possible at the same frequency. See more examples in the :ref:`esp32_pwm` tutorial. +DAC (digital to analog conversion) +---------------------------------- + +On the ESP32, DAC functionality is available on pins 25, 26. +On the ESP32S2, DAC functionality is available on pins 17, 18. + +Use the DAC:: + + from machine import DAC, Pin + + dac = DAC(Pin(25)) # create an DAC object acting on a pin + dac.write(128) # set a raw analog value in the range 0-255, 50% now + ADC (analog to digital conversion) ---------------------------------- @@ -566,7 +659,9 @@ See :ref:`machine.RTC ` :: from machine import RTC rtc = RTC() - rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time + rtc.datetime((2017, 8, 23, 0, 1, 12, 48, 0)) # set a specific date and + # time, eg. 2017/8/23 1:12:48 + # the day-of-week value is ignored rtc.datetime() # get date and time WDT (Watchdog timer) @@ -650,15 +745,15 @@ SD card See :ref:`machine.SDCard `. :: - import machine, os + import machine, os, vfs - # Slot 2 uses pins sck=18, cs=5, miso=19, mosi=23 + # On original ESP32, slot 2 uses pins sck=18, cs=5, miso=19, mosi=23 sd = machine.SDCard(slot=2) - os.mount(sd, '/sd') # mount + vfs.mount(sd, '/sd') # mount os.listdir('/sd') # list directory contents - os.umount('/sd') # eject + vfs.umount('/sd') # eject RMT --- @@ -740,20 +835,33 @@ APA102 (DotStar) uses a different driver as it has an additional clock pin. Capacitive touch ---------------- -Use the ``TouchPad`` class in the ``machine`` module:: +ESP32, ESP32-S2 and ESP32-S3 support capacitive touch via the ``TouchPad`` class +in the ``machine`` module:: from machine import TouchPad, Pin t = TouchPad(Pin(14)) t.read() # Returns a smaller number when touched -``TouchPad.read`` returns a value relative to the capacitive variation. Small numbers (typically in -the *tens*) are common when a pin is touched, larger numbers (above *one thousand*) when -no touch is present. However the values are *relative* and can vary depending on the board -and surrounding composition so some calibration may be required. - -There are ten capacitive touch-enabled pins that can be used on the ESP32: 0, 2, 4, 12, 13 -14, 15, 27, 32, 33. Trying to assign to any other pins will result in a ``ValueError``. +``TouchPad.read`` returns a value proportional to the capacitance between the +pin and the board's Ground connection. On ESP32 the number becomes smaller when +the pin (or connected touch pad) is touched, on ESP32-S2 and ESP32-S3 the number +becomes larger when the pin is touched. + +In all cases, a touch causes a significant change in the return value. Note the +returned values are *relative* and can vary depending on the board and +surrounding environment so some calibration (i.e. comparison to a baseline or +rolling average) may be required. + +========= ============================================== +Chip Touch-enabled pins +--------- ---------------------------------------------- +ESP32 0, 2, 4, 12, 13, 14, 15, 27, 32, 33 +ESP32-S2 1 to 14 inclusive +ESP32-S3 1 to 14 inclusive +========= ============================================== + +Trying to assign to any other pins will result in a ``ValueError``. Note that TouchPads can be used to wake an ESP32 from sleep:: diff --git a/docs/esp32/tutorial/img/mem32_gpio_output.jpg b/docs/esp32/tutorial/img/mem32_gpio_output.jpg new file mode 100755 index 0000000000000..5544202871eb7 Binary files /dev/null and b/docs/esp32/tutorial/img/mem32_gpio_output.jpg differ diff --git a/docs/esp32/tutorial/index.rst b/docs/esp32/tutorial/index.rst index c6242d731f180..2435f2ecd2f59 100644 --- a/docs/esp32/tutorial/index.rst +++ b/docs/esp32/tutorial/index.rst @@ -21,3 +21,4 @@ to ``__. intro.rst pwm.rst peripheral_access.rst + reset.rst diff --git a/docs/esp32/tutorial/intro.rst b/docs/esp32/tutorial/intro.rst index 8ed42dbd3dc95..599731ad755af 100644 --- a/docs/esp32/tutorial/intro.rst +++ b/docs/esp32/tutorial/intro.rst @@ -17,7 +17,7 @@ Requirements The first thing you need is a board with an ESP32 chip. The MicroPython software supports the ESP32 chip itself and any board should work. The main characteristic of a board is how the GPIO pins are connected to the outside -world, and whether it includes a built-in USB-serial convertor to make the +world, and whether it includes a built-in USB-serial converter to make the UART available to your PC. Names of pins will be given in this tutorial using the chip names (eg GPIO2) @@ -36,104 +36,95 @@ Getting the firmware The first thing you need to do is download the most recent MicroPython firmware .bin file to load onto your ESP32 device. You can download it from the -`MicroPython downloads page `_. -From here, you have 3 main choices: +`MicroPython download page`_. Search for your particular board on this page. -* Stable firmware builds -* Daily firmware builds -* Daily firmware builds with SPIRAM support +.. note:: If you don't see your specific board on the download page, then it's + very likely that one of the generic firmwares will work. These are + listed at the top of the download page and have names matching the + onboard Espressif chip (i.e. `ESP32 / WROOM`_, `ESP32-C3`_, + `ESP32-S3`_, etc). -If you are just starting with MicroPython, the best bet is to go for the Stable -firmware builds. If you are an advanced, experienced MicroPython ESP32 user -who would like to follow development closely and help with testing new -features, there are daily builds. If your board has SPIRAM support you can -use either the standard firmware or the firmware with SPIRAM support, and in -the latter case you will have access to more RAM for Python objects. + However, you may need to double check with the vendor you purchased + the board from. -Deploying the firmware ----------------------- - -Once you have the MicroPython firmware you need to load it onto your ESP32 device. -There are two main steps to do this: first you need to put your device in -bootloader mode, and second you need to copy across the firmware. The exact -procedure for these steps is highly dependent on the particular board and you will -need to refer to its documentation for details. +From here, you have a choice to make: -Fortunately, most boards have a USB connector, a USB-serial convertor, and the DTR -and RTS pins wired in a special way then deploying the firmware should be easy as -all steps can be done automatically. Boards that have such features -include the Adafruit Feather HUZZAH32, M5Stack, Wemos LOLIN32, and TinyPICO -boards, along with the Espressif DevKitC, PICO-KIT, WROVER-KIT dev-kits. +* Download a stable firmware release. +* Download a daily firmware "Preview" build. -For best results it is recommended to first erase the entire flash of your -device before putting on new MicroPython firmware. +If you are just starting with MicroPython, the best bet is to go for the stable +Release firmware builds. If you are an advanced, experienced MicroPython ESP32 +user who would like to follow development closely and help with testing new +features, then you may find the Preview builds useful. -Currently we only support esptool.py to copy across the firmware. You can find -this tool here: ``__, or install it -using pip:: +.. _esp32_flashing: - pip install esptool - -Versions starting with 1.3 support both Python 2.7 and Python 3.4 (or newer). -An older version (at least 1.2.1 is needed) works fine but will require Python -2.7. - -Using esptool.py you can erase the flash with the command:: +Deploying the firmware +---------------------- - esptool.py --port /dev/ttyUSB0 erase_flash +Once you have the MicroPython firmware you need to load it onto your ESP32 +device. There are two main steps to do this: first you need to put your device +in bootloader mode, and second you need to copy across the firmware. The exact +procedure for these steps is highly dependent on the particular board. -And then deploy the new firmware using:: +Detailed steps can be found on the same `MicroPython download page`_ for your +board. It's recommended that you follow the steps on the download page, as they +are customised for your particular board. - esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 esp32-20180511-v1.9.4.bin +If the above commands run without error then MicroPython should be installed on +your board! Skip ahead to :ref:`esp32_serial_prompt`. -Notes: +.. _esp32_troubleshooting_install: -* You might need to change the "port" setting to something else relevant for your - PC -* You may need to reduce the baudrate if you get errors when flashing - (eg down to 115200 by adding ``--baud 115200`` into the command) -* For some boards with a particular FlashROM configuration you may need to - change the flash mode (eg by adding ``-fm dio`` into the command) -* The filename of the firmware should match the file that you have +Troubleshooting installation problems +------------------------------------- -If the above commands run without error then MicroPython should be installed on -your board! +If you experience problems during flashing or with running firmware immediately +after flashing, here are some troubleshooting recommendations: + +* Esptool will try to detect the serial port where your ESP32 is connected. If + this doesn't work, or you have multiple serial ports, then you may need to + manually specify the port by adding the ``--port`` option to the start of the + ``esptool.py`` command line. For example, ``esptool.py --port /dev/ttyUSB0 + `` for Linux or ``esptool --port COM4 `` for + Windows. +* If the board isn't responding to esptool at all, it may need to be manually + reset into the bootloader download mode. Look for a button marked "BOOT" or + "IO0" on your board and a second button marked "RESET" or "RST". If you have + both buttons, try these steps: + + 1. Press "BOOT" (or "IO0") and hold it down. + 2. Press "RESET" (or "RST") and immediately release it. + 3. Release "BOOT" (or "IO0"). + 4. Re-run the flashing steps from the download page. + + If your board doesn't have these buttons, consult the board manufacturer's + documentation about entering bootloader download mode. +* If you get errors part-way through the flashing process then try reducing the + speed of data transfer by removing the ``--baud 460800`` argument. +* Hardware problems can cause flashing to fail. There are two common problems: + bad power source quality, and defective hardware (especially very low cost + unbranded development boards). Speaking of power source, not just raw amperage + is important, but also low ripple and noise/EMI in general. The most reliable + and convenient power source is a USB port. +* If you still experience problems with flashing the firmware then please also + refer to the `esptool Troubleshooting documentation`_. + +.. _esp32_serial_prompt: Serial prompt ------------- Once you have the firmware on the device you can access the REPL (Python prompt) -over UART0 (GPIO1=TX, GPIO3=RX), which might be connected to a USB-serial -convertor, depending on your board. The baudrate is 115200. +over either UART0, which might be connected to a USB-serial converter depending +on your board, or the chip's built-in USB device. The baudrate is 115200. From here you can now follow the ESP8266 tutorial, because these two Espressif chips are very similar when it comes to using MicroPython on them. The ESP8266 tutorial is found at :ref:`esp8266_tutorial` (but skip the Introduction section). -Troubleshooting installation problems -------------------------------------- - -If you experience problems during flashing or with running firmware immediately -after it, here are troubleshooting recommendations: - -* Be aware of and try to exclude hardware problems. There are 2 common - problems: bad power source quality, and worn-out/defective FlashROM. - Speaking of power source, not just raw amperage is important, but also low - ripple and noise/EMI in general. The most reliable and convenient power - source is a USB port. - -* The flashing instructions above use flashing speed of 460800 baud, which is - good compromise between speed and stability. However, depending on your - module/board, USB-UART convertor, cables, host OS, etc., the above baud - rate may be too high and lead to errors. Try a more common 115200 baud - rate instead in such cases. - -* To catch incorrect flash content (e.g. from a defective sector on a chip), - add ``--verify`` switch to the commands above. - -* If you still experience problems with flashing the firmware please - refer to esptool.py project page, https://github.com/espressif/esptool - for additional documentation and a bug tracker where you can report problems. - -* If you are able to flash the firmware but the ``--verify`` option returns - errors even after multiple retries the you may have a defective FlashROM chip. +.. _esptool Troubleshooting documentation: https://docs.espressif.com/projects/esptool/en/latest/esp32/troubleshooting.html +.. _MicroPython download page: https://micropython.org/download/?port=esp32 +.. _ESP32 / WROOM: https://micropython.org/download/ESP32_GENERIC +.. _ESP32-C3: https://micropython.org/download/ESP32_GENERIC_C3 +.. _ESP32-S3: https://micropython.org/download/ESP32_GENERIC_S3 diff --git a/docs/esp32/tutorial/peripheral_access.rst b/docs/esp32/tutorial/peripheral_access.rst index 3304c341de873..f7c32c367ca09 100644 --- a/docs/esp32/tutorial/peripheral_access.rst +++ b/docs/esp32/tutorial/peripheral_access.rst @@ -32,6 +32,18 @@ the prescaler of the MCPWM0 peripheral. mem32[MCPWM0] = 0x55 # change PWM_CLK_PRESCALE print(hex(mem32[MCPWM0])) # read PWM_CLK_CFG_REG +The specific addresses will be different on different ESP32 +models. For example, ESP32-S3 uses these values: + +.. code-block:: python3 + + DR_REG_DPORT_BASE = const(0x600C_0000) + DPORT_PERIP_CLK_EN0_REG = const(DR_REG_DPORT_BASE + 0x0018) + DPORT_PERIP_RST_EN0_REG = const(DR_REG_DPORT_BASE + 0x0020) + DPORT_PWM0_CLK_EN = const(1 << 17) + MCPWM0 = const(0x6001_E000 + 0x0004) + ... + Note that before a peripheral can be used its clock must be enabled and it must be taken out of reset. In the above example the following registers are used for this: @@ -42,3 +54,83 @@ for this: The MCPWM0 peripheral is in bit position 17 of the above two registers, hence the value of ``DPORT_PWM0_CLK_EN``. + +Synchronous access to pins directly via registers +------------------------------------------------- + +The following code shows how to access pins directly via registers. It has been +tested on a generic ESP32 board. It configures pins 16, 17, 32 and 33 in output +mode via registers, and switches pin output values via registers. Pins 16 and +17 are switched simultaneously. + +.. code-block:: python3 + + from micropython import const + from machine import mem32, Pin + + GPIO_OUT_REG = const(0x3FF44004) # GPIO 0-31 output register + GPIO_OUT1_REG = const(0x3FF44010) # GPIO 32-39 output register + + GPIO_ENABLE_REG = const(0x3FF44020) # GPIO 0-31 output enable register + GPIO_ENABLE1_REG = const(0x3FF4402C) # GPIO 32-39 output enable register + + M16 = 1 << 16 # Pin(16) bit mask + M17 = 1 << 17 # Pin(17) bit mask + + M32 = 1 << (32-32) # Pin(32) bit mask + M33 = 1 << (33-32) # Pin(33) bit mask + + # Enable pin output mode like + # p16 = Pin(16, mode=Pin.OUT) + # p17 = Pin(17, mode=Pin.OUT) + # p32 = Pin(32, mode=Pin.OUT) + # p33 = Pin(33, mode=Pin.OUT) + mem32[GPIO_ENABLE_REG] = mem32[GPIO_ENABLE_REG] | M16 | M17 + mem32[GPIO_ENABLE1_REG] = mem32[GPIO_ENABLE1_REG] | M32 | M33 + + print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG])) + + # Set outputs to 1 like + # p16(1) + # p17(1) + # p32(1) + # p33(1) + mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] | M16 | M17 + mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] | M32 | M33 + + print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG])) + + # Set outputs to 0 like + # p16(0) + # p17(0) + # p32(0) + # p33(0) + mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] & ~(M16 | M17) + mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] & ~(M32 | M33) + + print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG])) + + while True: + # Set outputs to 1 + mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] | M16 | M17 + mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] | M32 | M33 + + # Set outputs to 0 + mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] & ~(M16 | M17) + mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] & ~(M32 | M33) + + +Output is:: + + 0x0 0x0 + 0x30000 0x3 + 0x0 0x0 + +Pins 16 and 17 are switched synchronously: + +.. image:: img/mem32_gpio_output.jpg + +Same image on pins 32 and 33. + +Note that pins 34-36 and 39 are inputs only. Also pins 1 and 3 are Tx, Rx of the REPL UART, +pins 6-11 are connected to the built-in SPI flash. diff --git a/docs/esp32/tutorial/pwm.rst b/docs/esp32/tutorial/pwm.rst index 12d10a86b9474..2650284d35f41 100644 --- a/docs/esp32/tutorial/pwm.rst +++ b/docs/esp32/tutorial/pwm.rst @@ -50,7 +50,7 @@ low all of the time. * Example of a smooth frequency change:: - from utime import sleep + from time import sleep from machine import Pin, PWM F_MIN = 500 @@ -75,7 +75,7 @@ low all of the time. * Example of a smooth duty change:: - from utime import sleep + from time import sleep from machine import Pin, PWM DUTY_MAX = 2**16 - 1 diff --git a/docs/esp32/tutorial/reset.rst b/docs/esp32/tutorial/reset.rst new file mode 100644 index 0000000000000..b3fc6a85bd436 --- /dev/null +++ b/docs/esp32/tutorial/reset.rst @@ -0,0 +1,25 @@ +Factory reset +============= + +If something unexpected happens and your ESP32-based board no longer boots +MicroPython, then you may have to factory reset it. For more details, see +:ref:`soft_bricking`. + +Factory resetting the MicroPython esp32 port involves fully erasing the flash +and resetting the flash memory, so you will need to re-flash the MicroPython +firmware afterwards and copy any Python files to the filesystem again. + +1. You will need the Espressif `esptool`_ installed on your system. This is the + same tool that you may have used to initially install MicroPython on your + board (see :ref:`installation instructions `). +2. Find the serial port name of your board, and then use esptool to erase the + entire flash contents:: + + esptool.py -p PORTNAME erase_flash + +3. Use esptool to flash the MicroPython file to your board again. If needed, + this file and flashing instructions can be found on the `MicroPython + downloads page`_. + +.. _esptool: https://github.com/espressif/esptool +.. _MicroPython downloads page: https://micropython.org/download/?port=esp32 diff --git a/docs/esp8266/general.rst b/docs/esp8266/general.rst index be0437e752eed..d7211aa5ab745 100644 --- a/docs/esp8266/general.rst +++ b/docs/esp8266/general.rst @@ -74,40 +74,7 @@ as possible after use. Boot process ------------ -On boot, MicroPython EPS8266 port executes ``_boot.py`` script from internal -frozen modules. It mounts filesystem in FlashROM, or if it's not available, -performs first-time setup of the module and creates the filesystem. This -part of the boot process is considered fixed, and not available for customization -for end users (even if you build from source, please refrain from changes to -it; customization of early boot process is available only to advanced users -and developers, who can diagnose themselves any issues arising from -modifying the standard process). - -Once the filesystem is mounted, ``boot.py`` is executed from it. The standard -version of this file is created during first-time module set up and has -commands to start a WebREPL daemon (disabled by default, configurable -with ``webrepl_setup`` module), etc. This -file is customizable by end users (for example, you may want to set some -parameters or add other services which should be run on -a module start-up). But keep in mind that incorrect modifications to boot.py -may still lead to boot loops or lock ups, requiring to reflash a module -from scratch. (In particular, it's recommended that you use either -``webrepl_setup`` module or manual editing to configure WebREPL, but not -both). - -As a final step of boot procedure, ``main.py`` is executed from filesystem, -if exists. This file is a hook to start up a user application each time -on boot (instead of going to REPL). For small test applications, you may -name them directly as ``main.py``, and upload to module, but instead it's -recommended to keep your application(s) in separate files, and have just -the following in ``main.py``:: - - import my_app - my_app.main() - -This will allow to keep the structure of your application clear, as well as -allow to install multiple applications on a board, and switch among them. - +See :doc:`/reference/reset_boot`. Known Issues ------------ diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index ed2199737099a..e17b60f676105 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -49,19 +49,19 @@ The :mod:`esp` module:: Networking ---------- -The :mod:`network` module:: +The :class:`network.WLAN` class in the :mod:`network` module:: import network - wlan = network.WLAN(network.STA_IF) # create station interface + wlan = network.WLAN(network.WLAN.IF_STA) # create station interface wlan.active(True) # activate the interface wlan.scan() # scan for access points wlan.isconnected() # check if the station is connected to an AP wlan.connect('ssid', 'key') # connect to an AP wlan.config('mac') # get the interface's MAC address - wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses + wlan.ipconfig('addr4') # get the interface's IPv4 addresses - ap = network.WLAN(network.AP_IF) # create access-point interface + ap = network.WLAN(network.WLAN.IF_AP) # create access-point interface ap.active(True) # activate the interface ap.config(ssid='ESP-AP') # set the SSID of the access point @@ -69,14 +69,14 @@ A useful function for connecting to your local WiFi network is:: def do_connect(): import network - wlan = network.WLAN(network.STA_IF) + wlan = network.WLAN(network.WLAN.IF_STA) wlan.active(True) if not wlan.isconnected(): print('connecting to network...') wlan.connect('ssid', 'key') while not wlan.isconnected(): pass - print('network config:', wlan.ifconfig()) + print('network config:', wlan.ipconfig('addr4')) Once the network is established the :mod:`socket ` module can be used to create and use TCP/UDP sockets as usual. @@ -163,10 +163,10 @@ sys.stdin.read() if it's needed to read characters from the UART(0) while it's also used for the REPL (or detach, read, then reattach). When detached the UART(0) can be used for other purposes. -If there are no objects in any of the dupterm slots when the REPL is -started (on hard or soft reset) then UART(0) is automatically attached. -Without this, the only way to recover a board without a REPL would be to -completely erase and reflash (which would install the default boot.py which +If there are no objects in any of the dupterm slots when the REPL is started (on +:doc:`hard or soft reset `) then UART(0) is automatically +attached. Without this, the only way to recover a board without a REPL would be +to completely erase and reflash (which would install the default boot.py which attaches the REPL). To detach the REPL from UART0, use:: @@ -284,7 +284,9 @@ See :ref:`machine.RTC ` :: from machine import RTC rtc = RTC() - rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time + rtc.datetime((2017, 8, 23, 0, 1, 12, 48, 0)) # set a specific date and + # time, eg. 2017/8/23 1:12:48 + # the day-of-week value is ignored rtc.datetime() # get date and time # synchronize with ntp diff --git a/docs/esp8266/tutorial/intro.rst b/docs/esp8266/tutorial/intro.rst index 75739bd6f96fd..0d4bc42e2daba 100644 --- a/docs/esp8266/tutorial/intro.rst +++ b/docs/esp8266/tutorial/intro.rst @@ -18,7 +18,7 @@ The first thing you need is a board with an ESP8266 chip. The MicroPython software supports the ESP8266 chip itself and any board should work. The main characteristic of a board is how much flash it has, how the GPIO pins are connected to the outside world, and whether it includes a built-in USB-serial -convertor to make the UART available to your PC. +converter to make the UART available to your PC. The minimum requirement for flash size is 1Mbyte. There is also a special build for boards with 512KB, but it is highly limited comparing to the @@ -70,7 +70,7 @@ need to put your device in boot-loader mode, and second you need to copy across the firmware. The exact procedure for these steps is highly dependent on the particular board and you will need to refer to its documentation for details. -If you have a board that has a USB connector, a USB-serial convertor, and has +If you have a board that has a USB connector, a USB-serial converter, and has the DTR and RTS pins wired in a special way then deploying the firmware should be easy as all steps can be done automatically. Boards that have such features include the Adafruit Feather HUZZAH and NodeMCU boards. @@ -128,7 +128,7 @@ Serial prompt Once you have the firmware on the device you can access the REPL (Python prompt) over UART0 (GPIO1=TX, GPIO3=RX), which might be connected to a USB-serial -convertor, depending on your board. The baudrate is 115200. The next part of +converter, depending on your board. The baudrate is 115200. The next part of the tutorial will discuss the prompt in more detail. WiFi @@ -137,7 +137,7 @@ WiFi After a fresh install and boot the device configures itself as a WiFi access point (AP) that you can connect to. The ESSID is of the form MicroPython-xxxxxx where the x's are replaced with part of the MAC address of your device (so will -be the same everytime, and most likely different for all ESP8266 chips). The +be the same every time, and most likely different for all ESP8266 chips). The password for the WiFi is micropythoN (note the upper-case N). Its IP address will be 192.168.4.1 once you connect to its network. WiFi configuration will be discussed in more detail later in the tutorial. @@ -169,7 +169,7 @@ after it, here are troubleshooting recommendations: * The flashing instructions above use flashing speed of 460800 baud, which is good compromise between speed and stability. However, depending on your - module/board, USB-UART convertor, cables, host OS, etc., the above baud + module/board, USB-UART converter, cables, host OS, etc., the above baud rate may be too high and lead to errors. Try a more common 115200 baud rate instead in such cases. diff --git a/docs/esp8266/tutorial/network_basics.rst b/docs/esp8266/tutorial/network_basics.rst index dc3cd3dd5e070..e383c00c6ceed 100644 --- a/docs/esp8266/tutorial/network_basics.rst +++ b/docs/esp8266/tutorial/network_basics.rst @@ -1,14 +1,15 @@ Network basics ============== -The network module is used to configure the WiFi connection. There are two WiFi -interfaces, one for the station (when the ESP8266 connects to a router) and one -for the access point (for other devices to connect to the ESP8266). Create +The :class:`network.WLAN` class in the :mod:`network` module is used to +configure the WiFi connection. There are two WiFi interfaces, one for +the station (when the ESP8266 connects to a router) and one for the +access point (for other devices to connect to the ESP8266). Create instances of these objects using:: >>> import network - >>> sta_if = network.WLAN(network.STA_IF) - >>> ap_if = network.WLAN(network.AP_IF) + >>> sta_if = network.WLAN(network.WLAN.IF_STA) + >>> ap_if = network.WLAN(network.WLAN.IF_AP) You can check if the interfaces are active by:: @@ -19,10 +20,10 @@ You can check if the interfaces are active by:: You can also check the network settings of the interface by:: - >>> ap_if.ifconfig() - ('192.168.4.1', '255.255.255.0', '192.168.4.1', '8.8.8.8') + >>> ap_if.ipconfig('addr4') + ('192.168.4.1', '255.255.255.0') -The returned values are: IP address, netmask, gateway, DNS. +The returned values are: IP address and netmask. Configuration of the WiFi ------------------------- @@ -45,8 +46,8 @@ To check if the connection is established use:: Once established you can check the IP address:: - >>> sta_if.ifconfig() - ('192.168.0.2', '255.255.255.0', '192.168.0.1', '8.8.8.8') + >>> sta_if.ipconfig('addr4') + ('192.168.0.2', '255.255.255.0') You can then disable the access-point interface if you no longer need it:: @@ -57,14 +58,14 @@ connect to your WiFi network:: def do_connect(): import network - sta_if = network.WLAN(network.STA_IF) + sta_if = network.WLAN(network.WLAN.IF_STA) if not sta_if.isconnected(): print('connecting to network...') sta_if.active(True) sta_if.connect('', '') while not sta_if.isconnected(): pass - print('network config:', sta_if.ifconfig()) + print('network config:', sta_if.ipconfig('addr4')) Sockets ------- diff --git a/docs/esp8266/tutorial/repl.rst b/docs/esp8266/tutorial/repl.rst index 196541bd02cb6..db55d45facde8 100644 --- a/docs/esp8266/tutorial/repl.rst +++ b/docs/esp8266/tutorial/repl.rst @@ -13,7 +13,7 @@ REPL over the serial port The REPL is always available on the UART0 serial peripheral, which is connected to the pins GPIO1 for TX and GPIO3 for RX. The baudrate of the REPL is 115200. -If your board has a USB-serial convertor on it then you should be able to access +If your board has a USB-serial converter on it then you should be able to access the REPL directly from your PC. Otherwise you will need to have a way of communicating with the UART. @@ -38,7 +38,7 @@ browser. The latest versions of Firefox and Chrome are supported. For your convenience, WebREPL client is hosted at ``__. Alternatively, you can install it -locally from the the GitHub repository +locally from the GitHub repository ``__. Before connecting to WebREPL, you should set a password and enable it via diff --git a/docs/library/array.rst b/docs/library/array.rst index f94cece2b7ccf..957260c2c7f92 100644 --- a/docs/library/array.rst +++ b/docs/library/array.rst @@ -19,6 +19,10 @@ Classes array are given by *iterable*. If it is not provided, an empty array is created. + In addition to the methods below, array objects also implement the buffer + protocol. This means the contents of the entire array can be accessed as raw + bytes via a `memoryview` or other interfaces which use this protocol. + .. method:: append(val) Append new element *val* to the end of array, growing it. @@ -75,7 +79,7 @@ Classes Returns the string representation of the array, called as ``str(a)`` or ``repr(a)``` (where ``a`` is an ``array``). Returns the string ``"array(, [])"``, where ```` is the type code letter for the array and ```` is a comma - seperated list of the elements of the array. + separated list of the elements of the array. **Note:** ``__repr__`` cannot be called directly (``a.__repr__()`` fails) and is not present in ``__dict__``, however ``str(a)`` and ``repr(a)`` both work. diff --git a/docs/library/asyncio.rst b/docs/library/asyncio.rst new file mode 100644 index 0000000000000..51ad8a2876a34 --- /dev/null +++ b/docs/library/asyncio.rst @@ -0,0 +1,363 @@ +:mod:`asyncio` --- asynchronous I/O scheduler +============================================= + +.. module:: asyncio + :synopsis: asynchronous I/O scheduler for writing concurrent code + +|see_cpython_module| +`asyncio `_ + +Example:: + + import asyncio + + async def blink(led, period_ms): + while True: + led.on() + await asyncio.sleep_ms(5) + led.off() + await asyncio.sleep_ms(period_ms) + + async def main(led1, led2): + asyncio.create_task(blink(led1, 700)) + asyncio.create_task(blink(led2, 400)) + await asyncio.sleep_ms(10_000) + + # Running on a pyboard + from pyb import LED + asyncio.run(main(LED(1), LED(2))) + + # Running on a generic board + from machine import Pin + asyncio.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:: current_task() + + Return the `Task` object associated with the currently running task. + +.. 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 + than *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. The task receives + ``asyncio.CancelledError`` which may be ignored or trapped using ``try...except`` + or ``try...finally`` to run cleanup code. + + Returns the return value of *awaitable*. + + This is a coroutine. + +.. function:: wait_for_ms(awaitable, timeout) + + Similar to `wait_for` but *timeout* is an integer in milliseconds. + + This is a coroutine, and a MicroPython extension. + +.. 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 ``asyncio.CancelledError`` into it. The task may + ignore this exception. Cleanup code may be run by trapping it, or via + ``try ... finally``. + +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. + + Note: This must be called from within a task. It is not safe to call this + from an IRQ, scheduler callback, or other thread. See `ThreadSafeFlag`. + +.. 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 ThreadSafeFlag +-------------------- + +.. class:: ThreadSafeFlag() + + Create a new flag which can be used to synchronise a task with code running + outside the asyncio loop, such as other threads, IRQs, or scheduler + callbacks. Flags start in the cleared state. + +.. method:: ThreadSafeFlag.set() + + Set the flag. If there is a task waiting on the flag, it will be scheduled + to run. + +.. method:: ThreadSafeFlag.clear() + + Clear the flag. This may be used to ensure that a possibly previously-set + flag is clear before waiting for it. + +.. method:: ThreadSafeFlag.wait() + + Wait for the flag to be set. If the flag is already set then it returns + immediately. The flag is automatically reset upon return from ``wait``. + + A flag may only be waited on by a single task at a time. + + 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, ssl=None) + + 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. + If *ssl* is a `ssl.SSLContext` object, this context is used to create the transport; + if *ssl* is ``True``, a default context is used. + + 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, ssl=None) + + 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. + + If *ssl* is a `ssl.SSLContext` object, this context is used to create the transport. + + 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=-1) + + Read up to *n* bytes and return them. If *n* is not provided or -1 then read all + bytes until EOF. The returned value will be an empty bytes object if EOF is + encountered before any bytes are read. + + This is a coroutine. + +.. method:: Stream.readinto(buf) + + Read up to n bytes into *buf* with n being equal to the length of *buf*. + + Return the number of bytes read into *buf*. + + This is a coroutine, and a MicroPython extension. + +.. method:: Stream.readexactly(n) + + Read exactly *n* bytes and return them as a bytes object. + + Raises an ``EOFError`` exception if the stream ends before reading *n* bytes. + + 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/binascii.rst b/docs/library/binascii.rst index 6c02f019aaa58..c728c5a8a574c 100644 --- a/docs/library/binascii.rst +++ b/docs/library/binascii.rst @@ -36,3 +36,9 @@ Functions Encode binary data in base64 format, as in `RFC 3548 `_. Returns the encoded data followed by a newline character if newline is true, as a bytes object. + +.. function:: crc32(data, [value]) + + Compute CRC-32, the 32-bit checksum of *data*, starting with an initial CRC + of *value*. The default initial CRC is zero. The algorithm is consistent + with the ZIP file checksum. diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst index dd0f5ffd622af..b09c370abd46d 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/bluetooth.rst @@ -44,7 +44,7 @@ Configuration 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 + queried at a time. To set values use the keyword syntax, and one or more parameter can be set at a time. Currently supported values are: @@ -312,7 +312,7 @@ Broadcaster Role (Advertiser) 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 + to the previous call to ``gap_advertise`` will be reused. 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''``. @@ -665,7 +665,7 @@ L2CAP connection-oriented-channels Connect to a listening peer on the specified *psm* with local MTU set to *mtu*. - On successful connection, the the ``_IRQ_L2CAP_CONNECT`` event will be + On successful connection, the ``_IRQ_L2CAP_CONNECT`` event will be raised, allowing the client to obtain the CID and the local and remote (peer) MTU. An unsuccessful connection will raise the ``_IRQ_L2CAP_DISCONNECT`` event @@ -722,7 +722,7 @@ Pairing and bonding and ``_IRQ_SET_SECRET`` events. **Note:** This is currently only supported when using the NimBLE stack on - STM32 and Unix (not ESP32). + ESP32, STM32 and Unix. .. method:: BLE.gap_pair(conn_handle, /) diff --git a/docs/library/builtins.rst b/docs/library/builtins.rst index 7a0229c2aaaf6..b5d08ba7fed50 100644 --- a/docs/library/builtins.rst +++ b/docs/library/builtins.rst @@ -19,6 +19,8 @@ Functions and types .. class:: bytearray() + |see_cpython| `python:bytearray`. + .. class:: bytes() |see_cpython| `python:bytes`. @@ -82,6 +84,10 @@ Functions and types In MicroPython, `byteorder` parameter must be positional (this is compatible with CPython). + .. note:: The optional ``signed`` kwarg from CPython is not supported. + MicroPython currently converts negative integers as signed, + and positive as unsigned. (:ref:`Details `.) + .. function:: isinstance() .. function:: issubclass() @@ -100,6 +106,8 @@ Functions and types .. class:: memoryview() + |see_cpython| `python:memoryview`. + .. function:: min() .. function:: next() @@ -166,6 +174,10 @@ Exceptions .. exception:: KeyboardInterrupt + |see_cpython| `python:KeyboardInterrupt`. + + See also in the context of :ref:`soft_bricking`. + .. exception:: KeyError .. exception:: MemoryError @@ -186,6 +198,12 @@ Exceptions |see_cpython| `python:SystemExit`. + On non-embedded ports (i.e. Windows and Unix), an unhandled ``SystemExit`` + exits the MicroPython process in a similar way to CPython. + + On embedded ports, an unhandled ``SystemExit`` currently causes a + :ref:`soft_reset` of MicroPython. + .. exception:: TypeError |see_cpython| `python:TypeError`. diff --git a/docs/library/collections.rst b/docs/library/collections.rst index 6cf2c096ffc62..6a23e456c66a7 100644 --- a/docs/library/collections.rst +++ b/docs/library/collections.rst @@ -18,7 +18,9 @@ Classes appends and pops from either side of the deque. New deques are created using the following arguments: - - *iterable* must be the empty tuple, and the new deque is created empty. + - *iterable* is an iterable used to populate the deque when it is + created. It can be an empty tuple or list to create a deque that + is initially empty. - *maxlen* must be specified and the deque will be bounded to this maximum length. Once the deque is full, any new items added will @@ -26,18 +28,37 @@ Classes - The optional *flags* can be 1 to check for overflow when adding items. - As well as supporting `bool` and `len`, deque objects have the following - methods: + Deque objects support `bool`, `len`, iteration and subscript load and store. + They also have the following methods: .. method:: deque.append(x) Add *x* to the right side of the deque. - Raises IndexError if overflow checking is enabled and there is no more room left. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the queue. + + .. method:: deque.appendleft(x) + + Add *x* to the left side of the deque. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the queue. + + .. method:: deque.pop() + + Remove and return an item from the right side of the deque. + Raises ``IndexError`` if no items are present. .. method:: deque.popleft() Remove and return an item from the left side of the deque. - Raises IndexError if no items are present. + Raises ``IndexError`` if no items are present. + + .. method:: deque.extend(iterable) + + Extend the deque by appending all the items from *iterable* to + the right of the deque. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the deque. .. function:: namedtuple(name, fields) diff --git a/docs/library/deflate.rst b/docs/library/deflate.rst new file mode 100644 index 0000000000000..fad577870518d --- /dev/null +++ b/docs/library/deflate.rst @@ -0,0 +1,182 @@ +:mod:`deflate` -- deflate compression & decompression +===================================================== + +.. module:: deflate + :synopsis: deflate compression & decompression + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ +(commonly used in the zlib library and gzip archiver). + +**Availability:** + +* Added in MicroPython v1.21. + +* Decompression: Enabled via the ``MICROPY_PY_DEFLATE`` build option, on by default + on ports with the "extra features" level or higher (which is most boards). + +* Compression: Enabled via the ``MICROPY_PY_DEFLATE_COMPRESS`` build option, on + by default on ports with the "full features" level or higher (generally this means + you need to build your own firmware to enable this). + +Classes +------- + +.. class:: DeflateIO(stream, format=AUTO, wbits=0, close=False, /) + + This class can be used to wrap a *stream* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + The *stream* must be a blocking stream. Non-blocking streams are currently + not supported. + + The *format* can be set to any of the constants defined below, and defaults + to ``AUTO`` which for decompressing will auto-detect gzip or zlib streams, + and for compressing it will generate a raw stream. + + The *wbits* parameter sets the base-2 logarithm of the DEFLATE dictionary + window size. So for example, setting *wbits* to ``10`` sets the window size + to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to + window sizes of 32 to 32k bytes). + + If *wbits* is set to ``0`` (the default), then for compression a window size + of 256 bytes will be used (as if *wbits* was set to 8). For decompression, it + depends on the format: + + * ``RAW`` will use 256 bytes (corresponding to *wbits* set to 8). + * ``ZLIB`` (or ``AUTO`` with zlib detected) will use the value from the zlib + header. + * ``GZIP`` (or ``AUTO`` with gzip detected) will use 32 kilobytes + (corresponding to *wbits* set to 15). + + See the :ref:`window size ` notes below for more information + about the window size, zlib, and gzip streams. + + If *close* is set to ``True`` then the underlying stream will be closed + automatically when the :class:`deflate.DeflateIO` stream is closed. This is + useful if you want to return a :class:`deflate.DeflateIO` stream that wraps + another stream and not have the caller need to know about managing the + underlying stream. + + If compression is enabled, a given :class:`deflate.DeflateIO` instance + supports both reading and writing. For example, a bidirectional stream like + a socket can be wrapped, which allows for compression/decompression in both + directions. + +Constants +--------- + +.. data:: deflate.AUTO + deflate.RAW + deflate.ZLIB + deflate.GZIP + + Supported values for the *format* parameter. + +Examples +-------- + +A typical use case for :class:`deflate.DeflateIO` is to read or write a compressed +file from storage: + +.. code:: python + + import deflate + + # Writing a zlib-compressed stream (uses the default window size of 256 bytes). + with open("data.gz", "wb") as f: + with deflate.DeflateIO(f, deflate.ZLIB) as d: + # Use d.write(...) etc + + # Reading a zlib-compressed stream (auto-detect window size). + with open("data.z", "rb") as f: + with deflate.DeflateIO(f, deflate.ZLIB) as d: + # Use d.read(), d.readinto(), etc. + +Because :class:`deflate.DeflateIO` is a stream, it can be used for example +with :meth:`json.dump` and :meth:`json.load` (and any other places streams can +be used): + +.. code:: python + + import deflate, json + + # Write a dictionary as JSON in gzip format, with a + # small (64 byte) window size. + config = { ... } + with open("config.gz", "wb") as f: + with deflate.DeflateIO(f, deflate.GZIP, 6) as f: + json.dump(config, f) + + # Read back that dictionary. + with open("config.gz", "rb") as f: + with deflate.DeflateIO(f, deflate.GZIP, 6) as f: + config = json.load(f) + +If your source data is not in a stream format, you can use :class:`io.BytesIO` +to turn it into a stream suitable for use with :class:`deflate.DeflateIO`: + +.. code:: python + + import deflate, io + + # Decompress a bytes/bytearray value. + compressed_data = get_data_z() + with deflate.DeflateIO(io.BytesIO(compressed_data), deflate.ZLIB) as d: + decompressed_data = d.read() + + # Compress a bytes/bytearray value. + uncompressed_data = get_data() + stream = io.BytesIO() + with deflate.DeflateIO(stream, deflate.ZLIB) as d: + d.write(uncompressed_data) + compressed_data = stream.getvalue() + +.. _deflate_wbits: + +Deflate window size +------------------- + +The window size limits how far back in the stream the (de)compressor can +reference. Increasing the window size will improve compression, but will require +more memory and make the compressor slower. + +If an input stream was compressed a given window size, then `DeflateIO` +using a smaller window size will fail mid-way during decompression with +:exc:`OSError`, but only if a back-reference actually refers back further +than the decompressor's window size. This means it may be possible to decompress +with a smaller window size. For example, this would trivially be the case if the +original uncompressed data is shorter than the window size. + +Decompression +~~~~~~~~~~~~~ + +The zlib format includes a header which specifies the window size that was used +to compress the data. This indicates the maximum window size required to +decompress this stream. If this header value is less than the specified *wbits* +value (or if *wbits* is unset), then the header value will be used. + +The gzip format does not include the window size in the header, and assumes that +all gzip compressors (e.g. the ``gzip`` utility, or CPython's implementation of +:class:`gzip.GzipFile`) use the maximum window size of 32kiB. For this reason, +if the *wbits* parameter is not set, the decompressor will use a 32 kiB window +size (corresponding to *wbits* set to 15). This means that to be able to +decompress an arbitrary gzip stream, you must have at least this much RAM +available. If you control the source data, consider instead using the zlib +format with a smaller window size. + +The raw format has no header and therefore does not include any information +about the window size. If *wbits* is not set, then it will default to a window +size of 256 bytes, which may not be large enough for a given stream. Therefore +it is recommended that you should always explicitly set *wbits* if using the raw +format. + +Compression +~~~~~~~~~~~ + +For compression, MicroPython will default to a window size of 256 bytes for all +formats. This provides a reasonable amount of compression with minimal memory +usage and fast compression time, and will generate output that will work with +any decompressor. diff --git a/docs/library/esp.rst b/docs/library/esp.rst index 8920c8241ea0c..9c20b5e8b2d89 100644 --- a/docs/library/esp.rst +++ b/docs/library/esp.rst @@ -62,12 +62,35 @@ Functions .. function:: flash_erase(sector_no) -.. function:: osdebug(level) +.. function:: osdebug(uart_no) - Turn esp os debugging messages on or off. + .. note:: This is the ESP8266 form of this function. - The *level* parameter sets the threshold for the log messages for all esp components. - The log levels are defined as constants: + Change the level of OS serial debug log messages. On boot, + OS serial debug log messages are disabled. + + ``uart_no`` is the number of the UART peripheral which should receive + OS-level output, or ``None`` to disable OS serial debug log messages. + +.. function:: osdebug(uart_no, [level]) + :no-index: + + .. note:: This is the ESP32 form of this function. + + Change the level of OS serial debug log messages. On boot, OS + serial debug log messages are limited to Error output only. + + The behaviour of this function depends on the arguments passed to it. The + following combinations are supported: + + ``osdebug(None)`` restores the default OS debug log message level + (``LOG_ERROR``). + + ``osdebug(0)`` enables all available OS debug log messages (in the + default build configuration this is ``LOG_INFO``). + + ``osdebug(0, level)`` sets the OS debug log message level to the + specified value. The log levels are defined as constants: * ``LOG_NONE`` -- No log output * ``LOG_ERROR`` -- Critical errors, software module can not recover on its own @@ -77,6 +100,15 @@ Functions * ``LOG_VERBOSE`` -- Bigger chunks of debugging information, or frequent messages which can potentially flood the output + .. note:: ``LOG_DEBUG`` and ``LOG_VERBOSE`` are not compiled into the + MicroPython binary by default, to save size. A custom build with a + modified "``sdkconfig``" source file is needed to see any output + at these log levels. + + .. note:: Log output on ESP32 is automatically suspended in "Raw REPL" mode, + to prevent communications issues. This means OS level logging is never + seen when using ``mpremote run`` and similar tools. + .. function:: set_native_code_location(start, length) **Note**: ESP8266 only diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index f0f0c8ef1f56e..dc35e7905e162 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -44,10 +44,6 @@ Functions Read the raw value of the internal temperature sensor, returning an integer. -.. function:: hall_sensor() - - 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 @@ -55,8 +51,6 @@ Functions 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 @@ -72,6 +66,21 @@ Functions [(240, 0, 0, 0), (7288, 0, 0, 0), (16648, 4, 4, 4), (79912, 35712, 35512, 35108), (15072, 15036, 15036, 15036), (113840, 0, 0, 0)] + .. note:: Free IDF heap memory in the `esp32.HEAP_DATA` region is available + to be automatically added to the MicroPython heap to prevent a + MicroPython allocation from failing. However, the information returned + here is otherwise *not* useful to troubleshoot Python allocation + failures. :func:`micropython.mem_info()` and :func:`gc.mem_free()` should + be used instead: + + The "max new split" value in :func:`micropython.mem_info()` output + corresponds to the largest free block of ESP-IDF heap that could be + automatically added on demand to the MicroPython heap. + + The result of :func:`gc.mem_free()` is the total of the current "free" + and "max new split" values printed by :func:`micropython.mem_info()`. + + Flash partitions ---------------- @@ -105,12 +114,17 @@ methods to enable over-the-air (OTA) updates. These methods implement the simple and :ref:`extended ` block protocol defined by - :class:`os.AbstractBlockDev`. + :class:`vfs.AbstractBlockDev`. .. method:: Partition.set_boot() Sets the partition as the boot partition. + .. note:: Do not enter :func:`deepsleep` after changing + the OTA boot partition, without first performing a hard + :func:`reset` or power cycle. This ensures the bootloader + will validate the new image before booting. + .. method:: Partition.get_next_update() Gets the next update partition after this one, and returns a new Partition object. @@ -126,7 +140,7 @@ methods to enable over-the-air (OTA) updates. 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. + necessary when booting firmware that was loaded using esptool. Constants ~~~~~~~~~ @@ -179,7 +193,7 @@ numbers specified 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 +multiplying the resolution by a 15-bit (1-``PULSE_MAX``) 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 @@ -212,7 +226,7 @@ For more details see Espressif's `ESP-IDF RMT documentation. ``100``) and the output level to apply the carrier to (a boolean as per *idle_level*). -.. method:: RMT.source_freq() +.. classmethod:: RMT.source_freq() Returns the source clock frequency. Currently the source clock is not configurable so this will always return 80MHz. @@ -250,10 +264,10 @@ For more details see Espressif's `ESP-IDF RMT documentation. **Mode 3:** *duration* and *data* are lists or tuples of equal length, specifying individual durations and the output level for each. - Durations are in integer units of the channel resolution (as described - above), between 1 and 32767 units. Output levels are any value that can - be converted to a boolean, with ``True`` representing high voltage and - ``False`` representing low. + Durations are in integer units of the channel resolution (as + described above), between 1 and ``PULSE_MAX`` units. Output levels + are any value that can be converted to a boolean, with ``True`` + representing high voltage and ``False`` representing low. If transmission of an earlier sequence is in progress then this method will block until that transmission is complete before beginning the new sequence. @@ -276,9 +290,24 @@ For more details see Espressif's `ESP-IDF RMT documentation. Passing in no argument will not change the channel. This function returns the current channel number. +Constants +--------- + +.. data:: RMT.PULSE_MAX + + Maximum integer that can be set for a pulse duration. + Ultra-Low-Power co-processor ---------------------------- +This class gives access to the Ultra Low Power (ULP) co-processor on the ESP32, +ESP32-S2 and ESP32-S3 chips. + +.. warning:: + + This class does not provide access to the RISCV ULP co-processor available + on the ESP32-S2 and ESP32-S3 chips. + .. class:: ULP() This class provides access to the Ultra-Low-Power co-processor. diff --git a/docs/library/espnow.rst b/docs/library/espnow.rst new file mode 100644 index 0000000000000..84e9e9465de96 --- /dev/null +++ b/docs/library/espnow.rst @@ -0,0 +1,943 @@ +:mod:`espnow` --- support for the ESP-NOW wireless protocol +=========================================================== + +.. module:: espnow + :synopsis: ESP-NOW wireless protocol support + +This module provides an interface to the `ESP-NOW `_ protocol provided by Espressif on +ESP32 and ESP8266 devices (`API docs `_). + +Table of Contents: +------------------ + + - `Introduction`_ + - `Configuration`_ + - `Sending and Receiving Data`_ + - `Peer Management`_ + - `Callback Methods`_ + - `Exceptions`_ + - `Constants`_ + - `Wifi Signal Strength (RSSI) - (ESP32 Only)`_ + - `Supporting asyncio`_ + - `Broadcast and Multicast`_ + - `ESPNow and Wifi Operation`_ + - `ESPNow and Sleep Modes`_ + +Introduction +------------ + +ESP-NOW is a connection-less wireless communication protocol supporting: + +- Direct communication between up to 20 registered peers: + + - Without the need for a wireless access point (AP), + +- Encrypted and unencrypted communication (up to 6 encrypted peers), + +- Message sizes up to 250 bytes, + +- Can operate alongside Wifi operation (:doc:`network.WLAN`) on + ESP32 and ESP8266 devices. + +It is especially useful for small IoT networks, latency sensitive or power +sensitive applications (such as battery operated devices) and for long-range +communication between devices (hundreds of metres). + +This module also supports tracking the Wifi signal strength (RSSI) of peer +devices. + +A simple example would be: + +**Sender:** :: + + import network + import espnow + + # A WLAN interface must be active to send()/recv() + sta = network.WLAN(network.WLAN.IF_STA) # Or network.WLAN.IF_AP + sta.active(True) + sta.disconnect() # For ESP8266 + + e = espnow.ESPNow() + e.active(True) + peer = b'\xbb\xbb\xbb\xbb\xbb\xbb' # MAC address of peer's wifi interface + e.add_peer(peer) # Must add_peer() before send() + + e.send(peer, "Starting...") + for i in range(100): + e.send(peer, str(i)*20, True) + e.send(peer, b'end') + +**Receiver:** :: + + import network + import espnow + + # A WLAN interface must be active to send()/recv() + sta = network.WLAN(network.WLAN.IF_STA) + sta.active(True) + sta.disconnect() # Because ESP8266 auto-connects to last Access Point + + e = espnow.ESPNow() + e.active(True) + + while True: + host, msg = e.recv() + if msg: # msg == None if timeout in recv() + print(host, msg) + if msg == b'end': + break + +class ESPNow +------------ + +Constructor +----------- + +.. class:: ESPNow() + + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + +Configuration +------------- + +.. method:: ESPNow.active([flag]) + + Initialise or de-initialise the ESP-NOW communication protocol depending on + the value of the ``flag`` optional argument. + + .. data:: Arguments: + + - *flag*: Any python value which can be converted to a boolean type. + + - ``True``: Prepare the software and hardware for use of the ESP-NOW + communication protocol, including: + + - initialise the ESPNow data structures, + - allocate the recv data buffer, + - invoke esp_now_init() and + - register the send and recv callbacks. + + - ``False``: De-initialise the Espressif ESP-NOW software stack + (esp_now_deinit()), disable callbacks, deallocate the recv + data buffer and deregister all peers. + + If *flag* is not provided, return the current status of the ESPNow + interface. + + .. data:: Returns: + + ``True`` if interface is currently *active*, else ``False``. + +.. method:: ESPNow.config(param=value, ...) + ESPNow.config('param') (ESP32 only) + + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + .. data:: Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + .. data:: Returns: + + ``None`` or the value of the parameter being queried. + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + +Sending and Receiving Data +-------------------------- + +A wifi interface (``network.WLAN.IF_STA`` or ``network.WLAN.IF_AP``) must be +`active()` before messages can be sent or received, +but it is not necessary to connect or configure the WLAN interface. +For example:: + + import network + + sta = network.WLAN(network.WLAN.IF_STA) + sta.active(True) + sta.disconnect() # For ESP8266 + +**Note:** The ESP8266 has a *feature* that causes it to automatically reconnect +to the last wifi Access Point when set `active(True)` (even +after reboot/reset). This reduces the reliability of receiving ESP-NOW messages +(see `ESPNow and Wifi Operation`_). You can avoid this by calling +`disconnect()` after +`active(True)`. + +.. method:: ESPNow.send(mac, msg[, sync]) + ESPNow.send(msg) (ESP32 only) + + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + .. data:: Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + .. data:: Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + +.. method:: ESPNow.recv([timeout_ms]) + + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + .. data:: Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + .. data:: Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + + +.. method:: ESPNow.irecv([timeout_ms]) + + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + .. data:: Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + .. data:: Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + .. data:: Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + +.. method:: ESPNow.recvinto(data[, timeout_ms]) + + Wait for an incoming message and return the length of the message in bytes. + This is the low-level method used by both `recv()` and + `irecv()` to read messages. + + .. data:: Arguments: + + *data*: A list of at least two elements, ``[peer, msg]``. ``msg`` must + be a bytearray large enough to hold the message (250 bytes). On the + ESP8266, ``peer`` should be a bytearray of 6 bytes. The MAC address of + the sender and the message will be stored in these bytearrays (see Note + on ESP32 below). + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + .. data:: Returns: + + - Length of message in bytes or 0 if *timeout_ms* is reached before a + message is received. + + .. data:: Raises: + + - See `ESPNow.recv()`. + + **Note:** On the ESP32: + + - It is unnecessary to provide a bytearray in the first element of the + ``data`` list because it will be replaced by a reference to a unique + ``peer`` address in the **peer device table** (see `ESPNow.peers_table`). + - If the list is at least 4 elements long, the rssi and timestamp values + will be saved as the 3rd and 4th elements. + +.. method:: ESPNow.any() + + Check if data is available to be read with `ESPNow.recv()`. + + For more sophisticated querying of available characters use `select.poll()`:: + + import select + import espnow + + e = espnow.ESPNow() + poll = select.poll() + poll.register(e, select.POLLIN) + poll.poll(timeout) + + .. data:: Returns: + + ``True`` if data is available to be read, else ``False``. + +.. method:: ESPNow.stats() (ESP32 only) + + .. data:: Returns: + + A 5-tuple containing the number of packets sent/received/lost: + + ``(tx_pkts, tx_responses, tx_failures, rx_packets, rx_dropped_packets)`` + + Incoming packets are *dropped* when the recv buffers are full. To reduce + packet loss, increase the ``rxbuf`` config parameters and ensure you are + reading messages as quickly as possible. + + **Note**: Dropped packets will still be acknowledged to the sender as + received. + +Peer Management +--------------- + +On ESP32 devices, the Espressif ESP-NOW software requires that other devices +(peers) must be *registered* using `add_peer()` before we can +`send()` them messages (this is *not* enforced on ESP8266 +devices). It is **not** necessary to register a peer to receive an +un-encrypted message from that peer. + +**Encrypted messages**: To receive an *encrypted* message, the receiving device +must first register the sender and use the same encryption keys as the sender +(PMK and LMK) (see `set_pmk()` and `add_peer()`. + +.. method:: ESPNow.set_pmk(pmk) + + Set the Primary Master Key (PMK) which is used to encrypt the Local Master + Keys (LMK) for encrypting messages. If this is not set, a default PMK is + used by the underlying Espressif ESP-NOW software stack. + + **Note:** messages will only be encrypted if *lmk* is also set in + `ESPNow.add_peer()` (see `Security + `_ in the Espressif API + docs). + + .. data:: Arguments: + + *pmk*: Must be a byte string, bytearray or string of length + `espnow.KEY_LEN` (16 bytes). + + .. data:: Returns: + + ``None`` + + .. data:: Raises: + + ``ValueError()`` on invalid *pmk* values. + +.. method:: ESPNow.add_peer(mac, [lmk], [channel], [ifidx], [encrypt]) + ESPNow.add_peer(mac, param=value, ...) (ESP32 only) + + Add/register the provided *mac* address as a peer. Additional parameters may + also be specified as positional or keyword arguments (any parameter set to + ``None`` will be set to it's default value): + + .. data:: Arguments: + + - *mac*: The MAC address of the peer (as a 6-byte byte-string). + + - *lmk*: The Local Master Key (LMK) key used to encrypt data + transfers with this peer (unless the *encrypt* parameter is set to + ``False``). Must be: + + - a byte-string or bytearray or string of length ``espnow.KEY_LEN`` + (16 bytes), or + + - any non ``True`` python value (default= ``b''``), signifying an + *empty* key which will disable encryption. + + - *channel*: The wifi channel (2.4GHz) to communicate with this peer. + Must be an integer from 0 to 14. If channel is set to 0 the current + channel of the wifi device will be used, if channel is set to another + value then this must match the channel currently configured on the + interface (see :func:`WLAN.config`). (default=0) + + - *ifidx*: (ESP32 only) Index of the wifi interface which will be + used to send data to this peer. Must be an integer set to + ``network.WLAN.IF_STA`` (=0) or ``network.WLAN.IF_AP`` (=1). + (default=0/``network.WLAN.IF_STA``). See `ESPNow and Wifi Operation`_ + below for more information. + + - *encrypt*: (ESP32 only) If set to ``True`` data exchanged with + this peer will be encrypted with the PMK and LMK. (default = + ``True`` if *lmk* is set to a valid key, else ``False``) + + **ESP8266**: Keyword args may not be used on the ESP8266. + + **Note:** The maximum number of peers which may be registered is 20 + (`espnow.MAX_TOTAL_PEER_NUM`), with a maximum of 6 + (`espnow.MAX_ENCRYPT_PEER_NUM`) of those peers with encryption enabled + (see `ESP_NOW_MAX_ENCRYPT_PEER_NUM `_ in the Espressif API + docs). + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_EXIST")`` if *mac* is already + registered. + - ``OSError(num, "ESP_ERR_ESPNOW_FULL")`` if too many peers are + already registered. + - ``OSError(num, "ESP_ERR_ESPNOW_CHAN")`` if a channel value was + set that doesn't match the channel currently configured for this + interface. + - ``ValueError()`` on invalid keyword args or values. + +.. method:: ESPNow.del_peer(mac) + + Deregister the peer associated with the provided *mac* address. + + .. data:: Returns: + + ``None`` + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if *mac* is not + registered. + - ``ValueError()`` on invalid *mac* values. + +.. method:: ESPNow.get_peer(mac) (ESP32 only) + + Return information on a registered peer. + + .. data:: Returns: + + ``(mac, lmk, channel, ifidx, encrypt)``: a tuple of the "peer + info" associated with the given *mac* address. + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if *mac* is not + registered. + - ``ValueError()`` on invalid *mac* values. + +.. method:: ESPNow.peer_count() (ESP32 only) + + Return the number of registered peers: + + - ``(peer_num, encrypt_num)``: where + + - ``peer_num`` is the number of peers which are registered, and + - ``encrypt_num`` is the number of encrypted peers. + +.. method:: ESPNow.get_peers() (ESP32 only) + + Return the "peer info" parameters for all the registered peers (as a tuple + of tuples). + +.. method:: ESPNow.mod_peer(mac, lmk, [channel], [ifidx], [encrypt]) (ESP32 only) + ESPNow.mod_peer(mac, 'param'=value, ...) (ESP32 only) + + Modify the parameters of the peer associated with the provided *mac* + address. Parameters may be provided as positional or keyword arguments + (see `ESPNow.add_peer()`). Any parameter that is not set (or set to + ``None``) will retain the existing value for that parameter. + +Callback Methods +---------------- + +.. method:: ESPNow.irq(callback) (ESP32 only) + + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + +Constants +--------- + +.. data:: espnow.MAX_DATA_LEN(=250) + espnow.KEY_LEN(=16) + espnow.ADDR_LEN(=6) + espnow.MAX_TOTAL_PEER_NUM(=20) + espnow.MAX_ENCRYPT_PEER_NUM(=6) + +Exceptions +---------- + +If the underlying Espressif ESP-NOW software stack returns an error code, +the MicroPython espnow module will raise an ``OSError(errnum, errstring)`` +exception where ``errstring`` is set to the name of one of the error codes +identified in the +`Espressif ESP-NOW docs +`_. For example:: + + try: + e.send(peer, 'Hello') + except OSError as err: + if len(err.args) < 2: + raise err + if err.args[1] == 'ESP_ERR_ESPNOW_NOT_INIT': + e.active(True) + elif err.args[1] == 'ESP_ERR_ESPNOW_NOT_FOUND': + e.add_peer(peer) + elif err.args[1] == 'ESP_ERR_ESPNOW_IF': + network.WLAN(network.WLAN.IF_STA).active(True) + else: + raise err + +Wifi Signal Strength (RSSI) - (ESP32 only) +------------------------------------------ + +The ESPNow object maintains a **peer device table** which contains the signal +strength and timestamp of the last received message from all hosts. The **peer +device table** can be accessed using `ESPNow.peers_table` and can be used to +track device proximity and identify *nearest neighbours* in a network of peer +devices. This feature is **not** available on ESP8266 devices. + +.. data:: ESPNow.peers_table + + A reference to the **peer device table**: a dict of known peer devices + and rssi values:: + + {peer: [rssi, time_ms], ...} + + where: + + - ``peer`` is the peer MAC address (as `bytes`); + - ``rssi`` is the wifi signal strength in dBm (-127 to 0) of the last + message received from the peer; and + - ``time_ms`` is the time the message was received (in milliseconds since + system boot - wraps every 12 days). + + Example:: + + >>> e.peers_table + {b'\xaa\xaa\xaa\xaa\xaa\xaa': [-31, 18372], + b'\xbb\xbb\xbb\xbb\xbb\xbb': [-43, 12541]} + + **Note**: the ``mac`` addresses returned by `recv()` are references to + the ``peer`` key values in the **peer device table**. + + **Note**: RSSI and timestamp values in the device table are updated only + when the message is read by the application. + +Supporting asyncio +------------------ + +A supplementary module (`aioespnow`) is available to provide +:doc:`asyncio` support. + +**Note:** Asyncio support is available on all ESP32 targets as well as those +ESP8266 boards which include the asyncio module (ie. ESP8266 devices with at +least 2MB flash memory). + +A small async server example:: + + import network + import aioespnow + import asyncio + + # A WLAN interface must be active to send()/recv() + network.WLAN(network.WLAN.IF_STA).active(True) + + e = aioespnow.AIOESPNow() # Returns AIOESPNow enhanced with async support + e.active(True) + peer = b'\xbb\xbb\xbb\xbb\xbb\xbb' + e.add_peer(peer) + + # Send a periodic ping to a peer + async def heartbeat(e, peer, period=30): + while True: + if not await e.asend(peer, b'ping'): + print("Heartbeat: peer not responding:", peer) + else: + print("Heartbeat: ping", peer) + await asyncio.sleep(period) + + # Echo any received messages back to the sender + async def echo_server(e): + async for mac, msg in e: + print("Echo:", msg) + try: + await e.asend(mac, msg) + except OSError as err: + if len(err.args) > 1 and err.args[1] == 'ESP_ERR_ESPNOW_NOT_FOUND': + e.add_peer(mac) + await e.asend(mac, msg) + + async def main(e, peer, timeout, period): + asyncio.create_task(heartbeat(e, peer, period)) + asyncio.create_task(echo_server(e)) + await asyncio.sleep(timeout) + + asyncio.run(main(e, peer, 120, 10)) + +.. module:: aioespnow + :synopsis: ESP-NOW :doc:`asyncio` support + +.. class:: AIOESPNow() + + The `AIOESPNow` class inherits all the methods of `ESPNow` + and extends the interface with the following async methods. + +.. method:: async AIOESPNow.arecv() + + Asyncio support for `ESPNow.recv()`. Note that this method does not take a + timeout value as argument. + +.. method:: async AIOESPNow.airecv() + + Asyncio support for `ESPNow.irecv()`. Note that this method does not take a + timeout value as argument. + +.. method:: async AIOESPNow.asend(mac, msg, sync=True) + async AIOESPNow.asend(msg) + + Asyncio support for `ESPNow.send()`. + +.. method:: AIOESPNow._aiter__() / async AIOESPNow.__anext__() + + `AIOESPNow` also supports reading incoming messages by asynchronous + iteration using ``async for``; eg:: + + e = AIOESPNow() + e.active(True) + async def recv_till_halt(e): + async for mac, msg in e: + print(mac, msg) + if msg == b'halt': + break + asyncio.run(recv_till_halt(e)) + +Broadcast and Multicast +----------------------- + +All active ESPNow clients will receive messages sent to their MAC address and +all devices (**except ESP8266 devices**) will also receive messages sent to the +*broadcast* MAC address (``b'\xff\xff\xff\xff\xff\xff'``) or any multicast +MAC address. + +All ESPNow devices (including ESP8266 devices) can also send messages to the +broadcast MAC address or any multicast MAC address. + +To `send()` a broadcast message, the broadcast (or +multicast) MAC address must first be registered using +`add_peer()`. `send()` will always return +``True`` for broadcasts, regardless of whether any devices receive the +message. It is not permitted to encrypt messages sent to the broadcast +address or any multicast address. + +**Note**: `ESPNow.send(None, msg)` will send to all registered +peers *except* the broadcast address. To send a broadcast or multicast +message, you must specify the broadcast (or multicast) MAC address as the +peer. For example:: + + bcast = b'\xff' * 6 + e.add_peer(bcast) + e.send(bcast, "Hello World!") + +ESPNow and Wifi Operation +------------------------- + +ESPNow messages may be sent and received on any `active()` +`WLAN` interface (``network.WLAN.IF_STA`` or ``network.WLAN.IF_AP``), +even if that interface is also connected to a wifi network or configured as an access +point. When an ESP32 or ESP8266 device connects to a Wifi Access Point (see +`ESP32 Quickref <../esp32/quickref.html#networking>`__) the following things +happen which affect ESPNow communications: + +1. Wifi Power-saving Mode (`network.WLAN.PM_PERFORMANCE`) + is automatically activated and +2. The radio on the esp device changes wifi ``channel`` to match the channel + used by the Access Point. + +**Wifi Power-saving Mode:** (see `Espressif Docs `_) The power saving mode causes the +device to turn off the radio periodically (typically for hundreds of +milliseconds), making it unreliable in receiving ESPNow messages. This can be +resolved by either of: + +1. Disabling the power-saving mode on the STA_IF interface; + + - Use ``sta.config(pm=sta.PM_NONE)`` + +2. Turning on the AP_IF interface, which will disable the power saving mode. + However, the device will then be advertising an active wifi access point. + + - You **may** also choose to send your messages via the AP_IF interface, but + this is not necessary. + - ESP8266 peers must send messages to this AP_IF interface (see below). + +3. Configuring ESPNow clients to retry sending messages. + +**Receiving messages from an ESP8266 device:** Strangely, an ESP32 device +connected to a wifi network using method 1 or 2 above, will receive ESPNow +messages sent to the STA_IF MAC address from another ESP32 device, but will +**reject** messages from an ESP8266 device!!!. To receive messages from an +ESP8266 device, the AP_IF interface must be set to ``active(True)`` **and** +messages must be sent to the AP_IF MAC address. + +**Managing wifi channels:** Any other ESPNow devices wishing to communicate with +a device which is also connected to a Wifi Access Point MUST use the same +channel. A common scenario is where one ESPNow device is connected to a wifi +router and acts as a proxy for messages from a group of sensors connected via +ESPNow: + +**Proxy:** :: + + import network, time, espnow + + sta, ap = wifi_reset() # Reset wifi to AP off, STA on and disconnected + sta.connect('myssid', 'mypassword') + while not sta.isconnected(): # Wait until connected... + time.sleep(0.1) + sta.config(pm=sta.PM_NONE) # ..then disable power saving + + # Print the wifi channel used AFTER finished connecting to access point + print("Proxy running on channel:", sta.config("channel")) + e = espnow.ESPNow(); e.active(True) + for peer, msg in e: + # Receive espnow messages and forward them to MQTT broker over wifi + +**Sensor:** :: + + import network, espnow + + sta, ap = wifi_reset() # Reset wifi to AP off, STA on and disconnected + sta.config(channel=6) # Change to the channel used by the proxy above. + peer = b'0\xaa\xaa\xaa\xaa\xaa' # MAC address of proxy + e = espnow.ESPNow(); e.active(True); + e.add_peer(peer) + while True: + msg = read_sensor() + e.send(peer, msg) + time.sleep(1) + +Other issues to take care with when using ESPNow with wifi are: + +- **Set WIFI to known state on startup:** MicroPython does not reset the wifi + peripheral after a soft reset. This can lead to unexpected behaviour. To + guarantee the wifi is reset to a known state after a soft reset make sure you + deactivate the STA_IF and AP_IF before setting them to the desired state at + startup, eg.:: + + import network, time + + def wifi_reset(): # Reset wifi to AP_IF off, STA_IF on and disconnected + sta = network.WLAN(network.WLAN.IF_STA); sta.active(False) + ap = network.WLAN(network.WLAN.IF_AP); ap.active(False) + sta.active(True) + while not sta.active(): + time.sleep(0.1) + sta.disconnect() # For ESP8266 + while sta.isconnected(): + time.sleep(0.1) + return sta, ap + + sta, ap = wifi_reset() + + Remember that a soft reset occurs every time you connect to the device REPL + and when you type ``ctrl-D``. + +- **STA_IF and AP_IF always operate on the same channel:** the AP_IF will change + channel when you connect to a wifi network; regardless of the channel you set + for the AP_IF (see `Attention Note 3 + `_ + ). After all, there is really only one wifi radio on the device, which is + shared by the STA_IF and AP_IF virtual devices. + +- **Disable automatic channel assignment on your wifi router:** If the wifi + router for your wifi network is configured to automatically assign the wifi + channel, it may change the channel for the network if it detects interference + from other wifi routers. When this occurs, the ESP devices connected to the + wifi network will also change channels to match the router, but other + ESPNow-only devices will remain on the previous channel and communication will + be lost. To mitigate this, either set your wifi router to use a fixed wifi + channel or configure your devices to re-scan the wifi channels if they are + unable to find their expected peers on the current channel. + +- **MicroPython re-scans wifi channels when trying to reconnect:** If the esp + device is connected to a Wifi Access Point that goes down, MicroPython will + automatically start scanning channels in an attempt to reconnect to the + Access Point. This means ESPNow messages will be lost while scanning for the + AP. This can be disabled by ``sta.config(reconnects=0)``, which will also + disable the automatic reconnection after losing connection. + +- Some versions of the ESP IDF only permit sending ESPNow packets from the + STA_IF interface to peers which have been registered on the same wifi + channel as the STA_IF:: + + ESPNOW: Peer channel is not equal to the home channel, send fail! + +ESPNow and Sleep Modes +---------------------- + +The `machine.lightsleep([time_ms])` and +`machine.deepsleep([time_ms])` functions can be used to put +the ESP32 and peripherals (including the WiFi and Bluetooth radios) to sleep. +This is useful in many applications to conserve battery power. However, +applications must disable the WLAN peripheral (using +`active(False)`) before entering light or deep sleep (see +`Sleep Modes `_). +Otherwise the WiFi radio may not be initialised properly after wake from +sleep. If the ``STA_IF`` and ``AP_IF`` interfaces have both been set +`active(True)` then both interfaces should be set +`active(False)` before entering any sleep mode. + +**Example:** deep sleep:: + + import network, machine, espnow + + sta, ap = wifi_reset() # Reset wifi to AP off, STA on and disconnected + peer = b'0\xaa\xaa\xaa\xaa\xaa' # MAC address of peer + e = espnow.ESPNow() + e.active(True) + e.add_peer(peer) # Register peer on STA_IF + + print('Sending ping...') + if not e.send(peer, b'ping'): + print('Ping failed!') + e.active(False) + sta.active(False) # Disable the wifi before sleep + print('Going to sleep...') + machine.deepsleep(10000) # Sleep for 10 seconds then reboot + +**Example:** light sleep:: + + import network, machine, espnow + + sta, ap = wifi_reset() # Reset wifi to AP off, STA on and disconnected + sta.config(channel=6) + peer = b'0\xaa\xaa\xaa\xaa\xaa' # MAC address of peer + e = espnow.ESPNow() + e.active(True) + e.add_peer(peer) # Register peer on STA_IF + + while True: + print('Sending ping...') + if not e.send(peer, b'ping'): + print('Ping failed!') + sta.active(False) # Disable the wifi before sleep + print('Going to sleep...') + machine.lightsleep(10000) # Sleep for 10 seconds + sta.active(True) + sta.config(channel=6) # Wifi loses config after lightsleep() + diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 149f4d6609be9..f22a3613bdbcb 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -114,7 +114,7 @@ Drawing text .. method:: FrameBuffer.text(s, x, y[, c]) - Write text to the FrameBuffer using the the coordinates as the upper-left + Write text to the FrameBuffer using the coordinates as the upper-left corner of the text. The color of the text can be defined by the optional argument but is otherwise a default value of 1. All characters have dimensions of 8x8 pixels and there is currently no way to change the font. diff --git a/docs/library/gc.rst b/docs/library/gc.rst index c823aed3e688b..2ba204e2293c0 100644 --- a/docs/library/gc.rst +++ b/docs/library/gc.rst @@ -24,7 +24,7 @@ Functions .. function:: mem_alloc() - Return the number of bytes of heap RAM that are allocated. + Return the number of bytes of heap RAM that are allocated by Python code. .. admonition:: Difference to CPython :class: attention @@ -33,8 +33,8 @@ Functions .. function:: mem_free() - Return the number of bytes of available heap RAM, or -1 if this amount - is not known. + Return the number of bytes of heap RAM that is available for Python + code to allocate, or -1 if this amount is not known. .. admonition:: Difference to CPython :class: attention diff --git a/docs/library/gzip.rst b/docs/library/gzip.rst new file mode 100644 index 0000000000000..f36f896db3a11 --- /dev/null +++ b/docs/library/gzip.rst @@ -0,0 +1,106 @@ +:mod:`gzip` -- gzip compression & decompression +=============================================== + +.. module:: gzip + :synopsis: gzip compression & decompression + +|see_cpython_module| :mod:`python:gzip`. + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ used by the gzip +file format. + +.. note:: Prefer to use :class:`deflate.DeflateIO` instead of the functions in this + module as it provides a streaming interface to compression and decompression + which is convenient and more memory efficient when working with reading or + writing compressed data to a file, socket, or stream. + +**Availability:** + +* This module is **not present by default** in official MicroPython firmware + releases as it duplicates functionality available in the :mod:`deflate + ` module. + +* A copy of this module can be installed (or frozen) + from :term:`micropython-lib` (`source `_). + See :ref:`packages` for more information. This documentation describes that module. + +* Compression support will only be available if compression support is enabled + in the built-in :mod:`deflate ` module. + +Functions +--------- + +.. function:: open(filename, mode, /) + + Wrapper around built-in :func:`open` returning a GzipFile instance. + +.. function:: decompress(data, /) + + Decompresses *data* into a bytes object. + +.. function:: compress(data, /) + + Compresses *data* into a bytes object. + +Classes +------- + +.. class:: GzipFile(*, fileobj, mode) + + This class can be used to wrap a *fileobj* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + When the *mode* argument is ``"rb"``, reads from the GzipFile instance will + decompress the data in the underlying stream and return decompressed data. + + If compression support is enabled then the *mode* argument can be set to + ``"wb"``, and writes to the GzipFile instance will be compressed and written + to the underlying stream. + + By default the GzipFile class will read and write data using the gzip file + format, including a header and footer with checksum and a window size of 512 + bytes. + + The **file**, **compresslevel**, and **mtime** arguments are not + supported. **fileobj** and **mode** must always be specified as keyword + arguments. + +Examples +-------- + +A typical use case for :class:`gzip.GzipFile` is to read or write a compressed +file from storage: + +.. code:: python + + import gzip + + # Reading: + with open("data.gz", "rb") as f: + with gzip.GzipFile(fileobj=f, mode="rb") as g: + # Use g.read(), g.readinto(), etc. + + # Same, but using gzip.open: + with gzip.open("data.gz", "rb") as f: + # Use f.read(), f.readinto(), etc. + + # Writing: + with open("data.gz", "wb") as f: + with gzip.GzipFile(fileobj=f, mode="wb") as g: + # Use g.write(...) etc + + # Same, but using gzip.open: + with gzip.open("data.gz", "wb") as f: + # Use f.write(...) etc + + # Write a dictionary as JSON in gzip format, with a + # small (64 byte) window size. + config = { ... } + with gzip.open("config.gz", "wb") as f: + json.dump(config, f) + +For guidance on working with gzip sources and choosing the window size see the +note at the :ref:`end of the deflate documentation `. diff --git a/docs/library/index.rst b/docs/library/index.rst index 59ed1127a7836..2919378ce13b2 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -8,15 +8,17 @@ MicroPython libraries Important summary of this section * MicroPython provides built-in modules that mirror the functionality of the - Python standard library (e.g. :mod:`os`, :mod:`time`), as well as - MicroPython-specific modules (e.g. :mod:`bluetooth`, :mod:`machine`). - * Most standard library modules implement a subset of the functionality of - the equivalent Python module, and in a few cases provide some - MicroPython-specific extensions (e.g. :mod:`array`, :mod:`os`) + :ref:`Python standard library ` (e.g. :mod:`os`, + :mod:`time`), as well as :ref:`MicroPython-specific modules ` + (e.g. :mod:`bluetooth`, :mod:`machine`). + * Most Python standard library modules implement a subset of the + functionality of the equivalent Python module, and in a few cases provide + some MicroPython-specific extensions (e.g. :mod:`array`, :mod:`os`) * Due to resource constraints or other limitations, some ports or firmware versions may not include all the functionality documented here. - * To allow for extensibility, the built-in modules can be extended from - Python code loaded onto the device. + * To allow for extensibility, some built-in modules can be + :ref:`extended from Python code ` loaded onto + the device filesystem. This chapter describes modules (function and class libraries) which are built into MicroPython. This documentation in general aspires to describe all modules @@ -41,6 +43,8 @@ Beyond the built-in libraries described in this documentation, many more modules from the Python standard library, as well as further MicroPython extensions to it, can be found in :term:`micropython-lib`. +.. _micropython_lib_python: + Python standard libraries and micro-libraries --------------------------------------------- @@ -53,18 +57,22 @@ library. :maxdepth: 1 array.rst + asyncio.rst binascii.rst builtins.rst cmath.rst collections.rst errno.rst gc.rst + gzip.rst hashlib.rst heapq.rst io.rst json.rst + marshal.rst math.rst os.rst + platform.rst random.rst re.rst select.rst @@ -73,10 +81,10 @@ library. struct.rst sys.rst time.rst - uasyncio.rst zlib.rst _thread.rst +.. _micropython_lib_micropython: MicroPython-specific libraries ------------------------------ @@ -90,12 +98,15 @@ the following libraries. bluetooth.rst btree.rst cryptolib.rst + deflate.rst framebuf.rst machine.rst micropython.rst neopixel.rst network.rst + openamp.rst uctypes.rst + vfs.rst The following libraries provide drivers for hardware components. @@ -155,6 +166,11 @@ The following libraries are specific to the ESP8266 and ESP32. esp.rst esp32.rst +.. toctree:: + :maxdepth: 1 + + espnow.rst + Libraries specific to the RP2040 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -176,23 +192,60 @@ The following libraries are specific to the Zephyr port. zephyr.rst +.. _micropython_lib_extending: + Extending built-in libraries from Python ---------------------------------------- -In most cases, the above modules are actually named ``umodule`` rather than -``module``, but MicroPython will alias any module prefixed with a ``u`` to the -non-``u`` version. However a file (or :term:`frozen module`) named -``module.py`` will take precedence over this alias. +A subset of the built-in modules are able to be extended by Python code by +providing a module of the same name in the filesystem. This extensibility +applies to the following Python standard library modules which are built-in to +the firmware: ``array``, ``binascii``, ``collections``, ``errno``, ``gzip``, +``hashlib``, ``heapq``, ``io``, ``json``, ``os``, ``platform``, ``random``, +``re``, ``select``, ``socket``, ``ssl``, ``struct``, ``time`` ``zlib``, as well +as the MicroPython-specific ``machine`` module. All other built-in modules +cannot be extended from the filesystem. This allows the user to provide an extended implementation of a built-in library -(perhaps to provide additional CPython compatibility). The user-provided module -(in ``module.py``) can still use the built-in functionality by importing -``umodule`` directly. This is used extensively in :term:`micropython-lib`. See -:ref:`packages` for more information. - -This applies to both the Python standard libraries (e.g. ``os``, ``time``, etc), -but also the MicroPython libraries too (e.g. ``machine``, ``bluetooth``, etc). -The main exception is the port-specific libraries (``pyb``, ``esp``, etc). - -*Other than when you specifically want to force the use of the built-in module, -we recommend always using* ``import module`` *rather than* ``import umodule``. +(perhaps to provide additional CPython compatibility or missing functionality). +This is used extensively in :term:`micropython-lib`, see :ref:`packages` for +more information. The filesystem module will typically do a wildcard import of +the built-in module in order to inherit all the globals (classes, functions and +variables) from the built-in. + +In MicroPython v1.21.0 and higher, to prevent the filesystem module from +importing itself, it can force an import of the built-in module it by +temporarily clearing ``sys.path`` during the import. For example, to extend the +``time`` module from Python, a file named ``time.py`` on the filesystem would +do the following:: + + _path = sys.path + sys.path = () + try: + from time import * + finally: + sys.path = _path + del _path + + def extra_method(): + pass + +The result is that ``time.py`` contains all the globals of the built-in ``time`` +module, but adds ``extra_method``. + +In earlier versions of MicroPython, you can force an import of a built-in module +by appending a ``u`` to the start of its name. For example, ``import utime`` +instead of ``import time``. For example, ``time.py`` on the filesystem could +look like:: + + from utime import * + + def extra_method(): + pass + +This way is still supported, but the ``sys.path`` method described above is now +preferred as the ``u``-prefix will be removed from the names of built-in +modules in a future version of MicroPython. + +*Other than when it specifically needs to force the use of the built-in module, +code should always use* ``import module`` *rather than* ``import umodule``. diff --git a/docs/library/io.rst b/docs/library/io.rst index 6b4b9f1a476f6..caa59895227d4 100644 --- a/docs/library/io.rst +++ b/docs/library/io.rst @@ -86,16 +86,6 @@ Functions Classes ------- -.. class:: FileIO(...) - - This is type of a file open in binary mode, e.g. using ``open(name, "rb")``. - You should not instantiate this class directly. - -.. class:: TextIOWrapper(...) - - This is type of a file open in text mode, e.g. using ``open(name, "rt")``. - You should not instantiate this class directly. - .. class:: StringIO([string]) .. class:: BytesIO([string]) diff --git a/docs/library/machine.ADC.rst b/docs/library/machine.ADC.rst index eb538a4424f6f..65225ea8788da 100644 --- a/docs/library/machine.ADC.rst +++ b/docs/library/machine.ADC.rst @@ -4,7 +4,7 @@ class ADC -- analog to digital conversion ========================================= -The ADC class provides an interface to analog-to-digital convertors, and +The ADC class provides an interface to analog-to-digital converters, and represents a single endpoint that can sample a continuous voltage and convert it to a discretised value. diff --git a/docs/library/machine.ADCBlock.rst b/docs/library/machine.ADCBlock.rst index 56a468dd621b2..e947f70815071 100644 --- a/docs/library/machine.ADCBlock.rst +++ b/docs/library/machine.ADCBlock.rst @@ -26,7 +26,7 @@ Constructors Access the ADC peripheral identified by *id*, which may be an integer or string. - + The *bits* argument, if given, sets the resolution in bits of the conversion process. If not specified then the previous or default resolution is used. @@ -39,9 +39,9 @@ Methods Configure the ADC peripheral. *bits* will set the resolution of the conversion process. -.. method:: ADCBlock.connect(channel) - ADCBlock.connect(source) - ADCBlock.connect(channel, source) +.. method:: ADCBlock.connect(channel, *, ...) + ADCBlock.connect(source, *, ...) + ADCBlock.connect(channel, source, *, ...) Connect up a channel on the ADC peripheral so it is ready for sampling, and return an :ref:`ADC ` object that represents that connection. @@ -56,3 +56,6 @@ Methods If both *channel* and *source* are given then they are connected together and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. diff --git a/docs/library/machine.I2C.rst b/docs/library/machine.I2C.rst index bfc9f7ebcc9b4..635d5873444b5 100644 --- a/docs/library/machine.I2C.rst +++ b/docs/library/machine.I2C.rst @@ -94,7 +94,7 @@ General Methods - *freq* is the SCL clock rate In the case of hardware I2C the actual clock frequency may be lower than the - requested frequency. This is dependant on the platform hardware. The actual + requested frequency. This is dependent on the platform hardware. The actual rate may be determined by printing the I2C object. .. method:: I2C.deinit() diff --git a/docs/library/machine.I2S.rst b/docs/library/machine.I2S.rst index b602ac6504d3c..84edb94e78dbf 100644 --- a/docs/library/machine.I2S.rst +++ b/docs/library/machine.I2S.rst @@ -47,7 +47,7 @@ I2S objects can be created and initialized using:: 3 modes of operation are supported: - blocking - non-blocking - - uasyncio + - asyncio blocking:: @@ -63,13 +63,13 @@ non-blocking:: audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled num_read = audio_in.readinto(buf) # returns immediately -uasyncio:: +asyncio:: - swriter = uasyncio.StreamWriter(audio_out) + swriter = asyncio.StreamWriter(audio_out) swriter.write(buf) await swriter.drain() - sreader = uasyncio.StreamReader(audio_in) + sreader = asyncio.StreamReader(audio_in) num_read = await sreader.readinto(buf) Some codec devices like the WM8960 or SGTL5000 require separate initialization @@ -103,7 +103,7 @@ Constructor - ``ibuf`` specifies internal buffer length (bytes) For all ports, DMA runs continuously in the background and allows user applications to perform other operations while - sample data is transfered between the internal buffer and the I2S peripheral unit. + sample data is transferred between the internal buffer and the I2S peripheral unit. Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method). diff --git a/docs/library/machine.PWM.rst b/docs/library/machine.PWM.rst index 4b74355775602..5f592b8dff593 100644 --- a/docs/library/machine.PWM.rst +++ b/docs/library/machine.PWM.rst @@ -10,7 +10,8 @@ Example usage:: from machine import PWM - pwm = PWM(pin) # create a PWM object on a pin + pwm = PWM(pin, freq=50, duty_u16=8192) # create a PWM object on a pin + # and set freq and duty pwm.duty_u16(32768) # set duty to 50% # reinitialise with a period of 200us, duty of 5us @@ -23,7 +24,7 @@ Example usage:: Constructors ------------ -.. class:: PWM(dest, *, freq, duty_u16, duty_ns) +.. class:: PWM(dest, *, freq, duty_u16, duty_ns, invert) Construct and return a new PWM object using the following parameters: @@ -34,10 +35,12 @@ Constructors PWM cycle. - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``. - *duty_ns* sets the pulse width in nanoseconds. + - *invert* inverts the respective output if the value is True Setting *freq* may affect other PWM objects if the objects share the same underlying PWM generator (this is hardware specific). Only one of *duty_u16* and *duty_ns* should be specified at a time. + *invert* is not available at all ports. Methods ------- @@ -83,7 +86,7 @@ Specific PWM class implementations The following concrete class(es) implement enhancements to the PWM class. - | :ref:`pyb.Timer for PyBoard ` + | :ref:`pyb.Timer for PyBoard ` Limitations of PWM ------------------ @@ -100,7 +103,7 @@ Limitations of PWM Some ports like the RP2040 one use a fractional divider, which allow a finer granularity of the frequency at higher frequencies by switching the PWM pulse duration between two adjacent values, such that the resulting average - frequency is more close to the intended one, at the cost of spectral purity. + frequency is more close to the intended one, at the cost of spectral purity. * The duty cycle has the same discrete nature and its absolute accuracy is not achievable. On most hardware platforms the duty will be applied at the next diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index 49fb66beb38ea..4aac0f4b94be2 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -209,13 +209,13 @@ The following methods are not part of the core Pin API and only implemented on c Set pin to "0" output level. - Availability: nrf, rp2, stm32 ports. + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. .. method:: Pin.high() Set pin to "1" output level. - Availability: nrf, rp2, stm32 ports. + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. .. method:: Pin.mode([mode]) @@ -238,6 +238,12 @@ The following methods are not part of the core Pin API and only implemented on c Availability: cc3200 port. +.. method:: Pin.toggle() + + Toggle output pin from "0" to "1" or vice-versa. + + Availability: cc3200, esp32, esp8266, mimxrt, rp2, samd ports. + Constants --------- diff --git a/docs/library/machine.RTC.rst b/docs/library/machine.RTC.rst index be2be2eee5eea..e2ddd728bde4c 100644 --- a/docs/library/machine.RTC.rst +++ b/docs/library/machine.RTC.rst @@ -42,12 +42,21 @@ Methods Initialise the RTC. Datetime is a tuple of the form: - ``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])`` + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. .. method:: RTC.now() Get get the current datetime tuple. + Availability: WiPy. + .. method:: RTC.deinit() Resets the RTC to the time of January 1, 2015 and starts running it again. @@ -62,10 +71,13 @@ Methods Get the number of milliseconds left before the alarm expires. -.. method:: RTC.cancel(alarm_id=0) +.. method:: RTC.alarm_cancel(alarm_id=0) Cancel a running alarm. + The mimxrt port also exposes this function as ``RTC.cancel(alarm_id=0)``, but this is + scheduled to be removed in MicroPython 2.0. + .. method:: RTC.irq(*, trigger, handler=None, wake=machine.IDLE) Create an irq object triggered by a real time clock alarm. @@ -75,6 +87,21 @@ Methods - ``wake`` specifies the sleep mode from where this interrupt can wake up the system. +.. method:: RTC.memory([data]) + + ``RTC.memory(data)`` will write *data* to the RTC memory, where *data* is any + object which supports the buffer protocol (including `bytes`, `bytearray`, + `memoryview` and `array.array`). ``RTC.memory()`` reads RTC memory and returns + a `bytes` object. + + Data written to RTC user memory is persistent across restarts, including + :ref:`soft_reset` and `machine.deepsleep()`. + + The maximum length of RTC user memory is 2048 bytes by default on esp32, + and 492 bytes on esp8266. + + Availability: esp32, esp8266 ports. + Constants --------- diff --git a/docs/library/machine.SD.rst b/docs/library/machine.SD.rst index c736dc4d2836e..b10b407a2f65e 100644 --- a/docs/library/machine.SD.rst +++ b/docs/library/machine.SD.rst @@ -20,11 +20,11 @@ more info regarding the pins which can be remapped to be used with a SD card. Example usage:: from machine import SD - import os + import vfs # clk cmd and dat0 pins must be passed along with # their respective alternate functions sd = machine.SD(pins=('GP10', 'GP11', 'GP15')) - os.mount(sd, '/sd') + vfs.mount(sd, '/sd') # do normal file operations Constructors diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst index cde0bd1d145d9..c4a0d5d172b30 100644 --- a/docs/library/machine.SDCard.rst +++ b/docs/library/machine.SDCard.rst @@ -23,21 +23,23 @@ 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) +.. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, + cs=None, cmd=None, data=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:`os.AbstractBlockDev`. + The class implements the block protocol defined by :class:`vfs.AbstractBlockDev`. This allows the mounting of an SD card to be as simple as:: - os.mount(machine.SDCard(), "/sd") + vfs.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. + - *width* selects the bus width for the SD/MMC interface. This many data + pins must be connected to the SD card. - *cd* can be used to specify a card-detect pin. @@ -51,7 +53,14 @@ vary from platform to platform. - *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). + The following additional parameters are only present on ESP32 port: + + - *cmd* can be used to specify the SD CMD pin (ESP32-S3 only). + + - *data* can be used to specify a list or tuple of SD data bus pins + (ESP32-S3 only). + + - *freq* selects the SD/MMC interface frequency in Hz. Implementation-specific details ------------------------------- @@ -67,52 +76,130 @@ 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 - ====== ====== ====== ====== ====== +SD cards support access in both SD/MMC mode and the simpler (but slower) SPI +mode. + +SPI mode makes use of a `SPI` host peripheral, which cannot concurrently be used +for other SPI interactions. + +The ``slot`` argument determines which mode is used. Different values are +supported on different chips: + +========== ======== ======== ============ ============ +Chip Slot 0 Slot 1 Slot 2 Slot 3 +========== ======== ======== ============ ============ +ESP32 SD/MMC SPI (id=1) SPI (id=0) +ESP32-C3 SPI (id=0) +ESP32-C6 SPI (id=0) +ESP32-S2 SPI (id=1) SPI (id=0) +ESP32-S3 SD/MMC SD/MMC SPI (id=1) SPI (id=0) +========== ======== ======== ============ ============ + +Different slots support different data bus widths (number of data pins): + +========== ========== ===================== +Slot Type Supported data widths +========== ========== ===================== +0 SD/MMC 1, 4, 8 +1 SD/MMC 1, 4 +2 SPI 1 +3 SPI 1 +========== ========== ===================== + +.. 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. + +Additional details depend on which ESP32 family chip is in use: + +Original ESP32 +~~~~~~~~~~~~~~ + +In SD/MMC mode (slot 1), pin assignments in SD/MMC mode are fixed on the +original ESP32. The SPI mode slots (2 & 3) allow pins to be set to different +values in the constructor. + +The default pin assignments are as follows: + + ====== ====== ====== ====== ============ + Slot 1 2 3 Can be set + ------ ------ ------ ------ ------------ + Signal Pin Pin Pin + ====== ====== ====== ====== ============ + CLK 14 No + CMD 15 No + D0 2 No + D1 4 No + D2 12 No + D3 13 No + sck 18 14 Yes + cs 5 15 Yes + miso 19 12 Yes + mosi 23 13 Yes + ====== ====== ====== ====== ============ + +The ``cd`` and ``wp`` pins are not fixed in either mode and default to disabled, unless set. + +ESP32-S3 +~~~~~~~~ + +The ESP32-S3 chip allows pins to be set to different values for both SD/MMC and +SPI mode access. + +If not set, default pin assignments are as follows: + + ======== ====== ====== ====== ====== + Slot 0 1 2 3 + -------- ------ ------ ------ ------ + Signal Pin Pin Pin Pin + ======== ====== ====== ====== ====== + CLK 14 14 + CMD 15 15 + D0 2 2 + D1 4 4 + D2 12 12 + D3 13 13 + D4 33* + D5 34* + D6 35* + D7 36* + sck 37* 14 + cs 34* 13 + miso 37* 2 + mosi 35* 15 + ======== ====== ====== ====== ====== + +.. note:: Slots 0 and 1 cannot both be in use at the same time. + +.. note:: Pins marked with an asterisk * in the table must be changed from the + default if the ESP32-S3 board is configured for Octal SPI Flash or + PSRAM. + +To access a card in SD/MMC mode, set ``slot`` parameter value 0 or 1 and +parameters ``sck`` (for CLK), ``cmd`` and ``data`` as needed to assign pins. If +the ``data`` argument is passed then it should be a list or tuple of data pins +or pin numbers with length equal to the ``width`` argument. For example:: + + sd = SDCard(slot=0, width=4, sck=8, cmd=9, data=(10, 11, 12, 13)) + +To access a card in SPI mode, set ``slot`` parameter value 2 or 3 and pass +parameters ``sck``, ``cs``, ``miso``, ``mosi`` as needed to assign pins. + +In either mode the ``cd`` and ``wp`` pins default to disabled, unless set in the +constructor. + +Other ESP32 chips +~~~~~~~~~~~~~~~~~ + +Other ESP32 family chips do not have hardware SD/MMC host controllers and can +only access SD cards in SPI mode. + +To access a card in SPI mode, set ``slot`` parameter value 2 or 3 and pass +parameters ``sck``, ``cs``, ``miso``, ``mosi`` to assign pins. + +.. note:: ESP32-C3 and ESP32-C6 only have one available `SPI` bus, so the only + valid ``slot`` parameter value is 2. Using this bus for the SD card + will prevent also using it for :class:`machine.SPI`. cc3200 `````` diff --git a/docs/library/machine.SPI.rst b/docs/library/machine.SPI.rst index 7b0e8cf40689f..7c3c4b583265a 100644 --- a/docs/library/machine.SPI.rst +++ b/docs/library/machine.SPI.rst @@ -98,7 +98,7 @@ Methods specify them as a tuple of ``pins`` parameter. In the case of hardware SPI the actual clock frequency may be lower than the - requested baudrate. This is dependant on the platform hardware. The actual + requested baudrate. This is dependent on the platform hardware. The actual rate may be determined by printing the SPI object. .. method:: SPI.deinit() diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst index 48c023a11c342..44e6594080558 100644 --- a/docs/library/machine.Timer.rst +++ b/docs/library/machine.Timer.rst @@ -73,7 +73,7 @@ Methods - ``callback`` - The callable to call upon expiration of the timer period. The callback must take one argument, which is passed the Timer object. The ``callback`` argument shall be specified. Otherwise an exception - will occurr upon timer expiration: + will occur upon timer expiration: ``TypeError: 'NoneType' object isn't callable`` .. method:: Timer.deinit() diff --git a/docs/library/machine.TimerWiPy.rst b/docs/library/machine.TimerWiPy.rst index f8c8bb29da7fb..54280a5994ad5 100644 --- a/docs/library/machine.TimerWiPy.rst +++ b/docs/library/machine.TimerWiPy.rst @@ -71,7 +71,7 @@ Methods Otherwise, a TimerChannel object is initialized and returned. - The operating mode is is the one configured to the Timer object that was used to + The operating mode is the one configured to the Timer object that was used to create the channel. - ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``. diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index 072bdb7188a3d..5be79cccce884 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -83,7 +83,7 @@ Methods - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). Any of the pins can be None if one wants the UART to operate with limited functionality. - If the RTS pin is given the the RX pin must be given as well. The same applies to CTS. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. When no pins are given, then the default set of TX and RX pins is taken, and hardware flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. @@ -152,31 +152,6 @@ Methods Send a break condition on the bus. This drives the bus low for a duration longer than required for a normal transmission of a character. -.. method:: UART.irq(trigger, priority=1, handler=None, wake=machine.IDLE) - - Create a callback to be triggered when data is received on the UART. - - - *trigger* can only be ``UART.RX_ANY`` - - *priority* level of the interrupt. Can take values in the range 1-7. - Higher values represent higher priorities. - - *handler* an optional function to be called when new characters arrive. - - *wake* can only be ``machine.IDLE``. - - .. note:: - - The handler will be called whenever any of the following two conditions are met: - - - 8 new characters have been received. - - At least 1 new character is waiting in the Rx buffer and the Rx line has been - silent for the duration of 1 complete frame. - - This means that when the handler function is called there will be between 1 to 8 - characters waiting. - - Returns an irq object. - - Availability: WiPy. - .. method:: UART.flush() Waits until all data has been sent. In case of a timeout, an exception is raised. The timeout @@ -185,7 +160,7 @@ Methods .. note:: - For the rp2, esp8266 and nrf ports the call returns while the last byte is sent. + For the esp8266 and nrf ports the call returns while the last byte is sent. If required, a one character wait time has to be added in the calling script. Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra @@ -197,17 +172,91 @@ Methods .. note:: - For the rp2, esp8266 and nrf ports the call may return ``True`` even if the last byte + For the esp8266 and nrf ports the call may return ``True`` even if the last byte of a transfer is still being sent. If required, a one character wait time has to be added in the calling script. Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra +.. method:: UART.irq(handler=None, trigger=0, hard=False) + + Configure an interrupt handler to be called when a UART event occurs. + + The arguments are: + + - *handler* is an optional function to be called when the interrupt event + triggers. The handler must take exactly one argument which is the + ``UART`` instance. + + - *trigger* configures the event(s) which can generate an interrupt. + Possible values are a mask of one or more of the following: + + - ``UART.IRQ_RXIDLE`` interrupt after receiving at least one character + and then the RX line goes idle. + - ``UART.IRQ_RX`` interrupt after each received character. + - ``UART.IRQ_TXIDLE`` interrupt after or while the last character(s) of + a message are or have been sent. + - ``UART.IRQ_BREAK`` interrupt when a break state is detected at RX + + - *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`. + + Returns an irq object. + + Due to limitations of the hardware not all trigger events are available on all ports. + + .. table:: Availability of triggers + :align: center + + ============== ========== ====== ========== ========= + Port / Trigger IRQ_RXIDLE IRQ_RX IRQ_TXIDLE IRQ_BREAK + ============== ========== ====== ========== ========= + CC3200 yes + ESP32 yes yes yes + MIMXRT yes yes + NRF yes yes + RENESAS-RA yes yes + RP2 yes yes yes + SAMD yes yes yes + STM32 yes yes + ============== ========== ====== ========== ========= + + + .. note:: + - The ESP32 port does not support the option hard=True. + + - The rp2 port's UART.IRQ_TXIDLE is only triggered when the message + is longer than 5 characters and the trigger happens when still 5 characters + are to be sent. + + - The rp2 port's UART.IRQ_BREAK needs receiving valid characters for triggering + again. + + - The SAMD port's UART.IRQ_TXIDLE is triggered while the last character is sent. + + - On STM32F4xx MCU's, using the trigger UART.IRQ_RXIDLE the handler will be called once + after the first character and then after the end of the message, when the line is + idle. + + + Availability: cc3200, esp32, mimxrt, nrf, renesas-ra, rp2, samd, stm32. + Constants --------- -.. data:: UART.RX_ANY +.. data:: UART.RTS + UART.CTS + + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + +.. data:: UART.IRQ_RXIDLE + UART.IRQ_RX + UART.IRQ_TXIDLE + UART.IRQ_BREAK - IRQ trigger sources + IRQ trigger sources. - Availability: WiPy. + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. diff --git a/docs/library/machine.USBDevice.rst b/docs/library/machine.USBDevice.rst new file mode 100644 index 0000000000000..5291679ac1258 --- /dev/null +++ b/docs/library/machine.USBDevice.rst @@ -0,0 +1,304 @@ +.. currentmodule:: machine +.. _machine.USBDevice: + +class USBDevice -- USB Device driver +==================================== + +.. note:: ``machine.USBDevice`` is currently only supported for esp32, rp2 and + samd ports. Native USB support is also required, and not every board + supports native USB. + +USBDevice provides a low-level Python API for implementing USB device functions using +Python code. + +.. warning:: This low-level API assumes familiarity with the USB standard. There + are high-level `usb driver modules in micropython-lib`_ which provide a + simpler interface and more built-in functionality. + +Terminology +----------- + +- A "Runtime" USB device interface or driver is one which is defined using this + Python API after MicroPython initially starts up. + +- A "Built-in" USB device interface or driver is one that is compiled into the + MicroPython firmware, and is always available. Examples are USB-CDC (serial + port) which is usually enabled by default. Built-in USB-MSC (Mass Storage) is an + option on some ports. + +Lifecycle +--------- + +Managing a runtime USB interface can be tricky, especially if you are communicating +with MicroPython over a built-in USB-CDC serial port that's part of the same USB +device. + +- A MicroPython :ref:`soft reset ` will always clear all runtime USB + interfaces, which results in the entire USB device disconnecting from the + host. If MicroPython is also providing a built-in USB-CDC serial port then + this will re-appear after the soft reset. + + This means some functions (like ``mpremote run``) that target the USB-CDC + serial port will immediately fail if a runtime USB interface is active, + because the port goes away when ``mpremote`` triggers a soft reset. The + operation should succeed on the second try, as after the soft reset there is + no more runtime USB interface. + +- To configure a runtime USB device on every boot, it's recommended to place the + configuration code in the :ref:`boot.py` file on the :ref:`device VFS + `. On each reset this file is executed before the USB subsystem is + initialised (and before :ref:`main.py`), so it allows the board to come up with the runtime + USB device immediately. + +- For development or debugging, it may be convenient to connect a hardware + serial REPL and disable the built-in USB-CDC serial port entirely. Not all ports + support this (currently only ``rp2``). The custom build should be configured + with ``#define MICROPY_HW_USB_CDC (0)`` and ``#define + MICROPY_HW_ENABLE_UART_REPL (1)``. + +Constructors +------------ + +.. class:: USBDevice() + + Construct a USBDevice object. + + .. note:: This object is a singleton, each call to this constructor + returns the same object reference. + +Methods +------- + +.. method:: USBDevice.config(desc_dev, desc_cfg, desc_strs=None, open_itf_cb=None, reset_cb=None, control_xfer_cb=None, xfer_cb=None) + + Configures the ``USBDevice`` singleton object with the USB runtime device + state and callback functions: + + - ``desc_dev`` - A bytes-like object containing + the new USB device descriptor. + + - ``desc_cfg`` - A bytes-like object containing the + new USB configuration descriptor. + + - ``desc_strs`` - Optional object holding strings or bytes objects + containing USB string descriptor values. Can be a list, a dict, or any + object which supports subscript indexing with integer keys (USB string + descriptor index). + + Strings are an optional USB feature, and this parameter can be unset + (default) if no strings are referenced in the device and configuration + descriptors, or if only built-in strings should be used. + + Apart from index 0, all the string values should be plain ASCII. Index 0 + is the special "languages" USB descriptor, represented as a bytes object + with a custom format defined in the USB standard. ``None`` can be + returned at index 0 in order to use a default "English" language + descriptor. + + To fall back to providing a built-in string value for a given index, a + subscript lookup can return ``None``, raise ``KeyError``, or raise + ``IndexError``. + + - ``open_itf_cb`` - This callback is called once for each interface + or Interface Association Descriptor in response to a Set + Configuration request from the USB Host (the final stage before + the USB device is available to the host). + + The callback takes a single argument, which is a memoryview of the + interface or IAD descriptor that the host is accepting (including + all associated descriptors). It is a view into the same + ``desc_cfg`` object that was provided as a separate + argument to this function. The memoryview is only valid until the + callback function returns. + + - ``reset_cb`` - This callback is called when the USB host performs + a bus reset. The callback takes no arguments. Any in-progress + transfers will never complete. The USB host will most likely + proceed to re-enumerate the USB device by calling the descriptor + callbacks and then ``open_itf_cb()``. + + - ``control_xfer_cb`` - This callback is called one or more times + for each USB control transfer (device Endpoint 0). It takes two + arguments. + + The first argument is the control transfer stage. It is one of: + + - ``1`` for SETUP stage. + - ``2`` for DATA stage. + - ``3`` for ACK stage. + + Second argument is a memoryview to read the USB control request + data for this stage. The memoryview is only valid until the + callback function returns. Data in this memoryview will be the same + across each of the three stages of a single transfer. + + A successful transfer consists of this callback being called in sequence + for the three stages. Generally speaking, if a device wants to do + something in response to a control request then it's best to wait until + the ACK stage to confirm the host controller completed the transfer as + expected. + + The callback should return one of the following values: + + - ``False`` to stall the endpoint and reject the transfer. It won't + proceed to any remaining stages. + - ``True`` to continue the transfer to the next stage. + - A buffer object can be returned at the SETUP stage when the transfer + will send or receive additional data. Typically this is the case when + the ``wLength`` field in the request has a non-zero value. This should + be a writable buffer for an ``OUT`` direction transfer, or a readable + buffer with data for an ``IN`` direction transfer. + + - ``xfer_cb`` - This callback is called whenever a non-control + transfer submitted by calling :func:`USBDevice.submit_xfer` completes. + + The callback has three arguments: + + 1. The Endpoint number for the completed transfer. + 2. Result value: ``True`` if the transfer succeeded, ``False`` + otherwise. + 3. Number of bytes successfully transferred. In the case of a + "short" transfer, The result is ``True`` and ``xferred_bytes`` + will be smaller than the length of the buffer submitted for the + transfer. + + .. note:: If a bus reset occurs (see :func:`USBDevice.reset`), + ``xfer_cb`` is not called for any transfers that have not + already completed. + +.. method:: USBDevice.active(self, [value] /) + + Returns the current active state of this runtime USB device as a + boolean. The runtime USB device is "active" when it is available to + interact with the host, it doesn't mean that a USB Host is actually + present. + + If the optional ``value`` argument is set to a truthy value, then + the USB device will be activated. + + If the optional ``value`` argument is set to a falsey value, then + the USB device is deactivated. While the USB device is deactivated, + it will not be detected by the USB Host. + + To simulate a disconnect and a reconnect of the USB device, call + ``active(False)`` followed by ``active(True)``. This may be + necessary if the runtime device configuration has changed, so that + the host sees the new device. + +.. attribute:: USBDevice.builtin_driver + + This attribute holds the current built-in driver configuration, and must be + set to one of the ``USBDevice.BUILTIN_`` named constants defined on this object. + + By default it holds the value :data:`USBDevice.BUILTIN_NONE`. + + Runtime USB device must be inactive when setting this field. Call the + :func:`USBDevice.active` function to deactivate before setting if necessary + (and again to activate after setting). + + If this value is set to any value other than :data:`USBDevice.BUILTIN_NONE` then + the following restrictions apply to the :func:`USBDevice.config` arguments: + + - ``desc_cfg`` should begin with the built-in USB interface descriptor data + accessible via :data:`USBDevice.builtin_driver` attribute ``desc_cfg``. + Descriptors appended after the built-in configuration descriptors should use + interface, string and endpoint numbers starting from the max built-in values + defined in :data:`USBDevice.builtin_driver` attributes ``itf_max``, ``str_max`` and + ``ep_max``. + + - The ``bNumInterfaces`` field in the built-in configuration + descriptor will also need to be updated if any new interfaces + are appended to the end of ``desc_cfg``. + + - ``desc_strs`` should either be ``None`` or a list/dictionary where index + values less than ``USBDevice.builtin_driver.str_max`` are missing or have + value ``None``. This reserves those string indexes for the built-in + drivers. Placing a different string at any of these indexes overrides that + string in the built-in driver. + +.. method:: USBDevice.remote_wakeup(self) + + Wake up host if we are in suspend mode and the REMOTE_WAKEUP feature + is enabled by the host. This has to be enabled in the USB attributes, + and on the host. Returns ``True`` if remote wakeup was enabled and + active and the host was woken up. + +.. method:: USBDevice.submit_xfer(self, ep, buffer /) + + Submit a USB transfer on endpoint number ``ep``. ``buffer`` must be + an object implementing the buffer interface, with read access for + ``IN`` endpoints and write access for ``OUT`` endpoints. + + .. note:: ``ep`` cannot be the control Endpoint number 0. Control + transfers are built up through successive executions of + ``control_xfer_cb``, see above. + + Returns ``True`` if successful, ``False`` if the transfer could not + be queued (as USB device is not configured by host, or because + another transfer is queued on this endpoint.) + + When the USB host completes the transfer, the ``xfer_cb`` callback + is called (see above). + + Raises ``OSError`` with reason ``MP_EINVAL`` If the USB device is not + active. + +.. method:: USBDevice.stall(self, ep, [stall] /) + + Calling this function gets or sets the STALL state of a device endpoint. + + ``ep`` is the number of the endpoint. + + If the optional ``stall`` parameter is set, this is a boolean flag + for the STALL state. + + The return value is the current stall state of the endpoint (before + any change made by this function). + + An endpoint that is set to STALL may remain stalled until this + function is called again, or STALL may be cleared automatically by + the USB host. + + Raises ``OSError`` with reason ``MP_EINVAL`` If the USB device is not + active. + +Constants +--------- + +.. data:: USBDevice.BUILTIN_NONE +.. data:: USBDevice.BUILTIN_DEFAULT +.. data:: USBDevice.BUILTIN_CDC +.. data:: USBDevice.BUILTIN_MSC +.. data:: USBDevice.BUILTIN_CDC_MSC + + These constant objects hold the built-in descriptor data which is + compiled into the MicroPython firmware. ``USBDevice.BUILTIN_NONE`` and + ``USBDevice.BUILTIN_DEFAULT`` are always present. Additional objects may be present + depending on the firmware build configuration and the actual built-in drivers. + + .. note:: Currently at most one of ``USBDevice.BUILTIN_CDC``, + ``USBDevice.BUILTIN_MSC`` and ``USBDevice.BUILTIN_CDC_MSC`` is defined + and will be the same object as ``USBDevice.BUILTIN_DEFAULT``. + These constants are defined to allow run-time detection of + the built-in driver (if any). Support for selecting one of + multiple built-in driver configurations may be added in the + future. + + These values are assigned to :data:`USBDevice.builtin_driver` to get/set the + built-in configuration. + + Each object contains the following read-only fields: + + - ``itf_max`` - One more than the highest bInterfaceNumber value used + in the built-in configuration descriptor. + - ``ep_max`` - One more than the highest bEndpointAddress value used + in the built-in configuration descriptor. Does not include any + ``IN`` flag bit (0x80). + - ``str_max`` - One more than the highest string descriptor index + value used by any built-in descriptor. + - ``desc_dev`` - ``bytes`` object containing the built-in USB device + descriptor. + - ``desc_cfg`` - ``bytes`` object containing the complete built-in USB + configuration descriptor. + +.. _usb driver modules in micropython-lib: https://github.com/micropython/micropython-lib/tree/master/micropython/usb#readme diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst index 95893cec36be7..cf77df9632088 100644 --- a/docs/library/machine.WDT.rst +++ b/docs/library/machine.WDT.rst @@ -25,9 +25,8 @@ Constructors 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. On rp2040 devices, - the maximum timeout is 8388 ms. + Notes: On the esp8266 a timeout cannot be specified, it is determined by the underlying system. + On rp2040 devices, the maximum timeout is 8388 ms. Methods ------- diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 3f5cd6f13c72b..76d111f11ef3d 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -62,14 +62,13 @@ Reset related functions .. function:: reset() - Resets the device in a manner similar to pushing the external RESET - button. + :ref:`Hard 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). + Performs a :ref:`soft reset ` of the interpreter, deleting all + Python objects and resetting the Python heap. .. function:: reset_cause() @@ -127,14 +126,20 @@ Power related functions .. function:: idle() - Gates the clock to the CPU, useful to reduce power consumption at any time during - short or long periods. Peripherals continue working and execution resumes as soon - as any interrupt is triggered (on many ports this includes system timer - interrupt occurring at regular intervals on the order of millisecond). + Gates the clock to the CPU, useful to reduce power consumption at any time + during short or long periods. Peripherals continue working and execution + resumes as soon as any interrupt is triggered, or at most one millisecond + after the CPU was paused. + + It is recommended to call this function inside any tight loop that is + continuously checking for an external change (i.e. polling). This will reduce + power consumption without significantly impacting performance. To reduce + power consumption further then see the :func:`lightsleep`, + :func:`time.sleep()` and :func:`time.sleep_ms()` functions. .. function:: sleep() - .. note:: This function is deprecated, use `lightsleep()` instead with no arguments. + .. note:: This function is deprecated, use :func:`lightsleep()` instead with no arguments. .. function:: lightsleep([time_ms]) deepsleep([time_ms]) @@ -265,3 +270,4 @@ Classes machine.WDT.rst machine.SD.rst machine.SDCard.rst + machine.USBDevice.rst diff --git a/docs/library/marshal.rst b/docs/library/marshal.rst new file mode 100644 index 0000000000000..6d3213e0a6ec8 --- /dev/null +++ b/docs/library/marshal.rst @@ -0,0 +1,28 @@ +:mod:`marshal` -- Python object serialization +============================================= + +.. module:: marshal + :synopsis: Convert Python objects to and from a binary format + +|see_cpython_module| :mod:`python:marshal`. + +This module implements conversion between Python objects and a binary format. +The format is specific to MicroPython but does not depend on the machine +architecture, so the data can be transferred and used on a different MicroPython +instance, as long as the version of the binary data matches (it's currently +versioned as the mpy file version, see :ref:`mpy_files`). + +Functions +--------- + +.. function:: dumps(value, /) + + Convert the given *value* to binary format and return a corresponding ``bytes`` + object. + + Currently, code objects are the only supported values that can be converted. + +.. function:: loads(data, /) + + Convert the given bytes-like *data* to its corresponding Python object, and + return it. diff --git a/docs/library/math.rst b/docs/library/math.rst index a6f13d48c1892..335bd80781cfc 100644 --- a/docs/library/math.rst +++ b/docs/library/math.rst @@ -125,8 +125,11 @@ Functions Return the natural logarithm of the gamma function of ``x``. .. function:: log(x) + log(x, base) - Return the natural logarithm of ``x``. + With one argument, return the natural logarithm of *x*. + + With two arguments, return the logarithm of *x* to the given *base*. .. function:: log10(x) diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index b17dfa9a75a48..4d5a064a7a70e 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -136,6 +136,14 @@ Functions the heap may be locked) and scheduling a function to call later will lift those restrictions. + On multi-threaded ports, the scheduled function's behaviour depends on + whether the Global Interpreter Lock (GIL) is enabled for the specific port: + + - If GIL is enabled, the function can preempt any thread and run in its + context. + - If GIL is disabled, the function will only preempt the main thread and run + in its context. + Note: If `schedule()` is called from a preempting IRQ, when memory allocation is not allowed and the callback to be passed to `schedule()` is a bound method, passing this directly will fail. This is because creating a @@ -147,3 +155,71 @@ Functions There is a finite queue to hold the scheduled functions and `schedule()` will raise a `RuntimeError` if the queue is full. + +Classes +------- + +.. class:: RingIO(size) +.. class:: RingIO(buffer) + :noindex: + + Provides a fixed-size ringbuffer for bytes with a stream interface. Can be + considered like a fifo queue variant of `io.BytesIO`. + + When created with integer size a suitable buffer will be allocated. + Alternatively a `bytearray` or similar buffer protocol object can be provided + to the constructor for in-place use. + + The classic ringbuffer algorithm is used which allows for any size buffer + to be used however one byte will be consumed for tracking. If initialised + with an integer size this will be accounted for, for example ``RingIO(16)`` + will allocate a 17 byte buffer internally so it can hold 16 bytes of data. + When passing in a pre-allocated buffer however one byte less than its + original length will be available for storage, eg. ``RingIO(bytearray(16))`` + will only hold 15 bytes of data. + + A RingIO instance can be IRQ / thread safe when used to pass data in a single + direction eg. when written to in an IRQ and read from in a non-IRQ function + (or vice versa). This does not hold if you try to eg. write to a single instance + from both IRQ and non-IRQ code, this would often cause data corruption. + + .. method:: RingIO.any() + + Returns an integer counting the number of characters that can be read. + + .. method:: RingIO.read([nbytes]) + + Read available characters. This is a non-blocking function. If ``nbytes`` + is specified then read at most that many bytes, otherwise read as much + data as possible. + + Return value: a bytes object containing the bytes read. Will be + zero-length bytes object if no data is available. + + .. method:: RingIO.readline([nbytes]) + + Read a line, ending in a newline character or return if one exists in + the buffer, else return available bytes in buffer. If ``nbytes`` is + specified then read at most that many bytes. + + Return value: a bytes object containing the line read. + + .. method:: RingIO.readinto(buf[, nbytes]) + + Read available bytes into the provided ``buf``. If ``nbytes`` is + specified then read at most that many bytes. Otherwise, read at + most ``len(buf)`` bytes. + + Return value: Integer count of the number of bytes read into ``buf``. + + .. method:: RingIO.write(buf) + + Non-blocking write of bytes from ``buf`` into the ringbuffer, limited + by the available space in the ringbuffer. + + Return value: Integer count of bytes written. + + .. method:: RingIO.close() + + No-op provided as part of standard `stream` interface. Has no effect + on data in the ringbuffer. diff --git a/docs/library/neopixel.rst b/docs/library/neopixel.rst index 543f2588125e0..b618e6012c382 100644 --- a/docs/library/neopixel.rst +++ b/docs/library/neopixel.rst @@ -9,9 +9,7 @@ This module provides a driver for WS2818 / NeoPixel LEDs. .. note:: This module is only included by default on the ESP8266, ESP32 and RP2 ports. On STM32 / Pyboard and others, you can either install the ``neopixel`` package using :term:`mip`, or you can download the module - directly from - `_ - and copy it to the filesystem. + directly from :term:`micropython-lib` and copy it to the filesystem. class NeoPixel -------------- @@ -45,7 +43,8 @@ Constructors - *pin* is a machine.Pin instance. - *n* is the number of LEDs in the strip. - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. - - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). You + may also supply a timing tuple as accepted by `machine.bitstream()`. Pixel access methods -------------------- diff --git a/docs/library/network.LAN.rst b/docs/library/network.LAN.rst index 375e02cefecd0..1b3c19c560b36 100644 --- a/docs/library/network.LAN.rst +++ b/docs/library/network.LAN.rst @@ -6,11 +6,11 @@ class LAN -- control an Ethernet module This class allows you to control the Ethernet interface. The PHY hardware type is board-specific. -Example usage:: +Example usage, for a board with built-in LAN support:: import network nic = network.LAN(0) - print(nic.ifconfig()) + print(nic.ipconfig("addr4")) # now use socket as usual ... @@ -32,7 +32,7 @@ Constructors - *phy_addr* specifies the address of the PHY interface. As with *phy_type*, the hardwired value has to be used for most boards and that value is the default. - *ref_clk_mode* specifies, whether the data clock is provided by the Ethernet controller or - the PYH interface. + the PHY interface. The default value is the one that matches the board. If set to ``LAN.OUT`` or ``Pin.OUT`` or ``True``, the clock is driven by the Ethernet controller, if set to ``LAN.IN`` or ``Pin.IN`` or ``False``, the clock is driven by the PHY interface. @@ -41,6 +41,9 @@ Constructors nic = LAN(0, phy_type=LAN.PHY_LAN8720, phy_addr=1, ref_clk_mode=Pin.IN) + .. note:: On esp32 port the constructor requires different arguments. See + :ref:`esp32 port reference `. + Methods ------- diff --git a/docs/library/network.PPP.rst b/docs/library/network.PPP.rst new file mode 100644 index 0000000000000..15ab1da193448 --- /dev/null +++ b/docs/library/network.PPP.rst @@ -0,0 +1,106 @@ +.. currentmodule:: network +.. _network.PPP: + +class PPP -- create network connections over serial PPP +======================================================= + +This class allows you to create a network connection over a serial port using +the PPP protocol. + +.. note:: Currently only the esp32 port has PPP support enabled in the default + firmware build. PPP support can be enabled in custom builds of the + stm32 and rp2 ports by enabling networking support and setting + ``MICROPY_PY_NETWORK_PPP_LWIP`` to 1. + +Example usage:: + + import network + + ppp = network.PPP(uart) + ppp.connect() + + while not ppp.isconnected(): + pass + + print(ppp.ipconfig("addr4")) + + # use the socket module as usual, etc + + ppp.disconnect() + +Constructors +------------ + +.. class:: PPP(stream) + + Create a PPP driver object. + + Arguments are: + + - *stream* is any object that supports the stream protocol, but is most commonly a + :class:`machine.UART` instance. This stream object must have an ``irq()`` method + and an ``IRQ_RXIDLE`` constant, for use by `PPP.connect`. + +Methods +------- + +.. method:: PPP.connect(security=SEC_NONE, user=None, key=None) + + Initiate a PPP connection with the given parameters: + + - *security* is the type of security, either ``PPP.SEC_NONE``, ``PPP.SEC_PAP``, + or ``PPP.SEC_CHAP``. + - *user* is an optional user name to use with the security mode. + - *key* is an optional password to use with the security mode. + + When this method is called the underlying stream has its interrupt configured to call + `PPP.poll` via ``stream.irq(ppp.poll, stream.IRQ_RXIDLE)``. This makes sure the + stream is polled, and data passed up the PPP stack, wheverver data becomes available + on the stream. + + The connection proceeds asynchronously, in the background. + +.. method:: PPP.disconnect() + + Terminate the connection. This must be called to cleanly close the PPP connection. + +.. method:: PPP.isconnected() + + Returns ``True`` if the PPP link is connected and up. + Returns ``False`` otherwise. + +.. method:: PPP.status() + + Returns the PPP status. + +.. method:: PPP.config(config_parameters) + + Sets or gets parameters of the PPP interface. The only parameter that can be + retrieved and set is the underlying stream, using:: + + stream = PPP.config("stream") + PPP.config(stream=stream) + +.. method:: PPP.ipconfig('param') + PPP.ipconfig(param=value, ...) + + See `AbstractNIC.ipconfig`. + +.. method:: PPP.ifconfig([(ip, subnet, gateway, dns)]) + + See `AbstractNIC.ifconfig`. + +.. method:: PPP.poll() + + Poll the underlying stream for data, and pass it up the PPP stack. + This is called automatically if the stream is a UART with a RXIDLE interrupt, + so it's not usually necessary to call it manually. + +Constants +--------- + +.. data:: PPP.SEC_NONE + PPP.SEC_PAP + PPP.SEC_CHAP + + The type of connection security. diff --git a/docs/library/network.WIZNET5K.rst b/docs/library/network.WIZNET5K.rst index c13d43a376ece..d0778a7a37ce8 100644 --- a/docs/library/network.WIZNET5K.rst +++ b/docs/library/network.WIZNET5K.rst @@ -9,11 +9,14 @@ the W5200 and W5500 chipsets. The particular chipset that is supported by the firmware is selected at compile-time via the MICROPY_PY_NETWORK_WIZNET5K option. +.. note:: The esp32 port also supports WIZnet W5500 chipsets, but this port + uses the :ref:`network.LAN interface `. + Example usage:: import network nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4) - print(nic.ifconfig()) + print(nic.ipconfig("addr4")) # now use socket as usual ... @@ -51,20 +54,7 @@ Constructors Methods ------- -.. method:: WIZNET5K.isconnected() - - Returns ``True`` if the physical Ethernet link is connected and up. - Returns ``False`` otherwise. - -.. method:: WIZNET5K.ifconfig([(ip, subnet, gateway, dns)]) - - Get/set IP address, subnet mask, gateway and DNS. - - When called with no arguments, this method returns a 4-tuple with the above information. - - To set the above values, pass a 4-tuple with the required information. For example:: - - nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) +This class implements most methods from `AbstractNIC `, which are documented there. Additional methods are: .. method:: WIZNET5K.regs() diff --git a/docs/library/network.WLAN.rst b/docs/library/network.WLAN.rst index d1e620ef09f9b..ee0ef490fda84 100644 --- a/docs/library/network.WLAN.rst +++ b/docs/library/network.WLAN.rst @@ -8,7 +8,7 @@ This class provides a driver for WiFi network processors. Example usage:: import network # enable station interface and connect to WiFi access point - nic = network.WLAN(network.STA_IF) + nic = network.WLAN(network.WLAN.IF_STA) nic.active(True) nic.connect('your-ssid', 'your-key') # now use sockets as usual @@ -18,8 +18,8 @@ Constructors .. class:: WLAN(interface_id) Create a WLAN network interface object. Supported interfaces are -``network.STA_IF`` (station aka client, connects to upstream WiFi access -points) and ``network.AP_IF`` (access point, allows other WiFi clients to +``network.WLAN.IF_STA`` (station aka client, connects to upstream WiFi access +points) and ``network.WLAN.IF_AP`` (access point, allows other WiFi clients to connect). Availability of the methods below depends on interface type. For example, only STA interface may `WLAN.connect()` to an access point. @@ -75,7 +75,7 @@ Methods Return the current status of the wireless connection. When called with no argument the return value describes the network link status. - The possible statuses are defined as constants: + The possible statuses are defined as constants in the :mod:`network` module: * ``STAT_IDLE`` -- no connection and no activity, * ``STAT_CONNECTING`` -- connecting in progress, @@ -85,7 +85,18 @@ Methods * ``STAT_GOT_IP`` -- connection successful. When called with one argument *param* should be a string naming the status - parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``. + parameter to retrieve, and different parameters are supported depending on the + mode the WiFi is in. + + In STA mode, passing ``'rssi'`` returns a signal strength indicator value, whose + format varies depending on the port (this is available on all ports that support + WiFi network interfaces, except for CC3200). + + In AP mode, passing ``'stations'`` returns a list of connected WiFi stations + (this is available on all ports that support WiFi network interfaces, except for + CC3200). The format of the station information entries varies across ports, + providing either the raw BSSID of the connected station, the IP address of the + connected station, or both. .. method:: WLAN.isconnected() @@ -107,7 +118,7 @@ Methods Get or set general network interface parameters. These methods allow to work with additional parameters beyond standard IP configuration (as dealt with by - `WLAN.ifconfig()`). These include network-specific and hardware-specific + `AbstractNIC.ipconfig()`). These include network-specific and hardware-specific parameters. For setting parameters, keyword argument syntax should be used, multiple parameters can be set at once. For querying, parameters name should be quoted as a string, and only one parameter can be queries at time:: @@ -126,11 +137,27 @@ Methods ============= =========== mac MAC address (bytes) ssid WiFi access point name (string) - channel WiFi channel (integer) + channel WiFi channel (integer). Depending on the port this may only be supported on the AP interface. hidden Whether SSID is hidden (boolean) security Security protocol supported (enumeration, see module constants) key Access key (string) hostname The hostname that will be sent to DHCP (STA interfaces) and mDNS (if supported, both STA and AP). (Deprecated, use :func:`network.hostname` instead) reconnects Number of reconnect attempts to make (integer, 0=none, -1=unlimited) txpower Maximum transmit power in dBm (integer or float) + pm WiFi Power Management setting (see below for allowed values) ============= =========== + +Constants +--------- + +.. data:: WLAN.PM_PERFORMANCE + WLAN.PM_POWERSAVE + WLAN.PM_NONE + + Allowed values for the ``WLAN.config(pm=...)`` network interface parameter: + + * ``PM_PERFORMANCE``: enable WiFi power management to balance power + savings and WiFi performance + * ``PM_POWERSAVE``: enable WiFi power management with additional power + savings and reduced WiFi performance + * ``PM_NONE``: disable wifi power management diff --git a/docs/library/network.WLANWiPy.rst b/docs/library/network.WLANWiPy.rst index 2a5ba118454bc..4ac82e92c6a58 100644 --- a/docs/library/network.WLANWiPy.rst +++ b/docs/library/network.WLANWiPy.rst @@ -20,7 +20,7 @@ This class provides a driver for the WiFi network processor in the WiPy. Example wlan.connect('your-ssid', auth=(WLAN.WPA2, 'your-key')) while not wlan.isconnected(): time.sleep_ms(50) - print(wlan.ifconfig()) + print(wlan.ipconfig("addr4")) # now use socket as usual ... @@ -96,16 +96,10 @@ Methods In case of STA mode, returns ``True`` if connected to a WiFi access point and has a valid IP address. In AP mode returns ``True`` when a station is connected, ``False`` otherwise. -.. method:: WLANWiPy.ifconfig(if_id=0, config=['dhcp' or configtuple]) +.. method:: WLANWiPy.ipconfig('param') + WLANWiPy.ipconfig(param=value, ...) - With no parameters given returns a 4-tuple of *(ip, subnet_mask, gateway, DNS_server)*. - - if ``'dhcp'`` is passed as a parameter then the DHCP client is enabled and the IP params - are negotiated with the AP. - - If the 4-tuple config is given then a static IP is configured. For instance:: - - wlan.ifconfig(config=('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + See :meth:`AbstractNIC.ipconfig `. Supported parameters are: ``dhcp4``, ``addr4``, ``gw4``. .. method:: WLANWiPy.mode([mode]) diff --git a/docs/library/network.rst b/docs/library/network.rst index b13c84123ce7f..d05d17132dc67 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -24,7 +24,7 @@ For example:: print("Waiting for connection...") while not nic.isconnected(): time.sleep(1) - print(nic.ifconfig()) + print(nic.ipconfig("addr4")) # now use socket as usual import socket @@ -113,8 +113,48 @@ parameter should be `id`. connected to the AP. The list contains tuples of the form (MAC, RSSI). +.. method:: AbstractNIC.ipconfig('param') + AbstractNIC.ipconfig(param=value, ...) + + Get or set interface-specific IP-configuration interface parameters. + Supported parameters are the following (availability of a particular + parameter depends on the port and the specific network interface): + + * ``dhcp4`` (``True/False``) obtain an IPv4 address, gateway and dns + server via DHCP. This method does not block and wait for an address + to be obtained. To check if an address was obtained, use the read-only + property ``has_dhcp4``. + * ``gw4`` Get/set the IPv4 default-gateway. + * ``dhcp6`` (``True/False``) obtain a DNS server via stateless DHCPv6. + Obtaining IP Addresses via DHCPv6 is currently not implemented. + * ``autoconf6`` (``True/False``) obtain a stateless IPv6 address via + the network prefix shared in router advertisements. To check if a + stateless address was obtained, use the read-only + property ``has_autoconf6``. + * ``addr4`` (e.g. ``192.168.0.4/24``) obtain the current IPv4 address + and network mask as ``(ip, subnet)``-tuple, regardless of how this + address was obtained. This method can be used to set a static IPv4 + address either as ``(ip, subnet)``-tuple or in CIDR-notation. + * ``addr6`` (e.g. ``fe80::1234:5678``) obtain a list of current IPv6 + addresses as ``(ip, state, preferred_lifetime, valid_lifetime)``-tuple. + This include link-local, slaac and static addresses. + ``preferred_lifetime`` and ``valid_lifetime`` represent the remaining + valid and preferred lifetime of each IPv6 address, in seconds. + ``state`` indicates the current state of the address: + + * ``0x08`` - ``0x0f`` indicates the address is tentative, counting the + number of probes sent. + * ``0x10`` The address is deprecated (but still valid) + * ``0x30`` The address is preferred (and valid) + * ``0x40`` The address is duplicated and can not be used. + + This method can be used to set a static IPv6 + address, by setting this parameter to the address, like ``fe80::1234:5678``. + .. method:: AbstractNIC.ifconfig([(ip, subnet, gateway, dns)]) + .. note:: This function is deprecated, use `ipconfig()` instead. + Get/set IP-level network interface parameters: IP address, subnet mask, gateway and DNS server. When called with no arguments, this method returns a 4-tuple with the above information. To set the above values, pass a @@ -127,7 +167,7 @@ parameter should be `id`. Get or set general network interface parameters. These methods allow to work with additional parameters beyond standard IP configuration (as dealt with by - `ifconfig()`). These include network-specific and hardware-specific + `ipconfig()`). These include network-specific and hardware-specific parameters. For setting parameters, the keyword argument syntax should be used, and multiple parameters can be set at once. For querying, a parameter name should be quoted as a string, and only one @@ -152,6 +192,7 @@ provide a way to control networking interfaces of various kinds. network.WLANWiPy.rst network.WIZNET5K.rst network.LAN.rst + network.PPP.rst Network functions ================= @@ -171,8 +212,8 @@ The following are functions available in the network module. .. function:: hostname([name]) - Get or set the hostname that will identify this device on the network. It is - applied to all interfaces. + Get or set the hostname that will identify this device on the network. It will + be used by all interfaces. This hostname is used for: * Sending to the DHCP server in the client request. (If using DHCP) @@ -182,8 +223,33 @@ The following are functions available in the network module. If the function is called without parameters, it returns the current hostname. + A change in hostname is typically only applied during connection. For DHCP + this is because the hostname is part of the DHCP client request, and the + implementation of mDNS in most ports only initialises the hostname once + during connection. For this reason, you must set the hostname before + activating/connecting your network interfaces. + + The length of the hostname is limited to 32 characters. + :term:`MicroPython ports ` may choose to set a lower + limit for memory reasons. If the given name does not fit, a `ValueError` + is raised. + The default hostname is typically the name of the board. +.. function:: ipconfig('param') + ipconfig(param=value, ...) + + Get or set global IP-configuration parameters. + Supported parameters are the following (availability of a particular + parameter depends on the port and the specific network interface): + + * ``dns`` Get/set DNS server. This method can support both, IPv4 and + IPv6 addresses. + * ``prefer`` (``4/6``) Specify which address type to return, if a domain + name has both A and AAAA records. Note, that this does not clear the + local DNS cache, so that any previously obtained addresses might not + change. + .. function:: phy_mode([mode]) Get or set the PHY mode. diff --git a/docs/library/openamp.rst b/docs/library/openamp.rst new file mode 100644 index 0000000000000..de4d51ad06b5e --- /dev/null +++ b/docs/library/openamp.rst @@ -0,0 +1,115 @@ +:mod:`openamp` -- provides standard Asymmetric Multiprocessing (AMP) support +============================================================================ + +.. module:: openamp + :synopsis: provides standard Asymmetric Multiprocessing (AMP) support + +The ``openamp`` module provides a standard inter-processor communications infrastructure +for MicroPython. The module handles all of the details of OpenAMP, such as setting up +the shared resource table, initializing vrings, etc. It provides an API for using the +RPMsg bus infrastructure with the `Endpoint` class, and provides processor Life Cycle +Management (LCM) support, such as loading firmware and starting and stopping a remote +core, via the `RemoteProc` class. + +Example usage:: + + import openamp + + def ept_recv_callback(src, data): + print("Received message on endpoint", data) + + # Create a new RPMsg endpoint to communicate with the remote core. + ept = openamp.Endpoint("vuart-channel", callback=ept_recv_callback) + + # Create a RemoteProc object, load its firmware and start it. + rproc = openamp.RemoteProc("virtual_uart.elf") # Or entry point address (ex 0x081E0000) + rproc.start() + + while True: + if ept.is_ready(): + ept.send("data") + +Functions +--------- + +.. function:: new_service_callback(ns_callback) + + Set the new service callback. + + The *ns_callback* argument is a function that will be called when the remote processor + announces new services. At that point the host processor can choose to create the + announced endpoint, if this particular service is supported, or ignore it if it's + not. If this function is not set, the host processor should first register the + endpoint locally, and it will be automatically bound when the remote announces + the service. + +Endpoint class +-------------- + +.. class:: Endpoint(name, callback, src=ENDPOINT_ADDR_ANY, dest=ENDPOINT_ADDR_ANY) + + Construct a new RPMsg Endpoint. An endpoint is a bidirectional communication + channel between two cores. + + Arguments are: + + - *name* is the name of the endpoint. + - *callback* is a function that is called when the endpoint receives data with the + source address of the remote point, and the data as bytes passed by reference. + - *src* is the endpoint source address. If none is provided one will be assigned + to the endpoint by the library. + - *dest* is the endpoint destination address. If the endpoint is created from the + new_service_callback, this must be provided and it must match the remote endpoint's + source address. If the endpoint is registered locally, before the announcement, the + destination address will be assigned by the library when the endpoint is bound. + +.. method:: Endpoint.deinit() + + Destroy the endpoint and release all of its resources. + +.. method:: Endpoint.is_ready() + + Returns True if the endpoint is ready to send (i.e., has both a source and destination addresses) + +.. method:: Endpoint.send(src=-1, dest=-1, timeout=-1) + + Send a message to the remote processor over this endpoint. + + Arguments are: + + - *src* is the source endpoint address of the message. If none is provided, the + source address the endpoint is bound to is used. + - *dest* is the destination endpoint address of the message. If none is provided, + the destination address the endpoint is bound to is used. + - *timeout* specifies the time in milliseconds to wait for a free buffer. By default + the function is blocking. + +RemoteProc class +---------------- + +.. class:: RemoteProc(entry) + + The RemoteProc object provides processor Life Cycle Management (LCM) support, such as + loading firmware, starting and stopping a remote core. + + The *entry* argument can be a path to firmware image, in which case the firmware is + loaded from file to its target memory, or an entry point address, in which case the + firmware must be loaded already at the given address. + +.. method:: RemoteProc.start() + + Starts the remote processor. + +.. method:: RemoteProc.stop() + + Stops the remote processor. The exact behavior is platform-dependent. On the STM32H7 for + example it's not possible to stop and then restart the Cortex-M4 core, so a complete + system reset is performed on a call to this function. + +.. method:: RemoteProc.shutdown() + + Shutdown stops the remote processor and releases all of its resources. The exact behavior + is platform-dependent, however typically it disables power and clocks to the remote core. + This function is also used as the finaliser (i.e., called when ``RemoteProc`` object is + collected). Note that on the STM32H7, it's not possible to stop and then restart the + Cortex-M4 core, so a complete system reset is performed on a call to this function. diff --git a/docs/library/os.rst b/docs/library/os.rst index 19652ee2bc5ef..710875e34c39b 100644 --- a/docs/library/os.rst +++ b/docs/library/os.rst @@ -86,7 +86,7 @@ Filesystem access .. function:: statvfs(path) - Get the status of a fileystem. + Get the status of a filesystem. Returns a tuple with the filesystem information in the following order: @@ -136,192 +136,30 @@ Terminal redirection and duplication Filesystem mounting ------------------- -Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple -"real" filesystems within this VFS. Filesystem objects can be mounted at either -the root of the VFS, or at a subdirectory that lives in the root. This allows -dynamic and flexible configuration of the filesystem that is seen by Python -programs. Ports that have this functionality provide the :func:`mount` and -:func:`umount` functions, and possibly various filesystem implementations -represented by VFS classes. +The following functions and classes have been moved to the :mod:`vfs` module. +They are provided in this module only for backwards compatibility and will be +removed in version 2 of MicroPython. .. function:: mount(fsobj, mount_point, *, readonly) - Mount the filesystem object *fsobj* at the location in the VFS given by the - *mount_point* string. *fsobj* can be a a VFS object that has a ``mount()`` - method, or a block device. If it's a block device then the filesystem type - is automatically detected (an exception is raised if no filesystem was - recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root, - or ``'/'`` to mount it at a subdirectory under the root. - - If *readonly* is ``True`` then the filesystem is mounted read-only. - - During the mount process the method ``mount()`` is called on the filesystem - object. - - Will raise ``OSError(EPERM)`` if *mount_point* is already mounted. + See `vfs.mount`. .. function:: umount(mount_point) - Unmount a filesystem. *mount_point* can be a string naming the mount location, - or a previously-mounted filesystem object. During the unmount process the - method ``umount()`` is called on the filesystem object. - - Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + See `vfs.umount`. .. class:: VfsFat(block_dev) - Create a filesystem object that uses the FAT filesystem format. Storage of - the FAT filesystem is provided by *block_dev*. - Objects created by this constructor can be mounted using :func:`mount`. - - .. staticmethod:: mkfs(block_dev) - - Build a FAT filesystem on *block_dev*. + See `vfs.VfsFat`. .. class:: VfsLfs1(block_dev, readsize=32, progsize=32, lookahead=32) - 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, readsize=32, progsize=32, lookahead=32) - - Build a Lfs1 filesystem on *block_dev*. - - .. note:: There are reports of littlefs v1 failing in certain situations, - for details see `littlefs issue 347`_. + See `vfs.VfsLfs1`. .. class:: VfsLfs2(block_dev, readsize=32, progsize=32, lookahead=32, mtime=True) - 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 `vfs.VfsLfs2`. + +.. class:: VfsPosix(root=None) - The *mtime* argument enables modification timestamps for files, stored using - littlefs attributes. This option can be disabled or enabled differently each - mount time and timestamps will only be added or updated if *mtime* is enabled, - otherwise the timestamps will remain untouched. Littlefs v2 filesystems without - timestamps will work without reformatting and timestamps will be added - transparently to existing files once they are opened for writing. When *mtime* - is enabled `os.stat` on files without timestamps will return 0 for the timestamp. - - See :ref:`filesystem` for more information. - - .. staticmethod:: mkfs(block_dev, readsize=32, progsize=32, lookahead=32) - - 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. 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 ``os`` -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(...) - - Construct a block device object. The parameters to the constructor are - dependent on the specific block device. - - .. method:: readblocks(block_num, buf) - 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) - 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 - perform is given by *op* which is one of the following integers: - - - 1 -- initialise the device (*arg* is unused) - - 2 -- shutdown the device (*arg* is unused) - - 3 -- sync the device (*arg* is unused) - - 4 -- get a count of the number of blocks, should return an integer - (*arg* is unused) - - 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 - - As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs - ``ioctl(6, ...)`` must also be intercepted. The need for others is - hardware dependent. - - Prior to any call to ``writeblocks(block, ...)`` littlefs issues - ``ioctl(6, block)``. This enables a device driver to erase the block - prior to a write if the hardware requires it. Alternatively a driver - might intercept ``ioctl(6, block)`` and return 0 (success). In this case - the driver assumes responsibility for detecting the need for erasure. - - 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. + See `vfs.VfsPosix`. diff --git a/docs/library/platform.rst b/docs/library/platform.rst new file mode 100644 index 0000000000000..c091477d84cb1 --- /dev/null +++ b/docs/library/platform.rst @@ -0,0 +1,38 @@ +:mod:`platform` -- access to underlying platform’s identifying data +=================================================================== + +.. module:: platform + :synopsis: access to underlying platform’s identifying data + +|see_cpython_module| :mod:`python:platform`. + +This module tries to retrieve as much platform-identifying data as possible. It +makes this information available via function APIs. + +Functions +--------- + +.. function:: platform() + + Returns a string identifying the underlying platform. This string is composed + of several substrings in the following order, delimited by dashes (``-``): + + - the name of the platform system (e.g. Unix, Windows or MicroPython) + - the MicroPython version + - the architecture of the platform + - the version of the underlying platform + - the concatenation of the name of the libc that MicroPython is linked to + and its corresponding version. + + For example, this could be + ``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``. + +.. function:: python_compiler() + + Returns a string identifying the compiler used for compiling MicroPython. + +.. function:: libc_ver() + + Returns a tuple of strings *(lib, version)*, where *lib* is the name of the + libc that MicroPython is linked to, and *version* the corresponding version + of this libc. diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 5ca00b65e5c58..eb21d8223f26e 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -67,11 +67,17 @@ Methods :meth:`~CAN.restart()` can be used to leave the bus-off state - *baudrate* if a baudrate other than 0 is provided, this function will try to automatically calculate the CAN nominal bit time (overriding *prescaler*, *bs1* and *bs2*) that satisfies - both the baudrate and the desired *sample_point*. - - *sample_point* given in a percentage of the nominal bit time, the *sample_point* specifies the position - of the bit sample with respect to the whole nominal bit time. The default *sample_point* is 75%. + both the *baudrate* (within .1%) and the desired *sample_point* (to the nearest 1%). For more precise + control over the CAN timing, set the *prescaler*, *bs1* and *bs2* parameters directly. + - *sample_point* specifies the position of the bit sample with respect to the whole nominal bit time, + expressed as an integer percentage of the nominal bit time. The default *sample_point* is 75%. + This parameter is ignored unless *baudrate* is set. - *num_filter_banks* for classic CAN, this is the number of banks that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2). + + The remaining parameters are only present on boards with CAN FD support, and configure the optional CAN FD + Bit Rate Switch (BRS) feature: + - *brs_prescaler* is the value by which the CAN FD input clock is divided to generate the data bit time quanta. The prescaler can be a value between 1 and 32 inclusive. - *brs_sjw* is the resynchronisation jump width in units of time quanta for data bits; @@ -82,10 +88,11 @@ Methods it can be a value between 1 and 16 inclusive - *brs_baudrate* if a baudrate other than 0 is provided, this function will try to automatically calculate the CAN data bit time (overriding *brs_prescaler*, *brs_bs1* and *brs_bs2*) that satisfies - both the baudrate and the desired *brs_sample_point*. - - *brs_sample_point* given in a percentage of the data bit time, the *brs_sample_point* specifies the position - of the bit sample with respect to the whole data bit time. The default *brs_sample_point* is 75%. - + both the *brs_baudrate* (within .1%) and the desired *brs_sample_point* (to the nearest 1%). For more + precise control over the BRS timing, set the *brs_prescaler*, *brs_bs1* and *brs_bs2* parameters directly. + - *brs_sample_point* specifies the position of the bit sample with respect to the whole nominal bit time, + expressed as an integer percentage of the nominal bit time. The default *brs_sample_point* is 75%. + This parameter is ignored unless *brs_baudrate* is set. The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1); @@ -272,7 +279,7 @@ Methods - *fdf* for CAN FD controllers, if set to True, the frame will have an FD frame format, which supports data payloads up to 64 bytes. - *brs* for CAN FD controllers, if set to True, the bitrate switching mode - is enabled, in which the data phase is transmitted at a differet bitrate. + is enabled, in which the data phase is transmitted at a different bitrate. See :meth:`CAN.init` for the data bit timing configuration parameters. If timeout is 0 the message is placed in a buffer in one of three hardware diff --git a/docs/library/pyb.Flash.rst b/docs/library/pyb.Flash.rst index 984e13f4583a4..562bcf1e2466e 100644 --- a/docs/library/pyb.Flash.rst +++ b/docs/library/pyb.Flash.rst @@ -43,7 +43,7 @@ Methods These methods implement the simple and :ref:`extended ` block protocol defined by - :class:`os.AbstractBlockDev`. + :class:`vfs.AbstractBlockDev`. Hardware Note ------------- diff --git a/docs/library/pyb.I2C.rst b/docs/library/pyb.I2C.rst index 2c526854aa2ec..71d043aa6d4f9 100644 --- a/docs/library/pyb.I2C.rst +++ b/docs/library/pyb.I2C.rst @@ -97,7 +97,7 @@ Methods errors properly) The actual clock frequency may be lower than the requested frequency. - This is dependant on the platform hardware. The actual rate may be determined + This is dependent on the platform hardware. The actual rate may be determined by printing the I2C object. .. method:: I2C.is_ready(addr) diff --git a/docs/library/pyb.Timer.rst b/docs/library/pyb.Timer.rst index 1749efce2d508..c644e38d78624 100644 --- a/docs/library/pyb.Timer.rst +++ b/docs/library/pyb.Timer.rst @@ -163,7 +163,7 @@ Methods - ``callback`` - as per TimerChannel.callback() - ``pin`` None (the default) or a Pin object. If specified (and not None) - this will cause the alternate function of the the indicated pin + this will cause the alternate function of the indicated pin to be configured for this timer channel. An error will be raised if the pin doesn't support any alternate functions for this timer channel. diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index c8ef2c531542f..5eb75c22b608d 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -147,10 +147,10 @@ Power related functions (internal oscillator) directly. The higher frequencies use the HSE to drive the PLL (phase locked loop), and then use the output of the PLL. - Note that if you change the frequency while the USB is enabled then - the USB may become unreliable. It is best to change the frequency - in boot.py, before the USB peripheral is started. Also note that sysclk - frequencies below 36MHz do not allow the USB to function correctly. + Note that if you change the frequency while the USB is enabled then the USB + may become unreliable. It is best to change the frequency in :ref:`boot.py`, + before the USB peripheral is started. Also note that sysclk frequencies below + 36MHz do not allow the USB to function correctly. .. function:: wfi() @@ -205,19 +205,20 @@ Miscellaneous functions .. function:: main(filename) - Set the filename of the main script to run after boot.py is finished. If - this function is not called then the default file main.py will be executed. + Set the filename of the main script to run after :ref:`boot.py` is finished. + If this function is not called then the default file :ref:`main.py` will be + executed. It only makes sense to call this function from within boot.py. .. function:: mount(device, mountpoint, *, readonly=False, mkfs=False) .. note:: This function is deprecated. Mounting and unmounting devices should - be performed by :meth:`os.mount` and :meth:`os.umount` instead. + be performed by :meth:`vfs.mount` and :meth:`vfs.umount` instead. Mount a block device and make it available as part of the filesystem. ``device`` must be an object that provides the block protocol. (The - following is also deprecated. See :class:`os.AbstractBlockDev` for the + following is also deprecated. See :class:`vfs.AbstractBlockDev` for the correct way to create a block device.) - ``readblocks(self, blocknum, buf)`` diff --git a/docs/library/random.rst b/docs/library/random.rst index dd8b47c80f084..be56eb088eae7 100644 --- a/docs/library/random.rst +++ b/docs/library/random.rst @@ -24,7 +24,7 @@ This module implements a pseudo-random number generator (PRNG). .. note:: The :func:`randrange`, :func:`randint` and :func:`choice` functions are only - available if the ``MICROPY_PY_URANDOM_EXTRA_FUNCS`` configuration option is + available if the ``MICROPY_PY_RANDOM_EXTRA_FUNCS`` configuration option is enabled. @@ -73,7 +73,7 @@ Other Functions supported by the port) initialise the PRNG with a true random number (usually a hardware generated random number). - The ``None`` case only works if ``MICROPY_PY_URANDOM_SEED_INIT_FUNC`` is + The ``None`` case only works if ``MICROPY_PY_RANDOM_SEED_INIT_FUNC`` is enabled by the port, otherwise it raises ``ValueError``. .. function:: choice(sequence) diff --git a/docs/library/rp2.DMA.rst b/docs/library/rp2.DMA.rst new file mode 100644 index 0000000000000..c5e3f31aa2ed6 --- /dev/null +++ b/docs/library/rp2.DMA.rst @@ -0,0 +1,293 @@ +.. currentmodule:: rp2 +.. _rp2.DMA: + +class DMA -- access to the RP2040's DMA controller +================================================== + +The :class:`DMA` class offers access to the RP2040's Direct Memory Access (DMA) +controller, providing the ability move data between memory blocks and/or IO registers. The DMA +controller has its own, separate read and write bus master connections onto the bus fabric and +each DMA channel can independently read data from one address and write it back to another +address, optionally incrementing one or both pointers, allowing it to perform transfers on behalf +of the processor while the processor carries out other tasks or enters a low power state. The +RP2040's DMA controller has 12 independent DMA channels that can run concurrently. For full +details of the RP2040's DMA system see section 2.5 of the `RP2040 Datasheet +`_. + +Examples +-------- + +The simplest use of the DMA controller is to move data from one block of memory to another. +This can be accomplished with the following code:: + + a = bytearray(32*1024) + b = bytearray(32*1024) + d = rp2.DMA() + c = d.pack_ctrl() # Just use the default control value. + # The count is in 'transfers', which defaults to four-byte words, so divide length by 4 + d.config(read=a, write=b, count=len(a)//4, ctrl=c, trigger=True) + # Wait for completion + while d.active(): + pass + +Note that while this example sits in an idle loop while it waits for the transfer to complete, +the program could just as well do some useful work in this time instead. + +Another, perhaps more common use of the DMA controller is to transfer between memory and an IO +peripheral. In this situation the address of the IO register does not change for each transfer but +the memory address needs to be incremented. It is also necessary to control the pace of the +transfer so as to not write data before it can be accepted by a peripheral or read it before the +data is ready, and this can be controlled with the ``treq_sel`` field of the DMA channel's control +register. The various fields of the control register for each DMA channel can be packed +using the :meth:`DMA.pack_ctrl()` method and unpacked using the :meth:`DMA.unpack_ctrl()` +static method. Code to transfer data from a byte array to the TX FIFO of a PIO state machine, +one byte at a time, looks like this:: + + # pio_num is index of the PIO block being used, sm_num is the state machine in that block. + # my_state_machine is an rp2.PIO() instance. + DATA_REQUEST_INDEX = (pio_num << 3) + sm_num + + src_data = bytearray(1024) + d = rp2.DMA() + + # Transfer bytes, rather than words, don't increment the write address and pace the transfer. + c = d.pack_ctrl(size=0, inc_write=False, treq_sel=DATA_REQUEST_INDEX) + + d.config( + read=src_data, + write=my_state_machine, + count=len(src_data), + ctrl=c, + trigger=True + ) + +Note that in this example the value given for the write address is just the PIO state machine to +which we are sending the data. This works because PIO state machines present the buffer protocol, +allowing direct access to their data FIFO registers. + +Constructor +----------- + +.. class:: DMA() + + Claim one of the DMA controller channels for exclusive use. + +Methods +------- + +.. method:: DMA.config(read=None, write=None, count=None, ctrl=None, trigger=False) + + Configure the DMA registers for the channel and optionally start the transfer. + Parameters are: + + - *read*: The address from which the DMA controller will start reading data or + an object that will provide data to be read. It can be an integer or any + object that supports the buffer protocol. + - *write*: The address to which the DMA controller will start writing or an + object into which data will be written. It can be an integer or any object + that supports the buffer protocol. + - *count*: The number of bus transfers that will execute before this channel + stops. Note that this is the number of transfers, not the number of bytes. + If the transfers are 2 or 4 bytes wide then the total amount of data moved + (and thus the size of required buffer) needs to be multiplied accordingly. + - *ctrl*: The value for the DMA control register. This is an integer value + that is typically packed using the :meth:`DMA.pack_ctrl()`. + - *trigger*: Optionally commence the transfer immediately. + +.. method:: DMA.irq(handler=None, hard=False) + + Returns the IRQ object for this DMA channel and optionally configures it. + +.. method:: DMA.close() + + Release the claim on the underlying DMA channel and free the interrupt + handler. The :class:`DMA` object can not be used after this operation. + +.. method:: DMA.pack_ctrl(default=None, **kwargs) + + Pack the values provided in the keyword arguments into the named fields of a new control + register value. Any field that is not provided will be set to a default value. The + default will either be taken from the provided ``default`` value, or if that is not + given, a default suitable for the current channel; setting this to the current value + of the `DMA.ctrl` attribute provides an easy way to override a subset of the fields. + + The keys for the keyword arguments can be any key returned by the :meth:`DMA.unpack_ctrl()` + method. The writable values are: + + - *enable*: ``bool`` Set to enable the channel (default: ``True``). + + - *high_pri*: ``bool`` Make this channel's bus traffic high priority (default: ``False``). + + - *size*: ``int`` Transfer size: 0=byte, 1=half word, 2=word (default: 2). + + - *inc_read*: ``bool`` Increment the read address after each transfer (default: ``True``). + + - *inc_write*: ``bool`` Increment the write address after each transfer (default: ``True``). + + - *ring_size*: ``int`` If non-zero, only the bottom ``ring_size`` bits of one + address register will change when an address is incremented, causing the + address to wrap at the next ``1 << ring_size`` byte boundary. Which + address is wrapped is controlled by the ``ring_sel`` flag. A zero value + disables address wrapping. + + - *ring_sel*: ``bool`` Set to ``False`` to have the ``ring_size`` apply to the read address + or ``True`` to apply to the write address. + + - *chain_to*: ``int`` The channel number for a channel to trigger after this transfer + completes. Setting this value to this DMA object's own channel number + disables chaining (this is the default). + + - *treq_sel*: ``int`` Select a Transfer Request signal. See section 2.5.3 in the RP2040 + datasheet for details. + + - *irq_quiet*: ``bool`` Do not generate interrupt at the end of each transfer. Interrupts + will instead be generated when a zero value is written to the trigger + register, which will halt a sequence of chained transfers (default: + ``True``). + + - *bswap*: ``bool`` If set to true, bytes in words or half-words will be reversed before + writing (default: ``True``). + + - *sniff_en*: ``bool`` Set to ``True`` to allow data to be accessed by the chips sniff + hardware (default: ``False``). + + - *write_err*: ``bool`` Setting this to ``True`` will clear a previously reported write + error. + + - *read_err*: ``bool`` Setting this to ``True`` will clear a previously reported read + error. + + See the description of the ``CH0_CTRL_TRIG`` register in section 2.5.7 of the RP2040 + datasheet for details of all of these fields. + +.. method:: DMA.unpack_ctrl(value) + + Unpack a value for a DMA channel control register into a dictionary with key/value pairs + for each of the fields in the control register. *value* is the ``ctrl`` register value + to unpack. + + This method will return values for all the keys that can be passed to ``DMA.pack_ctrl``. + In addition, it will also return the read-only flags in the control register: ``busy``, + which goes high when a transfer starts and low when it ends, and ``ahb_err``, which is + the logical OR of the ``read_err`` and ``write_err`` flags. These values will be ignored + when packing, so that the dictionary created by unpacking a control register can be used + directly as the keyword arguments for packing. + +.. method:: DMA.active([value]) + + Gets or sets whether the DMA channel is currently running. + + >>> sm.active() + 0 + >>> sm.active(1) + >>> while sm.active(): + ... pass + +Attributes +---------- + +.. attribute:: DMA.read + + This attribute reflects the address from which the next bus transfer + will read. It may be written with either an integer or an object + that supports the buffer protocol and doing so has immediate effect. + +.. attribute:: DMA.write + + This attribute reflects the address to which the next bus transfer + will write. It may be written with either an integer or an object + that supports the buffer protocol and doing so has immediate effect. + +.. attribute:: DMA.count + + Reading this attribute will return the number of remaining bus + transfers in the *current* transfer sequence. Writing this attribute + sets the total number of transfers to be the *next* transfer sequence. + +.. attribute:: DMA.ctrl + + This attribute reflects DMA channel control register. It is typically written + with an integer packed using the :meth:`DMA.pack_ctrl()` method. The returned + register value can be unpacked using the :meth:`DMA.unpack_ctrl()` method. + +.. attribute:: DMA.channel + + The channel number of the DMA channel. This can be passed in the ``chain_to`` + argument of `DMA.pack_ctrl()` on another channel to allow DMA chaining. + +.. attribute:: DMA.registers + + This attribute is an array-like object that allows direct access to + the DMA channel's registers. The index is by word, rather than by byte, + so the register indices are the register address offsets divided by 4. + See the RP2040 data sheet for register details. + +Chaining and trigger register access +------------------------------------ + +The DMA controller in the RP2040 offers a couple advanced features to allow one DMA channel +to initiate a transfer on another channel. One is the use of the ``chain_to`` value in the +control register and the other is writing to one of the DMA channel's registers that has a +trigger effect. When coupled with the ability to have one DMA channel write directly to the +`DMA.registers` of another channel, this allows for complex transactions to be performed +without any CPU intervention. + +Below is an example of using both chaining and register +triggering to implement gathering of multiple blocks of data into a single destination. Full +details of these features can be found in section 2.5 of the RP2040 data sheet and the code +below is a Pythonic version of the example in sub-section 2.5.6.2. + +.. code-block:: python + + from rp2 import DMA + from uctypes import addressof + from array import array + + def gather_strings(string_list, buf): + # We use two DMA channels. The first sends lengths and source addresses from the gather + # list to the registers of the second. The second copies the data itself. + gather_dma = DMA() + buffer_dma = DMA() + + # Pack up length/address pairs to be sent to the registers. + gather_list = array("I") + + for s in string_list: + gather_list.append(len(s)) + gather_list.append(addressof(s)) + + gather_list.append(0) + gather_list.append(0) + + # When writing to the registers of the second DMA channel, we need to wrap the + # write address on an 8-byte (1<<3 bytes) boundary. We write to the ``TRANS_COUNT`` + # and ``READ_ADD_TRIG`` registers in the last register alias (registers 14 and 15). + gather_ctrl = gather_dma.pack_ctrl(ring_size=3, ring_sel=True) + gather_dma.config( + read=gather_list, write=buffer_dma.registers[14:16], + count=2, ctrl=gather_ctrl + ) + + # When copying the data, the transfer size is single bytes, and when completed we need + # to chain back to the start another gather DMA transaction. + buffer_ctrl = buffer_dma.pack_ctrl(size=0, chain_to=gather_dma.channel) + # The read and count values will be set by the other DMA channel. + buffer_dma.config(write=buf, ctrl=buffer_ctrl) + + # Set the transfer in motion. + gather_dma.active(1) + + # Wait until all the register values have been sent + end_address = addressof(gather_list) + 4 * len(gather_list) + while gather_dma.read != end_address: + pass + + input = ["This is ", "a ", "test", " of the scatter", " gather", " process"] + output = bytearray(64) + + print(output) + gather_strings(input, output) + print(output) + +This example idles while waiting for the transfer to complete; alternatively it could +set an interrupt handler and return immediately. diff --git a/docs/library/rp2.Flash.rst b/docs/library/rp2.Flash.rst index 1e94cf519c844..70cb127a192da 100644 --- a/docs/library/rp2.Flash.rst +++ b/docs/library/rp2.Flash.rst @@ -32,5 +32,5 @@ Methods These methods implement the simple and extended :ref:`block protocol ` defined by - :class:`os.AbstractBlockDev`. + :class:`vfs.AbstractBlockDev`. diff --git a/docs/library/rp2.PIO.rst b/docs/library/rp2.PIO.rst index e0675af1e9a2c..f922456c8c483 100644 --- a/docs/library/rp2.PIO.rst +++ b/docs/library/rp2.PIO.rst @@ -27,6 +27,17 @@ Constructors Methods ------- +.. method:: PIO.gpio_base([base]) + + Query and optionally set the current GPIO base for this PIO instance. + + If an argument is given then it must be a pin (or integer corresponding to a pin + number), restricted to either GPIO0 or GPIO16. The GPIO base will then be set to + that pin. Setting the GPIO base must be done before any programs are added or state + machines created. + + Returns the current GPIO base pin. + .. method:: PIO.add_program(program) Add the *program* to the instruction memory of this PIO instance. diff --git a/docs/library/rp2.StateMachine.rst b/docs/library/rp2.StateMachine.rst index d39194e6ffbec..1cb87e90b6e2d 100644 --- a/docs/library/rp2.StateMachine.rst +++ b/docs/library/rp2.StateMachine.rst @@ -32,7 +32,7 @@ Methods The program is added to the instruction memory of this PIO instance. If the instruction memory already contains this program, then its offset is - re-used so as to save on instruction memory. + reused so as to save on instruction memory. - *freq* is the frequency in Hz to run the state machine at. Defaults to the system clock frequency. @@ -82,11 +82,18 @@ Methods .. method:: StateMachine.exec(instr) - Execute a single PIO instruction. Uses `asm_pio_encode` to encode the - instruction from the given string *instr*. + Execute a single PIO instruction. + + If *instr* is a string then uses `asm_pio_encode` to encode the instruction + from the given string. >>> sm.exec("set(0, 1)") + If *instr* is an integer then it is treated as an already encoded PIO + machine code instruction to be executed. + + >>> sm.exec(rp2.asm_pio_encode("out(y, 8)", 0)) + .. method:: StateMachine.get(buf=None, shift=0) Pull a word from the state machine's RX FIFO. @@ -133,3 +140,10 @@ Methods Optionally configure it. +Buffer protocol +--------------- + +The StateMachine class supports the `buffer protocol`, allowing direct access to the transmit +and receive FIFOs for each state machine. This is primarily in order to allow StateMachine +objects to be passed directly as the read or write parameters when configuring a `rp2.DMA()` +channel. diff --git a/docs/library/rp2.rst b/docs/library/rp2.rst index 7a473387b4a81..a215e98b51e55 100644 --- a/docs/library/rp2.rst +++ b/docs/library/rp2.rst @@ -23,7 +23,7 @@ The ``rp2`` module includes functions for assembling PIO programs. For running PIO programs, see :class:`rp2.StateMachine`. -.. function:: asm_pio(*, out_init=None, set_init=None, sideset_init=None, in_shiftdir=0, out_shiftdir=0, autopush=False, autopull=False, push_thresh=32, pull_thresh=32, fifo_join=PIO.JOIN_NONE) +.. function:: asm_pio(*, out_init=None, set_init=None, sideset_init=None, side_pindir=False, in_shiftdir=PIO.SHIFT_LEFT, out_shiftdir=PIO.SHIFT_LEFT, autopush=False, autopull=False, push_thresh=32, pull_thresh=32, fifo_join=PIO.JOIN_NONE) Assemble a PIO program. @@ -35,8 +35,10 @@ For running PIO programs, see :class:`rp2.StateMachine`. - *out_init* configures the pins used for ``out()`` instructions. - *set_init* configures the pins used for ``set()`` instructions. There can be at most 5. - - *sideset_init* configures the pins used side-setting. There can be at - most 5. + - *sideset_init* configures the pins used for ``.side()`` modifiers. There + can be at most 5. + - *side_pindir* when set to ``True`` configures ``.side()`` modifiers to be + used for pin directions, instead of pin values (the default, when ``False``). The following parameters are used by default, but can be overridden in `StateMachine.init()`: @@ -241,6 +243,7 @@ Classes .. toctree:: :maxdepth: 1 + rp2.DMA.rst rp2.Flash.rst rp2.PIO.rst rp2.StateMachine.rst diff --git a/docs/library/ssl.rst b/docs/library/ssl.rst index 924b03b3541b3..4327c74bad6c8 100644 --- a/docs/library/ssl.rst +++ b/docs/library/ssl.rst @@ -13,38 +13,82 @@ facilities for network sockets, both client-side and server-side. Functions --------- -.. function:: ssl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, cadata=None, server_hostname=None, do_handshake=True) +.. function:: ssl.wrap_socket(sock, server_side=False, key=None, cert=None, cert_reqs=CERT_NONE, cadata=None, server_hostname=None, do_handshake=True) + + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + +class SSLContext +---------------- + +.. class:: SSLContext(protocol, /) + + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + +.. method:: SSLContext.load_cert_chain(certfile, keyfile) + + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + .. admonition:: Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + +.. method:: SSLContext.load_verify_locations(cafile=None, cadata=None) + + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + +.. method:: SSLContext.get_ciphers() + + Get a list of enabled ciphers, returned as a list of strings. + +.. method:: SSLContext.set_ciphers(ciphers) + + Set the available ciphers for sockets created with this context. *ciphers* should be + a list of strings in the `IANA cipher suite format `_ . + +.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None) Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), - and returns an instance of ssl.SSLSocket, which wraps the underlying stream in - an SSL context. Returned object has the usual `stream` interface methods like + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like ``read()``, ``write()``, etc. - A server-side SSL socket should be created from a normal socket returned from - :meth:`~socket.socket.accept()` on a non-SSL listening server socket. - - *do_handshake* determines whether the handshake is done as part of the ``wrap_socket`` + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` or whether it is deferred to be done as part of the initial reads or writes - (there is no ``do_handshake`` method as in CPython). For blocking sockets doing the handshake immediately is standard. For non-blocking sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) the handshake should generally be deferred because otherwise ``wrap_socket`` blocks until it completes. Note that in AXTLS the handshake can be deferred until the first read or write but it then blocks until completion. - - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. - Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not - validate any certificate, only ``ssl.CERT_REQUIRED`` will. - - - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will - validate the peer's certificate. Currently only a single DER-encoded certificate is supported. - - *server_hostname* is for use as a client, and sets the hostname to check against the received server certificate. It also sets the name for Server Name Indication (SNI), allowing the server to present the proper certificate. - Depending on the underlying module implementation in a particular - :term:`MicroPython port`, some or all keyword arguments above may be not supported. - .. warning:: Some implementations of ``ssl`` module do NOT validate server certificates, @@ -55,6 +99,17 @@ Functions returns an object more similar to CPython's ``SSLObject`` which does not have these socket methods. +.. attribute:: SSLContext.verify_mode + + Set or get the behaviour for verification of peer certificates. Must be one of the + ``CERT_*`` constants. + +.. note:: + + ``ssl.CERT_REQUIRED`` requires the device's date/time to be properly set, e.g. using + `mpremote rtc --set ` or ``ntptime``, and ``server_hostname`` + must be specified when on the client side. + Exceptions ---------- @@ -62,11 +117,38 @@ Exceptions This exception does NOT exist. Instead its base class, OSError, is used. +DTLS support +------------ + +.. admonition:: Difference to CPython + :class: attention + + This is a MicroPython extension. + +This module supports DTLS in client and server mode via the `PROTOCOL_DTLS_CLIENT` +and `PROTOCOL_DTLS_SERVER` constants that can be used as the ``protocol`` argument +of `SSLContext`. + +In this case the underlying socket is expected to behave as a datagram socket (i.e. +like the socket opened with ``socket.socket`` with ``socket.AF_INET`` as ``af`` and +``socket.SOCK_DGRAM`` as ``type``). + +DTLS is only supported on ports that use mbed TLS, and it is not enabled by default: +it requires enabling ``MBEDTLS_SSL_PROTO_DTLS`` in the specific port configuration. + Constants --------- +.. data:: ssl.PROTOCOL_TLS_CLIENT + ssl.PROTOCOL_TLS_SERVER + ssl.PROTOCOL_DTLS_CLIENT (when DTLS support is enabled) + ssl.PROTOCOL_DTLS_SERVER (when DTLS support is enabled) + + Supported values for the *protocol* parameter. + .. data:: ssl.CERT_NONE ssl.CERT_OPTIONAL ssl.CERT_REQUIRED - Supported values for *cert_reqs* parameter. + Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` + attribute. diff --git a/docs/library/stm.rst b/docs/library/stm.rst index a181d6044cc16..970ab188344a5 100644 --- a/docs/library/stm.rst +++ b/docs/library/stm.rst @@ -102,3 +102,39 @@ the second CPU, the RF core. Execute a HCI command on the SYS channel. The execution is synchronous. Returns a bytes object with the result of the SYS command. + +Functions specific to STM32WLxx MCUs +------------------------------------ + +These functions are available on STM32WLxx microcontrollers, and interact with +the integrated "SUBGHZ" radio modem peripheral. + +.. function:: subghz_cs(level) + + Sets the internal SPI CS pin attached to the radio peripheral. The ``level`` + argument is active-low: a truthy value means "CS pin high" and de-asserts the + signal, a falsey value means "CS pin low" and asserts the signal. + + The internal-only SPI bus corresponding to this CS signal can be instantiated + using :ref:`machine.SPI()` ``id`` value ``"SUBGHZ"``. + +.. function:: subghz_irq(handler) + + Sets the internal SUBGHZ radio interrupt handler to the provided + function. The handler function is called as a "hard" interrupt in response to + radio peripheral interrupts. See :ref:`isr_rules` for more information about + interrupt handlers in MicroPython. + + Calling this function with the handler argument set to None disables the IRQ. + + Due to a hardware limitation, each time this IRQ fires MicroPython disables + it before calling the handler. In order to receive another interrupt, Python + code should call ``subghz_irq()`` to set the handler again. This has the side + effect of re-enabling the IRQ. + +.. function:: subghz_is_busy() + + Return a ``bool`` corresponding to the internal "RFBUSYS" signal from the + radio peripheral. Before sending a new command to the radio over SPI then + this function should be polled until it returns ``False``, to confirm the + busy signal is de-asserted. diff --git a/docs/library/struct.rst b/docs/library/struct.rst index 026cb5e8ac3b4..c2357505960d7 100644 --- a/docs/library/struct.rst +++ b/docs/library/struct.rst @@ -45,6 +45,8 @@ The following data types are supported: +--------+--------------------+-------------------+---------------+ | Q | unsigned long long | integer (`1`) | 8 | +--------+--------------------+-------------------+---------------+ +| e | n/a (half-float) | float (`2`) | 2 | ++--------+--------------------+-------------------+---------------+ | f | float | float (`2`) | 4 | +--------+--------------------+-------------------+---------------+ | d | double | float (`2`) | 8 | diff --git a/docs/library/sys.rst b/docs/library/sys.rst index 3efdce964ce05..baefd927051d2 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -12,9 +12,12 @@ Functions .. 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 + function raises a `SystemExit` exception. If an argument is given, its value given as an argument to `SystemExit`. + On embedded ports (i.e. all ports but Windows and Unix), an unhandled + `SystemExit` currently causes a :ref:`soft_reset` of MicroPython. + .. function:: atexit(func) Register *func* to be called upon termination. *func* must be a callable @@ -46,7 +49,7 @@ Functions .. function:: settrace(tracefunc) Enable tracing of bytecode execution. For details see the `CPython - documentaion `_. + documentation `_. This function requires a custom MicroPython build as it is typically not present in pre-built firmware (due to it affecting performance). The relevant @@ -69,14 +72,29 @@ Constants MicroPython, it has following attributes: * *name* - string "micropython" - * *version* - tuple (major, minor, micro), e.g. (1, 7, 0) + * *version* - tuple (major, minor, micro, releaselevel), e.g. (1, 22, 0, '') * *_machine* - string describing the underlying machine * *_mpy* - supported mpy file-format version (optional attribute) + * *_build* - string that can help identify the configuration that + MicroPython was built with This object is the recommended way to distinguish MicroPython from other Python implementations (note that it still may not exist in the very minimal ports). + Starting with version 1.22.0-preview, the fourth node *releaselevel* in + *implementation.version* is either an empty string or ``"preview"``. + + The *_build* entry was added in version 1.25.0 and is a hyphen-separated + set of elements. New elements may be appended in the future so it's best to + access this field using ``sys.implementation._build.split("-")``. The + elements that are currently used are: + + * On the unix, webassembly and windows ports the first element is the variant + name, for example ``'standard'``. + * On microcontroller targets, the first element is the board name and the second + element (if present) is the board variant, for example ``'RPI_PICO2-RISCV'`` + .. admonition:: Difference to CPython :class: attention diff --git a/docs/library/time.rst b/docs/library/time.rst index 3ab5caf248c69..8c1c1d4d6fb23 100644 --- a/docs/library/time.rst +++ b/docs/library/time.rst @@ -163,8 +163,8 @@ Functions However, values returned by `ticks_ms()`, etc. functions may wrap around, so directly using subtraction on them will produce incorrect result. That is why `ticks_diff()` is needed, it implements modular (or more specifically, ring) - arithmetics to produce correct result even for wrap-around values (as long as they not - too distant inbetween, see below). The function returns **signed** value in the range + arithmetic to produce correct result even for wrap-around values (as long as they not + too distant in between, see below). The function returns **signed** value in the range [*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for two's-complement signed binary integers). If the result is negative, it means that *ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that @@ -183,7 +183,7 @@ Functions has passed. To avoid this mistake, just look at the clock regularly. Your application should do the same. "Too long sleep" metaphor also maps directly to application behaviour: don't let your application run any single task for too long. Run tasks - in steps, and do time-keeping inbetween. + in steps, and do time-keeping in between. `ticks_diff()` is designed to accommodate various usage patterns, among them: diff --git a/docs/library/uasyncio.rst b/docs/library/uasyncio.rst deleted file mode 100644 index 4cbcfa9f98ada..0000000000000 --- a/docs/library/uasyncio.rst +++ /dev/null @@ -1,360 +0,0 @@ -: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:: current_task() - - Return the `Task` object associated with the currently running task. - -.. 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 - than *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 ``uasyncio.TimeoutError``: - this should be trapped by the caller. The task receives - ``uasyncio.CancelledError`` which may be ignored or trapped using ``try...except`` - or ``try...finally`` to run cleanup code. - - Returns the return value of *awaitable*. - - This is a coroutine. - -.. function:: wait_for_ms(awaitable, timeout) - - Similar to `wait_for` but *timeout* is an integer in milliseconds. - - This is a coroutine, and a MicroPython extension. - -.. 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 ``uasyncio.CancelledError`` into it. The task may - ignore this exception. Cleanup code may be run by trapping it, or via - ``try ... finally``. - -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. - - Note: This must be called from within a task. It is not safe to call this - from an IRQ, scheduler callback, or other thread. See `ThreadSafeFlag`. - -.. 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 ThreadSafeFlag --------------------- - -.. class:: ThreadSafeFlag() - - Create a new flag which can be used to synchronise a task with code running - outside the uasyncio loop, such as other threads, IRQs, or scheduler - callbacks. Flags start in the cleared state. The class does not currently - work under the Unix build of MicroPython. - -.. method:: ThreadSafeFlag.set() - - Set the flag. If there is a task waiting on the flag, it will be scheduled - to run. - -.. method:: ThreadSafeFlag.clear() - - Clear the flag. This may be used to ensure that a possibly previously-set - flag is clear before waiting for it. - -.. method:: ThreadSafeFlag.wait() - - Wait for the flag to be set. If the flag is already set then it returns - immediately. The flag is automatically reset upon return from ``wait``. - - A flag may only be waited on by a single task at a time. - - 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=-1) - - Read up to *n* bytes and return them. If *n* is not provided or -1 then read all - bytes until EOF. The returned value will be an empty bytes object if EOF is - encountered before any bytes are read. - - This is a coroutine. - -.. method:: Stream.readinto(buf) - - Read up to n bytes into *buf* with n being equal to the length of *buf*. - - Return the number of bytes read into *buf*. - - This is a coroutine, and a MicroPython extension. - -.. method:: Stream.readexactly(n) - - Read exactly *n* bytes and return them as a bytes object. - - Raises an ``EOFError`` exception if the stream ends before reading *n* bytes. - - 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/vfs.rst b/docs/library/vfs.rst new file mode 100644 index 0000000000000..1fa1e3060cb5b --- /dev/null +++ b/docs/library/vfs.rst @@ -0,0 +1,216 @@ +:mod:`vfs` -- virtual filesystem control +======================================== + +.. module:: vfs + :synopsis: virtual filesystem control + +The ``vfs`` module contains functions for creating filesystem objects and +mounting/unmounting them in the Virtual Filesystem. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +.. function:: mount(fsobj, mount_point, *, readonly) + + Mount the filesystem object *fsobj* at the location in the VFS given by the + *mount_point* string. *fsobj* can be a a VFS object that has a ``mount()`` + method, or a block device. If it's a block device then the filesystem type + is automatically detected (an exception is raised if no filesystem was + recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root, + or ``'/'`` to mount it at a subdirectory under the root. + + If *readonly* is ``True`` then the filesystem is mounted read-only. + + During the mount process the method ``mount()`` is called on the filesystem + object. + + Will raise ``OSError(EPERM)`` if *mount_point* is already mounted. + +.. function:: mount() + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + +.. function:: umount(mount_point) + + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + +.. class:: VfsFat(block_dev) + + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + + .. staticmethod:: mkfs(block_dev) + + Build a FAT filesystem on *block_dev*. + +.. class:: VfsLfs1(block_dev, readsize=32, progsize=32, lookahead=32) + + 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, readsize=32, progsize=32, lookahead=32) + + 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, readsize=32, progsize=32, lookahead=32, mtime=True) + + 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`. + + The *mtime* argument enables modification timestamps for files, stored using + littlefs attributes. This option can be disabled or enabled differently each + mount time and timestamps will only be added or updated if *mtime* is enabled, + otherwise the timestamps will remain untouched. Littlefs v2 filesystems without + timestamps will work without reformatting and timestamps will be added + transparently to existing files once they are opened for writing. When *mtime* + is enabled `os.stat` on files without timestamps will return 0 for the timestamp. + + See :ref:`filesystem` for more information. + + .. staticmethod:: mkfs(block_dev, readsize=32, progsize=32, lookahead=32) + + Build a Lfs2 filesystem on *block_dev*. + + .. note:: There are reports of littlefs v2 failing in certain situations, + for details see `littlefs issue 295`_. + +.. class:: VfsPosix(root=None) + + Create a filesystem object that accesses the host POSIX filesystem. + If *root* is specified then it should be a path in the host filesystem to use + as the root of the ``VfsPosix`` object. Otherwise the current directory of + the host filesystem is used. + +.. _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. 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 ``os`` +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(...) + + Construct a block device object. The parameters to the constructor are + dependent on the specific block device. + + .. method:: readblocks(block_num, buf) + 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) + 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 + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 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 + + As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs + ``ioctl(6, ...)`` must also be intercepted. The need for others is + hardware dependent. + + Prior to any call to ``writeblocks(block, ...)`` littlefs issues + ``ioctl(6, block)``. This enables a device driver to erase the block + prior to a write if the hardware requires it. Alternatively a driver + might intercept ``ioctl(6, block)`` and return 0 (success). In this case + the driver assumes responsibility for detecting the need for erasure. + + 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/wm8960.rst b/docs/library/wm8960.rst index add003630eb8c..5abfb6a8a011c 100644 --- a/docs/library/wm8960.rst +++ b/docs/library/wm8960.rst @@ -251,7 +251,7 @@ controlling its operation: .. method:: WM8960.expand_3d(level) - Enable Stereo 3D exansion. *level* is a number between 0 and 15. + Enable Stereo 3D expansion. *level* is a number between 0 and 15. A value of 0 disables the expansion. .. method:: WM8960.mono(active) diff --git a/docs/library/zephyr.DiskAccess.rst b/docs/library/zephyr.DiskAccess.rst index d19d81a962e23..e5eac8ca4988b 100644 --- a/docs/library/zephyr.DiskAccess.rst +++ b/docs/library/zephyr.DiskAccess.rst @@ -34,5 +34,5 @@ Methods These methods implement the simple and extended :ref:`block protocol ` defined by - :class:`uos.AbstractBlockDev`. + :class:`vfs.AbstractBlockDev`. diff --git a/docs/library/zephyr.FlashArea.rst b/docs/library/zephyr.FlashArea.rst index 306347d449eab..749b90a3b43c5 100644 --- a/docs/library/zephyr.FlashArea.rst +++ b/docs/library/zephyr.FlashArea.rst @@ -37,4 +37,4 @@ Methods These methods implement the simple and extended :ref:`block protocol ` defined by - :class:`uos.AbstractBlockDev`. + :class:`vfs.AbstractBlockDev`. diff --git a/docs/library/zephyr.rst b/docs/library/zephyr.rst index da3d14a093ecf..1a106d50ea717 100644 --- a/docs/library/zephyr.rst +++ b/docs/library/zephyr.rst @@ -22,9 +22,10 @@ Functions Returns the thread id of the current thread, which is used to reference the thread. -.. function:: thread_analyze() +.. function:: thread_analyze(cpu) - Runs the Zephyr debug thread analyzer on the current thread and prints stack size statistics in the format: + Runs the Zephyr debug thread analyzer on the current thread on the given cpu + and prints stack size statistics in the format: "``thread_name``-20s: STACK: unused ``available_stack_space`` usage ``stack_space_used`` / ``stack_size`` (``percent_stack_space_used`` %); CPU: ``cpu_utilization`` %" @@ -32,9 +33,12 @@ Functions * *CPU utilization is only printed if runtime statistics are configured via the ``CONFIG_THREAD_RUNTIME_STATS`` kconfig* This function can only be accessed if ``CONFIG_THREAD_ANALYZER`` is configured for the port in ``zephyr/prj.conf``. - For more infomation, see documentation for Zephyr `thread analyzer + For more information, see documentation for Zephyr `thread analyzer `_. + Note that the ``cpu`` argument is only used in Zephyr v4.0.0 and + newer and ignored otherwise. + .. function:: shell_exec(cmd_in) Executes the given command on an UART backend. This function can only be accessed if ``CONFIG_SHELL_BACKEND_SERIAL`` diff --git a/docs/library/zlib.rst b/docs/library/zlib.rst index 96d6c245232ba..54310b72f2a3d 100644 --- a/docs/library/zlib.rst +++ b/docs/library/zlib.rst @@ -1,38 +1,82 @@ -:mod:`zlib` -- zlib decompression -================================= +:mod:`zlib` -- zlib compression & decompression +=============================================== .. module:: zlib - :synopsis: zlib decompression + :synopsis: zlib compression & decompression |see_cpython_module| :mod:`python:zlib`. -This module allows to decompress binary data compressed with +This module allows compression and decompression of binary data with the `DEFLATE algorithm `_ -(commonly used in zlib library and gzip archiver). Compression -is not yet implemented. +(commonly used in the zlib library and gzip archiver). + +.. note:: Prefer to use :class:`deflate.DeflateIO` instead of the functions in this + module as it provides a streaming interface to compression and decompression + which is convenient and more memory efficient when working with reading or + writing compressed data to a file, socket, or stream. + +**Availability:** + +* From MicroPython v1.21 onwards, this module may not be present by default on + all MicroPython firmware as it duplicates functionality available in + the :mod:`deflate ` module. + +* A copy of this module can be installed (or frozen) + from :term:`micropython-lib` (`source `_). + See :ref:`packages` for more information. This documentation describes that module. + +* Requires the built-in :mod:`deflate ` module (available since MicroPython v1.21) + +* Compression support will only be available if compression support is enabled + in the built-in :mod:`deflate ` module. Functions --------- -.. function:: decompress(data, wbits=0, bufsize=0, /) +.. function:: decompress(data, wbits=15, /) + + Decompresses *data* into a bytes object. + + The *wbits* parameter works the same way as for :meth:`zlib.compress` + with the following additional valid values: + + * ``0``: Automatically determine the window size from the zlib header + (*data* must be in zlib format). + * ``35`` to ``47``: Auto-detect either the zlib or gzip format. + + As for :meth:`zlib.compress`, see the :mod:`CPython documentation for zlib ` + for more information about the *wbits* parameter. As for :meth:`zlib.compress`, + MicroPython also supports smaller window sizes than CPython. See more + :ref:`MicroPython-specific details ` in the + :mod:`deflate ` module documentation. + + If the data to be decompressed requires a larger window size, it will + fail during decompression. + +.. function:: compress(data, wbits=15, /) - Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window - size used during compression (8-15, the dictionary size is power of 2 of - that value). Additionally, if value is positive, *data* is assumed to be - zlib stream (with zlib header). Otherwise, if it's negative, it's assumed - to be raw DEFLATE stream. *bufsize* parameter is for compatibility with - CPython and is ignored. + Compresses *data* into a bytes object. -.. class:: DecompIO(stream, wbits=0, /) + *wbits* allows you to configure the DEFLATE dictionary window size and the + output format. The window size allows you to trade-off memory usage for + compression level. A larger window size will allow the compressor to + reference fragments further back in the input. The output formats are "raw" + DEFLATE (no header/footer), zlib, and gzip, where the latter two + include a header and checksum. - Create a `stream` wrapper which allows transparent decompression of - compressed data in another *stream*. This allows to process compressed - streams with data larger than available heap size. In addition to - values described in :func:`decompress`, *wbits* may take values - 24..31 (16 + 8..15), meaning that input stream has gzip header. + The low four bits of the absolute value of *wbits* set the base-2 logarithm of + the DEFLATE dictionary window size. So for example, ``wbits=10``, + ``wbits=-10``, and ``wbits=26`` all set the window size to 1024 bytes. Valid + window sizes are ``5`` to ``15`` inclusive (corresponding to 32 to 32k bytes). - .. admonition:: Difference to CPython - :class: attention + Negative values of *wbits* between ``-5`` and ``-15`` correspond to "raw" + output mode, positive values between ``5`` and ``15`` correspond to zlib + output mode, and positive values between ``21`` and ``31`` correspond to + gzip output mode. - This class is MicroPython extension. It's included on provisional - basis and may be changed considerably or removed in later versions. + See the :mod:`CPython documentation for zlib ` for more + information about the *wbits* parameter. Note that MicroPython allows + for smaller window sizes, which is useful when memory is constrained while + still achieving a reasonable level of compression. It also speeds up + the compressor. See more :ref:`MicroPython-specific details ` + in the :mod:`deflate ` module documentation. diff --git a/docs/mimxrt/pinout.rst b/docs/mimxrt/pinout.rst index ef53fa63bff22..9aeb85401be8d 100644 --- a/docs/mimxrt/pinout.rst +++ b/docs/mimxrt/pinout.rst @@ -14,9 +14,9 @@ The pin assignment of UARTs to pins is fixed. The UARTs are numbered 0..8. The rx/tx pins are assigned according to the tables below: -================ =========== =========== =========== =========== +================= =========== =========== =========== =========== Board / Pin UART0 UART1 UART2 UART3 -================ =========== =========== =========== =========== +================= =========== =========== =========== =========== Teensy 4.0 - 0/1 7/8 14/15 Teensy 4.1 - 0/1 7/8 14/15 MIMXRT1010-EVK Debug USB D0/D1 D7/D6 - @@ -27,28 +27,31 @@ MIMXRT1050-EVKB Debug USB D0/D1 D7/D6 D8/D9 MIMXRT1060-EVK Debug USB D0/D1 D7/D6 D8/D9 MIMXRT1064-EVK Debug USB D0/D1 D7/D6 D8/D9 MIMXRT1170-EVK Debug USB D0/D1 D12/D11 D10/D13 -Olimex RT1010Py - RxD/TxD D5/D6 - -Seeed ARCH MIX - J3_19/J3_20 J4_16/J4_17 J4_06/J4_07 -================ =========== =========== =========== =========== +Adafruit Metro M7 - D0/D1 D7/D3 A1/A0 +Olimex RT1010Py - RxD/TxD D7/D8 D5/D6 +Seeed ARCH MIX - J3_19/J3_20 J4_16/J4_17 J4_06/J4_07 +Makerdiary RT1011 - D9/D10 D13/A0 D11/D12 +================= =========== =========== =========== =========== | -================ =========== =========== ======= ======= ===== -Board / Pin UART4 UART5 UART6 UART7 UART8 -================ =========== =========== ======= ======= ===== -Teensy 4.0 16/17 21/20 25/24 28/29 - -Teensy 4.1 16/17 21/20 25/24 28/29 34/35 -MIMXRT1010-EVK - - - - - -MIMXRT1015-EVK - - - - - -MIMXRT1020-EVK D15/D14 A1/A0 - - - -MIMXRT1050-EVK A1/A0 - - - - -MIMXRT1050-EVKB A1/A0 - - - - -MIMXRT1060-EVK A1/A0 - - - - -MIMXRT1064-EVK A1/A0 - - - - -MIMXRT1170-EVK D15/D14 D25/D26 D33/D34 D35/D36 - -Olimex RT1010Py - - - - - -Seeed ARCH MIX J4_10/J4_11 J5_08/J5_12 - - - -================ =========== =========== ======= ======= ===== +================= =========== =========== ======= ======= ===== +Board / Pin UART4 UART5 UART6 UART7 UART8 +================= =========== =========== ======= ======= ===== +Teensy 4.0 16/17 21/20 25/24 28/29 - +Teensy 4.1 16/17 21/20 25/24 28/29 34/35 +MIMXRT1010-EVK - - - - - +MIMXRT1015-EVK - - - - - +MIMXRT1020-EVK D15/D14 A1/A0 - - - +MIMXRT1050-EVK A1/A0 - - - - +MIMXRT1050-EVKB A1/A0 - - - - +MIMXRT1060-EVK A1/A0 - - - - +MIMXRT1064-EVK A1/A0 - - - - +MIMXRT1170-EVK D15/D14 D25/D26 D33/D34 D35/D36 - +Olimex RT1010Py - - - - - +Seeed ARCH MIX J4_10/J4_11 J5_08/J5_12 - - - +Makerdiary RT1011 A1/A2 - - - - +================= =========== =========== ======= ======= ===== .. _mimxrt_pwm_pinout: @@ -61,38 +64,38 @@ PWM pin assignment Pins are specified in the same way as for the Pin class. The following tables show the assignment of the board Pins to PWM modules: -=========== ========== ========== ====== ============== ====== -Pin/ MIMXRT 1010 1015 1020 1050/1060/1064 1170 -=========== ========== ========== ====== ============== ====== -D0 - Q1/1 F1/1/B - - -D1 - Q1/0 F1/1/A - - -D2 F1/3/B F1/3/A - F1/3/B - -D3 F1/3/A F1/0/A F2/3/B F4/0/A F1/2/A -D4 F1/3/A (*) Q1/2 Q2/1 F2/3/A Q4/2 -D5 F1/0/B (*) F1/0/B F2/3/A F1/3/A F1/2/B -D6 - F1/2/B F2/0/A Q3/2 F1/0/A -D7 - - F1/0/A Q3/3 - -D8 F1/0/A F1/1/B F1/0/B F1/1/X Q4/3 -D9 F1/1/B (*) F1/2/A F2/0/B F1/0/X F1/0/B -D10 F1/3/B - F2/2/B F1/0/B (*) F2/2/B -D11 F1/2/A - F2/1/A F1/1/A (*) - -D12 F1/2/B - F2/1/B F1/1/B (*) - -D13 F1/3/A - F2/2/A F1/0/A (*) F2/2/A -D14 F1/0/B - - F2/3/B - -D15 F1/0/A - - F2/3/A - -A0 - - F1/2/A - - -A1 F1/3/X F1/3/B F1/2/B - - -A2 F1/2/X F1/3/A F1/3/A - - -A3 - F1/2/A F1/3/B - - -A4 - - - Q3/1 - -A5 - - - Q3/0 - -D31 - - - - F1/2/B -D32 - - - - F1/2/A -D33 - - - - F1/1/B -D34 - - - - F1/1/A -D35 - - - - F1/0/B -D36 - - - - F1/0/A -=========== ========== ========== ====== ============== ====== +=========== ========== ========== ====== ========== ====== ======== +Pin/ MIMXRT 1010 1015 1020 1050/60/64 1170 Metro M7 +=========== ========== ========== ====== ========== ====== ======== +D0 - Q1/1 F1/1/B - - - +D1 - Q1/0 F1/1/A - - - +D2 F1/3/B F1/3/A - F1/3/B - - +D3 F1/3/A F1/0/A F2/3/B F4/0/A F1/2/A - +D4 F1/3/A (*) Q1/2 Q2/1 F2/3/A Q4/2 F1/0/B +D5 F1/0/B (*) F1/0/B F2/3/A F1/3/A F1/2/B F1/0/A +D6 - F1/2/B F2/0/A Q3/2 F1/0/A - +D7 - - F1/0/A Q3/3 - - +D8 F1/0/A F1/1/B F1/0/B F1/1/X Q4/3 F1/3/A +D9 F1/1/B (*) F1/2/A F2/0/B F1/0/X F1/0/B F1/3/B +D10 F1/3/B - F2/2/B F1/0/B (*) F2/2/B F1/2/A +D11 F1/2/A - F2/1/A F1/1/A (*) - F1/2/B +D12 F1/2/B - F2/1/B F1/1/B (*) - F1/1/A +D13 F1/3/A - F2/2/A F1/0/A (*) F2/2/A F1/1/B +D14 F1/0/B - - F2/3/B - F1/0/B +D15 F1/0/A - - F2/3/A - F1/0/A +A0 - - F1/2/A - - - +A1 F1/3/X F1/3/B F1/2/B - - - +A2 F1/2/X F1/3/A F1/3/A - - - +A3 - F1/2/A F1/3/B - - F1/3/B +A4 - - - Q3/1 - F1/2/X +A5 - - - Q3/0 - - +D31 - - - - F1/2/B - +D32 - - - - F1/2/A - +D33 - - - - F1/1/B - +D34 - - - - F1/1/A - +D35 - - - - F1/0/B - +D36 - - - - F1/0/A - +=========== ========== ========== ====== ========== ====== ======== Pins denoted with (*) are by default not wired at the board. @@ -187,7 +190,6 @@ LED_BLUE F1/3/B ========= =============== Pin Olimex RT1010PY ========= =============== -D0 - D1 F1/0/B D2 F1/0/A D3 F1/1/B @@ -196,13 +198,10 @@ D5 F1/2/B D6 F1/2/A D7 F1/3/B D8 F1/3/A -D9 - D10 F1/0/B D11 F1/0/A D12 F1/1/B D13 F1/1/A -D14 - -A0 - A1 F1/2/B A2 F1/2/A A3 F1/3/B @@ -213,6 +212,32 @@ CS0 F1/1/X SCK F1/0/X ========= =============== +| + +========= ================= +Pin Makerdiary RT1011 +========= ================= +D1 F1/0/B +D2 F1/0/A +D3 F1/1/B +D4 F1/1/A +D5 F1/2/B +D6 F1/2/A +D7 F1/3/B +D8 F1/3/A +A3 F1/2/B +A4 F1/2/A +A5 F1/3/B +A6 F1/3/A +A9 F1/3/X +A10 F1/2/X +A11 F1/1/X +SD1 F1/0/B +SD2 F1/0/A +LED F1/1/B +DIO F1/0/X +========= ================= + Legend: * Qm/n: QTMR module m, channel n @@ -318,8 +343,10 @@ MIXMXRT1050-EVKB D10/-/D11/D12/D13 (*) - - MIXMXRT1060-EVK D10/-/D11/D12/D13 (*) - - MIXMXRT1064-EVK D10/-/D11/D12/D13 (*) - - MIXMXRT1170-EVK D10/-/D11/D12/D13 D28/-/D25/D24/D26 -/-/D14/D15/D24 +Adafruit Metro M7 -/-/MOSI/MISO/SCK - - Olimex RT1010Py - CS0/-/SDO/SDI/SCK SDCARD with CS1 Seeed ARCH MIX J4_12/-/J4_14/J4_13/J4_15 J3_09/J3_05/J3_08_J3_11 +Makerdiary RT1011 A5/A2/A4/A3/A6 A11/A1/A10/A9/CLK ================= ========================= ======================= =============== Pins denoted with (*) are by default not wired at the board. The CS0 and CS1 signals @@ -350,8 +377,10 @@ MIXMXRT1050-EVKB A4/A5 D1/D0 - - - MIXMXRT1060-EVK A4/A5 D1/D0 - - - MIXMXRT1064-EVK A4/A5 D1/D0 - - - MIXMXRT1170-EVK D14/D15 D1/D0 A4/A5 D26/D25 D19/D18 +Adafruit Metro M7 D14/D15 D0/D1 Olimex RT1010Py - SDA1/SCL1 SDA2/SCL2 - - Seeed ARCH MIX J3_17/J3_16 J4_06/J4_07 J5_05/J5_04 - - +Makerdiary RT1011 D1/D2 A7/A8 ================= =========== =========== =========== ======= ======= .. _mimxrt_i2s_pinout: @@ -364,18 +393,20 @@ Hardware I2S pin assignment Pin assignments for a few MIMXRT boards: -=============== == ===== ======== ======= ======= ======== ======= ======= -Board ID MCK SCK_TX WS_TX SD_TX SCK_RX WS_RX SD_RX -=============== == ===== ======== ======= ======= ======== ======= ======= -Teensy 4.0 1 23 26 27 7 21 20 8 -Teensy 4.0 2 33 4 3 2 - - 5 -Teensy 4.1 1 23 26 27 7 21 20 8 -Teensy 4.1 2 33 4 3 2 - - 5 -Seeed Arch MIX 1 J4_09 J4_14 J4_15 J14_13 J4_11 J4_10 J4_10 -Olimex RT1010Py 1 D8 D6 D7 D4 D1 D2 D3 -Olimex RT1010Py 3 - D10 D9 D11 - - - -MIMXRT_DEV 1 "MCK" "SCK_TX" "WS_TX" "SD_TX" "SCK_RX" "WS_RX" "SD_RX" -=============== == ===== ======== ======= ======= ======== ======= ======= +================= == ===== ======== ======= ======= ======== ======= ======= +Board ID MCK SCK_TX WS_TX SD_TX SCK_RX WS_RX SD_RX +================= == ===== ======== ======= ======= ======== ======= ======= +Teensy 4.0 1 23 26 27 7 21 20 8 +Teensy 4.0 2 33 4 3 2 - - 5 +Teensy 4.1 1 23 26 27 7 21 20 8 +Teensy 4.1 2 33 4 3 2 - - 5 +Seeed Arch MIX 1 J4_09 J4_14 J4_15 J14_13 J4_11 J4_10 J4_10 +Adafruit Metro M7 1 D8 D10 D9 D12 D14 D15 D13 +Olimex RT1010Py 1 D8 D6 D7 D4 D1 D2 D3 +Olimex RT1010Py 3 - D10 D9 D11 - - - +MIMXRT_DEV 1 "MCK" "SCK_TX" "WS_TX" "SD_TX" "SCK_RX" "WS_RX" "SD_RX" +Makerdiary RT1011 1 D8 SD1 D7 D4 D1 D2 D3 +================= == ===== ======== ======= ======= ======== ======= ======= Symbolic pin names are provided for the MIMXRT_10xx_DEV boards. -These are provided for the other boards as well. \ No newline at end of file +These are provided for the other boards as well. diff --git a/docs/mimxrt/quickref.rst b/docs/mimxrt/quickref.rst index 06f91f7f50312..9f1efd4ffcad2 100644 --- a/docs/mimxrt/quickref.rst +++ b/docs/mimxrt/quickref.rst @@ -92,9 +92,7 @@ Use the :ref:`machine.Pin ` class:: Available Pins follow the ranges and labelling of the respective board, like: -- 0-33 for Teensy 4.0, -- 0-21 for the MIMXRT10xx-EVK board, or 'D0-Dxx', or 'A0-Ann', -- 0-14 for the Olimex RT1010Py board, or 'D0'-'Dxx' and 'A0'-'Ann' +- 'D0-Dxx', or 'A0-Ann' for Teensy 4.0, MIMXRT10xx-EVK ns Olimex board, - 'J3_xx', 'J4_xx', 'J5_xx' for the Seeed ARCH MIX board, or the pin names of the Pin.board or Pin.cpu classes. @@ -106,9 +104,9 @@ Notes: * At the MIMXRT1010_EVK, pins D4, D5 and D9 of the Arduino connector are by default not connected to the MCU. For details refer to the schematics. * At the MIMXRT1170_EVK board, the inner rows of the Arduino connectors are assigned as follows: - - D16 - D23: J9, odd pin numbers; D17 is by default not connected. - - D24 - D27: J26, odd pin numbers; J63-J66 have to be closed to enable these pins. - - D29 - D36: J25, odd pin numbers; D29 and D30 are by default not connected. + - 'D16' - 'D23': J9, odd pin numbers; 'D17' is by default not connected. + - 'D24' - 'D27': J26, odd pin numbers; J63-J66 have to be closed to enable these pins. + - 'D29' - 'D36': J25, odd pin numbers; 'D29' and 'D30' are by default not connected. There's a higher-level abstraction :ref:`machine.Signal ` which can be used to invert a pin. Useful for illuminating active-low LEDs @@ -124,10 +122,13 @@ See :ref:`machine.UART `. :: uart1 = UART(1, baudrate=115200) uart1.write('hello') # write 5 bytes uart1.read(5) # read up to 5 bytes + uart1 = UART(baudrate=19200) # open UART 1 at 19200 baud The i.MXRT has up to eight hardware UARTs, but not every board exposes all TX and RX pins for users. For the assignment of Pins to UART signals, -refer to the :ref:`UART pinout `. +refer to the :ref:`UART pinout `. If the UART ID is +omitted, UART(1) is selected. Then, the keyword +option for baudrate must be used to change it from the default value. PWM (pulse width modulation) ---------------------------- @@ -145,22 +146,23 @@ handling signal groups. :: from machine import Pin, PWM - pwm2 = PWM(Pin(2)) # create PWM object from a pin - pwm2.freq() # get current frequency - pwm2.freq(1000) # set frequency - pwm2.duty_u16() # get current duty cycle, range 0-65535 - pwm2.duty_u16(200) # set duty cycle, range 0-65535 + # create PWM object from a pin and set the frequency and duty cycle + pwm2 = PWM(Pin('D2'), freq=2000, duty_u16=32768) + pwm2.freq() # get the current frequency + pwm2.freq(1000) # set/change the frequency + pwm2.duty_u16() # get the current duty cycle, range 0-65535 + pwm2.duty_u16(200) # set the duty cycle, range 0-65535 pwm2.deinit() # turn off PWM on the pin # create a complementary signal pair on Pin 2 and 3 - pwm2 = PWM((2, 3), freq=2000, duty_ns=20000) + pwm2 = PWM(('D2', 'D3'), freq=2000, duty_ns=20000) # Create a group of four synchronized signals. - # Start with Pin(4) at submodule 0, which creates the sync pulse. - pwm4 = PWM(Pin(4), freq=1000, align=PWM.HEAD) - # Pins 5, 6, and 9 are pins at the same module - pwm5 = PWM(Pin(5), freq=1000, duty_u16=10000, align=PWM.HEAD, sync=True) - pwm6 = PWM(Pin(6), freq=1000, duty_u16=20000, align=PWM.HEAD, sync=True) - pwm9 = PWM(Pin(9), freq=1000, duty_u16=30000, align=PWM.HEAD, sync=True) + # Start with Pin('D4') at submodule 0, which creates the sync pulse. + pwm4 = PWM(Pin('D4'), freq=1000, align=PWM.HEAD) + # Pins D5, D6, and D9 are pins at the same module + pwm5 = PWM(Pin('D5'), freq=1000, duty_u16=10000, align=PWM.HEAD, sync=True) + pwm6 = PWM(Pin('D6', freq=1000, duty_u16=20000, align=PWM.HEAD, sync=True) + pwm9 = PWM(Pin('D9'), freq=1000, duty_u16=30000, align=PWM.HEAD, sync=True) pwm3 # show the PWM objects properties @@ -194,7 +196,7 @@ PWM Constructor - *freq* should be an integer which sets the frequency in Hz for the PWM cycle. The valid frequency range is 15 Hz resp. 18Hz resp. 24Hz up to > 1 MHz. - - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65536``. + - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``. The duty cycle of a X channel can only be changed, if the A and B channel of the respective submodule is not used. Otherwise the duty_16 value of the X channel is 32768 (50%). @@ -206,8 +208,9 @@ PWM Constructor - *align*\=value. Shortcuts for the pulse center setting, causing the pulse either at the center of the frame (value=0), the leading edge at the begin (value=1) or the trailing edge at the end of a pulse period (value=2). - - *invert*\=True|False channel_mask. Setting a bit in the mask inverts the respective channel. - Bit 0 inverts the first specified channel, bit 2 the second. The default is 0. + - *invert*\=value channel_mask. Setting a bit in the mask inverts the respective channel. + Bit 0 inverts the first specified channel, bit 1 the second. The default is 0. For a + PWM object with a single channel, True and False may be used as values. - *sync*\=True|False. If a channel of a module's submodule 0 is already active, other submodules of the same module can be forced to be synchronous to submodule 0. Their pulse period start then at at same clock cycle. The default is False. @@ -231,7 +234,7 @@ is created by dividing the pwm_clk signal by an integral factor, according to th f = pwm_clk / (2**n * m) -with n being in the range of 0..7, and m in the range of 2..65536. pmw_clk is 125Mhz +with n being in the range of 0..7, and m in the range of 2..65535. pmw_clk is 125Mhz for MIMXRT1010/1015/1020, 150 MHz for MIMXRT1050/1060/1064 and 160MHz for MIMXRT1170. The lowest frequency is pwm_clk/2**23 (15, 18, 20Hz). The highest frequency with U16 resolution is pwm_clk/2**16 (1907, 2288, 2441 Hz), the highest frequency @@ -254,8 +257,8 @@ Use the :ref:`machine.ADC ` class:: from machine import ADC - adc = ADC(Pin(32)) # create ADC object on ADC pin - adc.read_u16() # read value, 0-65536 across voltage range 0.0v - 3.3v + adc = ADC(Pin('A2')) # create ADC object on ADC pin + adc.read_u16() # read value, 0-65535 across voltage range 0.0v - 3.3v The resolution of the ADC is 12 bit with 10 to 11 bit accuracy, irrespective of the value returned by read_u16(). If you need a higher resolution or better accuracy, use @@ -272,7 +275,7 @@ Software SPI (using bit-banging) works on all pins, and is accessed via the # construct a SoftSPI bus on the given pins # polarity is the idle state of SCK # phase=0 means sample on the first edge of SCK, phase=1 means the second - spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4)) + spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin('D0'), mosi=Pin('D2'), miso=Pin('D4')) spi.init(baudrate=200000) # set the baudrate @@ -301,16 +304,19 @@ rates (up to 30Mhz). Hardware SPI is accessed via the from machine import SPI, Pin spi = SPI(0, 10000000) - cs_pin = Pin(6, Pin.OUT, value=1) + cs_pin = Pin('D6', Pin.OUT, value=1) cs_pin(0) spi.write('Hello World') cs_pin(1) + spi = SPI(baudrate=4_000_000) # Use SPI(0) at a baudrate of 4 MHz For the assignment of Pins to SPI signals, refer to :ref:`Hardware SPI pinout `. The keyword option cs=n can be used to enable the cs pin 0 or 1 for an automatic cs signal. The -default is cs=-1. Using cs=-1 the automatic cs signal is not created. +default is cs=-1. Using cs=-1 the automatic cs signal is not created. In that case, cs has to be set by the script. Clearing that assignment requires a power cycle. +If the SPI ID is omitted, SPI(0) is selected. Then, the keyword +option for baudrate must be used to change it from the default value. Notes: @@ -329,7 +335,7 @@ accessed via the :ref:`machine.SoftI2C ` class:: from machine import Pin, SoftI2C - i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000) + i2c = SoftI2C(scl=Pin('D5'), sda=Pin('D4'), freq=100000) i2c.scan() # scan for devices @@ -355,6 +361,10 @@ has the same methods as software SPI above:: i2c = I2C(0, 400_000) i2c.writeto(0x76, b"Hello World") + i2c = I2C(freq=100_000) # use I2C(0) at 100kHz + +If the I2C ID is omitted, I2C(0) is selected. Then, the keyword +option for freq must be used to change the freq from the default value. I2S bus ------- @@ -363,7 +373,7 @@ See :ref:`machine.I2S `. Example using a Teensy 4.1 board with a si external Codec like UDA1334.:: from machine import I2S, Pin - i2s = I2S(2, sck=Pin(26), ws=Pin(27), sd=Pin(7), + i2s = I2S(2, sck=Pin('D26'), ws=Pin('D27'), sd=Pin('D7'), mode=I2S.TX, bts=16,format=I2S.STEREO, rate=44100,ibuf=40000) i2s.write(buf) # write buffer of audio samples to I2S device @@ -395,7 +405,7 @@ Example using the Teensy audio shield:: from machine import I2C, I2S, Pin from sgtl5000 import CODEC - i2s = I2S(1, sck=Pin(21), ws=Pin(20), sd=Pin(7), mck=Pin(23), + i2s = I2S(1, sck=Pin('D21'), ws=Pin('D20'), sd=Pin('D7'), mck=Pin('D23'), mode=I2S.TX, bits=16,rate=44100,format=I2S.STEREO, ibuf=40000, ) @@ -429,7 +439,9 @@ See :ref:`machine.RTC `:: from machine import RTC rtc = RTC() - rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time + rtc.datetime((2017, 8, 23, 0, 1, 12, 48, 0)) # set a specific date and + # time, eg. 2017/8/23 1:12:48 + # the day-of-week value is ignored rtc.datetime() # get date and time rtc.now() # return date and time in CPython format. @@ -438,32 +450,36 @@ The i.MXRT MCU supports battery backup of the RTC. By connecting a battery of current drawn from the battery is ~20µA, which is rather high. A CR2032 coin cell will last for about one year. +Note: In v1.23.0 the support for subseconds was removed. When reading the RTC, 0 will +be returned as value for subsecond, When setting the RTC time, the subsecond +field is ignored. The RTC itself does not provide a microsecond value. + SD card ------- See :ref:`machine.SDCard `:: - import machine, os + import machine, os, vfs sd = machine.SDCard() - fs = os.VfsFat(sd) - os.mount(fs, "/sd") # mount + fs = vfs.VfsFat(sd) + vfs.mount(fs, "/sd") # mount os.listdir('/sd') # list directory contents - os.umount('/sd') # eject + vfs.umount('/sd') # eject Note: The i.mx-rt 1011 and 1015 based boards do not support the ``machine.SDCard`` class. For these, the SPI based driver ``sdcard.py`` from the MicroPython drivers can be used. When using it, you have to overdrive the CS pin of the SPI hardware module. Example:: - import os, sdcard, machine + import vfs, sdcard, machine cs_pin = "D10" spi = machine.SPI(0) # SPI0 with cs at Pin "D10" used for SDCARD cs = machine.Pin(cs_pin, machine.Pin.OUT, value=1) sd = sdcard.SDCard(spi, cs) - vfs = os.VfsFat(sd) - os.mount(vfs, "/sdcard") + fs = vfs.VfsFat(sd) + vfs.mount(fs, "/sdcard") OneWire driver -------------- @@ -473,7 +489,7 @@ The OneWire driver is implemented in software and works on all pins:: from machine import Pin import onewire - ow = onewire.OneWire(Pin(12)) # create a OneWire bus on GPIO12 + ow = onewire.OneWire(Pin('D12')) # create a OneWire bus on GPIO12 ow.scan() # return a list of devices on the bus ow.reset() # reset the bus ow.readbyte() # read a byte @@ -503,12 +519,12 @@ The DHT driver is implemented in software and works on all pins:: import dht import machine - d = dht.DHT11(machine.Pin(4)) + d = dht.DHT11(machine.Pin('D4')) d.measure() d.temperature() # eg. 23 (°C) d.humidity() # eg. 41 (% RH) - d = dht.DHT22(machine.Pin(4)) + d = dht.DHT22(machine.Pin('D4')) d.measure() d.temperature() # eg. 23.6 (°C) d.humidity() # eg. 41.3 (% RH) @@ -528,7 +544,7 @@ Ethernet. Example usage:: lan.active(True) If there is a DHCP server in the LAN, the IP address is supplied by that server. -Otherwise, the IP address can be set with lan.ifconfig(). The default address +Otherwise, the IP address can be set with lan.ipconfig(addr4="..."). The default address is 192.168.0.1. Teensy 4.1 does not have an Ethernet jack on the board, but PJRC offers an diff --git a/docs/pyboard/general.rst b/docs/pyboard/general.rst index 0fc7332dedf4f..d1bf3829bec18 100644 --- a/docs/pyboard/general.rst +++ b/docs/pyboard/general.rst @@ -21,7 +21,7 @@ If needed, you can prevent the use of the SD card by creating an empty file called ``/flash/SKIPSD``. If this file exists when the pyboard boots up then the SD card will be skipped and the pyboard will always boot from the internal filesystem (in this case the SD card won't be mounted but you can still -mount and use it later in your program using ``os.mount``). +mount and use it later in your program using ``vfs.mount``). (Note that on older versions of the board, ``/flash`` is called ``0:/`` and ``/sd`` is called ``1:/``). diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index 62157bff0a472..52ddc29b19340 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -138,7 +138,9 @@ See :ref:`pyb.RTC ` :: from pyb import RTC rtc = RTC() - rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time + rtc.datetime((2017, 8, 23, 0, 1, 12, 48, 0)) # set a specific date and + # time, eg. 2017/8/23 1:12:48 + # the day-of-week value is ignored rtc.datetime() # get date and time PWM (pulse width modulation) diff --git a/docs/pyboard/tutorial/reset.rst b/docs/pyboard/tutorial/reset.rst index 59a3cd82ae1a7..ad56995c60dd7 100644 --- a/docs/pyboard/tutorial/reset.rst +++ b/docs/pyboard/tutorial/reset.rst @@ -10,6 +10,8 @@ execution of ``boot.py`` and ``main.py`` and gives default USB settings. If you have problems with the filesystem you can do a factory reset, which restores the filesystem to its original state. +For more information, see :doc:`/reference/reset_boot`. + Safe mode --------- diff --git a/docs/pyboard/tutorial/usb_mouse.rst b/docs/pyboard/tutorial/usb_mouse.rst index d05b16ed5c978..31b463668fba8 100644 --- a/docs/pyboard/tutorial/usb_mouse.rst +++ b/docs/pyboard/tutorial/usb_mouse.rst @@ -120,7 +120,7 @@ minus sign in front of the y-coordinate in the ``hid.send()`` line above. Restoring your pyboard to normal -------------------------------- -If you leave your pyboard as-is, it'll behave as a mouse everytime you plug +If you leave your pyboard as-is, it'll behave as a mouse every time you plug it in. You probably want to change it back to normal. To do this you need to first enter safe mode (see above), and then edit the ``boot.py`` file. In the ``boot.py`` file, comment out (put a # in front of) the line with the diff --git a/docs/readthedocs/settings/local_settings.py b/docs/readthedocs/settings/local_settings.py index 8d2bac7a7690d..c6145dcc52adf 100644 --- a/docs/readthedocs/settings/local_settings.py +++ b/docs/readthedocs/settings/local_settings.py @@ -1,9 +1,10 @@ import os # Directory that the project lives in, aka ../.. -SITE_ROOT = '/'.join(os.path.dirname(__file__).split('/')[0:-2]) +SITE_ROOT = "/".join(os.path.dirname(__file__).split("/")[0:-2]) TEMPLATE_DIRS = ( - "%s/templates/" % SITE_ROOT, # Your custom template directory, before the RTD one to override it. - "%s/readthedocs/templates/" % SITE_ROOT, # Default RTD template dir + "%s/templates/" + % SITE_ROOT, # Your custom template directory, before the RTD one to override it. + "%s/readthedocs/templates/" % SITE_ROOT, # Default RTD template dir ) diff --git a/docs/reference/asm_thumb2_compare.rst b/docs/reference/asm_thumb2_compare.rst index 521af69da3b31..525819550314e 100644 --- a/docs/reference/asm_thumb2_compare.rst +++ b/docs/reference/asm_thumb2_compare.rst @@ -75,7 +75,7 @@ Execute the next instruction if is true: * ite() If then else -If is true, execute the next instruction, otherwise execute the +If is true, execute the next instruction, otherwise execute the subsequent one. Thus: :: @@ -86,5 +86,5 @@ subsequent one. Thus: mov(r0, 200) # runs if r0 != r1 # execution continues here -This may be extended to control the execution of upto four subsequent instructions: it[x[y[z]]] +This may be extended to control the execution of up to four subsequent instructions: it[x[y[z]]] where x,y,z=t/e; e.g. itt, itee, itete, ittte, itttt, iteee, etc. diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index 2bcf9f7fb7930..d9a349aa6bb27 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -211,7 +211,7 @@ two loops: spi.readinto(buf) # process data in buf -The first creates a buffer on each pass whereas the second re-uses a pre-allocated +The first creates a buffer on each pass whereas the second reuses a pre-allocated buffer; this is both faster and more efficient in terms of memory fragmentation. **Bytes are smaller than ints** @@ -264,7 +264,7 @@ were a string. **Runtime compiler execution** -The Python funcitons `eval` and `exec` invoke the compiler at runtime, which +The Python functions `eval` and `exec` invoke the compiler at runtime, which requires significant amounts of RAM. Note that the ``pickle`` library from `micropython-lib` employs `exec`. It may be more RAM efficient to use the `json` library for object serialisation. @@ -403,7 +403,7 @@ Control of garbage collection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A GC can be demanded at any time by issuing `gc.collect()`. It is advantageous -to do this at intervals, firstly to pre-empt fragmentation and secondly for +to do this at intervals, firstly to preempt fragmentation and secondly for performance. A GC can take several milliseconds but is quicker when there is little work to do (about 1ms on the Pyboard). An explicit call can minimise that delay while ensuring it occurs at points in the program when it is acceptable. diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst index ca9e56344ed4c..48a465856027d 100644 --- a/docs/reference/filesystem.rst +++ b/docs/reference/filesystem.rst @@ -40,7 +40,7 @@ Block devices ------------- A block device is an instance of a class that implements the -:class:`os.AbstractBlockDev` protocol. +:class:`vfs.AbstractBlockDev` protocol. Built-in block devices ~~~~~~~~~~~~~~~~~~~~~~ @@ -108,16 +108,16 @@ RAM using a ``bytearray``:: It can be used as follows:: - import os + import vfs bdev = RAMBlockDev(512, 50) - os.VfsFat.mkfs(bdev) - os.mount(bdev, '/ramdisk') + vfs.VfsFat.mkfs(bdev) + vfs.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:`os.AbstractBlockDev.readblocks` and -:meth:`os.AbstractBlockDev.writeblocks` methods) is:: +:meth:`vfs.AbstractBlockDev.readblocks` and +:meth:`vfs.AbstractBlockDev.writeblocks` methods) is:: class RAMBlockDev: def __init__(self, block_size, num_blocks): @@ -148,13 +148,13 @@ interface (i.e. both signatures and behaviours of the return 0 As it supports the extended interface, it can be used with :class:`littlefs -`:: +`:: - import os + import vfs bdev = RAMBlockDev(512, 50) - os.VfsLfs2.mkfs(bdev) - os.mount(bdev, '/ramdisk') + vfs.VfsLfs2.mkfs(bdev) + vfs.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:: @@ -166,8 +166,8 @@ normally would be used from Python code, for example:: Filesystems ----------- -MicroPython ports can provide implementations of :class:`FAT `, -:class:`littlefs v1 ` and :class:`littlefs v2 `. +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 @@ -197,16 +197,16 @@ 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, '/') + import vfs + vfs.umount('/') + vfs.VfsFat.mkfs(bdev) + vfs.mount(bdev, '/') # STM32 - import os, pyb - os.umount('/flash') - os.VfsFat.mkfs(pyb.Flash(start=0)) - os.mount(pyb.Flash(start=0), '/flash') + import os, vfs, pyb + vfs.umount('/flash') + vfs.VfsFat.mkfs(pyb.Flash(start=0)) + vfs.mount(pyb.Flash(start=0), '/flash') os.chdir('/flash') Littlefs @@ -222,16 +222,16 @@ resistant to filesystem corruption. To format the entire flash using littlefs v2:: # ESP8266 and ESP32 - import os - os.umount('/') - os.VfsLfs2.mkfs(bdev) - os.mount(bdev, '/') + import vfs + vfs.umount('/') + vfs.VfsLfs2.mkfs(bdev) + vfs.mount(bdev, '/') # STM32 - import os, pyb - os.umount('/flash') - os.VfsLfs2.mkfs(pyb.Flash(start=0)) - os.mount(pyb.Flash(start=0), '/flash') + import os, vfs, pyb + vfs.umount('/flash') + vfs.VfsLfs2.mkfs(pyb.Flash(start=0)) + vfs.mount(pyb.Flash(start=0), '/flash') os.chdir('/flash') A littlefs filesystem can be still be accessed on a PC over USB MSC using the @@ -264,14 +264,14 @@ 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') + import os, vfs, pyb + vfs.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') + vfs.VfsFat.mkfs(p1) + vfs.VfsLfs2.mkfs(p2) + vfs.mount(p1, '/flash') + vfs.mount(p2, '/data') os.chdir('/flash') This might be useful to make your Python files, configuration and other @@ -282,9 +282,9 @@ failure, etc. The partition at offset ``0`` will be mounted automatically (and the filesystem type automatically detected), but you can add:: - import os, pyb + import vfs, pyb p2 = pyb.Flash(start=256*1024) - os.mount(p2, '/data') + vfs.mount(p2, '/data') to ``boot.py`` to mount the data partition. @@ -297,7 +297,7 @@ 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 + import esp32, vfs p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo') - os.mount(p, '/foo') + vfs.mount(p, '/foo') diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index 74524b22fd4c2..efaa8f607f72a 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -32,7 +32,7 @@ Glossary callee-owned tuple This is a MicroPython-specific construct where, for efficiency - reasons, some built-in functions or methods may re-use the same + reasons, some built-in functions or methods may reuse 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 @@ -120,7 +120,7 @@ Glossary `_ 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 + Some of the modules 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 diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 8ac92c22ebc13..1558c0fdfa9b6 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -21,6 +21,7 @@ implementation and the best practices to use them. glossary.rst repl.rst + reset_boot.rst mpremote.rst mpyfiles.rst isr_rules.rst @@ -31,3 +32,4 @@ implementation and the best practices to use them. asm_thumb2_index.rst filesystem.rst pyboard.py.rst + micropython2_migration.rst diff --git a/docs/reference/isr_rules.rst b/docs/reference/isr_rules.rst index bdb838c590589..5e8d6ad61201a 100644 --- a/docs/reference/isr_rules.rst +++ b/docs/reference/isr_rules.rst @@ -170,11 +170,17 @@ is partially updated. When the ISR tries to read the object, a crash results. Be on rare, random occasions they can be hard to diagnose. There are ways to circumvent this issue, described in :ref:`Critical Sections ` below. -It is important to be clear about what constitutes the modification of an object. An alteration to a built-in type -such as a dictionary is problematic. Altering the contents of an array or bytearray is not. This is because bytes -or words are written as a single machine code instruction which is not interruptible: in the parlance of real time -programming the write is atomic. A user defined object might instantiate an integer, array or bytearray. It is valid -for both the main loop and the ISR to alter the contents of these. +It is important to be clear about what constitutes the modification of an object. Altering the contents of an array +or bytearray is safe. This is because bytes or words are written as a single machine code instruction which is not +interruptible: in the parlance of real time programming the write is atomic. The same is true of updating a +dictionary item because items are machine words, being integers or pointers to objects. A user defined object might +instantiate an array or bytearray. It is valid for both the main loop and the ISR to alter the contents of these. + +The hazard arises when the structure of an object is altered, notably in the case of dictionaries. Adding or deleting +keys can trigger a rehash. If a hard ISR runs while a rehash is in progress and attempts to access an item, a crash +may occur. Internally globals are implemented as a dictionary. Consequently the main program should create all +necessary globals before starting a process that generates hard interrupts. Application code should also avoid +deleting globals. MicroPython supports integers of arbitrary precision. Values between 2**30 -1 and -2**30 will be stored in a single machine word. Larger values are stored as Python objects. Consequently changes to long integers cannot @@ -203,7 +209,7 @@ issue a further interrupt. It then schedules a callback to process the data. Scheduled callbacks should comply with the principles of interrupt handler design outlined below. This is to avoid problems resulting from I/O activity and the modification of shared data which can arise in any code -which pre-empts the main program loop. +which preempts the main program loop. Execution time needs to be considered in relation to the frequency with which interrupts can occur. If an interrupt occurs while the previous callback is executing, a further instance of the callback will be queued @@ -219,20 +225,20 @@ 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. -Interfacing to uasyncio ------------------------ +Interfacing to asyncio +---------------------- -When an ISR runs it can preempt the `uasyncio` scheduler. If the ISR performs a `uasyncio` +When an ISR runs it can preempt the `asyncio` scheduler. If the ISR performs a `asyncio` operation the scheduler's operation can be disrupted. This applies whether the interrupt is hard or soft and also applies if the ISR has passed execution to another function via `micropython.schedule`. In particular creating or cancelling tasks is invalid in an ISR context. -The safe way to interact with `uasyncio` is to implement a coroutine with synchronisation performed by -`uasyncio.ThreadSafeFlag`. The following fragment illustrates the creation of a task in response +The safe way to interact with `asyncio` is to implement a coroutine with synchronisation performed by +`asyncio.ThreadSafeFlag`. The following fragment illustrates the creation of a task in response to an interrupt: .. code:: python - tsf = uasyncio.ThreadSafeFlag() + tsf = asyncio.ThreadSafeFlag() def isr(_): # Interrupt handler tsf.set() @@ -240,7 +246,7 @@ to an interrupt: async def foo(): while True: await tsf.wait() - uasyncio.create_task(bar()) + asyncio.create_task(bar()) In this example there will be a variable amount of latency between the execution of the ISR and the execution of ``foo()``. This is inherent to cooperative scheduling. The maximum latency is application diff --git a/docs/reference/manifest.rst b/docs/reference/manifest.rst index 9bcafd5839cab..dc9d6dd75b2b8 100644 --- a/docs/reference/manifest.rst +++ b/docs/reference/manifest.rst @@ -26,7 +26,7 @@ re-flashing the entire firmware. However, it can still be useful to selectively freeze some rarely-changing dependencies (such as third-party libraries). -The way to list the Python files to be be frozen into the firmware is via +The way to list the Python files to be frozen into the firmware is via a "manifest", which is a Python file that will be interpreted by the build process. Typically you would write a manifest file as part of a board definition, but you can also write a stand-alone manifest file and use it with @@ -95,6 +95,17 @@ Note: The ``opt`` keyword argument can be set on the various functions, this con the optimisation level used by the cross-compiler. See :func:`micropython.opt_level`. +.. function:: add_library(library, library_path, prepend=False) + + Register the path to an external named *library*. + + The path *library_path* will be automatically searched when using `require`. + By default the added library is added to the end of the list of libraries to + search. Pass ``True`` to *prepend* to add it to the start of the list. + + Additionally, the added library can be explicitly requested by using + ``require("name", library="library")``. + .. function:: package(package_path, files=None, base_path=".", opt=None) This is equivalent to copying the "package_path" directory to the device @@ -138,11 +149,13 @@ See :func:`micropython.opt_level`. You can use the variables above, such as ``$(PORT_DIR)`` in ``base_path``. -.. function:: require(name, unix_ffi=False) +.. function:: require(name, library=None) Require a package by name (and its dependencies) from :term:`micropython-lib`. - Optionally specify unix_ffi=True to use a module from the unix-ffi directory. + Optionally specify *library* (a string) to reference a package from a + library that has been previously registered with `add_library`. Otherwise + the list of library paths will be used. .. function:: include(manifest_path) diff --git a/docs/reference/micropython2_migration.rst b/docs/reference/micropython2_migration.rst new file mode 100644 index 0000000000000..3a114711406fd --- /dev/null +++ b/docs/reference/micropython2_migration.rst @@ -0,0 +1,81 @@ +.. _micropython2_migration: + +MicroPython 2.0 Migration Guide +=============================== + +MicroPython 2.0 is the (currently in development, not yet available) next major +release of MicroPython. + +After maintaining API compatibility for almost a decade with the ``1.x`` series, in +order to unblock some project-wide improvements MicroPython 2.0 will introduce a +small number of breaking API changes that will require some programs to be +updated. This guide explains how to update your Python code to accommodate these +changes. + +This document is a work-in-progress. As more work is done on MicroPython 2.0, +more items will be added to the lists below. + +**Note:** There are currently no MicroPython 2.0 firmware builds available for +download. You can build it yourself by enabling the ``MICROPY_PREVIEW_VERSION_2`` +config option. As it gets closer to being ready for release, builds will be +provided for both ``1.x.y`` and ``2.0.0-preview``. + +Hardware and peripherals +------------------------ + +Overview +~~~~~~~~ + +The goal is to improve consistency in the :mod:`machine` APIs across different +ports, making it easier to write code, documentation, and tutorials that work on +any supported microcontroller. + +This means that some ports' APIs need to change to match other ports. + +Changes +~~~~~~~ + +*None yet* + +OS & filesystem +--------------- + +Overview +~~~~~~~~ + +The primary goal is to support the ability to execute :term:`.mpy files <.mpy +file>` directly from the filesystem without first copying them into RAM. This +improves code deployment time and reduces memory overhead and fragmentation. + +Additionally, a further goal is to support a more flexible way of configuring +partitions, filesystem types, and options like USB mass storage. + +Changes +~~~~~~~ + +*None yet* + +CPython compatibility +--------------------- + +Overview +~~~~~~~~ + +The goal is to improve compatibility with CPython by removing MicroPython +extensions from CPython APIs. In most cases this means moving existing +MicroPython-specific functions or classes to new modules. + +This makes it easier to write code that works on both CPython and MicroPython, +which is useful for development and testing. + +Changes +~~~~~~~ + +Introduction of a new module :mod:`vfs`. The following functions and +classes have moved out of :mod:`os` to :mod:`vfs`: +- `os.mount` +- `os.umount` +- `os.VfsFat` +- `os.VfsLfs1` +- `os.VfsLfs2` +- `os.VfsPosix` diff --git a/docs/reference/mpremote.rst b/docs/reference/mpremote.rst index 3225fc5f244b2..32ca5c246a7a4 100644 --- a/docs/reference/mpremote.rst +++ b/docs/reference/mpremote.rst @@ -4,46 +4,89 @@ MicroPython remote control: mpremote ==================================== The ``mpremote`` command line tool provides an integrated set of utilities to -remotely interact with and automate a MicroPython device over a serial -connection. +remotely interact with, manage the filesystem on, and automate a MicroPython +device over a serial connection. -To use mpremote install it via ``pip``: +To use mpremote, first install it via ``pip``: .. code-block:: bash - $ pip install mpremote + $ pip install --user mpremote + +Or via `pipx `_: + +.. code-block:: bash + + $ pipx install mpremote The simplest way to use this tool is just by invoking it without any arguments: .. code-block:: bash - mpremote + $ mpremote This command automatically detects and connects to the first available USB -serial device and provides an interactive REPL. Serial ports are opened in -exclusive mode, so running a second (or third, etc) instance of ``mpremote`` -will connect to subsequent serial devices, if any are available. +serial device and provides an interactive terminal that you can use to access +the REPL and your program's output. Serial ports are opened in exclusive mode, +so running a second (or third, etc) instance of ``mpremote`` will connect to +subsequent serial devices, if any are available. + +Additionally ``pipx`` also allows you to directly run ``mpremote`` without +installing first: + +.. code-block:: bash + $ pipx run mpremote ...args Commands -------- -For REPL access, running ``mpremote`` without any arguments is usually all that -is needed. ``mpremote`` also supports a set of commands given at the command -line which will perform various actions on remote MicroPython devices. +``mpremote`` supports being given a series of commands given at the command line +which will perform various actions in sequence on a remote MicroPython device. +See the :ref:`examples section ` below to get an idea of how +this works and for some common combinations of commands. -For commands that support multiple arguments (e.g. a list of files), the -argument list can be terminated with ``+``. +Each command is of the form `` [--options] [args...]``. For commands +that support multiple arguments (e.g. a list of files), the argument list can +be terminated with ``+``. -The full list of supported commands are: +If no command is specified, the default command is ``repl``. Additionally, if +any command needs to access the device, and no earlier ``connect`` has been +specified, then an implicit ``connect auto`` is added. -- connect to a specified device via a device-name shortcut: +In order to get the device into a known state for any action command +(except ``repl``), once connected ``mpremote`` will stop any running program +and soft-reset the device before running the first command. You can control +this behavior using the ``resume`` and ``soft-reset`` commands. +See :ref:`auto-connection and auto-soft-reset ` for more details. - .. code-block:: bash +Multiple commands can be specified and they will be run sequentially. - $ mpremote +The full list of supported commands are: -- connect to specified device via name: +- `connect ` +- `disconnect ` +- `resume ` +- `soft_reset ` +- `repl ` +- `eval ` +- `exec ` +- `run ` +- `fs ` +- `df ` +- `edit ` +- `mip ` +- `mount ` +- `unmount ` +- `romfs ` +- `rtc ` +- `sleep ` +- `reset ` +- `bootloader ` + +.. _mpremote_command_connect: + +- **connect** -- connect to specified device via name: .. code-block:: bash @@ -54,88 +97,210 @@ The full list of supported commands are: - ``list``: list available devices - ``auto``: connect to the first available USB serial port - ``id:``: connect to the device with USB serial number - ```` (the second entry in the output from the ``connect list`` - command) - - ``port:``: connect to the device with the given path + ```` (the second column from the ``connect list`` + command output) + - ``port:``: connect to the device with the given path (the first column + from the ``connect list`` command output + - ``rfc2217://:``: connect to the device using serial over TCP + (e.g. a networked serial port based on RFC2217) - any valid device name/path, to connect to that device -- disconnect current device: + **Note:** Instead of using the ``connect`` command, there are several + :ref:`pre-defined shortcuts ` for common device paths. For + example the ``a0`` shortcut command is equivalent to + ``connect /dev/ttyACM0`` (Linux), or ``c0`` for ``COM0`` (Windows). + + **Note:** The ``auto`` option will only detect USB serial ports, i.e. a serial + port that has an associated USB VID/PID (i.e. CDC/ACM or FTDI-style + devices). Other types of serial ports will not be auto-detected. + +.. _mpremote_command_disconnect: + +- **disconnect** -- disconnect current device: .. code-block:: bash $ mpremote disconnect - After a disconnect, auto soft-reset is enabled. + After a disconnect, :ref:`auto-soft-reset ` is enabled. + +.. _mpremote_command_resume: -- resume a previous ``mpremote`` session: +- **resume** -- maintain existing interpreter state for subsequent commands: .. code-block:: bash $ mpremote resume - This disables auto soft-reset. + This disables :ref:`auto-soft-reset `. This is useful if you + want to run a subsequent command on a board without first soft-resetting it. -- perform a soft-reset of the device: +.. _mpremote_command_soft_reset: + +- **soft-reset** -- perform a soft-reset of the device: .. code-block:: bash $ mpremote soft-reset This will clear out the Python heap and restart the interpreter. It also - disables auto soft-reset. + prevents the subsequent command from triggering :ref:`auto-soft-reset `. + +.. _mpremote_command_repl: -- enter the REPL on the connected device: +- **repl** -- enter the REPL on the connected device: .. code-block:: bash - $ mpremote repl [options] + $ mpremote repl [--options] Options are: + - ``--escape-non-printable``, to print non-printable bytes/characters as their hex code - ``--capture ``, to capture output of the REPL session to the given file - ``--inject-code ``, to specify characters to inject at the REPL when - Ctrl-J is pressed + ``Ctrl-J`` is pressed. This allows you to automate a common command. - ``--inject-file ``, to specify a file to inject at the REPL when - Ctrl-K is pressed + ``Ctrl-K`` is pressed. This allows you to run a file (e.g. containing some + useful setup code, or even the program you are currently working on). + + While the ``repl`` command running, you can use ``Ctrl-]`` or ``Ctrl-x`` to + exit. + + **Note:** The name "REPL" here reflects that the common usage of this command + to access the Read Eval Print Loop that is running on the MicroPython + device. Strictly, the ``repl`` command is just functioning as a terminal + (or "serial monitor") to access the device. Because this command does not + trigger the :ref:`auto-reset behavior `, this means that if + a program is currently running, you will first need to interrupt it with + ``Ctrl-C`` to get to the REPL, which will then allow you to access program + state. You can also use ``mpremote soft-reset repl`` to get a "clean" REPL + with all program state cleared. + +.. _mpremote_command_eval: -- evaluate and print the result of a Python expression: +- **eval** -- evaluate and print the result of a Python expression: .. code-block:: bash $ mpremote eval -- execute the given Python code: +.. _mpremote_command_exec: + +- **exec** -- execute the given Python code: .. code-block:: bash $ mpremote exec -- run a script from the local filesystem: + By default, ``mpremote exec`` will display any output from the expression until it + terminates. The ``--no-follow`` flag can be specified to return immediately and leave + the device running the expression in the background. + +.. _mpremote_command_run: + +- **run** -- run a script from the local filesystem: .. code-block:: bash - $ mpremote run + $ mpremote run + + This will execute the file directly from RAM on the device without copying it + to the filesystem. This is a very useful way to iterate on the development of + a single piece of code without having to worry about deploying it to the + filesystem. + + By default, ``mpremote run`` will display any output from the script until it + terminates. The ``--no-follow`` flag can be specified to return immediately and leave + the device running the script in the background. + +.. _mpremote_command_fs: -- execute filesystem commands on the device: +- **fs** -- execute filesystem commands on the device: .. code-block:: bash - $ mpremote fs + $ mpremote fs - ```` may be: + ```` may be: - ``cat `` to show the contents of a file or files on the device - ``ls`` to list the current directory - ``ls `` to list the given directories - - ``cp [-r] `` to copy files; use ":" as a prefix to specify - a file on the device - - ``rm `` to remove files on the device + - ``cp [-rf] `` to copy files + - ``rm [-r] `` to remove files or folders on the device - ``mkdir `` to create directories on the device - ``rmdir `` to remove directories on the device - ``touch `` to create the files (if they don't already exist) + - ``sha256sum `` to calculate the SHA256 sum of files -- edit a file on the device: + The ``cp`` command uses a convention where a leading ``:`` represents a remote + path. Without a leading ``:`` means a local path. This is based on the + convention used by the `Secure Copy Protocol (scp) client + `_. + + So for example, ``mpremote fs cp main.py :main.py`` copies ``main.py`` from + the current local directory to the remote filesystem, whereas + ``mpremote fs cp :main.py main.py`` copies ``main.py`` from the device back + to the current directory. + + The ``mpremote rm -r`` command accepts both relative and absolute paths. + Use ``:`` to refer to the current remote working directory (cwd) to allow a + directory tree to be removed from the device's default path (eg ``/flash``, ``/``). + Use ``-v/--verbose`` to see the files being removed. + + For example: + + - ``mpremote rm -r :libs`` will remove the ``libs`` directory and all its + child items from the device. + - ``mpremote rm -rv :/sd`` will remove all files from a mounted SDCard and result + in a non-blocking warning. The mount will be retained. + - ``mpremote rm -rv :/`` will remove all files on the device, including any + located in mounted vfs such as ``/sd`` or ``/flash``. After removing all folders + and files, this will also return an error to mimic unix ``rm -rf /`` behaviour. + + .. warning:: + There is no supported way to undelete files removed by ``mpremote rm -r :``. + Please use with caution. + + All other commands implicitly assume the path is a remote path, but the ``:`` + can be optionally used for clarity. + + All of the filesystem sub-commands take multiple path arguments, so if there + is another command in the sequence, you must use ``+`` to terminate the + arguments, e.g. + + .. code-block:: bash + + $ mpremote fs cp main.py :main.py + repl + + This will copy the file to the device then enter the REPL. The ``+`` prevents + ``"repl"`` being interpreted as a path. + + The ``cp`` command supports the ``-r`` option to make a recursive copy. By + default ``cp`` will skip copying files to the remote device if the SHA256 hash + of the source and destination file matches. To force a copy regardless of the + hash use the ``-f`` option. + + **Note:** For convenience, all of the filesystem sub-commands are also + :ref:`aliased as regular commands `, i.e. you can write + ``mpremote cp ...`` instead of ``mpremote fs cp ...``. + +.. _mpremote_command_df: + +- **df** -- query device free/used space + + .. code-block:: bash + + $ mpremote df + + The ``df`` command will print size/used/free statistics for the device + filesystem, similar to the Unix ``df`` command. + +.. _mpremote_command_edit: + +- **edit** -- edit a file on the device: .. code-block:: bash @@ -146,7 +311,9 @@ The full list of supported commands are: variable ``$EDITOR``). If the editor exits successfully, the updated file will be copied back to the device. -- install packages from :term:`micropython-lib` (or GitHub) using the ``mip`` tool: +.. _mpremote_command_mip: + +- **mip** -- install packages from :term:`micropython-lib` (or GitHub) using the ``mip`` tool: .. code-block:: bash @@ -154,16 +321,34 @@ The full list of supported commands are: See :ref:`packages` for more information. -- mount the local directory on the remote device: +.. _mpremote_command_mount: + +- **mount** -- mount the local directory on the remote device: .. code-block:: bash $ mpremote mount [options] - During usage, Ctrl-D will soft-reboot and normally reconnect the mount automatically. - If the unit has a main.py running at startup however the remount cannot occur. - In this case a raw mode soft reboot can be used: Ctrl-A Ctrl-D to reboot, - then Ctrl-B to get back to normal repl at which point the mount will be ready. + This allows the remote device to see the local host directory as if it were + its own filesystem. This is useful for development, and avoids the need to + copy files to the device while you are working on them. + + The device installs a filesystem driver, which is then mounted in the + :ref:`device VFS ` as ``/remote``, which uses the serial + connection to ``mpremote`` as a side-channel to access files. The device + will have its current working directory (via ``os.chdir``) set to + ``/remote`` so that imports and file access will occur there instead of the + default filesystem path while the mount is active. + + **Note:** If the ``mount`` command is not followed by another action in the + sequence, a ``repl`` command will be implicitly added to the end of the + sequence. + + During usage, Ctrl-D will trigger a soft-reset as normal, but the mount will + automatically be re-connected. If the unit has a main.py running at startup + however the remount cannot occur. In this case a raw mode soft reboot can be + used: Ctrl-A Ctrl-D to reboot, then Ctrl-B to get back to normal repl at + which point the mount will be ready. Options are: @@ -172,22 +357,97 @@ The full list of supported commands are: local directory that is mounted. This option disables this check for symbolic links, allowing the device to follow symbolic links outside of the local directory. -- unmount the local directory from the remote device: +.. _mpremote_command_unmount: + +- **unmount** -- unmount the local directory from the remote device: .. code-block:: bash $ mpremote umount -Multiple commands can be specified and they will be run sequentially. + This happens automatically when ``mpremote`` terminates, but it can be used + in a sequence to unmount an earlier mount before subsequent command are run. + +.. _mpremote_command_romfs: + +- **romfs** -- manage ROMFS partitions on the device: + + .. code-block:: bash + + $ mpremote romfs + + ```` may be: + + - ``romfs query`` to list all the available ROMFS partitions and their size + - ``romfs [-o ] build `` to create a ROMFS image from the given + source directory; the default output file is the source appended by ``.romfs`` + - ``romfs [-p ] deploy `` to deploy a ROMFS image to the device; + will also create a temporary ROMFS image if the source is a directory + + The ``build`` and ``deploy`` sub-commands both support the ``-m``/``--mpy`` option + to automatically compile ``.py`` files to ``.mpy`` when creating the ROMFS image. + This option is enabled by default, but only works if the ``mpy_cross`` Python + package has been installed (eg via ``pip install mpy_cross``). If the package is + not installed then a warning is printed and ``.py`` files remain as is. Compiling + of ``.py`` files can be disabled with the ``--no-mpy`` option. + +.. _mpremote_command_rtc: + +- **rtc** -- set/get the device clock (RTC): + + .. code-block:: bash + + $ mpremote rtc + + This will query the device RTC for the current time and print it as a datetime + tuple. + + .. code-block:: bash + + $ mpremote rtc --set + + This will set the device RTC to the host PC's current time. + +.. _mpremote_command_sleep: + +- **sleep** -- sleep (delay) before executing the next command + + .. code-block:: bash + + $ mpremote sleep 0.5 + This will pause execution of the command sequence for the specified duration + in seconds, e.g. to wait for the device to do something. + +.. _mpremote_command_reset: + +- **reset** -- hard reset the device + + .. code-block:: bash + + $ mpremote reset + + **Note:** hard reset is equivalent to :func:`machine.reset`. + +.. _mpremote_command_bootloader: + +- **bootloader** enter the bootloader + + .. code-block:: bash + + $ mpremote bootloader + + This will make the device enter its bootloader. The bootloader is port- and + board-specific (e.g. DFU on stm32, UF2 on rp2040/Pico). + +.. _mpremote_reset: Auto connection and soft-reset ------------------------------ Connection and disconnection will be done automatically at the start and end of the execution of the tool, if such commands are not explicitly given. Automatic -connection will search for the first available USB serial device. If no action -is specified then the REPL will be entered. +connection will search for the first available USB serial device. Once connected to a device, ``mpremote`` will automatically soft-reset the device if needed. This clears the Python heap and restarts the interpreter, @@ -197,38 +457,60 @@ executed: ``mount``, ``eval``, ``exec``, ``run``, ``fs``. After doing a soft-reset for the first time, it will not be done again automatically, until a ``disconnect`` command is issued. -Auto soft-reset behaviour can be controlled by the ``resume`` command. And the -``soft-reset`` command can be used to perform an explicit soft reset. +Auto-soft-reset behaviour can be controlled by the ``resume`` command. This +might be useful to use the ``eval`` command to inspect the state of of the +device. The ``soft-reset`` command can be used to perform an explicit soft +reset in the middle of a sequence of commands. +.. _mpremote_shortcuts: Shortcuts --------- -Shortcuts can be defined using the macro system. Built-in shortcuts are:: +Shortcuts can be defined using the macro system. Built-in shortcuts are: -- ``devs``: list available devices (shortcut for ``connect list``) +- ``devs``: Alias for ``connect list`` -- ``a0``, ``a1``, ``a2``, ``a3``: connect to /dev/ttyACM? +- ``a0``, ``a1``, ``a2``, ``a3``: Aliases for ``connect /dev/ttyACMn`` -- ``u0``, ``u1``, ``u2``, ``u3``: connect to /dev/ttyUSB? +- ``u0``, ``u1``, ``u2``, ``u3``: Aliases for ``connect /dev/ttyUSBn`` -- ``c0``, ``c1``, ``c2``, ``c3``: connect to COM? +- ``c0``, ``c1``, ``c2``, ``c3``: Aliases for ``connect COMn`` -- ``cat``, ``ls``, ``cp``, ``rm``, ``mkdir``, ``rmdir``, ``touch``, ``df``: - filesystem commands +- ``cat``, ``edit``, ``ls``, ``cp``, ``rm``, ``mkdir``, ``rmdir``, ``touch``: Aliases for ``fs `` + +Additional shortcuts can be defined by in user-configuration files, which is +located at ``.config/mpremote/config.py``. This file should define a +dictionary named ``commands``. The keys of this dictionary are the shortcuts +and the values are either a string or a list-of-strings: + +.. code-block:: python3 + + "c33": "connect id:334D335C3138", + +The command ``c33`` is replaced by ``connect id:334D335C3138``. + +.. code-block:: python3 + + "test": ["mount", ".", "exec", "import test"], + +The command ``test`` is replaced by ``mount . exec "import test"``. + +Shortcuts can also accept arguments. For example: + +.. code-block:: python3 -- ``reset``: reset the device + "multiply x=4 y=7": "eval x*y", -- ``bootloader``: make the device enter its bootloader +Running ``mpremote times 3 7`` will set ``x`` and ``y`` as variables on the device, then evaluate the expression ``x*y``. -Any user configuration, including user-defined shortcuts, can be placed in the file -``.config/mpremote/config.py``. For example: +An example ``config.py`` might look like: .. code-block:: python3 commands = { - "c33": "connect id:334D335C3138", - "bl": "bootloader", + "c33": "connect id:334D335C3138", # Connect to a specific device by ID. + "bl": "bootloader", # Shorter alias for bootloader. "double x=4": "eval x*2", # x is an argument, with default 4 "wl_scan": ["exec", """ import network @@ -236,10 +518,16 @@ Any user configuration, including user-defined shortcuts, can be placed in the f wl.active(1) for ap in wl.scan(): print(ap) - """,], - "test": ["mount", ".", "exec", "import test"], + """,], # Print out nearby WiFi networks. + "wl_ipconfig": [ + "exec", + "import network; sta_if = network.WLAN(network.WLAN.IF_STA); print(sta_if.ipconfig('addr4'))", + """,], # Print ip address of station interface. + "test": ["mount", ".", "exec", "import test"], # Mount current directory and run test.py. + "demo": ["run", "path/to/demo.py"], # Execute demo.py on the device. } +.. _mpremote_examples: Examples -------- @@ -248,38 +536,212 @@ Examples mpremote +Connect to the first available device and implicitly run the ``repl`` command. + +.. code-block:: bash + mpremote a1 - mpremote connect /dev/ttyUSB0 repl +Connect to the device at ``/dev/ttyACM1`` (Linux) and implicitly run the +``repl`` command. See :ref:`shortcuts ` above. - mpremote ls +.. code-block:: bash + + mpremote c1 + +Connect to the device at ``COM1`` (Windows) and implicitly run the ``repl`` +command. See :ref:`shortcuts ` above. + +.. code-block:: bash + + mpremote connect /dev/ttyUSB0 + +Explicitly specify which device to connect to, and as above, implicitly run the +``repl`` command. + +.. code-block:: bash mpremote a1 ls +Connect to the device at ``/dev/ttyACM0`` and then run the ``ls`` command. + +It is equivalent to ``mpremote connect /dev/ttyACM1 fs ls``. + +.. code-block:: bash + mpremote exec "import micropython; micropython.mem_info()" +Run the specified Python command and display any output. This is equivalent to +typing the command at the REPL prompt. + +.. code-block:: bash + mpremote eval 1/2 eval 3/4 +Evaluate each expression in turn and print the results. + +.. code-block:: bash + + mpremote a0 eval 1/2 a1 eval 3/4 + +Evaluate ``1/2`` on the device at ``/dev/ttyACM0``, then ``3/4`` on the +device at ``/dev/ttyACM1``, printing each result. + +.. code-block:: bash + + mpremote resume exec "print_state_info()" soft-reset + +Connect to the device without triggering a :ref:`soft reset ` and +execute the ``print_state_info()`` function (e.g. to find out information about +the current program state), then trigger a soft reset. + +.. code-block:: bash + + mpremote reset sleep 0.5 bootloader + +Hard-reset the device, wait 500ms for it to become available, then enter the +bootloader. + +.. code-block:: bash + + mpremote cp utils/driver.py :utils/driver.py + run test.py + +Update the copy of utils/driver.py on the device, then execute the local +``test.py`` script on the device. ``test.py`` is never copied to the device +filesystem, rather it is run from RAM. + +.. code-block:: bash + + mpremote cp utils/driver.py :utils/driver.py + exec "import app" + +Update the copy of utils/driver.py on the device, then execute app.py on the +device. + +This is a common development workflow to update a single file and then re-start +your program. In this scenario, your ``main.py`` on the device would also do +``import app``. + +.. code-block:: bash + + mpremote cp utils/driver.py :utils/driver.py + soft-reset repl + +Update the copy of utils/driver.py on the device, then trigger a soft-reset to +restart your program, and then monitor the output via the ``repl`` command. + +.. code-block:: bash + + mpremote cp -r utils/ :utils/ + soft-reset repl + +Same as above, but update the entire utils directory first. + +.. code-block:: bash + mpremote mount . - mpremote mount . exec "import local_script" +Mount the current local directory at ``/remote`` on the device and starts a +``repl`` session which will use ``/remote`` as the working directory. - mpremote ls +.. code-block:: bash + + mpremote mount . exec "import demo" + +After mounting the current local directory, executes ``demo.py`` from the +mounted directory. + +.. code-block:: bash + + mpremote mount app run test.py + +After mounting the local directory ``app`` as ``/remote`` on the device, +executes the local ``test.py`` from the host's current directory without +copying it to the filesystem. + +.. code-block:: bash + + mpremote mount . repl --inject-code "import demo" + +After mounting the current local directory, executes ``demo.py`` from the +mounted directory each time ``Ctrl-J`` is pressed. + +You will first need to press ``Ctrl-D`` to reset the interpreter state +(which will preserve the mount) before pressing ``Ctrl-J`` to re-import +``demo.py``. + +.. code-block:: bash + + mpremote mount app repl --inject-file demo.py + +Same as above, but executes the contents of the local file demo.py at the REPL +every time ``Ctrl-K`` is pressed. As above, use Ctrl-D to reset the interpreter +state first. + +.. code-block:: bash mpremote cat boot.py +Displays the contents of ``boot.py`` on the device. + +.. code-block:: bash + + mpremote edit utils/driver.py + +Edit ``utils/driver.py`` on the device using your local ``$EDITOR``. + +.. code-block:: bash + mpremote cp :main.py . +Copy ``main.py`` from the device to the local directory. + +.. code-block:: bash + mpremote cp main.py : +Copy ``main.py`` from the local directory to the device. + +.. code-block:: bash + mpremote cp :a.py :b.py +Copy ``a.py`` on the device to ``b.py`` on the device. + +.. code-block:: bash + mpremote cp -r dir/ : +Recursively copy the local directory ``dir`` to the remote device. + +.. code-block:: bash + mpremote cp a.py b.py : + repl +Copy ``a.py`` and ``b.py`` from the local directory to the device, then run the +``repl`` command. + +.. code-block:: bash + mpremote mip install aioble +Install the ``aioble`` package from :term:`micropython-lib` to the device. +See :ref:`packages`. + +.. code-block:: bash + mpremote mip install github:org/repo@branch +Install the package from the specified branch at org/repo on GitHub to the +device. See :ref:`packages`. + +.. code-block:: bash + + mpremote mip install gitlab:org/repo@branch + +Install the package from the specified branch at org/repo on GitLab to the +device. See :ref:`packages`. + +.. code-block:: bash + mpremote mip install --target /flash/third-party functools + +Install the ``functools`` package from :term:`micropython-lib` to the +``/flash/third-party`` directory on the device. See :ref:`packages`. diff --git a/docs/reference/mpyfiles.rst b/docs/reference/mpyfiles.rst index d93a86383e98c..be0114701aea7 100644 --- a/docs/reference/mpyfiles.rst +++ b/docs/reference/mpyfiles.rst @@ -58,7 +58,7 @@ If importing an .mpy file fails then try the following: sys_mpy = sys.implementation._mpy arch = [None, 'x86', 'x64', 'armv6', 'armv6m', 'armv7m', 'armv7em', 'armv7emsp', 'armv7emdp', - 'xtensa', 'xtensawin'][sys_mpy >> 10] + 'xtensa', 'xtensawin', 'rv32imc'][sys_mpy >> 10] print('mpy version:', sys_mpy & 0xff) print('mpy sub-version:', sys_mpy >> 8 & 3) print('mpy flags:', end='') @@ -86,7 +86,10 @@ and .mpy version. =================== ============ MicroPython release .mpy version =================== ============ -v1.19 and up 6 +v1.23.0 and up 6.3 +v1.22.x 6.2 +v1.20 - v1.21.0 6.1 +v1.19.x 6 v1.12 - v1.18 5 v1.11 4 v1.9.3 - v1.10 3 @@ -100,6 +103,9 @@ MicroPython repository at which the .mpy version was changed. =================== ======================================== .mpy version change Git commit =================== ======================================== +6.2 to 6.3 bdbc869f9ea200c0d28b2bc7bfb60acd9d884e1b +6.1 to 6.2 6967ff3c581a66f73e9f3d78975f47528db39980 +6 to 6.1 d94141e1473aebae0d3c63aeaa8397651ad6fa01 5 to 6 f2040bfc7ee033e48acef9f289790f3b4e6b74e5 4 to 5 5716c5cf65e9b2cb46c2906f40302401bdd27517 3 to 4 9a5f92ea72754c01cc03e5efcdfe94021120531e @@ -146,8 +152,8 @@ The .mpy header is: size field ====== ================================ byte value 0x4d (ASCII 'M') -byte .mpy version number -byte feature flags +byte .mpy major version number +byte native arch and minor version number (was feature flags in older versions) byte number of bits in a small int ====== ================================ diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index 1ddbecb582b4a..5b5f626d45232 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -7,7 +7,7 @@ Installing packages with ``mip`` -------------------------------- Network-capable boards include the ``mip`` module, which can install packages -from :term:`micropython-lib` and from third-party sites (including GitHub). +from :term:`micropython-lib` and from third-party sites (including GitHub, GitLab). ``mip`` ("mip installs packages") is similar in concept to Python's ``pip`` tool, however it does not use the PyPI index, rather it uses :term:`micropython-lib` @@ -38,24 +38,28 @@ install third-party libraries. The simplest way is to download a file directly:: When installing a file directly, the ``target`` argument is still supported to set the destination path, but ``mpy`` and ``version`` are ignored. -The URL can also start with ``github:`` as a simple way of pointing to content -hosted on GitHub:: +The URL can also start with ``github:`` or ``gitlab:`` as a simple way of pointing to content +hosted on GitHub or GitLab:: >>> mip.install("github:org/repo/path/foo.py") # Uses default branch >>> mip.install("github:org/repo/path/foo.py", version="branch-or-tag") # Optionally specify the branch or tag + >>> mip.install("gitlab:org/repo/path/foo.py") # Uses default branch + >>> mip.install("gitlab:org/repo/path/foo.py", version="branch-or-tag") # Optionally specify the branch or tag More sophisticated packages (i.e. with more than one file, or with dependencies) can be downloaded by specifying the path to their ``package.json``. >>> mip.install("http://example.com/x/package.json") >>> mip.install("github:org/user/path/package.json") + >>> mip.install("gitlab:org/user/path/package.json") If no json file is specified, then "package.json" is implicitly added:: >>> mip.install("http://example.com/x/") - >>> mip.install("github:org/repo") + >>> mip.install("github:org/repo") # Uses default branch of that repo >>> mip.install("github:org/repo", version="branch-or-tag") - + >>> mip.install("gitlab:org/repo") # Uses default branch of that repo + >>> mip.install("gitlab:org/repo", version="branch-or-tag") Using ``mip`` on the Unix port ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -65,9 +69,9 @@ On the Unix port, ``mip`` can be used at the REPL as above, and also by using `` $ ./micropython -m mip install pkgname-or-url $ ./micropython -m mip install pkgname-or-url@version -The ``--target=path``, ``--no-mpy``, and ``--index`` arguments can be set:: +The ``--target path``, ``--no-mpy``, and ``--index`` arguments can be set:: - $ ./micropython -m mip install --target=third-party pkgname + $ ./micropython -m mip install --target third-party pkgname $ ./micropython -m mip install --no-mpy pkgname $ ./micropython -m mip install --index https://host/pi pkgname @@ -83,6 +87,8 @@ can be used from a host PC to install packages to a locally connected device $ mpremote mip install http://example.com/x/y/foo.py $ mpremote mip install github:org/repo $ mpremote mip install github:org/repo@branch-or-tag + $ mpremote mip install gitlab:org/repo + $ mpremote mip install gitlab:org/repo@branch-or-tag The ``--target=path``, ``--no-mpy``, and ``--index`` arguments can be set:: @@ -90,6 +96,18 @@ The ``--target=path``, ``--no-mpy``, and ``--index`` arguments can be set:: $ mpremote mip install --no-mpy pkgname $ mpremote mip install --index https://host/pi pkgname +:term:`mpremote` can also install packages from files stored on the host's local +filesystem:: + + $ mpremote mip install path/to/pkg.py + $ mpremote mip install path/to/app/package.json + $ mpremote mip install \\path\\to\\pkg.py + +This is especially useful for testing packages during development and for +installing packages from local clones of GitHub repositories. Note that URLs in +``package.json`` files must use forward slashes ("/") as directory separators, +even on Windows, so that they are compatible with installing from the web. + Installing packages manually ---------------------------- @@ -108,26 +126,54 @@ https://github.com/micropython/micropython-lib for more information. To write a "self-hosted" package that can be downloaded by ``mip`` or ``mpremote``, you need a static webserver (or GitHub) to host either a -single .py file, or a package.json file alongside your .py files. +single .py file, or a ``package.json`` file alongside your .py files. + +An example ``mlx90640`` library hosted on GitHub could be installed with:: + + $ mpremote mip install github:org/micropython-mlx90640 -A typical package.json for an example ``mlx90640`` library looks like:: +The layout for the package on GitHub might look like:: + + https://github.com/org/micropython-mlx90640/ + package.json + mlx90640/ + __init__.py + utils.py + +The ``package.json`` specifies the location of files to be installed and other +dependencies:: { "urls": [ - ["mlx90640/__init__.py", "github:org/micropython-mlx90640/mlx90640/__init__.py"], - ["mlx90640/utils.py", "github:org/micropython-mlx90640/mlx90640/utils.py"] + ["mlx90640/__init__.py", "mlx90640/__init__.py"], + ["mlx90640/utils.py", "mlx90640/utils.py"] ], "deps": [ ["collections-defaultdict", "latest"], - ["os-path", "latest"] + ["os-path", "latest"], + ["github:org/micropython-additions", "main"], + ["gitlab:org/micropython-otheradditions", "main"] ], "version": "0.2" } -This includes two files, hosted at a GitHub repo named -``org/micropython-mlx90640``, which install into the ``mlx90640`` directory on -the device. It depends on ``collections-defaultdict`` and ``os-path`` which will -be installed automatically. +The ``urls`` list specifies the files to be installed according to:: + + "urls": [ + [destination_path, source_url] + ... + +where ``destination_path`` is the location and name of the file to be installed +on the device and ``source_url`` is the URL of the file to be installed. The +source URL would usually be specified relative to the directory containing the +``package.json`` file, but can also be an absolute URL, eg:: + + ["mlx90640/utils.py", "github:org/micropython-mlx90640/mlx90640/utils.py"] + +The package depends on ``collections-defaultdict`` and ``os-path`` which will +be installed automatically from the :term:`micropython-lib`. The third +dependency installs the content as defined by the ``package.json`` file of the +``main`` branch of the GitHub repo ``org/micropython-additions``. Freezing packages ----------------- diff --git a/docs/reference/pyboard.py.rst b/docs/reference/pyboard.py.rst index a06ffdcd8fa96..13fc6b7a7a49d 100644 --- a/docs/reference/pyboard.py.rst +++ b/docs/reference/pyboard.py.rst @@ -120,9 +120,8 @@ Some more examples:: # 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 : + # Copy three files to the device, keeping their names. + $ pyboard.py --device /dev/ttyACM0 -f cp main.py app.py foo.py : # Remove a file from the device. $ pyboard.py --device /dev/ttyACM0 -f rm util.py diff --git a/docs/reference/repl.rst b/docs/reference/repl.rst index 55f76ee1a03b9..2c019350f7e2a 100644 --- a/docs/reference/repl.rst +++ b/docs/reference/repl.rst @@ -143,10 +143,12 @@ 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. +.. _repl_soft_reset: + Soft reset ---------- -A soft reset will reset the python interpreter, but tries not to reset the +A :ref:`soft_reset` will reset the python interpreter, but tries not to reset the method by which you're connected to the MicroPython board (USB-serial, or Wifi). You can perform a soft reset from the REPL by pressing Ctrl-D, or from your python @@ -182,6 +184,9 @@ variables no longer exist: ['__name__', 'pyb'] >>> +For more information about reset types and the startup process, see +:doc:`/reference/reset_boot`. + The special variable _ (underscore) ----------------------------------- @@ -196,6 +201,8 @@ So you can use the underscore to save the result in a variable. For example: 15 >>> +.. _raw_repl: + Raw mode and raw-paste mode --------------------------- @@ -206,7 +213,7 @@ echo turned off, and with optional flow control. Raw mode is entered using Ctrl-A. You then send your python code, followed by a Ctrl-D. The Ctrl-D will be acknowledged by 'OK' and then the python code will be compiled and executed. Any output (or errors) will be sent back. Entering -Ctrl-B will leave raw mode and return the the regular (aka friendly) REPL. +Ctrl-B will leave raw mode and return the regular (aka friendly) REPL. Raw-paste mode is an additional mode within the raw REPL that includes flow control, and which compiles code as it receives it. This makes it more robust for high-speed diff --git a/docs/reference/reset_boot.rst b/docs/reference/reset_boot.rst new file mode 100644 index 0000000000000..4772d02dd1e32 --- /dev/null +++ b/docs/reference/reset_boot.rst @@ -0,0 +1,262 @@ +Reset and Boot Sequence +======================= + +A device running MicroPython follows a particular boot sequence to start up and +initialise itself after a reset. + +.. _hard_reset: + +Hard reset +---------- + +Booting from hard reset is what happens when a board is first powered up, a cold +boot. This is a complete reset of the MCU hardware. + +The MicroPython port code initialises all essential hardware (including embedded +clocks and power regulators, internal serial UART, etc), and then starts the +MicroPython environment. Existing :doc:`RTC ` +configuration may be retained after a hard reset, but all other hardware state +is cleared. + +The same hard reset boot sequence can be triggered by a number of events such as: + +- Python code executing :func:`machine.reset()`. +- User presses a physical Reset button on the board (where applicable). +- Waking from deep sleep (on most ports). +- MCU hardware watchdog reset. +- MCU hardware brown out detector. + +The details of hardware-specific reset triggers depend on the port and +associated hardware. The :func:`machine.reset_cause()` function can be used to +further determine the cause of a reset. + +.. _soft_reset: + +Soft Reset +---------- + +When MicroPython is already running, it's possible to trigger a soft reset by +:ref:`typing Ctrl-D in the REPL ` or executing +:func:`machine.soft_reset()`. + +A soft reset clears the Python interpreter, frees all Python memory, and starts +the MicroPython environment again. + +State which is cleared by a soft reset includes: + +- All Python variables, objects, imported modules, etc. +- Most peripherals configured using the :doc:`machine module + `. There are very limited exceptions, for example + :doc:`machine.Pin ` modes (i.e. if a pin is input or + output, high or low) are not reset on most ports. More advanced configuration + such as :func:`Pin.irq()` is always reset. +- Bluetooth. +- Network sockets. Open TCP sockets are closed cleanly with respect to the other party. +- Open files. The filesystem is left in a valid state. + +Some system state remains the same after a soft reset, including: + +- Any existing network connections (Ethernet, Wi-Fi, etc) remain active at the + IP Network layer. Querying the :doc:`network interface from code + ` may indicate the network interface is still active with a + configured IP address, etc. +- An active :doc:`REPL ` appears continuous before and after soft reset, + except in some unusual cases: + + * If the :ref:`machine.USBDevice ` class has been used to + create a custom USB interface then any built-in USB serial device will + appear to disconnect and reconnect as the custom USB interface must be + cleared during reset. + * A serial UART REPL will restore its default hardware configuration (baud + rate, etc). + +- CPU clock speed is usually not changed by a soft reset. +- :doc:`RTC ` configuration (i.e. setting of the current + time) is not changed by soft reset. + +.. _boot_sequence: + +Boot Sequence +------------- + +When MicroPython boots following either a hard or soft reset, it follows this +boot sequence in order: + +_boot.py +^^^^^^^^ + +This is an internal script :doc:`frozen into the MicroPython firmware +`. It is provided by MicroPython on many ports to do essential +initialisation. + +For example, on most ports ``_boot.py`` will detect the first boot of a new +device and format the :doc:`internal flash filesystem ` ready for +use. + +Unless you're creating a custom MicroPython build or adding a new port then you +probably don't need to worry about ``_boot.py``. It's best not to change the +contents unless you really know what you're doing. + +.. _boot.py: + +boot.py +^^^^^^^ + +A file named ``boot.py`` can be copied to the board's internal :ref:`filesystem +` using :doc:`mpremote `. + +If ``boot.py`` is found then it is executed. You can add code in ``boot.py`` to +perform custom one-off initialisation (for example, to configure the board's +hardware). + +A common practice is to configure a board's network connection in ``boot.py`` so +that it's always available after reset for use with the :doc:`REPL `, +:doc:`mpremote `, etc. + +.. warning:: boot.py should always exit and not run indefinitely. + + Depending on the port, some hardware initialisation is delayed until after + ``boot.py`` exits. This includes initialising USB on the stm32 port and all + ports which support :ref:`machine.USBDevice `. On these + ports, output printed from ``boot.py`` may not be visible on the built-in USB + serial port until after ``boot.py`` finishes running. + + The purpose of this late initialisation is so that it's possible to + pre-configure particular hardware in ``boot.py``, and then have it start with + the correct configuration. + +.. note:: It is sometimes simpler to not have a ``boot.py`` file and place any + initialisation code at the top of ``main.py`` instead. + +.. _main.py: + +main.py +^^^^^^^ + +Similar to ``boot.py``, a file named ``main.py`` can be copied to the board's +internal :ref:`filesystem `. If found then it is executed next in the +startup process. + +``main.py`` is for any Python code that you want to run each time your device +starts. + +Some tips for ``main.py`` usage: + +- ``main.py`` doesn't have to exit, feel free to put an infinite ``while + True`` loop in there. +- For complex Python applications then you don't need to put all your + code in ``main.py``. ``main.py`` can be a simple entry point that + imports your application and starts execution:: + + import my_app + my_app.main() + + This can help keep the structure of your application clear. It also makes + it easy to install multiple applications on a board and switch among them. +- It's good practice when writing robust apps to wrap code in ``main.py`` with an + exception handler to take appropriate action if the code crashes. For example:: + + import machine, sys + import my_app + try: + my_app.main() + except Exception as e: + print("Fatal error in main:") + sys.print_exception(e) + + # Following a normal Exception or main() exiting, reset the board. + # Following a non-Exception error such as KeyboardInterrupt (Ctrl-C), + # this code will drop to a REPL. Place machine.reset() in a finally + # block to always reset, instead. + machine.reset() + + Otherwise MicroPython will drop to the REPL following any crash or if main + exits (see below). + +- Any global variables that were set in ``boot.py`` will still be set in the + global context of ``main.py``. + +- To fully optimise flash usage and memory consumption, you can copy + :doc:`pre-compiled ` ``main.mpy`` and/or ``boot.mpy`` files to the + filesystem, or even :doc:`freeze ` them into the firmware build + instead. +- ``main.py`` execution is skipped when a soft reset is initiated from :ref:`raw + REPL mode ` (for example, when :doc:`mpremote ` or another + program is interacting directly with MicroPython). + +Interactive Interpreter (REPL) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If ``main.py`` is not found, or if ``main.py`` exits, then :doc:`repl` +will start immediately. + +.. note:: Even if ``main.py`` contains an infinite loop, typing Ctrl-C on the + REPL serial port will inject a `KeyboardInterrupt`. If no exception + handler catches it then ``main.py`` will exit and the REPL will start. + +Any global variables that were set in ``boot.py`` and ``main.py`` will still be +set in the global context of the REPL. + +The REPL continues executing until Python code triggers a hard or soft reset. + +.. _soft_bricking: + +Soft Bricking (failure to boot) +--------------------------------- + +It is rare but possible for MicroPython to become unresponsive during startup, a +state sometimes called "soft bricked". For example: + +- If ``boot.py`` execution gets stuck and the native USB serial port + never initialises. +- If Python code reconfigures the REPL interface, making it inaccessible. + +Rest assured, recovery is possible! + +KeyboardInterrupt +^^^^^^^^^^^^^^^^^ + +In many cases, opening the REPL serial port and typing ``Ctrl-C`` will inject +`KeyboardInterrupt` and may cause the running script to exit and a REPL to +start. From the REPL, you can use :func:`os.remove()` to remove the misbehaving +Python file:: + + import os + os.remove('main.py') + +To confirm which files are still present in the internal filesystem:: + + import os + os.listdir() + +Safe Mode and Factory Reset +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you're unable to easily access the REPL then you may need to perform one of +two processes: + +1. "Safe mode" boot, which skips ``boot.py`` and ``main.py`` and immediately + starts a REPL, allowing you to clean up. This is only supported on some ports. +2. Factory Reset to erase the entire contents of the flash filesystem. This may + also be necessary if the internal flash filesystem has become corrupted + somehow. + +The specific process(es) are different on each port: + +- :doc:`pyboard and stm32 port instructions ` +- :doc:`esp32 port instructions ` +- :doc:`renesas-ra port instructions ` +- :doc:`rp2 port instructions ` +- :doc:`wipy port instructions ` + +For ports without specific instructions linked above, the factory reset process +involves erasing the board's entire flash and then flashing MicroPython again +from scratch. Usually this will involve the same tool(s) that were originally +used to install MicroPython. Consult the installation docs for your board, or +ask on the `GitHub Discussions`_ if you're not sure. + +.. warning:: Re-flashing the MicroPython firmware without erasing the entire + flash first will usually not recover from soft bricking, as a + firmware update usually preserves the contents of the filesystem. + +.. _GitHub Discussions: https://github.com/orgs/micropython/discussions diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index 834a53b0a7d72..64fd9df6c058a 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -57,6 +57,8 @@ and used in various methods. This is covered in further detail :ref:`Controlling garbage collection ` below. +.. _speed_buffers: + Buffers ~~~~~~~ @@ -69,6 +71,13 @@ 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. +Some useful classes for creating reusable buffer objects: + +- :class:`bytearray` +- :mod:`array` (:ref:`discussed below`) +- :class:`io.StringIO` and :class:`io.BytesIO` +- :class:`micropython.RingIO` + Floating point ~~~~~~~~~~~~~~ @@ -80,15 +89,20 @@ point to sections of the code where performance is not paramount. For example, capture ADC readings as integers values to an array in one quick go, and only then convert them to floating-point numbers for signal processing. +.. _speed_arrays: + Arrays ~~~~~~ Consider the use of the various types of array classes as an alternative to lists. -The `array` module supports various element types with 8-bit elements supported +The :mod:`array` module supports various element types with 8-bit elements supported by Python's built in `bytes` and `bytearray` classes. These data structures all store elements in contiguous memory locations. Once again to avoid memory allocation in critical code these should be pre-allocated and passed as arguments or as bound objects. +Memoryviews +~~~~~~~~~~~ + When passing slices of objects such as `bytearray` instances, Python creates a copy which involves allocation of the size proportional to the size of slice. This can be alleviated using a `memoryview` object. The `memoryview` itself @@ -118,6 +132,23 @@ of buffer and fills in entire buffer. What if you need to put data in the middle of existing buffer? Just create a memoryview into the needed section of buffer and pass it to ``readinto()``. +Strings vs Bytes +~~~~~~~~~~~~~~~~ + +MicroPython uses :ref:`string interning ` to save space when there are +multiple identical strings. Each time a new string is allocated at runtime (for +example, when two other strings are concatenated), MicroPython checks whether +the new string can be interned to save RAM. + +If you have code which performs performance-critical string operations then +consider using :class:`bytes` objects and literals (i.e. ``b"abc"``). This skips +the interning check, and can be several times faster than performing the same +operations with string objects. + +.. note:: The fastest performance will always be achieved by avoiding new object + creation entirely, for example with a reusable :ref:`buffer as described + above`. + Identifying the slowest section of code --------------------------------------- @@ -188,7 +219,7 @@ process known as garbage collection reclaims the memory used by these redundant objects and the allocation is then tried again - a process which can take several milliseconds. -There may be benefits in pre-empting this by periodically issuing `gc.collect()`. +There may be benefits in preempting this by periodically issuing `gc.collect()`. Firstly doing a collection before it is actually required is quicker - typically on the order of 1ms if done frequently. Secondly you can determine the point in code where this time is used rather than have a longer delay occur at random points, @@ -247,7 +278,6 @@ Python will interpret the result as 2**32 -1 rather than as -1. In addition to the restrictions imposed by the native emitter the following constraints apply: -* Functions may have up to four arguments. * Default argument values are not permitted. * Floating point may be used but is not optimised. diff --git a/docs/renesas-ra/general.rst b/docs/renesas-ra/general.rst index c8eea53f8bcef..59bc2ef2062ee 100644 --- a/docs/renesas-ra/general.rst +++ b/docs/renesas-ra/general.rst @@ -18,7 +18,7 @@ The following boards are officially supported. * RA4M1-CLICKER -For the manual and other references for the board and RA Family MCU, please refer to the web page: `EK-RA4M1 CLICKER `_ +For the manual and other references for the board and RA Family MCU, please refer to the web page: `RA4M1 CLICKER `_ * EK-RA6M2 diff --git a/docs/renesas-ra/quickref.rst b/docs/renesas-ra/quickref.rst index 47b49575bd5be..b5283707fc8f0 100644 --- a/docs/renesas-ra/quickref.rst +++ b/docs/renesas-ra/quickref.rst @@ -206,8 +206,9 @@ See :ref:`machine.RTC ` :: from machine import RTC rtc = RTC() - rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time - # time, eg 2017/8/23 1:12:48 + rtc.datetime((2017, 8, 23, 0, 1, 12, 48, 0)) # set a specific date and + # time, eg. 2017/8/23 1:12:48 + # the day-of-week value is ignored rtc.datetime() # get date and time Following functions are not supported at the present:: @@ -387,15 +388,15 @@ SDCard The frozen sdcard driver (drivers/sdcard/sdcard.py) is available by connecting microSD card device to hardware SPI0 pins.:: from machine import Pin, SPI - import os, sdcard + import os, vfs, sdcard spi = SPI(0, baudrate=500000) cs = Pin.cpu.P103 sd = sdcard.SDCard(spi, cs) - os.mount(sd, '/sd') + vfs.mount(sd, '/sd') os.listdir('/') os.chdir('/sd') - os.umount('/sd') + vfs.umount('/sd') OneWire driver -------------- diff --git a/docs/renesas-ra/tutorial/intro.rst b/docs/renesas-ra/tutorial/intro.rst index 6c41f43971cdf..6003e71575538 100644 --- a/docs/renesas-ra/tutorial/intro.rst +++ b/docs/renesas-ra/tutorial/intro.rst @@ -62,6 +62,6 @@ Access the MicroPython REPL (the Python prompt) via USB serial or UART with 1152 You can see the MicroPython REPL prompt like below:: - MicroPython v1.18-293-g339aa09b8-dirty on 2022-03-26; RA6M2_EK with RA6M2 + MicroPython v1.20.0 on 2023-04-27; EK-RA6M2 with RA6M2 Type "help()" for more information. >>> diff --git a/docs/renesas-ra/tutorial/program_in_flash.rst b/docs/renesas-ra/tutorial/program_in_flash.rst index 99a7a3839dd46..985ce6c7fe661 100644 --- a/docs/renesas-ra/tutorial/program_in_flash.rst +++ b/docs/renesas-ra/tutorial/program_in_flash.rst @@ -28,6 +28,8 @@ As the factory setting, following 2 files are created in the file system: * boot.py : executed first when the system starts * main.py : executed after boot.py completes +See :doc:`/reference/reset_boot` for more information. + Write a program in the internal file system ------------------------------------------- diff --git a/docs/renesas-ra/tutorial/reset.rst b/docs/renesas-ra/tutorial/reset.rst index de5f4db91b3e0..8799796479560 100644 --- a/docs/renesas-ra/tutorial/reset.rst +++ b/docs/renesas-ra/tutorial/reset.rst @@ -20,6 +20,8 @@ If that isn't working you can perform a hard reset (turn-it-off-and-on-again) by pressing the RESET button. This will end your session, disconnecting whatever program (PuTTY, screen, etc) that you used to connect to the board. +For more details, see :doc:`/reference/reset_boot`. + boot mode --------- @@ -29,7 +31,9 @@ There are 3 boot modes: * safe boot mode * factory filesystem boot mode -boot.py and main.py are executed on "normal boot mode". +boot.py and main.py are executed on "normal boot mode". See :ref:`boot_sequence`. + +The other modes can be used to recover from :ref:`soft_bricking`: boot.py and main.py are *NOT* executed on "safe boot mode". @@ -46,16 +50,4 @@ on the board: You have created the main.py which executes LED1 blinking in the previous part. If you change the boot mode to safe boot mode, the MicroPython starts without -the execution of main.py. Then you can remove the main.py by following -command or change the boot mode to factory file system boot mode.:: - - import os - os.remove('main.py') - -or change the boot mode to factory file system boot mode. - -You can confirm that the initialized file system that there are only boot.py and main.py files.:: - - import os - os.listdir() - +the execution of main.py. diff --git a/docs/renesas-ra/tutorial/using_peripheral.rst b/docs/renesas-ra/tutorial/using_peripheral.rst index c50181b3d681a..7296d8b3304f7 100644 --- a/docs/renesas-ra/tutorial/using_peripheral.rst +++ b/docs/renesas-ra/tutorial/using_peripheral.rst @@ -12,9 +12,8 @@ To list supported modules, please enter:: help('modules') -Especially `machine` module and class :ref:`machine.Pin ` are very important for using -peripherals. Note that prefix 'u' is added to the module for MicroPython, -so you can see "umachine" in the list but you can use it like "import machine". +Especially `machine` module and class :ref:`machine.Pin ` are very +important for using peripherals. Using "from machine import Pin", Pin name is available corresponding to the RA MCU's pin name which are Pin.cpu.P000 and 'P000'. diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000000000..824e9799c773a --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +sphinx~=7.2.6 +sphinxcontrib.jquery==4.1 diff --git a/docs/rp2/general.rst b/docs/rp2/general.rst index 6a8958d172a84..05b44f051ee31 100644 --- a/docs/rp2/general.rst +++ b/docs/rp2/general.rst @@ -30,7 +30,7 @@ The peripherals include: * 2 UARTs * 2 SPI controllers -* 2 I2C contollers +* 2 I2C controllers * 16 PWM channels * USB 1.1 controller * 8 PIO state machines diff --git a/docs/rp2/quickref.rst b/docs/rp2/quickref.rst index 430c130c6e865..23071d77215d5 100644 --- a/docs/rp2/quickref.rst +++ b/docs/rp2/quickref.rst @@ -31,17 +31,81 @@ The MicroPython REPL is accessed via the USB serial port. Tab-completion is usef find out what methods an object has. Paste mode (ctrl-E) is useful to paste a large slab of Python code into the REPL. -The :mod:`machine` module:: +The :mod:`machine` module: + +machine.freq() allows to change the MCU frequency and control the peripheral +frequency for UART and SPI. Usage:: + + machine.freq(MCU_frequency[, peripheral_frequency=48_000_000]) + +The MCU frequency can be set in a range from less than 48 MHz to about 250MHz. +The default at boot time is 125 MHz. The peripheral frequency must be either +48 MHz or identical to the MCU frequency, with 48 MHz as the default. +If the peripheral frequency is changed, any already existing instance of +UART and SPI will change it's baud rate and may have to be re-configured:: import machine machine.freq() # get the current frequency of the CPU - machine.freq(240000000) # set the CPU frequency to 240 MHz + machine.freq(240000000) # set the CPU frequency to 240 MHz and keep + # the UART frequency at 48MHz + machine.freq(125000000, 125000000) # set the CPU and UART frequency to 125 MHz The :mod:`rp2` module:: import rp2 +Networking +---------- + +WLAN +^^^^ + +.. note:: + This section applies only to devices that include WiFi support, such as the `Pico W`_ and `Pico 2 W`_. + +The :class:`network.WLAN` class in the :mod:`network` module:: + + import network + + wlan = network.WLAN() # create station interface (the default, see below for an access point interface) + wlan.active(True) # activate the interface + wlan.scan() # scan for access points + wlan.isconnected() # check if the station is connected to an AP + wlan.connect('ssid', 'key') # connect to an AP + wlan.config('mac') # get the interface's MAC address + wlan.ipconfig('addr4') # get the interface's IPv4 addresses + + ap = network.WLAN(network.WLAN.IF_AP) # create access-point interface + ap.config(ssid='RP2-AP') # set the SSID 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:: + + def do_connect(): + import machine, network + wlan = network.WLAN() + wlan.active(True) + if not wlan.isconnected(): + print('connecting to network...') + wlan.connect('ssid', 'key') + while not wlan.isconnected(): + machine.idle() + print('network config:', wlan.ipconfig('addr4')) + +Once the network is established the :mod:`socket ` module can be used +to create and use TCP/UDP sockets as usual, and the ``requests`` module for +convenient HTTP requests. + +After a call to ``wlan.connect()``, the device will by default retry to connect +**forever**, even when the authentication failed or no AP is in range. +``wlan.status()`` will return ``network.STAT_CONNECTING`` in this state until a +connection succeeds or the interface gets disabled. + +.. _Pico W: https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#picow-technical-specification +.. _Pico 2 W: https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#pico2w-technical-specification + Delay and timing ---------------- @@ -96,7 +160,7 @@ Programmable IO (PIO) --------------------- PIO is useful to build low-level IO interfaces from scratch. See the :mod:`rp2` module -for detailed explaination of the assembly instructions. +for detailed explanation of the assembly instructions. Example using PIO to blink an LED at 1Hz:: @@ -146,19 +210,30 @@ See :ref:`machine.UART `. :: PWM (pulse width modulation) ---------------------------- -There are 8 independent channels each of which have 2 outputs making it 16 -PWM channels in total which can be clocked from 7Hz to 125Mhz. +There are 8 independent PWM generators called slices, which each have two +channels making it 16 PWM channels in total which can be clocked from +8Hz to 62.5Mhz at a machine.freq() of 125Mhz. The two channels of a +slice run at the same frequency, but can have a different duty rate. +The two channels are usually assigned to adjacent GPIO pin pairs with +even/odd numbers. So GPIO0 and GPIO1 are at slice 0, GPIO2 and GPIO3 +are at slice 1, and so on. A certain channel can be assigned to +different GPIO pins (see Pinout). For instance slice 0, channel A can be assigned +to both GPIO0 and GPIO16. Use the ``machine.PWM`` class:: from machine import Pin, PWM - pwm0 = PWM(Pin(0)) # create PWM object from a pin - pwm0.freq() # get current frequency - pwm0.freq(1000) # set frequency - pwm0.duty_u16() # get current duty cycle, range 0-65535 - pwm0.duty_u16(200) # set duty cycle, range 0-65535 - pwm0.deinit() # turn off PWM on the pin + # create PWM object from a pin and set the frequency of slice 0 + # and duty cycle for channel A + pwm0 = PWM(Pin(0), freq=2000, duty_u16=32768) + pwm0.freq() # get the current frequency of slice 0 + pwm0.freq(1000) # set/change the frequency of slice 0 + pwm0.duty_u16() # get the current duty cycle of channel A, range 0-65535 + pwm0.duty_u16(200) # set the duty cycle of channel A, range 0-65535 + pwm0.duty_u16(0) # stop the output at channel A + print(pwm0) # show the properties of the PWM object. + pwm0.deinit() # turn off PWM of slice 0, stopping channels A and B ADC (analog to digital conversion) ---------------------------------- @@ -176,6 +251,14 @@ Use the :ref:`machine.ADC ` class:: adc = ADC(Pin(26)) # create ADC object on ADC pin adc.read_u16() # read value, 0-65535 across voltage range 0.0v - 3.3v +The argument of the constructor ADC specifies either a Pin by number, name of as +Pin object, or a channel number in the range 0 - 3 or ADC.CORE_TEMP for the +internal temperature sensor. If a pin is specified, +the pin is initialized in high-Z mode. If a channel number is used, the pin +is not initialized and configuring is left to the user code. After hard reset, +RP2040 pins operate in current sink mode at about 60µA. If the pin is not +otherwise configured, that may lead to wrong ADC readings. + Software SPI bus ---------------- @@ -278,8 +361,9 @@ See :ref:`machine.RTC ` :: from machine import RTC rtc = RTC() - rtc.datetime((2017, 8, 23, 2, 12, 48, 0, 0)) # set a specific date and + rtc.datetime((2017, 8, 23, 0, 1, 12, 48, 0)) # set a specific date and # time, eg. 2017/8/23 1:12:48 + # the day-of-week value is ignored rtc.datetime() # get date and time WDT (Watchdog timer) diff --git a/docs/rp2/tutorial/intro.rst b/docs/rp2/tutorial/intro.rst index 69c3e6b0a54ae..2d2990105dba0 100644 --- a/docs/rp2/tutorial/intro.rst +++ b/docs/rp2/tutorial/intro.rst @@ -8,4 +8,5 @@ Let's get started! .. toctree:: :maxdepth: 1 + reset.rst pio.rst diff --git a/docs/rp2/tutorial/reset.rst b/docs/rp2/tutorial/reset.rst new file mode 100644 index 0000000000000..3c296ec46ee18 --- /dev/null +++ b/docs/rp2/tutorial/reset.rst @@ -0,0 +1,18 @@ +Factory reset +============= + +If something unexpected happens and your RP2xxx-based board no longer boots +MicroPython, then you may have to factory reset it. For more details, see +:ref:`soft_bricking`. + +Factory resetting the MicroPython rp2 port involves fully erasing the flash and +resetting the flash memory, so you will need to re-flash the MicroPython +firmware afterwards and copy any Python files to the filesystem again. + +1. Follow the instructions on the Raspberry Pi website for `resetting flash + memory`_. +2. Copy the MicroPython .uf2 firmware file to your board. If needed, this file + can be found on the `MicroPython downloads page`_. + +.. _resetting flash memory: https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#resetting-flash-memory +.. _MicroPython downloads page: https://micropython.org/download/?port=rp2 diff --git a/docs/samd/pinout.rst b/docs/samd/pinout.rst index 46d9d7a29d1b1..3945e2bf2ff1c 100644 --- a/docs/samd/pinout.rst +++ b/docs/samd/pinout.rst @@ -17,44 +17,55 @@ Adafruit ItsyBitsy M0 Express pin assignment table === ==== ============ ==== ==== ====== ====== ====== ====== Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC === ==== ============ ==== ==== ====== ====== ====== ====== - 0 PA11 D0 11 19 0/3 2/3 1/1 0/3 - 1 PA10 D1 10 18 0/2 2/2 1/0 0/2 - 2 PA14 D2 14 - 2/2 4/2 3/0 0/4 - 3 PA09 D3 9 17 0/1 2/1 0/1 1/3 - 4 PA08 D4 - 16 0/0 2/0 0/0 1/2 - 5 PA15 D5 15 - 2/3 4/3 3/1 0/5 - 7 PA21 D7 5 - 5/3 3/3 7/1 0/7 - 9 PA07 D9 7 7 - 0/3 1/1 - - 10 PA18 D10 2 - 1/2 3/2 3/0 0/2 - 11 PA16 D11 0 - 1/0 3/0 2/0 0/6 - 12 PA19 D12 3 - 1/3 3/3 3/1 0/3 - 13 PA17 D13 1 - 1/1 3/1 2/1 0/7 - 14 PA02 A0 2 0 - - - - - 15 PB08 A1 8 2 - 4/0 4/0 - - 16 PB09 A2 9 3 - 4/1 4/1 - - 17 PA04 A3 4 4 - 0/0 0/0 - - 18 PA05 A4 5 5 - 0/1 0/1 - - 19 PB02 A5 2 - - 5/0 6/0 - - 20 PA22 SDA 6 - 3/0 5/0 4/0 0/4 - 21 PA23 SCL 7 - 3/1 5/1 4/1 0/5 - 22 PB10 MOSI 10 - - 4/2 5/0 0/4 - 23 PA12 MISO 12 - 2/0 4/0 2/0 0/6 - 24 PB11 SCK 11 - - 4/3 5/1 0/5 - 25 PA00 DOTSTAR_CLK 0 - - 1/0 2/0 - - 26 PA01 DOTSTAR_DATA 1 - - 1/1 2/1 - - 27 PB22 FLASH_MOSI 6 - - 5/2 7/0 - - 28 PB03 FLASH_MISO 3 - - 5/1 6/1 - - 29 PB23 FLASH_SCK 7 - - 5/3 7/1 - + 2 PA02 A0 2 0 - - - - + 40 PB08 A1 8 2 - 4/0 4/0 - + 41 PB09 A2 9 3 - 4/1 4/1 - + 4 PA04 A3 4 4 - 0/0 0/0 - + 5 PA05 A4 5 5 - 0/1 0/1 - + 34 PB02 A5 2 10 - 5/0 6/0 - + 11 PA11 D0 11 19 0/3 2/3 1/1 0/3 + 10 PA10 D1 10 18 0/2 2/2 1/0 0/2 + 14 PA14 D2 14 - 2/2 4/2 3/0 0/4 + 9 PA09 D3 9 17 0/1 2/1 0/1 1/3 + 8 PA08 D4 - 16 0/0 2/0 0/0 1/2 + 15 PA15 D5 15 - 2/3 4/3 3/1 0/5 + 21 PA21 D7 5 - 5/3 3/3 7/1 0/7 + 7 PA07 D9 7 7 - 0/3 1/1 - + 18 PA18 D10 2 - 1/2 3/2 3/0 0/2 + 16 PA16 D11 0 - 1/0 3/0 2/0 0/6 + 19 PA19 D12 3 - 1/3 3/3 3/1 0/3 + 17 PA17 D13 1 - 1/1 3/1 2/1 0/7 + 0 PA00 DOTSTAR_CLK 0 - - 1/0 2/0 - + 1 PA01 DOTSTAR_DATA 1 - - 1/1 2/1 - + 27 PA27 FLASH_CS 15 - - - - - + 35 PB03 FLASH_MISO 3 11 - 5/1 6/1 - + 54 PB22 FLASH_MOSI 6 - - 5/2 7/0 - + 55 PB23 FLASH_SCK 7 - - 5/3 7/1 - + 11 PA11 RX 11 19 0/3 2/3 1/1 0/3 + 10 PA10 TX 10 18 0/2 2/2 1/0 0/2 + 12 PA12 MISO 12 - 2/0 4/0 2/0 0/6 + 42 PA12 MOSI 10 - - 4/2 5/0 0/4 + 43 PA13 SCK 11 - - 4/3 5/1 0/5 + 23 PA23 SCL 7 - 3/1 5/1 4/1 0/5 + 22 PA22 SDA 6 - 3/0 5/0 4/0 0/4 + 30 PA30 SWCLK 10 - - 1/2 1/0 - + 31 PA31 SWDIO 11 - - 1/3 1/1 - + 24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2 + 25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3 + 3 PA03 3 1 - - - - + 6 PA06 6 6 - 0/2 1/0 - + 13 PA13 13 - 2/1 4/1 2/0 0/7 + 20 PA20 4 - 5/2 3/2 7/0 0/4 + 28 PA28 8 - - - - - === ==== ============ ==== ==== ====== ====== ====== ====== Description of the columns: - *Pin* - The number that is expected at ``machine.Pin(n)``, if the pin is given - as a number. This is NOT the GPIO number, but the board pin number, as - given in the board specific definition file. -- *GPIO* - The GPIO number. -- *Pin Name* - The name of a Pin which is expected argument to ``machine.Pin("name")``. + as a number. +- *GPIO* - The GPIO name, which can be used as argument to ``machine.Pin("name")``. +- *Pin Name* - The boards name, which can be used as argument to ``machine.Pin("name")``. - *IRQ* - The IRQ number assigned to that GPIO, used internally by ``Pin.irq()``. When using ``Pin.irq()``, different pins must use different IRQs - *ADC* - The ADC channel assigned to the pin. When using ADC, different pins must @@ -83,7 +94,9 @@ Examples for Adafruit ItsyBitsy M0 Express: - uart 4 at pins D2/D5 - uart 5 at pins SCL/SDA -or other combinations. +or other combinations. For hardware flow control, tx must be at pad 0, rx at pad 1, +rts at pad 2 and cts at pad 3. This applies for instance to +UART 3 or UART 1 at the pins D13/D11/D10/D12 for rx/tx/rts/cts. SAMD21 I2C assignments `````````````````````` @@ -105,7 +118,7 @@ or other combinations. SAMD21 SPI assignments `````````````````````` -The I2C devices and signals must be chosen according to the following rules: +The SPI devices and signals must be chosen according to the following rules: - The following pad number pairs are suitable for MOSI/SCK: 0/1, 2/3, 3/1, and 0/3. - The MISO signal must be at a Pin with a different pad number than MOSI or SCK. @@ -116,7 +129,7 @@ Examples for Adafruit ItsyBitsy M0 Express: - SPI 1 at pins D11/D12/D13 - SPI 2 at pins D0/D4/D1 - SPI 3 at pins D11/D12/D13 -- SPI 4 at Pin MOSI/MISO/SCK This is the default SPI device at the MOSI/MISO/SCK labelled pins. +- SPI 2 at Pin MOSI/MISO/SCK This is the default SPI device at the MOSI/MISO/SCK labelled pins. or other combinations. @@ -158,14 +171,16 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM 22 PA22 D13 6 - - 3/0 5/1 4/0 1/6 0/2 34 PB02 DOTSTAR_CLK 2 14 - - 5/0 6/0 2/2 - 35 PB03 DOTSTAR_DATA 9 15 - - 5/1 6/1 - - - 43 PB11 FLASH_CS 12 - - - 4/3 5/1 0/5 1/1 - 11 PA11 FLASH_HOLD 11 11 - 0/3 2/3 1/1 0/3 1/7 - 9 PA09 FLASH_MISO 9 9 3 0/1 2/0 0/1 0/1 1/5 - 8 PA08 FLASH_MOSI - 8 2 0/0 2/1 0/0 0/0 1/4 - 42 PB10 FLASH_SCK 10 - - - 4/2 5/0 0/4 1/0 - 10 PA10 FLASH_WP 10 10 - 0/2 2/2 1/0 0/2 1/6 + 16 PA16 RX 0 - - 1/0 3/1 2/0 1/0 0/4 + 17 PA17 TX 1 - - 1/1 3/0 2/1 1/1 0/5 55 PB23 MISO 7 - - 1/3 5/3 7/1 - - 0 PA00 MOSI 0 - - - 1/0 2/0 - - + 43 PB11 QSPI_CS 12 - - - 4/3 5/1 0/5 1/1 + 8 PA08 QSPI_D0 - 8 2 0/0 2/1 0/0 0/0 1/4 + 9 PA09 QSPI_D1 9 9 3 0/1 2/0 0/1 0/1 1/5 + 10 PA10 QSPI_D2 10 10 - 0/2 2/2 1/0 0/2 1/6 + 11 PA11 QSPI_D3 11 11 - 0/3 2/3 1/1 0/3 1/7 + 42 PB10 QSPI_SCK 10 - - - 4/2 5/0 0/4 1/0 1 PA01 SCK 1 - - - 1/1 2/1 - - 13 PA13 SCL 13 - - 2/1 4/0 2/1 0/7 1/3 12 PA12 SDA 12 - - 2/0 4/1 2/0 0/6 1/2 @@ -181,10 +196,9 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM Description of the columns: - *Pin* - The number that is expected at ``machine.Pin(n)``, if the pin is given - as a number. This is NOT the GPIO number, but the board pin number, as - given in the board specific definition file. -- *GPIO* - The GPIO number. -- *Pin Name* The name of a Pin which is expected argument to ``machine.Pin("name")``. + as a number. +- *GPIO* - The GPIO name, which can be used as argument to ``machine.Pin("name")``. +- *Pin Name* - The boards name, which can be used as argument to ``machine.Pin("name")``. - *IRQ* - The IRQ number assigned to that GPIO, used internally by ``Pin.irq()``. When using ``Pin.irq()``, different pins must use different IRQs - *ADC* - The ADC0/1 channel assigned to the pin. When using ADC, different pins must @@ -214,7 +228,9 @@ Examples for Adafruit ItsyBitsy 4 Express: - uart 4 at pins SDA/SCL - uart 5 at pins D12/D13 -or other combinations. +or other combinations. For hardware flow control, tx must be at pad 0, rx at pad 1, +rts at pad 2 and cts at pad 3. This applies for instance to +UART 5 at the pins D12/D13/D10/D11 for rx/tx/rts/cts. SAMD51 I2C assignments `````````````````````` @@ -223,7 +239,7 @@ The I2C devices and signals must be chosen according to the following rules: - The SDA signal must be at a Pin with pad numbers 0. - The SCL signal must be at a Pin with pad numbers 1. -Examples for Adafruit ItsyBitsy M0 Express: +Examples for Adafruit ItsyBitsy M4 Express: - I2C 0 at pins A3/A4 - I2C 1 at pins D0/D1 @@ -241,7 +257,7 @@ The SPI devices and signals must be chosen according to the following rules: - The following pad number pairs are suitable for MOSI/SCK: 0/1 and 3/1. - The MISO signal must be at a Pin with a different pad number than MOSI or SCK. -Examples for Adafruit ItsyBitsy M0 Express: +Examples for Adafruit ItsyBitsy M4 Express: - SPI 1 at Pin MOSI/MISO/SCK This is the default SPI device at the MOSI/MISO/SCK labelled pins. - SPI 3 at pins D13/D11/D12 @@ -284,15 +300,17 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM 21 PA21 D11 5 - - 5/3 3/3 7/1 1/5 0/1 22 PA22 D12 6 - - 3/0 5/1 4/0 1/6 0/2 23 PA23 D13 7 - - 3/1 5/0 4/1 1/7 0/3 - 43 PB11 FLASH_CS 12 - - - 4/3 5/1 0/5 1/1 - 11 PA11 FLASH_HOLD 11 11 - 0/3 2/3 1/1 0/3 1/7 - 9 PA09 FLASH_MISO 9 9 3 0/1 2/0 0/1 0/1 1/5 - 8 PA08 FLASH_MOSI - 8 2 0/0 2/1 0/0 0/0 1/4 - 42 PB10 FLASH_SCK 10 - - - 4/2 5/0 0/4 1/0 - 10 PA10 FLASH_WP 10 10 - 0/2 2/2 1/0 0/2 1/6 + 49 PB17 RX 1 - - 5/1 - 6/1 3/1 0/5 + 48 PB16 TX 0 - - 5/0 - 6/0 3/0 0/4 54 PB22 MISO 22 - - 1/2 5/2 7/0 - - 55 PB23 MOSI 7 - - 1/3 5/3 7/1 - - 35 PB03 NEOPIXEL 9 15 - - 5/1 6/1 - - + 43 PB11 QSPI_CS 12 - - - 4/3 5/1 0/5 1/1 + 8 PA08 QSPI_D0 - 8 2 0/0 2/1 0/0 0/0 1/4 + 9 PA09 QSPI_D1 9 9 3 0/1 2/0 0/1 0/1 1/5 + 10 PA10 QSPI_D2 10 10 - 0/2 2/2 1/0 0/2 1/6 + 11 PA11 QSPI_D3 11 11 - 0/3 2/3 1/1 0/3 1/7 + 42 PB10 QSPI_SCK 10 - - - 4/2 5/0 0/4 1/0 17 PA17 SCK 1 - - 1/1 3/0 2/1 1/1 0/5 13 PA13 SCL 13 - - 2/1 4/0 2/1 0/7 1/3 12 PA12 SDA 12 - - 2/0 4/1 2/0 0/6 1/2 @@ -330,6 +348,77 @@ The default devices at the board are: - SPI 1 at pins PA23/PA22/PA17, labelled MOSI, MISO and SCK - DAC output on pins PA02 and PA05, labelled A0 and A1 +Adafruit Metro M4 Airlift pin assignment table +---------------------------------------------- + +=== ==== ============ ==== ==== ==== ====== ====== ===== ===== ===== +Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM +=== ==== ============ ==== ==== ==== ====== ====== ===== ===== ===== + 2 PA02 A0 2 0 - - - - - - + 5 PA05 A1 5 5 - - 0/1 0/1 - - + 6 PA06 A2 6 6 - - 0/2 1/0 - - + 32 PB00 A3 9 12 - - 5/2 7/0 - - + 40 PB08 A4 8 2 0 - 4/0 4/0 - - + 41 PB09 A5 9 3 1 - 4/1 4/1 - - + 23 PA23 D0 7 - - 3/1 5/0 4/1 1/7 0/3 + 22 PA22 D1 6 - - 3/0 5/1 4/0 1/6 0/2 + 49 PB17 D2 1 - - 5/1 - 6/1 3/1 0/5 + 48 PB16 D3 0 - - 5/0 - 6/0 3/0 0/4 + 45 PB13 D4 13 - - 4/1 - 4/1 3/1 0/1 + 46 PB14 D5 14 - - 4/2 - 5/0 4/0 0/2 + 47 PB15 D6 15 - - 4/3 - 5/1 4/1 0/3 + 44 PB12 D7 12 - - 4/0 - 4/0 3/0 0/0 + 21 PA21 D8 5 - - 5/3 3/3 7/1 1/5 0/1 + 20 PA20 D9 4 - - 5/2 3/2 7/0 1/4 0/0 + 3 PA03 AREF 3 10 - - - - - - + 18 PA18 D10 2 - - 1/2 3/2 3/0 1/2 0/6 + 19 PA19 D11 3 - - 1/3 3/3 3/1 1/3 0/7 + 16 PA16 D13 0 - - 1/0 3/1 2/0 1/0 0/4 + 36 PB04 ESP_BUSY 4 - 6 - - - - - + 15 PA15 ESP_CS 15 - - 2/3 4/3 3/1 2/1 1/3 + 33 PB01 ESP_GPIO0 1 13 - - 5/3 7/1 - - + 37 PB05 ESP_RESET 5 - 7 - - - - - + 55 PB23 ESP_RTS 7 - - 1/3 5/3 7/1 - - + 7 PA07 ESP_RX 7 7 - - 0/3 1/1 - - + 4 PA04 ESP_TX 4 4 - - 0/0 0/0 - - + 43 PB11 FLASH_CS 12 - - - 4/3 5/1 0/5 1/1 + 11 PA11 FLASH_HOLD 11 11 - 0/3 2/3 1/1 0/3 1/7 + 9 PA09 FLASH_MISO 9 9 3 0/1 2/0 0/1 0/1 1/5 + 8 PA08 FLASH_MOSI - 8 2 0/0 2/1 0/0 0/0 1/4 + 42 PB10 FLASH_SCK 10 - - - 4/2 5/0 0/4 1/0 + 10 PA10 FLASH_WP 10 10 - 0/2 2/2 1/0 0/2 1/6 + 23 PA23 RX 7 - - 3/1 5/0 4/1 1/7 0/3 + 22 PA22 TX 6 - - 3/0 5/1 4/0 1/6 0/2 + 14 PA14 MISO 14 - - 2/2 4/2 3/0 2/0 1/2 + 12 PA12 MOSI 12 - - 2/0 4/1 2/0 0/6 1/2 + 54 PB22 NEOPIXEL 22 - - 1/2 5/2 7/0 - - + 38 PB06 RXLED 6 - 8 - - - - - + 13 PA13 SCK 13 - - 2/1 4/0 2/1 0/7 1/3 + 35 PB03 SCL 9 15 - - 5/1 6/1 - - + 34 PB02 SDA 2 14 - - 5/0 6/0 2/2 - + 30 PA30 SWCLK 14 - - 7/2 1/2 6/0 2/0 - + 31 PA31 SWDIO 15 - - 7/3 1/3 6/1 2/1 - + 62 PB30 SWO 14 - - 7/0 5/1 0/0 4/0 0/6 + 39 PB07 TXLED 7 - 9 - - - - - + 24 PA24 USB_DM 8 - - 3/2 5/2 5/0 2/2 - + 25 PA25 USB_DP 9 - - 3/3 5/3 5/1 - - + 17 PA17 USB_HOSTEN 1 - - 1/1 3/0 2/1 1/1 0/5 + 0 PA00 - 0 - - - 1/0 2/0 - - + 1 PA01 - 1 - - - 1/1 2/1 - - + 27 PA27 - 11 - - - - - - - + 63 PB31 - 15 - - 7/1 5/0 0/1 4/1 0/7 +=== ==== ============ ==== ==== ==== ====== ====== ===== ===== ===== + +For the definition of the table columns see the explanation at the table +for Adafruit ItsyBitsy M4 Express :ref:`samd51_pinout_table`. + +The default devices at the board are: + +- UART 3 at pins PA23/PA22, labelled D0/D1 resp. RX/TX +- I2C 5 at pins PB02/PB03, labelled SDA/SCL +- SPI 4 at pins PA12/PA14/PA13, labelled MOSI, MISO and SCK +- DAC output on pins PA02 and PA05, labelled A0 and A1 + SEEED XIAO pin assignment table ------------------------------- @@ -348,6 +437,13 @@ Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC 5 PA05 A9_D9 5 5 - 0/1 0/1 - 6 PA06 A10_D10 6 6 - 0/2 1/0 - 18 PA18 RX_LED 2 - 1/2 3/2 3/0 0/2 + 41 PB09 RX 9 3 - 4/1 4/1 - + 40 PB08 TX 8 2 - 4/0 4/0 - + 8 PA08 SDA - 16 0/0 2/0 0/0 1/2 + 9 PA09 SCL 9 17 0/1 2/1 0/1 1/3 + 6 PA06 MOSI 6 6 - 0/2 1/0 - + 5 PA05 MISO 5 5 - 0/1 0/1 - + 7 PA07 SCK 7 7 - 0/3 1/1 - 30 PA30 SWCLK 10 - - 1/2 1/0 - 31 PA31 SWDIO 11 - - 1/3 1/1 - 19 PA19 TX_LED 3 - 1/3 3/3 3/1 0/3 @@ -422,6 +518,8 @@ Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC 43 PB11 SCK 11 - - 4/3 5/1 0/5 23 PA23 SCL 7 - 3/1 5/1 4/1 0/5 22 PA22 SDA 6 - 3/0 5/0 4/0 0/4 + 11 PA11 RX 11 19 0/3 2/3 1/1 0/3 + 10 PA10 TX 10 18 0/2 2/2 1/0 0/2 30 PA30 SWCLK 10 - - 1/2 1/0 - 31 PA31 SWDIO 11 - - 1/3 1/1 - 24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2 @@ -437,9 +535,9 @@ Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`. The default devices at the board are: -- UART 5 at pins PB23/PB22, labelled RX/TX +- UART 2 at pins PA11/PA10, labelled RX/TX - I2C 3 at pins PA22/PA23, labelled SDA/SCL -- SPI 4 at pins PA10/PA12/PA11, labelled MOSI, MISO and SCK +- SPI 4 at pins PB10/PA12/PB11, labelled MOSI, MISO and SCK - DAC output on pin PA02, labelled A0 Adafruit Trinket M0 pin assignment table @@ -455,6 +553,13 @@ Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC 6 PA06 D4 6 6 - 0/2 1/0 - 1 PA01 DOTSTAR_CLK 1 - - 1/1 2/1 - 0 PA00 DOTSTAR_DATA 0 - - 1/0 2/0 - + 7 PA07 RX 7 7 - 0/3 1/1 - + 6 PA06 TX 6 6 - 0/2 1/0 - + 8 PA08 SDA - 16 0/0 2/0 0/0 1/2 + 9 PA09 SCL 9 17 0/1 2/1 0/1 1/3 + 6 PA06 MOSI 6 6 - 0/2 1/0 - + 9 PA09 MISO 9 17 0/1 2/1 0/1 1/3 + 7 PA07 SCK 7 7 - 0/3 1/1 - 10 PA10 LED 10 18 0/2 2/2 1/0 0/2 30 PA30 SWCLK 10 - - 1/2 1/0 - 31 PA31 SWDIO 11 - - 1/3 1/1 - @@ -486,6 +591,66 @@ The default devices at the board are: - SPI 0 at pins PA06/PA09/PA08, labelled D4, D2 and D0 - DAC output on pin PA02, labelled D1 +Adafruit QT PY pin assignment table +----------------------------------- + +=== ==== ============ ==== ==== ====== ====== ====== ====== +Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC +=== ==== ============ ==== ==== ====== ====== ====== ====== + 2 PA02 A0 2 0 - - - - + 3 PA03 A1 3 1 - - - - + 4 PA04 A2 4 4 - 0/0 0/0 - + 5 PA05 A3 5 5 - 0/1 0/1 - + 7 PA07 RX 7 7 - 0/3 1/1 - + 6 PA06 TX 6 6 - 0/2 1/0 - + 8 PA08 FLASH_CS - 16 0/0 2/0 0/0 1/2 + 19 PA19 FLASH_MISO 3 - 1/3 3/3 3/1 0/3 + 22 PA22 FLASH_MOSI 6 - 3/0 5/0 4/0 0/4 + 23 PA23 FLASH_SCK 7 - 3/1 5/1 4/1 0/5 + 9 PA09 MISO 9 17 0/1 2/1 0/1 1/3 + 10 PA10 MOSI 10 18 0/2 2/2 1/0 0/2 + 18 PA18 NEOPIX 2 - 1/2 3/2 3/0 0/2 + 15 PA15 NEO_PWR 15 - 2/3 4/3 3/1 0/5 + 11 PA11 SCK 11 19 0/3 2/3 1/1 0/3 + 17 PA17 SCL 1 - 1/1 3/1 2/1 0/7 + 16 PA16 SDA 0 - 1/0 3/0 2/0 0/6 + 30 PA30 SWCLK 10 - - 1/2 1/0 - + 31 PA31 SWDIO 11 - - 1/3 1/1 - + 24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2 + 25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3 +=== ==== ============ ==== ==== ====== ====== ====== ====== + +For the definition of the table columns see the explanation at the table for +Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`. + +The default devices at the board are: + +- UART 0 at pins PA07/PA06, labelled RX/TX +- I2C 1 at pins PA16/PA17, labelled SDA/SCL +- SPI 0 at pins PA09/PA10/PA11, labelled MISO, MOSI and SCK +- DAC output on pin PA02, labelled A0 + +Adafruit NeoKey Trinkey pin assignment table +-------------------------------------------- + +=== ==== ============ ==== ==== ====== ====== ====== ====== +Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC +=== ==== ============ ==== ==== ====== ====== ====== ====== + 15 PA15 NEOPIXEL 15 - 2/3 4/3 3/1 0/5 + 30 PA30 SWCLK 10 - - 1/2 1/0 - + 31 PA31 SWDIO 11 - - 1/3 1/1 - + 18 PA18 SWITCH 2 - 1/2 3/2 3/0 0/2 + 7 PA07 TOUCH 7 7 - 0/3 1/1 - + 24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2 + 25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3 +=== ==== ============ ==== ==== ====== ====== ====== ====== + +For the definition of the table columns see the explanation at the table for +Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`. + +The board does not provide access to UART, I2C, SPI or DAC. + + SAMD21 Xplained PRO pin assignment table ---------------------------------------- @@ -575,8 +740,16 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM 34 PB02 DOTSTAR_CLK 2 14 - - 5/0 6/0 2/2 - 35 PB03 DOTSTAR_DATA 9 15 - - 5/1 6/1 - - 15 PA15 LED 15 - - 2/3 4/3 3/1 2/1 1/3 - 55 PB23 MISO 7 - - 1/3 5/3 7/1 - - - 54 PB22 MOSI 22 - - 1/2 5/2 7/0 - - + 16 PA16 RX 0 - - 1/0 3/1 2/0 1/0 0/4 + 17 PA17 TX 1 - - 1/1 3/0 2/1 1/1 0/5 + 55 PB23 MOSI 7 - - 1/3 5/3 7/1 - - + 54 PB22 MISO 22 - - 1/2 5/2 7/0 - - + 43 PB11 QSPI_CS 12 - - - 4/3 5/1 0/5 1/1 + 8 PA08 QSPI_D0 - 8 2 0/0 2/1 0/0 0/0 1/4 + 9 PA09 QSPI_D1 9 9 3 0/1 2/0 0/1 0/1 1/5 + 10 PA10 QSPI_D2 10 10 - 0/2 2/2 1/0 0/2 1/6 + 11 PA11 QSPI_D3 11 11 - 0/3 2/3 1/1 0/3 1/7 + 42 PB10 QSPI_SCK 10 - - - 4/2 5/0 0/4 1/0 1 PA01 SCK 1 - - - 1/1 2/1 - - 13 PA13 SCL 13 - - 2/1 4/0 2/1 0/7 1/3 12 PA12 SDA 12 - - 2/0 4/1 2/0 0/6 1/2 @@ -584,17 +757,11 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM 31 PA31 SWDIO 15 - - 7/3 1/3 6/1 2/1 - 24 PA24 USB_DM 8 - - 3/2 5/2 5/0 2/2 - 25 PA25 USB_DP 9 - - 3/3 5/3 5/1 - - - 8 PA08 - - 8 2 0/0 2/1 0/0 0/0 1/4 - 9 PA09 - 9 9 3 0/1 2/0 0/1 0/1 1/5 - 10 PA10 - 10 10 - 0/2 2/2 1/0 0/2 1/6 - 11 PA11 - 11 11 - 0/3 2/3 1/1 0/3 1/7 14 PA14 - 14 - - 2/2 4/2 3/0 2/0 1/2 18 PA18 - 2 - - 1/2 3/2 3/0 1/2 0/6 22 PA22 - 6 - - 3/0 5/1 4/0 1/6 0/2 23 PA23 - 7 - - 3/1 5/0 4/1 1/7 0/3 27 PA27 - 11 - - - - - - - - 42 PB10 - 10 - - - 4/2 5/0 0/4 1/0 - 43 PB11 - 12 - - - 4/3 5/1 0/5 1/1 === ==== ============ ==== ==== ==== ====== ====== ===== ===== ===== For the definition of the table columns see the explanation at the table for @@ -661,6 +828,12 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM 117 PD21 SD_DET 11 - - 1/3 3/3 - 1/1 - 83 PC19 SD_CS 3 - - 6/3 0/3 - 0/3 - 82 PC18 SD_MISO 2 - - 6/2 0/2 - 0/2 - + 43 PB11 QSPI_CS 12 - - - 4/3 5/1 0/5 1/1 + 8 PA08 QSPI_D0 - 8 2 0/0 2/1 0/0 0/0 1/4 + 9 PA09 QSPI_D1 9 9 3 0/1 2/0 0/1 0/1 1/5 + 10 PA10 QSPI_D2 10 10 - 0/2 2/2 1/0 0/2 1/6 + 11 PA11 QSPI_D3 11 11 - 0/3 2/3 1/1 0/3 1/7 + 42 PB10 QSPI_SCK 10 - - - 4/2 5/0 0/4 1/0 80 PC16 SD_MOSI 0 - - 6/0 0/1 - 0/0 - 81 PC17 SD_SCK 1 - - 6/1 0/0 - 0/1 - 30 PA30 SWCLK 14 - - 7/2 1/2 6/0 2/0 - @@ -677,17 +850,11 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM 2 PA02 - 2 0 - - - - - - 3 PA03 - 3 10 - - - - - - 5 PA05 - 5 5 - - 0/1 0/1 - - - 8 PA08 - - 8 2 0/0 2/1 0/0 0/0 1/4 - 9 PA09 - 9 9 3 0/1 2/0 0/1 0/1 1/5 - 10 PA10 - 10 10 - 0/2 2/2 1/0 0/2 1/6 - 11 PA11 - 11 11 - 0/3 2/3 1/1 0/3 1/7 14 PA14 - 14 - - 2/2 4/2 3/0 2/0 1/2 18 PA18 - 2 - - 1/2 3/2 3/0 1/2 0/6 19 PA19 - 3 - - 1/3 3/3 3/1 1/3 0/7 23 PA23 - 7 - - 3/1 5/0 4/1 1/7 0/3 27 PA27 - 11 - - - - - - - - 42 PB10 - 10 - - - 4/2 5/0 0/4 1/0 - 43 PB11 - 12 - - - 4/3 5/1 0/5 1/1 46 PB14 - 14 - - 4/2 - 5/0 4/0 0/2 49 PB17 - 1 - - 5/1 - 6/1 3/1 0/5 54 PB22 - 22 - - 1/2 5/2 7/0 - - @@ -752,6 +919,8 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM 11 PA11 FLASH_MISO 11 11 - 0/3 2/3 1/1 0/3 1/7 8 PA08 FLASH_MOSI - 8 2 0/0 2/1 0/0 0/0 1/4 9 PA09 FLASH_SCK 9 9 3 0/1 2/0 0/1 0/1 1/5 + 13 PA13 RX 13 - - 2/1 4/0 2/1 0/7 1/3 + 12 PA12 TX 12 - - 2/0 4/1 2/0 0/6 1/2 43 PB11 MISO 12 - - - 4/3 5/1 0/5 1/1 44 PB12 MOSI 12 - - 4/0 - 4/0 3/0 0/0 55 PB23 RXD 7 - - 1/3 5/3 7/1 - - @@ -789,11 +958,193 @@ Adafruit ItsyBitsy M4 Express :ref:`samd51_pinout_table`. The default devices at the board are: -- UART 1 at pins PB23/PB22, labelled RXD/TXD -- I2C 5 at pins PA22/PA23, labelled SDA/SCL +- UART 2 at pins PA13/PA12, labelled RXD/TXD +- I2C 3 at pins PA22/PA23, labelled SDA/SCL - SPI 4 at pins PB12/PB11/PB13, labelled MOSI, MISO and SCK - DAC output on pins PA02 and PA05, labelled A0 and A4 +Generic SAMD21x18 pin assignment table +-------------------------------------- + +=== ==== ============ ==== ==== ====== ====== ====== ====== +Pin GPIO Name/Package IRQ ADC Serial Serial TCC/TC TCC/TC +=== ==== ============ ==== ==== ====== ====== ====== ====== + 0 PA00 EGJ 0 - - 1/0 2/0 - + 1 PA01 EGJ 1 - - 1/1 2/1 - + 2 PA02 EGJ 2 0 - - - - + 3 PA03 EGJ 3 1 - - - - + 4 PA04 EGJ 4 4 - 0/0 0/0 - + 5 PA05 EGJ 5 5 - 0/1 0/1 - + 6 PA06 EGJ 6 6 - 0/2 1/0 - + 7 PA07 EGJ 7 7 - 0/3 1/1 - + 8 PA08 EGJ - 16 0/0 2/0 0/0 1/2 + 9 PA09 EGJ 9 17 0/1 2/1 0/1 1/3 + 10 PA10 EGJ 10 18 0/2 2/2 1/0 0/2 + 11 PA11 EGJ 11 19 0/3 2/3 1/1 0/3 + 12 PA12 GJ 12 - 2/0 4/0 2/0 0/6 + 13 PA13 GJ 13 - 2/1 4/1 2/0 0/7 + 14 PA14 EGJ 14 - 2/2 4/2 3/0 0/4 + 15 PA15 EGJ 15 - 2/3 4/3 3/1 0/5 + 16 PA16 EGJ 0 - 1/0 3/0 2/0 0/6 + 17 PA17 EGJ 1 - 1/1 3/1 2/1 0/7 + 18 PA18 EGJ 2 - 1/2 3/2 3/0 0/2 + 19 PA19 EGJ 3 - 1/3 3/3 3/1 0/3 + 20 PA20 GJ 4 - 5/2 3/2 7/0 0/4 + 21 PA21 GJ 5 - 5/3 3/3 7/1 0/7 + 22 PA22 EGJ 6 - 3/0 5/0 4/0 0/4 + 23 PA23 EGJ 7 - 3/1 5/1 4/1 0/5 + 24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2 + 25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3 + 27 PA27 EGJ 15 - - - - - + 28 PA28 EGJ 8 - - - - - + 30 PA30 SWCLK 10 - - 1/2 1/0 - + 31 PA31 SWDIO 11 - - 1/3 1/1 - + 32 PB00 J 0 8 - 5/2 7/0 - + 33 PB01 J 1 9 - 5/3 7/1 - + 34 PB02 GJ 2 10 - 5/0 6/0 - + 35 PB03 GJ 3 11 - 5/1 6/1 - + 36 PB04 J 4 12 - - - - + 37 PB05 J 5 13 - - - - + 38 PB06 J 6 14 - - - - + 39 PB07 J 7 15 - - - - + 40 PB08 GJ 8 2 - 4/0 4/0 - + 41 PB09 GJ 9 3 - 4/1 4/1 - + 42 PB10 GJ 10 - - 4/2 5/0 0/4 + 43 PB11 GJ 11 - - 4/3 5/1 0/5 + 44 PB12 J 12 - 4/0 - 4/0 0/6 + 45 PB13 J 13 - 4/1 - 4/1 0/7 + 46 PB14 J 14 - 4/2 - 5/0 - + 47 PB15 J 15 - 4/3 - 5/1 - + 48 PB16 J 0 - 5/0 - 6/0 0/4 + 49 PB17 J 1 - 5/1 - 6/1 0/5 + 54 PB22 GJ 6 - - 5/2 7/0 - + 55 PB23 GJ 7 - - 5/3 7/1 - + 62 PB30 J 14 - - 5/0 0/0 1/2 + 63 PB31 J 15 - - 5/1 0/1 1/3 +=== ==== ============ ==== ==== ====== ====== ====== ====== + +For the definition of the table columns see the explanation at the table for +Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`. + +The Package column indicates the package letter providing this pin. An entry +EGJ tells for instance, that the pin is available for SAMD21E18, SAMD21G18 and +SAMD21J18. + + +Generic SAMD51x19 and SAM51x20 pin assignment table +--------------------------------------------------- + +For the definition of the table columns see the explanation at the table for +Adafruit ItsyBitsy M4 Express :ref:`samd51_pinout_table`. + +=== ==== ============ ==== ==== ==== ====== ====== ===== ===== ===== +Pin GPIO Name/Package IRQ ADC ADC Serial Serial TC PWM PWM +=== ==== ============ ==== ==== ==== ====== ====== ===== ===== ===== + 8 PA08 QSPI_D0 - 8 2 0/0 2/1 0/0 0/0 1/4 + 9 PA09 QSPI_D1 9 9 3 0/1 2/0 0/1 0/1 1/5 + 10 PA10 QSPI_D2 10 10 - 0/2 2/2 1/0 0/2 1/6 + 11 PA11 QSPI_D3 11 11 - 0/3 2/3 1/1 0/3 1/7 + 42 PB10 QSPI_SCK 10 - - - 4/2 5/0 0/4 1/0 + 23 PA23 USB_SOF 7 - - 3/1 5/0 4/1 1/7 0/3 + 24 PA24 USB_DM 8 - - 3/2 5/2 5/0 2/2 - + 25 PA25 USB_DP 9 - - 3/3 5/3 5/1 - - + 0 PA00 GJP 0 - - - 1/0 2/0 - - + 1 PA01 GJP 1 - - - 1/1 2/1 - - + 2 PA02 GJP 2 0 - - - - - - + 3 PA03 GJP 3 10 - - - - - - + 4 PA04 GJP 4 4 - - 0/0 0/0 - - + 5 PA05 GJP 5 5 - - 0/1 0/1 - - + 6 PA06 GJP 6 6 - - 0/2 1/0 - - + 7 PA07 GJP 7 7 - - 0/3 1/1 - - + 12 PA12 GJP 12 - - 2/0 4/1 2/0 0/6 1/2 + 13 PA13 GJP 13 - - 2/1 4/0 2/1 0/7 1/3 + 14 PA14 GJP 14 - - 2/2 4/2 3/0 2/0 1/2 + 15 PA15 GJP 15 - - 2/3 4/3 3/1 2/1 1/3 + 16 PA16 GJP 0 - - 1/0 3/1 2/0 1/0 0/4 + 17 PA17 GJP 1 - - 1/1 3/0 2/1 1/1 0/5 + 18 PA18 GJP 2 - - 1/2 3/2 3/0 1/2 0/6 + 19 PA19 GJP 3 - - 1/3 3/3 3/1 1/3 0/7 + 20 PA20 GJP 4 - - 5/2 3/2 7/0 1/4 0/0 + 21 PA21 GJP 5 - - 5/3 3/3 7/1 1/5 0/1 + 22 PA22 GJP 6 - - 3/0 5/1 4/0 1/6 0/2 + 27 PA27 GJP 11 - - - - - - - + 30 PA30 SWCLK 14 - - 7/2 1/2 6/0 2/0 - + 31 PA31 SWDIO 15 - - 7/3 1/3 6/1 2/1 - + 32 PB00 JP 0 12 - - 5/2 7/0 - - + 33 PB01 JP 1 13 - - 5/3 7/1 - - + 34 PB02 GJP 2 14 - - 5/0 6/0 2/2 - + 35 PB03 GJP 3 15 - - 5/1 6/1 - - + 36 PB04 JP 4 - 6 - - - - - + 37 PB05 JP 5 - 7 - - - - - + 38 PB06 JP 6 - 8 - - - - - + 39 PB07 JP 7 - 9 - - - - - + 40 PB08 GJP 8 2 0 - 4/0 4/0 - - + 41 PB09 GJP 9 3 1 - 4/1 4/1 - - + 44 PB12 JP 12 - - 4/0 - 4/0 3/0 0/0 + 45 PB13 JP 13 - - 4/1 - 4/1 3/1 0/1 + 46 PB14 JP 14 - - 4/2 - 5/0 4/0 0/2 + 47 PB15 JP 15 - - 4/3 - 5/1 4/1 0/3 + 48 PB16 JP 0 - - 5/0 - 6/0 3/0 0/4 + 49 PB17 JP 1 - - 5/1 - 6/1 3/1 0/5 + 50 PB18 P 2 - - 5/2 7/2 - 1/0 - + 51 PB19 P 3 - - 5/3 7/3 - 1/1 - + 52 PB20 P 4 - - 3/0 7/1 - 1/2 - + 53 PB21 P 5 - - 3/1 7/0 - 1/3 - + 54 PB22 GJP 6 - - 1/2 5/2 7/0 - - + 55 PB23 GJP 7 - - 1/3 5/3 7/1 - - + 56 PB24 P 8 - - 0/0 2/1 - - - + 57 PB25 P 9 - - 0/1 2/0 - - - + 58 PB26 P 12 - - 2/0 4/1 - 1/2 - + 59 PB27 P 13 - - 2/1 4/0 - 1/3 - + 60 PB28 P 14 - - 2/2 4/2 - 1/4 - + 61 PB29 P 15 - - 2/3 4/3 - 1/5 - + 62 PB30 JP 14 - - 7/0 5/1 0/0 4/0 0/6 + 63 PB31 JP 15 - - 7/1 5/0 0/1 4/1 0/7 + 64 PC00 P 0 - 10 - - - - - + 65 PC01 P 1 - 11 - - - - - + 66 PC02 P 2 - 4 - - - - - + 67 PC03 P 3 - 5 - - - - - + 68 PC04 P 4 - - 6/0 - - 0/0 - + 69 PC05 P 5 - - 6/1 - - - - + 70 PC06 P 6 - - 6/2 - - - - + 71 PC07 P 9 - - 6/3 - - - - + 74 PC10 P 10 - - 6/2 7/2 - 0/0 1/4 + 75 PC11 P 11 - - 6/3 7/3 - 0/1 1/5 + 76 PC12 P 12 - - 7/0 6/1 - 0/2 1/6 + 77 PC13 P 13 - - 7/1 6/0 - 0/3 1/7 + 78 PC14 P 14 - - 7/2 6/2 - 0/4 1/0 + 79 PC15 P 15 - - 7/3 6/3 - 0/5 1/1 + 80 PC16 P 0 - - 6/0 0/1 - 0/0 - + 81 PC17 P 1 - - 6/1 0/0 - 0/1 - + 82 PC18 P 2 - - 6/2 0/2 - 0/2 - + 83 PC19 P 3 - - 6/3 0/3 - 0/3 - + 84 PC20 P 4 - - - - - 0/4 - + 85 PC21 P 5 - - - - - 0/5 - + 86 PC22 P 6 - - 1/0 3/1 - 0/5 - + 87 PC23 P 7 - - 1/1 3/0 - 0/7 - + 88 PC24 P 8 - - 0/2 2/2 - - - + 89 PC25 P 9 - - 0/3 2/3 - - - + 90 PC26 P 10 - - - - - - - + 91 PC27 P 11 - - 1/0 - - - - + 92 PC28 P 12 - - 1/1 - - - - + 94 PC30 P 14 - 12 - - - - - + 95 PC31 P 15 - 13 - - - - - + 96 PD00 P 0 - 14 - - - - - + 97 PD01 P 1 - 15 - - - - - +104 PD08 P 3 - - 7/0 6/1 - 0/1 - +105 PD09 P 4 - - 7/1 6/0 - 0/2 - +106 PD10 P 5 - - 7/2 6/2 - 0/3 - +107 PD11 P 6 - - 7/3 6/3 - 0/4 - +108 PD12 P 7 - - - - - 0/5 - +116 PD20 P 10 - - 1/2 3/2 - 1/0 - +117 PD21 P 11 - - 1/3 3/3 - 1/1 - +=== ==== ============ ==== ==== ==== ====== ====== ===== ===== ===== + + +The Package column indicates the package letter providing this pin. An entry +GJP tells for instance, that the pin is available for SAMD51G19, SAMD51J19/-J20 and +SAMD51P19/-P20. + Scripts for creating the pin assignment tables ---------------------------------------------- @@ -803,36 +1154,36 @@ The tables shown above were created with small a Python script running on the ta from machine import Pin import os - def print_entry(e, txt): + def print_item(e, txt): print(txt, end=": ") if e == 255: print(" - ", end="") else: print("%d/%d" % (e >> 4, e & 0x0f), end="") - def print_pininfo(pin, info): - print("%3d" % pin, end=" ") - print("P%c%02d" % ("ABCD"[pin // 32], pin % 32), end="") - print(" %12s" % info[0], end="") + def print_pininfo(pin_id, name, info): + + print("%3d" % pin_id, end=" ") + print("%4s %12s" % (info[0], name), end="") print(" IRQ:%2s" % (info[1] if info[1] != 255 else "-"), end="") print(" ADC0:%2s" % (info[2] if info[2] != 255 else "-"), end="") if len(info) == 7: - print_entry(info[3], " Serial1") - print_entry(info[4], " Serial2") - print_entry(info[5], " PWM1" if (info[5] >> 4) < 3 else " TC") - print_entry(info[6], " PWM2") + print_item(info[3], " Serial1") + print_item(info[4], " Serial2") + print_item(info[5], " PWM1" if (info[5] >> 4) < 3 else " TC") + print_item(info[6], " PWM2") else: print(" ADC1:%2s" % (info[3] if info[3] != 255 else "-"), end="") - print_entry(info[4], " Serial1") - print_entry(info[5], " Serial2") - print_entry(info[6], " TC") - print_entry(info[7], " PWM1") - print_entry(info[8], " PWM2") + print_item(info[4], " Serial1") + print_item(info[5], " Serial2") + print_item(info[6], " TC") + print_item(info[7], " PWM1") + print_item(info[8], " PWM2") print() def tblkey(i): - name = i[1][0] - if name != "-": + name = i[1] + if name != "": if len(name) < 3: return " " + name else: @@ -840,17 +1191,25 @@ The tables shown above were created with small a Python script running on the ta else: return "zzzzzzz%03d" % i[0] - def table(num = 127): + def pinnum(p): + return (ord(p[1]) - ord("A")) * 32 + int(p[2:]) + + def table(num = 127, sort=True): pintbl = [] - for i in range(num): - try: - pintbl.append((i, pininfo(i))) - except: - pass - # print("not defined") - - pintbl.sort(key=tblkey) + pinlist = [] + for name in Pin.board.__dict__.keys(): + p = Pin(name) + pi = pininfo(p) + pintbl.append((pinnum(pi[0]), name, pi)) + pinlist.append(p) + for pc in Pin.cpu.__dict__.keys(): + p = Pin(pc) + pi = pininfo(p) + if not p in pinlist: + pintbl.append((pinnum(pi[0]), "", pi)) + if sort: + pintbl.sort(key=tblkey) for item in pintbl: - print_pininfo(item[0], item[1]) + print_pininfo(item[0], item[1], item[2]) table() diff --git a/docs/samd/quickref.rst b/docs/samd/quickref.rst index cdfb0a4750724..781686d2f60e6 100644 --- a/docs/samd/quickref.rst +++ b/docs/samd/quickref.rst @@ -65,6 +65,8 @@ Use the :mod:`time