kopia lustrzana https://github.com/micropython/micropython
Merge branch 'micropython:master' into master
commit
ecf441049e
|
@ -1,3 +1,18 @@
|
|||
# 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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -0,0 +1,107 @@
|
|||
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).
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Checks
|
||||
description: |
|
||||
Before submitting your bug report, please go over these check points:
|
||||
options:
|
||||
- label: |
|
||||
I 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.
|
||||
required: true
|
||||
- label: |
|
||||
I've searched for [existing issues](https://github.com/micropython/micropython/issues) matching this bug, and didn't find any.
|
||||
required: true
|
||||
- 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: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to help improve MicroPython.
|
|
@ -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.
|
|
@ -0,0 +1,44 @@
|
|||
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.
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Checks
|
||||
description: |
|
||||
Before submitting your bug report, please go over these check points:
|
||||
options:
|
||||
- label: |
|
||||
I 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.
|
||||
required: true
|
||||
- label: |
|
||||
I've searched for [existing issues](https://github.com/micropython/micropython/issues) and didn't find any that matched.
|
||||
required: true
|
||||
- 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: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to help improve MicroPython.
|
|
@ -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.
|
|
@ -0,0 +1,65 @@
|
|||
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.
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Checks
|
||||
description: |
|
||||
Before submitting your feature request, please go over these check points:
|
||||
options:
|
||||
- label: |
|
||||
I 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.
|
||||
required: true
|
||||
- label: |
|
||||
I've searched for [existing issues](https://github.com/micropython/micropython/issues) regarding this feature, and didn't find any.
|
||||
required: true
|
||||
- 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: checkboxes
|
||||
id: implementation
|
||||
attributes:
|
||||
label: Implementation
|
||||
options:
|
||||
- label: I intend to implement this feature and would submit a Pull Request if desirable.
|
||||
- label: I hope the MicroPython maintainers or community will implement this feature.
|
||||
- label: I would like to [Sponsor](https://github.com/sponsors/micropython#sponsors) development of this feature.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to suggest improvements for MicroPython.
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
name: Security report
|
||||
about: Report a security issue or vulnerability 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.
|
|
@ -0,0 +1,59 @@
|
|||
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.
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Checks
|
||||
description: |
|
||||
Before submitting your bug report, please go over these check points:
|
||||
options:
|
||||
- label: |
|
||||
I 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.
|
||||
required: true
|
||||
- label: I wish to report a specific security issue that is **not readily exploitable and does not have high impact** for MicroPython developers or users.
|
||||
required: true
|
||||
- label: |
|
||||
I've searched for [existing issues](https://github.com/micropython/micropython/issues) and didn't find any that matched.
|
||||
required: true
|
||||
- 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
|
|
@ -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
|
|
@ -11,20 +11,10 @@ jobs:
|
|||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@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
|
||||
|
||||
code-spelling:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_code_spell_setup
|
||||
- name: Run spell checker
|
||||
run: source tools/ci.sh && ci_code_spell_run
|
||||
|
|
|
@ -36,7 +36,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: |
|
||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
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: |
|
||||
|
|
|
@ -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.2.6 tomli
|
||||
- run: codespell
|
||||
|
|
@ -13,6 +13,6 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: '100'
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Check commit message formatting
|
||||
run: source tools/ci.sh && ci_commit_formatting_run
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
name: Build docs
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- docs/**
|
||||
|
@ -15,8 +16,8 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@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
|
||||
|
|
|
@ -16,13 +16,13 @@ jobs:
|
|||
# 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@v4
|
||||
- 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: |
|
||||
|
|
|
@ -18,11 +18,40 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build_idf50:
|
||||
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-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_esp32_idf50_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_esp32_build
|
||||
|
||||
- id: idf_ver
|
||||
name: Read the ESP-IDF version
|
||||
run: source tools/ci.sh && echo "IDF_VER=$IDF_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 }}
|
||||
|
|
|
@ -20,8 +20,13 @@ concurrency:
|
|||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: 'micropython repo' # test build with space in path
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: 'micropython repo'
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_mimxrt_setup
|
||||
- name: Build
|
||||
|
|
|
@ -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@v4
|
||||
with:
|
||||
path: 'micropython repo'
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_rp2_setup
|
||||
- name: Build
|
||||
|
|
|
@ -18,20 +18,19 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build_pyb:
|
||||
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-20.04
|
||||
steps:
|
||||
- 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@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_stm32_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_stm32_nucleo_build
|
||||
|
|
|
@ -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@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_teensy_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_teensy_build
|
|
@ -55,6 +55,18 @@ 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:
|
||||
|
@ -184,7 +196,7 @@ jobs:
|
|||
runs-on: macos-11.0
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.8'
|
||||
- name: Build
|
||||
|
|
|
@ -18,7 +18,134 @@ 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
|
||||
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:
|
||||
- name: Get Python path
|
||||
id: python_path
|
||||
shell: python
|
||||
run: |
|
||||
import os
|
||||
import sys
|
||||
output = f"python={os.fspath(sys.executable)}"
|
||||
print(output)
|
||||
with open(os.environ["GITHUB_OUTPUT"], "w") as f:
|
||||
f.write(output)
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.sys }}
|
||||
update: true
|
||||
install: >-
|
||||
make
|
||||
mingw-w64-${{ matrix.env }}-gcc
|
||||
pkg-config
|
||||
python3
|
||||
git
|
||||
diffutils
|
||||
- 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
|
||||
# msys python breaks tests so we need to use "real" windows python
|
||||
run: MICROPY_CPYTHON3=$(cygpath "${{ steps.python_path.outputs.python }}") 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@v4
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
||||
name: Python code lint with ruff
|
||||
name: Python code lint and formatting with ruff
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ruff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: pip install --user ruff
|
||||
- run: ruff --format=github .
|
||||
# ruff version should be kept in sync with .pre-commit-config.yaml
|
||||
- run: pip install --user ruff==0.1.3
|
||||
- run: ruff check --output-format=github .
|
||||
- run: ruff format --diff .
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
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
|
||||
|
@ -59,3 +59,9 @@
|
|||
[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
|
||||
|
|
|
@ -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
|
||||
|
@ -12,6 +12,16 @@ repos:
|
|||
verbose: true
|
||||
stages: [commit-msg]
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.265
|
||||
# Version should be kept in sync with .github/workflows/ruff.yml
|
||||
rev: v0.1.3
|
||||
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.2.6
|
||||
hooks:
|
||||
- id: codespell
|
||||
name: Spellcheck for changed files (codespell)
|
||||
additional_dependencies:
|
||||
- tomli
|
||||
|
|
|
@ -53,13 +53,16 @@ are then certifying and signing off against the following:
|
|||
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
|
||||
==========
|
||||
|
@ -101,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
|
||||
==========================
|
||||
|
||||
|
@ -151,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.
|
||||
|
|
6
LICENSE
6
LICENSE
|
@ -48,12 +48,14 @@ 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)
|
||||
|
@ -69,6 +71,8 @@ used during the build process and is not part of the compiled source code.
|
|||
/FreeRTOS (GPL-2.0 with FreeRTOS exception)
|
||||
/esp32
|
||||
/ppp_set_auth.* (Apache-2.0)
|
||||
/rp2
|
||||
/mutex_extra.c (BSD-3-clause)
|
||||
/stm32
|
||||
/usbd*.c (MCD-ST Liberty SW License Agreement V2)
|
||||
/stm32_it.* (MIT + BSD-3-clause)
|
||||
|
@ -78,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
|
||||
|
|
|
@ -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
|
||||
=======================
|
||||
|
@ -119,7 +119,6 @@ In addition, the following ports are provided in this repository:
|
|||
- [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.
|
||||
|
||||
|
|
194
docs/conf.py
194
docs/conf.py
|
@ -19,55 +19,56 @@ import os
|
|||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
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
|
||||
"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"),
|
||||
],
|
||||
'downloads':[
|
||||
('PDF', url_pattern % micropy_version + '/micropython-docs.pdf'),
|
||||
],
|
||||
'is_release': micropy_version != 'latest',
|
||||
"is_release": micropy_version != "latest",
|
||||
}
|
||||
|
||||
|
||||
# -- 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-2023, Damien P. George, Paul Sokolovsky, and contributors"
|
||||
|
||||
# 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 +80,41 @@ version = release = micropy_version
|
|||
|
||||
# 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 +126,148 @@ rst_epilog = """
|
|||
# -- 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
|
||||
# "<project> v<release> 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 <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
# 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': r'\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",
|
||||
"Damien P. George, Paul Sokolovsky, and contributors",
|
||||
"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 +277,17 @@ latex_engine = "xelatex"
|
|||
# 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",
|
||||
["Damien P. George, Paul Sokolovsky, and contributors"],
|
||||
1,
|
||||
),
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
# man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
@ -286,23 +296,29 @@ man_pages = [
|
|||
# (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",
|
||||
"Damien P. George, Paul Sokolovsky, and contributors",
|
||||
"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)}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
>>>
|
||||
|
@ -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:
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -128,7 +128,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 +136,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 +145,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) {
|
||||
|
|
|
@ -83,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);
|
||||
}
|
||||
|
||||
|
@ -262,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 },
|
||||
|
|
|
@ -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 <https://peps.python.org/pep-0570/>`_.
|
||||
|
||||
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<socket.socket>` 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)
|
|
@ -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.
|
||||
|
|
|
@ -101,7 +101,7 @@ A useful function for connecting to your local WiFi network is::
|
|||
print('network config:', wlan.ifconfig())
|
||||
|
||||
Once the network is established the :mod:`socket <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
|
||||
|
@ -128,6 +128,7 @@ The keyword arguments for the constructor defining the PHY type and interface ar
|
|||
|
||||
- mdc=pin-object # set the mdc and mdio pins.
|
||||
- mdio=pin-object
|
||||
- reset=pin-object # set the reset pin of the PHY device.
|
||||
- power=pin-object # set the pin which switches the power of the PHY device.
|
||||
- phy_type=<type> # Select the PHY device type. Supported devices are PHY_LAN8710,
|
||||
PHY_LAN8720, PH_IP101, PHY_RTL8201, PHY_DP83848 and PHY_KSZ8041
|
||||
|
@ -141,7 +142,7 @@ These are working configurations for LAN interfaces of popular 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),
|
||||
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)
|
||||
|
||||
|
@ -330,6 +331,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)
|
||||
----------------------------------
|
||||
|
||||
|
@ -637,15 +651,15 @@ SD card
|
|||
|
||||
See :ref:`machine.SDCard <machine.SDCard>`. ::
|
||||
|
||||
import machine, os
|
||||
import machine, os, vfs
|
||||
|
||||
# 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
|
||||
---
|
||||
|
|
|
@ -201,10 +201,12 @@ class Lock
|
|||
TCP stream connections
|
||||
----------------------
|
||||
|
||||
.. function:: open_connection(host, port)
|
||||
.. 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
|
||||
|
@ -212,12 +214,14 @@ TCP stream connections
|
|||
|
||||
This is a coroutine.
|
||||
|
||||
.. function:: start_server(callback, host, port, backlog=5)
|
||||
.. 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.
|
||||
|
|
|
@ -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''``.
|
||||
|
||||
|
@ -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, /)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -114,7 +114,7 @@ methods to enable over-the-air (OTA) updates.
|
|||
|
||||
These methods implement the simple and :ref:`extended
|
||||
<block-device-interface>` block protocol defined by
|
||||
:class:`os.AbstractBlockDev`.
|
||||
:class:`vfs.AbstractBlockDev`.
|
||||
|
||||
.. method:: Partition.set_boot()
|
||||
|
||||
|
@ -193,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
|
||||
|
@ -226,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.
|
||||
|
@ -264,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.
|
||||
|
@ -290,6 +290,13 @@ 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
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -287,7 +287,7 @@ after reboot/reset). This reduces the reliability of receiving ESP-NOW messages
|
|||
|
||||
.. method:: ESPNow.irecv([timeout_ms])
|
||||
|
||||
Works like `ESPNow.recv()` but will re-use internal bytearrays to store the
|
||||
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.
|
||||
|
||||
|
|
|
@ -103,7 +103,9 @@ the following libraries.
|
|||
micropython.rst
|
||||
neopixel.rst
|
||||
network.rst
|
||||
openamp.rst
|
||||
uctypes.rst
|
||||
vfs.rst
|
||||
|
||||
The following libraries provide drivers for hardware components.
|
||||
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
|
@ -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 <machine.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 <machine.ADC.init>` method.
|
||||
|
|
|
@ -86,7 +86,7 @@ Specific PWM class implementations
|
|||
|
||||
The following concrete class(es) implement enhancements to the PWM class.
|
||||
|
||||
| :ref:`pyb.Timer for PyBoard <pyb.Timer>`
|
||||
| :ref:`pyb.Timer for PyBoard <pyb.Timer>`
|
||||
|
||||
Limitations of PWM
|
||||
------------------
|
||||
|
@ -103,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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -27,10 +27,10 @@ vary from platform to platform.
|
|||
|
||||
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:
|
||||
|
||||
|
|
|
@ -0,0 +1,286 @@
|
|||
.. currentmodule:: machine
|
||||
.. _machine.USBDevice:
|
||||
|
||||
class USBDevice -- USB Device driver
|
||||
====================================
|
||||
|
||||
.. note:: ``machine.USBDevice`` is currently only supported on the rp2 and samd
|
||||
ports.
|
||||
|
||||
USBDevice provides a low-level Python API for implementing USB device functions using
|
||||
Python code. This low-level API assumes familiarity with the USB standard. It's
|
||||
not recommended to use this API directly, instead install the high-level usbd
|
||||
module from micropython-lib.
|
||||
|
||||
.. warning:: This functionality is very new and the high-level usbd module is
|
||||
not yet merged into micropython-lib. It can be found `here on
|
||||
GitHub <https://github.com/micropython/micropython-lib/pull/558>`_.
|
||||
|
||||
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 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 ``boot.py`` file on the :ref:`device VFS
|
||||
<filesystem>`. On each reset this file is executed before the USB subsystem is
|
||||
initialised (and before ``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.
|
||||
|
||||
The callback should return one of the following values:
|
||||
|
||||
- ``False`` to stall the endpoint and reject the transfer.
|
||||
- ``True`` to continue the transfer to the next stage.
|
||||
- A buffer object to provide data for this stage of the transfer.
|
||||
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:: USDBD.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.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.
|
|
@ -265,3 +265,4 @@ Classes
|
|||
machine.WDT.rst
|
||||
machine.SD.rst
|
||||
machine.SDCard.rst
|
||||
machine.USBDevice.rst
|
||||
|
|
|
@ -188,6 +188,11 @@ The following are functions available in the network module.
|
|||
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 <MicroPython port>` 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:: phy_mode([mode])
|
||||
|
|
|
@ -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.
|
|
@ -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 ``'/<name>'`` 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 <block-device-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 <block-device-interface>`.
|
||||
Objects created by this constructor can be mounted using :func:`mount`.
|
||||
See `vfs.VfsLfs2`.
|
||||
|
||||
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.
|
||||
.. class:: VfsPosix(root=None)
|
||||
|
||||
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`.
|
||||
|
|
|
@ -43,7 +43,7 @@ Methods
|
|||
|
||||
These methods implement the simple and :ref:`extended
|
||||
<block-device-interface>` block protocol defined by
|
||||
:class:`os.AbstractBlockDev`.
|
||||
:class:`vfs.AbstractBlockDev`.
|
||||
|
||||
Hardware Note
|
||||
-------------
|
||||
|
|
|
@ -213,11 +213,11 @@ Miscellaneous functions
|
|||
.. 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)``
|
||||
|
|
|
@ -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
|
||||
<https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf>`_.
|
||||
|
||||
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.
|
|
@ -32,5 +32,5 @@ Methods
|
|||
|
||||
These methods implement the simple and extended
|
||||
:ref:`block protocol <block-device-interface>` defined by
|
||||
:class:`os.AbstractBlockDev`.
|
||||
:class:`vfs.AbstractBlockDev`.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -140,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.
|
||||
|
|
|
@ -241,6 +241,7 @@ Classes
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
rp2.DMA.rst
|
||||
rp2.Flash.rst
|
||||
rp2.PIO.rst
|
||||
rp2.StateMachine.rst
|
||||
|
|
|
@ -13,7 +13,7 @@ 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`
|
||||
|
@ -39,6 +39,33 @@ class SSLContext
|
|||
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 <https://wiki.mozilla.org/Security/Cipher_Suites>`_ .
|
||||
|
||||
.. 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),
|
||||
|
@ -77,6 +104,12 @@ class SSLContext
|
|||
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 <mpremote_command_rtc>` or ``ntptime``, and ``server_hostname``
|
||||
must be specified when on the client side.
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ The following data types are supported:
|
|||
+--------+--------------------+-------------------+---------------+
|
||||
| Q | unsigned long long | integer (`1<fn>`) | 8 |
|
||||
+--------+--------------------+-------------------+---------------+
|
||||
| e | n/a (half-float) | float (`2<fn>`) | 2 |
|
||||
+--------+--------------------+-------------------+---------------+
|
||||
| f | float | float (`2<fn>`) | 4 |
|
||||
+--------+--------------------+-------------------+---------------+
|
||||
| d | double | float (`2<fn>`) | 8 |
|
||||
|
|
|
@ -69,7 +69,7 @@ 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)
|
||||
|
||||
|
@ -77,6 +77,9 @@ Constants
|
|||
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"``.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
: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 ``'/<name>'`` 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:: 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 <block-device-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 <block-device-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.
|
|
@ -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)
|
||||
|
|
|
@ -34,5 +34,5 @@ Methods
|
|||
|
||||
These methods implement the simple and extended
|
||||
:ref:`block protocol <block-device-interface>` defined by
|
||||
:class:`os.AbstractBlockDev`.
|
||||
:class:`vfs.AbstractBlockDev`.
|
||||
|
||||
|
|
|
@ -37,4 +37,4 @@ Methods
|
|||
|
||||
These methods implement the simple and extended
|
||||
:ref:`block protocol <block-device-interface>` defined by
|
||||
:class:`os.AbstractBlockDev`.
|
||||
:class:`vfs.AbstractBlockDev`.
|
||||
|
|
|
@ -28,7 +28,7 @@ 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
|
||||
Adafruit Metro M7 - D0/D1 D7/D3 A1/A0
|
||||
Olimex RT1010Py - RxD/TxD D5/D6 -
|
||||
Olimex RT1010Py - RxD/TxD D7/D8 D5/D6
|
||||
Seeed ARCH MIX - J3_19/J3_20 J4_16/J4_17 J4_06/J4_07
|
||||
================= =========== =========== =========== ===========
|
||||
|
||||
|
@ -319,7 +319,7 @@ 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 - -
|
||||
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
|
||||
================= ========================= ======================= ===============
|
||||
|
@ -375,7 +375,7 @@ 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
|
||||
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"
|
||||
|
|
|
@ -92,9 +92,7 @@ Use the :ref:`machine.Pin <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 <machine.Signal>`
|
||||
which can be used to invert a pin. Useful for illuminating active-low LEDs
|
||||
|
@ -146,22 +144,22 @@ handling signal groups. ::
|
|||
from machine import Pin, PWM
|
||||
|
||||
# create PWM object from a pin and set the frequency and duty cycle
|
||||
pwm2 = PWM(Pin(2), freq=2000, duty_u16=32768)
|
||||
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
|
||||
|
||||
|
@ -256,7 +254,7 @@ Use the :ref:`machine.ADC <machine.ADC>` class::
|
|||
|
||||
from machine import ADC
|
||||
|
||||
adc = ADC(Pin(32)) # create ADC object on ADC pin
|
||||
adc = ADC(Pin('A2')) # create ADC object on ADC pin
|
||||
adc.read_u16() # read value, 0-65536 across voltage range 0.0v - 3.3v
|
||||
|
||||
The resolution of the ADC is 12 bit with 10 to 11 bit accuracy, irrespective of the
|
||||
|
@ -274,7 +272,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
|
||||
|
||||
|
@ -303,7 +301,7 @@ 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)
|
||||
|
@ -311,7 +309,7 @@ rates (up to 30Mhz). Hardware SPI is accessed via the
|
|||
For the assignment of Pins to SPI signals, refer to
|
||||
:ref:`Hardware SPI pinout <mimxrt_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.
|
||||
|
||||
Notes:
|
||||
|
@ -331,7 +329,7 @@ accessed via the :ref:`machine.SoftI2C <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
|
||||
|
||||
|
@ -365,7 +363,7 @@ See :ref:`machine.I2S <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
|
||||
|
@ -397,7 +395,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,
|
||||
)
|
||||
|
@ -445,27 +443,27 @@ SD card
|
|||
|
||||
See :ref:`machine.SDCard <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
|
||||
--------------
|
||||
|
@ -475,7 +473,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
|
||||
|
@ -505,12 +503,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)
|
||||
|
|
|
@ -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:/``).
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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**
|
||||
|
|
|
@ -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
|
||||
<os.VfsLfs2>`::
|
||||
<vfs.VfsLfs2>`::
|
||||
|
||||
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 <os.VfsFat>`,
|
||||
:class:`littlefs v1 <os.VfsLfs1>` and :class:`littlefs v2 <os.VfsLfs2>`.
|
||||
MicroPython ports can provide implementations of :class:`FAT <vfs.VfsFat>`,
|
||||
:class:`littlefs v1 <vfs.VfsLfs1>` and :class:`littlefs v2 <vfs.VfsLfs2>`.
|
||||
|
||||
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')
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -31,3 +31,4 @@ implementation and the best practices to use them.
|
|||
asm_thumb2_index.rst
|
||||
filesystem.rst
|
||||
pyboard.py.rst
|
||||
micropython2_migration.rst
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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`
|
|
@ -100,6 +100,8 @@ The full list of supported commands are:
|
|||
command output)
|
||||
- ``port:<path>``: connect to the device with the given path (the first column
|
||||
from the ``connect list`` command output
|
||||
- ``rfc2217://<host>:<port>``: 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
|
||||
|
||||
**Note:** Instead of using the ``connect`` command, there are several
|
||||
|
@ -109,7 +111,7 @@ The full list of supported commands are:
|
|||
|
||||
**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
|
||||
devices). Other types of serial ports will not be auto-detected.
|
||||
|
||||
.. _mpremote_command_disconnect:
|
||||
|
||||
|
|
|
@ -86,7 +86,8 @@ and .mpy version.
|
|||
=================== ============
|
||||
MicroPython release .mpy version
|
||||
=================== ============
|
||||
v1.20 and up 6.1
|
||||
v1.22.0 and up 6.2
|
||||
v1.20 - v1.21.0 6.1
|
||||
v1.19.x 6
|
||||
v1.12 - v1.18 5
|
||||
v1.11 4
|
||||
|
@ -101,6 +102,7 @@ MicroPython repository at which the .mpy version was changed.
|
|||
=================== ========================================
|
||||
.mpy version change Git commit
|
||||
=================== ========================================
|
||||
6.1 to 6.2 6967ff3c581a66f73e9f3d78975f47528db39980
|
||||
6 to 6.1 d94141e1473aebae0d3c63aeaa8397651ad6fa01
|
||||
5 to 6 f2040bfc7ee033e48acef9f289790f3b4e6b74e5
|
||||
4 to 5 5716c5cf65e9b2cb46c2906f40302401bdd27517
|
||||
|
|
|
@ -387,15 +387,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
|
||||
--------------
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
sphinx~=7.2.6
|
||||
sphinxcontrib.jquery==4.1
|
|
@ -17,44 +17,53 @@ 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 -
|
||||
12 PA12 MISO 12 - 2/0 4/0 2/0 0/6
|
||||
42 PB10 MOSI 10 - - 4/2 5/0 0/4
|
||||
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
|
||||
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
|
||||
|
@ -183,10 +192,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
|
||||
|
@ -340,12 +348,12 @@ 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 - -
|
||||
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
|
||||
|
@ -356,17 +364,17 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM
|
|||
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 - - - - - -
|
||||
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 - - - - -
|
||||
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 - -
|
||||
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
|
||||
|
@ -375,21 +383,21 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM
|
|||
10 PA10 FLASH_WP 10 10 - 0/2 2/2 1/0 0/2 1/6
|
||||
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 - - - - -
|
||||
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 -
|
||||
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 - -
|
||||
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 - - - - - - -
|
||||
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
|
||||
=== ==== ============ ==== ==== ==== ====== ====== ===== ===== =====
|
||||
|
||||
|
@ -862,7 +870,7 @@ Adafruit ItsyBitsy M4 Express :ref:`samd51_pinout_table`.
|
|||
|
||||
The default devices at the board are:
|
||||
|
||||
- UART 1 at pins PB23/PB22, labelled RXD/TXD
|
||||
- UART 2 at pins PA13/PA12, labelled RXD/TXD
|
||||
- I2C 5 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
|
||||
|
@ -876,36 +884,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:
|
||||
|
@ -913,17 +921,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 table(num=127, sort=True):
|
||||
pintbl = []
|
||||
inv_bd = {v: k for k, v in Pin.board.__dict__.items()}
|
||||
for i in range(num):
|
||||
try:
|
||||
pintbl.append((i, pininfo(i)))
|
||||
p = Pin(i)
|
||||
pi = pininfo(p)
|
||||
if p in inv_bd.keys():
|
||||
name = inv_bd[p]
|
||||
else:
|
||||
name = ""
|
||||
pintbl.append((i, name, pininfo(i)))
|
||||
except:
|
||||
pass
|
||||
# print("not defined")
|
||||
|
||||
pintbl.sort(key=tblkey)
|
||||
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()
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{% if is_release %}
|
||||
<div class="wy-alert wy-alert-danger">
|
||||
<p>
|
||||
This is the v{{ release }} version of the MicroPython
|
||||
This is the {{ release }} version of the MicroPython
|
||||
documentation. The <a href="/en/latest/{{ pagename }}.html">latest
|
||||
development version</a> of this page may be more current.
|
||||
</p>
|
||||
|
|
|
@ -373,7 +373,7 @@ functions are defined in ``os`` module:
|
|||
Mounts a block device (like an ``SD`` object) in the specified mount
|
||||
point. Example::
|
||||
|
||||
os.mount(sd, '/sd')
|
||||
vfs.mount(sd, '/sd')
|
||||
|
||||
.. function:: unmount(path)
|
||||
|
||||
|
|
|
@ -171,13 +171,13 @@ SD card
|
|||
See :ref:`machine.SD <machine.SD>`. ::
|
||||
|
||||
from machine import SD
|
||||
import os
|
||||
import vfs
|
||||
|
||||
# clock pin, cmd pin, data0 pin
|
||||
sd = SD(pins=('GP10', 'GP11', 'GP15'))
|
||||
# or use default ones for the expansion board
|
||||
sd = SD()
|
||||
os.mount(sd, '/sd')
|
||||
vfs.mount(sd, '/sd')
|
||||
|
||||
WLAN (WiFi)
|
||||
-----------
|
||||
|
|
|
@ -109,12 +109,12 @@ Disk Access
|
|||
|
||||
Use the :ref:`zephyr.DiskAccess <zephyr.DiskAccess>` class to support filesystem::
|
||||
|
||||
import os
|
||||
import vfs
|
||||
from zephyr import DiskAccess
|
||||
|
||||
block_dev = DiskAccess('SDHC') # create a block device object for an SD card
|
||||
os.VfsFat.mkfs(block_dev) # create FAT filesystem object using the disk storage block
|
||||
os.mount(block_dev, '/sd') # mount the filesystem at the SD card subdirectory
|
||||
vfs.VfsFat.mkfs(block_dev) # create FAT filesystem object using the disk storage block
|
||||
vfs.mount(block_dev, '/sd') # mount the filesystem at the SD card subdirectory
|
||||
|
||||
# with the filesystem mounted, files can be manipulated as normal
|
||||
with open('/sd/hello.txt','w') as f: # open a new file in the directory
|
||||
|
@ -126,12 +126,12 @@ Flash Area
|
|||
|
||||
Use the :ref:`zephyr.FlashArea <zephyr.FlashArea>` class to support filesystem::
|
||||
|
||||
import os
|
||||
import vfs
|
||||
from zephyr import FlashArea
|
||||
|
||||
block_dev = FlashArea(4, 4096) # creates a block device object in the frdm-k64f flash scratch partition
|
||||
os.VfsLfs2.mkfs(block_dev) # create filesystem in lfs2 format using the flash block device
|
||||
os.mount(block_dev, '/flash') # mount the filesystem at the flash subdirectory
|
||||
vfs.VfsLfs2.mkfs(block_dev) # create filesystem in lfs2 format using the flash block device
|
||||
vfs.mount(block_dev, '/flash') # mount the filesystem at the flash subdirectory
|
||||
|
||||
# with the filesystem mounted, files can be manipulated as normal
|
||||
with open('/flash/hello.txt','w') as f: # open a new file in the directory
|
||||
|
|
|
@ -6,14 +6,14 @@ Filesystems and Storage
|
|||
Storage modules support virtual filesystem with FAT and littlefs formats, backed by either
|
||||
Zephyr DiskAccess or FlashArea (flash map) APIs depending on which the board supports.
|
||||
|
||||
See `os Filesystem Mounting <https://docs.micropython.org/en/latest/library/os.html?highlight=os#filesystem-mounting>`_.
|
||||
See `vfs Filesystem Mounting <https://docs.micropython.org/en/latest/library/vfs.html?highlight=vfs#filesystem-mounting>`_.
|
||||
|
||||
Disk Access
|
||||
-----------
|
||||
|
||||
The :ref:`zephyr.DiskAccess <zephyr.DiskAccess>` class can be used to access storage devices, such as SD cards.
|
||||
This class uses `Zephyr Disk Access API <https://docs.zephyrproject.org/latest/reference/storage/disk/access.html>`_ and
|
||||
implements the `os.AbstractBlockDev` protocol.
|
||||
implements the `vfs.AbstractBlockDev` protocol.
|
||||
|
||||
For use with SD card controllers, SD cards must be present at boot & not removed; they will
|
||||
be auto detected and initialized by filesystem at boot. Use the disk driver interface and a
|
||||
|
@ -21,11 +21,11 @@ file system to access SD cards via disk access (see below).
|
|||
|
||||
Example usage of FatFS with an SD card on the mimxrt1050_evk board::
|
||||
|
||||
import os
|
||||
import vfs
|
||||
from zephyr import DiskAccess
|
||||
bdev = zephyr.DiskAccess('SDHC') # create block device object using DiskAccess
|
||||
os.VfsFat.mkfs(bdev) # create FAT filesystem object using the disk storage block
|
||||
os.mount(bdev, '/sd') # mount the filesystem at the SD card subdirectory
|
||||
vfs.VfsFat.mkfs(bdev) # create FAT filesystem object using the disk storage block
|
||||
vfs.mount(bdev, '/sd') # mount the filesystem at the SD card subdirectory
|
||||
with open('/sd/hello.txt','w') as f: # open a new file in the directory
|
||||
f.write('Hello world') # write to the file
|
||||
print(open('/sd/hello.txt').read()) # print contents of the file
|
||||
|
@ -39,15 +39,15 @@ customize filesystem configurations. To store persistent data on the device, usi
|
|||
API is recommended (see below).
|
||||
|
||||
This class uses `Zephyr Flash map API <https://docs.zephyrproject.org/latest/reference/storage/flash_map/flash_map.html#>`_ and
|
||||
implements the `os.AbstractBlockDev` protocol.
|
||||
implements the `vfs.AbstractBlockDev` protocol.
|
||||
|
||||
Example usage with the internal flash on the reel_board or the rv32m1_vega_ri5cy board::
|
||||
|
||||
import os
|
||||
import vfs
|
||||
from zephyr import FlashArea
|
||||
bdev = FlashArea(FlashArea.STORAGE, 4096) # create block device object using FlashArea
|
||||
os.VfsLfs2.mkfs(bdev) # create Little filesystem object using the flash area block
|
||||
os.mount(bdev, '/flash') # mount the filesystem at the flash storage subdirectory
|
||||
vfs.VfsLfs2.mkfs(bdev) # create Little filesystem object using the flash area block
|
||||
vfs.mount(bdev, '/flash') # mount the filesystem at the flash storage subdirectory
|
||||
with open('/flash/hello.txt','w') as f: # open a new file in the directory
|
||||
f.write('Hello world') # write to the file
|
||||
print(open('/flash/hello.txt').read()) # print contents of the file
|
||||
|
|
|
@ -49,14 +49,14 @@
|
|||
|
||||
#endif
|
||||
|
||||
STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) {
|
||||
static void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) {
|
||||
mp_hal_pin_write(self->io0, v & 1);
|
||||
mp_hal_pin_write(self->io1, (v >> 1) & 1);
|
||||
mp_hal_pin_write(self->io2, (v >> 2) & 1);
|
||||
mp_hal_pin_write(self->io3, (v >> 3) & 1);
|
||||
}
|
||||
|
||||
STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) {
|
||||
static int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) {
|
||||
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -80,7 +80,7 @@ STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) {
|
|||
return 0; // success
|
||||
}
|
||||
|
||||
STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
static void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
// Will run as fast as possible, limited only by CPU speed and GPIO time
|
||||
mp_hal_pin_input(self->io1);
|
||||
mp_hal_pin_output(self->io0);
|
||||
|
@ -119,7 +119,7 @@ STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const ui
|
|||
}
|
||||
}
|
||||
|
||||
STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) {
|
||||
static void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) {
|
||||
// Make all IO lines input
|
||||
mp_hal_pin_input(self->io2);
|
||||
mp_hal_pin_input(self->io3);
|
||||
|
@ -137,7 +137,7 @@ STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *bu
|
|||
}
|
||||
}
|
||||
|
||||
STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) {
|
||||
static void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) {
|
||||
// Make all IO lines output
|
||||
mp_hal_pin_output(self->io2);
|
||||
mp_hal_pin_output(self->io3);
|
||||
|
@ -158,7 +158,7 @@ STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint
|
|||
//mp_hal_pin_input(self->io1);
|
||||
}
|
||||
|
||||
STATIC int mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
|
||||
static int mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
|
||||
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
|
||||
uint32_t cmd_buf = cmd | data << 8;
|
||||
CS_LOW(self);
|
||||
|
@ -167,7 +167,7 @@ STATIC int mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, u
|
|||
return 0;
|
||||
}
|
||||
|
||||
STATIC int mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
static int mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
|
||||
uint8_t cmd_buf[5] = {cmd};
|
||||
uint8_t addr_len = mp_spi_set_addr_buff(&cmd_buf[1], addr);
|
||||
|
@ -178,7 +178,7 @@ STATIC int mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
STATIC int mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len, uint32_t *dest) {
|
||||
static int mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len, uint32_t *dest) {
|
||||
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
|
||||
uint32_t cmd_buf = cmd;
|
||||
CS_LOW(self);
|
||||
|
@ -188,7 +188,7 @@ STATIC int mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len, uint32_
|
|||
return 0;
|
||||
}
|
||||
|
||||
STATIC int mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
|
||||
static int mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
|
||||
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
|
||||
uint8_t cmd_buf[7] = {cmd};
|
||||
uint8_t addr_len = mp_spi_set_addr_buff(&cmd_buf[1], addr);
|
||||
|
|
|
@ -49,9 +49,9 @@ extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
|
|||
#include "uart.h"
|
||||
|
||||
// Provided by the port.
|
||||
extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj;
|
||||
extern machine_uart_obj_t mp_bluetooth_hci_uart_obj;
|
||||
|
||||
STATIC void cywbt_wait_cts_low(void) {
|
||||
static void cywbt_wait_cts_low(void) {
|
||||
mp_hal_pin_config(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
||||
for (int i = 0; i < 200; ++i) {
|
||||
if (mp_hal_pin_read(CYW43_PIN_BT_CTS) == 0) {
|
||||
|
@ -64,11 +64,11 @@ STATIC void cywbt_wait_cts_low(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
||||
static int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
||||
mp_bluetooth_hci_uart_write((void *)buf, len);
|
||||
for (int c, i = 0; i < 6; ++i) {
|
||||
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
buf[i] = c;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
|||
int sz = buf[2] - 3;
|
||||
for (int c, i = 0; i < sz; ++i) {
|
||||
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
buf[i] = c;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
STATIC int cywbt_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) {
|
||||
static int cywbt_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) {
|
||||
uint8_t *buf = mp_bluetooth_hci_cmd_buf;
|
||||
buf[0] = 0x01;
|
||||
buf[1] = ocf;
|
||||
|
@ -108,19 +108,19 @@ STATIC int cywbt_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *para
|
|||
return cywbt_hci_cmd_raw(4 + param_len, buf);
|
||||
}
|
||||
|
||||
STATIC void put_le16(uint8_t *buf, uint16_t val) {
|
||||
static void put_le16(uint8_t *buf, uint16_t val) {
|
||||
buf[0] = val;
|
||||
buf[1] = val >> 8;
|
||||
}
|
||||
|
||||
STATIC void put_le32(uint8_t *buf, uint32_t val) {
|
||||
static void put_le32(uint8_t *buf, uint32_t val) {
|
||||
buf[0] = val;
|
||||
buf[1] = val >> 8;
|
||||
buf[2] = val >> 16;
|
||||
buf[3] = val >> 24;
|
||||
}
|
||||
|
||||
STATIC int cywbt_set_baudrate(uint32_t baudrate) {
|
||||
static int cywbt_set_baudrate(uint32_t baudrate) {
|
||||
uint8_t buf[6];
|
||||
put_le16(buf, 0);
|
||||
put_le32(buf + 2, baudrate);
|
||||
|
@ -128,7 +128,7 @@ STATIC int cywbt_set_baudrate(uint32_t baudrate) {
|
|||
}
|
||||
|
||||
// download firmware
|
||||
STATIC int cywbt_download_firmware(const uint8_t *firmware) {
|
||||
static int cywbt_download_firmware(const uint8_t *firmware) {
|
||||
cywbt_hci_cmd(0x3f, 0x2e, 0, NULL);
|
||||
|
||||
bool last_packet = false;
|
||||
|
@ -255,7 +255,7 @@ int mp_bluetooth_hci_controller_deinit(void) {
|
|||
}
|
||||
|
||||
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||
STATIC uint32_t bt_sleep_ticks;
|
||||
static uint32_t bt_sleep_ticks;
|
||||
#endif
|
||||
|
||||
int mp_bluetooth_hci_controller_sleep_maybe(void) {
|
||||
|
|
|
@ -29,7 +29,10 @@
|
|||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/machine_pulse.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_PULSE
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
#include "drivers/dht/dht.h"
|
||||
|
||||
// Allow the open-drain-high call to be DHT specific for ports that need it
|
||||
|
@ -37,7 +40,7 @@
|
|||
#define mp_hal_pin_od_high_dht mp_hal_pin_od_high
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) {
|
||||
static mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) {
|
||||
mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(pin_in);
|
||||
mp_hal_pin_open_drain(pin);
|
||||
|
||||
|
@ -92,3 +95,5 @@ timeout:
|
|||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(dht_readinto_obj, dht_readinto);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_PULSE
|
||||
|
|
|
@ -34,23 +34,24 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "modmachine.h"
|
||||
#include "extmod/machine_spi.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "extmod/modmachine.h"
|
||||
#ifdef MICROPY_HW_WIFI_LED
|
||||
#include "led.h"
|
||||
#endif
|
||||
|
||||
#include "esp_hosted_hal.h"
|
||||
#include "esp_hosted_wifi.h"
|
||||
|
||||
#ifndef MICROPY_HW_WIFI_IRQ
|
||||
#define MICROPY_HW_WIFI_IRQ MICROPY_HW_WIFI_HANDSHAKE
|
||||
#endif
|
||||
extern void mod_network_poll_events(void);
|
||||
|
||||
STATIC mp_obj_t esp_hosted_pin_irq_callback(mp_obj_t self_in) {
|
||||
extern void mod_network_poll_events(void);
|
||||
static mp_obj_t esp_hosted_pin_irq_callback(mp_obj_t self_in) {
|
||||
#ifdef MICROPY_HW_WIFI_LED
|
||||
led_toggle(MICROPY_HW_WIFI_LED);
|
||||
#endif
|
||||
mod_network_poll_events();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_hosted_pin_irq_callback_obj, esp_hosted_pin_irq_callback);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(esp_hosted_pin_irq_callback_obj, esp_hosted_pin_irq_callback);
|
||||
|
||||
MP_WEAK int esp_hosted_hal_init(uint32_t mode) {
|
||||
// Perform a hard reset and set pins to their defaults.
|
||||
|
@ -64,34 +65,16 @@ MP_WEAK int esp_hosted_hal_init(uint32_t mode) {
|
|||
mp_hal_pin_input(MICROPY_HW_WIFI_HANDSHAKE);
|
||||
mp_hal_pin_input(MICROPY_HW_WIFI_DATAREADY);
|
||||
|
||||
// Enable Pin-IRQ for the handshake PIN to call esp_hosted_wifi_poll()
|
||||
mp_obj_t irq_rising_attr[2];
|
||||
mp_load_method_maybe((mp_obj_t)MICROPY_HW_WIFI_IRQ, MP_QSTR_IRQ_RISING, irq_rising_attr);
|
||||
|
||||
if (irq_rising_attr[0] != MP_OBJ_NULL && irq_rising_attr[1] == MP_OBJ_NULL) { // value for IRQ rising found
|
||||
mp_obj_t pin_args[] = {
|
||||
NULL, // Method pointer
|
||||
(mp_obj_t)MICROPY_HW_WIFI_IRQ, // Pin object
|
||||
(mp_obj_t)&esp_hosted_pin_irq_callback_obj, // Callback function object
|
||||
NULL, // The Rising edge value is set below.
|
||||
mp_const_true, // Hard IRQ, since the actual polling is scheduled.
|
||||
};
|
||||
pin_args[3] = irq_rising_attr[0];
|
||||
mp_load_method_maybe((mp_obj_t)MICROPY_HW_WIFI_IRQ, MP_QSTR_irq, pin_args);
|
||||
if (pin_args[0] != MP_OBJ_NULL && pin_args[1] != MP_OBJ_NULL) {
|
||||
mp_call_method_n_kw(3, 0, pin_args);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize SPI.
|
||||
mp_obj_t args[] = {
|
||||
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_ID),
|
||||
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_BAUDRATE),
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_phase), MP_OBJ_NEW_SMALL_INT(0),
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_polarity), MP_OBJ_NEW_SMALL_INT(1),
|
||||
};
|
||||
|
||||
MP_STATE_PORT(mp_wifi_spi) =
|
||||
MP_OBJ_TYPE_GET_SLOT(&machine_spi_type, make_new)((mp_obj_t)&machine_spi_type, 2, 1, args);
|
||||
MP_OBJ_TYPE_GET_SLOT(&machine_spi_type, make_new)((mp_obj_t)&machine_spi_type, 2, 2, args);
|
||||
|
||||
// SPI might change the direction/mode of CS pin,
|
||||
// set it to GPIO again just in case.
|
||||
|
@ -101,16 +84,8 @@ MP_WEAK int esp_hosted_hal_init(uint32_t mode) {
|
|||
}
|
||||
|
||||
MP_WEAK int esp_hosted_hal_deinit(void) {
|
||||
// Disable Pin-IRQ for the handshake PIN
|
||||
mp_obj_t pin_args[] = {
|
||||
NULL, // Method pointer
|
||||
(mp_obj_t)MICROPY_HW_WIFI_IRQ, // Pin object
|
||||
mp_const_none // Set to None
|
||||
};
|
||||
mp_load_method_maybe((mp_obj_t)MICROPY_HW_WIFI_IRQ, MP_QSTR_irq, pin_args);
|
||||
if (pin_args[0] && pin_args[1]) {
|
||||
mp_call_method_n_kw(1, 0, pin_args);
|
||||
}
|
||||
// Disable pin IRQ.
|
||||
esp_hosted_hal_irq_enable(false);
|
||||
|
||||
// Remove all network interfaces and reset wifi state.
|
||||
esp_hosted_wifi_deinit();
|
||||
|
@ -134,6 +109,43 @@ MP_WEAK int esp_hosted_hal_deinit(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
MP_WEAK void esp_hosted_hal_irq_enable(bool enable) {
|
||||
#ifdef MICROPY_HW_WIFI_IRQ_PIN
|
||||
// Disable Pin-IRQ for the handshake PIN
|
||||
mp_obj_t pin_args[] = {
|
||||
NULL, // Method pointer
|
||||
(mp_obj_t)MICROPY_HW_WIFI_IRQ_PIN, // Pin object
|
||||
mp_const_none // Set to None
|
||||
};
|
||||
mp_load_method_maybe((mp_obj_t)MICROPY_HW_WIFI_IRQ_PIN, MP_QSTR_irq, pin_args);
|
||||
if (pin_args[0] && pin_args[1]) {
|
||||
mp_call_method_n_kw(1, 0, pin_args);
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
// Enable Pin-IRQ for the handshake PIN to call esp_hosted_wifi_poll()
|
||||
mp_obj_t irq_rising_attr[2];
|
||||
mp_load_method_maybe((mp_obj_t)MICROPY_HW_WIFI_IRQ_PIN, MP_QSTR_IRQ_RISING, irq_rising_attr);
|
||||
|
||||
if (irq_rising_attr[0] != MP_OBJ_NULL && irq_rising_attr[1] == MP_OBJ_NULL) {
|
||||
// value for IRQ rising found
|
||||
mp_obj_t pin_args[] = {
|
||||
NULL, // Method pointer
|
||||
(mp_obj_t)MICROPY_HW_WIFI_IRQ_PIN, // Pin object
|
||||
(mp_obj_t)&esp_hosted_pin_irq_callback_obj, // Callback function object
|
||||
NULL, // The Rising edge value is set below.
|
||||
mp_const_true, // Hard IRQ, since the actual polling is scheduled.
|
||||
};
|
||||
pin_args[3] = irq_rising_attr[0];
|
||||
mp_load_method_maybe((mp_obj_t)MICROPY_HW_WIFI_IRQ_PIN, MP_QSTR_irq, pin_args);
|
||||
if (pin_args[0] != MP_OBJ_NULL && pin_args[1] != MP_OBJ_NULL) {
|
||||
mp_call_method_n_kw(3, 0, pin_args);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MP_WEAK int esp_hosted_hal_atomic_enter(void) {
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
mp_sched_lock();
|
||||
|
@ -149,7 +161,7 @@ MP_WEAK int esp_hosted_hal_atomic_exit(void) {
|
|||
}
|
||||
|
||||
MP_WEAK bool esp_hosted_hal_data_ready(void) {
|
||||
return mp_hal_pin_read(MICROPY_HW_WIFI_DATAREADY) && mp_hal_pin_read(MICROPY_HW_WIFI_HANDSHAKE);
|
||||
return mp_hal_pin_read(MICROPY_HW_WIFI_DATAREADY);
|
||||
}
|
||||
|
||||
MP_WEAK int esp_hosted_hal_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) {
|
||||
|
@ -158,7 +170,8 @@ MP_WEAK int esp_hosted_hal_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf,
|
|||
|
||||
// Wait for handshake pin to go high.
|
||||
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(1)) {
|
||||
if (mp_hal_pin_read(MICROPY_HW_WIFI_HANDSHAKE)) {
|
||||
if (mp_hal_pin_read(MICROPY_HW_WIFI_HANDSHAKE) &&
|
||||
(rx_buf == NULL || mp_hal_pin_read(MICROPY_HW_WIFI_DATAREADY))) {
|
||||
break;
|
||||
}
|
||||
if ((mp_hal_ticks_ms() - start) >= 1000) {
|
||||
|
@ -171,6 +184,11 @@ MP_WEAK int esp_hosted_hal_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf,
|
|||
mp_hal_delay_us(10);
|
||||
spi_proto->transfer(mp_wifi_spi, size, tx_buf, rx_buf);
|
||||
mp_hal_pin_write(MICROPY_HW_WIFI_SPI_CS, 1);
|
||||
mp_hal_delay_us(100);
|
||||
|
||||
if (esp_hosted_hal_data_ready()) {
|
||||
mod_network_poll_events();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ typedef enum {
|
|||
// Note A default machine-based implementation is provided in esp_hosted_hal.c.
|
||||
int esp_hosted_hal_init(uint32_t mode);
|
||||
int esp_hosted_hal_deinit(void);
|
||||
void esp_hosted_hal_irq_enable(bool enable);
|
||||
bool esp_hosted_hal_data_ready(void);
|
||||
int esp_hosted_hal_atomic_enter(void);
|
||||
int esp_hosted_hal_atomic_exit(void);
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
#ifndef MICROPY_INCLUDED_DRIVERS_ESP_HOSTED_INTERNAL_H
|
||||
#define MICROPY_INCLUDED_DRIVERS_ESP_HOSTED_INTERNAL_H
|
||||
|
||||
#define ESP_HOSTED_DEBUG (0)
|
||||
|
||||
#define ESP_FRAME_MAX_SIZE (1600)
|
||||
#define ESP_FRAME_MAX_PAYLOAD (ESP_FRAME_MAX_SIZE - sizeof(esp_header_t))
|
||||
#define ESP_FRAME_FLAGS_FRAGMENT (1 << 0)
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
static err_t netif_struct_init(struct netif *netif) {
|
||||
netif->linkoutput = esp_hosted_netif_output;
|
||||
netif->output = etharp_output;
|
||||
netif->mtu = 1500;
|
||||
netif->mtu = ESP_FRAME_MAX_PAYLOAD;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
|
||||
esp_hosted_wifi_get_mac(netif->name[1] - '0', netif->hwaddr);
|
||||
netif->hwaddr_len = sizeof(netif->hwaddr);
|
||||
|
|
|
@ -476,6 +476,10 @@ int esp_hosted_wifi_init(uint32_t itf) {
|
|||
esp_hosted_netif_init(&esp_state, itf);
|
||||
info_printf("esp_hosted_init() initialized itf %lu\n", itf);
|
||||
}
|
||||
|
||||
// Re/enable IRQ pin.
|
||||
esp_hosted_hal_irq_enable(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,21 +56,21 @@
|
|||
#define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer
|
||||
#define SECTOR_SIZE MP_SPIFLASH_ERASE_BLOCK_SIZE
|
||||
|
||||
STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) {
|
||||
static void mp_spiflash_acquire_bus(mp_spiflash_t *self) {
|
||||
const mp_spiflash_config_t *c = self->config;
|
||||
if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) {
|
||||
c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_ACQUIRE);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) {
|
||||
static void mp_spiflash_release_bus(mp_spiflash_t *self) {
|
||||
const mp_spiflash_config_t *c = self->config;
|
||||
if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) {
|
||||
c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) {
|
||||
static int mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) {
|
||||
int ret = 0;
|
||||
const mp_spiflash_config_t *c = self->config;
|
||||
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
|
||||
|
@ -84,7 +84,7 @@ STATIC int mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t l
|
|||
return ret;
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_transfer_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
static int mp_spiflash_transfer_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
int ret = 0;
|
||||
const mp_spiflash_config_t *c = self->config;
|
||||
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
|
||||
|
@ -109,7 +109,7 @@ STATIC int mp_spiflash_transfer_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t *dest) {
|
||||
static int mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t *dest) {
|
||||
const mp_spiflash_config_t *c = self->config;
|
||||
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
|
||||
mp_hal_pin_write(c->bus.u_spi.cs, 0);
|
||||
|
@ -122,7 +122,7 @@ STATIC int mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len, ui
|
|||
}
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
|
||||
static int mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
|
||||
const mp_spiflash_config_t *c = self->config;
|
||||
uint8_t cmd;
|
||||
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
|
||||
|
@ -133,11 +133,11 @@ STATIC int mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len,
|
|||
return mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, NULL, dest);
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) {
|
||||
static int mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) {
|
||||
return mp_spiflash_write_cmd_data(self, cmd, 0, 0);
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) {
|
||||
static int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) {
|
||||
do {
|
||||
uint32_t sr;
|
||||
int ret = mp_spiflash_read_cmd(self, CMD_RDSR, 1, &sr);
|
||||
|
@ -152,11 +152,11 @@ STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, u
|
|||
return -MP_ETIMEDOUT;
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_wait_wel1(mp_spiflash_t *self) {
|
||||
static int mp_spiflash_wait_wel1(mp_spiflash_t *self) {
|
||||
return mp_spiflash_wait_sr(self, 2, 2, WAIT_SR_TIMEOUT);
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_wait_wip0(mp_spiflash_t *self) {
|
||||
static int mp_spiflash_wait_wip0(mp_spiflash_t *self) {
|
||||
return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT);
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ void mp_spiflash_deepsleep(mp_spiflash_t *self, int value) {
|
|||
}
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) {
|
||||
static int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) {
|
||||
int ret = 0;
|
||||
// enable writes
|
||||
ret = mp_spiflash_write_cmd(self, CMD_WREN);
|
||||
|
@ -244,7 +244,7 @@ STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr)
|
|||
return mp_spiflash_wait_wip0(self);
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
static int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
int ret = 0;
|
||||
// enable writes
|
||||
ret = mp_spiflash_write_cmd(self, CMD_WREN);
|
||||
|
@ -361,7 +361,7 @@ int mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint
|
|||
return ret;
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_cache_flush_internal(mp_spiflash_t *self) {
|
||||
static int mp_spiflash_cache_flush_internal(mp_spiflash_t *self) {
|
||||
#if USE_WR_DELAY
|
||||
if (!(self->flags & 1)) {
|
||||
return 0;
|
||||
|
@ -396,7 +396,7 @@ int mp_spiflash_cache_flush(mp_spiflash_t *self) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
static int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
|
||||
// Align to 4096 sector
|
||||
uint32_t offset = addr & 0xfff;
|
||||
uint32_t sec = addr >> 12;
|
||||
|
|
|
@ -42,9 +42,13 @@
|
|||
|
||||
#define NINA_GPIO_MODE (0x50)
|
||||
#define NINA_GPIO_READ (0x53)
|
||||
#define NINA_GPIO_READ_ANALOG (0x54)
|
||||
#define NINA_GPIO_WRITE (0x51)
|
||||
#define NINA_GPIO_IS_INPUT_ONLY(p) ((p >= 34 && p <= 36) || (p == 39))
|
||||
#define NINA_GPIO_IS_INPUT_ONLY(p) ((p >= 3 && p <= 6))
|
||||
#define NINA_GPIO_IS_ADC_CHANNEL(p) ((p >= 3 && p <= 6))
|
||||
|
||||
// This maps logical pin ID (0..MICROPY_HW_PIN_EXT_COUNT) to
|
||||
// physical pins on the Nina module.
|
||||
static uint8_t pin_map[MICROPY_HW_PIN_EXT_COUNT] = {
|
||||
27, // LEDR
|
||||
25, // LEDG
|
||||
|
@ -55,10 +59,30 @@ static uint8_t pin_map[MICROPY_HW_PIN_EXT_COUNT] = {
|
|||
35, // A7
|
||||
};
|
||||
|
||||
// This maps logical pin ID (0..MICROPY_HW_PIN_EXT_COUNT) to
|
||||
// ADC channel numbers on the Nina module.
|
||||
static uint8_t adc_map[MICROPY_HW_PIN_EXT_COUNT] = {
|
||||
-1, // LEDR
|
||||
-1, // LEDG
|
||||
-1, // LEDB
|
||||
6, // A4
|
||||
3, // A5
|
||||
0, // A6
|
||||
7, // A7
|
||||
};
|
||||
|
||||
void machine_pin_ext_init(void) {
|
||||
nina_init();
|
||||
}
|
||||
|
||||
bool machine_pin_ext_is_adc_channel(const machine_pin_obj_t *self) {
|
||||
return NINA_GPIO_IS_ADC_CHANNEL(self->id);
|
||||
}
|
||||
|
||||
uint32_t machine_pin_ext_to_adc_channel(const machine_pin_obj_t *self) {
|
||||
return adc_map[self->id];
|
||||
}
|
||||
|
||||
void machine_pin_ext_set(machine_pin_obj_t *self, bool value) {
|
||||
if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
|
||||
uint8_t buf[] = {pin_map[self->id], value};
|
||||
|
@ -76,8 +100,14 @@ bool machine_pin_ext_get(machine_pin_obj_t *self) {
|
|||
return value;
|
||||
}
|
||||
|
||||
uint16_t machine_pin_ext_read_u16(uint32_t channel) {
|
||||
uint16_t buf = channel;
|
||||
nina_ioctl(NINA_GPIO_READ_ANALOG, sizeof(buf), (uint8_t *)&buf, 0);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) {
|
||||
if (mode == MACHINE_PIN_MODE_IN) {
|
||||
if (mode == MACHINE_PIN_MODE_IN || mode == MACHINE_PIN_MODE_ANALOG) {
|
||||
mode = NINA_GPIO_INPUT;
|
||||
self->is_output = false;
|
||||
} else if (mode == MACHINE_PIN_MODE_OUT) {
|
||||
|
@ -89,7 +119,7 @@ void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) {
|
|||
if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
|
||||
uint8_t buf[] = {pin_map[self->id], mode};
|
||||
if (mode == NINA_GPIO_OUTPUT) {
|
||||
if (NINA_GPIO_IS_INPUT_ONLY(buf[0])) {
|
||||
if (NINA_GPIO_IS_INPUT_ONLY(self->id)) {
|
||||
mp_raise_ValueError("only Pin.IN is supported for this pin");
|
||||
}
|
||||
machine_pin_ext_set(self, value);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue