mirror of
https://github.com/micropython/micropython.git
synced 2025-08-23 19:10:30 +02:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8cd15829e2 | ||
|
ee3c9ccb54 | ||
|
e72d03855e | ||
|
02df2b09d4 | ||
|
e7ff724a87 | ||
|
cc7cfc7e8d | ||
|
b979c5a92a | ||
|
f53ee9f12b | ||
|
2531a15200 | ||
|
8b6e89a8ca | ||
|
a2e9ab362b | ||
|
1e8cc6c503 | ||
|
4c7d955a62 | ||
|
068aa28fc5 | ||
|
d5f3fcd935 | ||
|
9b8c64c9ce | ||
|
ac5e0b9f62 | ||
|
61b8361f5f | ||
|
4b4f6011e8 |
@@ -1,12 +1,3 @@
|
||||
# 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
|
||||
|
||||
|
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
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.
|
107
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
107
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,107 +0,0 @@
|
||||
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.
|
16
.github/ISSUE_TEMPLATE/documentation.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/documentation.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
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.
|
44
.github/ISSUE_TEMPLATE/documentation.yml
vendored
44
.github/ISSUE_TEMPLATE/documentation.yml
vendored
@@ -1,44 +0,0 @@
|
||||
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.
|
24
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
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.
|
65
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
65
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,65 +0,0 @@
|
||||
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.
|
16
.github/ISSUE_TEMPLATE/security.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/security.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
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.
|
59
.github/ISSUE_TEMPLATE/security.yml
vendored
59
.github/ISSUE_TEMPLATE/security.yml
vendored
@@ -1,59 +0,0 @@
|
||||
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
|
16
.github/workflows/biome.yml
vendored
16
.github/workflows/biome.yml
vendored
@@ -1,16 +0,0 @@
|
||||
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
|
10
.github/workflows/code_formatting.yml
vendored
10
.github/workflows/code_formatting.yml
vendored
@@ -18,3 +18,13 @@ jobs:
|
||||
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@v5
|
||||
- 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
|
||||
|
6
.github/workflows/code_size.yml
vendored
6
.github/workflows/code_size.yml
vendored
@@ -8,15 +8,9 @@ on:
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'shared/**'
|
||||
- 'lib/**'
|
||||
- 'ports/bare-arm/**'
|
||||
- 'ports/mimxrt/**'
|
||||
- 'ports/minimal/**'
|
||||
- 'ports/rp2/**'
|
||||
- 'ports/samd/**'
|
||||
- 'ports/stm32/**'
|
||||
- 'ports/unix/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
13
.github/workflows/codespell.yml
vendored
13
.github/workflows/codespell.yml
vendored
@@ -1,13 +0,0 @@
|
||||
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
|
||||
|
2
.github/workflows/ports_esp32.yml
vendored
2
.github/workflows/ports_esp32.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
- name: Cached ESP-IDF install
|
||||
id: cache_esp_idf
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./esp-idf/
|
||||
|
5
.github/workflows/ports_mimxrt.yml
vendored
5
.github/workflows/ports_mimxrt.yml
vendored
@@ -20,13 +20,8 @@ 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
|
||||
|
5
.github/workflows/ports_rp2.yml
vendored
5
.github/workflows/ports_rp2.yml
vendored
@@ -20,13 +20,8 @@ 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
|
||||
|
1
.github/workflows/ports_stm32.yml
vendored
1
.github/workflows/ports_stm32.yml
vendored
@@ -25,7 +25,6 @@ jobs:
|
||||
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
|
||||
|
3
.github/workflows/ports_unix.yml
vendored
3
.github/workflows/ports_unix.yml
vendored
@@ -88,11 +88,10 @@ jobs:
|
||||
(cd ports/unix && gcov -o build-coverage/py ../../py/*.c || true)
|
||||
(cd ports/unix && gcov -o build-coverage/extmod ../../extmod/*.c || true)
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
129
.github/workflows/ports_windows.yml
vendored
129
.github/workflows/ports_windows.yml
vendored
@@ -18,134 +18,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
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:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
4
.github/workflows/ruff.yml
vendored
4
.github/workflows/ruff.yml
vendored
@@ -1,13 +1,11 @@
|
||||
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
||||
name: Python code lint and formatting with ruff
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ruff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# ruff version should be kept in sync with .pre-commit-config.yaml
|
||||
- run: pip install --user ruff==0.1.3
|
||||
- run: ruff check --output-format=github .
|
||||
- run: ruff format --diff .
|
||||
|
11
.gitmodules
vendored
11
.gitmodules
vendored
@@ -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/micropython/berkeley-db-1.xx
|
||||
url = https://github.com/pfalcon/berkeley-db-1.xx
|
||||
[submodule "lib/stm32lib"]
|
||||
path = lib/stm32lib
|
||||
url = https://github.com/micropython/stm32lib
|
||||
@@ -59,12 +59,3 @@
|
||||
[submodule "lib/protobuf-c"]
|
||||
path = lib/protobuf-c
|
||||
url = https://github.com/protobuf-c/protobuf-c.git
|
||||
[submodule "lib/open-amp"]
|
||||
path = lib/open-amp
|
||||
url = https://github.com/OpenAMP/open-amp.git
|
||||
[submodule "lib/libmetal"]
|
||||
path = lib/libmetal
|
||||
url = https://github.com/OpenAMP/libmetal.git
|
||||
[submodule "lib/arduino-lib"]
|
||||
path = lib/arduino-lib
|
||||
url = https://github.com/arduino/arduino-lib-mpy.git
|
||||
|
@@ -12,16 +12,7 @@ repos:
|
||||
verbose: true
|
||||
stages: [commit-msg]
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# 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
|
||||
|
@@ -104,22 +104,6 @@ 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
|
||||
==========================
|
||||
|
||||
|
4
LICENSE
4
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2024 Damien P. George
|
||||
Copyright (c) 2013-2023 Damien P. George
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -48,14 +48,12 @@ 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)
|
||||
|
@@ -68,7 +68,7 @@ master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = "MicroPython"
|
||||
copyright = "- The MicroPython Documentation is Copyright © 2014-2024, Damien P. George, Paul Sokolovsky, and contributors"
|
||||
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
|
||||
|
@@ -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_proto_fun(cm.rc, cm.context, NULL);
|
||||
return mp_make_function_from_raw_code(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.
|
||||
>>>
|
||||
|
@@ -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) {
|
||||
|
@@ -33,7 +33,7 @@ Variables
|
||||
MicroPython processes local and global variables differently. Global variables
|
||||
are stored and looked up from a global dictionary that is allocated on the heap
|
||||
(note that each module has its own separate dict, so separate namespace).
|
||||
Local variables on the other hand are stored on the Python value stack, which may
|
||||
Local variables on the other hand are are stored on the Python value stack, which may
|
||||
live on the C stack or on the heap. They are accessed directly by their offset
|
||||
within the Python stack, which is more efficient than a global lookup in a dict.
|
||||
|
||||
|
@@ -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(qstr filename) {
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *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 },
|
||||
|
@@ -1,33 +0,0 @@
|
||||
.. 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.
|
||||
|
@@ -18,9 +18,6 @@ working with this board it may be useful to get an overview of the microcontroll
|
||||
general.rst
|
||||
tutorial/index.rst
|
||||
|
||||
Note that there are several varieties of ESP32 -- ESP32, ESP32C3, ESP32S2, ESP32S3 --
|
||||
supported by MicroPython, with some differences in functionality between them.
|
||||
|
||||
Installing MicroPython
|
||||
----------------------
|
||||
|
||||
@@ -61,18 +58,12 @@ The :mod:`esp32` module::
|
||||
import esp32
|
||||
|
||||
esp32.raw_temperature() # read the internal temperature of the MCU, in Fahrenheit
|
||||
esp32.ULP() # access to the Ultra-Low-Power Co-processor, not on ESP32C3
|
||||
esp32.ULP() # access to the Ultra-Low-Power Co-processor
|
||||
|
||||
Note that the temperature sensor in the ESP32 will typically read higher than
|
||||
ambient due to the IC getting warm while it runs. This effect can be minimised
|
||||
by reading the temperature sensor immediately after waking up from sleep.
|
||||
|
||||
ESP32C3, ESP32S2, and ESP32S3 also have an internal temperature sensor available.
|
||||
It is implemented a bit differently to the ESP32 and returns the temperature in
|
||||
Celsius::
|
||||
|
||||
esp32.mcu_temperature() # read the internal temperature of the MCU, in Celsius
|
||||
|
||||
Networking
|
||||
----------
|
||||
|
||||
@@ -137,7 +128,6 @@ 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
|
||||
@@ -660,15 +650,15 @@ SD card
|
||||
|
||||
See :ref:`machine.SDCard <machine.SDCard>`. ::
|
||||
|
||||
import machine, os, vfs
|
||||
import machine, os
|
||||
|
||||
# Slot 2 uses pins sck=18, cs=5, miso=19, mosi=23
|
||||
sd = machine.SDCard(slot=2)
|
||||
vfs.mount(sd, '/sd') # mount
|
||||
os.mount(sd, '/sd') # mount
|
||||
|
||||
os.listdir('/sd') # list directory contents
|
||||
|
||||
vfs.umount('/sd') # eject
|
||||
os.umount('/sd') # eject
|
||||
|
||||
RMT
|
||||
---
|
||||
|
@@ -149,7 +149,8 @@ class ThreadSafeFlag
|
||||
|
||||
Create a new flag which can be used to synchronise a task with code running
|
||||
outside the asyncio loop, such as other threads, IRQs, or scheduler
|
||||
callbacks. Flags start in the cleared state.
|
||||
callbacks. Flags start in the cleared state. The class does not currently
|
||||
work under the Unix build of MicroPython.
|
||||
|
||||
.. method:: ThreadSafeFlag.set()
|
||||
|
||||
|
@@ -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 reused. This allows a
|
||||
to the previous call to ``gap_advertise`` will be re-used. This allows a
|
||||
broadcaster to resume advertising with just ``gap_advertise(interval_us)``.
|
||||
To clear the advertising payload pass an empty ``bytes``, i.e. ``b''``.
|
||||
|
||||
@@ -722,7 +722,7 @@ Pairing and bonding
|
||||
and ``_IRQ_SET_SECRET`` events.
|
||||
|
||||
**Note:** This is currently only supported when using the NimBLE stack on
|
||||
ESP32, STM32 and Unix.
|
||||
STM32 and Unix (not ESP32).
|
||||
|
||||
.. method:: BLE.gap_pair(conn_handle, /)
|
||||
|
||||
|
@@ -18,9 +18,7 @@ Classes
|
||||
appends and pops from either side of the deque. New deques are created
|
||||
using the following arguments:
|
||||
|
||||
- *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.
|
||||
- *iterable* must be the empty tuple, and the new deque is created 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
|
||||
@@ -28,37 +26,18 @@ Classes
|
||||
|
||||
- The optional *flags* can be 1 to check for overflow when adding items.
|
||||
|
||||
Deque objects support `bool`, `len`, iteration and subscript load and store.
|
||||
They also have the following methods:
|
||||
As well as supporting `bool` and `len`, deque objects 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 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.
|
||||
Raises IndexError if overflow checking is enabled and there is no more room left.
|
||||
|
||||
.. method:: deque.popleft()
|
||||
|
||||
Remove and return an item from the left side of the deque.
|
||||
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.
|
||||
Raises IndexError if no items are present.
|
||||
|
||||
.. function:: namedtuple(name, fields)
|
||||
|
||||
|
@@ -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:`vfs.AbstractBlockDev`.
|
||||
:class:`os.AbstractBlockDev`.
|
||||
|
||||
.. method:: Partition.set_boot()
|
||||
|
||||
|
@@ -103,9 +103,7 @@ the following libraries.
|
||||
micropython.rst
|
||||
neopixel.rst
|
||||
network.rst
|
||||
openamp.rst
|
||||
uctypes.rst
|
||||
vfs.rst
|
||||
|
||||
The following libraries provide drivers for hardware components.
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -75,21 +75,6 @@ Methods
|
||||
- ``wake`` specifies the sleep mode from where this interrupt can wake
|
||||
up the system.
|
||||
|
||||
.. method:: RTC.memory([data])
|
||||
|
||||
``RTC.memory(data)`` will write *data* to the RTC memory, where *data* is any
|
||||
object which supports the buffer protocol (including `bytes`, `bytearray`,
|
||||
`memoryview` and `array.array`). ``RTC.memory()`` reads RTC memory and returns
|
||||
a `bytes` object.
|
||||
|
||||
Data written to RTC user memory is persistent across restarts, including
|
||||
`machine.soft_reset()` and `machine.deepsleep()`.
|
||||
|
||||
The maximum length of RTC user memory is 2048 bytes by default on esp32,
|
||||
and 492 bytes on esp8266.
|
||||
|
||||
Availability: esp32, esp8266 ports.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
|
@@ -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 vfs
|
||||
import os
|
||||
# clk cmd and dat0 pins must be passed along with
|
||||
# their respective alternate functions
|
||||
sd = machine.SD(pins=('GP10', 'GP11', 'GP15'))
|
||||
vfs.mount(sd, '/sd')
|
||||
os.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:`vfs.AbstractBlockDev`.
|
||||
The class implements the block protocol defined by :class:`os.AbstractBlockDev`.
|
||||
This allows the mounting of an SD card to be as simple as::
|
||||
|
||||
vfs.mount(machine.SDCard(), "/sd")
|
||||
os.mount(machine.SDCard(), "/sd")
|
||||
|
||||
The constructor takes the following parameters:
|
||||
|
||||
|
@@ -1,296 +0,0 @@
|
||||
.. 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.
|
||||
|
||||
.. warning:: This low-level API assumes familiarity with the USB standard. There
|
||||
are high-level `usb driver modules in micropython-lib`_ which provide a
|
||||
simpler interface and more built-in functionality.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
- A "Runtime" USB device interface or driver is one which is defined using this
|
||||
Python API after MicroPython initially starts up.
|
||||
|
||||
- A "Built-in" USB device interface or driver is one that is compiled into the
|
||||
MicroPython firmware, and is always available. Examples are USB-CDC (serial
|
||||
port) which is usually enabled by default. Built-in USB-MSC (Mass Storage) is an
|
||||
option on some ports.
|
||||
|
||||
Lifecycle
|
||||
---------
|
||||
|
||||
Managing a runtime USB interface can be tricky, especially if you are communicating
|
||||
with MicroPython over a built-in USB-CDC serial port that's part of the same USB
|
||||
device.
|
||||
|
||||
- A MicroPython 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. Data in this memoryview will be the same
|
||||
across each of the three stages of a single transfer.
|
||||
|
||||
A successful transfer consists of this callback being called in sequence
|
||||
for the three stages. Generally speaking, if a device wants to do
|
||||
something in response to a control request then it's best to wait until
|
||||
the ACK stage to confirm the host controller completed the transfer as
|
||||
expected.
|
||||
|
||||
The callback should return one of the following values:
|
||||
|
||||
- ``False`` to stall the endpoint and reject the transfer. It won't
|
||||
proceed to any remaining stages.
|
||||
- ``True`` to continue the transfer to the next stage.
|
||||
- A buffer object can be returned at the SETUP stage when the transfer
|
||||
will send or receive additional data. Typically this is the case when
|
||||
the ``wLength`` field in the request has a non-zero value. This should
|
||||
be a writable buffer for an ``OUT`` direction transfer, or a readable
|
||||
buffer with data for an ``IN`` direction transfer.
|
||||
|
||||
- ``xfer_cb`` - This callback is called whenever a non-control
|
||||
transfer submitted by calling :func:`USBDevice.submit_xfer` completes.
|
||||
|
||||
The callback has three arguments:
|
||||
|
||||
1. The Endpoint number for the completed transfer.
|
||||
2. Result value: ``True`` if the transfer succeeded, ``False``
|
||||
otherwise.
|
||||
3. Number of bytes successfully transferred. In the case of a
|
||||
"short" transfer, The result is ``True`` and ``xferred_bytes``
|
||||
will be smaller than the length of the buffer submitted for the
|
||||
transfer.
|
||||
|
||||
.. note:: If a bus reset occurs (see :func:`USBDevice.reset`),
|
||||
``xfer_cb`` is not called for any transfers that have not
|
||||
already completed.
|
||||
|
||||
.. method:: USBDevice.active(self, [value] /)
|
||||
|
||||
Returns the current active state of this runtime USB device as a
|
||||
boolean. The runtime USB device is "active" when it is available to
|
||||
interact with the host, it doesn't mean that a USB Host is actually
|
||||
present.
|
||||
|
||||
If the optional ``value`` argument is set to a truthy value, then
|
||||
the USB device will be activated.
|
||||
|
||||
If the optional ``value`` argument is set to a falsey value, then
|
||||
the USB device is deactivated. While the USB device is deactivated,
|
||||
it will not be detected by the USB Host.
|
||||
|
||||
To simulate a disconnect and a reconnect of the USB device, call
|
||||
``active(False)`` followed by ``active(True)``. This may be
|
||||
necessary if the runtime device configuration has changed, so that
|
||||
the host sees the new device.
|
||||
|
||||
.. attribute:: USBDevice.builtin_driver
|
||||
|
||||
This attribute holds the current built-in driver configuration, and must be
|
||||
set to one of the ``USBDevice.BUILTIN_`` named constants defined on this object.
|
||||
|
||||
By default it holds the value :data:`USBDevice.BUILTIN_NONE`.
|
||||
|
||||
Runtime USB device must be inactive when setting this field. Call the
|
||||
:func:`USBDevice.active` function to deactivate before setting if necessary
|
||||
(and again to activate after setting).
|
||||
|
||||
If this value is set to any value other than :data:`USBDevice.BUILTIN_NONE` then
|
||||
the following restrictions apply to the :func:`USBDevice.config` arguments:
|
||||
|
||||
- ``desc_cfg`` should begin with the built-in USB interface descriptor data
|
||||
accessible via :data:`USBDevice.builtin_driver` attribute ``desc_cfg``.
|
||||
Descriptors appended after the built-in configuration descriptors should use
|
||||
interface, string and endpoint numbers starting from the max built-in values
|
||||
defined in :data:`USBDevice.builtin_driver` attributes ``itf_max``, ``str_max`` and
|
||||
``ep_max``.
|
||||
|
||||
- The ``bNumInterfaces`` field in the built-in configuration
|
||||
descriptor will also need to be updated if any new interfaces
|
||||
are appended to the end of ``desc_cfg``.
|
||||
|
||||
- ``desc_strs`` should either be ``None`` or a list/dictionary where index
|
||||
values less than ``USBDevice.builtin_driver.str_max`` are missing or have
|
||||
value ``None``. This reserves those string indexes for the built-in
|
||||
drivers. Placing a different string at any of these indexes overrides that
|
||||
string in the built-in driver.
|
||||
|
||||
.. method:: USBDevice.submit_xfer(self, ep, buffer /)
|
||||
|
||||
Submit a USB transfer on endpoint number ``ep``. ``buffer`` must be
|
||||
an object implementing the buffer interface, with read access for
|
||||
``IN`` endpoints and write access for ``OUT`` endpoints.
|
||||
|
||||
.. note:: ``ep`` cannot be the control Endpoint number 0. Control
|
||||
transfers are built up through successive executions of
|
||||
``control_xfer_cb``, see above.
|
||||
|
||||
Returns ``True`` if successful, ``False`` if the transfer could not
|
||||
be queued (as USB device is not configured by host, or because
|
||||
another transfer is queued on this endpoint.)
|
||||
|
||||
When the USB host completes the transfer, the ``xfer_cb`` callback
|
||||
is called (see above).
|
||||
|
||||
Raises ``OSError`` with reason ``MP_EINVAL`` If the USB device is not
|
||||
active.
|
||||
|
||||
.. method:: USBDevice.stall(self, ep, [stall] /)
|
||||
|
||||
Calling this function gets or sets the STALL state of a device endpoint.
|
||||
|
||||
``ep`` is the number of the endpoint.
|
||||
|
||||
If the optional ``stall`` parameter is set, this is a boolean flag
|
||||
for the STALL state.
|
||||
|
||||
The return value is the current stall state of the endpoint (before
|
||||
any change made by this function).
|
||||
|
||||
An endpoint that is set to STALL may remain stalled until this
|
||||
function is called again, or STALL may be cleared automatically by
|
||||
the USB host.
|
||||
|
||||
Raises ``OSError`` with reason ``MP_EINVAL`` If the USB device is not
|
||||
active.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: USBDevice.BUILTIN_NONE
|
||||
.. data:: USBDevice.BUILTIN_DEFAULT
|
||||
.. data:: USBDevice.BUILTIN_CDC
|
||||
.. data:: USBDevice.BUILTIN_MSC
|
||||
.. data:: USBDevice.BUILTIN_CDC_MSC
|
||||
|
||||
These constant objects hold the built-in descriptor data which is
|
||||
compiled into the MicroPython firmware. ``USBDevice.BUILTIN_NONE`` and
|
||||
``USBDevice.BUILTIN_DEFAULT`` are always present. Additional objects may be present
|
||||
depending on the firmware build configuration and the actual built-in drivers.
|
||||
|
||||
.. note:: Currently at most one of ``USBDevice.BUILTIN_CDC``,
|
||||
``USBDevice.BUILTIN_MSC`` and ``USBDevice.BUILTIN_CDC_MSC`` is defined
|
||||
and will be the same object as ``USBDevice.BUILTIN_DEFAULT``.
|
||||
These constants are defined to allow run-time detection of
|
||||
the built-in driver (if any). Support for selecting one of
|
||||
multiple built-in driver configurations may be added in the
|
||||
future.
|
||||
|
||||
These values are assigned to :data:`USBDevice.builtin_driver` to get/set the
|
||||
built-in configuration.
|
||||
|
||||
Each object contains the following read-only fields:
|
||||
|
||||
- ``itf_max`` - One more than the highest bInterfaceNumber value used
|
||||
in the built-in configuration descriptor.
|
||||
- ``ep_max`` - One more than the highest bEndpointAddress value used
|
||||
in the built-in configuration descriptor. Does not include any
|
||||
``IN`` flag bit (0x80).
|
||||
- ``str_max`` - One more than the highest string descriptor index
|
||||
value used by any built-in descriptor.
|
||||
- ``desc_dev`` - ``bytes`` object containing the built-in USB device
|
||||
descriptor.
|
||||
- ``desc_cfg`` - ``bytes`` object containing the complete built-in USB
|
||||
configuration descriptor.
|
||||
|
||||
.. _usb driver modules in micropython-lib: https://github.com/micropython/micropython-lib/tree/master/micropython/usb#readme
|
@@ -265,4 +265,3 @@ Classes
|
||||
machine.WDT.rst
|
||||
machine.SD.rst
|
||||
machine.SDCard.rst
|
||||
machine.USBDevice.rst
|
||||
|
@@ -1,115 +0,0 @@
|
||||
: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,30 +136,192 @@ Terminal redirection and duplication
|
||||
Filesystem mounting
|
||||
-------------------
|
||||
|
||||
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.
|
||||
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)
|
||||
|
||||
See `vfs.mount`.
|
||||
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)
|
||||
|
||||
See `vfs.umount`.
|
||||
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)
|
||||
|
||||
See `vfs.VfsFat`.
|
||||
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)
|
||||
|
||||
See `vfs.VfsLfs1`.
|
||||
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)
|
||||
|
||||
See `vfs.VfsLfs2`.
|
||||
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`.
|
||||
|
||||
.. class:: VfsPosix(root=None)
|
||||
The *mtime* argument enables modification timestamps for files, stored using
|
||||
littlefs attributes. This option can be disabled or enabled differently each
|
||||
mount time and timestamps will only be added or updated if *mtime* is enabled,
|
||||
otherwise the timestamps will remain untouched. Littlefs v2 filesystems without
|
||||
timestamps will work without reformatting and timestamps will be added
|
||||
transparently to existing files once they are opened for writing. When *mtime*
|
||||
is enabled `os.stat` on files without timestamps will return 0 for the timestamp.
|
||||
|
||||
See `vfs.VfsPosix`.
|
||||
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.
|
||||
|
@@ -43,7 +43,7 @@ Methods
|
||||
|
||||
These methods implement the simple and :ref:`extended
|
||||
<block-device-interface>` block protocol defined by
|
||||
:class:`vfs.AbstractBlockDev`.
|
||||
:class:`os.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:`vfs.mount` and :meth:`vfs.umount` instead.
|
||||
be performed by :meth:`os.mount` and :meth:`os.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:`vfs.AbstractBlockDev` for the
|
||||
following is also deprecated. See :class:`os.AbstractBlockDev` for the
|
||||
correct way to create a block device.)
|
||||
|
||||
- ``readblocks(self, blocknum, buf)``
|
||||
|
@@ -1,293 +0,0 @@
|
||||
.. 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:`vfs.AbstractBlockDev`.
|
||||
:class:`os.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
|
||||
reused so as to save on instruction memory.
|
||||
re-used 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,10 +140,3 @@ 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,7 +241,6 @@ 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, key=None, cert=None, cert_reqs=CERT_NONE, cadata=None, server_hostname=None, do_handshake=True)
|
||||
.. function:: ssl.wrap_socket(sock, server_side=False, keyfile=None, certfile=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`
|
||||
|
@@ -45,8 +45,6 @@ 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, releaselevel), e.g. (1, 22, 0, '')
|
||||
* *version* - tuple (major, minor, micro), e.g. (1, 7, 0)
|
||||
* *_machine* - string describing the underlying machine
|
||||
* *_mpy* - supported mpy file-format version (optional attribute)
|
||||
|
||||
@@ -77,9 +77,6 @@ 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
|
||||
|
||||
|
@@ -1,208 +0,0 @@
|
||||
: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.
|
@@ -34,5 +34,5 @@ Methods
|
||||
|
||||
These methods implement the simple and extended
|
||||
:ref:`block protocol <block-device-interface>` defined by
|
||||
:class:`vfs.AbstractBlockDev`.
|
||||
:class:`os.AbstractBlockDev`.
|
||||
|
||||
|
@@ -37,4 +37,4 @@ Methods
|
||||
|
||||
These methods implement the simple and extended
|
||||
:ref:`block protocol <block-device-interface>` defined by
|
||||
:class:`vfs.AbstractBlockDev`.
|
||||
:class:`os.AbstractBlockDev`.
|
||||
|
@@ -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"
|
||||
|
@@ -309,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:
|
||||
@@ -443,27 +443,27 @@ SD card
|
||||
|
||||
See :ref:`machine.SDCard <machine.SDCard>`::
|
||||
|
||||
import machine, os, vfs
|
||||
import machine, os
|
||||
|
||||
sd = machine.SDCard()
|
||||
fs = vfs.VfsFat(sd)
|
||||
vfs.mount(fs, "/sd") # mount
|
||||
fs = os.VfsFat(sd)
|
||||
os.mount(fs, "/sd") # mount
|
||||
os.listdir('/sd') # list directory contents
|
||||
vfs.umount('/sd') # eject
|
||||
os.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 vfs, sdcard, machine
|
||||
import os, 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)
|
||||
fs = vfs.VfsFat(sd)
|
||||
vfs.mount(fs, "/sdcard")
|
||||
vfs = os.VfsFat(sd)
|
||||
os.mount(vfs, "/sdcard")
|
||||
|
||||
OneWire driver
|
||||
--------------
|
||||
|
@@ -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 ``vfs.mount``).
|
||||
mount and use it later in your program using ``os.mount``).
|
||||
|
||||
(Note that on older versions of the board, ``/flash`` is called ``0:/`` and ``/sd``
|
||||
is called ``1:/``).
|
||||
|
@@ -211,7 +211,7 @@ two loops:
|
||||
spi.readinto(buf)
|
||||
# process data in buf
|
||||
|
||||
The first creates a buffer on each pass whereas the second reuses a pre-allocated
|
||||
The first creates a buffer on each pass whereas the second re-uses 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:`vfs.AbstractBlockDev` protocol.
|
||||
:class:`os.AbstractBlockDev` protocol.
|
||||
|
||||
Built-in block devices
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -108,16 +108,16 @@ RAM using a ``bytearray``::
|
||||
|
||||
It can be used as follows::
|
||||
|
||||
import vfs
|
||||
import os
|
||||
|
||||
bdev = RAMBlockDev(512, 50)
|
||||
vfs.VfsFat.mkfs(bdev)
|
||||
vfs.mount(bdev, '/ramdisk')
|
||||
os.VfsFat.mkfs(bdev)
|
||||
os.mount(bdev, '/ramdisk')
|
||||
|
||||
An example of a block device that supports both the simple and extended
|
||||
interface (i.e. both signatures and behaviours of the
|
||||
:meth:`vfs.AbstractBlockDev.readblocks` and
|
||||
:meth:`vfs.AbstractBlockDev.writeblocks` methods) is::
|
||||
:meth:`os.AbstractBlockDev.readblocks` and
|
||||
:meth:`os.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
|
||||
<vfs.VfsLfs2>`::
|
||||
<os.VfsLfs2>`::
|
||||
|
||||
import vfs
|
||||
import os
|
||||
|
||||
bdev = RAMBlockDev(512, 50)
|
||||
vfs.VfsLfs2.mkfs(bdev)
|
||||
vfs.mount(bdev, '/ramdisk')
|
||||
os.VfsLfs2.mkfs(bdev)
|
||||
os.mount(bdev, '/ramdisk')
|
||||
|
||||
Once mounted, the filesystem (regardless of its type) can be used as it
|
||||
normally would be used from Python code, for example::
|
||||
@@ -166,8 +166,8 @@ normally would be used from Python code, for example::
|
||||
Filesystems
|
||||
-----------
|
||||
|
||||
MicroPython ports can provide implementations of :class:`FAT <vfs.VfsFat>`,
|
||||
:class:`littlefs v1 <vfs.VfsLfs1>` and :class:`littlefs v2 <vfs.VfsLfs2>`.
|
||||
MicroPython ports can provide implementations of :class:`FAT <os.VfsFat>`,
|
||||
:class:`littlefs v1 <os.VfsLfs1>` and :class:`littlefs v2 <os.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 vfs
|
||||
vfs.umount('/')
|
||||
vfs.VfsFat.mkfs(bdev)
|
||||
vfs.mount(bdev, '/')
|
||||
import os
|
||||
os.umount('/')
|
||||
os.VfsFat.mkfs(bdev)
|
||||
os.mount(bdev, '/')
|
||||
|
||||
# STM32
|
||||
import os, vfs, pyb
|
||||
vfs.umount('/flash')
|
||||
vfs.VfsFat.mkfs(pyb.Flash(start=0))
|
||||
vfs.mount(pyb.Flash(start=0), '/flash')
|
||||
import os, pyb
|
||||
os.umount('/flash')
|
||||
os.VfsFat.mkfs(pyb.Flash(start=0))
|
||||
os.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 vfs
|
||||
vfs.umount('/')
|
||||
vfs.VfsLfs2.mkfs(bdev)
|
||||
vfs.mount(bdev, '/')
|
||||
import os
|
||||
os.umount('/')
|
||||
os.VfsLfs2.mkfs(bdev)
|
||||
os.mount(bdev, '/')
|
||||
|
||||
# STM32
|
||||
import os, vfs, pyb
|
||||
vfs.umount('/flash')
|
||||
vfs.VfsLfs2.mkfs(pyb.Flash(start=0))
|
||||
vfs.mount(pyb.Flash(start=0), '/flash')
|
||||
import os, pyb
|
||||
os.umount('/flash')
|
||||
os.VfsLfs2.mkfs(pyb.Flash(start=0))
|
||||
os.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, vfs, pyb
|
||||
vfs.umount('/flash')
|
||||
import os, pyb
|
||||
os.umount('/flash')
|
||||
p1 = pyb.Flash(start=0, len=256*1024)
|
||||
p2 = pyb.Flash(start=256*1024)
|
||||
vfs.VfsFat.mkfs(p1)
|
||||
vfs.VfsLfs2.mkfs(p2)
|
||||
vfs.mount(p1, '/flash')
|
||||
vfs.mount(p2, '/data')
|
||||
os.VfsFat.mkfs(p1)
|
||||
os.VfsLfs2.mkfs(p2)
|
||||
os.mount(p1, '/flash')
|
||||
os.mount(p2, '/data')
|
||||
os.chdir('/flash')
|
||||
|
||||
This might be useful to make your Python files, configuration and other
|
||||
@@ -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 vfs, pyb
|
||||
import os, pyb
|
||||
p2 = pyb.Flash(start=256*1024)
|
||||
vfs.mount(p2, '/data')
|
||||
os.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, vfs
|
||||
import esp32, os
|
||||
p = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='foo')
|
||||
vfs.mount(p, '/foo')
|
||||
os.mount(p, '/foo')
|
||||
|
||||
|
@@ -95,17 +95,6 @@ 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
|
||||
@@ -149,13 +138,11 @@ See :func:`micropython.opt_level`.
|
||||
|
||||
You can use the variables above, such as ``$(PORT_DIR)`` in ``base_path``.
|
||||
|
||||
.. function:: require(name, library=None)
|
||||
.. function:: require(name, unix_ffi=False)
|
||||
|
||||
Require a package by name (and its dependencies) from :term:`micropython-lib`.
|
||||
|
||||
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.
|
||||
Optionally specify unix_ffi=True to use a module from the unix-ffi directory.
|
||||
|
||||
.. function:: include(manifest_path)
|
||||
|
||||
|
@@ -71,11 +71,4 @@ 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`
|
||||
*None yet*
|
||||
|
@@ -682,13 +682,6 @@ See :ref:`packages`.
|
||||
Install the package from the specified branch at org/repo on GitHub to the
|
||||
device. See :ref:`packages`.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mpremote mip install gitlab:org/repo@branch
|
||||
|
||||
Install the package from the specified branch at org/repo on GitLab to the
|
||||
device. See :ref:`packages`.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mpremote mip install --target /flash/third-party functools
|
||||
|
@@ -86,8 +86,7 @@ and .mpy version.
|
||||
=================== ============
|
||||
MicroPython release .mpy version
|
||||
=================== ============
|
||||
v1.23.0 and up 6.3
|
||||
v1.22.x 6.2
|
||||
v1.22.0 and up 6.2
|
||||
v1.20 - v1.21.0 6.1
|
||||
v1.19.x 6
|
||||
v1.12 - v1.18 5
|
||||
@@ -103,7 +102,6 @@ MicroPython repository at which the .mpy version was changed.
|
||||
=================== ========================================
|
||||
.mpy version change Git commit
|
||||
=================== ========================================
|
||||
6.2 to 6.3 bdbc869f9ea200c0d28b2bc7bfb60acd9d884e1b
|
||||
6.1 to 6.2 6967ff3c581a66f73e9f3d78975f47528db39980
|
||||
6 to 6.1 d94141e1473aebae0d3c63aeaa8397651ad6fa01
|
||||
5 to 6 f2040bfc7ee033e48acef9f289790f3b4e6b74e5
|
||||
|
@@ -7,7 +7,7 @@ Installing packages with ``mip``
|
||||
--------------------------------
|
||||
|
||||
Network-capable boards include the ``mip`` module, which can install packages
|
||||
from :term:`micropython-lib` and from third-party sites (including GitHub, GitLab).
|
||||
from :term:`micropython-lib` and from third-party sites (including GitHub).
|
||||
|
||||
``mip`` ("mip installs packages") is similar in concept to Python's ``pip`` tool,
|
||||
however it does not use the PyPI index, rather it uses :term:`micropython-lib`
|
||||
@@ -38,28 +38,24 @@ install third-party libraries. The simplest way is to download a file directly::
|
||||
When installing a file directly, the ``target`` argument is still supported to set
|
||||
the destination path, but ``mpy`` and ``version`` are ignored.
|
||||
|
||||
The URL can also start with ``github:`` or ``gitlab:`` as a simple way of pointing to content
|
||||
hosted on GitHub or GitLab::
|
||||
The URL can also start with ``github:`` as a simple way of pointing to content
|
||||
hosted on GitHub::
|
||||
|
||||
>>> mip.install("github:org/repo/path/foo.py") # Uses default branch
|
||||
>>> mip.install("github:org/repo/path/foo.py", version="branch-or-tag") # Optionally specify the branch or tag
|
||||
>>> mip.install("gitlab:org/repo/path/foo.py") # Uses default branch
|
||||
>>> mip.install("gitlab:org/repo/path/foo.py", version="branch-or-tag") # Optionally specify the branch or tag
|
||||
|
||||
More sophisticated packages (i.e. with more than one file, or with dependencies)
|
||||
can be downloaded by specifying the path to their ``package.json``.
|
||||
|
||||
>>> mip.install("http://example.com/x/package.json")
|
||||
>>> mip.install("github:org/user/path/package.json")
|
||||
>>> mip.install("gitlab:org/user/path/package.json")
|
||||
|
||||
If no json file is specified, then "package.json" is implicitly added::
|
||||
|
||||
>>> mip.install("http://example.com/x/")
|
||||
>>> mip.install("github:org/repo") # Uses default branch of that repo
|
||||
>>> mip.install("github:org/repo", version="branch-or-tag")
|
||||
>>> mip.install("gitlab:org/repo") # Uses default branch of that repo
|
||||
>>> mip.install("gitlab:org/repo", version="branch-or-tag")
|
||||
|
||||
|
||||
Using ``mip`` on the Unix port
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -87,8 +83,6 @@ can be used from a host PC to install packages to a locally connected device
|
||||
$ mpremote mip install http://example.com/x/y/foo.py
|
||||
$ mpremote mip install github:org/repo
|
||||
$ mpremote mip install github:org/repo@branch-or-tag
|
||||
$ mpremote mip install gitlab:org/repo
|
||||
$ mpremote mip install gitlab:org/repo@branch-or-tag
|
||||
|
||||
The ``--target=path``, ``--no-mpy``, and ``--index`` arguments can be set::
|
||||
|
||||
@@ -126,8 +120,7 @@ A typical ``package.json`` for an example ``mlx90640`` library looks like::
|
||||
"deps": [
|
||||
["collections-defaultdict", "latest"],
|
||||
["os-path", "latest"],
|
||||
["github:org/micropython-additions", "main"],
|
||||
["gitlab:org/micropython-otheradditions", "main"]
|
||||
["github:org/micropython-additions", "main"]
|
||||
],
|
||||
"version": "0.2"
|
||||
}
|
||||
|
@@ -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, vfs, sdcard
|
||||
import os, sdcard
|
||||
|
||||
spi = SPI(0, baudrate=500000)
|
||||
cs = Pin.cpu.P103
|
||||
sd = sdcard.SDCard(spi, cs)
|
||||
vfs.mount(sd, '/sd')
|
||||
os.mount(sd, '/sd')
|
||||
os.listdir('/')
|
||||
os.chdir('/sd')
|
||||
vfs.umount('/sd')
|
||||
os.umount('/sd')
|
||||
|
||||
OneWire driver
|
||||
--------------
|
||||
|
@@ -17,12 +17,12 @@ Adafruit ItsyBitsy M0 Express pin assignment table
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
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 -
|
||||
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
|
||||
@@ -30,31 +30,31 @@ Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC
|
||||
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 -
|
||||
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 -
|
||||
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 -
|
||||
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 -
|
||||
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 - - - - -
|
||||
28 PA28 8 - - - - -
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
|
||||
|
||||
@@ -348,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
|
||||
@@ -364,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
|
||||
@@ -383,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
|
||||
=== ==== ============ ==== ==== ==== ====== ====== ===== ===== =====
|
||||
|
||||
@@ -870,7 +870,7 @@ Adafruit ItsyBitsy M4 Express :ref:`samd51_pinout_table`.
|
||||
|
||||
The default devices at the board are:
|
||||
|
||||
- UART 2 at pins PA13/PA12, labelled RXD/TXD
|
||||
- UART 1 at pins PB23/PB22, 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
|
||||
@@ -884,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_item(e, txt):
|
||||
def print_entry(e, txt):
|
||||
print(txt, end=": ")
|
||||
if e == 255:
|
||||
print(" - ", end="")
|
||||
else:
|
||||
print("%d/%d" % (e >> 4, e & 0x0f), end="")
|
||||
|
||||
def print_pininfo(pin_id, name, info):
|
||||
|
||||
print("%3d" % pin_id, end=" ")
|
||||
print("%4s %12s" % (info[0], name), 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="")
|
||||
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_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")
|
||||
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")
|
||||
else:
|
||||
print(" ADC1:%2s" % (info[3] if info[3] != 255 else "-"), end="")
|
||||
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_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()
|
||||
|
||||
def tblkey(i):
|
||||
name = i[1]
|
||||
if name != "":
|
||||
name = i[1][0]
|
||||
if name != "-":
|
||||
if len(name) < 3:
|
||||
return " " + name
|
||||
else:
|
||||
@@ -921,25 +921,17 @@ 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, sort=True):
|
||||
def table(num = 127):
|
||||
pintbl = []
|
||||
inv_bd = {v: k for k, v in Pin.board.__dict__.items()}
|
||||
for i in range(num):
|
||||
try:
|
||||
p = Pin(i)
|
||||
pi = pininfo(p)
|
||||
if p in inv_bd.keys():
|
||||
name = inv_bd[p]
|
||||
else:
|
||||
name = ""
|
||||
pintbl.append((i, name, pininfo(i)))
|
||||
pintbl.append((i, pininfo(i)))
|
||||
except:
|
||||
pass
|
||||
# print("not defined")
|
||||
|
||||
if sort:
|
||||
pintbl.sort(key=tblkey)
|
||||
pintbl.sort(key=tblkey)
|
||||
for item in pintbl:
|
||||
print_pininfo(item[0], item[1], item[2])
|
||||
print_pininfo(item[0], item[1])
|
||||
|
||||
table()
|
||||
|
@@ -373,7 +373,7 @@ functions are defined in ``os`` module:
|
||||
Mounts a block device (like an ``SD`` object) in the specified mount
|
||||
point. Example::
|
||||
|
||||
vfs.mount(sd, '/sd')
|
||||
os.mount(sd, '/sd')
|
||||
|
||||
.. function:: unmount(path)
|
||||
|
||||
|
@@ -171,13 +171,13 @@ SD card
|
||||
See :ref:`machine.SD <machine.SD>`. ::
|
||||
|
||||
from machine import SD
|
||||
import vfs
|
||||
import os
|
||||
|
||||
# clock pin, cmd pin, data0 pin
|
||||
sd = SD(pins=('GP10', 'GP11', 'GP15'))
|
||||
# or use default ones for the expansion board
|
||||
sd = SD()
|
||||
vfs.mount(sd, '/sd')
|
||||
os.mount(sd, '/sd')
|
||||
|
||||
WLAN (WiFi)
|
||||
-----------
|
||||
|
@@ -109,12 +109,12 @@ Disk Access
|
||||
|
||||
Use the :ref:`zephyr.DiskAccess <zephyr.DiskAccess>` class to support filesystem::
|
||||
|
||||
import vfs
|
||||
import os
|
||||
from zephyr import DiskAccess
|
||||
|
||||
block_dev = DiskAccess('SDHC') # create a block device object for an SD card
|
||||
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
|
||||
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
|
||||
|
||||
# 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 vfs
|
||||
import os
|
||||
from zephyr import FlashArea
|
||||
|
||||
block_dev = FlashArea(4, 4096) # creates a block device object in the frdm-k64f flash scratch partition
|
||||
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
|
||||
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
|
||||
|
||||
# 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 `vfs Filesystem Mounting <https://docs.micropython.org/en/latest/library/vfs.html?highlight=vfs#filesystem-mounting>`_.
|
||||
See `os Filesystem Mounting <https://docs.micropython.org/en/latest/library/os.html?highlight=os#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 `vfs.AbstractBlockDev` protocol.
|
||||
implements the `os.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 vfs
|
||||
import os
|
||||
from zephyr import DiskAccess
|
||||
bdev = zephyr.DiskAccess('SDHC') # create block device object using DiskAccess
|
||||
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
|
||||
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
|
||||
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 `vfs.AbstractBlockDev` protocol.
|
||||
implements the `os.AbstractBlockDev` protocol.
|
||||
|
||||
Example usage with the internal flash on the reel_board or the rv32m1_vega_ri5cy board::
|
||||
|
||||
import vfs
|
||||
import os
|
||||
from zephyr import FlashArea
|
||||
bdev = FlashArea(FlashArea.STORAGE, 4096) # create block device object using FlashArea
|
||||
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
|
||||
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
|
||||
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);
|
||||
|
@@ -51,7 +51,7 @@ extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
|
||||
// Provided by the port.
|
||||
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,7 +64,7 @@ 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) {
|
||||
@@ -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,9 +29,6 @@
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_PULSE
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
#include "drivers/dht/dht.h"
|
||||
|
||||
@@ -40,7 +37,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);
|
||||
|
||||
@@ -95,5 +92,3 @@ timeout:
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(dht_readinto_obj, dht_readinto);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_PULSE
|
||||
|
@@ -44,14 +44,14 @@
|
||||
|
||||
extern void mod_network_poll_events(void);
|
||||
|
||||
static mp_obj_t esp_hosted_pin_irq_callback(mp_obj_t self_in) {
|
||||
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.
|
||||
|
@@ -442,23 +442,6 @@ typedef struct {
|
||||
.single_status_byte = false, \
|
||||
}
|
||||
|
||||
// Settings for the ISSI devices
|
||||
#define IS25LPWP064D { \
|
||||
.total_size = (1 << 23), /* 8 MiB */ \
|
||||
.start_up_time_us = 5000, \
|
||||
.manufacturer_id = 0x9D, \
|
||||
.memory_type = 0x60, \
|
||||
.capacity = 0x17, \
|
||||
.max_clock_speed_mhz = 80, \
|
||||
.quad_enable_bit_mask = 0x40, \
|
||||
.has_sector_protection = false, \
|
||||
.supports_fast_read = true, \
|
||||
.supports_qspi = true, \
|
||||
.supports_qspi_writes = true, \
|
||||
.write_status_register_split = false, \
|
||||
.single_status_byte = true, \
|
||||
}
|
||||
|
||||
// Settings for a GENERIC device with the most common setting
|
||||
#define GENERIC { \
|
||||
.total_size = (1 << 21), /* 2 MiB */ \
|
||||
|
@@ -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;
|
||||
|
@@ -12,7 +12,7 @@ PROG = embed
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I$(EMBED_DIR)
|
||||
CFLAGS += -I$(EMBED_DIR)/port
|
||||
CFLAGS += -Wall -Og -fno-common
|
||||
CFLAGS += -Wall -Og
|
||||
|
||||
SRC += main.c
|
||||
SRC += $(wildcard $(EMBED_DIR)/*/*.c) $(wildcard $(EMBED_DIR)/*/*/*.c)
|
||||
|
@@ -31,14 +31,7 @@ static char heap[8 * 1024];
|
||||
|
||||
int main() {
|
||||
// Initialise MicroPython.
|
||||
//
|
||||
// Note: &stack_top below should be good enough for many cases.
|
||||
// However, depending on environment, there might be more appropriate
|
||||
// ways to get the stack top value.
|
||||
// eg. pthread_get_stackaddr_np, pthread_getattr_np,
|
||||
// __builtin_frame_address/__builtin_stack_address, etc.
|
||||
int stack_top;
|
||||
mp_embed_init(&heap[0], sizeof(heap), &stack_top);
|
||||
mp_embed_init(&heap[0], sizeof(heap));
|
||||
|
||||
// Run the example scripts (they will be compiled first).
|
||||
mp_embed_exec_str(example_1);
|
||||
|
@@ -5,16 +5,15 @@ MPY_DIR = ../../..
|
||||
MOD = btree_$(ARCH)
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = btree_c.c
|
||||
SRC = btree_c.c btree_py.py
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
||||
|
||||
BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx
|
||||
BERKELEY_DB_CONFIG_FILE ?= \"extmod/berkeley-db/berkeley_db_config_port.h\"
|
||||
CFLAGS += -I$(BTREE_DIR)/include
|
||||
CFLAGS += -DBERKELEY_DB_CONFIG_FILE=$(BERKELEY_DB_CONFIG_FILE)
|
||||
CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter
|
||||
BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error="(void)" -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA)
|
||||
CFLAGS += -I$(BTREE_DIR)/PORT/include
|
||||
CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS)
|
||||
|
||||
SRC += $(addprefix $(realpath $(BTREE_DIR))/,\
|
||||
btree/bt_close.c \
|
||||
|
@@ -39,10 +39,6 @@ void abort_(void) {
|
||||
nlr_raise(mp_obj_new_exception(mp_load_global(MP_QSTR_RuntimeError)));
|
||||
}
|
||||
|
||||
int puts(const char *s) {
|
||||
return mp_printf(&mp_plat_print, "%s\n", s);
|
||||
}
|
||||
|
||||
int native_errno;
|
||||
#if defined(__linux__)
|
||||
int *__errno_location (void)
|
||||
@@ -104,41 +100,25 @@ mp_getiter_iternext_custom_t btree_getiter_iternext;
|
||||
#include "extmod/modbtree.c"
|
||||
|
||||
mp_map_elem_t btree_locals_dict_table[8];
|
||||
static MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table);
|
||||
|
||||
static mp_obj_t btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// The allowed_args array must have its qstr's populated at runtime.
|
||||
enum { ARG_flags, ARG_cachesize, ARG_pagesize, ARG_minkeypage };
|
||||
mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
allowed_args[0].qst = MP_QSTR_flags;
|
||||
allowed_args[1].qst = MP_QSTR_cachesize;
|
||||
allowed_args[2].qst = MP_QSTR_pagesize;
|
||||
allowed_args[3].qst = MP_QSTR_minkeypage;
|
||||
STATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table);
|
||||
|
||||
STATIC mp_obj_t btree_open(size_t n_args, const mp_obj_t *args) {
|
||||
// Make sure we got a stream object
|
||||
mp_get_stream_raise(pos_args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
|
||||
|
||||
BTREEINFO openinfo = {0};
|
||||
openinfo.flags = args[ARG_flags].u_int;
|
||||
openinfo.cachesize = args[ARG_cachesize].u_int;
|
||||
openinfo.psize = args[ARG_pagesize].u_int;
|
||||
openinfo.minkeypage = args[ARG_minkeypage].u_int;
|
||||
DB *db = __bt_open(MP_OBJ_TO_PTR(pos_args[0]), &btree_stream_fvtable, &openinfo, 0);
|
||||
openinfo.flags = mp_obj_get_int(args[1]);
|
||||
openinfo.cachesize = mp_obj_get_int(args[2]);
|
||||
openinfo.psize = mp_obj_get_int(args[3]);
|
||||
openinfo.minkeypage = mp_obj_get_int(args[4]);
|
||||
DB *db = __bt_open(MP_OBJ_TO_PTR(args[0]), &btree_stream_fvtable, &openinfo, 0);
|
||||
if (db == NULL) {
|
||||
mp_raise_OSError(native_errno);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(btree_new(db, pos_args[0]));
|
||||
return MP_OBJ_FROM_PTR(btree_new(db, args[0]));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(btree_open_obj, 1, btree_open);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_open_obj, 5, 5, btree_open);
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
@@ -163,7 +143,7 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
|
||||
btree_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_items), MP_OBJ_FROM_PTR(&btree_items_obj) };
|
||||
MP_OBJ_TYPE_SET_SLOT(&btree_type, locals_dict, (void*)&btree_locals_dict, 4);
|
||||
|
||||
mp_store_global(MP_QSTR_open, MP_OBJ_FROM_PTR(&btree_open_obj));
|
||||
mp_store_global(MP_QSTR__open, MP_OBJ_FROM_PTR(&btree_open_obj));
|
||||
mp_store_global(MP_QSTR_INCL, MP_OBJ_NEW_SMALL_INT(FLAG_END_KEY_INCL));
|
||||
mp_store_global(MP_QSTR_DESC, MP_OBJ_NEW_SMALL_INT(FLAG_DESC));
|
||||
|
||||
|
7
examples/natmod/btree/btree_py.py
Normal file
7
examples/natmod/btree/btree_py.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# Implemented in Python to support keyword arguments
|
||||
|
||||
# ruff: noqa: F821 - this file is evaluated with C-defined names in scope
|
||||
|
||||
|
||||
def open(stream, *, flags=0, cachesize=0, pagesize=0, minkeypage=0):
|
||||
return _open(stream, flags, cachesize, pagesize, minkeypage)
|
@@ -29,7 +29,7 @@ mp_obj_t mp_stream_close(mp_obj_t stream) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close);
|
||||
|
||||
// Re-implemented from py/stream.c, not yet available in dynruntime.h.
|
||||
static mp_obj_t mp_stream___exit__(size_t n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t mp_stream___exit__(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
return mp_stream_close(args[0]);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ mp_obj_t mp_identity(mp_obj_t self) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
|
||||
|
||||
mp_map_elem_t deflateio_locals_dict_table[7];
|
||||
static MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table);
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#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;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ static mp_int_t factorial_helper(mp_int_t x) {
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -25,7 +25,7 @@ static mp_obj_t factorial(mp_obj_t x_obj) {
|
||||
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) {
|
||||
|
@@ -25,15 +25,15 @@ uint16_t *const table_ptr16a[] = { &data16[0], &data16[1], &data16[2], &data16[3
|
||||
const uint16_t *const table_ptr16b[] = { &table16[0], &table16[1] };
|
||||
|
||||
// A simple function that adds its 2 arguments (must be integers)
|
||||
static mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) {
|
||||
STATIC mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) {
|
||||
mp_int_t x = mp_obj_get_int(x_in);
|
||||
mp_int_t y = mp_obj_get_int(y_in);
|
||||
return mp_obj_new_int(x + y);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);
|
||||
|
||||
// A local helper function (not exposed to Python)
|
||||
static mp_int_t fibonacci_helper(mp_int_t x) {
|
||||
STATIC mp_int_t fibonacci_helper(mp_int_t x) {
|
||||
if (x < MP_ARRAY_SIZE(table8)) {
|
||||
return table8[x];
|
||||
} else {
|
||||
@@ -42,17 +42,17 @@ static mp_int_t fibonacci_helper(mp_int_t x) {
|
||||
}
|
||||
|
||||
// A function which computes Fibonacci numbers
|
||||
static mp_obj_t fibonacci(mp_obj_t x_in) {
|
||||
STATIC mp_obj_t fibonacci(mp_obj_t x_in) {
|
||||
mp_int_t x = mp_obj_get_int(x_in);
|
||||
if (x < 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("can't compute negative Fibonacci number"));
|
||||
}
|
||||
return mp_obj_new_int(fibonacci_helper(x));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);
|
||||
|
||||
// A function that accesses the BSS data
|
||||
static mp_obj_t access(size_t n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t access(size_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
// Create a list holding all items from data16
|
||||
mp_obj_list_t *lst = MP_OBJ_TO_PTR(mp_obj_new_list(MP_ARRAY_SIZE(data16), NULL));
|
||||
@@ -71,17 +71,17 @@ static mp_obj_t access(size_t n_args, const mp_obj_t *args) {
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access);
|
||||
|
||||
// A function that allocates memory and creates a bytearray
|
||||
static mp_obj_t make_array(void) {
|
||||
STATIC mp_obj_t make_array(void) {
|
||||
uint16_t *ptr = m_new(uint16_t, MP_ARRAY_SIZE(table_ptr16b));
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(table_ptr16b); ++i) {
|
||||
ptr[i] = *table_ptr16b[i];
|
||||
}
|
||||
return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) * MP_ARRAY_SIZE(table_ptr16b), ptr);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array);
|
||||
|
||||
// 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) {
|
||||
|
@@ -22,29 +22,29 @@
|
||||
|
||||
// A function that uses the default float type configured for the current target
|
||||
// This default can be overridden by specifying MICROPY_FLOAT_IMPL at the make level
|
||||
static mp_obj_t add(mp_obj_t x, mp_obj_t y) {
|
||||
STATIC mp_obj_t add(mp_obj_t x, mp_obj_t y) {
|
||||
return mp_obj_new_float(mp_obj_get_float(x) + mp_obj_get_float(y));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);
|
||||
|
||||
// A function that explicitly uses single precision floats
|
||||
static mp_obj_t add_f(mp_obj_t x, mp_obj_t y) {
|
||||
STATIC mp_obj_t add_f(mp_obj_t x, mp_obj_t y) {
|
||||
return mp_obj_new_float_from_f(mp_obj_get_float_to_f(x) + mp_obj_get_float_to_f(y));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(add_f_obj, add_f);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_f_obj, add_f);
|
||||
|
||||
#if USE_DOUBLE
|
||||
// A function that explicitly uses double precision floats
|
||||
static mp_obj_t add_d(mp_obj_t x, mp_obj_t y) {
|
||||
STATIC mp_obj_t add_d(mp_obj_t x, mp_obj_t y) {
|
||||
return mp_obj_new_float_from_d(mp_obj_get_float_to_d(x) + mp_obj_get_float_to_d(y));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(add_d_obj, add_d);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_d_obj, add_d);
|
||||
#endif
|
||||
|
||||
// A function that computes the product of floats in an array.
|
||||
// This function uses the most general C argument interface, which is more difficult
|
||||
// to use but has access to the globals dict of the module via self->globals.
|
||||
static mp_obj_t productf(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
STATIC mp_obj_t productf(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
// Check number of arguments is valid
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
// A function that returns a tuple of object types.
|
||||
static mp_obj_t get_types(void) {
|
||||
STATIC mp_obj_t get_types(void) {
|
||||
return mp_obj_new_tuple(9, ((mp_obj_t []) {
|
||||
MP_OBJ_FROM_PTR(&mp_type_type),
|
||||
MP_OBJ_FROM_PTR(&mp_type_NoneType),
|
||||
@@ -21,10 +21,10 @@ static mp_obj_t get_types(void) {
|
||||
MP_OBJ_FROM_PTR(&mp_type_dict),
|
||||
}));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_0(get_types_obj, get_types);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_types_obj, get_types);
|
||||
|
||||
// A function that returns a tuple of constant objects.
|
||||
static mp_obj_t get_const_objects(void) {
|
||||
STATIC mp_obj_t get_const_objects(void) {
|
||||
return mp_obj_new_tuple(5, ((mp_obj_t []) {
|
||||
mp_const_none,
|
||||
mp_const_false,
|
||||
@@ -33,17 +33,17 @@ static mp_obj_t get_const_objects(void) {
|
||||
mp_const_empty_tuple,
|
||||
}));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_0(get_const_objects_obj, get_const_objects);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_const_objects_obj, get_const_objects);
|
||||
|
||||
// A function that creates a dictionary from the given arguments.
|
||||
static mp_obj_t make_dict(size_t n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t make_dict(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_t dict = mp_obj_new_dict(n_args / 2);
|
||||
for (; n_args >= 2; n_args -= 2, args += 2) {
|
||||
mp_obj_dict_store(dict, args[0], args[1]);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(make_dict_obj, 0, MP_OBJ_FUN_ARGS_MAX, make_dict);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(make_dict_obj, 0, MP_OBJ_FUN_ARGS_MAX, make_dict);
|
||||
|
||||
// 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) {
|
||||
|
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
This example extends on features0 but demonstrates how to define a class,
|
||||
and a custom exception.
|
||||
This example extends on features0 but demonstrates how to define a class.
|
||||
|
||||
The Factorial class constructor takes an integer, and then the calculate
|
||||
method can be called to get the factorial.
|
||||
@@ -9,9 +8,6 @@
|
||||
>>> f = features4.Factorial(4)
|
||||
>>> f.calculate()
|
||||
24
|
||||
|
||||
If the argument to the Factorial class constructor is less than zero, a
|
||||
FactorialError is raised.
|
||||
*/
|
||||
|
||||
// Include the header file to get access to the MicroPython API
|
||||
@@ -26,24 +22,18 @@ typedef struct {
|
||||
mp_int_t n;
|
||||
} mp_obj_factorial_t;
|
||||
|
||||
mp_obj_full_type_t mp_type_FactorialError;
|
||||
|
||||
// Essentially Factorial.__new__ (but also kind of __init__).
|
||||
// Takes a single argument (the number to find the factorial of)
|
||||
static mp_obj_t factorial_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
|
||||
STATIC mp_obj_t factorial_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
|
||||
mp_obj_factorial_t *o = mp_obj_malloc(mp_obj_factorial_t, type);
|
||||
o->n = mp_obj_get_int(args_in[0]);
|
||||
|
||||
if (o->n < 0) {
|
||||
mp_raise_msg((mp_obj_type_t *)&mp_type_FactorialError, "argument must be zero or above");
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -51,16 +41,16 @@ static mp_int_t factorial_helper(mp_int_t x) {
|
||||
}
|
||||
|
||||
// Implements Factorial.calculate()
|
||||
static mp_obj_t factorial_calculate(mp_obj_t self_in) {
|
||||
STATIC mp_obj_t factorial_calculate(mp_obj_t self_in) {
|
||||
mp_obj_factorial_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_obj_new_int(factorial_helper(self->n));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(factorial_calculate_obj, factorial_calculate);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_calculate_obj, factorial_calculate);
|
||||
|
||||
// Locals dict for the Factorial type (will have a single method, calculate,
|
||||
// added in mpy_init).
|
||||
mp_map_elem_t factorial_locals_dict_table[1];
|
||||
static MP_DEFINE_CONST_DICT(factorial_locals_dict, factorial_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(factorial_locals_dict, factorial_locals_dict_table);
|
||||
|
||||
// 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) {
|
||||
@@ -78,12 +68,6 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
|
||||
// Make the Factorial type available on the module.
|
||||
mp_store_global(MP_QSTR_Factorial, MP_OBJ_FROM_PTR(&mp_type_factorial));
|
||||
|
||||
// Initialise the exception type.
|
||||
mp_obj_exception_init(&mp_type_FactorialError, MP_QSTR_FactorialError, &mp_type_Exception);
|
||||
|
||||
// Make the FactorialError type available on the module.
|
||||
mp_store_global(MP_QSTR_FactorialError, MP_OBJ_FROM_PTR(&mp_type_FactorialError));
|
||||
|
||||
// This must be last, it restores the globals dict
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#define MICROPY_PY_ARRAY (1)
|
||||
#define MICROPY_PY_FRAMEBUF (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
@@ -13,8 +12,8 @@ mp_obj_full_type_t mp_type_framebuf;
|
||||
|
||||
#include "extmod/modframebuf.c"
|
||||
|
||||
mp_map_elem_t framebuf_locals_dict_table[12];
|
||||
static MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table);
|
||||
mp_map_elem_t framebuf_locals_dict_table[11];
|
||||
STATIC MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table);
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
@@ -31,10 +30,9 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
|
||||
framebuf_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_rect), MP_OBJ_FROM_PTR(&framebuf_rect_obj) };
|
||||
framebuf_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_line), MP_OBJ_FROM_PTR(&framebuf_line_obj) };
|
||||
framebuf_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_ellipse), MP_OBJ_FROM_PTR(&framebuf_ellipse_obj) };
|
||||
framebuf_locals_dict_table[8] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_poly), MP_OBJ_FROM_PTR(&framebuf_poly_obj) };
|
||||
framebuf_locals_dict_table[9] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) };
|
||||
framebuf_locals_dict_table[10] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) };
|
||||
framebuf_locals_dict_table[11] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) };
|
||||
framebuf_locals_dict_table[8] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) };
|
||||
framebuf_locals_dict_table[9] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) };
|
||||
framebuf_locals_dict_table[10] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) };
|
||||
MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, locals_dict, (void*)&framebuf_locals_dict, 2);
|
||||
|
||||
mp_store_global(MP_QSTR_FrameBuffer, MP_OBJ_FROM_PTR(&mp_type_framebuf));
|
||||
|
@@ -38,10 +38,10 @@ mp_obj_full_type_t re_type;
|
||||
#include "extmod/modre.c"
|
||||
|
||||
mp_map_elem_t match_locals_dict_table[5];
|
||||
static MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
|
||||
|
||||
mp_map_elem_t re_locals_dict_table[3];
|
||||
static MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
@@ -1,75 +0,0 @@
|
||||
# Example of a HTTPS client working with non-blocking sockets.
|
||||
#
|
||||
# Non-blocking SSL streams works differently in MicroPython compared to CPython. In
|
||||
# CPython a write to an SSLSocket may raise ssl.SSLWantReadError. In MicroPython an
|
||||
# SSLSocket behaves like a normal socket/stream and can be polled for reading/writing.
|
||||
|
||||
from errno import EINPROGRESS
|
||||
import select
|
||||
import socket
|
||||
import ssl
|
||||
|
||||
|
||||
def connect_nonblocking(sock, addr):
|
||||
sock.setblocking(False)
|
||||
try:
|
||||
sock.connect(addr)
|
||||
except OSError as er:
|
||||
if er.errno != EINPROGRESS:
|
||||
raise er
|
||||
|
||||
|
||||
def write_nonblocking(poller, sock, data):
|
||||
poller.register(sock, select.POLLOUT)
|
||||
while data:
|
||||
poller.poll()
|
||||
n = sock.write(data)
|
||||
print("Wrote:", n)
|
||||
if n is not None:
|
||||
data = data[n:]
|
||||
|
||||
|
||||
def read_nonblocking(poller, sock, n):
|
||||
poller.register(sock, select.POLLIN)
|
||||
poller.poll()
|
||||
data = sock.read(n)
|
||||
print("Read:", len(data))
|
||||
return data
|
||||
|
||||
|
||||
def main(url):
|
||||
# Split the given URL into components.
|
||||
proto, _, host, path = url.split(b"/", 3)
|
||||
assert proto == b"https:"
|
||||
|
||||
# Note: this getaddrinfo() call is blocking!
|
||||
ai = socket.getaddrinfo(host, 443)[0]
|
||||
addr = ai[-1]
|
||||
print("Connect address:", addr)
|
||||
|
||||
# Create a TCP socket and connect to the server in non-blocking mode.
|
||||
sock = socket.socket(ai[0], ai[1], ai[2])
|
||||
connect_nonblocking(sock, addr)
|
||||
|
||||
# Wrap the TCP socket in an SSL stream in non-blocking mode.
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
sock = ctx.wrap_socket(sock, server_hostname=host, do_handshake_on_connect=False)
|
||||
sock.setblocking(False)
|
||||
|
||||
# Create an object to poll the SSL stream for readability/writability.
|
||||
poller = select.poll()
|
||||
|
||||
# Send the HTTP request on the SSL stream.
|
||||
request = b"GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path, host)
|
||||
write_nonblocking(poller, sock, request)
|
||||
|
||||
# Receive the HTTP response from the SSL stream.
|
||||
response = read_nonblocking(poller, sock, 1000)
|
||||
for line in response.split(b"\n"):
|
||||
print(line)
|
||||
|
||||
# Close the SSL stream. This will also close the underlying TCP socket.
|
||||
sock.close()
|
||||
|
||||
|
||||
main(b"https://micropython.org/ks/test.html")
|
@@ -1,16 +0,0 @@
|
||||
## USBDevice Examples
|
||||
|
||||
These are examples of how to use the low-level `machine.USBDevice` class to create custom
|
||||
USB device functionality.
|
||||
|
||||
Alternatively, there are [usb driver modules in
|
||||
micropython-lib](https://github.com/micropython/micropython-lib/tree/master/micropython/usb#readme)
|
||||
which provide a simpler interface and more built-in functionality.
|
||||
|
||||
In this directory:
|
||||
|
||||
* `usb_dfu_device.py` implements the USB Device Firmware Update protocol.
|
||||
* `usb_simple_device.py` implements a custom USB protocol, with a matching host
|
||||
program to run on a PC.
|
||||
|
||||
See comments at the top of each Python file for more details.
|
@@ -1,327 +0,0 @@
|
||||
# Implementation of USB DFU device in Python.
|
||||
#
|
||||
# To run, just execute this file on a device with machine.USBDevice support. The device
|
||||
# will then change to DFU mode.
|
||||
#
|
||||
# For example, use `mpremote` (the `--no-follow` option starts the script running
|
||||
# without waiting for a response, because there won't be a response, the USB will change
|
||||
# to a DFU device):
|
||||
#
|
||||
# $ mpremote run --no-follow usb_dfu_device.py
|
||||
#
|
||||
# Then you can access the DFU device using the `pydfu.py` script in this repository, to
|
||||
# list DFU device, copy a file to the device, then exit DFU mode:
|
||||
#
|
||||
# $ ../../tools/pydfu.py -l
|
||||
# $ ../../tools/pydfu.py -u <file.dfu>
|
||||
#
|
||||
# After running the last command above, the USB CDC device and REPL should reappear.
|
||||
|
||||
import struct, machine
|
||||
|
||||
# USB constants for bmRequestType.
|
||||
USB_REQ_RECIP_INTERFACE = 0x01
|
||||
USB_REQ_TYPE_CLASS = 0x20
|
||||
USB_DIR_OUT = 0x00
|
||||
USB_DIR_IN = 0x80
|
||||
|
||||
# String describing the memory layout of the DFU device.
|
||||
MEMORY_LAYOUT = b"@Internal Flash /0x08000000/16*128Kg"
|
||||
|
||||
# VID and PID of the DFU device (these are the ST values).
|
||||
VID = 0x0483
|
||||
PID = 0xDF11
|
||||
|
||||
# Maximum transfer size for RX and TX.
|
||||
wTransferSize = 2048
|
||||
|
||||
# DFU device descriptor.
|
||||
_desc_dev = bytes(
|
||||
[
|
||||
0x12, # bLength
|
||||
0x01, # bDescriptorType: Device
|
||||
0x00,
|
||||
0x02, # USB version: 2.00
|
||||
0x00, # bDeviceClass
|
||||
0x00, # bDeviceSubClass
|
||||
0x00, # bDeviceProtocol
|
||||
0x40, # bMaxPacketSize
|
||||
VID & 0xFF,
|
||||
VID >> 8, # VID
|
||||
PID & 0xFF,
|
||||
PID >> 8, # PID
|
||||
0x00,
|
||||
0x01, # bcdDevice: 1.00
|
||||
0x11, # iManufacturer
|
||||
0x12, # iProduct
|
||||
0x13, # iSerialNumber
|
||||
0x01, # bNumConfigurations: 1
|
||||
]
|
||||
)
|
||||
|
||||
# DFU configuration descriptor.
|
||||
_desc_cfg = bytes(
|
||||
[
|
||||
# Configuration Descriptor.
|
||||
0x09, # bLength
|
||||
0x02, # bDescriptorType
|
||||
0x1B,
|
||||
0x00, # wTotalLength: 27
|
||||
0x01, # bNumInterfaces
|
||||
0x01, # bConfigurationValue
|
||||
0x00, # iConfiguration
|
||||
0x80, # bmAttributes (bus powered)
|
||||
0x32, # bMaxPower
|
||||
# Interface Descriptor.
|
||||
0x09, # bLength
|
||||
0x04, # bDescriptorType
|
||||
0x00, # bInterfaceNumber
|
||||
0x00, # bNumEndpointns
|
||||
0x00, # bAlternateSetting
|
||||
0xFE, # bInterfaceClass: application specific interface
|
||||
0x01, # bInterfaceSubClasse: device firmware update
|
||||
0x02, # bInterfaceProtocol
|
||||
0x14, # iInterface
|
||||
# Device Firmware Upgrade Interface Descriptor.
|
||||
0x09, # bLength
|
||||
0x21, # bDescriptorType
|
||||
0x0B, # bmAttributes (will detach, upload supported, download supported)
|
||||
0xFF,
|
||||
0x00, # wDetatchTimeout
|
||||
wTransferSize & 0xFF,
|
||||
wTransferSize >> 8, # wTransferSize
|
||||
0x1A,
|
||||
0x01, # bcdDFUVersion
|
||||
]
|
||||
)
|
||||
|
||||
# DFU strings.
|
||||
_desc_strs = {
|
||||
0x11: b"iManufacturer",
|
||||
0x12: b"iProduct",
|
||||
0x13: b"iSerialNumber",
|
||||
0x14: MEMORY_LAYOUT,
|
||||
}
|
||||
|
||||
|
||||
# This class handles the DFU USB device logic.
|
||||
class DFUOverUSB:
|
||||
def __init__(self, dfu):
|
||||
# USB buffer for transfers.
|
||||
self.usb_buf = bytearray(wTransferSize)
|
||||
# Instance of the DFU state machine.
|
||||
self.dfu = dfu
|
||||
|
||||
def _control_xfer_cb(self, stage, request):
|
||||
bmRequestType, bRequest, wValue, wIndex, wLength = struct.unpack("<BBHHH", request)
|
||||
if stage == 1: # SETUP
|
||||
if bmRequestType == USB_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_RECIP_INTERFACE:
|
||||
# Data coming from host, prepare to receive it.
|
||||
return memoryview(self.usb_buf)[:wLength]
|
||||
if bmRequestType == USB_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_RECIP_INTERFACE:
|
||||
# Host requests data, prepare to send it.
|
||||
buf = memoryview(self.usb_buf)[:wLength]
|
||||
return self.dfu.handle_tx(bRequest, wValue, buf)
|
||||
elif stage == 3: # ACK
|
||||
if bmRequestType & USB_DIR_IN:
|
||||
# EP0 TX sent.
|
||||
self.dfu.process()
|
||||
else:
|
||||
# EP0 RX ready.
|
||||
buf = memoryview(self.usb_buf)[:wLength]
|
||||
self.dfu.handle_rx(bRequest, wValue, buf)
|
||||
return True
|
||||
|
||||
|
||||
# This class handles the DFU state machine.
|
||||
class DFU:
|
||||
# DFU class requests.
|
||||
DETACH = 0
|
||||
DNLOAD = 1
|
||||
UPLOAD = 2
|
||||
GETSTATUS = 3
|
||||
CLRSTATUS = 4
|
||||
GETSTATE = 5
|
||||
ABORT = 6
|
||||
|
||||
# DFU states.
|
||||
STATE_IDLE = 2
|
||||
STATE_BUSY = 4
|
||||
STATE_DNLOAD_IDLE = 5
|
||||
STATE_MANIFEST = 7
|
||||
STATE_UPLOAD_IDLE = 9
|
||||
STATE_ERROR = 0xA
|
||||
|
||||
# DFU commands.
|
||||
CMD_NONE = 0
|
||||
CMD_EXIT = 1
|
||||
CMD_UPLOAD = 7
|
||||
CMD_DNLOAD = 8
|
||||
|
||||
# Download sub-commands.
|
||||
CMD_DNLOAD_SET_ADDRESS = 0x21
|
||||
CMD_DNLOAD_ERASE = 0x41
|
||||
CMD_DNLOAD_READ_UNPROTECT = 0x92
|
||||
|
||||
# Error status flags.
|
||||
STATUS_OK = 0x00
|
||||
|
||||
def __init__(self):
|
||||
self.state = DFU.STATE_IDLE
|
||||
self.cmd = DFU.CMD_NONE
|
||||
self.status = DFU.STATUS_OK
|
||||
self.error = 0
|
||||
self.leave_dfu = False
|
||||
self.addr = 0
|
||||
self.dnload_block_num = 0
|
||||
self.dnload_len = 0
|
||||
self.dnload_buf = bytearray(wTransferSize)
|
||||
|
||||
def handle_rx(self, cmd, arg, buf):
|
||||
# Handle an incoming packet of data.
|
||||
if cmd == DFU.CLRSTATUS:
|
||||
self.state = DFU.STATE_IDLE
|
||||
self.cmd = DFU.CMD_NONE
|
||||
self.status = DFU.STATUS_OK
|
||||
self.error = 0
|
||||
elif cmd == DFU.ABORT:
|
||||
self.state = DFU.STATE_IDLE
|
||||
self.cmd = DFU.CMD_NONE
|
||||
self.status = DFU.STATUS_OK
|
||||
self.error = 0
|
||||
elif cmd == DFU.DNLOAD:
|
||||
if len(buf) == 0:
|
||||
# Exit DFU.
|
||||
self.cmd = DFU.CMD_EXIT
|
||||
else:
|
||||
# Download data to device.
|
||||
self.cmd = DFU.CMD_DNLOAD
|
||||
self.dnload_block_num = arg
|
||||
self.dnload_len = len(buf)
|
||||
self.dnload_buf[: len(buf)] = buf
|
||||
|
||||
def handle_tx(self, cmd, arg, buf):
|
||||
# Prepare data to go to the host.
|
||||
if cmd == DFU.UPLOAD:
|
||||
if arg >= 2:
|
||||
self.cmd = DFU.CMD_UPLOAD
|
||||
addr = (arg - 2) * len(buf) + self.addr
|
||||
self.do_read(addr, buf)
|
||||
return buf
|
||||
return None
|
||||
elif cmd == DFU.GETSTATUS and len(buf) == 6:
|
||||
if self.cmd == DFU.CMD_NONE:
|
||||
pass
|
||||
elif self.cmd == DFU.CMD_EXIT:
|
||||
self.state = DFU.STATE_MANIFEST
|
||||
elif self.cmd == DFU.CMD_UPLOAD:
|
||||
self.state = DFU.STATE_UPLOAD_IDLE
|
||||
elif self.cmd == DFU.CMD_DNLOAD:
|
||||
self.state = DFU.STATE_BUSY
|
||||
else:
|
||||
self.state = DFU.STATE_BUSY
|
||||
|
||||
# Populate the buffer to return to the host.
|
||||
buf[0] = self.status
|
||||
buf[1] = 0
|
||||
buf[2] = 0
|
||||
buf[3] = 0
|
||||
buf[4] = self.state
|
||||
buf[5] = self.error
|
||||
|
||||
# Clear errors now they've been sent to host.
|
||||
self.status = DFU.STATUS_OK
|
||||
self.error = 0
|
||||
|
||||
return buf
|
||||
else:
|
||||
return None
|
||||
|
||||
def process(self):
|
||||
# Transition the DFU state machine.
|
||||
if self.state == DFU.STATE_MANIFEST:
|
||||
self.leave_dfu = True
|
||||
elif self.state == DFU.STATE_BUSY:
|
||||
if self.cmd == DFU.CMD_DNLOAD:
|
||||
self.cmd = DFU.CMD_NONE
|
||||
self.state = self.process_dnload()
|
||||
|
||||
def process_dnload(self):
|
||||
ret = -1 # Assume error.
|
||||
if self.dnload_block_num == 0:
|
||||
# Download control commands.
|
||||
if self.dnload_len >= 1 and self.dnload_buf[0] == DFU.CMD_DNLOAD_ERASE:
|
||||
if self.dnload_len == 1:
|
||||
# Mass erase.
|
||||
ret = self.do_mass_erase()
|
||||
if ret != 0:
|
||||
self.cmd = DFU.CMD_NONE
|
||||
elif self.dnload_len == 5:
|
||||
# Erase page.
|
||||
addr = struct.unpack_from("<L", self.dnload_buf, 1)[0]
|
||||
ret = self.do_page_erase(addr)
|
||||
elif self.dnload_len >= 1 and self.dnload_buf[0] == DFU.CMD_DNLOAD_SET_ADDRESS:
|
||||
if self.dnload_len == 5:
|
||||
# Set address.
|
||||
self.addr = struct.unpack_from("<L", self.dnload_buf, 1)[0]
|
||||
ret = 0
|
||||
elif self.dnload_block_num > 1:
|
||||
# Write data to memory.
|
||||
addr = (self.dnload_block_num - 2) * wTransferSize + self.addr
|
||||
ret = self.do_write(addr, self.dnload_len, self.dnload_buf)
|
||||
if ret == 0:
|
||||
return DFU.STATE_DNLOAD_IDLE
|
||||
else:
|
||||
return DFU.STATE_ERROR
|
||||
|
||||
def do_mass_erase(self):
|
||||
# This function would implement a mass erase of flash memory.
|
||||
return 0 # indicate success
|
||||
|
||||
def do_page_erase(self, addr):
|
||||
# This function would implement an erase of a page in flash memory.
|
||||
return 0 # indicate success
|
||||
|
||||
def do_read(self, addr, buf):
|
||||
# This function would implement a read at the given address of flash memory.
|
||||
# Return some dummy bytes.
|
||||
for i in range(len(buf)):
|
||||
buf[i] = i & 0xFF
|
||||
return 0 # indicate success
|
||||
|
||||
def do_write(self, addr, size, buf):
|
||||
# This function would implement a write of the given data to flash memory.
|
||||
return 0 # indicate success
|
||||
|
||||
|
||||
# Create an instance of the DFU state machine.
|
||||
dfu = DFU()
|
||||
|
||||
# Create an instance of the DFU USB handler.
|
||||
dfu_usb = DFUOverUSB(dfu)
|
||||
|
||||
# Switch the USB device to the custom DFU driver.
|
||||
usbd = machine.USBDevice()
|
||||
usbd.active(0)
|
||||
usbd.builtin_driver = usbd.BUILTIN_NONE
|
||||
usbd.config(
|
||||
desc_dev=_desc_dev,
|
||||
desc_cfg=_desc_cfg,
|
||||
desc_strs=_desc_strs,
|
||||
control_xfer_cb=dfu_usb._control_xfer_cb,
|
||||
)
|
||||
usbd.active(1)
|
||||
|
||||
# Wait for the DFU state machine to complete.
|
||||
while not dfu.leave_dfu:
|
||||
machine.idle()
|
||||
|
||||
# Switch the USB device back to the default built-in driver.
|
||||
usbd.active(0)
|
||||
usbd.builtin_driver = usbd.BUILTIN_DEFAULT
|
||||
usbd.config(
|
||||
desc_dev=usbd.builtin_driver.desc_dev,
|
||||
desc_cfg=usbd.builtin_driver.desc_cfg,
|
||||
desc_strs=(),
|
||||
)
|
||||
usbd.active(1)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user