diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 195e1e06eea..97b5e558f40 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,3 +1,6 @@ +# all: Apply code formatting to new paths. +48c7daaa3d7068c127c5bc395ffa72029ab9bba1 + # all: Prune trailing whitespace. dda9b9c6da5d3c31fa8769e581a753e95a270803 diff --git a/.gitattributes b/.gitattributes index fbab4e69abe..04a84d3e098 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,7 @@ # These are binary so should never be modified by git. *.a binary +*.FLM binary *.ico binary *.png binary *.jpg binary diff --git a/.github/actions/setup_esp32/action.yml b/.github/actions/setup_esp32/action.yml index 42c44cf76ce..3b5da9eca87 100644 --- a/.github/actions/setup_esp32/action.yml +++ b/.github/actions/setup_esp32/action.yml @@ -19,7 +19,7 @@ runs: - name: Cached ESP-IDF install id: cache_esp_idf - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: | ./esp-idf/ diff --git a/.github/workflows/biome.yml b/.github/workflows/biome.yml index 0cde10acc91..eba4e9f3908 100644 --- a/.github/workflows/biome.yml +++ b/.github/workflows/biome.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Setup Biome uses: biomejs/setup-biome@v2 with: diff --git a/.github/workflows/code_formatting.yml b/.github/workflows/code_formatting.yml index 95653d941f9..5616fe33d7c 100644 --- a/.github/workflows/code_formatting.yml +++ b/.github/workflows/code_formatting.yml @@ -10,8 +10,8 @@ jobs: code-formatting: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 - name: Install packages run: tools/ci.sh c_code_formatting_setup - name: Run code formatting diff --git a/.github/workflows/code_size.yml b/.github/workflows/code_size.yml index f3238a85d9a..dc3a47ded26 100644 --- a/.github/workflows/code_size.yml +++ b/.github/workflows/code_size.yml @@ -26,7 +26,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: fetch-depth: 100 - name: Install packages @@ -38,6 +38,12 @@ jobs: echo "IDF_VER="$(yq .env.IDF_NEWEST_VER < .github/workflows/ports_esp32.yml) \ | tee "${GITHUB_OUTPUT}" + # The reference and current commit may be configured for different ESP-IDF versions + # but we use the same ESP-IDF version to build both, so disable the + # MICROPY_MAINTAINER_BUILD check (it'll be verified on the normal esp32 CI). + - name: Disable extra checks for older ESP-IDF + run: echo "MICROPY_MAINTAINER_BUILD=0" >> ${GITHUB_ENV} + - name: Setup ESP-IDF uses: ./.github/actions/setup_esp32 with: diff --git a/.github/workflows/code_size_comment.yml b/.github/workflows/code_size_comment.yml index 2eed0b06b8e..ea9d45ddb87 100644 --- a/.github/workflows/code_size_comment.yml +++ b/.github/workflows/code_size_comment.yml @@ -15,7 +15,7 @@ jobs: steps: - name: 'Download artifact' id: download-artifact - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: result-encoding: string script: | @@ -56,7 +56,7 @@ jobs: run: unzip code-size-report.zip - name: Post comment to pull request if: steps.download-artifact.outputs.result == 'ok' - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index e3a9c79bd5e..6155a348b5d 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -6,7 +6,7 @@ jobs: codespell: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 # codespell version should be kept in sync with .pre-commit-config.yml - run: pip install --user codespell==2.4.1 tomli - run: codespell diff --git a/.github/workflows/commit_formatting.yml b/.github/workflows/commit_formatting.yml index 6abc3612a00..0e38ebcf868 100644 --- a/.github/workflows/commit_formatting.yml +++ b/.github/workflows/commit_formatting.yml @@ -10,9 +10,9 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: fetch-depth: 100 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v7 - name: Check commit message formatting run: tools/ci.sh commit_formatting_run diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 79755b74197..a27196734ad 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -17,8 +17,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 - name: Install Python packages run: pip install -r docs/requirements.txt - name: Build unix port diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 4627247fb9f..bbfc93b1f64 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -18,6 +18,6 @@ jobs: embedding: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build run: tools/ci.sh embedding_build diff --git a/.github/workflows/mpremote.yml b/.github/workflows/mpremote.yml index ad5dd454905..65ae823a14b 100644 --- a/.github/workflows/mpremote.yml +++ b/.github/workflows/mpremote.yml @@ -11,12 +11,12 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: # Setting this to zero means fetch all history and tags, # which hatch-vcs can use to discover the version tag. fetch-depth: 0 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v7 - name: Install build tools run: pip install build - name: Build mpremote wheel diff --git a/.github/workflows/mpy_format.yml b/.github/workflows/mpy_format.yml index ab668c1cb5e..965bcedc73e 100644 --- a/.github/workflows/mpy_format.yml +++ b/.github/workflows/mpy_format.yml @@ -19,7 +19,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh mpy_format_setup - name: Test mpy-tool.py diff --git a/.github/workflows/ports.yml b/.github/workflows/ports.yml index 5e71d4d076a..5da3f2be969 100644 --- a/.github/workflows/ports.yml +++ b/.github/workflows/ports.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build ports download metadata run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards diff --git a/.github/workflows/ports_alif.yml b/.github/workflows/ports_alif.yml index 6fb225937a9..e7d1064c97a 100644 --- a/.github/workflows/ports_alif.yml +++ b/.github/workflows/ports_alif.yml @@ -26,7 +26,7 @@ jobs: - alif_ae3_build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh alif_setup - name: Build ci_${{matrix.ci_func }} diff --git a/.github/workflows/ports_cc3200.yml b/.github/workflows/ports_cc3200.yml index 194483ec218..5f920efda78 100644 --- a/.github/workflows/ports_cc3200.yml +++ b/.github/workflows/ports_cc3200.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh cc3200_setup - name: Build diff --git a/.github/workflows/ports_esp32.yml b/.github/workflows/ports_esp32.yml index 56dce3b69d9..e1b57a24b7b 100644 --- a/.github/workflows/ports_esp32.yml +++ b/.github/workflows/ports_esp32.yml @@ -20,7 +20,7 @@ concurrency: env: # Oldest and newest supported ESP-IDF versions, should match ports/esp32/README.md IDF_OLDEST_VER: &oldest "v5.3" - IDF_NEWEST_VER: &newest "v5.5.1" + IDF_NEWEST_VER: &newest "v5.5.5" jobs: build_idf: @@ -31,19 +31,19 @@ jobs: - *oldest - *newest ci_func: # names are functions in ci.sh - - esp32_build_cmod_spiram_s2 - - esp32_build_s3_c3 + - esp32_build_cmod_spiram_d2wd + - esp32_build_s2_s3_c3 - esp32_build_c2_c5_c6 - - esp32_build_p4 + - esp32_build_h2_p4 exclude: # Exclude some jobs on the oldest IDF version, to save resources - idf_ver: *oldest ci_func: esp32_build_c2_c5_c6 - idf_ver: *oldest - ci_func: esp32_build_p4 + ci_func: esp32_build_h2_p4 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 # Only the newest IDF version will build the ESP-IDF lockfiles correctly, # so we need to disable MICROPY_MAINTAINER_BUILD on older versions. diff --git a/.github/workflows/ports_esp8266.yml b/.github/workflows/ports_esp8266.yml index eb7f59cdc49..156f3181bbc 100644 --- a/.github/workflows/ports_esp8266.yml +++ b/.github/workflows/ports_esp8266.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh esp8266_setup && tools/ci.sh esp8266_path >> $GITHUB_PATH - name: Build diff --git a/.github/workflows/ports_mimxrt.yml b/.github/workflows/ports_mimxrt.yml index fd80f3f6329..4f171d11474 100644 --- a/.github/workflows/ports_mimxrt.yml +++ b/.github/workflows/ports_mimxrt.yml @@ -24,7 +24,7 @@ jobs: run: working-directory: 'micropython repo' # test build with space in path steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: path: 'micropython repo' - name: Install packages diff --git a/.github/workflows/ports_nrf.yml b/.github/workflows/ports_nrf.yml index bec9a5dfb5b..53a5d6139d6 100644 --- a/.github/workflows/ports_nrf.yml +++ b/.github/workflows/ports_nrf.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh nrf_setup - name: Build diff --git a/.github/workflows/ports_powerpc.yml b/.github/workflows/ports_psoc-edge.yml similarity index 67% rename from .github/workflows/ports_powerpc.yml rename to .github/workflows/ports_psoc-edge.yml index a883d026806..f0f37e94939 100644 --- a/.github/workflows/ports_powerpc.yml +++ b/.github/workflows/ports_psoc-edge.yml @@ -1,4 +1,4 @@ -name: powerpc port +name: psoc-edge port on: push: @@ -11,18 +11,18 @@ on: - 'shared/**' - 'lib/**' - 'drivers/**' - - 'ports/powerpc/**' + - 'ports/psoc-edge/**' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - build: + build_psoc_edge: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages - run: tools/ci.sh powerpc_setup + run: tools/ci.sh psoc_edge_setup - name: Build - run: tools/ci.sh powerpc_build + run: tools/ci.sh psoc_edge_build diff --git a/.github/workflows/ports_qemu.yml b/.github/workflows/ports_qemu.yml index 0ed95dbe5f9..f064930d832 100644 --- a/.github/workflows/ports_qemu.yml +++ b/.github/workflows/ports_qemu.yml @@ -30,7 +30,7 @@ jobs: - thumb_hardfp runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh qemu_setup_arm - name: Build and run test suite ci_qemu_build_arm_${{ matrix.ci_func }} @@ -42,7 +42,7 @@ jobs: build_and_test_rv32: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh qemu_setup_rv32 - name: Build and run test suite @@ -54,7 +54,7 @@ jobs: build_and_test_rv64: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh qemu_setup_rv64 - name: Build and run test suite @@ -62,3 +62,15 @@ jobs: - name: Print failures if: failure() run: tests/run-tests.py --print-failures + + build_and_test_ppc64: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - name: Install packages + run: tools/ci.sh qemu_setup_ppc64 + - name: Build and run test suite + run: tools/ci.sh qemu_build_ppc64 + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures diff --git a/.github/workflows/ports_renesas-ra.yml b/.github/workflows/ports_renesas-ra.yml index 920691eca70..1e5bfb447e8 100644 --- a/.github/workflows/ports_renesas-ra.yml +++ b/.github/workflows/ports_renesas-ra.yml @@ -21,7 +21,7 @@ jobs: build_renesas_ra_board: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh renesas_ra_setup - name: Build diff --git a/.github/workflows/ports_rp2.yml b/.github/workflows/ports_rp2.yml index ea19e2da7ff..27d6c60a5c5 100644 --- a/.github/workflows/ports_rp2.yml +++ b/.github/workflows/ports_rp2.yml @@ -24,7 +24,7 @@ jobs: run: working-directory: 'micropython repo' # test build with space in path steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: path: 'micropython repo' - name: Install packages diff --git a/.github/workflows/ports_samd.yml b/.github/workflows/ports_samd.yml index eb806ceb044..04cddeb76de 100644 --- a/.github/workflows/ports_samd.yml +++ b/.github/workflows/ports_samd.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh samd_setup - name: Build diff --git a/.github/workflows/ports_stm32.yml b/.github/workflows/ports_stm32.yml index 2ed730eb4e8..2099b8b7c03 100644 --- a/.github/workflows/ports_stm32.yml +++ b/.github/workflows/ports_stm32.yml @@ -24,11 +24,12 @@ jobs: matrix: ci_func: # names are functions in ci.sh - stm32_pyb_build + - stm32_build_cmod - stm32_nucleo_build - stm32_misc_build runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh stm32_setup && tools/ci.sh stm32_path >> $GITHUB_PATH - name: Build ci_${{matrix.ci_func }} diff --git a/.github/workflows/ports_unix.yml b/.github/workflows/ports_unix.yml index 57f4a964b2f..8231c1eb1ea 100644 --- a/.github/workflows/ports_unix.yml +++ b/.github/workflows/ports_unix.yml @@ -23,7 +23,7 @@ jobs: minimal: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build run: tools/ci.sh unix_minimal_build - name: Run main test suite @@ -35,7 +35,7 @@ jobs: reproducible: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build with reproducible date run: tools/ci.sh unix_minimal_build env: @@ -46,7 +46,7 @@ jobs: standard: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build run: tools/ci.sh unix_standard_build - name: Run main test suite @@ -58,7 +58,7 @@ jobs: standard_v2: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build run: tools/ci.sh unix_standard_v2_build - name: Run main test suite @@ -67,11 +67,35 @@ jobs: if: failure() run: tests/run-tests.py --print-failures + standard_error_terse: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - name: Build + run: tools/ci.sh unix_standard_error_terse_build + - name: Run main test suite + run: tools/ci.sh unix_standard_error_terse_run_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures + + standard_error_none: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - name: Build + run: tools/ci.sh unix_standard_error_none_build + - name: Run main test suite + run: tools/ci.sh unix_standard_error_none_run_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures + coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -93,12 +117,14 @@ 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@v6 + uses: codecov/codecov-action@v7 with: # Only fail the job on error if a token is set, or we're running against upstream repo. # This avoids the annoying situation of the job failing on every push to a fork (if no token is set). fail_ci_if_error: ${{ secrets.CODECOV_TOKEN != '' || github.repository_owner == 'micropython' }} verbose: true + flags: unix-coverage-64bit + name: unix-coverage-64bit # note: when a fork opens a PR into MicroPython repo, the pull_request trigger can't access # secrets so this token value will be empty (codecov will do a 'tokenless' upload). token: ${{ secrets.CODECOV_TOKEN }} @@ -109,8 +135,8 @@ jobs: coverage_32bit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -125,6 +151,20 @@ jobs: run: tools/ci.sh native_mpy_modules_32bit_build - name: Test importing .mpy generated by mpy_ld.py run: tools/ci.sh unix_coverage_32bit_run_native_mpy_tests + - name: Run gcov coverage analysis + run: | + (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@v7 + with: + # See corresponding comment above. + fail_ci_if_error: ${{ secrets.CODECOV_TOKEN != '' || github.repository_owner == 'micropython' }} + verbose: true + flags: unix-coverage-32bit + name: unix-coverage-32bit + # See corresponding comment above. + token: ${{ secrets.CODECOV_TOKEN }} - name: Print failures if: failure() run: tests/run-tests.py --print-failures @@ -132,8 +172,8 @@ jobs: nanbox: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -151,8 +191,8 @@ jobs: longlong: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -170,7 +210,7 @@ jobs: float: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build run: tools/ci.sh unix_float_build - name: Run main test suite @@ -182,7 +222,7 @@ jobs: gil_enabled: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build run: tools/ci.sh unix_gil_enabled_build - name: Run main test suite @@ -194,7 +234,7 @@ jobs: stackless_clang: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh unix_clang_setup - name: Build @@ -208,13 +248,17 @@ jobs: float_clang: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh unix_clang_setup - name: Build run: tools/ci.sh unix_float_clang_build - name: Run main test suite run: tools/ci.sh unix_float_clang_run_tests + - name: Build native mpy modules + run: tools/ci.sh native_mpy_modules_clang_build + - name: Test importing .mpy generated by mpy_ld.py + run: tools/ci.sh unix_standard_run_native_mpy_tests - name: Print failures if: failure() run: tests/run-tests.py --print-failures @@ -222,8 +266,8 @@ jobs: settrace_stackless: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -239,8 +283,8 @@ jobs: repr_b: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -258,8 +302,8 @@ jobs: macos: runs-on: macos-26 steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 with: python-version: '3.8' - name: Build @@ -273,8 +317,8 @@ jobs: qemu_mips: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -292,8 +336,8 @@ jobs: qemu_arm: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -311,8 +355,8 @@ jobs: qemu_riscv64: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -327,11 +371,49 @@ jobs: if: failure() run: tests/run-tests.py --print-failures + qemu_loong64: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. + # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. + with: + python-version: '3.11' + - name: Install packages + run: tools/ci.sh unix_qemu_loong64_setup + - name: Build + run: tools/ci.sh unix_qemu_loong64_build + - name: Run main test suite + run: tools/ci.sh unix_qemu_loong64_run_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures + + qemu_x64: + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. + # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. + with: + python-version: '3.11' + - name: Install packages + run: tools/ci.sh unix_qemu_x64_setup + - name: Build + run: tools/ci.sh unix_qemu_x64_build + - name: Run main test suite + run: tools/ci.sh unix_qemu_x64_run_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures + sanitize_address: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: @@ -355,8 +437,8 @@ jobs: sanitize_undefined: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. with: diff --git a/.github/workflows/ports_webassembly.yml b/.github/workflows/ports_webassembly.yml index f6619cc8976..ac2050129ef 100644 --- a/.github/workflows/ports_webassembly.yml +++ b/.github/workflows/ports_webassembly.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh webassembly_setup - name: Build diff --git a/.github/workflows/ports_windows.yml b/.github/workflows/ports_windows.yml index 1243366d413..af830ca194e 100644 --- a/.github/workflows/ports_windows.yml +++ b/.github/workflows/ports_windows.yml @@ -49,13 +49,13 @@ jobs: - name: Install Python 3.11 # As of 20260112 the default Python version in Windows image is 3.12, which breaks settrace tests # Use 3.11 for now - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: '3.11' - uses: microsoft/setup-msbuild@v3 with: vs-version: ${{ matrix.vs_version }} - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build mpy-cross.exe run: msbuild mpy-cross\mpy-cross.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} -property:PlatformToolset=${{ matrix.platform_toolset }} - name: Update submodules @@ -106,7 +106,7 @@ jobs: run: shell: msys2 {0} steps: - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v7 # note: can go back to installing mingw-w64-${{ matrix.env }}-python after # MSYS2 updates to Python >3.12 (due to settrace compatibility issue) with: @@ -122,7 +122,7 @@ jobs: git diffutils path-type: inherit # Remove when setup-python is removed - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Build mpy-cross.exe run: make -C mpy-cross -j2 - name: Update submodules @@ -140,7 +140,7 @@ jobs: cross-build-on-linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install packages run: tools/ci.sh windows_setup - name: Build diff --git a/.github/workflows/ports_zephyr.yml b/.github/workflows/ports_zephyr.yml index 330121d1de6..8ed9845927f 100644 --- a/.github/workflows/ports_zephyr.yml +++ b/.github/workflows/ports_zephyr.yml @@ -33,13 +33,13 @@ jobs: docker-images: false tool-cache: true swap-storage: false - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - id: versions name: Read Zephyr version run: source tools/ci.sh && echo "ZEPHYR=$ZEPHYR_VERSION" | tee "$GITHUB_OUTPUT" - name: Cached Zephyr Workspace id: cache_workspace - uses: actions/cache@v5 + uses: actions/cache@v6 with: # note that the Zephyr CI docker image is 15GB. At time of writing # GitHub caches are limited to 10GB total for a project. So we only diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 6a8d4055a91..a5a6fc7e26c 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -6,7 +6,7 @@ jobs: ruff: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 # ruff version should be kept in sync with .pre-commit-config.yaml & also micropython-lib - run: pipx install ruff==0.11.6 - run: ruff check --output-format=github . diff --git a/.gitignore b/.gitignore index 56616426fb2..b17423ca050 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ build/ build-*/ docs/genrst/ +.mpy_ld_cache-*/ # Test failure outputs and intermediate artefacts tests/results/* diff --git a/.gitmodules b/.gitmodules index d2c229dd6d7..425bf7fd333 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,7 +26,7 @@ branch = circuitpython [submodule "lib/tinyusb"] path = lib/tinyusb - url = https://github.com/hathach/tinyusb + url = https://github.com/micropython/tinyusb.git [submodule "lib/mynewt-nimble"] path = lib/mynewt-nimble url = https://github.com/micropython/mynewt-nimble.git @@ -74,3 +74,33 @@ [submodule "lib/alif-security-toolkit"] path = lib/alif-security-toolkit url = https://github.com/micropython/alif-security-toolkit.git +[submodule "lib/CMSIS_5"] + path = lib/CMSIS_5 + url = https://github.com/ARM-software/CMSIS_5.git +[submodule "lib/CMSIS_6"] + path = lib/CMSIS_6 + url = https://github.com/ARM-software/CMSIS_6.git +[submodule "lib/psoc-edge/TARGET_KIT_PSE84_AI"] + path = lib/psoc-edge/TARGET_KIT_PSE84_AI + url = https://github.com/Infineon/TARGET_KIT_PSE84_AI.git +[submodule "lib/psoc-edge/core-lib"] + path = lib/psoc-edge/core-lib + url = https://github.com/Infineon/core-lib.git +[submodule "lib/psoc-edge/mtb-dsl-pse8xxgp"] + path = lib/psoc-edge/mtb-dsl-pse8xxgp + url = https://github.com/Infineon/mtb-dsl-pse8xxgp.git +[submodule "lib/psoc-edge/mtb-srf"] + path = lib/psoc-edge/mtb-srf + url = https://github.com/Infineon/mtb-srf.git +[submodule "lib/psoc-edge/se-rt-services-utils"] + path = lib/psoc-edge/se-rt-services-utils + url = https://github.com/Infineon/se-rt-services-utils.git +[submodule "lib/psoc-edge/serial-memory"] + path = lib/psoc-edge/serial-memory + url = https://github.com/Infineon/serial-memory.git +[submodule "lib/psoc-edge/mtb-ipc"] + path = lib/psoc-edge/mtb-ipc + url = https://github.com/Infineon/mtb-ipc.git +[submodule "lib/psoc-edge/async-transfer"] + path = lib/psoc-edge/async-transfer + url = https://github.com/Infineon/async-transfer.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ac9785bb592..ad4136c59fc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,6 +5,8 @@ repos: name: MicroPython codeformat.py for changed C files entry: tools/codeformat.py -v -c -f language: python + additional_dependencies: + - micropython-uncrustify==1.0.0.post1 - id: verifygitlog name: MicroPython git commit message format checker entry: tools/verifygitlog.py --check-file --ignore-rebase diff --git a/CODECONVENTIONS.md b/CODECONVENTIONS.md index d3f71cb083d..0f40156b878 100644 --- a/CODECONVENTIONS.md +++ b/CODECONVENTIONS.md @@ -72,36 +72,28 @@ be used for MicroPython. Different uncrustify versions produce slightly different formatting, and the configuration file formats are often incompatible. v0.73 or newer *will not work*. -Depending on your operating system version, it may be possible to install a pre-compiled -uncrustify version: +Depending on your operating system version, it may be possible to install a +compatible pre-compiled uncrustify version. Otherwise, a compatible version is +available via the PyPI package archive: -Ubuntu, Debian --------------- - -Ubuntu versions 21.10 or 22.04LTS, and Debian versions bullseye or bookworm all -include v0.72 so can be installed directly: +Pip +--- ``` -$ apt install uncrustify +pip install micropython-uncrustify ``` -Arch Linux ----------- - -The current Arch uncrustify version is too new. There is an [old Arch package -for v0.72](https://archive.archlinux.org/packages/u/uncrustify/) that can be -installed from the Arch Linux archive ([more -information](https://wiki.archlinux.org/title/Downgrading_packages#Arch_Linux_Archive)). Use -the [IgnorePkg feature](https://wiki.archlinux.org/title/Pacman#Skip_package_from_being_upgraded) -to prevent it re-updating. +This installs a native compiled uncrustify binary as a Python executable, so it +can be installed into a virtualenv. -Brew +Pipx ---- -This command may work, please raise a new Issue if it doesn't: +It's also possible to install via [pipx](https://pipx.pypa.io/) if not using a +virtualenv: ``` -curl -L https://github.com/Homebrew/homebrew-core/raw/2b07d8192623365078a8b855a164ebcdf81494a6/Formula/uncrustify.rb > uncrustify.rb && brew install uncrustify.rb && rm uncrustify.rb +pipx install micropython-uncrustify ``` Code spell checking @@ -127,6 +119,9 @@ To have code formatting and commit message conventions automatically checked, a configuration file is provided for the [pre-commit](https://pre-commit.com/) tool. +Pre-commit will automatically install the correct version of dependencies +such as codespell, uncrustify, etc. + First install `pre-commit`, either from your system package manager or via `pip`. When installing `pre-commit` via pip, it is recommended to use a virtual environment. Other sources, such as Brew are also available, see @@ -139,10 +134,6 @@ $ brew install pre-commit # Brew $ pip install pre-commit # PyPI ``` -Next, install [uncrustify (see above)](#uncrustify). Other dependencies are managed by -pre-commit automatically, but uncrustify needs to be installed and available on -the PATH. - Then, inside the MicroPython repository, register the git hooks for pre-commit by running: diff --git a/LICENSE b/LICENSE index 28b5239e5fe..b9078c7c71c 100644 --- a/LICENSE +++ b/LICENSE @@ -37,6 +37,8 @@ used during the build process and is not part of the compiled source code. /drivers /cc3100 (BSD-3-clause) /lib + /CMSIS_5 (Apache-2.0) + /CMSIS_6 (Apache-2.0) /asf4 (Apache-2.0) /axtls (BSD-3-clause) /config @@ -45,7 +47,6 @@ used during the build process and is not part of the compiled source code. /Rules.mak (GPL-2.0) /berkeley-db-1xx (BSD-4-clause) /btstack (See btstack/LICENSE) - /cmsis (BSD-3-clause) /crypto-algorithms (NONE) /libhydrogen (ISC) /libmetal (BSD-3-clause) diff --git a/README.md b/README.md index 5f6d4288bf2..51bd471e428 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ still fully supported: | [alif](ports/alif) | Alif Semiconductor Ensemble MCUs (E3, E7) | | | [embed](ports/embed) | Generates a set of .c/.h files for embedding into a project | | | [nrf](ports/nrf) | Nordic Semiconductor nRF51 and nRF52 | | +| [psoc-edge](ports/psoc-edge) | Infineon PSOC™ Edge | [here](https://docs.micropython.org/en/latest/psoc-edge/quickref.html) | | [renesas-ra](ports/renesas-ra) | Renesas RA family | [here](https://docs.micropython.org/en/latest/renesas-ra/quickref.html) | | [webassembly](ports/webassembly) | Emscripten port targeting browsers and NodeJS | | | [zephyr](ports/zephyr) | Zephyr RTOS | [here](https://docs.micropython.org/en/latest/zephyr/quickref.html) | @@ -182,7 +183,6 @@ are built in CI but not regularly tested by the MicroPython maintainers: | [cc3200](ports/cc3200) | Texas Instruments CC3200 | [For WiPy](https://docs.micropython.org/en/latest/wipy/quickref.html) | | [esp8266](ports/esp8266) | Espressif ESP8266 SoC | [here](https://docs.micropython.org/en/latest/esp8266/quickref.html) | | [pic16bit](ports/pic16bit) | Microchip PIC 16-bit | | -| [powerpc](ports/powerpc) | IBM PowerPC (including Microwatt) | | Additional Ports ================ @@ -200,7 +200,7 @@ primarily for maintenance, development and testing: to another microcontroller. - The [qemu](ports/qemu) port is a QEMU-based emulated target for Cortex-A, - Cortex-M, RISC-V 32-bit and RISC-V 64-bit architectures. + Cortex-M, RISC-V 32-bit, RISC-V 64-bit, and PowerPC 64-bit architectures. The MicroPython cross-compiler, mpy-cross ----------------------------------------- diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index ec20e65f477..e1c6658f075 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -264,6 +264,32 @@ structures. If not done correctly it will compile but importing will fail to find the module. +Specifying C modules via a manifest +----------------------------------- + +As an alternative to passing ``USER_C_MODULES`` on the command line, C modules +can be listed inside a frozen manifest using ``c_module()``. This is convenient +when a board or project always pulls in the same set of C modules: the manifest +becomes the single place that declares both frozen Python code and the C +modules required to support it. + +.. code-block:: python3 + + # In ports/myboard/boards/MYBOARD/manifest.py + include("$(PORT_DIR)/boards/manifest.py") + c_module("$(MPY_DIR)/examples/usercmodule/cexample") + c_module("$(BOARD_DIR)/../../drivers/sensor") + +The manifest will need to be loaded via ``FROZEN_MANIFEST`` (either set in +``mpconfigboard.{mk,cmake}`` or passed on the make command line), and modules +listed with ``c_module()`` combine additively with any paths supplied via +``USER_C_MODULES`` on the command line. Duplicate paths are de-duplicated, so +mixing the two is safe. + +See :ref:`manifest` for the full ``c_module()`` API and supported +``$(VAR)`` path substitutions. + + Module usage in MicroPython --------------------------- diff --git a/docs/develop/optimizations.rst b/docs/develop/optimizations.rst index 533dd64116f..3f07aebbc66 100644 --- a/docs/develop/optimizations.rst +++ b/docs/develop/optimizations.rst @@ -59,6 +59,9 @@ Compiles to: X = 1 foo(1, 2) +See :func:`micropython.const` for complete details on usage requirements and +limitations. + Allocation of memory -------------------- diff --git a/docs/develop/support_tiers.rst b/docs/develop/support_tiers.rst index f49ee4124f8..6c62c495d16 100644 --- a/docs/develop/support_tiers.rst +++ b/docs/develop/support_tiers.rst @@ -50,6 +50,7 @@ Tier 2 ports: - alif - embed - nrf + - psoc-edge - renesas-ra - webassembly - zephyr @@ -59,7 +60,6 @@ Tier 3 ports: - cc3200 - esp8266 - pic16bit - - powerpc Tier M ports: diff --git a/docs/develop/writingtests.rst b/docs/develop/writingtests.rst index fd3daf91c1e..7ac7e038ca8 100644 --- a/docs/develop/writingtests.rst +++ b/docs/develop/writingtests.rst @@ -46,6 +46,11 @@ If you run your tests, this test should appear in the test output: Tests are run by comparing the output from the test target against the output from CPython. So any test should use print statements to indicate test results. +When writing tests for name or string-related functionality, please add both English/ASCII +as well as non-English/non-ASCII text and include Unicode examples. +Please do add comments in English explaining the meaning and intent of the Unicode text. +This help ensure Unicode support is tested and verified across different platforms. + For tests that can't be compared to CPython (i.e. micropython-specific functionality), you can provide a ``.py.exp`` file which will be used as the truth for comparison. diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index b4961fd4ed4..6b3fa951653 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -192,9 +192,19 @@ These are working configurations for LAN interfaces of some popular ESP32 boards # Espressif ESP32-Ethernet-Kit_A_V1.2 - lan = network.LAN(id=0, mdc=Pin(23), mdio=Pin(18), power=Pin(5), + lan = network.LAN(id=0, mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5), phy_type=network.PHY_IP101, phy_addr=1) + # ESP32-WROOM-32UE with KSZ8863RLL (Integrated 3-Port 10/100 Managed Switch with PHYs) + + lan = network.LAN(mdc=machine.Pin(23), # connected to SCL_MDC pin of KSZ8863RLL + mdio=machine.Pin(15), # connected to SDA_MDIO pin of KSZ8863RLL + power=machine.Pin(16), # connected to RSTN pin of KSZ8863RLL + phy_type=network.PHY_GENERIC, + phy_addr=3, + ref_clk_mode=machine.Pin.IN, + ref_clk=machine.Pin(0)) # REF_CLK 50MHz from KSZ8863RLL + .. _esp32_spi_ethernet: @@ -284,8 +294,7 @@ with a timer ID of 0, 0 and 1, or from 0 to 3 (inclusive):: tim1 = Timer(1) tim1.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(1)) -The period is in milliseconds. When using UART.IRQ_RXIDLE, timer 0 is needed for -the IRQ_RXIDLE mechanism and must not be used otherwise. +The period is in milliseconds. Timer callbacks are scheduled as soft interrupts on this port; hard callbacks are not implemented. Specifying ``hard=True`` will raise diff --git a/docs/esp8266/tutorial/intro.rst b/docs/esp8266/tutorial/intro.rst index 0d4bc42e2da..789fc287c27 100644 --- a/docs/esp8266/tutorial/intro.rst +++ b/docs/esp8266/tutorial/intro.rst @@ -20,12 +20,25 @@ characteristic of a board is how much flash it has, how the GPIO pins are connected to the outside world, and whether it includes a built-in USB-serial converter to make the UART available to your PC. -The minimum requirement for flash size is 1Mbyte. There is also a special -build for boards with 512KB, but it is highly limited comparing to the -normal build: there is no support for filesystem, and thus features which -depend on it won't work (WebREPL, mip, etc.). As such, 512KB build will -be more interesting for users who build from source and fine-tune parameters -for their particular application. +MicroPython is distributed as several firmware variants to suit the amount of +flash on your board: + +* The standard build (``ESP8266_GENERIC``) targets boards with **2MiB or more** + of flash. This is the recommended build and the best choice for most users. +* The ``FLASH_1M`` variant is for boards with **1MiB** of flash. It removes + asyncio and FAT-filesystem support, as well as some modules from + micropython-lib. +* The ``FLASH_2M_ROMFS`` variant targets **2MiB** boards and reserves part of + the flash for a read-only ROMFS filesystem. +* The ``FLASH_512K`` variant is for boards with only **512kiB** of flash. It is + highly limited compared to the other builds: there is no filesystem support, + and so features that depend on it won't work (WebREPL, mip, etc.). It also + drops framebuffer support, some Python language features, and has less + detailed error messages. This variant is mainly of interest to users who + build from source and fine-tune parameters for their particular application. + +The minimum recommended flash size is therefore 1MiB, with 2MiB or more giving +the best experience. Names of pins will be given in this tutorial using the chip names (eg GPIO0) and it should be straightforward to find which pin this corresponds to on your @@ -43,23 +56,31 @@ Getting the firmware The first thing you need to do is download the most recent MicroPython firmware .bin file to load onto your ESP8266 device. You can download it from the -`MicroPython downloads page `_. -From here, you have 3 main choices +`ESP8266 download page `_. -* Stable firmware builds for 1024kb modules and above. -* Daily firmware builds for 1024kb modules and above. -* Daily firmware builds for 512kb modules. +The download page offers the firmware variants described above. Pick the one +that matches your board's flash size: -If you are just starting with MicroPython, the best bet is to go for the Stable -firmware builds. If you are an advanced, experienced MicroPython ESP8266 user -who would like to follow development closely and help with testing new -features, there are daily builds (note: you actually may need some -development experience, e.g. being ready to follow git history to know -what new changes and features were introduced). +========================================================= ========================================= +Firmware file Board flash size +========================================================= ========================================= +``ESP8266_GENERIC--.bin`` 2MiB-4MiB, 8MiB-16MiB** (the standard build) +``ESP8266_GENERIC-FLASH_1M--.bin`` 1MiB +``ESP8266_GENERIC-FLASH_2M_ROMFS--.bin`` 2MiB-4MiB, 8MiB-16MiB** (includes a ROMFS) +``ESP8266_GENERIC-FLASH_512K--.bin`` 512kiB +========================================================= ========================================= -Support for 512kb modules is provided on a feature preview basis. For end -users, it's recommended to use modules with flash of 1024kb or more. As -such, only daily builds for 512kb modules are provided. +** Boards with 8MiB or 16MiB of flash can use the standard build, +but require an manual step to set up the RF calibration data, see :ref:`esp8266_large_flash` below. + +For each variant the page lists *release* builds and *preview* builds. If you +are just starting with MicroPython, choose the latest release build. If you are +an experienced user who would like to follow development closely and help with +testing new features, the preview builds are automatic builds of the +development branch. + +Throughout the rest of this tutorial the example commands use the standard +``ESP8266_GENERIC`` firmware; substitute the exact filename you downloaded. Deploying the firmware ---------------------- @@ -88,10 +109,6 @@ using pip:: pip install esptool -Versions starting with 1.3 support both Python 2.7 and Python 3.4 (or newer). -An older version (at least 1.2.1 is needed) works fine but will require Python -2.7. - Any other flashing program should work, so feel free to try them out or refer to the documentation for your board to see its recommendations. @@ -101,20 +118,33 @@ Using esptool.py you can erase the flash with the command:: And then deploy the new firmware using:: - esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin + esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 ESP8266_GENERIC-20260406-v1.28.0.bin You might need to change the "port" setting to something else relevant for your PC. You may also need to reduce the baudrate if you get errors when flashing (eg down to 115200). The filename of the firmware should also match the file that you have. +The ``--flash_size=detect`` option tells esptool.py to read the flash size from +the chip's JEDEC ID. MicroPython itself also autodetects the flash size at +runtime for chips up to **4MB**, so a single firmware build adapts to the actual +flash on your board without any extra configuration. The filesystem is +automatically sized to use all of the available flash. + +The ESP8266 needs a small block of RF calibration data, known as +``esp_init_data``, near the end of the flash before WiFi will start. On first +boot MicroPython checks this region and, if it is blank (for example because you +just ran ``erase_flash``), it automatically writes the default calibration data +for you. For boards with **4MB of flash or less**, no manual step is needed. See +:ref:`esp8266_large_flash` below for boards larger than 4MB. + For some boards with a particular FlashROM configuration (e.g. some variants of a NodeMCU board) you may need to manually set a compatible `SPI Flash Mode `_. You'd usually pick the fastest option that is compatible with your device, but the ``-fm dout`` option (the slowest option) should have the best compatibility:: - esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dout 0 esp8266-20170108-v1.8.7.bin + esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dout 0 ESP8266_GENERIC-20260406-v1.28.0.bin If the above commands run without error then MicroPython should be installed on your board! @@ -123,6 +153,64 @@ If you pulled GPIO0 manually to ground to enter programming mode, release it now and reset the device by again pulling the reset pin to ground for a short duration. +.. _esp8266_large_flash: + +Boards with more than 4MB of flash +---------------------------------- + +Boards with **8MB or 16MB** of flash need one extra step. The flash routines +built into the ESP8266 boot ROM (which MicroPython uses to write the calibration +data on first boot) cannot address flash beyond 4MB: the ROM reads the chip's +device ID but clamps the reported size to 4MB, so any access above that offset +fails. As a result MicroPython can only write the ``esp_init_data`` RF +calibration block automatically within the first 4MB of flash. +So after a full flash erase MicroPython cannot place the calibration data at the correct end-of-flash +address by itself. Without it the WiFi subsystem will not start (typically +showing up as a continuous reset loop or ``rf_cal`` errors). For more background +on this ROM limitation see +`ESP8266 16MB Flash Handling `_. + +To fix this, flash the ``esp_init_data_default.bin`` file (shipped with the +Espressif NONOS SDK) to the calibration address, which is the flash size minus +``0x4000``, see table below. + +You can download ``esp_init_data_default.bin`` from the Espressif repository +(open the link and click "View raw" to download the file): +``__ + +The calibration addresses are: + +=========== ===================================== +Flash size ``esp_init_data`` address +=========== ===================================== +8MB ``0x7FC000`` +16MB ``0xFFC000`` +=========== ===================================== + +The full procedure for a 16MB board is:: + + # 1. Make sure esptool is up to date + pip install --upgrade esptool + + # 2. Erase the flash + esptool.py --port /dev/ttyUSB0 --baud 460800 erase_flash + + # 3. Flash the RF calibration blob at the end of flash (16MB example) + esptool.py --port /dev/ttyUSB0 write_flash 0xFFC000 esp_init_data_default.bin + + # 4. Flash MicroPython, telling esptool the real flash size + esptool.py --port /dev/ttyUSB0 --baud 460800 \ + write_flash -fm dio --flash_size 16MB 0 ESP8266_GENERIC-20260406-v1.28.0.bin + + # 5. Check detected flash size in the REPL + mpremote exec "import esp;print(f'Detected flash: {esp.flash_size():_}')" + +For an 8MB board, use ``0x7FC000`` in step 3 and ``--flash_size 8MB`` in step 4. + +The filesystem is sized automatically from the detected flash size, so it +will use all of the available space once the board boots. + + Serial prompt ------------- @@ -173,15 +261,8 @@ after it, here are troubleshooting recommendations: rate may be too high and lead to errors. Try a more common 115200 baud rate instead in such cases. -* If lower baud rate didn't help, you may want to try older version of - esptool.py, which had a different programming algorithm:: - - pip install esptool==1.0.1 - - This version doesn't support ``--flash_size=detect`` option, so you will - need to specify FlashROM size explicitly (in megabits). It also requires - Python 2.7, so you may need to use ``pip2`` instead of ``pip`` in the - command above. +* If lower baud rate didn't help, you may want to try a different version of + esptool.py, which may use a different programming algorithm. * The ``--flash_size`` option in the commands above is mandatory. Omitting it will lead to a corrupted firmware. diff --git a/docs/index.rst b/docs/index.rst index 64b83618da1..a6b68e8e898 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,6 +13,7 @@ MicroPython documentation and references esp32/quickref.rst rp2/quickref.rst mimxrt/quickref.rst + psoc-edge/quickref.rst wipy/quickref.rst unix/quickref.rst zephyr/quickref.rst diff --git a/docs/library/builtins.rst b/docs/library/builtins.rst index b5d08ba7fed..92c0b8dcf7f 100644 --- a/docs/library/builtins.rst +++ b/docs/library/builtins.rst @@ -25,6 +25,35 @@ Functions and types |see_cpython| `python:bytes`. + .. method:: bytes.decode(encoding='utf-8', errors='strict') + + Decode the bytes object to a string using the specified *encoding*. + + MicroPython supports the following encodings: + + - ``'utf-8'`` or ``'utf8'`` - UTF-8 encoding (default) + - ``'ascii'`` - ASCII encoding (subset of UTF-8) + + The *errors* parameter controls how decoding errors are handled: + + - ``'strict'`` - Raise a ``UnicodeError`` on invalid UTF-8 (default) + - ``'ignore'`` - Skip invalid bytes (requires ``MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS``) + - ``'replace'`` - Replace invalid bytes with U+FFFD '�' (requires ``MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS``) + + .. note:: + Error handler support depends on build configuration. On constrained + systems, only ``'strict'`` mode may be available. + + Example:: + + >>> b'\xc2\xa9 2024'.decode('utf-8') # © symbol + '© 2024' + >>> b'hello\xffworld'.decode('utf-8', 'ignore') # Skip invalid bytes + 'helloworld' + + Raises ``LookupError`` if the encoding is not supported, or + ``UnicodeError`` if the data contains invalid UTF-8 and ``errors='strict'``. + .. function:: callable() .. function:: chr() @@ -79,15 +108,11 @@ Functions and types In MicroPython, `byteorder` parameter must be positional (this is compatible with CPython). - .. method:: to_bytes(size, byteorder) + .. method:: to_bytes(size, byteorder, /, *, signed=False) In MicroPython, `byteorder` parameter must be positional (this is compatible with CPython). - .. note:: The optional ``signed`` kwarg from CPython is not supported. - MicroPython currently converts negative integers as signed, - and positive as unsigned. (:ref:`Details `.) - .. function:: isinstance() .. function:: issubclass() @@ -148,6 +173,35 @@ Functions and types .. class:: str() + .. method:: str.encode(encoding='utf-8') + + Encode the string to bytes using the specified *encoding*. + + MicroPython supports the following encodings: + + - ``'utf-8'`` or ``'utf8'`` - UTF-8 encoding (default) + - ``'ascii'`` - ASCII encoding (subset of UTF-8) + + Example:: + + >>> '© 2024'.encode('utf-8') # Copyright symbol + b'\xc2\xa9 2024' + + Raises ``LookupError`` if the encoding is not supported. + + .. method:: str.center(width) + + Return a centered string of length *width*. Padding is done using spaces. + + When Unicode support is enabled (``MICROPY_PY_BUILTINS_STR_UNICODE``), this + method counts Unicode characters rather than bytes, ensuring proper alignment + for multi-byte UTF-8 characters. + + Example:: + + >>> 'café'.center(10) # é is 2 bytes in UTF-8 + ' café ' + .. function:: sum() .. function:: super() diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index f48f82d79c2..77121b7189c 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -639,4 +639,4 @@ For more details see Espressif's `ESP-IDF LDO documentation. .. method:: LDO.release() - Release the LDO channel. + Release the LDO channel, disabling its voltage output. Create a new LDO object to re-enable the output. diff --git a/docs/library/espnow.rst b/docs/library/espnow.rst index 14a92c11400..b71e772e864 100644 --- a/docs/library/espnow.rst +++ b/docs/library/espnow.rst @@ -32,23 +32,42 @@ ESP-NOW is a connection-less wireless communication protocol supporting: - Direct communication between up to 20 registered peers: - - Without the need for a wireless access point (AP), +- Without the need for a wireless access point (AP), - Encrypted and unencrypted communication (up to 6 encrypted peers), -- Message sizes up to 250 bytes, +- Message sizes up to 1470 bytes (For ESP-NOW v2), -- Can operate alongside Wifi operation (:doc:`network.WLAN`) on +- Can operate alongside Wi-Fi operation (:doc:`network.WLAN`) on ESP32 and ESP8266 devices. +- Track the Wi-Fi signal strength (RSSI) of ESP-NOW peer devices. + It is especially useful for small IoT networks, latency sensitive or power sensitive applications (such as battery operated devices) and for long-range communication between devices (hundreds of metres). -This module also supports tracking the Wifi signal strength (RSSI) of peer -devices. +ESP-NOW Versions +~~~~~~~~~~~~~~~~ + +Since ESP-IDF V5.4, two ESP-NOW versions are supported when running on ESP32: +V1 and V2. + +- The maximum packet length supported by V2 devices is 1470 bytes +- The maximum packet length supported by V1 devices is 250 bytes. + +To check at runtime whether ESP-NOW V2 is available, check the value of +`espnow.MAX_DATA_LEN`. -A simple example would be: +ESP-NOW V2 devices are capable of receiving packets from both V2 and V1 devices. + +ESP-NOW V1 devices (including ESP8266) can receive packets from other V1 +devices, or from V2 devices if the packet length doesn't exceed 250 bytes. For +packets exceeding this length, a V1 device will either truncate the data to the +first 250 bytes or discard the packet entirely. + +Example +~~~~~~~ **Sender:** :: @@ -148,23 +167,26 @@ Configuration .. data:: Options: - *rxbuf*: (default=526) Get/set the size in bytes of the internal - buffer used to store incoming ESPNow packet data. The default size is - selected to fit two max-sized ESPNow packets (250 bytes) with associated - mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + *rxbuf*: (default=528 or 2972) Get/set the size in bytes of the internal + buffer used to store incoming ESP-NOW packet data. The default size is + selected to fit two max-sized ESP-NOW packets (250 or 1470 bytes) with associated + mac_address (6 bytes), a message byte count (2 byte) and RSSI data plus buffer overhead. Increase this if you expect to receive a lot of large packets or expect bursty incoming traffic. - **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing - this value will have no effect until the next call of - `ESPNow.active(True)`. + .. note:: If only using ESP-NOW V1 packets and low throughput, recommend + setting ``rxbuf=528`` here to reduce memory overhead. - *timeout_ms*: (default=300,000) Default timeout (in milliseconds) - for receiving ESPNow messages. If *timeout_ms* is less than zero, then + .. note:: The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300_000) Default timeout (in milliseconds) + for receiving ESP-NOW messages. If *timeout_ms* is less than zero, then wait forever. The timeout can also be provided as arg to `recv()`/`irecv()`/`recvinto()`. - *rate*: (ESP32 only) Set the transmission data rate for ESPNow packets. + *rate*: (ESP32 only) Set the transmission data rate for ESP-NOW packets. The default setting is `espnow.RATE_1M`. It's recommended to use one of the other ``espnow.RATE_nnn`` constants to set this, but it's also possible to pass an integer corresponding to the `enum wifi_phy_rate_t @@ -214,12 +236,12 @@ after reboot/reset). This reduces the reliability of receiving ESP-NOW messages .. data:: Arguments: - - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + - *mac*: byte string exactly `espnow.ADDR_LEN` (6 bytes) long or ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent to all registered peers, except any broadcast or multicast MAC addresses. - - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + - *msg*: string or byte-string up to `espnow.MAX_DATA_LEN` (250 or 1470) bytes long. - *sync*: @@ -243,7 +265,7 @@ after reboot/reset). This reduces the reliability of receiving ESP-NOW messages `active()`. - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are full. - - ``ValueError()`` on invalid values for the parameters. + - ``ValueError()`` or ``TypeError()`` on invalid values or types for the parameters. **Note**: A peer will respond with success if its wifi interface is `active()` and set to the same channel as the sender, @@ -327,10 +349,10 @@ after reboot/reset). This reduces the reliability of receiving ESP-NOW messages .. data:: Arguments: *data*: A list of at least two elements, ``[peer, msg]``. ``msg`` must - be a bytearray large enough to hold the message (250 bytes). On the - ESP8266, ``peer`` should be a bytearray of 6 bytes. The MAC address of - the sender and the message will be stored in these bytearrays (see Note - on ESP32 below). + be a bytearray large enough to hold the received message (recommended at + least `espnow.MAX_DATA_LEN`). On the ESP8266, ``peer`` should be a + bytearray of 6 bytes. The MAC address of the sender and the message will + be stored in these bytearrays (see Note on ESP32 below). *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). @@ -343,6 +365,10 @@ after reboot/reset). This reduces the reliability of receiving ESP-NOW messages - See `ESPNow.recv()`. + - This function will also raise a ``ValueError`` if the received message + is too large for the provided buffer. If this error is raised, received + message(s) will be lost. + **Note:** On the ESP32: - It is unnecessary to provide a bytearray in the first element of the @@ -479,7 +505,7 @@ must first register the sender and use the same encryption keys as the sender - ``OSError(num, "ESP_ERR_ESPNOW_CHAN")`` if a channel value was set that doesn't match the channel currently configured for this interface. - - ``ValueError()`` on invalid keyword args or values. + - ``ValueError()`` or ``TypeError()`` on invalid keyword args or values. .. method:: ESPNow.del_peer(mac) @@ -494,7 +520,7 @@ must first register the sender and use the same encryption keys as the sender - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if *mac* is not registered. - - ``ValueError()`` on invalid *mac* values. + - ``ValueError()`` or ``TypeError()`` on invalid *mac* values. .. method:: ESPNow.get_peer(mac) (ESP32 only) @@ -510,7 +536,7 @@ must first register the sender and use the same encryption keys as the sender - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if *mac* is not registered. - - ``ValueError()`` on invalid *mac* values. + - ``ValueError()`` or ``TypeError()`` on invalid *mac* values. .. method:: ESPNow.peer_count() (ESP32 only) @@ -570,7 +596,7 @@ Callback Methods Constants --------- -.. data:: espnow.MAX_DATA_LEN(=250) +.. data:: espnow.MAX_DATA_LEN(=250 or 1470 for ESPNow V1 or V2) espnow.KEY_LEN(=16) espnow.ADDR_LEN(=6) espnow.MAX_TOTAL_PEER_NUM(=20) diff --git a/docs/library/machine.CAN.rst b/docs/library/machine.CAN.rst index 0da26b90167..c790e28da60 100644 --- a/docs/library/machine.CAN.rst +++ b/docs/library/machine.CAN.rst @@ -24,6 +24,8 @@ errors. .. note:: The planned ``can`` and ``aiocan`` micropython-lib modules will be the recommended way to use CAN with MicroPython. +Availability: **STM32, MIMXRT, Alif** + Constructor ----------- @@ -192,6 +194,10 @@ Methods .. note:: This intentionally low-level implementation is designed so the caller can establish a software queue of outgoing messages. + .. note:: The **Alif** port always returns 0, since the transmit buffer index is not reported by + the CAN controller. + + .. important:: The CAN "transmit queue" is not a FIFO queue, it is priority ordered, and although it can hold up to `CAN.TX_QUEUE_LEN` items there may be other hardware restrictions on messages @@ -335,6 +341,10 @@ Methods transmission is cancelled and then the same buffer is used to send another message (especially if the CAN controller IRQ is not "hard"). + .. note:: The **Alif** port cannot address a specific message to be cancelled. + Instead all messages in the TX queue will be cancelled. + + .. method:: CAN.state() Returns an integer value indicating the current state of the controller. @@ -367,6 +377,9 @@ Methods .. note:: If a controller doesn't support a particular counter, it will return ``None`` for that list element. + .. note:: The **Alif** port cannot report the exact number of pending RX or TX messages. It + will report a number > 0, if messages are pending. + .. method:: CAN.get_timings(list=None /) Returns a list of elements indicating the current timings configured in the diff --git a/docs/library/machine.I2C.rst b/docs/library/machine.I2C.rst index 635d5873444..a10c6cf6d74 100644 --- a/docs/library/machine.I2C.rst +++ b/docs/library/machine.I2C.rst @@ -101,8 +101,6 @@ General Methods Turn off the I2C bus. - Availability: WiPy. - .. method:: I2C.scan() Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of diff --git a/docs/library/machine.I2CTarget.rst b/docs/library/machine.I2CTarget.rst index 2765b98143a..1d54cf795e9 100644 --- a/docs/library/machine.I2CTarget.rst +++ b/docs/library/machine.I2CTarget.rst @@ -74,6 +74,8 @@ example, to see the raw events as they are triggered:: ) i2c.irq(irq_handler, trigger=all_triggers, hard=True) +Availability: **Alif, ESP32, MIMXRT, RP2, SAMD, STM32, Zephyr** + Constructors ------------ diff --git a/docs/library/machine.I2S.rst b/docs/library/machine.I2S.rst index 84edb94e78d..f2704e9a33d 100644 --- a/docs/library/machine.I2S.rst +++ b/docs/library/machine.I2S.rst @@ -79,6 +79,8 @@ other things. For these drivers see: - :ref:`wm8960` +Availability: **ESP32, MIMXRT, RP2, STM32** + Constructor ----------- diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index 37dcac877fa..e9a5ec1575a 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -209,40 +209,40 @@ The following methods are not part of the core Pin API and only implemented on c Set pin to "0" output level. - Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + Availability: mimxrt, nrf, psoc-edge, renesas-ra, rp2, samd, stm32 ports. .. method:: Pin.high() Set pin to "1" output level. - Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + Availability: mimxrt, nrf, psoc-edge, renesas-ra, rp2, samd, stm32 ports. .. method:: Pin.mode([mode]) Get or set the pin mode. See the constructor documentation for details of the ``mode`` argument. - Availability: cc3200, stm32 ports. + Availability: cc3200, psoc-edge, stm32 ports. .. method:: Pin.pull([pull]) Get or set the pin pull state. See the constructor documentation for details of the ``pull`` argument. - Availability: cc3200, stm32 ports. + Availability: cc3200, psoc-edge, stm32 ports. .. method:: Pin.drive([drive]) Get or set the pin drive strength. See the constructor documentation for details of the ``drive`` argument. - Availability: cc3200 port. + Availability: cc3200, psoc-edge ports. .. method:: Pin.toggle() Toggle output pin from "0" to "1" or vice-versa. - Availability: cc3200, esp32, esp8266, mimxrt, rp2, samd ports. + Availability: cc3200, esp32, esp8266, mimxrt, psoc-edge, rp2, samd ports. Attributes ---------- diff --git a/docs/library/machine.RTC.rst b/docs/library/machine.RTC.rst index e2ddd728bde..80570601bbd 100644 --- a/docs/library/machine.RTC.rst +++ b/docs/library/machine.RTC.rst @@ -13,6 +13,7 @@ Example usage:: rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0)) print(rtc.datetime()) +Availability: **Alif, ESP32, ESP8266, MIMXRT, Renesas-RA, RP2, SAMD, STM32** Constructors ------------ @@ -102,6 +103,18 @@ Methods Availability: esp32, esp8266 ports. + .. note:: + + For cross-port persistent storage, see :func:`machine.mem_backup` + which is available on more ports and provides direct memoryview access. + + .. warning:: + + On esp32, ``RTC.memory()`` and :func:`machine.mem_backup` share the same + backing buffer but track length independently. Writes through one API + are not reflected in the length seen by the other. Avoid mixing the two + in the same application. + Constants --------- diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst index c4a0d5d172b..1677a6e3108 100644 --- a/docs/library/machine.SDCard.rst +++ b/docs/library/machine.SDCard.rst @@ -24,7 +24,7 @@ or a non-standard pin assignment. The exact subset of arguments supported will vary from platform to platform. .. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, - cs=None, cmd=None, data=None, freq=20000000) + cs=None, cmd=None, data=None, ldo=None, freq=20000000) This class provides access to SD or MMC storage cards using either a dedicated SD/MMC interface hardware or through an SPI channel. @@ -60,6 +60,9 @@ vary from platform to platform. - *data* can be used to specify a list or tuple of SD data bus pins (ESP32-S3 only). + - *ldo* can be used to specify the internal LDO channel used for SD + card logic level for SDIO 3.0 (ESP32-P4 only). + - *freq* selects the SD/MMC interface frequency in Hz. Implementation-specific details @@ -188,6 +191,16 @@ parameters ``sck``, ``cs``, ``miso``, ``mosi`` as needed to assign pins. In either mode the ``cd`` and ``wp`` pins default to disabled, unless set in the constructor. +ESP32-P4 +~~~~~~~~ + +The ESP32-P4 has multiple internal adjustable LDO regulators, and some boards use +one of LDOs to control the SD card logic level required by SDIO 3.0. Most boards +will automatically select the correct LDO channel, but it may be necessary to +manually specify the ``ldo`` parameter as an integer (1 through 4). For example:: + + sd = SDCard(ldo=4) + Other ESP32 chips ~~~~~~~~~~~~~~~~~ diff --git a/docs/library/machine.Signal.rst b/docs/library/machine.Signal.rst index 1e1fcb5483a..57b07e304bc 100644 --- a/docs/library/machine.Signal.rst +++ b/docs/library/machine.Signal.rst @@ -93,6 +93,34 @@ Constructors - ``invert`` - if True, the signal will be inverted (active low). + .. note:: + The value of the pin can be set in the Pin constructor *and/or* the Signal constructor. + If the Signal is also *inverted* then a value set in the *Pin* constructor will be in the opposite sense. + + Example:: + + >>> c0 = Signal(Pin(0, Pin.OUT, value=0), invert=True) + >>> c0() + 1 + >>> c1 = Signal(1, Pin.OUT, value=0, invert=True) + >>> c1() + 0 + + The first creates the pin and sets it's initial value and then Signal inverts the logic. + Whereas, the second sets the pin to the inverted value. + + This behavior is only different after construction and before a call + to a 'set' method. + + Example:: + + >>> c0.off() + >>> c0() + 0 + >>> c1.off() + >>> c1() + 0 + Methods ------- @@ -114,6 +142,12 @@ Methods to logical 0. For inverted/active-low signal, active status corresponds to logical 0, while inactive - to logical 1. +.. method:: Signal.__call__([x]) + + Signal objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Signal.value([x]). + See :meth:`Signal.value` for more details. + .. method:: Signal.on() Activate signal. diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst index 69eea9d8d1f..2767bff6043 100644 --- a/docs/library/machine.Timer.rst +++ b/docs/library/machine.Timer.rst @@ -20,8 +20,7 @@ There are two types of Timer in MicroPython, but not all ports support both: - Virtual timers. These are managed in software, and are generally more flexible. Multiple virtual timers can be constructed and active at once. The - ``id`` of a virtual timer is ``-1``. Not all ports support virtual timers, but - it's recommended to use them when available. + ``id`` of a virtual timer is ``-1``. - Hardware timers. Hardware timers have integer ``id`` values starting at ``0``. The number of available ``id`` values is determined by the hardware. Hardware timers may be more accurate for very fine sub-millisecond timing (especially diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index fbad3fc5922..6a6f60a918f 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -163,7 +163,7 @@ Methods For the esp8266 and nrf ports the call returns while the last byte is sent. If required, a one character wait time has to be added in the calling script. - Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, psoc-edge, renesas-ra .. method:: UART.txdone() @@ -176,7 +176,7 @@ Methods of a transfer is still being sent. If required, a one character wait time has to be added in the calling script. - Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, psoc-edge, renesas-ra .. method:: UART.irq(handler=None, trigger=0, hard=False) @@ -216,6 +216,7 @@ Methods ESP32 yes yes yes MIMXRT yes yes NRF yes yes + PSOC-EDGE yes yes yes RENESAS-RA yes yes RP2 yes yes yes SAMD yes yes yes @@ -224,8 +225,7 @@ Methods .. note:: - - The ESP32 port does not support the option hard=True. It uses Timer(0) - for UART.IRQ_RXIDLE, so this timer cannot be used for other means. + - The ESP32 port does not support the option hard=True. - The rp2 port's UART.IRQ_TXIDLE is only triggered when the message is longer than 5 characters and the trigger happens when still 5 characters @@ -241,7 +241,7 @@ Methods idle. - Availability: cc3200, esp32, mimxrt, nrf, renesas-ra, rp2, samd, stm32. + Availability: cc3200, esp32, mimxrt, nrf, psoc-edge, renesas-ra, rp2, samd, stm32. Constants --------- @@ -260,4 +260,4 @@ Constants IRQ trigger sources. - Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200, psoc-edge. diff --git a/docs/library/machine.USBDevice.rst b/docs/library/machine.USBDevice.rst index 45f9e9cef38..15bf49a4d31 100644 --- a/docs/library/machine.USBDevice.rst +++ b/docs/library/machine.USBDevice.rst @@ -4,9 +4,9 @@ class USBDevice -- USB Device driver ==================================== -.. note:: ``machine.USBDevice`` is currently only supported for esp32, rp2 and - samd ports. Native USB support is also required, and not every board - supports native USB. +Availability: **ESP32, RP2, SAMD** + +.. note:: Native USB support is required, and not every board supports native USB. USBDevice provides a low-level Python API for implementing USB device functions using Python code. diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst index cf77df96320..deb00626db5 100644 --- a/docs/library/machine.WDT.rst +++ b/docs/library/machine.WDT.rst @@ -15,7 +15,7 @@ Example usage:: wdt = WDT(timeout=2000) # enable it with a timeout of 2s wdt.feed() -Availability of this class: pyboard, WiPy, esp8266, esp32, rp2040, mimxrt. +Availability: **Alif, ESP32, ESP8266, MIMXRT, RP2, SAMD, STM32, Zephyr** Constructors ------------ @@ -25,8 +25,22 @@ Constructors Create a WDT object and start it. The timeout must be given in milliseconds. Once it is running the timeout cannot be changed and the WDT cannot be stopped either. - Notes: On the esp8266 a timeout cannot be specified, it is determined by the underlying system. - On rp2040 devices, the maximum timeout is 8388 ms. + Notes: + + - On the alif port the HP and HE cores have independent watchdogs, both accessed + by the default ``id=0``. The maximum timeout on the HP core is 10737ms. The + watchdog does not run during deepsleep. + + - On the esp8266 port a timeout cannot be specified, it is determined by the underlying + system. + + - On rp2040 devices the maximum timeout is 8388 ms. + + - On the stm32 port the default ``id=0`` is the IWDG, which can also be specified by + an id of ``"IWDG"``. Use an id of ``"WWDG"`` to access the WWDG peripheral. + For dual-core STM32H7 MCUs there are also ``"IWDG2"`` and ``"WWDG2"``. + The WWDG has a very limited maximum timeout across all MCUs, of around 100ms (but + it depends heavily on the APB clock). Methods ------- diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 481820defc1..6389b3f0883 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -49,6 +49,136 @@ Example use (registers are specific to an stm32 microcontroller): # read PA3 value = (machine.mem32[GPIOA + GPIO_IDR] >> 3) & 1 + +Note: the returned values are signed integers. +Example: reading the cpuid register on esp8266 + +.. code-block:: python3 + + value = mem32[0x40001000] + +will return a negative value, that could be counter-intuitive. + +To always read a positive integer + +.. code-block:: python3 + + value = mem32[0x40001000] & 0xffffffff + +.. function:: mem_backup(region=0) + + Return a writable `memoryview` over a persistent hardware memory region that + survives at least :ref:`soft_reset` on all ports; battery-backed ports also + survive power-off. Per-port persistence guarantees vary, see the table below. + + *region* selects which backup region to access (default 0, the primary region). + Pass ``-1`` to get a tuple of all available regions instead. + + The element type depends on the port's hardware alignment requirements: + ``'B'`` (unsigned byte) on ports with byte-addressable backup memory, + ``'I'`` (unsigned 32-bit) on ports backed by word-sized registers. + Use ``mem.itemsize`` to discover the access granularity at runtime. + + The total size in bytes is ``len(mem) * mem.itemsize``, where ``len(mem)`` + is the number of elements and ``mem.itemsize`` is the size of each element. + For example, on a port with 4 word-sized registers, ``len(mem)`` is 4 and + ``mem.itemsize`` is 4, giving 16 bytes total. On a port with 4096 bytes + of byte-addressable backup SRAM, ``len(mem)`` is 4096 and ``mem.itemsize`` + is 1. + + Cross-port guarantees for portable code: ``mem.itemsize`` is either ``1`` + or ``4``; valid indices are ``0..len(mem)-1``; out-of-range access raises + ``IndexError``; values are stored in host-native byte order. Region index + semantics are not portable, see notes below for ``stm32`` in particular. + + Usage:: + + import machine + + mem = machine.mem_backup() + mem[0] = 0x12345678 # write element 0 + print(hex(mem[0])) # read element 0 + print(len(mem)) # number of elements + print(mem.itemsize) # bytes per element + print(len(mem) * mem.itemsize) # total bytes available + + # Discover all available regions + for i, r in enumerate(machine.mem_backup(-1)): + print(i, len(r), r.itemsize) + + The total byte size and backing hardware vary by port: + + ====== =============================================== =========== ============== + Port Backing storage Total bytes Battery-backed + ====== =============================================== =========== ============== + alif Backup SRAM 4080 yes + esp32 RTC slow memory 2048 no + mimxrt SNVS LPGPR registers (4 per chip) 12-16 yes + nrf POWER GPREGRET registers 1-2 no + rp2 Watchdog scratch registers 28-60 no + samd Backup RAM (SAMD51 only) 8192 yes + stm32 Backup SRAM + BKP registers (F4/F7/H5/H7/U5/N6) 2048-8192 yes + stm32 RTC BKP registers (other families) 20-128 yes + ====== =============================================== =========== ============== + + .. note:: + + On esp32 and rp2, data persists across :ref:`soft_reset`, + `machine.reset()` and `machine.deepsleep()` wake but is lost on + power-off and on poweron-style resets. On esp32 in particular this + includes pressing the EN/RESET button on most dev boards, which the + chip reports as a power-on reset. + + Some ports split backup storage across multiple regions, or exclude + registers reserved by the bootloader or system firmware: + + ====== ==================== ================================================ + Port Register(s) Note + ====== ==================== ================================================ + mimxrt LPGPR[3] Excluded; used by TinyUF2 (when used) + rp2 scratch[4] Excluded; used by pico-sdk on reset + rp2 powman scratch[0..7] Region 2 on RP2350 only + stm32 BKP registers Region 1 on BKPSRAM families (F4/F7/H5/H7/U5/N6) + ====== ==================== ================================================ + + Use ``machine.mem_backup(-1)`` to discover available regions and their sizes. + + On stm32 the region index does not have a uniform meaning across boards: + region 0 is BKPSRAM (``itemsize=1``) on BKPSRAM families and BKP registers + (``itemsize=4``) on others. Portable code should branch on ``mem.itemsize`` + before structuring data. + + Some registers within a region are accessible but reserved by convention + and should not be overwritten. The BKP register file is region 1 on + BKPSRAM families and region 0 on the others: + + ====== ============== ========================================================= + Port Register(s) Used by + ====== ============== ========================================================= + stm32 BKP0R Arduino bootloader (Portenta H7, Giga, Opta, Nicla) + stm32 BKP16R-BKP18R ``rfcore_firmware.py`` on STM32WB + stm32 last BKP reg clock frequency (``MICROPY_HW_CLK_LAST_FREQ``) + stm32 BKP31R (N6) mboot bootloader entry + ====== ============== ========================================================= + + The buffer allows direct register access and can be combined with + ``uctypes`` for structured layouts:: + + import machine, uctypes + + mem = machine.mem_backup() + + # Structured access via uctypes (check len(mem) for your board) + layout = { + "flags": (0 * 4, uctypes.UINT32), # register 0 + "counter": (1 * 4, uctypes.UINT32), # register 1 + } + regs = uctypes.struct(uctypes.addressof(mem), layout) + regs.flags = 0x01 + print(regs.counter) + + Availability: alif, esp32, mimxrt, nrf, rp2, samd, stm32 ports. + Reset related functions ----------------------- @@ -163,6 +293,13 @@ Power related functions Availability: ESP32, WiPy. +.. function:: wake_pins() + + Returns the GPIO pin numbers of those pins which caused wakeup from deep sleep as a + tuple of integers. + + Availability: ESP32. + Miscellaneous functions ----------------------- diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index 65fa204315a..c5fdf41099d 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -17,15 +17,70 @@ Functions CONST_X = const(123) CONST_Y = const(2 * CONST_X + 1) - Constants declared this way are still accessible as global variables from - outside the module they are declared in. On the other hand, if a constant - begins with an underscore then it is hidden, it is not available as a global - variable, and does not take up any memory during execution. - - This `const` function is recognised directly by the MicroPython parser and is - provided as part of the :mod:`micropython` module mainly so that scripts can be - written which run under both CPython and MicroPython, by following the above - pattern. + When the parser encounters ``NAME = const(expr)``, it evaluates the expression + at compile time and substitutes the resulting value directly into the bytecode at + every use of ``NAME``, avoiding a global dictionary lookup each time. + + The ``const`` name is recognised directly by the parser so no import is actually + required in MicroPython. However ``from micropython import const`` is recommended + so the script also runs on CPython where ``const`` is provided as an identity + function. Note that the parser only recognises the bare name ``const`` -- using + ``micropython.const()`` (with module prefix) or an alias will not trigger the + optimisation. + + Constants declared this way are still stored as global variables in the module's + dictionary, so other modules can access them (e.g. + ``import mymodule; print(mymodule.X)``). Reassigning the global from another + module does not affect the inlined values within the defining module. This global + entry costs at least two machine words of RAM. + + **Module-private constants:** To avoid this RAM cost, prefix the name with an + underscore (e.g. ``_X = const(1)``). This prevents the variable from being added + to the module dictionary and hides it from other modules. + + The expression passed to ``const()`` must be evaluable at compile time. Supported + types are: + + - ``int`` (including expressions with arithmetic and bitwise operators) + - ``float`` + - ``str`` + - ``bytes`` + - ``bool`` (``True``, ``False``), ``None``, ``...`` (Ellipsis) + - ``tuple`` of constants + + The expression can reference previously defined constants. Using runtime values + or function calls raises ``SyntaxError: not a constant``. + + Examples:: + + BUFFER_SIZE = const(1024) + BUFFER_MASK = const(BUFFER_SIZE - 1) + FLAGS = const(0x01 | 0x02) + _SCALE = const(0.001) + _PREFIX = const("data_") + _HEADER = const(b"\x00\xff") + _MODES = const(("read", "write")) + + Because the compiler evaluates boolean constants at compile time, ``const()`` + can be used for conditional compilation. Code guarded by a false constant is + eliminated from the bytecode entirely, and when frozen via ``mpy-cross`` the + unreachable code is stripped from the output:: + + FEATURE_X = const(True) + + if FEATURE_X: + def feature_x_handler(): + ... + + For cross-platform compatibility with CPython, the typical pattern is:: + + try: + from micropython import const + except ImportError: + const = lambda x: x + + See also :ref:`constrained` and :ref:`speed_python` for practical guidance on + using constants to reduce memory usage and improve performance. .. function:: opt_level([level]) @@ -186,6 +241,10 @@ Functions There is a finite queue to hold the scheduled functions and `schedule()` will raise a `RuntimeError` if the queue is full. + As a special case, it's possible to pass `micropython.kbd_intr` to this function + as the first argument (and ``None`` as the second argument), and that will + schedule a `KeyboardInterrupt` to be raised "very soon" in the main thread. + Classes ------- diff --git a/docs/library/network.USBD_NCM.rst b/docs/library/network.USBD_NCM.rst new file mode 100644 index 00000000000..e807f930b8c --- /dev/null +++ b/docs/library/network.USBD_NCM.rst @@ -0,0 +1,82 @@ +.. currentmodule:: network +.. _network.USBD_NCM: + +class USBD_NCM -- USB NCM network interface +=========================================== + +This class provides a network interface over USB using the NCM (Network +Control Model) protocol. The host computer sees this device as a USB +Ethernet adapter and assigns it an IP address via DHCP (served by the +MicroPython device). + +.. note:: ``network.USBD_NCM`` requires a port with TinyUSB and NCM support, + enabled at build time by defining ``MICROPY_PY_NETWORK_USBD_NCM`` + (off by default). + +Example usage:: + + import network + + nic = network.USBD_NCM() + nic.active(True) + # wait for USB host to configure the NCM interface + while not nic.isconnected(): + pass + + print(nic.ipconfig("addr4")) + +Constructors +------------ + +.. class:: USBD_NCM() + + Create and return a USBD_NCM object. This initialises the NCM network + interface if it has not already been initialised. Only one instance + exists (singleton). + +Methods +------- + +.. method:: USBD_NCM.active([is_active]) + + Activate or deactivate the network interface. Without argument returns + current state as a bool. + + The interface is brought up automatically before USB enumeration, so this + returns ``True`` from boot. + +.. method:: USBD_NCM.isconnected() + + Returns ``True`` if the USB host has configured the NCM interface, + ``False`` otherwise. + + When USB is disconnected, this returns ``False`` and network traffic + stops. The interface remains registered with lwIP and can resume when + the host reconnects and re-enumerates the device. + +.. method:: USBD_NCM.status() + + Returns the link status as an integer: ``1`` if the interface is up, + ``0`` otherwise. + +.. method:: USBD_NCM.ipconfig('param') + USBD_NCM.ipconfig(param=value, ...) + + See `AbstractNIC.ipconfig`. + +.. method:: USBD_NCM.ifconfig([(ip, subnet, gateway, dns)]) + + See `AbstractNIC.ifconfig`. + +Notes +----- + +**Link-local IP address:** The device IP (169.254.x.1) is derived +deterministically from the device MAC address. RFC 3927 ARP probe/announce +(conflict detection) is not implemented, so if two devices happen to derive +the same address on the same network segment, the conflict will go undetected. + +**MAC address uniqueness:** The device and host-side MAC addresses are derived +from the value returned by ``mp_hal_get_mac()``. If two boards have the same +hardware MAC (e.g. the port does not use a hardware UID), they will present +the same network addresses and cause ARP conflicts. diff --git a/docs/library/network.WLAN.rst b/docs/library/network.WLAN.rst index e4653bc35ca..4e60d918125 100644 --- a/docs/library/network.WLAN.rst +++ b/docs/library/network.WLAN.rst @@ -146,8 +146,110 @@ Methods txpower Maximum transmit power in dBm (integer or float) pm WiFi Power Management setting (see below for allowed values) protocol (ESP32 Only.) WiFi Low level 802.11 protocol. See `WLAN.PROTOCOL_DEFAULT`. + bandwidth (ESP32 Only.) WiFi channel bandwidth. See `WLAN.BANDWIDTH_20` and others. ============= =========== +CSI Methods (ESP32 only) +------------------------ + +.. note:: + These methods are only available on ESP32 builds with CSI support enabled. + The standard generic ESP32, ESP32-C3, ESP32-C5, ESP32-C6, and ESP32-S3 + board definitions enable this in their default configuration. Other builds + need ``CONFIG_ESP_WIFI_CSI_ENABLED=y`` in the ESP-IDF configuration. + +Channel State Information (CSI) provides per-packet physical layer channel data +derived from received Wi-Fi frames. CSI capture requires an active Wi-Fi +connection and incoming traffic to the device. Without traffic, no CSI frames +will be captured. + +Other Espressif CSI options are hard-coded to defaults intended for connected +station capture. + +.. method:: WLAN.csi_enable(buffer_size=16) + + Enable CSI capture and allocate a circular buffer for received frames. + + The optional ``buffer_size`` argument sets the number of frames stored before + new incoming frames are dropped. Larger values reduce drops at the cost of RAM. The + exact maximum depends on the build, but it is limited by the underlying + ringbuffer implementation to roughly 100 frames. + + Raises ``OSError`` if CSI cannot be enabled, for example if Wi-Fi is not + active or the ESP-IDF rejects the configuration. + + Example:: + + import network + import time + + wlan = network.WLAN(network.WLAN.IF_STA) + wlan.active(True) + wlan.config(protocol=network.MODE_11B | network.MODE_11G | network.MODE_11N) + wlan.config(pm=wlan.PM_NONE) + wlan.connect("SSID", "password") + + while not wlan.isconnected(): + time.sleep_ms(100) + + wlan.csi_enable(buffer_size=32) + +.. method:: WLAN.csi_disable() + + Disable CSI capture and clean up resources. + +.. method:: WLAN.csi_read([result]) + + Read a CSI frame from the buffer. + + **Returns:** A list containing CSI frame data, or ``None`` if no frames are + available. + + If the optional ``result`` argument is provided, it must be a previous list + returned by `WLAN.csi_read()`. The list will be updated in place and + returned again. This reduces heap churn in busy read loops by reusing the + existing list object and, when the captured frame fits, the existing CSI + data ``bytearray``. + + **Frame list fields (in order):** + + * **0 - rssi** (int): Received signal strength in dBm + * **1 - channel** (int): Wi-Fi channel number + * **2 - mac** (bytes): Source MAC address (6 bytes) + * **3 - timestamp** (int): Timestamp in microseconds + * **4 - local_timestamp** (int): Local timestamp from Wi-Fi hardware + * **5 - data** (bytearray): CSI raw data (I/Q components as int8_t values) + * **6 - rate** (int): Data rate + * **7 - sig_mode** (int): Signal mode (legacy, HT, VHT) + * **8 - mcs** (int): Modulation and Coding Scheme index + * **9 - cwb** (int): Channel bandwidth + * **10 - smoothing** (int): Smoothing applied + * **11 - not_sounding** (int): Not sounding frame + * **12 - aggregation** (int): Aggregation + * **13 - stbc** (int): STBC + * **14 - fec_coding** (int): FEC coding + * **15 - sgi** (int): Short GI + * **16 - noise_floor** (int): Background noise level in dBm + * **17 - ampdu_cnt** (int): AMPDU count + * **18 - secondary_channel** (int): Secondary channel + * **19 - ant** (int): Antenna + * **20 - sig_len** (int): Signal length + * **21 - rx_state** (int): RX state + + Some metadata fields may be ``0`` on targets where ESP-IDF does not provide + the corresponding value in the public CSI receive structure. + +.. method:: WLAN.csi_available() + + Get the number of CSI frames available in the buffer. + +.. method:: WLAN.csi_dropped() + + Get the number of CSI frames dropped due to buffer overflow. + Frames are dropped when the buffer is full and new frames arrive faster than + they can be read. Increase ``buffer_size`` in ``csi_enable()`` to reduce + drops. + Constants --------- @@ -190,6 +292,26 @@ network interface parameter: Long range mode is not supported on ESP32-C2. +.. data:: WLAN.BANDWIDTH_20 + WLAN.BANDWIDTH_40 + WLAN.BANDWIDTH_80 + WLAN.BANDWIDTH_160 + WLAN.BANDWIDTH_80_80 + + Allowed values for the ``WLAN.config(bandwidth=...)`` network interface parameter: + + * ``BANDWIDTH_20``: specifies a 20MHz wide WiFi channel when in STA and AP mode + * ``BANDWIDTH_40``: specifies a 40MHz wide WiFi channel when in STA and AP mode + * ``BANDWIDTH_80``: specifies a 80MHz wide WiFi channel when in AP mode, may not + be available on all ESP32 models + * ``BANDWIDTH_160``: specifies a 160MHz wide WiFi channel when in AP mode, may not + be available on all ESP32 models + * ``BANDWIDTH_80_80``: specifies a multi-antenna 80MHz + 80MHz wide WiFi channel + setup when in AP mode, may not be available on all ESP32 models. + + When in STA mode, bandwidth can only be changed when the adapter is not connected to a + network. In AP mode it can be changed at any time. + .. _ESP-IDF Wi-Fi Protocols: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/wifi.html#wi-fi-protocol-mode .. _Espressif proprietary "long-range" mode: .. _Espressif long-range documentation: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/wifi.html#long-range-lr diff --git a/docs/library/network.rst b/docs/library/network.rst index d05d17132dc..3da27e39b2e 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -193,6 +193,7 @@ provide a way to control networking interfaces of various kinds. network.WIZNET5K.rst network.LAN.rst network.PPP.rst + network.USBD_NCM.rst Network functions ================= diff --git a/docs/library/os.rst b/docs/library/os.rst index 483ef1c0a1e..598891a330b 100644 --- a/docs/library/os.rst +++ b/docs/library/os.rst @@ -107,6 +107,7 @@ Filesystem access .. function:: sync() Sync all filesystems. + On some ports this function isn't present because it isn't necessary to sync after writes to the file-system. Terminal redirection and duplication ------------------------------------ diff --git a/docs/library/pyb.Timer.rst b/docs/library/pyb.Timer.rst index 0e9e49c0eab..fe7e6d89e4d 100644 --- a/docs/library/pyb.Timer.rst +++ b/docs/library/pyb.Timer.rst @@ -183,6 +183,8 @@ Methods - ``pulse_width`` - determines the initial pulse width value to use. - ``pulse_width_percent`` - determines the initial pulse width percentage to use. + - ``pulse_width_us`` - determines the initial pulse width in microseconds. + - ``pulse_width_ns`` - determines the initial pulse width in nanoseconds. Keyword arguments for Timer.OC modes: @@ -294,6 +296,22 @@ Methods floating-point number for more accuracy. For example, a value of 25 gives a duty cycle of 25%. +.. method:: timerchannel.pulse_width_us([value]) + + Get or set the pulse width in microseconds associated with a channel. + The value is converted to/from timer ticks using the timer's clock and + prescaler. Conversions are performed assuming simple up-counting and do not + account for center-aligned mode. For example, passing 1000 sets the pulse + width to 1 ms. + +.. method:: timerchannel.pulse_width_ns([value]) + + Get or set the pulse width in nanoseconds associated with a channel. + The value is converted to/from timer ticks using the timer's clock and + prescaler. Conversions are performed assuming simple up-counting and do not + account for center-aligned mode. This method offers finer resolution than + ``pulse_width_us()`` and matches the interface of :meth:`machine.PWM.duty_ns`. + Constants --------- diff --git a/docs/library/rp2.DMA.rst b/docs/library/rp2.DMA.rst index c5e3f31aa2e..5004bacfa32 100644 --- a/docs/library/rp2.DMA.rst +++ b/docs/library/rp2.DMA.rst @@ -5,7 +5,7 @@ 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, providing the ability to 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 @@ -14,6 +14,10 @@ RP2040's DMA controller has 12 independent DMA channels that can run concurrentl details of the RP2040's DMA system see section 2.5 of the `RP2040 Datasheet `_. +The companion class :class:`DMATimer` provides access to the DMA controller's pacing timers. +These timers can be used to control the speed of transfers into memory or peripherals that do +not have their own transfer request signalling. + Examples -------- @@ -128,17 +132,19 @@ Methods 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. + disables address wrapping (default: 0). - *ring_sel*: ``bool`` Set to ``False`` to have the ``ring_size`` apply to the read address - or ``True`` to apply to the write address. + or ``True`` to apply to the write address (default: ``False``). - *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. + datasheet for details. You may also pass a :class:`DMATimer` instance to use that timer + for pacing the transfer. The default is ``0x3f`` (``PERMANENT``), which means the + DMA channel runs at full bus speed without waiting for any external request. - *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 @@ -146,16 +152,16 @@ Methods ``True``). - *bswap*: ``bool`` If set to true, bytes in words or half-words will be reversed before - writing (default: ``True``). + writing (default: ``False``). - - *sniff_en*: ``bool`` Set to ``True`` to allow data to be accessed by the chips sniff + - *sniff_en*: ``bool`` Set to ``True`` to allow data to be accessed by the chip's sniff hardware (default: ``False``). - *write_err*: ``bool`` Setting this to ``True`` will clear a previously reported write - error. + error (default: ``False``). - *read_err*: ``bool`` Setting this to ``True`` will clear a previously reported read - error. + error (default: ``False``). 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. @@ -291,3 +297,69 @@ below is a Pythonic version of the example in sub-section 2.5.6.2. This example idles while waiting for the transfer to complete; alternatively it could set an interrupt handler and return immediately. + +class DMATimer -- pacing timers for DMA transfers +================================================= + +The RP2040 and RP2350 DMA controllers provide four "pacing" timers that can be used to +control the rate at which DMA transfers take place. In the absence of specifying a transfer +request signal using the ``treq_sel`` parameter in the control configuration the DMA controller +will try to transfer data as fast as the bus will allow, which can be as fast as the system +clock speed. Often I/O operations should happen +at some lower rate, and it is also sometimes valuable to moderate the rate of transfers from +memory to memory in order to avoid overloading the bus (particularly when using external +PSRAM, which is much slower than the on-chip SRAM). By using a :class:`DMATimer` the user +can select a rate that is a rational fraction of the system clock speed. Each timer can +independently trigger transfer requests at rate that is ``X/Y`` times the system clock, +where ``X < Y``. + +:class:`DMATimer` objects can be used directly as the value for treq_sel passed into the +:meth:`DMA.pack_ctrl()` function, since the value if ``int(dma_timer)`` is the index +of the transfer request selector for the timer. Thus if you want to pace a transfer to +run at 10,000 operations per second you can use:: + + dma = rp2.DMA() + timer = rp2.DMATimer(freq=10000) + ctrl = d.pack_ctrl(treq_sel=timer) # Default control value with paced by the timer + dma.config(read=src, write=dst, count=length, ctrl=ctrl, trigger=True) + +Note: The underlying DMA pacing timer will get released when a :class:`DMATimer` gets +garbage collected. If you are setting in motion a DMA transfer that is not expected to +complete before the timer object goes out of scope then it is a good idea to keep a +reference to it so that the timer does not get reassigned to some other caller (which +might change the frequency on you). + +Constructor +----------- + +.. class:: DMATimer(timer_id=None, *, freq=None, ratio=None) + + Claim one of the DMA pacing timers for exclusive use and optionally set the frequency or ratio. + + - *timer_id*: Which timer to use. Leave empty to select any unclaimed timer. + - *freq*: The optional value to assign to the :attr:`freq` attribute. + - *ratio*: The optional value to assign to the :attr:`ratio` attribute. + + If both ``freq`` and ``ratio`` are provided then ``ratio`` is used. + +Methods +------- + +.. method:: DMATimer.close() + + Release the exclusive claim on the underlying timer. + +Attributes +---------- + +.. attribute:: DMATimer.ratio + + Set or read the ``(X, Y)`` tuple for the system clock division ratio. When setting the ratio + both X and Y need to in the range 0 < X, Y < 65536. + +.. attribute:: DMATimer.freq + + Set or read the DMATimer frequency in Hz. When setting, the frequency will be set to the closest + frequency that can be achieved by the divider. Reading the frequency back will show the actual + selected frequency, to the nearest 1Hz. The requested value needs be less than or equal to the + system clock speed and greater than or equal to 1/65535 of the system clock. diff --git a/docs/library/ssl.rst b/docs/library/ssl.rst index c86101872c3..2c0365dd2c9 100644 --- a/docs/library/ssl.rst +++ b/docs/library/ssl.rst @@ -25,8 +25,9 @@ Functions Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not validate any certificate, only ``ssl.CERT_REQUIRED`` will. - - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will - validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + - *cadata* is a str or bytes object containing the CA certificate chain that will validate the + peer's certificate. It can be one or more certificates in PEM format, or single DER-encoded + certificate. Depending on the underlying module implementation in a particular :term:`MicroPython port`, some or all keyword arguments above may be not supported. @@ -66,6 +67,31 @@ class SSLContext Set the available ciphers for sockets created with this context. *ciphers* should be a list of strings in the `IANA cipher suite format `_ . +.. attribute:: SSLContext.psk_identity + SSLContext.psk_key + + The pre-shared key (PSK) identity and key to authenticate with as a client. + Set both to use PSK: *psk_identity* is the identity sent to the server and + *psk_key* is the shared key, both as `bytes` objects. + + While PSK is configured the context offers only PSK cipher suites, so the + connection cannot fall back to a non-PSK (e.g. certificate-based) suite. + + Availability depends on the port's mbedTLS being built with PSK support. + +.. attribute:: SSLContext.server_psk_keys + + A mapping used by a server to look up the key for the identity presented by a + connecting client. Set it to accept PSK clients:: + + ctx.server_psk_keys = {b"my-identity": b"my-key"} + + Its ``get()`` method is called with the client's identity (a `bytes` object) + and should return the corresponding key as a `bytes` object, or ``None`` to + reject an unknown identity. Any object providing such a ``get()`` method may + be used, so keys can be computed or fetched on demand. As with the client, + the context is restricted to PSK cipher suites while this is set. + .. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None, client_id=None) Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), diff --git a/docs/library/vfs.rst b/docs/library/vfs.rst index 1fa1e3060cb..97f96510bbb 100644 --- a/docs/library/vfs.rst +++ b/docs/library/vfs.rst @@ -50,6 +50,9 @@ represented by VFS classes. Will raise ``OSError(EINVAL)`` if *mount_point* is not found. +Filesystem Types +---------------- + .. class:: VfsFat(block_dev) Create a filesystem object that uses the FAT filesystem format. Storage of @@ -107,11 +110,87 @@ represented by VFS classes. as the root of the ``VfsPosix`` object. Otherwise the current directory of the host filesystem is used. +.. class:: VfsRom(buffer) + + This class is only available when the firmware is built with + ``MICROPY_VFS_ROM`` enabled. + + Create a filesystem object that uses the :ref:`ROMFS read-only filesystem + format `. *buffer* must be an object supporting the buffer protocol + (e.g. ``bytes``, ``bytearray``, or ``memoryview``) that contains a valid + ROMFS image. + The constructor validates that *buffer* begins with the ROMFS magic bytes + (``b"\xd2\xcd\x31"``). If the buffer is too small or not a valid ROMFS + then ``OSError(ENODEV)`` is raised. + + See :ref:`romfs` for more information on the ROMFS filesystem and how to + deploy images using :ref:`mpremote `. + + .. method:: VfsRom.open(path, mode) + + Open a file from the ROMFS. Only read modes (``''``, ``'r'``, + ``'rt'``, ``'rb'``) are supported. + For binary files opened in read mode, + the returned object also supports the buffer protocol so that a + ``memoryview`` of the file data can be obtained, which refers + directly into the ROMFS memory (zero-copy). + + .. method:: VfsRom.statvfs(path) + + The block size is reported as 1 and + the block count represents the total size of the ROMFS image in bytes. + + .. method:: VfsRom.chdir(path) + + Change directory within the ROMFS. Only the root (``'/'``) is + supported; changing to any subdirectory raises ``OSError(EOPNOTSUPP)``. + .. _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 +Miscellaneous Functions +----------------------- + +.. function:: rom_ioctl(op, ...) + + Low-level interface for accessing the read-only memory (ROM) partition(s) + of the device. This function is only available on ports that support ROMFS + (i.e. where ``MICROPY_VFS_ROM_IOCTL`` is enabled). + + The supported operations are: + + - ``vfs.rom_ioctl(1)`` -- Return the number of available ROM partitions. + - ``vfs.rom_ioctl(2, id)`` -- Return ROM partition *id* as an object that + supports the buffer protocol. Depending on the port, this is either a + block device or a ``memoryview``. A block device supports the standard + block protocol, including erase and write operations. If a ``memoryview`` + is returned, the port must provide erase and write operations through + ``vfs.rom_ioctl()`` operations 3, 4, and 5 below. + - ``vfs.rom_ioctl(3, id, length)`` -- Prepare the first *length* bytes of + ROM partition *id* for writing (for example, by erasing flash). Returns + the minimum write size in bytes (the alignment required for subsequent + writes). + - ``vfs.rom_ioctl(3, id, offset, length)`` -- Prepare *length* bytes of ROM + partition *id*, starting at byte *offset*, for writing. This form allows + a partition to be prepared incrementally. Returns + the minimum write size in bytes. + - ``vfs.rom_ioctl(4, id, offset, buf)`` -- Write *buf* (a bytes-like object) + to the ROM partition with index *id* at byte *offset*. + - ``vfs.rom_ioctl(5, id)`` -- Complete a write sequence to partition *id* + (performs any finalisation needed after writing, such as cache flushing). + - ``vfs.rom_ioctl(6, id)`` -- Return the minimum number of bytes of ROM + partition *id* that can be prepared at once. A positive return value + indicates that the four-argument form of operation 3 is supported; + *offset* and *length* must be aligned to this value. Otherwise, only the + three-argument form of operation 3 is supported. + + These operations are used internally by ``mpremote`` to deploy ROMFS images. + Most users do not need to call ``vfs.rom_ioctl()`` directly. + + See :ref:`romfs` for more information. + Block devices ------------- @@ -163,6 +242,9 @@ that the block device supports the extended interface. 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*. + Upon success the method should return ``None`` or 0. Upon failure it should + return a negative integer corresponding to an ``OSError`` errno code. + .. method:: writeblocks(block_num, buf) writeblocks(block_num, buf, offset) @@ -184,6 +266,9 @@ that the block device supports the extended interface. Note that implementations must never implicitly erase blocks if the offset argument is specified, even if it is zero. + Upon success the method should return ``None`` or 0. Upon failure it should + return a negative integer corresponding to an ``OSError`` errno code. + .. method:: ioctl(op, arg) Control the block device and query its parameters. The operation to diff --git a/docs/mimxrt/pinout.rst b/docs/mimxrt/pinout.rst index b2ff0683f7b..d151b5e50c9 100644 --- a/docs/mimxrt/pinout.rst +++ b/docs/mimxrt/pinout.rst @@ -477,3 +477,34 @@ assignment to the Encoder or Counter are: Pins J3_14, J3_15, J4_19, J4_20, J5_15, J5_16, J5_17, J5_22, J5_23, J5_24, J5_25 and J5_26. Pins J3_14 and J3_15 cannot be used for the match output. + + +.. _mimxrt_can_pinout: + +| +| + +Hardware CAN pin assignment +--------------------------- + +Pin assignments for a few MIMXRT boards. The list show the MCU TX/RX pins. + +================= =========== =========== ======= +Board CAN1 CAN2 CAN3 +================= =========== =========== ======= +Teensy 4.0 A8/A9 D1/D0 - +Teensy 4.1 A8/A9 D1/D0 D31/D30 +Seeed Arch MIX J4_08/J4_09 J3_14/J3_15 +MIMXRT1020_DEV Transceiver - - +MIMXRT1050_DEV Transceiver - - +MIMXRT1060_DEV Transceiver - - +MIMXRT1064_DEV Transceiver - - +MIMXRT1170_DEV Transceiver D4/D8 - +phyBOARD-RT1170 CAN port - - +================= =========== =========== ======= + +All supported MIMXRT Developments boards are equipped with a CAN transceiver +and do expose it's MCU pins. At the 3 pin transceiver connector +CAN_H is as pin 1, CAN_L at Pin 3. Pin 2 is connected to GND. +A documentation showing the CAN pin assignments of the phyBOARD-RT1170 +does not seem to be accessible. diff --git a/docs/psoc-edge/general.rst b/docs/psoc-edge/general.rst new file mode 100644 index 00000000000..5b6f4105cd9 --- /dev/null +++ b/docs/psoc-edge/general.rst @@ -0,0 +1,53 @@ +.. _psoc_edge_general: + +.. include:: links.rst + +General information about the PSOC™ Edge port +============================================== + +The PSOC™ Edge is designed for next generation responsive compute and control applications, featuring hardware-assisted machine learning (ML) acceleration. +The PSOC™ Edge devices are based on high performance Arm® Cortex®-M55, including Helium™ DSP support paired with Arm® Ethos™-U55 and Cortex®-M33 paired Infineon’s ultra-low power NNLite neural network accelerator. + +The PSOC™ Edge port supports boards powered by the `Infineon PSOC™ Edge family of microcontrollers `_ and currently supports the following MCUs: + +* PSOC™ Edge E84 + +.. _Supported boards: + +Supported boards +^^^^^^^^^^^^^^^^^ + +The following boards are supported on this port: + +.. list-table:: + :widths: 20 20 50 + :header-rows: 1 + + * - Board name + - Connectivity + - Special feature + * - KIT_PSE84_AI + - Wi-Fi, BT + - 60GHz radar, analog microphone, digital microphone, barometric pressure sensor, external flash, speaker interface, IMU sensor, magnetometer, image sensor + + +For more hardware-related details, refer to the following sections. + +KIT_PSE84_AI +------------ + +Pinout +****** + +.. image:: img/kit_pse84_ai_pinout.png + :width: 500 + + +Technical specifications +************************ +Links for product details: + +* `KIT_PSE84_AI PSOC™ Edge E84 AI product page `_ +* `KIT_PSE84_AI PSOC™ Edge E84 AI Kit guide `_ +* `PSOC™ Edge E8x2, E8x3, E8x5, E8x6 Consumer Datasheet `_ +* `PSOC™ Edge E8x2, E8x3, E8x5, E8x6 Architecture Reference Manual `_ \ No newline at end of file diff --git a/docs/psoc-edge/img/kit-pse84-ai.png b/docs/psoc-edge/img/kit-pse84-ai.png new file mode 100644 index 00000000000..4abc67d83bc Binary files /dev/null and b/docs/psoc-edge/img/kit-pse84-ai.png differ diff --git a/docs/psoc-edge/img/kit_pse84_ai_pinout.png b/docs/psoc-edge/img/kit_pse84_ai_pinout.png new file mode 100644 index 00000000000..36b119c768a Binary files /dev/null and b/docs/psoc-edge/img/kit_pse84_ai_pinout.png differ diff --git a/docs/psoc-edge/installation.rst b/docs/psoc-edge/installation.rst new file mode 100644 index 00000000000..dd680e1543d --- /dev/null +++ b/docs/psoc-edge/installation.rst @@ -0,0 +1,62 @@ +.. _pse_mpy_install: + +Installing MicroPython +====================== + +To facilitate the installation of the MicroPython PSOC™ Edge port, the ``mp-ifx-flash.py`` Python script is +provided. It is compatible with Windows, Linux, and macOS. + +Prerequisites +------------- + +Before downloading and running the script, it is recommended to create a new folder to keep all the +related files together. For example: + +.. code-block:: bash + + $ mkdir mp-install + $ cd mp-install + +You can easily download the script from the terminal using the following command: + +.. code-block:: bash + + $ curl -s -L https://raw.githubusercontent.com/micropython/micropython/master/ports/psoc-edge/tools/mp-ifx-flash.py > mp-ifx-flash.py + +Ensure you have a recent version of `Python 3.x `_ and the +`pip `_ package installed. Then install the following packages: + +.. code-block:: bash + + $ pip install requests + +Getting the firmware +^^^^^^^^^^^^^^^^^^^^ + +Download the desired MicroPython firmware version for the PSOC™ Edge board from the `MicroPython download page `_. +The downloaded file is a ``.zip`` package containing the firmware binary and the necessary files for flashing. + +Flashing +-------- + +To flash the firmware, use the ``from-package`` command. +Specify the board using the ``--board`` flag and the path to the +downloaded ``.zip`` package using the ``--zip-package`` flag, as shown below: + +.. code-block:: bash + + $ python mp-ifx-flash.py from-package --board KIT_PSE84_AI --zip-package pathtodir/psoc-edge-package.zip + +Multiple connected devices +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you have multiple PSOC™ Edge boards connected to your computer, you can identify them by their +serial number and flash each one individually. To do so, use the ``-n`` flag to provide the serial number of +the target board as shown below: + +.. code-block:: bash + + $ python mp-ifx-flash.py from-package --board KIT_PSE84_AI --zip-package pathtodir/psoc-edge-package.zip -n 181F0D5A01212300 + + + diff --git a/docs/psoc-edge/links.rst b/docs/psoc-edge/links.rst new file mode 100644 index 00000000000..eccc46bb9d7 --- /dev/null +++ b/docs/psoc-edge/links.rst @@ -0,0 +1,6 @@ +.. _links.rst: + +.. _pse84_kit_ai_product_page: https://www.infineon.com/evaluation-board/KIT-PSE84-AI +.. _pse84_kit_ai_guide: https://www.infineon.com/assets/row/public/documents/30/44/infineon-kit-pse84-ai-user-guide-usermanual-en.pdf +.. _pse8x_consumer_datasheet: https://www.infineon.com/assets/row/public/documents/30/49/infineon-psoc-edge-e8x-consumer-datasheet-datasheet-en.pdf +.. _pse8x_arch_ref_manual: https://www.infineon.com/assets/row/public/documents/30/57/infineon-psoc-edge-e8x-architecture-reference-manual-additionaltechnicalinformation-en.pdf \ No newline at end of file diff --git a/docs/psoc-edge/quickref.rst b/docs/psoc-edge/quickref.rst new file mode 100644 index 00000000000..eb0a504bbcf --- /dev/null +++ b/docs/psoc-edge/quickref.rst @@ -0,0 +1,259 @@ +.. _psoc_edge_quickref: + +.. include:: links.rst + +Quick reference for the PSOC™ Edge +=================================== + +.. image:: img/kit-pse84-ai.png + :alt: KIT_PSE84_AI board + :width: 540px + +The `PSOC™ Edge E84 AI Kit `_. + +Below is a quick reference for PSOC™ Edge E84 boards. If it is your first time +working with this port it may be useful to get an overview of the microcontroller: + +.. toctree:: + :maxdepth: 1 + :includehidden: + + general.rst + installation.rst + +.. note:: + + You can follow the latest progress for this port in the `Infineon MicroPython + PSOC™ Edge fork `_. + We are working to bring those features here. Meanwhile, you can try them early + by installing the fork version. + +Pins and GPIO +------------- + +See :ref:`machine.Pin ` for the complete Pin API reference. +This section focuses on the specific PSOC™ Edge port variations and particularities. + +The constructor +^^^^^^^^^^^^^^^ + +The controller pin naming follows the nomenclature ``P_``, where: + + - ```` is a numeric identifier for the port (e.g., 0-21 for the PSOC™ Edge E84) + - ```` is the pin number within that port. + +Use the respective board pinout diagram to find the available pins and their locations. + +This is the ``id`` that needs to be passed to the constructor in one of the following formats: + + - As a **string label**, single or double quoted: ``'P_'`` or ``"P_"`` + - A **pre-instantiated object** ``Pin.cpu.`` or ``Pin.board.``. + +:: + + from machine import Pin + + p_in = Pin('P0_0', Pin.IN) + p_out = Pin("P7_0", Pin.OUT, value=False) + + p = Pin(Pin.cpu.P17_1, Pin.OPEN_DRAIN) + + +The pre-instantiated object can be used directly without calling the constructor. +Instead, you can use ``init()`` to configure it. + +:: + + from machine import Pin + + pin = Pin.cpu.P17_0 + pin.init(mode=Pin.IN) + + +.. tip:: + Use the REPL interface to discover the available user pins, using tab for completion: + + >>> from machine import Pin + >>> Pin.cpu.P + P10_5 P10_7 P11_3 P12_3 + P13_0 P13_1 P13_2 P13_3 + P13_4 P13_5 P13_6 P13_7 + P14_0 P14_1 P14_2 P14_3 + P14_4 P14_5 P14_6 P14_7 + P15_0 P15_1 P15_2 P15_3 + P15_4 P15_5 P15_6 P15_7 + P16_0 P16_1 P16_2 P16_3 + P16_4 P16_5 P16_6 P16_7 + P17_0 P17_1 P17_2 P17_3 + P17_4 P17_5 P17_7 P20_3 + P20_4 P20_5 P20_6 P20_7 + P21_1 P21_2 P21_3 P21_4 + P21_5 P21_6 P21_7 P3_0 + P3_1 P6_4 P6_6 P7_0 + P7_7 P8_0 P8_1 P8_5 + P8_6 P9_0 P9_1 P9_2 + P9_3 + + >>> from machine import Pin + >>> Pin.board. + AMIC1_CTB_INN AMIC1_CTB_INP AMIC1_CTB_OUT AMIC1_CTB_REF + AMIC2_CTB_INN AMIC2_CTB_INP AMIC2_CTB_OUT AMIC2_CTB_REF + I2C_SCL_1V8 I2C_SCL_3V3 I2C_SDA_1V8 I2C_SDA_3V3 + I2S_TX_FYSYNC I2S_TX_MCK I2S_TX_SCK I2S_TX_SD + I3C_SCL I3C_SDA IMU0_INT IMU1_INT + MAG_INT PDM_CLK PDM_DATA PRESS_SENS_INT + RADAR_INT RADAR_RESET RADAR_SPI_CLK RADAR_SPI_CS + RADAR_SPI_MISO RADAR_SPI_MOSI SERIAL_INT0 SERIAL_INT1 + SERIAL_INT2 SERIAL_INT3 USER_BUTTON USER_LED1 + USER_LED2 USER_LED_B USER_LED_G USER_LED_R + + + + + +The ``drive`` parameter accepts up to 8 levels, which set the following drive strength for the pin: + + - ``DRIVE_0``: 1mA/2mA drive current (normal/high speed IO) + - ``DRIVE_1``: 2mA/4mA drive current (normal/high speed IO) + - ``DRIVE_2``: 3mA/6mA drive current (normal/high speed IO) + - ``DRIVE_3``: 4mA/8mA drive current (normal/high speed IO) + - ``DRIVE_4``: 5mA/10mA drive current (normal/high speed IO) + - ``DRIVE_5``: 6mA/12mA drive current (normal/high speed IO) + - ``DRIVE_6``: 7mA/14mA drive current (normal/high speed IO) + - ``DRIVE_7``: 8mA/16mA drive current (normal/high speed IO) + +For more information about drive strength, check the PSOC™ Edge `Datasheet `_ and `Architecture Reference Manual `_. + +.. note:: + + The following constructor arguments and/or configuration values are NOT supported in this port: + + - ``alt``: Alternate functionality is not supported. + - ``mode``: ``Pin.ALT``, ``Pin.ALT_OPEN_DRAIN``, and ``Pin.ANALOG`` modes are not supported. + + The following ``mode``- ``pull`` combinations are not supported in this port: + + - ``Pin.OUT`` with ``Pin.PULL_UP`` or ``Pin.PULL_DOWN`` + - ``Pin.OPEN_DRAIN`` with ``Pin.PULL_DOWN`` + + +Methods +^^^^^^^ + +.. method:: Pin.irq(handler=None, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING), priority=7) + +The following parameters have port-specific behavior: + + - ``priority``: Priority values range from 7 (lowest) to 0 (highest). Default is 7. + + .. note:: + + All pins on the same port share the same interrupt line. Therefore, only one priority can be set for all pins on the same port. + If multiple pins configure interrupts for the same port, the highest priority will be used. + If only one pin is configured for an interrupt, its priority can be reconfigured to any value. + +.. note:: + + The following ``irq()`` features are not supported in this port: + + - ``trigger``: The ``Pin.IRQ_LOW_LEVEL`` and ``Pin.IRQ_HIGH_LEVEL`` triggers are not supported. + - ``wake``: The wake parameter is currently not supported. + - ``hard``: This parameter is ignored. It can be passed but currently has no effect. + +.. note:: + + **None** of the non-core methods from the Pin API are currently implemented for this port. + + +Real time clock (RTC) +--------------------- + +See :ref:`machine.RTC `: :: + + from machine import RTC + import time + + irq_counter = 0 + + def cback(event): + global irq_counter + irq_counter += 1 + + rtc = RTC() + rtc.init((2023, 1, 1, 0, 0, 0, 0, 0)) # initialise rtc with specific date and time, + # eg. 2023/1/1 00:00:00 + rtc.datetime((2017, 8, 23, 2, 12, 48, 0, 0)) # set a specific date and + # time, eg. 2017/8/23 1:12:48 + rtc.datetime() # get date and time + + rtc.irq(trigger=RTC.ALARM0, handler=cback) + rtc.alarm(1000, repeat=False) # set one-shot short alarm in ms + rtc.alarm_left() # Read the time left for the alarm to expire + time.sleep_ms(1008) # wait sufficient time + print(irq_counter) # Check irq counter + + rtc.irq(trigger=RTC.ALARM0, handler=cback) + rtc.alarm(3000, repeat=True) # set periodic short alarm in ms + rtc.cancel() # cancel the alarm + + rtc.irq(trigger=RTC.ALARM0, handler=cback) + rtc.alarm((2023, 1, 1, 0, 0, 1, 0, 0), repeat=False) # set one-shot longer duration alarm + + rtc.memory(b"hello") # write bytes into RTC user memory + rtc.memory() # read bytes from RTC user memory + + +.. note:: + Setting a random week day in 'wday' field is not valid. The underlying library implements the logic to always + calculate the right weekday based on the year, date and month passed. However, datetime() will not raise an error + for this but rather re-write the field with the last calculated actual value. + +.. note:: + RTC API behavior on this port has the following specifics: + + - ``RTC()`` is a singleton constructor with no ``id`` or additional constructor arguments. + - ``rtc.irq()`` accepts alarm trigger ``0`` (``RTC.ALARM0``); ``wake`` is not implemented. + - ``rtc.alarm()`` accepts ``time`` and optional ``repeat``; no positional alarm ``id`` argument is used. + - Input ``weekday`` in datetime tuples is ignored and hardware computes the weekday from date fields. + - The current ``rtc.memory([data])`` maximum payload on KIT_PSE84_AI is 28 bytes. + +.. warning:: + RTC alarm timing on this port has second-level resolution. Millisecond alarm values are accepted, but are rounded + up to whole seconds internally. + +UART +---- + +See :ref:`machine.UART `. + +The following specialization applies to this port: + +Constructor +^^^^^^^^^^^^ + +.. class:: UART(id) + + The following parameters are supported with limited configuration: + + - ``bits``. Only 8 bits. + + These are planned for future implementation, but yet unavailable: + + - ``rts`` + - ``cts`` + - ``flow`` + +.. Note:: + + These parameters are not implemented: + + - ``txbuf`` + - ``invert`` + + +Methods +^^^^^^^ + +.. method:: UART.init(baudrate=9600, bits=8, parity=None, stop=1, *, ...) + + The same parameters as the constructor are supported, with the same limitations. \ No newline at end of file diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index 616dc8833fd..224a2c58067 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -116,6 +116,9 @@ to a constant e.g. ``0x100``, ``1 << 8`` or ``(True, "string", b"bytes")`` (see section below for details). It can even include other const symbols that have already been defined, e.g. ``1 << BIT``. +See :func:`micropython.const` for complete documentation including scope +requirements, import syntax, and other important limitations. + **Constant data structures** Where there is a substantial volume of constant data and the platform supports @@ -251,7 +254,26 @@ instances so the process of eliminating Unicode can be painless. b = b'the quick brown fox' # A bytes instance Where it is necessary to convert between strings and bytes the :meth:`str.encode` -and the :meth:`bytes.decode` methods can be used. Note that both strings and bytes +and the :meth:`bytes.decode` methods can be used. MicroPython validates the +encoding parameter and only supports UTF-8 and ASCII. The :meth:`bytes.decode` +method also supports error handlers (``'ignore'`` and ``'replace'``) for handling +invalid UTF-8, when enabled in the build configuration. + +For memory-conscious applications processing untrusted data, using the ``'ignore'`` +error handler can be more efficient than ``'strict'`` mode (the default), as it +avoids raising exceptions while still recovering valid text:: + + # Strict mode (default) raises an error on invalid UTF-8 + try: + s = data.decode('utf-8') + except UnicodeError: + # Handle error + pass + + # Ignore mode skips invalid bytes (more memory-efficient) + s = data.decode('utf-8', 'ignore') + +Note that both strings and bytes are immutable. Any operation which takes as input such an object and produces another implies at least one RAM allocation to produce the result. In the second line below a new bytes object is allocated. This would also occur if ``foo`` diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst index 48a46585602..59491310d15 100644 --- a/docs/reference/filesystem.rst +++ b/docs/reference/filesystem.rst @@ -163,6 +163,9 @@ normally would be used from Python code, for example:: f.write('Hello world') print(open('/ramdisk/hello.txt').read()) +For further details of the block device methods and their return values +see :class:`vfs.AbstractBlockDev`. + Filesystems ----------- diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 1558c0fdfa9..18be1c80342 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -31,5 +31,7 @@ implementation and the best practices to use them. packages.rst asm_thumb2_index.rst filesystem.rst + romfs.rst + unicode_support.rst pyboard.py.rst micropython2_migration.rst diff --git a/docs/reference/manifest.rst b/docs/reference/manifest.rst index dc9d6dd75b2..1e43f4729a7 100644 --- a/docs/reference/manifest.rst +++ b/docs/reference/manifest.rst @@ -149,6 +149,37 @@ See :func:`micropython.opt_level`. You can use the variables above, such as ``$(PORT_DIR)`` in ``base_path``. +.. function:: c_module(module_path) + + Include a C module directory in the build. + + The *module_path* should be a directory containing a ``micropython.mk`` + and/or ``micropython.cmake`` file that defines the C module. + + This function can be called multiple times to include multiple C modules: + + .. code-block:: python3 + + c_module("$(MPY_DIR)/examples/usercmodule/cexample") + c_module("$(BOARD_DIR)/../../drivers/sensor") + + Supports ``$(VAR)`` path substitution just like other manifest functions. + + ``c_module()`` only takes effect when the manifest is loaded as a + ``FROZEN_MANIFEST`` (it has no effect when the manifest is processed in + package-build or compile-only modes). Modules added with ``c_module()`` + are merged with any paths passed on the command line via + ``USER_C_MODULES``; both sources combine additively and duplicate paths + are de-duplicated. + + The referenced C module directories must already be present on disk at + build time. If a path points into a submodule, ensure that + ``make submodules`` has been run first. + + Note: on Makefile-based ports, paths containing whitespace are not + supported (a GNU make limitation). CMake-based ports handle whitespace + paths correctly. + .. function:: require(name, library=None) Require a package by name (and its dependencies) from :term:`micropython-lib`. diff --git a/docs/reference/mpremote.rst b/docs/reference/mpremote.rst index 8aecc3a5d48..32986c2161d 100644 --- a/docs/reference/mpremote.rst +++ b/docs/reference/mpremote.rst @@ -215,6 +215,12 @@ The full list of supported commands are: terminates. The ``--no-follow`` flag can be specified to return immediately and leave the device running the script in the background. + **Note:** Only the contents of the local file are sent to the device; the + local filename has no special meaning, so passing a file called ``main.py`` + is no different from any other name. The script is executed in raw REPL + after a soft reset, so the device's own ``main.py`` is not run beforehand. + Any ``main.py`` already stored on the device filesystem is left untouched. + .. _mpremote_command_fs: - **fs** -- execute filesystem commands on the device: @@ -376,28 +382,13 @@ The full list of supported commands are: This happens automatically when ``mpremote`` terminates, but it can be used in a sequence to unmount an earlier mount before subsequent command are run. -.. _mpremote_command_romfs: - - **romfs** -- manage ROMFS partitions on the device: .. code-block:: bash $ mpremote romfs - ```` may be: - - - ``romfs query`` to list all the available ROMFS partitions and their size - - ``romfs [-o ] build `` to create a ROMFS image from the given - source directory; the default output file is the source appended by ``.romfs`` - - ``romfs [-p ] deploy `` to deploy a ROMFS image to the device; - will also create a temporary ROMFS image if the source is a directory - - The ``build`` and ``deploy`` sub-commands both support the ``-m``/``--mpy`` option - to automatically compile ``.py`` files to ``.mpy`` when creating the ROMFS image. - This option is enabled by default, but only works if the ``mpy_cross`` Python - package has been installed (eg via ``pip install mpy_cross``). If the package is - not installed then a warning is printed and ``.py`` files remain as is. Compiling - of ``.py`` files can be disabled with the ``--no-mpy`` option. + See :ref:`mpremote ROMFS commands ` for details. .. _mpremote_command_rtc: @@ -448,6 +439,107 @@ The full list of supported commands are: This will make the device enter its bootloader. The bootloader is port- and board-specific (e.g. DFU on stm32, UF2 on rp2040/Pico). +.. _mpremote_command_romfs: + +ROMFS commands +-------------- + +The ``romfs`` command provides three sub-commands for managing ROMFS images on +a connected device. + +.. _mpremote_command_romfs_query: + +mpremote romfs query +~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + $ mpremote romfs query + +Lists all available ROMFS partitions on the device and their sizes. Also +shows the first 12 bytes of each partition in hex and reports whether a +valid ROMFS image is present. + +Example output:: + + ROMFS0 partition has size 131072 bytes (32 blocks of 4096 bytes each) + Raw contents: d2:cd:31:XX:XX:XX:XX:XX:XX:XX:XX:XX ... + ROMFS image size: 1234 + +.. _mpremote_command_romfs_build: + +mpremote romfs build +~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + $ mpremote romfs [-o ] build + +Build a ROMFS image from the directory *source* on the host PC. The image +is written to *output* (default: ``.romfs``). + +Options: + +- ``-o ``, ``--output ``: Specify the output file path. +- ``-m``, ``--mpy`` (default): Automatically compile ``.py`` files to + ``.mpy`` using ``mpy_cross`` before adding them to the image. This requires + the ``mpy_cross`` Python package (``pip install mpy_cross``); without it, + ``mpremote`` prints a warning and leaves the ``.py`` files unchanged. +- ``--no-mpy``: Disable automatic compilation of ``.py`` files. + +Example:: + + $ mpremote romfs build myapp/ + Building romfs filesystem, source directory: myapp/ + / + |-- main.py -> .mpy + \-- lib/ + \-- helper.py -> .mpy + Writing 2048 bytes to output file myapp.romfs + +.. _mpremote_command_romfs_deploy: + +mpremote romfs deploy +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + $ mpremote romfs [-p ] deploy + +Deploy a ROMFS image to the device. *source* can be either: + +- A directory on the host: the ROMFS image is built in memory and deployed + directly. +- A ``.romfs`` or ``.img`` file: the image is read from disk and deployed. + +Options: + +- ``-p ``, ``--partition ``: Specify the target + partition index (default: ``0``). +- ``-m``, ``--mpy`` (default): Compile ``.py`` to ``.mpy`` when *source* + is a directory. If ``mpy_cross`` is not installed, ``mpremote`` prints a + warning and leaves the ``.py`` files unchanged. +- ``--no-mpy``: Disable automatic compilation of ``.py`` files. + +After deployment, the device must be soft-reset for the new ROMFS to be +mounted at ``/rom``. + +Example:: + + $ mpremote romfs deploy myapp/ + Building romfs filesystem, source directory: myapp/ + / + |-- main.py -> .mpy + \-- lib/ + \-- helper.py -> .mpy + Image size is 2048 bytes + ROMFS0 partition has size 131072 bytes (32 blocks of 4096 bytes each) + Preparing ROMFS0 partition for writing + Deploying ROMFS to ROMFS0 partition + ROMFS image deployed + + $ mpremote soft-reset + .. _mpremote_reset: Auto connection and soft-reset diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index 5b5f626d452..adc9f95e01f 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -38,13 +38,15 @@ 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:``, ``gitlab:``, or ``codeberg:`` as a simple +way of pointing to content hosted on GitHub, GitLab, or Codeberg:: >>> 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 + >>> mip.install("codeberg:org/repo/path/foo.py") # Uses default branch + >>> mip.install("codeberg: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``. @@ -52,6 +54,7 @@ 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") + >>> mip.install("codeberg:org/user/path/package.json") If no json file is specified, then "package.json" is implicitly added:: @@ -60,6 +63,8 @@ If no json file is specified, then "package.json" is implicitly added:: >>> 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") + >>> mip.install("codeberg:org/repo") # Uses default branch of that repo + >>> mip.install("codeberg:org/repo", version="branch-or-tag") Using ``mip`` on the Unix port ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -89,6 +94,8 @@ can be used from a host PC to install packages to a locally connected device $ mpremote mip install github:org/repo@branch-or-tag $ mpremote mip install gitlab:org/repo $ mpremote mip install gitlab:org/repo@branch-or-tag + $ mpremote mip install codeberg:org/repo + $ mpremote mip install codeberg:org/repo@branch-or-tag The ``--target=path``, ``--no-mpy``, and ``--index`` arguments can be set:: diff --git a/docs/reference/romfs.rst b/docs/reference/romfs.rst new file mode 100644 index 00000000000..ec4643ae757 --- /dev/null +++ b/docs/reference/romfs.rst @@ -0,0 +1,253 @@ +.. _romfs: + +Working with ROMFS +================== + +.. contents:: + +Overview +-------- + +ROMFS (Read-Only Memory Filesystem) is a lightweight, read-only filesystem +optimised for microcontrollers and embedded systems +where code and data need to be stored in flash memory and +accessed efficiently without being copied into RAM. + +The key benefits of ROMFS are: + +- **Zero-copy imports**: ``.mpy`` bytecode files stored in a ROMFS can be + executed directly from flash memory (memory-mapped) rather than being copied + into RAM first. This is similar to how :ref:`frozen modules ` work, + but does not require reflashing the entire firmware. +- **Low RAM overhead**: String and byte constant objects in ``.mpy`` + files loaded from ROMFS are referenced directly from flash, not duplicated + in RAM. +- **Flexible deployment**: A ROMFS image can be built on a host PC and deployed + to the device using ``mpremote``, without rebuilding the firmware. +- **Standard filesystem interface**: A ROMFS is mounted in the :ref:`VFS + ` and accessed via normal Python file operations (``open``, + ``os.listdir``, ``import``, etc.). + +ROMFS is complementary to both the read-write LittleFS/FAT filesystems (which +live in other flash partitions) and to :ref:`frozen modules ` (which +are compiled into the firmware itself). + +.. note:: + + ROMFS requires firmware that has been built with ROMFS support enabled + (``MICROPY_VFS_ROM``). Not all ports or boards include this by default; + check your board's documentation or build configuration. + +Port support +------------ + +The following ports support ROMFS. On these ports, if a ROMFS partition is +configured for the board, it will be automatically detected at boot time and +mounted at ``/rom`` in the VFS. Both ``/rom`` and ``/rom/lib`` are +automatically added to ``sys.path`` so that modules stored there can be +imported directly. + +============== ==================================================== +Port Notes +============== ==================================================== +alif Supported on boards with ROMFS partition configured. +esp32 Supported with custom partition table. +esp8266 Supported on 2MiB+ boards (ESP8266_GENERIC FLASH_2M_ROMFS variant). +mimxrt Supported on boards with ROMFS partition configured. +nrf Supported on boards with ROMFS partition configured. +qemu Supported (used for CI testing). +renesas-ra Supported on boards with ROMFS partition configured. +rp2 Supported on boards with ROMFS partition configured. +samd Supported on boards with ROMFS partition configured. +stm32 Supported on boards with ROMFS partition configured. +unix Supported (primarily for testing). +============== ==================================================== + +Enabling ROMFS for a port or board +---------------------------------- + +The ROMFS implementation is port specific at this time and requires too much detail to explain here. + +Workflow +-------- + +The typical workflow for using ROMFS is: + +1. Create a directory on your PC with the Python files (or ``.mpy`` files) + you want to deploy. +2. Use ``mpremote romfs deploy `` to build and deploy the ROMFS + image to the device. +3. The ROMFS will be mounted at ``/rom`` on next boot (or can be mounted + immediately if the device is soft-reset). +4. Python code on the device can then ``import`` modules from the ROMFS just + like from any other filesystem. + +For example, on the host PC, with a directory "myapp/" containing app.py:: + + $ mpremote romfs deploy myapp/ + +After a soft-reset, the device will have ``/rom/app.mpy`` available for import +(or ``/rom/app.py`` if ``mpy_cross`` is not installed). + +Alternatively, you can build the ROMFS image on the host PC first, then deploy +it to the device:: + + $ mpremote romfs build myapp + $ mpremote romfs deploy myapp.romfs + +See the :ref:`mpremote romfs commands ` section for +full details of the ``mpremote`` commands. + +Automatic mounting at boot +-------------------------- + +When ROMFS support is enabled in the firmware, MicroPython will automatically +attempt to mount the first ROM partition at ``/rom`` during initialisation +(after ``mp_init()``). If the partition contains a valid ROMFS image, it is +mounted and both ``/rom`` and ``/rom/lib`` are added to ``sys.path`` +automatically. + +This means that after deploying a ROMFS image with ``mpremote``, a soft-reset +is sufficient to make the new modules importable. + +If no valid ROMFS image is found in the partition (e.g. on a freshly-programmed +board), the mount is silently skipped. + +Using mpremote to manage ROMFS +------------------------------ + +The :ref:`mpremote ` ``romfs`` command can query ROMFS partitions, +build ROMFS images, and deploy images to a connected device. See +:ref:`mpremote ROMFS commands ` for command syntax, +options, and examples. + +ROMFS usage examples +-------------------- + +Deploying a simple application +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Suppose you have a project directory ``myapp/`` with the following structure:: + + ── myapp + ├── myapp.py + ├── utils.py + └── lib + └── helper.py + +To deploy it to the device's ROMFS:: + + $ mpremote romfs deploy myapp/ + $ mpremote tree + tree : + :/ + └── rom + ├── lib + │ └── helper.mpy + ├── myapp.mpy + └── utils.mpy + +After a soft-reset, the modules are importable from the ROMFS as its mount point +and lib folder have been added to ``sys.path``:: + + import myapp + import utils + import helper + +Listing ROMFS contents from Python +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After mounting, the ROMFS contents can be explored like any other +filesystem:: + + import os + + for entry in os.ilistdir('/rom'): + print(entry) + + # Or simply: + print(os.listdir('/rom')) + +Manually mount a second ROMFS image +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If there are multiple ROMFS partitions, it is possible to mount +a second ROMFS image from another partition on the device. +For example, if the second ROMFS partition is at index 2, you can +mount it using:: + + import vfs + dev = vfs.rom_ioctl(2, 1) # get second partition + vfs.mount(vfs.VfsRom(dev), "/rom2") + +Mount a ROMFS image stored in a file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +A ROMFS image stored as a file within a ROMFS can be mounted as a +nested filesystem without copying it into RAM. For example, if +``/rom/data.romfs`` exists, you can mount it using:: + + # boot.py + import vfs + with open('/rom/data.romfs', 'rb') as f: + fs = vfs.VfsRom(f) + vfs.mount(fs, '/data') + +Then after a soft-reset, the nested ROMFS is available at ``/data``:: + + $ mpremote tree + tree : + :/ + ├── boot.py + ├── data + │ └── facts.db + ├── main.py + └── rom + ├── data.romfs + ├── lib + │ └── helper.mpy + ├── myapp.mpy + └── utils.mpy + +ROMFS filesystem format +======================= +ROMFS is a flexible and extensible filesystem format designed to represent a +directory hierarchy with files, where those files are read-only and their data +can be memory mapped. + +Concepts: + +- ``varuint`` : An unsigned integer that is encoded in a variable number of bytes. + It is stored big-endian with the high bit of the byte set if there are following bytes. +- ``record`` : A variable sized element with a type. It is stored as two ``varuint``'s and then + a payload. The first ``varuint`` is the record kind and the second ``varuint`` is the + payload length (which may be zero bytes long). + +A ROMFS filesystem is a record with record kind 0x14a6b1, chosen so the encoded value +is ``0xd2-0xcd-0x31`` which is ``"RM1"`` with the first two bytes having their high bit set. +If the ROMFS record's payload is non-empty then it contains records. + +Record types: + +- ``0`` -- **unused**: Can be used to detect corruption of the filesystem. +- ``1`` -- **padding/comments**: Can contain any data in the payload. +- ``2`` -- **verbatim data**: Used to store file data. +- ``3`` -- **indirect data**: Points to an offset within the ROMFS payload. +- ``4`` -- **directory**: The payload contains a ``varuint`` giving the length of + the directory name in bytes, followed by the name and optional nested records + for the directory contents (including optional metadata). +- ``5`` -- **file**: The payload contains a ``varuint`` giving the length of the + filename in bytes, followed by the name and optional nested records. + +Unknown record types are silently skipped, providing forwards compatibility. + +This format is defined in ``extmod/vfs_rom.c`` in the MicroPython source. +The Python implementation used by ``mpremote`` to build images is in +``tools/mpremote/mpremote/romfs.py``. + +.. seealso:: + + - :ref:`filesystem` -- Overview of the MicroPython VFS and available + filesystem types. + - :ref:`manifest` -- How to freeze Python modules into firmware. + - :ref:`mpy_files` -- MicroPython ``.mpy`` binary file format. + - :ref:`mpremote` -- The full ``mpremote`` command reference. diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index 6382394bd50..b3357066175 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -182,9 +182,13 @@ The const() declaration MicroPython provides a ``const()`` declaration. This works in a similar way to ``#define`` in C in that when the code is compiled to bytecode the compiler -substitutes the numeric value for the identifier. This avoids a dictionary +substitutes the constant value for the identifier. This avoids a dictionary lookup at runtime. The argument to ``const()`` may be anything which, at -compile time, evaluates to an integer e.g. ``0x100`` or ``1 << 8``. +compile time, evaluates to a constant e.g. ``0x100``, ``1 << 8``, +``"string"``, ``0.001``, ``b"\x00\xff"`` or ``("read", "write")``. + +See :func:`micropython.const` for complete documentation including usage +requirements, limitations, and examples. .. _Caching: diff --git a/docs/reference/unicode_support.rst b/docs/reference/unicode_support.rst new file mode 100644 index 00000000000..602bedbf78c --- /dev/null +++ b/docs/reference/unicode_support.rst @@ -0,0 +1,226 @@ +.. _unicode_support: + +Unicode Support +=============== + +MicroPython provides Unicode support for strings. All Tier 1, 2 and 3 ports +have Unicode support enabled by default, but it is possible to change that with +a different build configuration. + +Terminology +----------- + +This document uses the following Unicode terms: + +- **Code point**: a single Unicode value in the range U+0000 to U+10FFFF, for + example U+0041 ``A`` or U+1F600 😀. MicroPython strings are sequences of + code points. +- **Character**: informally used to mean a code point. Be aware that a + user-perceived character (a *grapheme*) may consist of several code points, + such as a base letter followed by combining marks. +- **Byte**: a single 8-bit value. In UTF-8 each code point is stored as one to + four bytes (see below). + +Operations such as ``len()``, indexing and slicing act on code points, not on +graphemes or display width, so a base letter followed by a combining mark counts +as two code points. + +Character Encoding +------------------ + +MicroPython uses UTF-8 encoding for all strings. When Unicode support is enabled +(``MICROPY_PY_BUILTINS_STR_UNICODE``), strings can contain any valid Unicode code +point from U+0000 to U+10FFFF. + +ASCII characters (0-127) are stored in a single byte, making them as memory-efficient +as on systems without Unicode support. Multi-byte UTF-8 code points use 2-4 bytes +depending on the code point: + +- U+0000 to U+007F: 1 byte (ASCII) +- U+0080 to U+07FF: 2 bytes +- U+0800 to U+FFFF: 3 bytes +- U+10000 to U+10FFFF: 4 bytes + +Encoding and Decoding +---------------------- + +The :meth:`bytes.decode` and :meth:`str.encode` methods support the following encodings: + +- UTF-8 (``'utf-8'`` or ``'utf8'``) +- ASCII (``'ascii'``) + +Other encodings (such as ``'latin-1'``, ``'utf-16'``, etc.) are not supported +and will raise ``LookupError``. The encoding argument must also match one of the +supported strings exactly (for example, ``'utf8'`` is valid but ``'UTF8'`` +is not). `More details `. + +Example:: + + >>> '日本語'.encode('utf-8') + b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e' + >>> b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e'.decode('utf-8') + '日本語' + +Error Handling +~~~~~~~~~~~~~~ + +When decoding bytes that contain invalid UTF-8 sequences, the ``errors`` parameter +of :meth:`bytes.decode` controls the behavior: + +- ``'strict'`` (default): Raise ``UnicodeError`` +- ``'ignore'``: Skip invalid bytes (requires ``MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS``) +- ``'replace'``: Replace invalid bytes with U+FFFD � (requires ``MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS``) + +Example:: + + >>> # Strict mode (default) raises an error + >>> b'hello\xffworld'.decode('utf-8') + UnicodeError: invalid UTF-8 + + >>> # Ignore mode skips invalid bytes + >>> b'hello\xffworld'.decode('utf-8', 'ignore') + 'helloworld' + + >>> # Replace mode substitutes replacement character + >>> b'hello\xffworld'.decode('utf-8', 'replace') + 'hello�world' + +For memory-conscious applications, consider using ``'ignore'`` mode when processing +untrusted or partially corrupted data, as it avoids raising exceptions while still +recovering valid text. + +The same ``errors`` handling applies when decoding any bytes-like object, including +via the ``str()`` constructor (for example ``str(buf, 'utf-8', 'replace')`` where +``buf`` is a ``bytes``, ``bytearray``, ``memoryview`` or ``array`` object). + +Encoding to Bytes +~~~~~~~~~~~~~~~~~ + +Function ``str.encode()`` and the ``bytes()`` constructor accept an ``encoding`` +argument which can be ``'utf8'``, ``'utf-8'`` or ``'ascii'``:: + + >>> "abc".encode("ascii") + b'abc' + +If encoding ``'ascii'`` is specified then an exception is raised if the string +contains non-ASCII characters. + +The ``'ignore'`` and ``'replace'`` ``errors`` values are not supported in these +conversions from string to bytes and `any errors argument is ignored +`. + +String Methods +-------------- + +When Unicode support is enabled, string methods operate on code points rather than bytes: + +- :meth:`str.center` - Counts code points for width calculation +- ``len(s)`` - Returns number of code points (not bytes) +- String indexing and slicing work on code-point boundaries +- No support for display width calculations (East Asian width, combining characters, etc.) + +Example:: + + >>> s = 'Hello 世界' + >>> len(s) # 8 code points + 8 + >>> len(s.encode()) # 12 bytes + 12 + >>> s.center(12) # Centered by code-point count + ' Hello 世界 ' + +String Formatting +----------------- + +The ``%c`` format specifier and ``{:c}`` format code support full Unicode: + +- Accepts code points from 0 to 0x10FFFF +- Properly encodes multi-byte UTF-8 code points +- Raises ``ValueError`` for invalid code points + +Example:: + + >>> '%c' % 65 # ASCII + 'A' + >>> '%c' % 0x03B1 # Greek α + 'α' + >>> '%c' % 0x1F600 # Emoji 😀 + '😀' + >>> '{:c}'.format(0x4E2D) # Chinese 中 + '中' + + >>> # Invalid code point + >>> '%c' % 0x110000 + ValueError: %c arg not in range(0x110000) + +F-strings also support the ``:c`` format code:: + + >>> code_point = 0x2665 # Heart suit ♥ + >>> f'I {code_point:c} Python' + 'I ♥ Python' + +Build Configuration +------------------- + +Unicode features are controlled by several build-time flags in ``mpconfigport.h``: + +``MICROPY_PY_BUILTINS_STR_UNICODE`` + Enable Unicode string support. When enabled, strings can contain any valid + Unicode character and string operations work on character boundaries rather + than byte boundaries. + + Default: Enabled at ``MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES`` and above. + + Enabled on all Tier 1, 2 and 3 ports. + +``MICROPY_PY_BUILTINS_STR_UNICODE_CHECK`` + Enable UTF-8 validation during string operations. When disabled, string + operations may produce incorrect results with invalid UTF-8 sequences. + + Default: Follows ``MICROPY_PY_BUILTINS_STR_UNICODE`` setting. + + Enabled on all Tier 1, 2 and 3 ports. + +``MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS`` + Enable the ``'ignore'`` and ``'replace'`` error handlers for + :meth:`bytes.decode`. When enabled, invalid UTF-8 bytes can be either + skipped (``'ignore'``) or replaced with U+FFFD (``'replace'``). + + Default: Enabled at ``MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES`` and above. + + Enabled on alif, esp32, esp8266, mimxrt, renesas-ra, rp2, samd (SAMD51 only), + stm32, unix and webassembly ports. + +Example Configuration +~~~~~~~~~~~~~~~~~~~~~ + +For a constrained port with limited flash, disable error handlers:: + + #define MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS (0) + +For a port with more resources, enable all Unicode features:: + + #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) + // This automatically enables: + // - MICROPY_PY_BUILTINS_STR_UNICODE + // - MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS + +Limitations +----------- + +MicroPython's Unicode support has some limitations compared to CPython: + +- Only UTF-8 and ASCII encodings are supported +- No support for Unicode normalization +- No locale-aware string operations +- The ``errors`` parameter accepts only positional arguments (not keyword arguments) +- String methods like ``upper()``, ``lower()``, etc. work correctly only for ASCII +- The MicroPython interactive REPL and ``input()`` function currently have limited + Unicode support. The line editor is unaware of the displayed width of characters: + wide characters (for example many CJK characters) take two terminal columns, while a + grapheme cluster (a base code point plus combining marks, or an emoji sequence) can + span several code points yet occupy a single column. Because editing tracks code + points rather than displayed columns, line-editing keys such as backspace and the + left/right arrows may leave the cursor misaligned with the text shown on screen. + A workaround is to place the Unicode text in a UTF-8 encoded MicroPython script and + run it using ``mpremote run ``. diff --git a/docs/rp2/general.rst b/docs/rp2/general.rst index 05b44f051ee..c63560bae38 100644 --- a/docs/rp2/general.rst +++ b/docs/rp2/general.rst @@ -4,17 +4,18 @@ General information about the RP2xxx port ========================================= The rp2 port supports boards powered by the Raspberry Pi Foundation's RP2xxx -family of microcontrollers, most notably the Raspberry Pi Pico that employs -the RP2040. +family of microcontrollers, including the RP2040 and RP2350. Technical specifications and SoC datasheets ------------------------------------------- -For detailed technical specifications, please refer to the `datasheets -`_ +RP2040 +^^^^^^ The RP2040 microcontroller is manufactured on a 40 nm silicon process in a 7x7mm -QFN-56 SMD package. The key features include: +QFN-56 SMD package. + +The key features include: * 133 MHz dual ARM Cortex-M0+ cores (overclockable to over 400 MHz) * 264KB SRAM in six independent banks @@ -34,3 +35,32 @@ The peripherals include: * 16 PWM channels * USB 1.1 controller * 8 PIO state machines + +For detailed technical specifications, please refer to the `rp2040-datasheet +`_ + +RP2350 +^^^^^^ + +The RP2350 microcontroller is manufactured on a 40 nm silicon process and is available in +QFN-60 (RP2350A) or QFN-80 (RP2350B) packages. + +The key features include: + +* Dual-core Arm Cortex-M33 or Hazard3 RISC-V processors at up to 150MHz +* 520KB on-chip SRAM +* Support for up to 16MB of off-chip Flash memory via QSPI +* USB 2.0 Full-Speed/Low-Speed controller +* 30 GPIO pins (RP2350A) or 48 GPIO pins (RP2350B) + +The peripherals include: + +* 2 UARTs +* 2 SPI controllers +* 2 I2C controllers +* 24 PWM channels +* 12 PIO state machines +* HSTX high-speed transmitter + +For detailed technical specifications, please refer to the `rp2350-datasheet +`_ diff --git a/docs/rp2/quickref.rst b/docs/rp2/quickref.rst index ec31442990f..8e0f6d6bae7 100644 --- a/docs/rp2/quickref.rst +++ b/docs/rp2/quickref.rst @@ -207,10 +207,26 @@ See :ref:`machine.UART `. :: uart1.write('hello') # write 5 bytes uart1.read(5) # read up to 5 bytes -.. note:: +It is possible to access the REPL over UART, but this is disabled by +default. To duplicate the REPL stream over UART, use :func:`os.dupterm`. +This code should be in :ref:`boot.py` or :ref:`main.py` to establish UART on boot. + +.. code-block:: python + + from machine import UART + import os + uart = UART(0) + os.dupterm(uart, 0) + uart.irq(os.dupterm_notify, UART.IRQ_RXIDLE) # ensure inputs are handled + +To use UART for REPL instead of the standard USB interface (for example if you are +using :mod:`machine.USBDevice`), you will need to :doc:`build MicroPython from source `. +Modify ``ports/rp2/mpconfigport.h``, and change the ``MICROPY_HW_ENABLE_UART_REPL`` +variable to ``1``: + +.. code-block:: c - REPL over UART is disabled by default. You can see the :ref:`rp2_intro` for - details on how to enable REPL over UART. + #define MICROPY_HW_ENABLE_UART_REPL (1) // useful if there is no USB PWM (pulse width modulation) @@ -226,7 +242,7 @@ are at slice 1, and so on. A certain channel can be assigned to different GPIO pins (see Pinout). For instance slice 0, channel A can be assigned to both GPIO0 and GPIO16. -Use the ``machine.PWM`` class:: +Use the :ref:`machine.PWM ` class:: from machine import Pin, PWM @@ -336,7 +352,7 @@ has the same methods as software I2C above:: from machine import Pin, I2C - i2c = I2C(0) # default assignment: scl=Pin(9), sda=Pin(8) + i2c = I2C(0) # default assignment for Pico: scl=Pin(5), sda=Pin(4) i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=400_000) I2S bus diff --git a/docs/rp2/tutorial/pio.rst b/docs/rp2/tutorial/pio.rst index 4e519650eea..65b7cd97637 100644 --- a/docs/rp2/tutorial/pio.rst +++ b/docs/rp2/tutorial/pio.rst @@ -1,21 +1,57 @@ Programmable IO =============== -The RP2040 has hardware support for standard communication protocols like I2C, -SPI and UART. For protocols where there is no hardware support, or where there -is a requirement of custom I/O behaviour, Programmable Input Output (PIO) comes -into play. Also, some MicroPython applications make use of a technique called -bit banging in which pins are rapidly turned on and off to transmit data. This -can make the entire process slow as the processor concentrates on bit banging -rather than executing other logic. However, PIO allows bit banging to happen -in the background while the CPU is executing the main work. - -Along with the two central Cortex-M0+ processing cores, the RP2040 has two PIO -blocks each of which has four independent state machines. These state machines -can transfer data to/from other entities using First-In-First-Out (FIFO) buffers, -which allow the state machine and main processor to work independently yet also -synchronise their data. Each FIFO has four words (each of 32 bits) which can be -linked to the DMA to transfer larger amounts of data. +The RP2xxx family of microcontrollers provides hardware support for standard +communication protocols like I2C, SPI and UART. For protocols where there +is no hardware support, or where there is a requirement of custom I/O +behaviour, Programmable Input Output (PIO) comes into play. Also, some +MicroPython applications make use of a technique called bit banging in which +pins are rapidly turned on and off to transmit data. This can make the entire +process slow as the processor concentrates on bit banging rather than executing +other logic. However, PIO allows bit banging to happen in the background while +the CPU is executing the main work. + +PIO State Machines +------------------ + +State machines transfer data to/from other entities using First-In-First-Out (FIFO) +buffers, which allow the state machine and main processor to work independently +yet also synchronise their data. The FIFOs can be linked to the DMA to transfer +larger amounts of data without extensive CPU usage. + + +**RP2040** +^^^^^^^^^^ + +The RP2040 has two PIO blocks, each with four independent state machines (total of 8). + +Each FIFO has four words (each of 32 bits) per state machine (TX and RX). + +**RP2350** +^^^^^^^^^^ + +The RP2350 has three PIO blocks, each with four independent state machines (total of 12). + +Similar to the RP2040, each state machine has a four-word FIFO per state machine (TX and RX), +but they have some additional functions + +For each state machine: + +- TX or RX FIFOs can be combined into a single 8-word FIFO for higher bandwidth. +- The RX FIFO supports random read/write access to its registers. + +**Compatibility** +^^^^^^^^^^^^^^^^^ + +RP2350 PIO is backward-compatible with RP2040, with some additional enhancements. + +At the moment, native support for RP2350 PIO enhancements is very limited, +but work for some features are already in progress + +Instructions +------------ + +Each PIO block has 32 instructions of memory shared among its four state machines. All PIO instructions follow a common pattern:: @@ -124,3 +160,18 @@ the following: The entire routine takes exactly 2000 cycles of the state machine. Setting the frequency of the state machine to 2000Hz makes the LED blink at 1Hz. + +This example works identically on both RP2040 and RP2350 (using StateMachine ID 0). On +RP2350, higher ``freq`` values are possible due to the faster system clock. + +Compatibility Notes +------------------- + +PIO programs using the basic instructions shown here are fully compatible between RP2040 +and RP2350. The MicroPython ``rp2`` module API (including ``@rp2.asm_pio``, +``StateMachine``, etc.) is the same, though RP2350 supports StateMachine IDs 0–11. + +RP2350 offers additional advanced features (new instructions, FIFO modes, security, GPIO +relocation) not covered in this introduction; see the RP2350 datasheet for details. Some +programs may require minor adjustments due to differences in default GPIO reset states +between the two chips. diff --git a/docs/samd/quickref.rst b/docs/samd/quickref.rst index 781686d2f60..31a91640a5d 100644 --- a/docs/samd/quickref.rst +++ b/docs/samd/quickref.rst @@ -261,30 +261,40 @@ an external ADC. ADC Constructor ``````````````` -.. class:: ADC(dest, *, average=16, vref=n) +.. class:: ADC(dest, *, average=16, bits=12, vref=ADC.AREF, callback=None) :noindex: -Construct and return a new ADC object using the following parameters: - - - *dest* is the Pin object on which the ADC is output. - -Keyword arguments: +On the SAMD21/SAMD51 ADC functionality is available on Pins labelled 'Ann'. - - *average* is used to reduce the noise. With a value of 16 the LSB noise is about 1 digit. - - *vref* sets the reference voltage for the ADC. +Use the :ref:`machine.ADC ` class:: - The default setting is for 3.3V. Other values are: + from machine import ADC - ==== ============================== =============================== - vref SAMD21 SAMD51 - ==== ============================== =============================== - 0 1.0V voltage reference internal bandgap reference (1V) - 1 1/1.48 Analogue voltage supply Analogue voltage supply - 2 1/2 Analogue voltage supply 1/2 Analogue voltage supply - 3 External reference A External reference A - 4 External reference B External reference B - 5 - External reference C - ==== ============================== =============================== + adc0 = ADC(Pin("A0")) # create ADC object on ADC pin, average=16 + adc0.read_u16() # read value, 0-65536 across voltage range 0.0v - 3.3v + adc1 = ADC(Pin("A1"), average=1) # create ADC object on ADC pin, average=1 + +The resolution of the ADC is set by the bits keyword option. The default is 12. +Suitable values are 8, 10 and 12. If you need a higher resolution or better +accuracy, use an external ADC. The default value of average is 16. +Averaging is used to reduce the noise. With a value of 16 the LSB noise is +about 1 digit. When averaging is enabled, the resolution is forced to +12 bits. The vref=n option sets the reference voltage for the ADC. +The default setting is for 3.3V. Other values are: + +========= ===== ============================== ============================= +Symbol Value SAMD21 SAMD51 +========= ===== ============================== ============================= +INT_VREF 0 1.0V voltage reference 1V internal bandgap reference +VDDA 1 1/1.48 Analogue voltage supply Analogue voltage supply +VDDA2 2 1/2 Analogue voltage supply 1/2 Analogue voltage supply +AREF 3 External reference A (PA03) External reference A (PA03) +AREFB 4 External reference B (PA04) External reference B (PA04) +AREFC 5 External reference C (PA06) +========= ===== ============================== ============================= + +The callback keyword option is used for timed ADC sampling. The callback is executed +when all data has been sampled. ADC Methods ``````````` @@ -294,38 +304,78 @@ ADC Methods Read a single ADC value as unsigned 16 bit quantity. The voltage range is defined by the vref option of the constructor, the resolutions by the bits option. -DAC (digital to analog conversion) ----------------------------------- +.. method:: read_timed(data, freq) -The DAC class provides a fast digital to analog conversion. Usage example:: +Read ADC values into the data buffer at a supplied frequency. The buffer +must be preallocated. Values are stored as 16 bit quantities in the binary +range given by the bits option. If bits=12, the value range is 0-4095. +The voltage range is defined by the vref option. +The sampling frequency range depends on the bits and average setting. At bits=8 +and average=1, the largest rate is >1 MHz for SAMD51 and 350kHz for SAMD21. +the lowest sampling rate is 1 Hz. The call to the method returns immediately, +The data transfer is done by DMA in the background, controlled by a hardware timer. +If in the constructor a callback was defined, it will be called after all data has been +read. Alternatively, the method busy() can be used to tell, if the capture has finished. - from machine import DAC +Example for a call to adc.read_timed() and a callback:: - dac0 = DAC(0) # create DAC object on DAC pin A0 - dac0.write(1023) # write value, 0-4095 across voltage range 0.0v - 3.3v - dac1 = DAC(1) # create DAC object on DAC pin A1 - dac1.write(2000) # write value, 0-4095 across voltage range 0.0v - 3.3v + from machine import ADC + from array import array -The resolution of the DAC is 12 bit for SAMD51 and 10 bit for SAMD21. SAMD21 devices -have 1 DAC channel at GPIO PA02, SAMD51 devices have 2 DAC channels at GPIO PA02 and PA05. + def finished(adc_o): + print("Sampling finished on ADC", adc_o) + + # create ADC object on ADC pin A0, average=1 + adc = ADC(Pin("A0"), average=1, callback=finished) + buffer = array("H", bytearray(512)) # create an array for 256 ADC values + adc.read_timed(buffer, 10000) # read 256 12 bit values at a frequency of + # 10 kHz and call finished() when done. + +.. method:: busy() + +busy() returns `True` while the data acquisition using read_timed() is ongoing, `False` +otherwise. + +.. method deinit() + +Deinitialize an ADC object and release the resources used by it, especially the ADC +channel and the timer used for read_timed(). + + +DAC (digital to analogue conversion) +------------------------------------ DAC Constructor ``````````````` -.. class:: DAC(id, *, vref=3) +.. class:: DAC(id, *, vref=3, callback=None) :noindex: + +The DAC class provides a fast digital to analogue conversion. Usage example:: + + from machine import DAC + + dac0 = DAC(0) # create DAC object on DAC pin A0 + dac0.write(1023) # write value, 0-4095 across voltage range 0.0V - 3.3V + dac1 = DAC(1) # create DAC object on DAC pin A1 + dac1.write(2000) # write value, 0-4095 across voltage range 0.0V - 3.3V + +The resolution of the DAC is 12 bit for SAMD51 and 10 bit for SAMD21. SAMD21 devices +have 1 DAC channel at GPIO PA02, accepting only 0 as id. SAMD51 devices have +2 DAC channels at GPIO PA02 and PA05 with values 0 and 1 for the id. The vref arguments defines the output voltage range, the callback option is used for dac_timed(). Suitable values for vref are: -==== ============================ ================================ -vref SAMD21 SAMD51 -==== ============================ ================================ -0 Internal voltage reference Internal bandgap reference (~1V) -1 Analogue voltage supply Analogue voltage supply -2 External reference Unbuffered external reference -3 - Buffered external reference -==== ============================ ================================ +========= ===== ============================ ================================ +Symbol Value SAMD21 SAMD51 +========= ===== ============================ ================================ +INT_VREF 0 Internal voltage reference Internal bandgap reference (~1V) +VDDA 1 Analogue voltage supply Analogue voltage supply +AREF 2 External reference Unbuffered external reference +AREFB 3 Buffered external reference +========= ===== ============================ ================================ + DAC Methods ``````````` @@ -335,6 +385,52 @@ DAC Methods Write a single value to the selected DAC output. The value range is 0-1023 for SAMD21 and 0-4095 for SAMD51. The voltage range depends on the vref setting. +.. method:: write_timed(data, freq [, count=1]) + +The call to dac_timed() allows to output a series of analogue values at a given rate. +data must be a buffer with 16 bit values in the range of the DAC (10 bit of 12 bit). +freq may have a range of 1Hz to ~200kHz for SAMD21 and 1 Hz to ~500kHz for SAMD51. +The optional argument count specifies, how often data output will be repeated. The +range is 1 - (2**32 - 1). If count == 0, the data output will be repeated until stopped +by a call to deinit(). If the data has been output count times, a callback will +be called, if given. + +Example:: + + from machine import DAC + from array import array + + data = array("H", [i for i in range(0, 4096, 256)]) # create a step sequence + + def done(dac_o): + print("Sequence done at", dac_o) + + dac = DAC(0, callback=done) + dac.write_timed(data, 1000, 10) # output data 10 times at a rate of 1000 values/s + # and call done() when finished. + +The data transfer is done by DMA and not affected by python code execution. +It is possible to restart dac.write_timed() in the callback function with changed +parameters. + + +.. method:: busy() + :noindex: + +Tell, whether a write_timed() activity is ongoing. It returns `True` if yes, `False` +otherwise. + + +.. method:: deinit() + +Deinitialize the DAC and release the resources used by it, especially the DMA channel +and the Timer. On most SAMD21 boards, there is just one timer available for +dac.write_timed() and adc.read_timed(). So they cannot run both at the same time, +and releasing the timer may be important. The DAC driver consumes a substantial amount +of current. deinit() will reduce that as well. After calling deinit(), the +DAC objects cannot be used any more and must be recreated. + + Software SPI bus ---------------- diff --git a/docs/templates/topindex.html b/docs/templates/topindex.html index e3bcd7cce14..344b971ea79 100644 --- a/docs/templates/topindex.html +++ b/docs/templates/topindex.html @@ -57,6 +57,10 @@

MicroPython documentation

Quick reference for the ESP32
pinout for ESP32-based boards, snippets of useful code, and a tutorial

+