diff --git a/.github/workflows/biome.yml b/.github/workflows/biome.yml index fea9c9c8bd7bc..0cde10acc9182 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@v5 + uses: actions/checkout@v6 - name: Setup Biome uses: biomejs/setup-biome@v2 with: diff --git a/.github/workflows/code_formatting.yml b/.github/workflows/code_formatting.yml index 8a18ca034540c..95653d941f91f 100644 --- a/.github/workflows/code_formatting.yml +++ b/.github/workflows/code_formatting.yml @@ -10,7 +10,7 @@ jobs: code-formatting: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 - name: Install packages run: tools/ci.sh c_code_formatting_setup diff --git a/.github/workflows/code_size.yml b/.github/workflows/code_size.yml index f82d1d0c73567..cf6838b7ae1d3 100644 --- a/.github/workflows/code_size.yml +++ b/.github/workflows/code_size.yml @@ -10,6 +10,7 @@ on: - 'shared/**' - 'lib/**' - 'ports/bare-arm/**' + - 'ports/esp32/**' - 'ports/mimxrt/**' - 'ports/minimal/**' - 'ports/rp2/**' @@ -23,13 +24,37 @@ concurrency: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 100 - name: Install packages run: tools/ci.sh code_size_setup + + # Needs to be kept in synch with ports_esp32.yml + - id: idf_ver + name: Read the ESP-IDF version (including Python version) and set outputs.IDF_VER + run: tools/ci.sh esp32_idf_ver | tee "${GITHUB_OUTPUT}" + - name: Cached ESP-IDF install + id: cache_esp_idf + uses: actions/cache@v5 + with: + path: | + ./esp-idf/ + ~/.espressif/ + !~/.espressif/dist/ + ~/.cache/pip/ + key: esp-idf-${{ steps.idf_ver.outputs.IDF_VER }} + - name: Install ESP-IDF packages + if: steps.cache_esp_idf.outputs.cache-hit != 'true' + run: tools/ci.sh esp32_idf_setup + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: code_size + - name: Build run: tools/ci.sh code_size_build - name: Compute code size difference @@ -41,7 +66,7 @@ jobs: run: echo $PR_NUMBER > pr_number - name: Upload diff if: github.event_name == 'pull_request' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: code-size-report path: | diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 688134b42515c..e3a9c79bd5e78 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -6,8 +6,13 @@ jobs: codespell: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 # codespell version should be kept in sync with .pre-commit-config.yml - run: pip install --user codespell==2.4.1 tomli - run: codespell - + # additionally check for misspelling of "MicroPython" + - run: | + if git grep -n Micropython -- ":(exclude).github/workflows/codespell.yml"; then + echo "Please correct capitalisation of MicroPython on the above lines" + exit 1 + fi diff --git a/.github/workflows/commit_formatting.yml b/.github/workflows/commit_formatting.yml index ca63fc796b0cc..6abc3612a0004 100644 --- a/.github/workflows/commit_formatting.yml +++ b/.github/workflows/commit_formatting.yml @@ -10,7 +10,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 100 - uses: actions/setup-python@v6 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index aa05cfb13873b..79755b741973f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 - name: Install Python packages run: pip install -r docs/requirements.txt diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index d16122b720b6c..4627247fb9f2a 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -18,8 +18,6 @@ jobs: embedding: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Build - run: make -C examples/embedding -f micropython_embed.mk && make -C examples/embedding - - name: Run - run: ./examples/embedding/embed | grep "hello world" + run: tools/ci.sh embedding_build diff --git a/.github/workflows/mpremote.yml b/.github/workflows/mpremote.yml index 36904764c991b..25cf56d587d5b 100644 --- a/.github/workflows/mpremote.yml +++ b/.github/workflows/mpremote.yml @@ -11,7 +11,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: # Setting this to zero means fetch all history and tags, # which hatch-vcs can use to discover the version tag. @@ -22,7 +22,7 @@ jobs: - name: Build mpremote wheel run: cd tools/mpremote && python -m build --wheel - name: Archive mpremote wheel - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: mpremote path: | diff --git a/.github/workflows/mpy_format.yml b/.github/workflows/mpy_format.yml index e692a853e7b2c..ab668c1cb5ea0 100644 --- a/.github/workflows/mpy_format.yml +++ b/.github/workflows/mpy_format.yml @@ -6,6 +6,8 @@ on: paths: - '.github/workflows/*.yml' - 'examples/**' + - 'mpy-cross/**' + - 'py/**' - 'tests/**' - 'tools/**' @@ -17,8 +19,10 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install packages run: tools/ci.sh mpy_format_setup - name: Test mpy-tool.py run: tools/ci.sh mpy_format_test + - name: Test mpy-cross debug emitter + run: tools/ci.sh mpy_cross_debug_emitter diff --git a/.github/workflows/ports.yml b/.github/workflows/ports.yml index d4e89bd1aa924..5e71d4d076ae3 100644 --- a/.github/workflows/ports.yml +++ b/.github/workflows/ports.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - 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 eea8f53900ebc..6fb225937a90d 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@v5 + - uses: actions/checkout@v6 - 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 c57309c23a6d0..194483ec218d1 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@v5 + - uses: actions/checkout@v6 - 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 578bf33af5b58..87ab6dbe35543 100644 --- a/.github/workflows/ports_esp32.yml +++ b/.github/workflows/ports_esp32.yml @@ -30,17 +30,19 @@ jobs: - esp32_build_cmod_spiram_s2 - esp32_build_s3_c3 - esp32_build_c2_c5_c6 + - esp32_build_p4 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + # Needs to be kept in synch with code_size.yml - id: idf_ver - name: Read the ESP-IDF version (including Python version) - run: source tools/ci.sh && echo "IDF_VER=${IDF_VER}-py${PYTHON_VER}" | tee "$GITHUB_OUTPUT" + name: Read the ESP-IDF version (including Python version) and set outputs.IDF_VER + run: tools/ci.sh esp32_idf_ver | tee "${GITHUB_OUTPUT}" - name: Cached ESP-IDF install id: cache_esp_idf - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ./esp-idf/ @@ -53,6 +55,7 @@ jobs: if: steps.cache_esp_idf.outputs.cache-hit != 'true' run: tools/ci.sh esp32_idf_setup + # Needs to be kept in synch with code_size.yml - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: diff --git a/.github/workflows/ports_esp8266.yml b/.github/workflows/ports_esp8266.yml index 96cf0c5a5cd3f..eb7f59cdc4900 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@v5 + - uses: actions/checkout@v6 - 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 bcbaf3de066c9..fd80f3f632925 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@v5 + - uses: actions/checkout@v6 with: path: 'micropython repo' - name: Install packages diff --git a/.github/workflows/ports_nrf.yml b/.github/workflows/ports_nrf.yml index 995f65933e0b0..bec9a5dfb5b8f 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@v5 + - uses: actions/checkout@v6 - name: Install packages run: tools/ci.sh nrf_setup - name: Build diff --git a/.github/workflows/ports_powerpc.yml b/.github/workflows/ports_powerpc.yml index 27417fb3c3cf2..a883d026806b5 100644 --- a/.github/workflows/ports_powerpc.yml +++ b/.github/workflows/ports_powerpc.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install packages run: tools/ci.sh powerpc_setup - name: Build diff --git a/.github/workflows/ports_qemu.yml b/.github/workflows/ports_qemu.yml index b038b03e71fed..0ed95dbe5f93a 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@v5 + - uses: actions/checkout@v6 - 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@v5 + - uses: actions/checkout@v6 - 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@v5 + - uses: actions/checkout@v6 - name: Install packages run: tools/ci.sh qemu_setup_rv64 - name: Build and run test suite diff --git a/.github/workflows/ports_renesas-ra.yml b/.github/workflows/ports_renesas-ra.yml index 600b8ea8046bd..920691eca70e1 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@v5 + - uses: actions/checkout@v6 - 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 0837c06c97bd4..ea19e2da7ffc9 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@v5 + - uses: actions/checkout@v6 with: path: 'micropython repo' - name: Install packages diff --git a/.github/workflows/ports_samd.yml b/.github/workflows/ports_samd.yml index d159fde175d54..eb806ceb04400 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@v5 + - uses: actions/checkout@v6 - 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 eae3bae871f45..2ed730eb4e8d0 100644 --- a/.github/workflows/ports_stm32.yml +++ b/.github/workflows/ports_stm32.yml @@ -28,9 +28,9 @@ jobs: - stm32_misc_build runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install packages - run: tools/ci.sh stm32_setup + run: tools/ci.sh stm32_setup && tools/ci.sh stm32_path >> $GITHUB_PATH - name: Build ci_${{matrix.ci_func }} run: tools/ci.sh ${{ matrix.ci_func }} diff --git a/.github/workflows/ports_unix.yml b/.github/workflows/ports_unix.yml index deee7b265fcb7..bd04163ded8f5 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@v5 + - uses: actions/checkout@v6 - 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@v5 + - uses: actions/checkout@v6 - 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@v5 + - uses: actions/checkout@v6 - 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@v5 + - uses: actions/checkout@v6 - name: Build run: tools/ci.sh unix_standard_v2_build - name: Run main test suite @@ -70,7 +70,7 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 # 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. @@ -103,9 +103,14 @@ jobs: run: tests/run-tests.py --print-failures coverage_32bit: - runs-on: ubuntu-22.04 # use 22.04 to get libffi-dev:i386 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + # 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_32bit_setup - name: Build @@ -121,9 +126,14 @@ jobs: run: tests/run-tests.py --print-failures nanbox: - runs-on: ubuntu-22.04 # use 22.04 to get libffi-dev:i386 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + # 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_32bit_setup - name: Build @@ -135,9 +145,14 @@ jobs: run: tests/run-tests.py --print-failures longlong: - runs-on: ubuntu-22.04 # use 22.04 to get libffi-dev:i386 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + # 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_32bit_setup - name: Build @@ -151,7 +166,7 @@ jobs: float: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Build run: tools/ci.sh unix_float_build - name: Run main test suite @@ -163,7 +178,7 @@ jobs: gil_enabled: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Build run: tools/ci.sh unix_gil_enabled_build - name: Run main test suite @@ -175,7 +190,7 @@ jobs: stackless_clang: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install packages run: tools/ci.sh unix_clang_setup - name: Build @@ -189,7 +204,7 @@ jobs: float_clang: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install packages run: tools/ci.sh unix_clang_setup - name: Build @@ -203,7 +218,7 @@ jobs: settrace_stackless: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 # 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. @@ -218,9 +233,14 @@ jobs: run: tests/run-tests.py --print-failures repr_b: - runs-on: ubuntu-22.04 # use 22.04 to get libffi-dev:i386 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + # 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_32bit_setup - name: Build @@ -234,7 +254,7 @@ jobs: macos: runs-on: macos-26 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: '3.8' @@ -247,10 +267,14 @@ jobs: run: tests/run-tests.py --print-failures qemu_mips: - # ubuntu-22.04 is needed for older libffi. - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + # 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_mips_setup - name: Build @@ -262,10 +286,14 @@ jobs: run: tests/run-tests.py --print-failures qemu_arm: - # ubuntu-22.04 is needed for older libffi. - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + # 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_arm_setup - name: Build @@ -277,10 +305,14 @@ jobs: run: tests/run-tests.py --print-failures qemu_riscv64: - # ubuntu-22.04 is needed for older libffi. - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + # 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_riscv64_setup - name: Build @@ -294,7 +326,7 @@ jobs: sanitize_address: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 # 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. @@ -319,7 +351,7 @@ jobs: sanitize_undefined: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 # 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. diff --git a/.github/workflows/ports_webassembly.yml b/.github/workflows/ports_webassembly.yml index 6bfbb5aec6c8e..f6619cc8976df 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@v5 + - uses: actions/checkout@v6 - 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 e4e0152d3e9da..5318a85198153 100644 --- a/.github/workflows/ports_windows.yml +++ b/.github/workflows/ports_windows.yml @@ -45,6 +45,12 @@ jobs: env: CI_BUILD_CONFIGURATION: ${{ matrix.configuration }} steps: + - 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 + with: + python-version: '3.11' - name: Install Visual Studio ${{ matrix.visualstudio }} if: matrix.custom_vs_install shell: bash @@ -59,7 +65,7 @@ jobs: - uses: microsoft/setup-msbuild@v2 with: vs-version: ${{ matrix.vs_version }} - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Build mpy-cross.exe run: msbuild mpy-cross\mpy-cross.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }} - name: Update submodules @@ -126,7 +132,7 @@ jobs: git diffutils path-type: inherit # Remove when setup-python is removed - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Build mpy-cross.exe run: make -C mpy-cross -j2 - name: Update submodules @@ -144,7 +150,7 @@ jobs: cross-build-on-linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - 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 3579f4e1bc90c..571a443e903f8 100644 --- a/.github/workflows/ports_zephyr.yml +++ b/.github/workflows/ports_zephyr.yml @@ -37,13 +37,13 @@ jobs: docker-images: false tool-cache: true swap-storage: false - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - id: versions name: Read Zephyr version run: source tools/ci.sh && echo "ZEPHYR=$ZEPHYR_VERSION" | tee "$GITHUB_OUTPUT" - name: Cached Zephyr Workspace id: cache_workspace - uses: actions/cache@v4 + uses: actions/cache@v5 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 633b0cdf82ef4..6a8d4055a91b0 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@v5 + - uses: actions/checkout@v6 # 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/docs/develop/gettingstarted.rst b/docs/develop/gettingstarted.rst index cb479458e1102..a6afc5cad84c7 100644 --- a/docs/develop/gettingstarted.rst +++ b/docs/develop/gettingstarted.rst @@ -338,7 +338,15 @@ If you use the bash shell, you can add a ``ci`` command with tab completion: .. code-block:: bash - $ eval `tools/ci.sh --bash-completion` + $ eval $(tools/ci.sh --bash-completion) + +For the zsh shell, replace ``--bash-completion`` with ``--zsh-completion``. +For the fish shell, replace ``--bash-completion`` with ``--fish-completion``. + +Then, typing: + +.. code-block:: bash + $ ci unix_cov This will complete the ci step name to ``unix_coverage_``. diff --git a/docs/develop/natmod.rst b/docs/develop/natmod.rst index 072d78b2076b4..e0f7bdaaa8939 100644 --- a/docs/develop/natmod.rst +++ b/docs/develop/natmod.rst @@ -41,10 +41,16 @@ options for the ``ARCH`` variable, see below): * ``xtensa`` (non-windowed, eg ESP8266) * ``xtensawin`` (windowed with window size 8, eg ESP32, ESP32S3) * ``rv32imc`` (RISC-V 32 bits with compressed instructions, eg ESP32C3, ESP32C6) +* ``rv64imc`` (RISC-V 64 bits with compressed instructions) + +If the chosen platform supports explicit architecture flags and you want to let +the output .mpy file carry those flags' value, you must pass them to the +``ARCH_FLAGS`` flags variable when building the .mpy file. When compiling and linking the native .mpy file the architecture must be chosen -and the corresponding file can only be imported on that architecture. For more -details about .mpy files see :ref:`mpy_files`. +and the corresponding file can only be imported on that architecture (and if +architecture flags are present, only if they match the target's capabilities). +For more details about .mpy files see :ref:`mpy_files`. Native code must be compiled as position independent code (PIC) and use a global offset table (GOT), although the details of this varies from architecture to @@ -123,7 +129,8 @@ The filesystem layout consists of two main parts, the source files and the Makef location of the MicroPython repository (to find header files, the relevant Makefile fragment, and the ``mpy_ld.py`` tool), ``MOD`` as the name of the module, ``SRC`` as the list of source files, optionally specify the machine architecture via ``ARCH``, - and then include ``py/dynruntime.mk``. + along with optional machine architecture flags specified via ``ARCH_FLAGS``, and + then include ``py/dynruntime.mk``. Minimal example --------------- @@ -190,7 +197,7 @@ The file ``Makefile`` contains: # Source files (.c or .py) SRC = factorial.c - # Architecture to build for (x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc) + # Architecture to build for (x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module @@ -216,6 +223,10 @@ Without modifying the Makefile you can specify the target architecture via:: $ make ARCH=armv7m +Same applies for optional architecture flags via:: + + $ make ARCH=rv32imc ARCH_FLAGS=zba + Module usage in MicroPython --------------------------- @@ -232,15 +243,15 @@ Using Picolibc when building modules ------------------------------------ Using `Picolibc `_ as your C standard -library is not only supported, but in fact it is the default for the rv32imc -platform. However, there are a couple of things worth mentioning to make sure -you don't run into problems later when building code. +library is not only supported, but in fact it is the default for the rv32imc and +rv64imc platforms. However, there are a couple of things worth mentioning to make +sure you don't run into problems later when building code. Some pre-built Picolibc versions (for example, those provided by Ubuntu Linux as the ``picolibc-arm-none-eabi``, ``picolibc-riscv64-unknown-elf``, and ``picolibc-xtensa-lx106-elf`` packages) assume thread-local storage (TLS) is available at runtime, but unfortunately MicroPython modules do not support that -on some architectures (namely ``rv32imc``). This means that some +on some architectures (namely ``rv32imc`` and ``rv64imc``). This means that some functionalities provided by Picolibc will default to use TLS, returning an error either during compilation or during linking. diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 0cf7d81a7eaac..b4961fd4ed432 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -380,6 +380,9 @@ tx 1 10 17 rx 3 9 16 ===== ===== ===== ===== +On ESP32 with SPIRAM, the default pins for UART1 are ``tx=5`` and ``rx=4`` +to avoid possible conflicts with the SPIRAM pins. + PWM (pulse width modulation) ---------------------------- diff --git a/docs/library/collections.rst b/docs/library/collections.rst index 6a23e456c66a7..f973e521e2ea5 100644 --- a/docs/library/collections.rst +++ b/docs/library/collections.rst @@ -101,3 +101,19 @@ Classes a 2 w 5 b 3 + + .. method:: OrderedDict.popitem() + + Remove and return a (key, value) pair from the dictionary. + Pairs are returned in LIFO order. + + .. admonition:: Difference to CPython + :class: attention + + ``OrderedDict.popitem()`` does not support the ``last=False`` argument and + will always remove and return the last item if present. + + A workaround for this is to use ``pop()`` to remove the first item:: + + first_key = next(iter(d)) + d.pop(first_key) diff --git a/docs/library/espnow.rst b/docs/library/espnow.rst index 84e9e9465de96..14a92c11400b9 100644 --- a/docs/library/espnow.rst +++ b/docs/library/espnow.rst @@ -164,13 +164,15 @@ Configuration wait forever. The timeout can also be provided as arg to `recv()`/`irecv()`/`recvinto()`. - *rate*: (ESP32 only) Set the transmission speed for - ESPNow packets. Must be set to a number from the allowed numeric values - in `enum wifi_phy_rate_t - `_. This parameter is actually *write-only* due to ESP-IDF not providing any means for querying the radio interface's rate parameter. + See also `espnow-long-range`. This API currently doesn't work on ESP32-C6. .. data:: Returns: @@ -574,6 +576,45 @@ Constants espnow.MAX_TOTAL_PEER_NUM(=20) espnow.MAX_ENCRYPT_PEER_NUM(=6) +The following constants correspond to different transmit data rates on ESP32 +only. Lower data rates are generally more reliable over long distances: + +.. data:: espnow.RATE_LORA_250K + espnow.RATE_LORA_500K + + See `espnow-long-range`. + +.. data:: espnow.RATE_1M + espnow.RATE_2M + espnow.RATE_5M + espnow.RATE_6M + espnow.RATE_11M + espnow.RATE_12M + espnow.RATE_24M + espnow.RATE_54M + +Unless using the two proprietary long range data rates, only the sender must +configure the data rate. + +.. _espnow-long-range: + +Long Range Mode +--------------- + +(ESP32 Only, except ESP32-C2) + +To use the `espnow.RATE_LORA_250K` and `espnow.RATE_LORA_500K` data rates, +first set the `WLAN` interface object to long-range mode, i.e.:: + + import network, espnow + sta = network.WLAN(network.WLAN.IF_STA) + sta.active(True) + sta.config(channel=6, protocol=WLAN.PROTOCOL_LR) # Set on sender & receiver + e = espnow.ESPNow() + e.config(rate=espnow.RATE_LORA_250K) # Needed on sender only + +For more information about the limitations of long-range mode, see `WLAN.PROTOCOL_LR`. + Exceptions ---------- diff --git a/docs/library/index.rst b/docs/library/index.rst index 2919378ce13b2..e64809bfa8487 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -172,6 +172,16 @@ The following libraries are specific to the ESP8266 and ESP32. espnow.rst +Libraries specific to NXP i.MXRT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following libraries are specific to the NXP i.MXRT family of microcontrollers. + +.. toctree:: + :maxdepth: 2 + + mimxrt.rst + Libraries specific to the RP2040 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/library/machine.DAC.rst b/docs/library/machine.DAC.rst new file mode 100644 index 0000000000000..befcba8323060 --- /dev/null +++ b/docs/library/machine.DAC.rst @@ -0,0 +1,68 @@ +.. currentmodule:: machine +.. _machine.DAC: + +class DAC -- digital to analog conversion +========================================= + +The DAC is used to output an analog voltage based on a digital value. + +The output voltage will be between 0 and 3.3V. + +DAC is currently supported on ESP32 [#esp32_dac]_, SAMD and Renesas RA. + +.. note:: + The STM32 port has similar functionality to ``machine.DAC``. See + :ref:`pyb.DAC ` for details. + +Example usage (ESP32):: + + from machine import DAC + + dac = DAC(pin) # create a DAC object acting on a pin + dac.write(128) # write a value to the DAC + dac.write(255) # output maximum value, 3.3V + +Constructors +------------ + +.. class:: DAC(id) + + Construct a new DAC object. + + ``id`` is a pin object (ESP32 and Renesas RA) or an index to a DAC resource (SAMD). + +.. note:: + On the ESP32, DAC functionality is available on pins 25 and 26. On the + ESP32-S2, pins 17 and 18. See :ref:`ESP32 Quickref ` + for more details. + +.. note:: + SAMD21 has one DAC resource, SAMD51 has two. See :ref:`SAMD Quickref ` + for more details. + +Methods +------- + +.. method:: DAC.write(value) + + Output an analog voltage to the pin connected to the DAC. + + ``value`` is a representation of the desired output; a linear interpolation of + 0-3.3V, though the range differs depending on the port and micro, see below: + + +--------------+------+--------+ + | *Port/micro* | Bits | Range | + +==============+======+========+ + | ESP32 | 8 | 0-255 | + +--------------+------+--------+ + | SAMD21 | 10 | 0-1023 | + +--------------+------+--------+ + | SAMD51 | 12 | 0-4095 | + +--------------+------+--------+ + | Renesas RA | 12 | 0-4095 | + +--------------+------+--------+ + +.. rubric:: Footnotes + +.. [#esp32_dac] The original ESP32 and ESP32-S2 *only*, since DAC hardware is + not present on other microcontrollers in the family. diff --git a/docs/library/machine.I2CTarget.rst b/docs/library/machine.I2CTarget.rst index 0e4af84cb687c..2765b98143a5f 100644 --- a/docs/library/machine.I2CTarget.rst +++ b/docs/library/machine.I2CTarget.rst @@ -126,7 +126,7 @@ General Methods - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a controller for a read transaction. - - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + - ``IRQ_ADDR_MATCH_WRITE`` indicates that the target was addressed by a controller for a write transaction. - ``IRQ_READ_REQ`` indicates that the controller is requesting data, and this request must be satisfied by calling `I2CTarget.write` with the data to be @@ -141,7 +141,7 @@ General Methods Note the following restrictions: - - ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_READ``, ``IRQ_READ_REQ`` and + - ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_WRITE``, ``IRQ_READ_REQ`` and ``IRQ_WRITE_REQ`` must be handled by a hard IRQ callback (with the *hard* argument set to ``True``). This is because these events have very strict timing requirements and must usually be satisfied synchronously with the hardware event. diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst index 5d228ea7b67b5..69eea9d8d1f4f 100644 --- a/docs/library/machine.Timer.rst +++ b/docs/library/machine.Timer.rst @@ -4,37 +4,47 @@ class Timer -- control hardware timers ====================================== -Hardware timers deal with timing of periods and events. Timers are perhaps -the most flexible and heterogeneous kind of hardware in MCUs and SoCs, -differently greatly from a model to a model. MicroPython's Timer class -defines a baseline operation of executing a callback with a given period -(or once after some delay), and allow specific boards to define more -non-standard behaviour (which thus won't be portable to other boards). +Timer class provides the ability to trigger a Python callback function after an +expiry time, or periodically at a regular interval. -See discussion of :ref:`important constraints ` on -Timer callbacks. - -.. note:: - - Memory can't be allocated inside irq handlers (an interrupt) and so - exceptions raised within a handler don't give much information. See - :func:`micropython.alloc_emergency_exception_buf` for how to get around - this limitation, which applies to all callbacks of Timers created with - ``hard=True``. +The available features and restrictions of Timer objects vary depending on the +MicroPython board and port. If you are using a WiPy board please refer to :ref:`machine.TimerWiPy ` instead of this class. +Timer Types +----------- + +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. +- 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 + when ``hard=True`` is supported and set, see :ref:`isr_rules`.) Most + microcontroller ports support hardware timers, except Zephyr and RP2 which + only support virtual timers. + Constructors ------------ .. class:: Timer(id, /, ...) - Construct a new timer object of the given ``id``. ``id`` of -1 constructs a - virtual timer (if supported by a board). + Construct a new Timer object with the given ``id``. + + On ports which support virtual timers the ``id`` parameter is optional - the + default value is ``-1`` which constructs a virtual timer. + + On ports which support hardware timers, setting the ``id`` parameter to a + non-negative integer determines which timer to use. + ``id`` shall not be passed as a keyword argument. - See ``init`` for parameters of initialisation. + Any additional parameters are handled the same as :func:`Timer.init()`. Methods ------- @@ -73,22 +83,22 @@ Methods - ``callback`` - The callable to call upon expiration of the timer period. The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception will occur upon timer expiration: ``TypeError: 'NoneType' object isn't callable`` - ``hard`` can be one of: - - ``True`` - The callback will be executed in hard interrupt - context, which minimises delay and jitter but is subject to the - limitations described in :ref:`isr_rules` including being unable - to allocate on the heap. + - ``True`` - The callback will be executed in hard interrupt context, + which minimises delay and jitter but is subject to the limitations + described in :ref:`isr_rules`. Not all ports support hard interrupts, + see the port documentation for more information. - ``False`` - The callback will be scheduled as a soft interrupt, allowing it to allocate but possibly also introducing garbage-collection delays and jitter. - The default value of this option is port-specific for historical - reasons. + The default value of this parameter is port-specific for historical reasons. .. method:: Timer.deinit() diff --git a/docs/library/machine.TimerWiPy.rst b/docs/library/machine.TimerWiPy.rst index 54280a5994ad5..17215d502038c 100644 --- a/docs/library/machine.TimerWiPy.rst +++ b/docs/library/machine.TimerWiPy.rst @@ -18,16 +18,6 @@ defines a baseline operation of executing a callback with a given period (or once after some delay), and allow specific boards to define more non-standard behaviour (which thus won't be portable to other boards). -See discussion of :ref:`important constraints ` on -Timer callbacks. - -.. note:: - - Memory can't be allocated inside irq handlers (an interrupt) and so - exceptions raised within a handler don't give much information. See - :func:`micropython.alloc_emergency_exception_buf` for how to get around this - limitation. - Constructors ------------ @@ -134,6 +124,9 @@ Methods ``TimerWiPy.ONE_SHOT``. In the case that mode is ``TimerWiPy.PWM`` then trigger must be equal to ``TimerWiPy.MATCH``. + Note that callback handlers are hard interrupts, and the constraints described in :ref:`isr_rules` + apply when they are executed. + Returns a callback object. .. method:: timerchannel.freq([value]) diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 7acaddde815bc..31acb74920c49 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -11,14 +11,6 @@ and unrestricted access to and control of hardware blocks on a system malfunction, lockups, crashes of your board, and in extreme cases, hardware damage. -.. _machine_callbacks: - -A note of callbacks used by functions and class methods of :mod:`machine` module: -all these callbacks should be considered as executing in an interrupt context. -This is true for both physical devices with IDs >= 0 and "virtual" devices -with negative IDs like -1 (these "virtual" devices are still thin shims on -top of real hardware and real hardware interrupts). See :ref:`isr_rules`. - Memory access ------------- @@ -260,6 +252,7 @@ Classes machine.Signal.rst machine.ADC.rst machine.ADCBlock.rst + machine.DAC.rst machine.PWM.rst machine.UART.rst machine.SPI.rst diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index 4d5a064a7a70e..2da9a6e3fd76f 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -130,6 +130,11 @@ Functions a critical region but they will not be executed until that region is exited. An example of a critical region is a preempting interrupt handler (an IRQ). + - Inside native code functions, scheduled functions are not called unless + the native code calls a function that specifically does so. + - Certain functions including ``poll.poll``, ``poll.ipoll``, + ``time.sleep`` and ``time.sleep_ms`` (including zero-duration sleeps) + will call scheduled functions. A use for this function is to schedule a callback from a preempting IRQ. Such an IRQ puts restrictions on the code that runs in the IRQ (for example diff --git a/docs/library/mimxrt.Flash.rst b/docs/library/mimxrt.Flash.rst new file mode 100644 index 0000000000000..161ef4ff2a4b7 --- /dev/null +++ b/docs/library/mimxrt.Flash.rst @@ -0,0 +1,39 @@ +.. currentmodule:: mimxrt +.. _mimxrt.Flash: + +class Flash -- access to built-in flash storage +=============================================== + +This class gives access to the SPI flash memory. + +In most cases, to store persistent data on the device, you'll want to use a +higher-level abstraction, for example the filesystem via Python's standard file +API, but this interface is useful to :ref:`customise the filesystem +configuration ` or implement a low-level storage system for your +application. + + +Constructors +------------ + +.. class:: Flash() + + Gets the singleton object for accessing the SPI flash memory. + + +Methods +------- + +.. method:: Flash.readblocks(block_num, buf) + Flash.readblocks(block_num, buf, offset) +.. method:: Flash.writeblocks(block_num, buf) + Flash.writeblocks(block_num, buf, offset) +.. method:: Flash.ioctl(cmd, arg) + + These methods implement the simple and extended + :ref:`block protocol ` defined by + :class:`vfs.AbstractBlockDev`. + + The block size can be queried by calling ``ioctl(5, 0)``. Block numbers + are relative to the start of the user flash storage area, not the physical + start of flash memory. diff --git a/docs/library/mimxrt.rst b/docs/library/mimxrt.rst new file mode 100644 index 0000000000000..fdb4c1a1da66f --- /dev/null +++ b/docs/library/mimxrt.rst @@ -0,0 +1,19 @@ +.. currentmodule:: mimxrt + +:mod:`mimxrt` --- functionality specific to NXP i.MXRT +====================================================== + +.. module:: mimxrt + :synopsis: functionality specific to NXP i.MXRT + +The ``mimxrt`` module contains functions and classes specific to the NXP i.MXRT +family of microcontrollers. + + +Classes +------- + +.. toctree:: + :maxdepth: 1 + + mimxrt.Flash.rst diff --git a/docs/library/network.WLAN.rst b/docs/library/network.WLAN.rst index ee0ef490fda84..e4653bc35ca52 100644 --- a/docs/library/network.WLAN.rst +++ b/docs/library/network.WLAN.rst @@ -145,6 +145,7 @@ Methods reconnects Number of reconnect attempts to make (integer, 0=none, -1=unlimited) txpower Maximum transmit power in dBm (integer or float) pm WiFi Power Management setting (see below for allowed values) + protocol (ESP32 Only.) WiFi Low level 802.11 protocol. See `WLAN.PROTOCOL_DEFAULT`. ============= =========== Constants @@ -161,3 +162,34 @@ Constants * ``PM_POWERSAVE``: enable WiFi power management with additional power savings and reduced WiFi performance * ``PM_NONE``: disable wifi power management + + +ESP32 Protocol Constants +------------------------ + +The following ESP32-only constants relate to the ``WLAN.config(protocol=...)`` +network interface parameter: + +.. data:: WLAN.PROTOCOL_DEFAULT + + A bitmap representing all of the default 802.11 Wi-Fi modes supported by + the chip. Consult `ESP-IDF Wi-Fi Protocols`_ documentation for details. + +.. data:: WLAN.PROTOCOL_LR + + This value corresponds to the `Espressif proprietary "long-range" mode`_, + which is not compatible with standard Wi-Fi devices. By setting this + protocol it's possible for an ESP32 STA in long-range mode to connect to + an ESP32 AP in long-range mode, or to use `ESP-NOW long range modes + `. + + This mode can be bitwise ORed with some standard 802.11 protocol bits + (including `WLAN.PROTOCOL_DEFAULT`) in order to support a mix of standard + Wi-Fi modes as well as LR mode, consult the `Espressif long-range + documentation`_ for more details. + + Long range mode is not supported on ESP32-C2. + +.. _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/select.rst b/docs/library/select.rst index 57adbb49afd20..6df1ff9c23060 100644 --- a/docs/library/select.rst +++ b/docs/library/select.rst @@ -76,6 +76,9 @@ Methods In case of timeout, an empty list is returned. + Calling ``poll.poll`` is guaranteed to call pending callback functions + before entering the polling loop. + .. admonition:: Difference to CPython :class: attention @@ -93,6 +96,9 @@ Methods won't be processed until new mask is set with `poll.modify()`. This behaviour is useful for asynchronous I/O schedulers. + Calling ``poll.ipoll`` is guaranteed to call pending callback functions + before entering the polling loop. + .. admonition:: Difference to CPython :class: attention diff --git a/docs/library/time.rst b/docs/library/time.rst index b53bb133ec408..8f413fca92b53 100644 --- a/docs/library/time.rst +++ b/docs/library/time.rst @@ -71,6 +71,9 @@ Functions other boards may not accept a floating-point argument, for compatibility with them use `sleep_ms()` and `sleep_us()` functions. + Calling ``sleep``, including ``sleep(0)`` is guaranteed to call pending callback + functions. + .. function:: sleep_ms(ms) Delay for given number of milliseconds, should be positive or 0. @@ -80,6 +83,9 @@ Functions interrupt handlers or other threads. Passing in 0 for *ms* will still allow this other processing to occur. Use `sleep_us()` for more precise delays. + Calling ``sleep_ms``, including ``sleep_ms(0)`` is guaranteed to call + pending callback functions. + .. function:: sleep_us(us) Delay for given number of microseconds, should be positive or 0. diff --git a/docs/mimxrt/pinout.rst b/docs/mimxrt/pinout.rst index d2b62d56d01d6..09953164bde4f 100644 --- a/docs/mimxrt/pinout.rst +++ b/docs/mimxrt/pinout.rst @@ -67,41 +67,43 @@ PWM pin assignment Pins are specified in the same way as for the Pin class. The following tables show the assignment of the board Pins to PWM modules: -=========== ========== ========== ====== ========== ====== ======== -Pin/ MIMXRT 1010 1015 1020 1050/60/64 1170 Metro M7 -=========== ========== ========== ====== ========== ====== ======== -D0 - Q1/1 F1/1/B - - - -D1 - Q1/0 F1/1/A - - - -D2 F1/3/B F1/3/A - F1/3/B - - -D3 F1/3/A F1/0/A F2/3/B F4/0/A F1/2/A - -D4 F1/3/A (*) Q1/2 Q2/1 F2/3/A Q4/2 F1/0/B -D5 F1/0/B (*) F1/0/B F2/3/A F1/3/A F1/2/B F1/0/A -D6 - F1/2/B F2/0/A Q3/2 F1/0/A - -D7 - - F1/0/A Q3/3 - - -D8 F1/0/A F1/1/B F1/0/B F1/1/X Q4/3 F1/3/A -D9 F1/1/B (*) F1/2/A F2/0/B F1/0/X F1/0/B F1/3/B -D10 F1/3/B - F2/2/B F1/0/B (*) F2/2/B F1/2/A -D11 F1/2/A - F2/1/A F1/1/A (*) - F1/2/B -D12 F1/2/B - F2/1/B F1/1/B (*) - F1/1/A -D13 F1/3/A - F2/2/A F1/0/A (*) F2/2/A F1/1/B -D14 F1/0/B - - F2/3/B - F1/0/B -D15 F1/0/A - - F2/3/A - F1/0/A -A0 - - F1/2/A - - - -A1 F1/3/X F1/3/B F1/2/B - - - -A2 F1/2/X F1/3/A F1/3/A - - - -A3 - F1/2/A F1/3/B - - F1/3/B -A4 - - - Q3/1 - F1/2/X -A5 - - - Q3/0 - - -D31 - - - - F1/2/B - -D32 - - - - F1/2/A - -D33 - - - - F1/1/B - -D34 - - - - F1/1/A - -D35 - - - - F1/0/B - -D36 - - - - F1/0/A - -=========== ========== ========== ====== ========== ====== ======== +=========== ========== ========== ====== ========== =========== ======== +Pin/ MIMXRT 1010 1015 1020 1050/60/64 1170 Metro M7 +=========== ========== ========== ====== ========== =========== ======== +D0 - Q1/1 F1/1/B - - - +D1 - Q1/0 F1/1/A - - - +D2 F1/3/B F1/3/A - F1/3/B - - +D3 F1/3/A F1/0/A F2/3/B F4/0/A F1/2/A (&) - +D4 F1/3/A (*) Q1/2 Q2/1 F2/3/A F1/0/X (&) F1/0/B +D5 F1/0/B (*) F1/0/B F2/3/A F1/3/A F1/2/B (&) F1/0/A +D6 - F1/2/B F2/0/A Q3/2 F1/0/A - +D7 - - F1/0/A Q3/3 F3/0/X - +D8 F1/0/A F1/1/B F1/0/B F1/1/X F1/1/X (&) F1/3/A +D9 F1/1/B (*) F1/2/A F2/0/B F1/0/X F1/0/B F1/3/B +D10 F1/3/B - F2/2/B F1/0/B (*) F2/2/B F1/2/A +D11 F1/2/A - F2/1/A F1/1/A (*) - F1/2/B +D12 F1/2/B - F2/1/B F1/1/B (*) - F1/1/A +D13 F1/3/A - F2/2/A F1/0/A (*) F2/2/A F1/1/B +D14 F1/0/B - - F2/3/B - F1/0/B +D15 F1/0/A - - F2/3/A - F1/0/A +A0 - - F1/2/A - F2/0/X - +A1 F1/3/X F1/3/B F1/2/B - F2/1/X - +A2 F1/2/X F1/3/A F1/3/A - F2/2/X - +A3 - F1/2/A F1/3/B - F2/3/X F1/3/B +A4 - - - Q3/1 F1/3/X F1/2/X +A5 - - - Q3/0 F1/2/X - +D31 - - - - F1/2/B (&) - +D32 - - - - F1/2/A (&) - +D33 - - - - F1/1/B - +D34 - - - - F1/1/A - +D35 - - - - F1/0/B - +D36 - - - - F1/0/A - +=========== ========== ========== ====== ========== =========== ======== Pins denoted with (*) are by default not wired at the board. +Pins denoted with (&) have alternative PWM options available. + ==== ========== ==== ========== Pin Teensy 4.0 Pin Teensy 4.1 ==== ========== ==== ========== @@ -317,6 +319,10 @@ Pin.cpu.GPIO_EMC_B1_29 FLEXPWM3 Channel A (*) Pin.cpu.GPIO_EMC_B1_30 FLEXPWM3 Channel B (*) Pin.cpu.GPIO_AD_00 FLEXPWM1 Channel A Pin.cpu.GPIO_AD_01 FLEXPWM1 Channel B +Pin.cpu.GPIO_AD_06 FLEXPWM1 Channel X +Pin.cpu.GPIO_AD_10 FLEXPWM2 Channel X +Pin.cpu.GPIO_AD_14 FLEXPWM3 Channel X +Pin.cpu.GPIO_AD_18 FLEXPWM4 Channel X Pin.cpu.GPIO_AD_24 FLEXPWM2 Channel A Pin.cpu.GPIO_AD_25 FLEXPWM2 Channel B ====================== ====================== diff --git a/docs/reference/mpyfiles.rst b/docs/reference/mpyfiles.rst index 58e45e158523c..978a798350a78 100644 --- a/docs/reference/mpyfiles.rst +++ b/docs/reference/mpyfiles.rst @@ -193,7 +193,8 @@ MPY files is used to indicate that no specific extensions are needed, and saves one byte in the final output binary. See also the ``-march-flags`` command-line option in both ``mpy-tool.py`` and -``mpy-cross`` to set this value when creating MPY files. +``mpy-cross``, and the ``--arch-flags`` command-line option in ``mpy_ld.py`` to +set this value when creating MPY files. The global qstr and constant tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/examples/embedding/.gitignore b/examples/embedding/.gitignore new file mode 100644 index 0000000000000..78bd33eb13e74 --- /dev/null +++ b/examples/embedding/.gitignore @@ -0,0 +1,4 @@ +# Files created by ci.sh embed_build +embed +main.o +micropython_embed diff --git a/examples/natmod/btree/Makefile b/examples/natmod/btree/Makefile index 1910c67c1fc24..4ded62bafdeed 100644 --- a/examples/natmod/btree/Makefile +++ b/examples/natmod/btree/Makefile @@ -7,7 +7,7 @@ MOD = btree_$(ARCH) # Source files (.c or .py) SRC = btree_c.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH ?= x64 BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx diff --git a/examples/natmod/deflate/Makefile b/examples/natmod/deflate/Makefile index 5823aa4d45bf2..0574bbaf41272 100644 --- a/examples/natmod/deflate/Makefile +++ b/examples/natmod/deflate/Makefile @@ -7,7 +7,7 @@ MOD = deflate_$(ARCH) # Source files (.c or .py) SRC = deflate.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH ?= x64 ifeq ($(ARCH),armv6m) diff --git a/examples/natmod/features0/Makefile b/examples/natmod/features0/Makefile index fb01b8d031aaa..788d035eb8bff 100644 --- a/examples/natmod/features0/Makefile +++ b/examples/natmod/features0/Makefile @@ -7,7 +7,7 @@ MOD = features0 # Source files (.c or .py) SRC = features0.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/examples/natmod/features1/Makefile b/examples/natmod/features1/Makefile index 49040511020eb..47deeed8f2ae2 100644 --- a/examples/natmod/features1/Makefile +++ b/examples/natmod/features1/Makefile @@ -7,7 +7,7 @@ MOD = features1 # Source files (.c or .py) SRC = features1.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/examples/natmod/features2/Makefile b/examples/natmod/features2/Makefile index 5ddb74087b71a..efd096c4ede71 100644 --- a/examples/natmod/features2/Makefile +++ b/examples/natmod/features2/Makefile @@ -7,7 +7,7 @@ MOD = features2 # Source files (.c or .py) SRC = main.c prod.c test.py -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Link with libm.a and libgcc.a from the toolchain diff --git a/examples/natmod/features3/Makefile b/examples/natmod/features3/Makefile index 3573f41caca82..85d1a13421fa8 100644 --- a/examples/natmod/features3/Makefile +++ b/examples/natmod/features3/Makefile @@ -7,7 +7,7 @@ MOD = features3 # Source files (.c or .py) SRC = features3.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/examples/natmod/features4/Makefile b/examples/natmod/features4/Makefile index 34fc3a7ef7bf4..4eb657b7220b8 100644 --- a/examples/natmod/features4/Makefile +++ b/examples/natmod/features4/Makefile @@ -7,7 +7,7 @@ MOD = features4 # Source files (.c or .py) SRC = features4.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/examples/natmod/framebuf/Makefile b/examples/natmod/framebuf/Makefile index 35453c0bb4b4c..a86efef41f42b 100644 --- a/examples/natmod/framebuf/Makefile +++ b/examples/natmod/framebuf/Makefile @@ -7,7 +7,7 @@ MOD = framebuf_$(ARCH) # Source files (.c or .py) SRC = framebuf.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH ?= x64 ifeq ($(ARCH),armv6m) diff --git a/examples/natmod/heapq/Makefile b/examples/natmod/heapq/Makefile index 61e2fc8fcc0e0..345359abb3ca2 100644 --- a/examples/natmod/heapq/Makefile +++ b/examples/natmod/heapq/Makefile @@ -7,7 +7,7 @@ MOD = heapq_$(ARCH) # Source files (.c or .py) SRC = heapq.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/random/Makefile b/examples/natmod/random/Makefile index bffbb32d60ef1..27d8ec935fe38 100644 --- a/examples/natmod/random/Makefile +++ b/examples/natmod/random/Makefile @@ -7,7 +7,7 @@ MOD = random_$(ARCH) # Source files (.c or .py) SRC = random.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH ?= x64 ifeq ($(ARCH),xtensa) diff --git a/examples/natmod/re/Makefile b/examples/natmod/re/Makefile index 6535693dcb88c..c5f05e64ab4b6 100644 --- a/examples/natmod/re/Makefile +++ b/examples/natmod/re/Makefile @@ -7,7 +7,7 @@ MOD = re_$(ARCH) # Source files (.c or .py) SRC = re.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 ifeq ($(ARCH),armv6m) diff --git a/extmod/machine_usb_device.c b/extmod/machine_usb_device.c index 5019cd98779f5..3d4cde942cb9f 100644 --- a/extmod/machine_usb_device.c +++ b/extmod/machine_usb_device.c @@ -42,6 +42,8 @@ #define HAS_BUILTIN_DRIVERS (MICROPY_HW_USB_CDC || MICROPY_HW_USB_MSC) +#define RHPORT TUD_OPT_RHPORT + const mp_obj_type_t machine_usb_device_type; static mp_obj_t usb_device_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -111,11 +113,11 @@ static mp_obj_t usb_device_submit_xfer(mp_obj_t self, mp_obj_t ep, mp_obj_t buff mp_raise_ValueError(MP_ERROR_TEXT("ep")); } - if (!usbd_edpt_claim(USBD_RHPORT, ep_addr)) { + if (!usbd_edpt_claim(RHPORT, ep_addr)) { mp_raise_OSError(MP_EBUSY); } - result = usbd_edpt_xfer(USBD_RHPORT, ep_addr, buf_info.buf, buf_info.len); + result = usbd_edpt_xfer(RHPORT, ep_addr, buf_info.buf, buf_info.len); if (result) { // Store the buffer object until the transfer completes @@ -168,14 +170,14 @@ static mp_obj_t usb_device_stall(size_t n_args, const mp_obj_t *args) { usb_device_check_active(self); - mp_obj_t res = mp_obj_new_bool(usbd_edpt_stalled(USBD_RHPORT, epnum)); + mp_obj_t res = mp_obj_new_bool(usbd_edpt_stalled(RHPORT, epnum)); if (n_args == 3) { // Set stall state mp_obj_t stall = args[2]; if (mp_obj_is_true(stall)) { - usbd_edpt_stall(USBD_RHPORT, epnum); + usbd_edpt_stall(RHPORT, epnum); } else { - usbd_edpt_clear_stall(USBD_RHPORT, epnum); + usbd_edpt_clear_stall(RHPORT, epnum); } } diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 4b1c1b8f3a5ec..bcec34bca3b0c 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -213,7 +213,7 @@ static MP_DEFINE_CONST_OBJ_TYPE( // TODO: We just know that change happened somewhere between 1.4.0 and 1.4.1, // investigate in more detail. #if LWIP_VERSION_MACRO < 0x01040100 -static const int error_lookup_table[] = { +static const int8_t error_lookup_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ MP_ENOBUFS, /* ERR_BUF -2 Buffer error. */ @@ -234,7 +234,7 @@ static const int error_lookup_table[] = { MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; #elif LWIP_VERSION_MACRO < 0x02000000 -static const int error_lookup_table[] = { +static const int8_t error_lookup_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ MP_ENOBUFS, /* ERR_BUF -2 Buffer error. */ @@ -258,7 +258,7 @@ static const int error_lookup_table[] = { // Matches lwIP 2.0.3 #undef _ERR_BADF #define _ERR_BADF -17 -static const int error_lookup_table[] = { +static const int8_t error_lookup_table[] = { 0, /* ERR_OK 0 No error, everything OK */ MP_ENOMEM, /* ERR_MEM -1 Out of memory error */ MP_ENOBUFS, /* ERR_BUF -2 Buffer error */ @@ -348,8 +348,9 @@ typedef struct _lwip_socket_obj_t { #define STATE_LISTENING 1 #define STATE_CONNECTING 2 #define STATE_CONNECTED 3 - #define STATE_PEER_CLOSED 4 - #define STATE_ACTIVE_UDP 5 + #define STATE_ACTIVE_UDP 4 + #define STATE_PEER_CLOSED 5 // Values higher than this must also be closed by peer + #define STATE_PEER_RST_HANDLED 6 // Negative value is lwIP error int8_t state; } lwip_socket_obj_t; @@ -370,14 +371,10 @@ static struct tcp_pcb *volatile *lwip_socket_incoming_array(lwip_socket_obj_t *s } } -static void lwip_socket_free_incoming(lwip_socket_obj_t *socket) { - bool socket_is_listener = - socket->type == MOD_NETWORK_SOCK_STREAM - && socket->pcb.tcp->state == LISTEN; - - if (!socket_is_listener) { +static void lwip_socket_free_incoming(lwip_socket_obj_t *socket, bool free_queued_stream_data) { + if (socket->state != STATE_LISTENING) { if (socket->type == MOD_NETWORK_SOCK_STREAM) { - if (socket->incoming.tcp.pbuf != NULL) { + if (free_queued_stream_data && socket->incoming.tcp.pbuf != NULL) { pbuf_free(socket->incoming.tcp.pbuf); socket->incoming.tcp.pbuf = NULL; } @@ -403,6 +400,8 @@ static void lwip_socket_free_incoming(lwip_socket_obj_t *socket) { tcp_array[i] = NULL; } } + // This socket is now a non-listening stream, so clear the relevant state. + socket->incoming.tcp.pbuf = NULL; } } @@ -491,8 +490,9 @@ static void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, static void _lwip_tcp_error(void *arg, err_t err) { lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg; - // Free any incoming buffers or connections that are stored - lwip_socket_free_incoming(socket); + // Free any incoming buffers or connections that are stored, but keep potential + // queued TCP data in case it's read later. Will be freed by MP_STREAM_CLOSE. + lwip_socket_free_incoming(socket, false); // Pass the error code back via the connection variable. socket->state = err; // If we got here, the lwIP stack either has deallocated or will deallocate the pcb. @@ -822,9 +822,6 @@ static mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // Helper function for recv/recvfrom to handle TCP packets static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, mp_int_t flags, int *_errno) { - // Check for any pending errors - STREAM_ERROR_CHECK(socket); - if (socket->state == STATE_LISTENING) { // original socket in listening state, not the accepted connection. *_errno = MP_ENOTCONN; @@ -832,10 +829,20 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } if (socket->incoming.tcp.pbuf == NULL) { + // Check for any pending errors that should propagate out on socket read. + if (socket->state < 0) { + *_errno = error_lookup_table[-socket->state]; + if (*_errno == MP_ECONNRESET) { + socket->state = STATE_PEER_RST_HANDLED; + } else { + socket->state = _ERR_BADF; + } + return MP_STREAM_ERROR; + } // Non-blocking socket or flag if (socket->timeout == 0 || (flags & MSG_DONTWAIT)) { - if (socket->state == STATE_PEER_CLOSED) { + if (socket->state >= STATE_PEER_CLOSED) { return 0; } *_errno = MP_EAGAIN; @@ -851,7 +858,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ poll_sockets(); } - if (socket->state == STATE_PEER_CLOSED) { + if (socket->state >= STATE_PEER_CLOSED) { if (socket->incoming.tcp.pbuf == NULL) { // socket closed and no data left in buffer return 0; @@ -868,8 +875,6 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ MICROPY_PY_LWIP_ENTER - assert(socket->pcb.tcp != NULL); - struct pbuf *p = socket->incoming.tcp.pbuf; mp_uint_t remaining = p->len - socket->recv_offset; @@ -892,7 +897,9 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } else { socket->recv_offset += len; } - tcp_recved(socket->pcb.tcp, len); + if (socket->pcb.tcp != NULL) { + tcp_recved(socket->pcb.tcp, len); + } } MICROPY_PY_LWIP_EXIT @@ -1091,15 +1098,10 @@ static mp_obj_t lwip_socket_accept(mp_obj_t self_in) { mp_raise_OSError(MP_EOPNOTSUPP); } - // Create new socket object, do it here because we must not raise an out-of-memory - // exception when the LWIP concurrency lock is held - lwip_socket_obj_t *socket2 = mp_obj_malloc_with_finaliser(lwip_socket_obj_t, &lwip_socket_type); - MICROPY_PY_LWIP_ENTER if (socket->pcb.tcp == NULL) { MICROPY_PY_LWIP_EXIT - m_del_obj(lwip_socket_obj_t, socket2); mp_raise_OSError(MP_EBADF); } @@ -1107,7 +1109,6 @@ static mp_obj_t lwip_socket_accept(mp_obj_t self_in) { struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { MICROPY_PY_LWIP_EXIT - m_del_obj(lwip_socket_obj_t, socket2); mp_raise_OSError(MP_EINVAL); } @@ -1124,7 +1125,6 @@ static mp_obj_t lwip_socket_accept(mp_obj_t self_in) { } if (socket_is_timedout(socket, ticks_start)) { MICROPY_PY_LWIP_EXIT - m_del_obj(lwip_socket_obj_t, socket2); if (socket->timeout == 0) { mp_raise_OSError(MP_EAGAIN); } else { @@ -1135,13 +1135,20 @@ static mp_obj_t lwip_socket_accept(mp_obj_t self_in) { } // We get a new pcb handle... - socket2->pcb.tcp = *incoming_connection; + struct tcp_pcb *pcb_new = *incoming_connection; if (++socket->incoming.connection.iget >= socket->incoming.connection.alloc) { socket->incoming.connection.iget = 0; } *incoming_connection = NULL; + MICROPY_PY_LWIP_EXIT + // ...and set up the new socket for it. + // + // Creating the new socket object must be done in one step due to the finaliser, and + // outside the lwIP concurrency lock in case it raises an out-of-memory exception. + lwip_socket_obj_t *socket2 = mp_obj_malloc_with_finaliser(lwip_socket_obj_t, &lwip_socket_type); + socket2->pcb.tcp = pcb_new; socket2->domain = MOD_NETWORK_AF_INET; socket2->type = MOD_NETWORK_SOCK_STREAM; socket2->incoming.tcp.pbuf = NULL; @@ -1149,10 +1156,12 @@ static mp_obj_t lwip_socket_accept(mp_obj_t self_in) { socket2->state = STATE_CONNECTED; socket2->recv_offset = 0; socket2->callback = MP_OBJ_NULL; + + MICROPY_PY_LWIP_REENTER + tcp_arg(socket2->pcb.tcp, (void *)socket2); tcp_err(socket2->pcb.tcp, _lwip_tcp_error); tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv); - tcp_accepted(listener); MICROPY_PY_LWIP_EXIT @@ -1294,8 +1303,6 @@ static mp_obj_t lwip_socket_recv_common(size_t n_args, const mp_obj_t *args, ip_ vstr_t vstr; mp_uint_t ret = 0; - lwip_socket_check_connected(socket); - vstr_init_len(&vstr, len); switch (socket->type) { @@ -1310,6 +1317,7 @@ static mp_obj_t lwip_socket_recv_common(size_t n_args, const mp_obj_t *args, ip_ #if MICROPY_PY_LWIP_SOCK_RAW case MOD_NETWORK_SOCK_RAW: #endif + lwip_socket_check_connected(socket); ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, flags, ip, port, &_errno); break; } @@ -1582,7 +1590,10 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } } else if (socket->type == MOD_NETWORK_SOCK_STREAM) { // For TCP sockets there is just one slot for incoming data - if (socket->incoming.tcp.pbuf != NULL) { + // The socket is also readable when in RST state + if (socket->incoming.tcp.pbuf != NULL + || socket->state == ERR_RST + || socket->state == STATE_PEER_RST_HANDLED) { ret |= MP_STREAM_POLL_RD; } } else { @@ -1621,6 +1632,8 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } else if (socket->state == ERR_RST) { // Socket was reset by peer, a write will return an error ret |= flags & MP_STREAM_POLL_WR; + ret |= MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP; + } else if (socket->state == STATE_PEER_RST_HANDLED) { ret |= MP_STREAM_POLL_HUP; } else if (socket->state == _ERR_BADF) { ret |= MP_STREAM_POLL_NVAL; @@ -1631,14 +1644,15 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } } else if (request == MP_STREAM_CLOSE) { + // Free any incoming buffers or connections that are stored + lwip_socket_free_incoming(socket, true); + if (socket->pcb.tcp == NULL) { + socket->state = _ERR_BADF; MICROPY_PY_LWIP_EXIT return 0; } - // Free any incoming buffers or connections that are stored - lwip_socket_free_incoming(socket); - switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { // Deregister callback (pcb.tcp is set to NULL below so must deregister now) @@ -1646,7 +1660,7 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ tcp_err(socket->pcb.tcp, NULL); tcp_recv(socket->pcb.tcp, NULL); - if (socket->pcb.tcp->state != LISTEN) { + if (socket->state != STATE_LISTENING) { // Schedule a callback to abort the connection if it's not cleanly closed after // the given timeout. The callback must be set before calling tcp_close since // the latter may free the pcb; if it doesn't then the callback will be active. diff --git a/extmod/modmarshal.c b/extmod/modmarshal.c index 93d2bcf115065..cc7878e864d92 100644 --- a/extmod/modmarshal.c +++ b/extmod/modmarshal.c @@ -36,17 +36,7 @@ static mp_obj_t marshal_dumps(mp_obj_t value_in) { if (mp_obj_is_type(value_in, &mp_type_code)) { mp_obj_code_t *code = MP_OBJ_TO_PTR(value_in); const void *proto_fun = mp_code_get_proto_fun(code); - const uint8_t *bytecode; - if (mp_proto_fun_is_bytecode(proto_fun)) { - bytecode = proto_fun; - } else { - const mp_raw_code_t *rc = proto_fun; - if (!(rc->kind == MP_CODE_BYTECODE && rc->children == NULL)) { - mp_raise_ValueError(MP_ERROR_TEXT("function must be bytecode with no children")); - } - bytecode = rc->fun_data; - } - return mp_raw_code_save_fun_to_bytes(mp_code_get_constants(code), bytecode); + return mp_raw_code_save_fun_to_bytes(mp_code_get_constants(code), proto_fun); } else { mp_raise_ValueError(MP_ERROR_TEXT("unmarshallable object")); } diff --git a/extmod/modopenamp.c b/extmod/modopenamp.c index 7d5841c40001d..b5e813495ba20 100644 --- a/extmod/modopenamp.c +++ b/extmod/modopenamp.c @@ -80,11 +80,12 @@ #define VRING_BUFF_ADDR (METAL_SHM_ADDR + 0x2000) #define VRING_BUFF_SIZE (METAL_SHM_SIZE - 0x2000) -#if MICROPY_PY_OPENAMP_HOST -static const char openamp_trace_buf[128]; +#if MICROPY_PY_OPENAMP_HOST && MICROPY_PY_OPENAMP_TRACE_BUF_ENABLE +#ifndef MICROPY_PY_OPENAMP_TRACE_BUF +static char openamp_trace_buf[MICROPY_PY_OPENAMP_TRACE_BUF_LEN]; #define MICROPY_PY_OPENAMP_TRACE_BUF ((uint32_t)openamp_trace_buf) -#define MICROPY_PY_OPENAMP_TRACE_BUF_LEN sizeof(MICROPY_PY_OPENAMP_TRACE_BUF) -#endif // MICROPY_PY_OPENAMP_HOST +#endif // MICROPY_PY_OPENAMP_TRACE_BUF +#endif // MICROPY_PY_OPENAMP_HOST && MICROPY_PY_OPENAMP_TRACE_BUF_ENABLE #endif // MICROPY_PY_OPENAMP_RSC_TABLE_ENABLE diff --git a/extmod/modopenamp.h b/extmod/modopenamp.h index 8f677788f90be..463399507b964 100644 --- a/extmod/modopenamp.h +++ b/extmod/modopenamp.h @@ -47,6 +47,12 @@ #define MICROPY_PY_OPENAMP_TRACE_BUF_ENABLE (1) #endif +// Set the default trace buffer size, making it 128 bytes long unless +// marked otherwise. +#ifndef MICROPY_PY_OPENAMP_TRACE_BUF_LEN +#define MICROPY_PY_OPENAMP_TRACE_BUF_LEN (128) +#endif + // For ports that don't define a custom image store, this enables a generic // VFS-based image store that supports loading elf files from storage. #ifndef MICROPY_PY_OPENAMP_REMOTEPROC_STORE_ENABLE diff --git a/extmod/modselect.c b/extmod/modselect.c index d06157e585ae1..229f8f737b517 100644 --- a/extmod/modselect.c +++ b/extmod/modselect.c @@ -342,6 +342,8 @@ static mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size mp_uint_t start_ticks = mp_hal_ticks_ms(); bool has_timeout = timeout != (mp_uint_t)-1; + mp_handle_pending(true); + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS for (;;) { diff --git a/lib/micropython-lib b/lib/micropython-lib index 34c4ee1647ac4..6ae440a8a1442 160000 --- a/lib/micropython-lib +++ b/lib/micropython-lib @@ -1 +1 @@ -Subproject commit 34c4ee1647ac4b177ae40adf0ec514660e433dc0 +Subproject commit 6ae440a8a144233e6e703f6759b7e7a0afaa37a4 diff --git a/lib/nxp_driver b/lib/nxp_driver index 91b04b34a59f6..a298e8a3cad2d 160000 --- a/lib/nxp_driver +++ b/lib/nxp_driver @@ -1 +1 @@ -Subproject commit 91b04b34a59f6d81661cec6f84611afe6330ce92 +Subproject commit a298e8a3cad2df737de020bbeac4ee2147d189ca diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 38190671c6ddd..c9109788fb3da 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -145,8 +145,8 @@ static int usage(char **argv) { "-march= : set architecture for native emitter;\n" " x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp,\n" " armv7emdp, xtensa, xtensawin, rv32imc, rv64imc, host, debug\n" - "-march-flags= : set architecture-specific flags (can be either a dec/hex/bin value or a string)\n" - " supported flags for rv32imc: zba\n" + "-march-flags= : set architecture-specific flags (can be either a dec/hex/bin value or a comma-separated flags string)\n" + " supported flags for rv32imc: zba, zcmp\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -259,6 +259,34 @@ static bool parse_integer(const char *value, mp_uint_t *integer) { return valid; } +#if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 +static bool parse_rv32_flags_string(const char *source, mp_uint_t *flags) { + assert(source && "Flag arguments string is NULL."); + assert(flags && "Collected flags pointer is NULL."); + + const char *current = source; + const char *end = source + strlen(source); + mp_uint_t collected_flags = 0; + while (current < end) { + const char *separator = strchr(current, ','); + if (separator == NULL) { + separator = end; + } + ptrdiff_t length = separator - current; + if (length == (sizeof("zba") - 1) && memcmp(current, "zba", length) == 0) { + collected_flags |= RV32_EXT_ZBA; + } else if (length == (sizeof("zcmp") - 1) && memcmp(current, "zcmp", length) == 0) { + collected_flags |= RV32_EXT_ZCMP; + } else { + return false; + } + current = separator + 1; + } + *flags = collected_flags; + return collected_flags != 0; +} +#endif + MP_NOINLINE int main_(int argc, char **argv) { pre_process_options(argc, argv); @@ -412,14 +440,11 @@ MP_NOINLINE int main_(int argc, char **argv) { if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_RV32IMC) { mp_dynamic_compiler.backend_options = (void *)&rv32_options; mp_uint_t raw_flags = 0; - if (parse_integer(arch_flags, &raw_flags)) { + if (parse_integer(arch_flags, &raw_flags) || parse_rv32_flags_string(arch_flags, &raw_flags)) { if ((raw_flags & ~((mp_uint_t)RV32_EXT_ALL)) == 0) { rv32_options.allowed_extensions = raw_flags; processed = true; } - } else if (strncmp(arch_flags, "zba", sizeof("zba") - 1) == 0) { - rv32_options.allowed_extensions |= RV32_EXT_ZBA; - processed = true; } } #endif diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index febd18cc2b059..9c23257260cae 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -28,6 +28,7 @@ #define MICROPY_ALLOC_PATH_MAX (PATH_MAX) #define MICROPY_PERSISTENT_CODE_LOAD (0) +#define MICROPY_PERSISTENT_CODE_LOAD_NATIVE (0) #define MICROPY_PERSISTENT_CODE_SAVE (1) #ifndef MICROPY_PERSISTENT_CODE_SAVE_FILE diff --git a/ports/alif/Makefile b/ports/alif/Makefile index d258b27b1d578..e7a4d2f104c72 100644 --- a/ports/alif/Makefile +++ b/ports/alif/Makefile @@ -82,17 +82,17 @@ $(BUILD): $(MKDIR) -p $@ $(BUILD)/M55_HP/firmware.bin: - make -f alif.mk BUILD=$(BUILD)/M55_HP MCU_CORE=M55_HP MICROPY_PY_OPENAMP_MODE=0 + $(MAKE) -f alif.mk BUILD=$(BUILD)/M55_HP MCU_CORE=M55_HP MICROPY_PY_OPENAMP_MODE=0 $(BUILD)/M55_HE/firmware.bin: - make -f alif.mk BUILD=$(BUILD)/M55_HE MCU_CORE=M55_HE MICROPY_PY_OPENAMP_MODE=1 + $(MAKE) -f alif.mk BUILD=$(BUILD)/M55_HE MCU_CORE=M55_HE MICROPY_PY_OPENAMP_MODE=1 $(BUILD)/$(ALIF_TOC_CONFIG): mcu/$(ALIF_TOC_CONFIG).in | $(BUILD) $(ECHO) "Preprocess toc config $@" $(Q)$(CPP) -P -E $(ALIF_TOC_CFLAGS) - < mcu/$(ALIF_TOC_CONFIG).in > $@ $(ALIF_TOC_BIN): $(ALIF_TOC_APPS) - $(Q)python $(ALIF_TOOLS)/app-gen-toc.py \ + $(Q)$(PYTHON) $(ALIF_TOOLS)/app-gen-toc.py \ --filename $(abspath $(BUILD)/$(ALIF_TOC_CONFIG)) \ --output-dir $(BUILD) \ --firmware-dir $(BUILD) \ @@ -105,7 +105,7 @@ $(BUILD)/firmware.zip: $(ALIF_TOC_BIN) $(ALIF_TOC_APPS) .PHONY: deploy deploy: $(ALIF_TOC_BIN) $(ECHO) "Writing $< to the board" - $(Q)python $(ALIF_TOOLS)/app-write-mram.py \ + $(Q)$(PYTHON) $(ALIF_TOOLS)/app-write-mram.py \ --cfg-part $(ALIF_TOOLKIT_CFG_PART) \ --port $(PORT) \ --pad \ @@ -117,13 +117,13 @@ deploy-jlink: $(ALIF_TOC_APPS) .PHONY: maintenance maintenance: - $(Q)python $(ALIF_TOOLS)/maintenance.py \ + $(Q)$(PYTHON) $(ALIF_TOOLS)/maintenance.py \ --cfg-part $(ALIF_TOOLKIT_CFG_PART) \ --port $(PORT) .PHONY: update-system-package update-system-package: - $(Q)python $(ALIF_TOOLS)/updateSystemPackage.py \ + $(Q)$(PYTHON) $(ALIF_TOOLS)/updateSystemPackage.py \ --cfg-part $(ALIF_TOOLKIT_CFG_PART) \ --port $(PORT) diff --git a/ports/alif/boards/OPENMV_AE3/board.ld.S b/ports/alif/boards/OPENMV_AE3/board.ld.S index 0d09bb15f874f..539e24b1de260 100644 --- a/ports/alif/boards/OPENMV_AE3/board.ld.S +++ b/ports/alif/boards/OPENMV_AE3/board.ld.S @@ -3,8 +3,8 @@ /* Define ROMFS partition locations. */ #if CORE_M55_HP /* The HP core has access to the external OSPI flash and MRAM ROMFS partitions. */ -_micropy_hw_romfs_part0_start = 0xa1000000; -_micropy_hw_romfs_part0_size = 16M; +_micropy_hw_romfs_part0_start = 0xa0800000; +_micropy_hw_romfs_part0_size = 24M; _micropy_hw_romfs_part1_start = ORIGIN(MRAM_FS); _micropy_hw_romfs_part1_size = LENGTH(MRAM_FS); #else diff --git a/ports/alif/boards/OPENMV_AE3/mpconfigboard.h b/ports/alif/boards/OPENMV_AE3/mpconfigboard.h index 0495bc81c8a62..a4981ce167e55 100644 --- a/ports/alif/boards/OPENMV_AE3/mpconfigboard.h +++ b/ports/alif/boards/OPENMV_AE3/mpconfigboard.h @@ -67,8 +67,8 @@ extern void board_exit_standby(void); // This is used for alif.Flash() and USB MSC. #define MICROPY_HW_FLASH_STORAGE_BASE_ADDR (0) #define MICROPY_HW_FLASH_STORAGE_BYTES (32 * 1024 * 1024) -#define MICROPY_HW_FLASH_STORAGE_FS_BYTES (16 * 1024 * 1024) -#define MICROPY_HW_FLASH_STORAGE_ROMFS_BYTES (16 * 1024 * 1024) +#define MICROPY_HW_FLASH_STORAGE_FS_BYTES (8 * 1024 * 1024) +#define MICROPY_HW_FLASH_STORAGE_ROMFS_BYTES (24 * 1024 * 1024) // Murata 1YN configuration #define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "lib/cyw43-driver/firmware/w43439_sdio_1yn_7_95_59_combined.h" diff --git a/ports/alif/boards/OPENMV_AE3/pins.csv b/ports/alif/boards/OPENMV_AE3/pins.csv index 360b27af813c5..9ebd3b726bdd8 100644 --- a/ports/alif/boards/OPENMV_AE3/pins.csv +++ b/ports/alif/boards/OPENMV_AE3/pins.csv @@ -55,6 +55,10 @@ P6,P7_2 P7,P7_3 P8,P1_2 P9,P1_3 +P10,P4_4 +P11,P4_7 +P13,P4_5 +P14,P4_6 # UART buses UART1_TX,P0_5 diff --git a/ports/alif/mcu/ensemble_pin_alt.csv b/ports/alif/mcu/ensemble_pin_alt.csv index 34f13e86f6d3c..751f8e4b60052 100644 --- a/ports/alif/mcu/ensemble_pin_alt.csv +++ b/ports/alif/mcu/ensemble_pin_alt.csv @@ -45,8 +45,7 @@ P5_2,GPIO,OSPI1_SCLKN,UART5_RX,PDM_C3,SPI0_SS0,LPI2C_SCL,UT1_T0,SD_D2 P5_3,GPIO,OSPI1_SCLK,UART5_TX,SPI0_SCLK,LPI2C_SDA,UT1_T1,SD_D3,CDC_PCLK P5_4,GPIO,OSPI1_SS1,UART3_CTS,PDM_D2,SPI0_SS3,UT2_T0,SD_D4,CDC_DE P5_5,GPIO,OSPI1_SCLK,UART3_RTS,PDM_D3,UT2_T1,SD_D5,ETH_RXD0,CDC_HSYNC -# P5_6 doesn't really have OSPI on AF1 but it's needed for P10_7 to be in OSPI1_RXDS mode -P5_6,GPIO,OSPI1_RXDS,UART1_CTS,I2C2_SCL,UT3_T0,SD_D6,ETH_RXD1,CDC_VSYNC +P5_6,GPIO,,UART1_CTS,I2C2_SCL,UT3_T0,SD_D6,ETH_RXD1,CDC_VSYNC P5_7,GPIO,OSPI1_SS0,UART1_RTS,I2C2_SDA,UT3_T1,SD_D7,ETH_RST, P6_0,GPIO,OSPI0_D0,UART4_DE,PDM_D0,UT4_T0,SD_D0,ETH_TXD0, P6_1,GPIO,OSPI0_D1,UART5_DE,PDM_C0,UT4_T1,SD_D1,ETH_TXD1, diff --git a/ports/alif/ospi_flash.c b/ports/alif/ospi_flash.c index f78002eb0ef97..64c2438c2f1f2 100644 --- a/ports/alif/ospi_flash.c +++ b/ports/alif/ospi_flash.c @@ -274,11 +274,6 @@ int ospi_flash_init(void) { if (pin->pin_rwds != NULL) { mp_hal_pin_config(pin->pin_rwds, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_HIGH, MP_HAL_PIN_DRIVE_12MA, MP_HAL_PIN_ALT(OSPI_RXDS, unit), true); - if (pin->pin_rwds->port == PORT_10 && pin->pin_rwds->pin == PIN_7) { - // Alif: P5_6 is needed to support proper alt function selection of P10_7. - mp_hal_pin_config(pin_P5_6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, - MP_HAL_PIN_SPEED_HIGH, MP_HAL_PIN_DRIVE_12MA, MP_HAL_PIN_ALT(OSPI_RXDS, unit), true); - } } mp_hal_pin_config(pin->pin_d0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_HIGH, MP_HAL_PIN_DRIVE_12MA, MP_HAL_PIN_ALT(OSPI_D0, unit), true); diff --git a/ports/cc3200/mods/pybpin.h b/ports/cc3200/mods/pybpin.h index 74f0af2b3ca65..5e55d2cf95a3b 100644 --- a/ports/cc3200/mods/pybpin.h +++ b/ports/cc3200/mods/pybpin.h @@ -88,7 +88,7 @@ enum { }; typedef struct { - qstr name; + qstr_short_t name; int8_t idx; uint8_t fn; uint8_t unit; diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index d0984127ce344..e767f96c29072 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -112,4 +112,4 @@ size-files: # This is done in a dedicated build directory as some CMake cache values are not # set correctly if not all submodules are loaded yet. submodules: - $(Q)IDF_COMPONENT_MANAGER=0 idf.py $(IDFPY_FLAGS) -B $(BUILD)/submodules -D UPDATE_SUBMODULES=1 reconfigure + $(Q)idf.py $(IDFPY_FLAGS) -B $(BUILD)/submodules -D UPDATE_SUBMODULES=1 reconfigure diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 5a2bb9240d932..b5cd1c2a8c6bb 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -5,16 +5,17 @@ This is a port of MicroPython to the Espressif ESP32 series of microcontrollers. It uses the ESP-IDF framework and MicroPython runs as a task under FreeRTOS. -Currently supports ESP32, ESP32-C2 (aka ESP8684), ESP32-C3, ESP32-C6, ESP32-S2 -and ESP32-S3 (ESP8266 is supported by a separate MicroPython port). +Currently supports ESP32, ESP32-C2 (aka ESP8684), ESP32-C3, ESP32-C5, ESP32-C6, +ESP32-P4, ESP32-S2 and ESP32-S3. ESP8266 is supported by a separate MicroPython port. Supported features include: -- REPL (Python prompt) over UART0. -- 16k stack for the MicroPython task and approximately 100k Python heap. +- REPL (Python prompt) over UART0 and/or the integrated USB peripheral. - Many of MicroPython's features are enabled: unicode, arbitrary-precision integers, single-precision floats, complex numbers, frozen bytecode, as well as many of the internal modules. -- Internal filesystem using the flash (currently 2M in size). +- Internal filesystem using the remaining flash area. +- Threading support via the _thread module (built on native FreeRTOS tasks), + with GIL enabled. - The machine module with GPIO, UART, SPI, software I2C, ADC, DAC, PWM, TouchPad, WDT and Timer. - The network module with WLAN (WiFi) support. @@ -22,6 +23,26 @@ Supported features include: Initial development of this ESP32 port was sponsored in part by Microbric Pty Ltd. +Choosing a suitable chip +------------------------ + +ESP32 chips are not all the same. The different ESP32 families have different +capabilities and resources available. In particular, the ESP32-C2 and ESP32-S2 +(without external SPIRAM) have the least RAM. They can still run MicroPython +well but may run out of RAM if a program uses a lot of resources, eg if it +needs many complex code modules, multiple TLS connections, large memory +buffers for a display, etc. + +ESP32 boards with external "SPIRAM" (also called PSRAM) have megabytes of RAM +available - significantly more than any board without external SPIRAM. SPIRAM is +supported on original ESP32, ESP32-S2 and ESP32-S3 chips. Not every ESP32 board +has SPIRAM included, even if the chip supports it. + +If you don't need particular hardware features but are looking for a board with +the usual Wi-Fi and BLE support, many peripherals and plenty of RAM then +recommend finding a board based on ESP32-S3 with SPIRAM included (usually 2MB, +4MB or 8MB). + Setting up ESP-IDF and the build environment -------------------------------------------- diff --git a/ports/esp32/boards/ESP32_GENERIC_C2/board.json b/ports/esp32/boards/ESP32_GENERIC_C2/board.json index c496396ef1aea..ab05c93881d0a 100644 --- a/ports/esp32/boards/ESP32_GENERIC_C2/board.json +++ b/ports/esp32/boards/ESP32_GENERIC_C2/board.json @@ -12,7 +12,7 @@ "WiFi" ], "images": [ - "esp32c2_devkitmini.jpg" + "esp8684_devkitc.jpg" ], "mcu": "esp32c2", "product": "ESP32-C2", diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/board.json b/ports/esp32/boards/ESP32_GENERIC_C5/board.json index 371da3929c52d..9ee69f0ba654a 100644 --- a/ports/esp32/boards/ESP32_GENERIC_C5/board.json +++ b/ports/esp32/boards/ESP32_GENERIC_C5/board.json @@ -12,7 +12,7 @@ "WiFi" ], "images": [ - "esp32c5_devkitmini.jpg" + "esp32c5_devkitc.jpg" ], "mcu": "esp32c5", "product": "ESP32-C5", diff --git a/ports/esp32/boards/ESP32_GENERIC_P4/board.json b/ports/esp32/boards/ESP32_GENERIC_P4/board.json new file mode 100644 index 0000000000000..480b4fbfd1d19 --- /dev/null +++ b/ports/esp32/boards/ESP32_GENERIC_P4/board.json @@ -0,0 +1,25 @@ +{ + "deploy": [ + "../deploy.md" + ], + "deploy_options": { + "flash_offset": "0x2000" + }, + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "images": [ + "esp32_p4_function_ev_board.jpg" + ], + "mcu": "esp32p4", + "product": "ESP32-P4", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "variants": { + "C5_WIFI": "Support for external C5 WiFi/BLE", + "C6_WIFI": "Support for external C6 WiFi/BLE" + }, + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/ESP32_GENERIC_P4/board.md b/ports/esp32/boards/ESP32_GENERIC_P4/board.md new file mode 100644 index 0000000000000..29f72832aa62a --- /dev/null +++ b/ports/esp32/boards/ESP32_GENERIC_P4/board.md @@ -0,0 +1,11 @@ +The following firmware is applicable to most development boards based on ESP32-P4, and +the development boards must be equipped with at least 16 MiB external SPI Flash. + +This board has multiple variants available: + +* If your board has a standalone ESP32-P4 processor (or the board has a coprocessor but + you do not want to use it) then choose the generic variant (first heading below). +* If your board has an external ESP32-C5 coprocessor for WiFi and BLE then choose the + "C5 WiFi/BLE" variant. +* If your board has an external ESP32-C6 coprocessor for WiFi and BLE then choose the + "C6 WiFi/BLE" variant. diff --git a/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigboard.cmake new file mode 100644 index 0000000000000..876a186decc76 --- /dev/null +++ b/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigboard.cmake @@ -0,0 +1,6 @@ +set(IDF_TARGET esp32p4) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.p4 +) diff --git a/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigboard.h b/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigboard.h new file mode 100644 index 0000000000000..b7a887848028f --- /dev/null +++ b/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigboard.h @@ -0,0 +1,31 @@ +// Both of these can be set by mpconfigboard.cmake if a BOARD_VARIANT is +// specified. + +#ifndef MICROPY_HW_BOARD_NAME +#define MICROPY_HW_BOARD_NAME "Generic ESP32P4 module" +#endif + +#ifndef MICROPY_HW_MCU_NAME +#define MICROPY_HW_MCU_NAME "ESP32P4" +#endif + +#define MICROPY_PY_ESPNOW (0) + +#define MICROPY_HW_ENABLE_SDCARD (1) + +#ifndef USB_SERIAL_JTAG_PACKET_SZ_BYTES +#define USB_SERIAL_JTAG_PACKET_SZ_BYTES (64) +#endif + +// Enable UART REPL for modules that have an external USB-UART and don't use native USB. +#define MICROPY_HW_ENABLE_UART_REPL (1) + +#define MICROPY_PY_MACHINE_I2S (1) + +// Disable Wi-Fi and Bluetooth by default, these are re-enabled in the WIFI variants +#ifndef MICROPY_PY_NETWORK_WLAN +#define MICROPY_PY_NETWORK_WLAN (0) +#endif +#ifndef MICROPY_PY_BLUETOOTH +#define MICROPY_PY_BLUETOOTH (0) +#endif diff --git a/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigvariant_C5_WIFI.cmake b/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigvariant_C5_WIFI.cmake new file mode 100644 index 0000000000000..507ed2ccc56d1 --- /dev/null +++ b/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigvariant_C5_WIFI.cmake @@ -0,0 +1,14 @@ +set(IDF_TARGET esp32p4) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.p4 + boards/sdkconfig.p4_wifi_common + boards/sdkconfig.p4_wifi_c5 +) + +list(APPEND MICROPY_DEF_BOARD + MICROPY_HW_BOARD_NAME="Generic ESP32P4 module with WIFI module of external ESP32C5" + MICROPY_PY_NETWORK_WLAN=1 + MICROPY_PY_BLUETOOTH=1 +) diff --git a/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigvariant_C6_WIFI.cmake b/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigvariant_C6_WIFI.cmake new file mode 100644 index 0000000000000..36de6d1bf70e1 --- /dev/null +++ b/ports/esp32/boards/ESP32_GENERIC_P4/mpconfigvariant_C6_WIFI.cmake @@ -0,0 +1,14 @@ +set(IDF_TARGET esp32p4) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.p4 + boards/sdkconfig.p4_wifi_common + boards/sdkconfig.p4_wifi_c6 +) + +list(APPEND MICROPY_DEF_BOARD + MICROPY_HW_BOARD_NAME="Generic ESP32P4 module with WIFI module of external ESP32C6" + MICROPY_PY_NETWORK_WLAN=1 + MICROPY_PY_BLUETOOTH=1 +) diff --git a/ports/esp32/boards/ESP32_GENERIC_S3/board.json b/ports/esp32/boards/ESP32_GENERIC_S3/board.json index 7a546d35fcd4f..b383dfa068a58 100644 --- a/ports/esp32/boards/ESP32_GENERIC_S3/board.json +++ b/ports/esp32/boards/ESP32_GENERIC_S3/board.json @@ -22,5 +22,8 @@ "vendor": "Espressif", "variants": { "SPIRAM_OCT": "Support for Octal-SPIRAM" + }, + "old_variants": { + "FLASH_4M": ["4MiB flash", "Use the standard variant instead."] } } diff --git a/ports/esp32/boards/SOLDERED_NULA_MINI/board.json b/ports/esp32/boards/SOLDERED_NULA_MINI/board.json new file mode 100644 index 0000000000000..85b12e98df2ff --- /dev/null +++ b/ports/esp32/boards/SOLDERED_NULA_MINI/board.json @@ -0,0 +1,23 @@ +{ + "deploy": [ + "../deploy.md" + ], + "deploy_options": { + "flash_offset": "0" + }, + "docs": "", + "features": [ + "BLE", + "WiFi", + "USB-C", + "JST-PH" + ], + "images": [ + "soldered-nula-mini-esp32c6.jpg" + ], + "mcu": "esp32c6", + "product": "NULA Mini", + "thumbnail": "", + "url": "https://soldered.com/product/nula-mini-esp32-c6/", + "vendor": "Soldered Electronics" +} diff --git a/ports/esp32/boards/SOLDERED_NULA_MINI/mpconfigboard.cmake b/ports/esp32/boards/SOLDERED_NULA_MINI/mpconfigboard.cmake new file mode 100644 index 0000000000000..48946f7094530 --- /dev/null +++ b/ports/esp32/boards/SOLDERED_NULA_MINI/mpconfigboard.cmake @@ -0,0 +1,8 @@ +set(IDF_TARGET esp32c6) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.riscv + boards/sdkconfig.c6 + boards/sdkconfig.ble +) diff --git a/ports/esp32/boards/SOLDERED_NULA_MINI/mpconfigboard.h b/ports/esp32/boards/SOLDERED_NULA_MINI/mpconfigboard.h new file mode 100644 index 0000000000000..658919eaf4f3a --- /dev/null +++ b/ports/esp32/boards/SOLDERED_NULA_MINI/mpconfigboard.h @@ -0,0 +1,10 @@ +// This configuration is for a generic ESP32C6 board with 4MiB (or more) of flash. + +#define MICROPY_HW_BOARD_NAME "Soldered NULA Mini" +#define MICROPY_HW_MCU_NAME "ESP32C6" + +// Enable UART REPL for modules that have an external USB-UART and don't use native USB. +#define MICROPY_HW_ENABLE_UART_REPL (1) + +#define MICROPY_HW_I2C0_SCL (7) +#define MICROPY_HW_I2C0_SDA (6) diff --git a/ports/esp32/boards/SOLDERED_NULA_MINI/pins.csv b/ports/esp32/boards/SOLDERED_NULA_MINI/pins.csv new file mode 100644 index 0000000000000..1ed8bbd91ce80 --- /dev/null +++ b/ports/esp32/boards/SOLDERED_NULA_MINI/pins.csv @@ -0,0 +1,7 @@ +IO2,GPIO2 +IO3,GPIO3 +IO4,GPIO4 +IO5,GPIO5 +IO18,GPIO18 +IO19,GPIO19 +USER_BUTTON,GPIO9 diff --git a/ports/esp32/boards/make-pins.py b/ports/esp32/boards/make-pins.py index 49b10f0ce15c9..c7375e67d66bb 100755 --- a/ports/esp32/boards/make-pins.py +++ b/ports/esp32/boards/make-pins.py @@ -7,8 +7,8 @@ import boardgen -# Pins start at zero, and the highest pin index on any ESP32* chip is 48. -NUM_GPIOS = 49 +# Pins start at zero, and the highest pin index on any ESP32* chip is 54. +NUM_GPIOS = 55 class Esp32Pin(boardgen.Pin): diff --git a/ports/esp32/boards/sdkconfig.p4 b/ports/esp32/boards/sdkconfig.p4 new file mode 100644 index 0000000000000..042eec40cf7f8 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.p4 @@ -0,0 +1,18 @@ +# Select the minimum chip revision to cover all possible boards. +CONFIG_ESP32P4_REV_MIN_0=y + +# Flash +CONFIG_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y + +# Memory +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MEMTEST= +CONFIG_SPIRAM_IGNORE_NOTFOUND=y +CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC=y +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=50768 + +# ULP: not fixed +CONFIG_SOC_ULP_SUPPORTED=n +CONFIG_ULP_COPROC_ENABLED=n +CONFIG_ULP_COPROC_TYPE_FSM=n diff --git a/ports/esp32/boards/sdkconfig.p4_wifi_c5 b/ports/esp32/boards/sdkconfig.p4_wifi_c5 new file mode 100644 index 0000000000000..bee529f9b13e3 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.p4_wifi_c5 @@ -0,0 +1,2 @@ +# Most settings are in sdkconfig.p4_wifi_common +CONFIG_SLAVE_IDF_TARGET_ESP32C5=y diff --git a/ports/esp32/boards/sdkconfig.p4_wifi_c6 b/ports/esp32/boards/sdkconfig.p4_wifi_c6 new file mode 100644 index 0000000000000..4a80725c53dc9 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.p4_wifi_c6 @@ -0,0 +1,2 @@ +# Most settings are in sdkconfig.p4_wifi_common +CONFIG_SLAVE_IDF_TARGET_ESP32C6=y diff --git a/ports/esp32/boards/sdkconfig.p4_wifi_common b/ports/esp32/boards/sdkconfig.p4_wifi_common new file mode 100644 index 0000000000000..a55e941ba6847 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.p4_wifi_common @@ -0,0 +1,59 @@ +# This sdkconfig file has the common settings for an ESP32-P4 +# host with an external ESP-Hosted Wi-Fi/BT interface. + +# Wifi +CONFIG_ESP_HOSTED_ENABLED=y +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64 +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64 +CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP_WIFI_TX_BA_WIN=32 +CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP_WIFI_RX_BA_WIN=32 + +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65534 +CONFIG_LWIP_TCP_WND_DEFAULT=65534 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=64 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=64 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64 + +CONFIG_LWIP_TCP_SACK_OUT=y + +# Bluetooth Support +CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID=y +CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE=y +CONFIG_ESP_HOSTED_NIMBLE_HCI_VHCI=y +CONFIG_ESP_WIFI_REMOTE_ENABLED=y +CONFIG_SLAVE_SOC_WIFI_SUPPORTED=y +CONFIG_SLAVE_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SLAVE_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SLAVE_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SLAVE_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH=12 +CONFIG_SLAVE_SOC_WIFI_HW_TSF=y +CONFIG_SLAVE_SOC_WIFI_FTM_SUPPORT=y +CONFIG_SLAVE_FREERTOS_UNICORE=y +CONFIG_SLAVE_SOC_WIFI_GCMP_SUPPORT=y +CONFIG_SLAVE_IDF_TARGET_ARCH_RISCV=y +CONFIG_SLAVE_SOC_WIFI_HE_SUPPORT=y +CONFIG_SLAVE_SOC_WIFI_MAC_VERSION_NUM=2 +CONFIG_ESP_WIFI_REMOTE_LIBRARY_HOSTED=y + +CONFIG_ESP_HOSTED_P4_DEV_BOARD_FUNC_BOARD=y + +# BLE +CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE=y +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_CONTROLLER_DISABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_TRANSPORT_UART=n +CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR=y + +CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="MPY ESP32" +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 + +CONFIG_BT_HCI_LOG_DEBUG_EN=y + +# Increase NimBLE task stack size from the default, because Python code +# (BLE IRQ handlers) will most likely run on this task. +CONFIG_BT_NIMBLE_TASK_STACK_SIZE=6144 diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake index 807d712830af2..ea60c395a7665 100644 --- a/ports/esp32/esp32_common.cmake +++ b/ports/esp32/esp32_common.cmake @@ -23,7 +23,7 @@ if(CONFIG_IDF_TARGET_ARCH_RISCV) endif() if(NOT DEFINED MICROPY_PY_TINYUSB) - if(CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3) + if(CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3 OR CONFIG_IDF_TARGET_ESP32P4) set(MICROPY_PY_TINYUSB ON) endif() endif() @@ -166,7 +166,9 @@ list(APPEND IDF_COMPONENTS driver esp_adc esp_app_format + esp_mm esp_common + esp_driver_touch_sens esp_eth esp_event esp_hw_support @@ -242,7 +244,11 @@ set(MICROPY_TARGET ${COMPONENT_TARGET}) if(CONFIG_IDF_TARGET_ARCH_XTENSA) set(MICROPY_CROSS_FLAGS -march=xtensawin) elseif(CONFIG_IDF_TARGET_ARCH_RISCV) - set(MICROPY_CROSS_FLAGS -march=rv32imc) + if (CONFIG_IDF_TARGET_ESP32P4) + set(MICROPY_CROSS_FLAGS "-march=rv32imc -march-flags=zcmp") + else() + set(MICROPY_CROSS_FLAGS -march=rv32imc) + endif() endif() # Set compile options for this port. diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c index 85a98c2910bac..8b77e2ac6fa63 100644 --- a/ports/esp32/esp32_rmt.c +++ b/ports/esp32/esp32_rmt.c @@ -193,14 +193,13 @@ static void esp32_rmt_deactivate(esp32_rmt_obj_t *self) { if (self->enabled) { // FIXME: panics in ESP32 if called while TX is ongoing and TX sequence is long (>300ms) // Does not panic in ESP32-S3, ESP32-C3 and ESP32-C6. - // Tested with ESP-IDF up to 5.5 - // ESP-IDF issue: https://github.com/espressif/esp-idf/issues/17692 + // Happens with ESP-IDF up to 5.5.1. Fixed in ESP-IDF 5.5.2. + // ESP-IDF GitHub issue: https://github.com/espressif/esp-idf/issues/17692 // - // Cause is Interrupt WDT to trigger because ESP-IDF rmt_disable() disables - // interrupts and spinlocks until the ongoing TX sequence is finished. - // - // Workaround is never try to stop RMT sequences longer than 300ms (which are unusual - // anyway). Or apply the patch mentioned at the GitHub issue to ESP-IDF. + // Workarounds: + // - recompile with ESP-IDF 5.5.2 or better + // - never try to stop RMT sequences longer than 300ms + // - apply to ESP-IDF the patch mentioned at the GitHub issue rmt_disable(self->channel); self->enabled = false; } diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32 b/ports/esp32/lockfiles/dependencies.lock.esp32 index 4b0b2d9729d85..8ba25c77011c2 100644 --- a/ports/esp32/lockfiles/dependencies.lock.esp32 +++ b/ports/esp32/lockfiles/dependencies.lock.esp32 @@ -30,6 +30,6 @@ direct_dependencies: - espressif/lan867x - espressif/mdns - idf -manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3 +manifest_hash: 482087bc40f0e187795a9ef9ad08ef15a585b4cdabc296c715a9d19284622150 target: esp32 version: 2.0.0 diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c2 b/ports/esp32/lockfiles/dependencies.lock.esp32c2 index 5c5cea0c9a189..8a366af342369 100644 --- a/ports/esp32/lockfiles/dependencies.lock.esp32c2 +++ b/ports/esp32/lockfiles/dependencies.lock.esp32c2 @@ -16,6 +16,6 @@ dependencies: direct_dependencies: - espressif/mdns - idf -manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3 +manifest_hash: 482087bc40f0e187795a9ef9ad08ef15a585b4cdabc296c715a9d19284622150 target: esp32c2 version: 2.0.0 diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c3 b/ports/esp32/lockfiles/dependencies.lock.esp32c3 index 4c4c869c27ea3..3aa99692d9f35 100644 --- a/ports/esp32/lockfiles/dependencies.lock.esp32c3 +++ b/ports/esp32/lockfiles/dependencies.lock.esp32c3 @@ -16,6 +16,6 @@ dependencies: direct_dependencies: - espressif/mdns - idf -manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3 +manifest_hash: 482087bc40f0e187795a9ef9ad08ef15a585b4cdabc296c715a9d19284622150 target: esp32c3 version: 2.0.0 diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c5 b/ports/esp32/lockfiles/dependencies.lock.esp32c5 index 6f24d013470eb..2fb130b8e5282 100644 --- a/ports/esp32/lockfiles/dependencies.lock.esp32c5 +++ b/ports/esp32/lockfiles/dependencies.lock.esp32c5 @@ -16,6 +16,6 @@ dependencies: direct_dependencies: - espressif/mdns - idf -manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3 +manifest_hash: 482087bc40f0e187795a9ef9ad08ef15a585b4cdabc296c715a9d19284622150 target: esp32c5 version: 2.0.0 diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c6 b/ports/esp32/lockfiles/dependencies.lock.esp32c6 index b7435e1076718..c81806909a631 100644 --- a/ports/esp32/lockfiles/dependencies.lock.esp32c6 +++ b/ports/esp32/lockfiles/dependencies.lock.esp32c6 @@ -16,6 +16,6 @@ dependencies: direct_dependencies: - espressif/mdns - idf -manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3 +manifest_hash: 482087bc40f0e187795a9ef9ad08ef15a585b4cdabc296c715a9d19284622150 target: esp32c6 version: 2.0.0 diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32p4 b/ports/esp32/lockfiles/dependencies.lock.esp32p4 new file mode 100644 index 0000000000000..aea6ec2cc3607 --- /dev/null +++ b/ports/esp32/lockfiles/dependencies.lock.esp32p4 @@ -0,0 +1,93 @@ +dependencies: + espressif/eppp_link: + component_hash: 41f6519edda527ec6a0553c872ebaf8fc6d3812523c9d4c8d1660ad21c720abe + dependencies: + - name: espressif/esp_serial_slave_link + registry_url: https://components.espressif.com + require: private + version: ^1.1.0 + - name: idf + require: private + version: '>=5.2' + source: + registry_url: https://components.espressif.com + type: service + version: 1.1.3 + espressif/esp_hosted: + component_hash: 53544436deb5fcbfdbf4a8e2c643cdbe31126556781784278c016d674df99cd2 + dependencies: + - name: idf + require: private + version: '>=5.3' + source: + registry_url: https://components.espressif.com/ + type: service + version: 2.7.0 + espressif/esp_serial_slave_link: + component_hash: ac1776806de0a6e371c84e87898bb983e19ce62aa7f1e2e5c4a3b0234a575d2c + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com + type: service + version: 1.1.2 + espressif/esp_wifi_remote: + component_hash: 4ed1ebe454d63ddb4a91bbd8db74a6f883c85a863db1f79770c57fbd2e5c134c + dependencies: + - name: espressif/eppp_link + registry_url: https://components.espressif.com + require: private + version: '>=0.1' + - name: espressif/esp_hosted + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32h2, esp32p4] + version: '>=0.0.6' + - name: idf + require: private + version: '>=5.3' + source: + registry_url: https://components.espressif.com/ + type: service + version: 0.15.2 + espressif/mdns: + component_hash: 46ee81d32fbf850462d8af1e83303389602f6a6a9eddd2a55104cb4c063858ed + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.1.0 + espressif/tinyusb: + component_hash: ee1c962cff61eb975d508258d509974d58031cc27ff0d6c4117a67a613a49594 + dependencies: + - name: idf + version: '>=5.0' + source: + git: https://github.com/micropython/tinyusb-espressif.git + path: . + type: git + targets: + - esp32s2 + - esp32s3 + - esp32p4 + - esp32h4 + version: e4c0ec3caab3d9c25374de7047653b9ced8f14ff + idf: + source: + type: idf + version: 5.5.1 +direct_dependencies: +- espressif/esp_hosted +- espressif/esp_wifi_remote +- espressif/mdns +- espressif/tinyusb +- idf +manifest_hash: 482087bc40f0e187795a9ef9ad08ef15a585b4cdabc296c715a9d19284622150 +target: esp32p4 +version: 2.0.0 diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32s2 b/ports/esp32/lockfiles/dependencies.lock.esp32s2 index a13d9fd401d47..8717181c10ac7 100644 --- a/ports/esp32/lockfiles/dependencies.lock.esp32s2 +++ b/ports/esp32/lockfiles/dependencies.lock.esp32s2 @@ -32,6 +32,6 @@ direct_dependencies: - espressif/mdns - espressif/tinyusb - idf -manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3 +manifest_hash: 482087bc40f0e187795a9ef9ad08ef15a585b4cdabc296c715a9d19284622150 target: esp32s2 version: 2.0.0 diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32s3 b/ports/esp32/lockfiles/dependencies.lock.esp32s3 index d5e7045b77a69..0b8b8e92bd57b 100644 --- a/ports/esp32/lockfiles/dependencies.lock.esp32s3 +++ b/ports/esp32/lockfiles/dependencies.lock.esp32s3 @@ -32,6 +32,6 @@ direct_dependencies: - espressif/mdns - espressif/tinyusb - idf -manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3 +manifest_hash: 482087bc40f0e187795a9ef9ad08ef15a585b4cdabc296c715a9d19284622150 target: esp32s3 version: 2.0.0 diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c index 432df3d3a20e6..ff80762ebd7d8 100644 --- a/ports/esp32/machine_adc.c +++ b/ports/esp32/machine_adc.c @@ -136,6 +136,21 @@ static const machine_adc_obj_t madc_obj[] = { {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_7, GPIO_NUM_18}, {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_8, GPIO_NUM_19}, {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_9, GPIO_NUM_20}, + #elif CONFIG_IDF_TARGET_ESP32P4 + {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_0, GPIO_NUM_16}, + {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_1, GPIO_NUM_17}, + {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_2, GPIO_NUM_18}, + {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_3, GPIO_NUM_19}, + {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_4, GPIO_NUM_20}, + {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_5, GPIO_NUM_21}, + {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_6, GPIO_NUM_22}, + {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_7, GPIO_NUM_23}, + {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_0, GPIO_NUM_49}, + {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_1, GPIO_NUM_50}, + {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_2, GPIO_NUM_51}, + {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_3, GPIO_NUM_52}, + {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_4, GPIO_NUM_53}, + {{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_5, GPIO_NUM_54}, #endif }; diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index dcf8b3942a70b..aea6bd00fe890 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -73,6 +73,10 @@ #define MICROPY_HW_SPI2_SCK (36) #define MICROPY_HW_SPI2_MOSI (35) #define MICROPY_HW_SPI2_MISO (37) +#elif CONFIG_IDF_TARGET_ESP32P4 +#define MICROPY_HW_SPI2_SCK (43) +#define MICROPY_HW_SPI2_MOSI (44) +#define MICROPY_HW_SPI2_MISO (39) #endif #endif diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index efe6733194cbf..74ee15a24acce 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -55,6 +55,8 @@ #define GPIO_FIRST_NON_OUTPUT (34) #elif CONFIG_IDF_TARGET_ESP32S2 #define GPIO_FIRST_NON_OUTPUT (46) +#elif CONFIG_IDF_TARGET_ESP32P4 +#define GPIO_FIRST_NON_OUTPUT (54) #endif // Return the gpio_num_t index for a given machine_pin_obj_t pointer. diff --git a/ports/esp32/machine_pin.h b/ports/esp32/machine_pin.h index 9e247a7367f0c..c63630eb85daf 100644 --- a/ports/esp32/machine_pin.h +++ b/ports/esp32/machine_pin.h @@ -49,7 +49,7 @@ #define MICROPY_HW_ENABLE_GPIO13 (1) #define MICROPY_HW_ENABLE_GPIO14 (1) #define MICROPY_HW_ENABLE_GPIO15 (1) -#if !CONFIG_ESP32_SPIRAM_SUPPORT +#if !CONFIG_SPIRAM #define MICROPY_HW_ENABLE_GPIO16 (1) #define MICROPY_HW_ENABLE_GPIO17 (1) #endif @@ -216,6 +216,66 @@ #define MICROPY_HW_ENABLE_GPIO47 (1) #define MICROPY_HW_ENABLE_GPIO48 (1) #endif +#elif CONFIG_IDF_TARGET_ESP32P4 +#define MICROPY_HW_ENABLE_GPIO0 (1) +#define MICROPY_HW_ENABLE_GPIO1 (1) +#define MICROPY_HW_ENABLE_GPIO2 (1) +#define MICROPY_HW_ENABLE_GPIO3 (1) +#define MICROPY_HW_ENABLE_GPIO4 (1) +#define MICROPY_HW_ENABLE_GPIO5 (1) +#define MICROPY_HW_ENABLE_GPIO6 (1) +#define MICROPY_HW_ENABLE_GPIO7 (1) +#define MICROPY_HW_ENABLE_GPIO8 (1) +#define MICROPY_HW_ENABLE_GPIO9 (1) +#define MICROPY_HW_ENABLE_GPIO10 (1) +#define MICROPY_HW_ENABLE_GPIO11 (1) +#define MICROPY_HW_ENABLE_GPIO12 (1) +#define MICROPY_HW_ENABLE_GPIO13 (1) +#define MICROPY_HW_ENABLE_GPIO14 (1) +#define MICROPY_HW_ENABLE_GPIO15 (1) +#define MICROPY_HW_ENABLE_GPIO16 (1) +#define MICROPY_HW_ENABLE_GPIO17 (1) +#define MICROPY_HW_ENABLE_GPIO18 (1) +#define MICROPY_HW_ENABLE_GPIO19 (1) +#define MICROPY_HW_ENABLE_GPIO20 (1) +#define MICROPY_HW_ENABLE_GPIO21 (1) +#define MICROPY_HW_ENABLE_GPIO22 (1) +#define MICROPY_HW_ENABLE_GPIO23 (1) +#if !MICROPY_HW_ESP_USB_SERIAL_JTAG +// Note: ESP32-P4 can switch USJ to 26/27 instead, but +// this isn't supported +#define MICROPY_HW_ENABLE_GPIO24 (1) +#define MICROPY_HW_ENABLE_GPIO25 (1) +#endif +#define MICROPY_HW_ENABLE_GPIO26 (1) +#define MICROPY_HW_ENABLE_GPIO27 (1) +#define MICROPY_HW_ENABLE_GPIO28 (1) +#define MICROPY_HW_ENABLE_GPIO29 (1) +#define MICROPY_HW_ENABLE_GPIO30 (1) +#define MICROPY_HW_ENABLE_GPIO31 (1) +#define MICROPY_HW_ENABLE_GPIO32 (1) +#define MICROPY_HW_ENABLE_GPIO33 (1) +#define MICROPY_HW_ENABLE_GPIO34 (1) +#define MICROPY_HW_ENABLE_GPIO35 (1) +#define MICROPY_HW_ENABLE_GPIO36 (1) +#define MICROPY_HW_ENABLE_GPIO37 (1) +#define MICROPY_HW_ENABLE_GPIO38 (1) +#define MICROPY_HW_ENABLE_GPIO39 (1) +#define MICROPY_HW_ENABLE_GPIO40 (1) +#define MICROPY_HW_ENABLE_GPIO41 (1) +#define MICROPY_HW_ENABLE_GPIO42 (1) +#define MICROPY_HW_ENABLE_GPIO43 (1) +#define MICROPY_HW_ENABLE_GPIO44 (1) +#define MICROPY_HW_ENABLE_GPIO45 (1) +#define MICROPY_HW_ENABLE_GPIO46 (1) +#define MICROPY_HW_ENABLE_GPIO47 (1) +#define MICROPY_HW_ENABLE_GPIO48 (1) +#define MICROPY_HW_ENABLE_GPIO49 (1) +#define MICROPY_HW_ENABLE_GPIO50 (1) +#define MICROPY_HW_ENABLE_GPIO51 (1) +#define MICROPY_HW_ENABLE_GPIO52 (1) +#define MICROPY_HW_ENABLE_GPIO53 (1) +#define MICROPY_HW_ENABLE_GPIO54 (1) #endif diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c index 0f8bd844692b4..4785a7254a865 100644 --- a/ports/esp32/machine_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -166,6 +166,8 @@ static esp_err_t sdcard_ensure_card_init(sdcard_card_obj_t *self, bool force) { esp_err_t err = sdmmc_card_init(&(self->host), &(self->card)); if (err == ESP_OK) { + // Ensure card's host structure has the correct slot after init + self->card.host.slot = self->host.slot; self->flags |= SDCARD_CARD_FLAGS_CARD_INIT_DONE; } else { self->flags &= ~SDCARD_CARD_FLAGS_CARD_INIT_DONE; @@ -307,6 +309,7 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args else { sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT(); _temp_host.max_freq_khz = freq / 1000; + _temp_host.slot = slot_num; self->host = _temp_host; } #endif diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c index ea9ce5469b0b7..b9cd80f48efed 100644 --- a/ports/esp32/machine_timer.c +++ b/ports/esp32/machine_timer.c @@ -47,6 +47,9 @@ #define TIMER_FLAGS 0 +#if CONFIG_IDF_TARGET_ESP32P4 +static uint8_t __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused)); +#endif const mp_obj_type_t machine_timer_type; static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c index 299c489f5a831..88b34d64ff070 100644 --- a/ports/esp32/machine_touchpad.c +++ b/ports/esp32/machine_touchpad.c @@ -41,8 +41,11 @@ #if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 only #include "driver/touch_pad.h" -#elif SOC_TOUCH_SENSOR_VERSION == 2 // All other SoCs with touch, to date +#elif SOC_TOUCH_SENSOR_VERSION == 2 // most ESP32 #include "driver/touch_sensor.h" +#elif SOC_TOUCH_SENSOR_VERSION == 3 // At present, it can only be used on ESP32P4. +#include "driver/touch_sens.h" +#include "soc/touch_sensor_channel.h" #else #error "Unknown touch hardware version" #endif @@ -50,9 +53,18 @@ typedef struct _mtp_obj_t { mp_obj_base_t base; gpio_num_t gpio_id; + #if SOC_TOUCH_SENSOR_VERSION == 1 || SOC_TOUCH_SENSOR_VERSION == 2 touch_pad_t touchpad_id; + #elif SOC_TOUCH_SENSOR_VERSION == 3 + int touchpad_id; + #endif } mtp_obj_t; +#if SOC_TOUCH_SENSOR_VERSION == 3 +static touch_sensor_handle_t touch_sens_handle; +static touch_channel_handle_t touch_chan_handle[15]; +#endif + static const mtp_obj_t touchpad_obj[] = { #if CONFIG_IDF_TARGET_ESP32 {{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM0}, @@ -80,6 +92,21 @@ static const mtp_obj_t touchpad_obj[] = { {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM12}, {{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM13}, {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM14}, + #elif CONFIG_IDF_TARGET_ESP32P4 + {{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_GPIO2_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_3, TOUCH_PAD_GPIO3_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_GPIO4_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_5, TOUCH_PAD_GPIO5_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_6, TOUCH_PAD_GPIO6_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_7, TOUCH_PAD_GPIO7_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_8, TOUCH_PAD_GPIO8_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_9, TOUCH_PAD_GPIO9_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_10, TOUCH_PAD_GPIO10_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_11, TOUCH_PAD_GPIO11_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_GPIO12_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_GPIO13_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_GPIO14_CHANNEL}, + {{&machine_touchpad_type}, GPIO_NUM_15, TOUCH_PAD_GPIO15_CHANNEL}, #else #error "Please add GPIO mapping for this SoC" #endif @@ -102,14 +129,45 @@ static mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ static int initialized = 0; if (!initialized) { + #if SOC_TOUCH_SENSOR_VERSION == 1 || SOC_TOUCH_SENSOR_VERSION == 2 touch_pad_init(); touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); + #elif SOC_TOUCH_SENSOR_VERSION == 3 + touch_sensor_sample_config_t sample_cfg[1] = { + TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(1, 1, 1), + }; + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(1, sample_cfg); + check_esp_err(touch_sensor_new_controller(&sens_cfg, &touch_sens_handle)); + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + check_esp_err(touch_sensor_config_filter(touch_sens_handle, &filter_cfg)); + #endif initialized = 1; } + #if SOC_TOUCH_SENSOR_VERSION == 3 + else { + // Stop the touch controller so a new channel can be added. + check_esp_err(touch_sensor_stop_continuous_scanning(touch_sens_handle)); + check_esp_err(touch_sensor_disable(touch_sens_handle)); + } + #endif #if SOC_TOUCH_SENSOR_VERSION == 1 esp_err_t err = touch_pad_config(self->touchpad_id, 0); #elif SOC_TOUCH_SENSOR_VERSION == 2 esp_err_t err = touch_pad_config(self->touchpad_id); + #elif SOC_TOUCH_SENSOR_VERSION == 3 + touch_channel_config_t chan_cfg = { + .active_thresh = {1000}, + }; + esp_err_t err = ESP_OK; + if (touch_chan_handle[self->touchpad_id] != NULL) { + err = touch_sensor_del_channel(touch_chan_handle[self->touchpad_id]); + touch_chan_handle[self->touchpad_id] = NULL; + } + if (err == ESP_OK) { + err = touch_sensor_new_channel(touch_sens_handle, self->touchpad_id, &chan_cfg, &touch_chan_handle[self->touchpad_id]); + } + check_esp_err(touch_sensor_enable(touch_sens_handle)); + check_esp_err(touch_sensor_start_continuous_scanning(touch_sens_handle)); #endif if (err == ESP_OK) { #if SOC_TOUCH_SENSOR_VERSION == 2 @@ -121,6 +179,7 @@ static mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_raise_ValueError(MP_ERROR_TEXT("Touch pad error")); } +#if SOC_TOUCH_SENSOR_VERSION == 1 || SOC_TOUCH_SENSOR_VERSION == 2 static mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) { mtp_obj_t *self = self_in; #if SOC_TOUCH_SENSOR_VERSION == 1 @@ -135,6 +194,7 @@ static mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) { mp_raise_ValueError(MP_ERROR_TEXT("Touch pad error")); } MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config); +#endif static mp_obj_t mtp_read(mp_obj_t self_in) { mtp_obj_t *self = self_in; @@ -144,6 +204,9 @@ static mp_obj_t mtp_read(mp_obj_t self_in) { #elif SOC_TOUCH_SENSOR_VERSION == 2 uint32_t value; esp_err_t err = touch_pad_read_raw_data(self->touchpad_id, &value); + #elif SOC_TOUCH_SENSOR_VERSION == 3 + uint32_t value; + esp_err_t err = touch_channel_read_data(touch_chan_handle[self->touchpad_id], TOUCH_CHAN_DATA_TYPE_SMOOTH, &value); #endif if (err == ESP_OK) { return MP_OBJ_NEW_SMALL_INT(value); @@ -154,7 +217,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(mtp_read_obj, mtp_read); static const mp_rom_map_elem_t mtp_locals_dict_table[] = { // instance methods + #if SOC_TOUCH_SENSOR_VERSION == 1 || SOC_TOUCH_SENSOR_VERSION == 2 { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&mtp_config_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mtp_read_obj) }, }; diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index ea403f4221835..4a0782f7443b5 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -278,8 +278,14 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, self->tx = UART_PIN_NO_CHANGE; // GPIO 1 break; case UART_NUM_1: + #if CONFIG_IDF_TARGET_ESP32 && CONFIG_SPIRAM + // ESP32 usually uses pins 9 and 10 for SPIRAM bus, so avoid those pins as defaults. + self->rx = 4; + self->tx = 5; + #else self->rx = 9; self->tx = 10; + #endif break; #if SOC_UART_HP_NUM > 2 case UART_NUM_2: @@ -293,6 +299,14 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, self->tx = 5; break; #endif + #if SOC_UART_HP_NUM > 3 + case UART_NUM_3: + break; + #endif + #if SOC_UART_HP_NUM > 4 + case UART_NUM_4: + break; + #endif case UART_NUM_MAX: assert(0); // Range is checked in mp_machine_uart_make_new, value should be unreachable } diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 41eea29b08ec3..12835f313e7bb 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -90,7 +90,8 @@ int vprintf_null(const char *format, va_list ap) { return 0; } -time_t platform_mbedtls_time(time_t *timer) { +#if MICROPY_SSL_MBEDTLS +static time_t platform_mbedtls_time(time_t *timer) { // mbedtls_time requires time in seconds from EPOCH 1970 struct timeval tv; @@ -98,6 +99,7 @@ time_t platform_mbedtls_time(time_t *timer) { return tv.tv_sec + TIMEUTILS_SECONDS_1970_TO_2000; } +#endif void mp_task(void *pvParameter) { volatile uint32_t sp = (uint32_t)esp_cpu_get_sp(); @@ -106,7 +108,8 @@ void mp_task(void *pvParameter) { #endif #if MICROPY_HW_ESP_USB_SERIAL_JTAG usb_serial_jtag_init(); - #elif MICROPY_HW_ENABLE_USBDEV + #endif + #if MICROPY_HW_ENABLE_USBDEV usb_phy_init(); #endif #if MICROPY_HW_ENABLE_UART_REPL @@ -114,8 +117,10 @@ void mp_task(void *pvParameter) { #endif machine_init(); + #if MICROPY_SSL_MBEDTLS // Configure time function, for mbedtls certificate time validation. mbedtls_platform_set_time(platform_mbedtls_time); + #endif esp_err_t err = esp_event_loop_create_default(); if (err != ESP_OK) { diff --git a/ports/esp32/main/idf_component.yml b/ports/esp32/main/idf_component.yml index 77904865baae1..176e29c3c4862 100644 --- a/ports/esp32/main/idf_component.yml +++ b/ports/esp32/main/idf_component.yml @@ -1,13 +1,20 @@ -## IDF Component Manager Manifest File dependencies: espressif/mdns: "~1.1.0" espressif/tinyusb: rules: - - if: "target in [esp32s2, esp32s3]" + - if: "target in [esp32s2, esp32s3, esp32p4]" # Temporary workaround for https://github.com/hathach/tinyusb/issues/3154 # Can be removed once fix is released in espressif/tinyusb git: https://github.com/micropython/tinyusb-espressif.git version: cherrypick/dwc2_zlp_fix + espressif/esp_hosted: + rules: + - if: "target == esp32p4" + version: "2.7.0" + espressif/esp_wifi_remote: + rules: + - if: "target == esp32p4" + version: "0.15.2" espressif/lan867x: version: "~1.0.0" rules: diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 1d002fc84bb03..a2ad9267cb268 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -196,7 +196,7 @@ static mp_obj_t esp32_wake_on_gpio(size_t n_args, const mp_obj_t *pos_args, mp_m } static MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_gpio_obj, 0, esp32_wake_on_gpio); -#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP +#if SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP static mp_obj_t esp32_gpio_deep_sleep_hold(const mp_obj_t enable) { if (mp_obj_is_true(enable)) { gpio_deep_sleep_hold_en(); @@ -331,7 +331,7 @@ static const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_wake_on_ulp), MP_ROM_PTR(&esp32_wake_on_ulp_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_wake_on_gpio), MP_ROM_PTR(&esp32_wake_on_gpio_obj) }, - #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP + #if SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP { MP_ROM_QSTR(MP_QSTR_gpio_deep_sleep_hold), MP_ROM_PTR(&esp32_gpio_deep_sleep_hold_obj) }, #endif #if CONFIG_IDF_TARGET_ESP32 diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index 60c386565b8aa..6b6a6578a7512 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -32,6 +32,21 @@ ) #define RTC_LAST_EXT_PIN 21 +#elif CONFIG_IDF_TARGET_ESP32C6 + + #define RTC_VALID_EXT_PINS \ + ( \ + (1ll << 0) | \ + (1ll << 1) | \ + (1ll << 2) | \ + (1ll << 3) | \ + (1ll << 4) | \ + (1ll << 5) | \ + (1ll << 6) | \ + (1ll << 7) \ + ) + #define RTC_LAST_EXT_PIN 7 + #else #define RTC_VALID_EXT_PINS \ diff --git a/ports/esp32/modespnow.c b/ports/esp32/modespnow.c index ab50032ffeb51..725374ea77c55 100644 --- a/ports/esp32/modespnow.c +++ b/ports/esp32/modespnow.c @@ -187,6 +187,16 @@ static void send_cb(const esp_now_send_info_t *tx_info, esp_now_send_status_t st static void recv_cb(const esp_now_recv_info_t *recv_info, const uint8_t *msg, int msg_len); +// Return the current wifi mode, or raise ValueError +static wifi_mode_t get_wifi_mode(void) { + wifi_mode_t mode; + if (esp_wifi_get_mode(&mode) != ESP_OK || mode == WIFI_MODE_NULL) { + // network.WLAN STA or AP must be set active(True) before ESP-NOW can be used + mp_raise_OSError(MP_ENOENT); + } + return mode; +} + // ESPNow.init(): Initialise the data buffers and ESP-NOW functions. // Initialise the Espressif ESPNOW software stack, register callbacks and // allocate the recv data buffers. @@ -197,7 +207,6 @@ static mp_obj_t espnow_init(mp_obj_t _) { self->recv_buffer = m_new_obj(ringbuf_t); ringbuf_alloc(self->recv_buffer, self->recv_buffer_size); - esp_initialise_wifi(); // Call the wifi init code in network_wlan.c check_esp_err(esp_now_init()); check_esp_err(esp_now_register_recv_cb(recv_cb)); check_esp_err(esp_now_register_send_cb(send_cb)); @@ -260,9 +269,13 @@ static mp_obj_t espnow_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t self->recv_timeout_ms = args[ARG_timeout_ms].u_int; } if (args[ARG_rate].u_int >= 0) { - esp_initialise_wifi(); // Call the wifi init code in network_wlan.c - check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, args[ARG_rate].u_int)); - check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, args[ARG_rate].u_int)); + wifi_mode_t mode = get_wifi_mode(); + if (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA) { + check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, args[ARG_rate].u_int)); + } + if (mode == WIFI_MODE_AP || mode == WIFI_MODE_APSTA) { + check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, args[ARG_rate].u_int)); + } } if (args[ARG_get].u_obj == MP_OBJ_NULL) { return mp_const_none; @@ -804,6 +817,22 @@ static const mp_rom_map_elem_t espnow_globals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_KEY_LEN), MP_ROM_INT(ESP_NOW_KEY_LEN)}, { MP_ROM_QSTR(MP_QSTR_MAX_TOTAL_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_TOTAL_PEER_NUM)}, { MP_ROM_QSTR(MP_QSTR_MAX_ENCRYPT_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_ENCRYPT_PEER_NUM)}, + + #if !CONFIG_IDF_TARGET_ESP32C2 + { MP_ROM_QSTR(MP_QSTR_RATE_LORA_250K), MP_ROM_INT(WIFI_PHY_RATE_LORA_250K)}, + { MP_ROM_QSTR(MP_QSTR_RATE_LORA_500K), MP_ROM_INT(WIFI_PHY_RATE_LORA_500K)}, + #endif + // Note: specifying long preamble versions for the lower bit rates apart + // from the non-802.11b 6Mbit rate, for more robust error correction + { MP_ROM_QSTR(MP_QSTR_RATE_1M), MP_ROM_INT(WIFI_PHY_RATE_1M_L)}, + { MP_ROM_QSTR(MP_QSTR_RATE_2M), MP_ROM_INT(WIFI_PHY_RATE_2M_L)}, + { MP_ROM_QSTR(MP_QSTR_RATE_5M), MP_ROM_INT(WIFI_PHY_RATE_5M_L)}, + { MP_ROM_QSTR(MP_QSTR_RATE_6M), MP_ROM_INT(WIFI_PHY_RATE_6M)}, + { MP_ROM_QSTR(MP_QSTR_RATE_11M), MP_ROM_INT(WIFI_PHY_RATE_11M_L)}, + { MP_ROM_QSTR(MP_QSTR_RATE_12M), MP_ROM_INT(WIFI_PHY_RATE_12M)}, + { MP_ROM_QSTR(MP_QSTR_RATE_24M), MP_ROM_INT(WIFI_PHY_RATE_24M)}, + { MP_ROM_QSTR(MP_QSTR_RATE_54M), MP_ROM_INT(WIFI_PHY_RATE_54M)}, + }; static MP_DEFINE_CONST_DICT(espnow_globals_dict, espnow_globals_dict_table); diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 62f0bf73cf945..ec972bfc68ee7 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -260,8 +260,12 @@ static mp_int_t mp_machine_reset_cause(void) { } #if MICROPY_ESP32_USE_BOOTLOADER_RTC +#if !CONFIG_IDF_TARGET_ESP32P4 #include "soc/rtc_cntl_reg.h" #include "usb.h" +#else +#include "soc/lp_system_reg.h" +#endif #if CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/rom/usb/usb_dc.h" #include "esp32s3/rom/usb/usb_persist.h" @@ -274,8 +278,13 @@ MP_NORETURN static void machine_bootloader_rtc(void) { usb_dc_prepare_persist(); chip_usb_set_persist_flags(USBDC_BOOT_DFU); #endif + #if !CONFIG_IDF_TARGET_ESP32P4 REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); esp_restart(); + #else + REG_WRITE(LP_SYSTEM_REG_SYS_CTRL_REG, LP_SYSTEM_REG_FORCE_DOWNLOAD_BOOT); + esp_restart(); + #endif } #endif diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 2050d1d04d4d6..d8ebd3a895401 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -55,6 +55,9 @@ #include "lwip/igmp.h" #include "esp_log.h" +// See note at bottom of file about why this isn't MICROPY_PY_SOCKET +#if MICROPY_PY_NETWORK + #define SOCKET_POLL_US (100000) #define MDNS_QUERY_TIMEOUT_MS (5000) #define MDNS_LOCAL_SUFFIX ".local" @@ -1028,3 +1031,5 @@ const mp_obj_module_t mp_module_socket = { // this will not conflict with the common implementation provided by // extmod/mod{lwip,socket}.c. MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_socket, mp_module_socket); + +#endif // MICROPY_PY_NETWORK diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 7b973ebb969d2..69419ce009b69 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -44,6 +44,9 @@ #define MICROPY_EMIT_RV32 (0) #else #define MICROPY_EMIT_RV32 (1) +#if CONFIG_IDF_TARGET_ESP32P4 +#define MICROPY_EMIT_RV32_ZCMP (1) +#endif #endif #else #define MICROPY_EMIT_XTENSAWIN (1) @@ -92,6 +95,9 @@ #endif #ifndef MICROPY_PY_BLUETOOTH #define MICROPY_PY_BLUETOOTH (1) +#endif + +#if MICROPY_PY_BLUETOOTH #define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS (1) #define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS_WITH_INTERLOCK (1) // Event stack size is the RTOS stack size minus an allowance for the stack used @@ -102,7 +108,8 @@ #define MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING (1) #define MICROPY_BLUETOOTH_NIMBLE (1) #define MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY (1) -#endif +#endif // MICROPY_PY_BLUETOOTH + #define MICROPY_PY_RANDOM_SEED_INIT_FUNC (esp_random()) #define MICROPY_PY_OS_INCLUDEFILE "ports/esp32/modos.c" #define MICROPY_PY_OS_DUPTERM (1) @@ -158,7 +165,9 @@ #define MICROPY_PY_MACHINE_UART_IRQ (1) #define MICROPY_PY_MACHINE_WDT (1) #define MICROPY_PY_MACHINE_WDT_INCLUDEFILE "ports/esp32/machine_wdt.c" +#ifndef MICROPY_PY_NETWORK #define MICROPY_PY_NETWORK (1) +#endif #ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT #if CONFIG_IDF_TARGET_ESP32 #define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32" @@ -174,6 +183,8 @@ #define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c5" #elif CONFIG_IDF_TARGET_ESP32C6 #define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c6" +#elif CONFIG_IDF_TARGET_ESP32P4 +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32p4" #endif #endif #define MICROPY_PY_NETWORK_INCLUDEFILE "ports/esp32/modnetwork.h" @@ -189,10 +200,10 @@ #ifndef MICROPY_HW_ESP_NEW_I2C_DRIVER #define MICROPY_HW_ESP_NEW_I2C_DRIVER (0) #endif -#define MICROPY_PY_SSL (1) -#define MICROPY_SSL_MBEDTLS (1) -#define MICROPY_PY_WEBSOCKET (1) -#define MICROPY_PY_WEBREPL (1) +#define MICROPY_PY_SSL (MICROPY_PY_NETWORK) +#define MICROPY_SSL_MBEDTLS (MICROPY_PY_SSL) +#define MICROPY_PY_WEBSOCKET (MICROPY_PY_NETWORK) +#define MICROPY_PY_WEBREPL (MICROPY_PY_NETWORK) #define MICROPY_PY_ONEWIRE (1) #define MICROPY_PY_SOCKET_EVENTS (MICROPY_PY_WEBREPL) #define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1) @@ -251,6 +262,17 @@ #define MICROPY_HW_USB_PRODUCT_FS_STRING "Espressif Device" #endif +#if CONFIG_IDF_TARGET_ESP32P4 +// By default, ESP32-P4 uses the HS USB PHY (RHPORT1) for TinyUSB +// and configures the full speed USB port as USB Serial/JTAG device +#ifndef MICROPY_HW_USB_HS +#define MICROPY_HW_USB_HS 1 +#endif // MICROPY_HW_USB_HS +#if MICROPY_HW_USB_HS && !defined(CFG_TUSB_RHPORT0_MODE) && !defined(CFG_TUSB_RHPORT1_MODE) +#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) +#endif +#endif + #endif // MICROPY_HW_ENABLE_USBDEV // Enable stdio over native USB peripheral CDC via TinyUSB @@ -259,14 +281,14 @@ #endif // Enable stdio over USB Serial/JTAG peripheral +// (SOC_USB_OTG_PERIPH_NUM is only 2 on the ESP32-P4, which supports both native USB & Serial/JTAG simultaneously) #ifndef MICROPY_HW_ESP_USB_SERIAL_JTAG -#define MICROPY_HW_ESP_USB_SERIAL_JTAG (SOC_USB_SERIAL_JTAG_SUPPORTED && !MICROPY_HW_USB_CDC) +#define MICROPY_HW_ESP_USB_SERIAL_JTAG (SOC_USB_SERIAL_JTAG_SUPPORTED && (!MICROPY_HW_USB_CDC || SOC_USB_OTG_PERIPH_NUM > 1)) #endif -#if MICROPY_HW_USB_CDC && MICROPY_HW_ESP_USB_SERIAL_JTAG +#if MICROPY_HW_USB_CDC && MICROPY_HW_ESP_USB_SERIAL_JTAG && (SOC_USB_OTG_PERIPH_NUM <= 1) #error "Invalid build config: Can't enable both native USB and USB Serial/JTAG peripheral" #endif - // type definitions for the specific machine #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p))) @@ -345,7 +367,7 @@ typedef long mp_off_t; #ifndef MICROPY_BOARD_ENTER_BOOTLOADER // RTC has a register to trigger bootloader on these targets -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32P4 #define MICROPY_ESP32_USE_BOOTLOADER_RTC (1) #define MICROPY_BOARD_ENTER_BOOTLOADER(nargs, args) machine_bootloader_rtc() #endif diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index d779b6e66c09e..a2b11520a5ae3 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -36,6 +36,7 @@ #include "freertos/task.h" #include "driver/spi_master.h" +#include "esp_cache.h" #include "soc/gpio_reg.h" #define MICROPY_PLATFORM_VERSION "IDF" IDF_VER @@ -51,6 +52,11 @@ #define MP_TASK_COREID (1) #endif +#if CONFIG_IDF_TARGET_ESP32P4 +#define MP_HAL_CLEAN_DCACHE(data, len) \ + esp_cache_msync((void *)(data), (len), ESP_CACHE_MSYNC_FLAG_UNALIGNED | ESP_CACHE_MSYNC_FLAG_DIR_C2M) +#endif + extern TaskHandle_t mp_main_task_handle; extern ringbuf_t stdin_ringbuf; diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index 309ee0b14a23c..37f72c26349fe 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -182,13 +182,13 @@ static mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar } eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); - #if CONFIG_IDF_TARGET_ESP32 + #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32P4 eth_esp32_emac_config_t esp32_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); #endif esp_eth_mac_t *mac = NULL; - #if CONFIG_IDF_TARGET_ESP32 + #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32P4 // Dynamic ref_clk configuration. if (args[ARG_ref_clk_mode].u_int != -1) { // Map the GPIO_MODE constants to EMAC_CLK constants. @@ -223,7 +223,7 @@ static mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar #endif switch (args[ARG_phy_type].u_int) { - #if CONFIG_IDF_TARGET_ESP32 + #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32P4 case PHY_LAN8710: case PHY_LAN8720: self->phy = esp_eth_phy_new_lan87xx(&phy_config); @@ -251,7 +251,7 @@ static mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar self->phy = esp_eth_phy_new_generic(&phy_config); break; #endif - #endif // CONFIG_IDF_TARGET_ESP32 + #endif // CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32P4 #if CONFIG_ETH_USE_SPI_ETHERNET #if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL case PHY_KSZ8851SNL: { @@ -286,7 +286,7 @@ static mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar #endif } - #if CONFIG_IDF_TARGET_ESP32 + #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32P4 if (!IS_SPI_PHY(args[ARG_phy_type].u_int)) { if (self->mdc_pin == -1 || self->mdio_pin == -1) { mp_raise_ValueError(MP_ERROR_TEXT("mdc and mdio must be specified")); diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index e20af4806c43d..07b16e91cb941 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -79,6 +79,15 @@ static bool mdns_initialised = false; static uint8_t conf_wifi_sta_reconnects = 0; static uint8_t wifi_sta_reconnects; +// The rules for this default are defined in the documentation of esp_wifi_set_protocol() +// rather than in code, so we have to recreate them here. +#if CONFIG_SOC_WIFI_HE_SUPPORT +// Note: No Explicit support for 5GHz here, yet +#define WIFI_PROTOCOL_DEFAULT (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11AX) +#else +#define WIFI_PROTOCOL_DEFAULT (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) +#endif + // This function is called by the system-event task and so runs in a different // thread to the main MicroPython task. It must not raise any Python exceptions. static void network_wlan_wifi_event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { @@ -771,6 +780,11 @@ static const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_SEC_WPA_ENT), MP_ROM_INT(WIFI_AUTH_WPA_ENTERPRISE) }, #endif + { MP_ROM_QSTR(MP_QSTR_PROTOCOL_DEFAULT), MP_ROM_INT(WIFI_PROTOCOL_DEFAULT) }, + #if !CONFIG_IDF_TARGET_ESP32C2 + { MP_ROM_QSTR(MP_QSTR_PROTOCOL_LR), MP_ROM_INT(WIFI_PROTOCOL_LR) }, + #endif + { MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(WIFI_PS_NONE) }, { MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(WIFI_PS_MIN_MODEM) }, { MP_ROM_QSTR(MP_QSTR_PM_POWERSAVE), MP_ROM_INT(WIFI_PS_MAX_MODEM) }, diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c index 491314e04d106..6e00fa3aa2609 100644 --- a/ports/esp32/uart.c +++ b/ports/esp32/uart.c @@ -40,6 +40,10 @@ static void uart_irq_handler(void *arg); +#if CONFIG_IDF_TARGET_ESP32P4 +static uint8_t __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused)); +#endif + // Declaring the HAL structure on the stack saves a tiny amount of static RAM #define REPL_HAL_DEFN() { .dev = UART_LL_GET_HW(MICROPY_HW_UART_REPL) } diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c index b90f53aa49daa..bca2305f19c7b 100644 --- a/ports/esp32/usb.c +++ b/ports/esp32/usb.c @@ -42,18 +42,17 @@ void usb_phy_init(void) { // ref: https://github.com/espressif/esp-usb/blob/4b6a798d0bed444fff48147c8dcdbbd038e92892/device/esp_tinyusb/tinyusb.c // Configure USB PHY - usb_phy_config_t phy_conf = { + static const usb_phy_config_t phy_conf = { .controller = USB_PHY_CTRL_OTG, .otg_mode = USB_OTG_MODE_DEVICE, + .target = USB_PHY_TARGET_INT, }; - // Internal USB PHY - phy_conf.target = USB_PHY_TARGET_INT; // Init ESP USB Phy usb_new_phy(&phy_conf, &phy_hdl); } -#if CONFIG_IDF_TARGET_ESP32S3 +#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 void usb_usj_mode(void) { // Switch the USB PHY back to Serial/Jtag mode, disabling OTG support // This should be run before jumping to bootloader. diff --git a/ports/esp32/usb_serial_jtag.c b/ports/esp32/usb_serial_jtag.c index c4834e56f962d..2df7e20086283 100644 --- a/ports/esp32/usb_serial_jtag.c +++ b/ports/esp32/usb_serial_jtag.c @@ -71,23 +71,31 @@ static void usb_serial_jtag_handle_rx(void) { static void usb_serial_jtag_isr_handler(void *arg) { uint32_t flags = usb_serial_jtag_ll_get_intsts_mask(); - - if (flags & USB_SERIAL_JTAG_INTR_SOF) { - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF); - } + usb_serial_jtag_ll_clr_intsts_mask(flags); if (flags & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) { - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); usb_serial_jtag_handle_rx(); mp_hal_wake_main_task_from_isr(); } + + if (flags & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) { + // As per the ESP-IDF driver, allow for the possibility the USJ just sent a full + // 64-bit endpoint to the host and now it's waiting for another ZLP to flush the result + // to the OS + usb_serial_jtag_ll_txfifo_flush(); + + // Disable this interrupt until next time we write into the FIFO + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + } } void usb_serial_jtag_init(void) { + // Note: Don't clear the SERIAL_IN_EMPTY interrupt, as it's possible the + // bootloader wrote enough data to the host that we need the interrupt to flush it. usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_SOF); usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | - USB_SERIAL_JTAG_INTR_SOF); + USB_SERIAL_JTAG_INTR_SOF | USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); ESP_ERROR_CHECK(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, usb_serial_jtag_isr_handler, NULL, NULL)); } @@ -114,10 +122,11 @@ void usb_serial_jtag_tx_strn(const char *str, size_t len) { } terminal_connected = true; l = usb_serial_jtag_ll_write_txfifo((const uint8_t *)str, l); - usb_serial_jtag_ll_txfifo_flush(); str += l; len -= l; + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); } + usb_serial_jtag_ll_txfifo_flush(); } #endif // MICROPY_HW_ESP_USB_SERIAL_JTAG diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 1c9de01503abd..abdc9076a0165 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -208,20 +208,10 @@ erase: reset: echo -e "\r\nimport machine; machine.reset()\r\n" >$(PORT) -ifeq ($(BOARD_VARIANT),OTA) -$(FWBIN): $(BUILD)/firmware.elf - $(ECHO) "Create $@" - $(Q)$(ESPTOOL) elf2image $^ - $(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x[0-5][1-f]000.bin $(BUILD)/firmware-ota.bin - - $(Q)cat $(YAOTA8266)/yaota8266.bin $(BUILD)/firmware-ota.bin > $@ - $(Q)$(PYTHON) $(YAOTA8266)/ota-client/ota_client.py sign $@ -else $(FWBIN): $(BUILD)/firmware.elf $(ECHO) "Create $@" $(Q)$(ESPTOOL) elf2image $^ $(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x[0-5][1-f]000.bin $@ -endif $(BUILD)/firmware.elf: $(OBJ) $(ECHO) "LINK $@" diff --git a/ports/esp8266/boards/ESP8266_GENERIC/board.json b/ports/esp8266/boards/ESP8266_GENERIC/board.json index 8f2aa1240f280..84c4ff4951013 100644 --- a/ports/esp8266/boards/ESP8266_GENERIC/board.json +++ b/ports/esp8266/boards/ESP8266_GENERIC/board.json @@ -15,10 +15,12 @@ "thumbnail": "", "url": "https://www.espressif.com/en/products/modules", "variants": { - "OTA": "OTA compatible", "FLASH_1M": "1MiB flash", "FLASH_512K": "512kiB flash", "FLASH_2M_ROMFS": "2MiB flash with ROMFS" }, + "old_variants": { + "OTA": ["OTA compatible", "OTA firmware is no longer supported."] + }, "vendor": "Espressif" } diff --git a/ports/esp8266/boards/ESP8266_GENERIC/board.md b/ports/esp8266/boards/ESP8266_GENERIC/board.md index e8d63fcead0c4..b83d2910cd673 100644 --- a/ports/esp8266/boards/ESP8266_GENERIC/board.md +++ b/ports/esp8266/boards/ESP8266_GENERIC/board.md @@ -14,13 +14,3 @@ Note: v1.12-334 and newer (including v1.13) require an ESP8266 module with upgrading from older firmware please backup your files first, and either erase all flash before upgrading, or after upgrading execute `vfs.VfsLfs2.mkfs(bdev)`. - -### OTA builds -Over-The-Air (OTA) builds of the ESP8266 firmware are also provided. - -The first time you use this build you need to flash one of the "initial image" -images using esptool.py as described above. After that, you can update the -firmware over the air using the "OTA update" file in conjunction with the -ota-client script from yaota8266. The "OTA update" files are digitally signed -and will only work with the provided "initial image" files, and vice versa. -(Note: this feature is work-in-progress.) diff --git a/ports/esp8266/boards/ESP8266_GENERIC/mpconfigvariant_OTA.mk b/ports/esp8266/boards/ESP8266_GENERIC/mpconfigvariant_OTA.mk deleted file mode 100644 index 759eab3dc750b..0000000000000 --- a/ports/esp8266/boards/ESP8266_GENERIC/mpconfigvariant_OTA.mk +++ /dev/null @@ -1,10 +0,0 @@ -LD_FILES = boards/esp8266_ota.ld - -MICROPY_PY_ESPNOW ?= 1 -MICROPY_PY_BTREE ?= 1 -MICROPY_VFS_LFS2 ?= 1 - -# Note: Implicitly uses the port manifest. - -# Configure mpconfigboard.h. -CFLAGS += -DMICROPY_ESP8266_1M diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c index e1f9d39687593..4b62175509418 100644 --- a/ports/esp8266/modesp.c +++ b/ports/esp8266/modesp.c @@ -159,10 +159,6 @@ static mp_obj_t esp_flash_size(void) { } static MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size); -// If there's just 1 loadable segment at the start of flash, -// we assume there's a yaota8266 bootloader. -#define IS_OTA_FIRMWARE() ((*(uint32_t *)0x40200000 & 0xff00) == 0x100) - extern byte _firmware_size[]; #if MICROPY_VFS_ROM_IOCTL extern uint8_t _micropy_hw_romfs_part0_size; @@ -180,11 +176,6 @@ static MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start) static mp_obj_t esp_check_fw(void) { MD5_CTX ctx; char *fw_start = (char *)0x40200000; - if (IS_OTA_FIRMWARE()) { - // Skip yaota8266 bootloader - fw_start += 0x3c000; - } - uint32_t size = *(uint32_t *)(fw_start + 0x8ffc); printf("size: %d\n", size); if (size > 1024 * 1024) { @@ -243,7 +234,7 @@ static mp_obj_t esp_esf_free_bufs(mp_obj_t idx_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(esp_esf_free_bufs_obj, esp_esf_free_bufs); -#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA +#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_PERSISTENT_CODE_LOAD_NATIVE // We provide here a way of committing executable data to a region from // which it can be executed by the CPU. There are 2 such writable regions: @@ -367,7 +358,7 @@ static const mp_rom_map_elem_t esp_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_malloc), MP_ROM_PTR(&esp_malloc_obj) }, { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&esp_free_obj) }, { MP_ROM_QSTR(MP_QSTR_esf_free_bufs), MP_ROM_PTR(&esp_esf_free_bufs_obj) }, - #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA + #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_PERSISTENT_CODE_LOAD_NATIVE { MP_ROM_QSTR(MP_QSTR_set_native_code_location), MP_ROM_PTR(&esp_set_native_code_location_obj) }, #endif diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index fea7e56da22f4..9694464b5b828 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -56,7 +56,7 @@ MCUX_SDK_DIR = lib/nxp_driver/sdk MCU_DIR = $(MCUX_SDK_DIR)/devices/$(MCU_SERIES) # Select linker scripts based on MCU_SERIES -LD_FILES = boards/$(MCU_SERIES).ld boards/common.ld +LD_FILES ?= boards/$(MCU_SERIES).ld boards/common.ld # Parameter configurations for generation AF_FILE = boards/$(MCU_SERIES)_af.csv @@ -113,6 +113,7 @@ SRC_ETH_C += \ $(MCUX_SDK_DIR)/drivers/enet/fsl_enet.c \ hal/phy/device/phydp83825/fsl_phydp83825.c \ hal/phy/device/phydp83848/fsl_phydp83848.c \ + hal/phy/device/phydp83867/fsl_phydp83867.c \ hal/phy/device/phyksz8081/fsl_phyksz8081.c \ hal/phy/device/phylan8720/fsl_phylan8720.c \ hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.c \ @@ -136,6 +137,7 @@ SRC_HAL_IMX_C += \ $(MCUX_SDK_DIR)/drivers/lpi2c/fsl_lpi2c.c \ $(MCUX_SDK_DIR)/drivers/lpspi/fsl_lpspi.c \ $(MCUX_SDK_DIR)/drivers/lpspi/fsl_lpspi_edma.c \ + $(MCUX_SDK_DIR)/drivers/lpuart/fsl_lpuart.c \ $(MCUX_SDK_DIR)/drivers/pit/fsl_pit.c \ $(MCUX_SDK_DIR)/drivers/pwm/fsl_pwm.c \ $(MCUX_SDK_DIR)/drivers/sai/fsl_sai.c \ @@ -151,6 +153,10 @@ else SRC_HAL_IMX_C += $(MCU_DIR)/xip/fsl_flexspi_nor_boot.c endif +# UART IRQ wrapper for UART.IRQ_RXIDLE support (see machine_uart.c for implementation details) +# Double wrapping is required because SDK stores function pointers in s_lpuartIsr[] dispatch table +LDFLAGS += --wrap=LPUART_TransferCreateHandle --wrap=LPUART_TransferHandleIRQ + INC_HAL_IMX += \ -I$(TOP)/$(MCU_DIR) \ -I$(TOP)/$(MCU_DIR)/drivers \ @@ -243,7 +249,6 @@ SRC_C += \ eth.c \ fatfs_port.c \ flash.c \ - hal/fsl_lpuart.c \ hal/pwm_backport.c \ help.c \ led.c \ @@ -265,6 +270,7 @@ SRC_C += \ network_lan.c \ pendsv.c \ pin.c \ + psram.c \ sdcard.c \ sdio.c \ systick.c \ @@ -311,6 +317,11 @@ ifeq ($(USE_UF2_BOOTLOADER),1) CFLAGS += -DMICROPY_MACHINE_UF2_BOOTLOADER=1 endif +# Set the default size of the VfsRom file system. Can be changed at board level +ifeq ($(MICROPY_HW_ROMFS_BYTES),) + MICROPY_HW_ROMFS_BYTES ?= 0x40000 +endif + # Add sources for respective board flash type # Add hal/flexspi_nor_flash.c or hal/flashspi_hyper_flash.c respectively SRC_HAL_C += hal/flexspi_$(subst qspi_,,$(FLEXSPI_FLASH_TYPE)).c @@ -430,6 +441,15 @@ CFLAGS += \ -Wfloat-conversion \ -Wno-error=unused-parameter +# Flags for optional C++ source code +CXXFLAGS += $(filter-out -std=c99,$(CFLAGS)) + +# TODO make this common -- shouldn't be using these "private" vars from py.mk +ifneq ($(SRC_CXX)$(SRC_USERMOD_CXX)$(SRC_USERMOD_LIB_CXX),) +LIBSTDCPP_FILE_NAME = "$(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a)" +LDFLAGS += -L"$(shell dirname $(LIBSTDCPP_FILE_NAME))" +endif + # Configure respective board flash type # Add hal/flexspi_nor_flash.h or hal/flexspi_hyper_flash.h respectively CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_$(subst qspi_,,$(FLEXSPI_FLASH_TYPE)).h\" @@ -489,14 +509,16 @@ LDFLAGS += \ --cref \ --gc-sections \ --print-memory-usage \ - -Map=$@.map + -Map=$@.map \ + --wrap=LPUART_TransferCreateHandle --wrap=LPUART_TransferHandleIRQ # LDDEFINES are used for link time adaptation of linker scripts, utilizing # the C preprocessor. Therefore keep LDDEFINES separated from LDFLAGS! -LDDEFINES = \ +LDDEFINES += \ -DMICROPY_HW_FLASH_BASE=$(MICROPY_HW_FLASH_BASE) \ - -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) + -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \ + -DMICROPY_HW_ROMFS_BYTES=$(MICROPY_HW_ROMFS_BYTES) ifdef MICROPY_HW_FLASH_RESERVED LDDEFINES += -DMICROPY_HW_FLASH_RESERVED=$(MICROPY_HW_FLASH_RESERVED) @@ -573,7 +595,7 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(BOARD_DIR)/mpconfigboard.h $(GEN_FLEXRAM_CONFIG_SRC): $(HEADER_BUILD) $(ECHO) "Create $@" $(Q)$(PYTHON) $(MAKE_FLEXRAM_LD) -d $(TOP)/$(MCU_DIR)/$(MCU_SERIES)$(MCU_CORE).h \ - -f $(TOP)/$(MCU_DIR)/$(MCU_SERIES)$(MCU_CORE)_features.h -l boards/$(MCU_SERIES).ld -c $(MCU_SERIES) > $@ + -f $(TOP)/$(MCU_DIR)/$(MCU_SERIES)$(MCU_CORE)_features.h $(addprefix -l,$(LD_FILES)) -c $(MCU_SERIES) > $@ # Use a pattern rule here so that make will only call make-pins.py once to make # both pins_gen.c and pins.h diff --git a/ports/mimxrt/boards/MIMXRT1011.ld b/ports/mimxrt/boards/MIMXRT1011.ld index 0e961a49433f2..dba02f0ec39c4 100644 --- a/ports/mimxrt/boards/MIMXRT1011.ld +++ b/ports/mimxrt/boards/MIMXRT1011.ld @@ -18,8 +18,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +_micropy_hw_romfs_part0_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +_micropy_hw_romfs_part0_size = MICROPY_HW_ROMFS_BYTES; +text_size = ((_micropy_hw_romfs_part0_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00008000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1015.ld b/ports/mimxrt/boards/MIMXRT1015.ld index 58b88e0fe3084..70959685fa0e3 100644 --- a/ports/mimxrt/boards/MIMXRT1015.ld +++ b/ports/mimxrt/boards/MIMXRT1015.ld @@ -18,8 +18,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +_micropy_hw_romfs_part0_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +_micropy_hw_romfs_part0_size = MICROPY_HW_ROMFS_BYTES; +text_size = ((_micropy_hw_romfs_part0_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00008000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld index 78add04c0c26c..78e8e22a0ff4d 100644 --- a/ports/mimxrt/boards/MIMXRT1021.ld +++ b/ports/mimxrt/boards/MIMXRT1021.ld @@ -18,8 +18,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +_micropy_hw_romfs_part0_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +_micropy_hw_romfs_part0_size = MICROPY_HW_ROMFS_BYTES; +text_size = ((_micropy_hw_romfs_part0_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00010000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk index 8b048c85eaa98..3631df4b0d4d3 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk @@ -10,6 +10,7 @@ MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB MICROPY_HW_FLASH_CLK = kFlexSpiSerialClk_133MHz MICROPY_HW_FLASH_QE_CMD = 0x01 MICROPY_HW_FLASH_QE_ARG = 0x40 +MICROPY_HW_ROMFS_BYTES = 0 # Disabled for a board with Hyperflash MICROPY_PY_LWIP = 1 MICROPY_PY_SSL = 1 diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld index ea034d713e2f6..0370d805acc3e 100644 --- a/ports/mimxrt/boards/MIMXRT1052.ld +++ b/ports/mimxrt/boards/MIMXRT1052.ld @@ -20,8 +20,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00200000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +_micropy_hw_romfs_part0_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +_micropy_hw_romfs_part0_size = MICROPY_HW_ROMFS_BYTES; +text_size = ((_micropy_hw_romfs_part0_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1062.ld b/ports/mimxrt/boards/MIMXRT1062.ld index 3d7e6d0634196..686d1bdc845d4 100644 --- a/ports/mimxrt/boards/MIMXRT1062.ld +++ b/ports/mimxrt/boards/MIMXRT1062.ld @@ -20,8 +20,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +_micropy_hw_romfs_part0_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +_micropy_hw_romfs_part0_size = MICROPY_HW_ROMFS_BYTES; +text_size = ((_micropy_hw_romfs_part0_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1064.ld b/ports/mimxrt/boards/MIMXRT1064.ld index 7c35cb60c750b..16f6f19b5add8 100644 --- a/ports/mimxrt/boards/MIMXRT1064.ld +++ b/ports/mimxrt/boards/MIMXRT1064.ld @@ -14,8 +14,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +_micropy_hw_romfs_part0_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +_micropy_hw_romfs_part0_size = MICROPY_HW_ROMFS_BYTES; +text_size = ((_micropy_hw_romfs_part0_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h index 131c5e1725477..1154aac83005d 100644 --- a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h @@ -167,18 +167,12 @@ { IOMUXC_GPIO_AD_33_ENET_MDIO, 0, 0x06u }, \ { IOMUXC_GPIO_AD_32_ENET_MDC, 0, 0x06u }, -// A second ETH port is present. -#define ENET_DUAL_PORT (1) -// 1G Transceiver Phy Parameters +// 1G Transceiver Phy Parameters (second ETH port) #define ENET_1_PHY_ADDRESS (1) #define ENET_1_PHY RTL8211F #define ENET_1_PHY_OPS phyrtl8211f_ops // 1G Ethernet PIN definitions -// No INT pin for ENET_1G -#define ENET_1_RESET_PIN &pin_GPIO_DISP_B2_13 -#define ENET_1_INT_PIN NULL - #define IOMUX_TABLE_ENET_1 \ { IOMUXC_GPIO_DISP_B1_00_ENET_1G_RX_EN, 0, 0x08U }, \ { IOMUXC_GPIO_DISP_B1_01_ENET_1G_RX_CLK, 0, 0x08U }, \ diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk index ef4ab683a215c..f534406fcdefe 100644 --- a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk @@ -9,6 +9,7 @@ MICROPY_HW_FLASH_RESERVED ?= 0x100000 # 1MB CM4 Code address space MICROPY_HW_FLASH_CLK = kFlexSpiSerialClk_133MHz MICROPY_HW_FLASH_QE_CMD = 0x31 MICROPY_HW_FLASH_QE_ARG = 0x02 +MICROPY_HW_ROMFS_BYTES = 0x80000 # 512kB MICROPY_HW_SDRAM_AVAIL = 1 MICROPY_HW_SDRAM_SIZE = 0x4000000 # 64MB diff --git a/ports/mimxrt/boards/MIMXRT1176.ld b/ports/mimxrt/boards/MIMXRT1176.ld index 4d114ef96fa4a..57243b68da797 100644 --- a/ports/mimxrt/boards/MIMXRT1176.ld +++ b/ports/mimxrt/boards/MIMXRT1176.ld @@ -30,8 +30,10 @@ m_core1_image_start = vfs_start - 0x00040000; m_core1_image_size = 0x00040000; #endif -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +_micropy_hw_romfs_part0_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +_micropy_hw_romfs_part0_size = MICROPY_HW_ROMFS_BYTES; +text_size = ((_micropy_hw_romfs_part0_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1176_af.csv b/ports/mimxrt/boards/MIMXRT1176_af.csv index 5e99a49003af7..0b13e509aa276 100644 --- a/ports/mimxrt/boards/MIMXRT1176_af.csv +++ b/ports/mimxrt/boards/MIMXRT1176_af.csv @@ -1,175 +1,175 @@ -Pad,ALT0,ALT1,ALT2,ALT3,ALT4,ALT5,ALT6,ALT7,ALT8,ALT9,ALT10,ADC,ACMP,Default -GPIO_SD_B1_00,USDHC1_CMD,,XBAR1_INOUT20,GPT4_CAPTURE1,,GPIO4_IO03,FLEXSPI2_A_SS0_B,,KPP_ROW07,,GPIO10_IO03,,, -GPIO_SD_B1_01,USDHC1_CLK,,XBAR1_INOUT21,GPT4_CAPTURE2,,GPIO4_IO04,FLEXSPI2_A_SCLK,,KPP_COL07,,GPIO10_IO04,,, -GPIO_SD_B1_02,USDHC1_DATA0,,XBAR1_INOUT22,GPT4_COMPARE1,,GPIO4_IO05,FLEXSPI2_A_DATA00,,KPP_ROW06,FLEXSPI1_A_SS1_B,GPIO10_IO05,,, -GPIO_SD_B1_03,USDHC1_DATA1,,XBAR1_INOUT23,GPT4_COMPARE2,,GPIO4_IO06,FLEXSPI2_A_DATA01,,KPP_COL06,FLEXSPI1_B_SS1_B,GPIO10_IO06,,, -GPIO_SD_B1_04,USDHC1_DATA2,,XBAR1_INOUT24,GPT4_COMPARE3,,GPIO4_IO07,FLEXSPI2_A_DATA02,,FLEXSPI1_B_SS0_B,ENET_QOS_1588_EVENT2_AUX_IN,GPIO10_IO07,,, -GPIO_SD_B1_05,USDHC1_DATA3,,XBAR1_INOUT25,GPT4_CLK,,GPIO4_IO08,FLEXSPI2_A_DATA03,,FLEXSPI1_B_DQS,ENET_QOS_1588_EVENT3_AUX_IN,GPIO10_IO08,,, -GPIO_SD_B2_00,USDHC2_DATA3,FLEXSPI1_B_DATA03,ENET_1G_RX_EN,LPUART9_TXD,LPSPI4_SCK,GPIO4_IO09,,,,,GPIO10_IO09,,, -GPIO_SD_B2_01,USDHC2_DATA2,FLEXSPI1_B_DATA02,ENET_1G_RX_CLK,LPUART9_RXD,LPSPI4_PCS0,GPIO4_IO10,,,,,GPIO10_IO10,,, -GPIO_SD_B2_02,USDHC2_DATA1,FLEXSPI1_B_DATA01,ENET_1G_RX_DATA00,LPUART9_CTS_B,LPSPI4_SOUT,GPIO4_IO11,,,,,GPIO10_IO11,,, -GPIO_SD_B2_03,USDHC2_DATA0,FLEXSPI1_B_DATA00,ENET_1G_RX_DATA01,LPUART9_RTS_B,LPSPI4_SIN,GPIO4_IO12,,,,,GPIO10_IO12,,, -GPIO_SD_B2_04,USDHC2_CLK,FLEXSPI1_B_SCLK,ENET_1G_RX_DATA02,FLEXSPI1_A_SS1_B,LPSPI4_PCS1,GPIO4_IO13,,,,,GPIO10_IO13,,, -GPIO_SD_B2_05,USDHC2_CMD,FLEXSPI1_A_DQS,ENET_1G_RX_DATA03,FLEXSPI1_B_SS0_B,LPSPI4_PCS2,GPIO4_IO14,,,,,GPIO10_IO14,,, -GPIO_SD_B2_06,USDHC2_RESET_B,FLEXSPI1_A_SS0_B,ENET_1G_TX_DATA03,LPSPI4_PCS3,GPT6_CAPTURE1,GPIO4_IO15,,,,,GPIO10_IO15,,, -GPIO_SD_B2_07,USDHC2_STROBE,FLEXSPI1_A_SCLK,ENET_1G_TX_DATA02,LPUART3_CTS_B,GPT6_CAPTURE2,GPIO4_IO16,LPSPI2_SCK,,ENET_TX_ER,ENET_QOS_REF_CLK,GPIO10_IO16,,, -GPIO_SD_B2_08,USDHC2_DATA4,FLEXSPI1_A_DATA00,ENET_1G_TX_DATA01,LPUART3_RTS_B,GPT6_COMPARE1,GPIO4_IO17,LPSPI2_PCS0,,,,GPIO10_IO17,,, -GPIO_SD_B2_09,USDHC2_DATA5,FLEXSPI1_A_DATA01,ENET_1G_TX_DATA00,LPUART5_CTS_B,GPT6_COMPARE2,GPIO4_IO18,LPSPI2_SOUT,,,,GPIO10_IO18,,, -GPIO_SD_B2_10,USDHC2_DATA6,FLEXSPI1_A_DATA02,ENET_1G_TX_EN,LPUART5_RTS_B,GPT6_COMPARE3,GPIO4_IO19,LPSPI2_SIN,,,,GPIO10_IO19,,, -GPIO_SD_B2_11,USDHC2_DATA7,FLEXSPI1_A_DATA03,ENET_1G_TX_CLK_IO,ENET_1G_REF_CLK,GPT6_CLK,GPIO4_IO20,LPSPI2_PCS1,,,,GPIO10_IO20,,, -GPIO_EMC_B1_00,SEMC_DATA00,FLEXPWM4_PWM0_A,,,,GPIO1_IO00,,,FLEXIO1_D00,,GPIO7_IO00,,, -GPIO_EMC_B1_01,SEMC_DATA01,FLEXPWM4_PWM0_B,,,,GPIO1_IO01,,,FLEXIO1_D01,,GPIO7_IO01,,, -GPIO_EMC_B1_02,SEMC_DATA02,FLEXPWM4_PWM1_A,,,,GPIO1_IO02,,,FLEXIO1_D02,,GPIO7_IO02,,, -GPIO_EMC_B1_03,SEMC_DATA03,FLEXPWM4_PWM1_B,,,,GPIO1_IO03,,,FLEXIO1_D03,,GPIO7_IO03,,, -GPIO_EMC_B1_04,SEMC_DATA04,FLEXPWM4_PWM2_A,,,,GPIO1_IO04,,,FLEXIO1_D04,,GPIO7_IO04,,, -GPIO_EMC_B1_05,SEMC_DATA05,FLEXPWM4_PWM2_B,,,,GPIO1_IO05,,,FLEXIO1_D05,,GPIO7_IO05,,, -GPIO_EMC_B1_06,SEMC_DATA06,FLEXPWM2_PWM0_A,,,,GPIO1_IO06,,,FLEXIO1_D06,,GPIO7_IO06,,, -GPIO_EMC_B1_07,SEMC_DATA07,FLEXPWM2_PWM0_B,,,,GPIO1_IO07,,,FLEXIO1_D07,,GPIO7_IO07,,, -GPIO_EMC_B1_08,SEMC_DM00,FLEXPWM2_PWM1_A,,,,GPIO1_IO08,,,FLEXIO1_D08,,GPIO7_IO08,,, -GPIO_EMC_B1_09,SEMC_ADDR00,FLEXPWM2_PWM1_B,GPT5_CAPTURE1,,,GPIO1_IO09,,,FLEXIO1_D09,,GPIO7_IO09,,, -GPIO_EMC_B1_10,SEMC_ADDR01,FLEXPWM2_PWM2_A,GPT5_CAPTURE2,,,GPIO1_IO10,,,FLEXIO1_D10,,GPIO7_IO10,,, -GPIO_EMC_B1_11,SEMC_ADDR02,FLEXPWM2_PWM2_B,GPT5_COMPARE1,,,GPIO1_IO11,,,FLEXIO1_D11,,GPIO7_IO11,,, -GPIO_EMC_B1_12,SEMC_ADDR03,XBAR1_INOUT04,GPT5_COMPARE2,,,GPIO1_IO12,,,FLEXIO1_D12,,GPIO7_IO12,,, -GPIO_EMC_B1_13,SEMC_ADDR04,XBAR1_INOUT05,GPT5_COMPARE3,,,GPIO1_IO13,,,FLEXIO1_D13,,GPIO7_IO13,,, -GPIO_EMC_B1_14,SEMC_ADDR05,XBAR1_INOUT06,GPT5_CLK,,,GPIO1_IO14,,,FLEXIO1_D14,,GPIO7_IO14,,, -GPIO_EMC_B1_15,SEMC_ADDR06,XBAR1_INOUT07,,,,GPIO1_IO15,,,FLEXIO1_D15,,GPIO7_IO15,,, -GPIO_EMC_B1_16,SEMC_ADDR07,XBAR1_INOUT08,,,,GPIO1_IO16,,,FLEXIO1_D16,,GPIO7_IO16,,, -GPIO_EMC_B1_17,SEMC_ADDR08,FLEXPWM4_PWM3_A,TMR1_TIMER0,,,GPIO1_IO17,,,FLEXIO1_D17,,GPIO7_IO17,,, -GPIO_EMC_B1_18,SEMC_ADDR09,FLEXPWM4_PWM3_B,TMR2_TIMER0,,,GPIO1_IO18,,,FLEXIO1_D18,,GPIO7_IO18,,, -GPIO_EMC_B1_19,SEMC_ADDR11,FLEXPWM2_PWM3_A,TMR3_TIMER0,,,GPIO1_IO19,,,FLEXIO1_D19,,GPIO7_IO19,,, -GPIO_EMC_B1_20,SEMC_ADDR12,FLEXPWM2_PWM3_B,TMR4_TIMER0,,,GPIO1_IO20,,,FLEXIO1_D20,,GPIO7_IO20,,, -GPIO_EMC_B1_21,SEMC_BA0,FLEXPWM3_PWM3_A,,,,GPIO1_IO21,,,FLEXIO1_D21,,GPIO7_IO21,,, -GPIO_EMC_B1_22,SEMC_BA1,FLEXPWM3_PWM3_B,,,,GPIO1_IO22,,,FLEXIO1_D22,,GPIO7_IO22,,, -GPIO_EMC_B1_23,SEMC_ADDR10,FLEXPWM1_PWM0_A,,,,GPIO1_IO23,,,FLEXIO1_D23,,GPIO7_IO23,,, -GPIO_EMC_B1_24,SEMC_CAS,FLEXPWM1_PWM0_B,,,,GPIO1_IO24,,,FLEXIO1_D24,,GPIO7_IO24,,, -GPIO_EMC_B1_25,SEMC_RAS,FLEXPWM1_PWM1_A,,,,GPIO1_IO25,,,FLEXIO1_D25,,GPIO7_IO25,,, -GPIO_EMC_B1_26,SEMC_CLK,FLEXPWM1_PWM1_B,,,,GPIO1_IO26,,,FLEXIO1_D26,,GPIO7_IO26,,, -GPIO_EMC_B1_27,SEMC_CKE,FLEXPWM1_PWM2_A,,,,GPIO1_IO27,,,FLEXIO1_D27,,GPIO7_IO27,,, -GPIO_EMC_B1_28,SEMC_WE,FLEXPWM1_PWM2_B,,,,GPIO1_IO28,,,FLEXIO1_D28,,GPIO7_IO28,,, -GPIO_EMC_B1_29,SEMC_CS0,FLEXPWM3_PWM0_A,,,,GPIO1_IO29,,,FLEXIO1_D29,,GPIO7_IO29,,, -GPIO_EMC_B1_30,SEMC_DATA08,FLEXPWM3_PWM0_B,,,,GPIO1_IO30,,,FLEXIO1_D30,,GPIO7_IO30,,, -GPIO_EMC_B1_31,SEMC_DATA09,FLEXPWM3_PWM1_A,,,,GPIO1_IO31,,,FLEXIO1_D31,,GPIO7_IO31,,, -GPIO_EMC_B1_32,SEMC_DATA10,FLEXPWM3_PWM1_B,,,,GPIO2_IO00,,,,,GPIO8_IO00,,, -GPIO_EMC_B1_33,SEMC_DATA11,FLEXPWM3_PWM2_A,,,,GPIO2_IO01,,,,,GPIO8_IO01,,, -GPIO_EMC_B1_34,SEMC_DATA12,FLEXPWM3_PWM2_B,,,,GPIO2_IO02,,,,,GPIO8_IO02,,, -GPIO_EMC_B1_35,SEMC_DATA13,XBAR1_INOUT09,,,,GPIO2_IO03,,,,,GPIO8_IO03,,, -GPIO_EMC_B1_36,SEMC_DATA14,XBAR1_INOUT10,,,,GPIO2_IO04,,,,,GPIO8_IO04,,, -GPIO_EMC_B1_37,SEMC_DATA15,XBAR1_INOUT11,,,,GPIO2_IO05,,,,,GPIO8_IO05,,, -GPIO_EMC_B1_38,SEMC_DM01,FLEXPWM1_PWM3_A,TMR1_TIMER1,,,GPIO2_IO06,,,,,GPIO8_IO06,,, -GPIO_EMC_B1_39,SEMC_DQS,FLEXPWM1_PWM3_B,TMR2_TIMER1,,,GPIO2_IO07,,,,,GPIO8_IO07,,, -GPIO_EMC_B1_40,SEMC_RDY,XBAR1_INOUT12,MQS_RIGHT,LPUART6_TXD,,GPIO2_IO08,,ENET_1G_MDC,,CCM_CLKO1,GPIO8_IO08,,, -GPIO_EMC_B1_41,SEMC_CSX00,XBAR1_INOUT13,MQS_LEFT,LPUART6_RXD,FLEXSPI2_B_DATA07,GPIO2_IO09,,ENET_1G_MDIO,,CCM_CLKO2,GPIO8_IO09,,, -GPIO_EMC_B2_00,SEMC_DATA16,CCM_ENET_REF_CLK_25M,TMR3_TIMER1,LPUART6_CTS_B,FLEXSPI2_B_DATA06,GPIO2_IO10,XBAR1_INOUT20,ENET_QOS_1588_EVENT1_OUT,LPSPI1_SCK,LPI2C2_SCL,GPIO8_IO10,,, -GPIO_EMC_B2_01,SEMC_DATA17,USDHC2_CD_B,TMR4_TIMER1,LPUART6_RTS_B,FLEXSPI2_B_DATA05,GPIO2_IO11,XBAR1_INOUT21,ENET_QOS_1588_EVENT1_IN,LPSPI1_PCS0,LPI2C2_SDA,GPIO8_IO11,,, -GPIO_EMC_B2_02,SEMC_DATA18,USDHC2_WP,,VIDEO_MUX_CSI_DATA23,FLEXSPI2_B_DATA04,GPIO2_IO12,XBAR1_INOUT22,ENET_QOS_1588_EVENT1_AUX_IN,LPSPI1_SOUT,,GPIO8_IO12,,, -GPIO_EMC_B2_03,SEMC_DATA19,USDHC2_VSELECT,,VIDEO_MUX_CSI_DATA22,FLEXSPI2_B_DATA03,GPIO2_IO13,XBAR1_INOUT23,ENET_1G_TX_DATA03,LPSPI1_SIN,,GPIO8_IO13,,, -GPIO_EMC_B2_04,SEMC_DATA20,USDHC2_RESET_B,SAI2_MCLK,VIDEO_MUX_CSI_DATA21,FLEXSPI2_B_DATA02,GPIO2_IO14,XBAR1_INOUT24,ENET_1G_TX_DATA02,LPSPI3_SCK,,GPIO8_IO14,,, -GPIO_EMC_B2_05,SEMC_DATA21,GPT3_CLK,SAI2_RX_SYNC,VIDEO_MUX_CSI_DATA20,FLEXSPI2_B_DATA01,GPIO2_IO15,XBAR1_INOUT25,ENET_1G_RX_CLK,LPSPI3_PCS0,PIT1_TRIGGER0,GPIO8_IO15,,, -GPIO_EMC_B2_06,SEMC_DATA22,GPT3_CAPTURE1,SAI2_RX_BCLK,VIDEO_MUX_CSI_DATA19,FLEXSPI2_B_DATA00,GPIO2_IO16,XBAR1_INOUT26,ENET_1G_TX_ER,LPSPI3_SOUT,PIT1_TRIGGER1,GPIO8_IO16,,, -GPIO_EMC_B2_07,SEMC_DATA23,GPT3_CAPTURE2,SAI2_RX_DATA,VIDEO_MUX_CSI_DATA18,FLEXSPI2_B_DQS,GPIO2_IO17,XBAR1_INOUT27,ENET_1G_RX_DATA03,LPSPI3_SIN,PIT1_TRIGGER2,GPIO8_IO17,,, -GPIO_EMC_B2_08,SEMC_DM02,GPT3_COMPARE1,SAI2_TX_DATA,VIDEO_MUX_CSI_DATA17,FLEXSPI2_B_SS0_B,GPIO2_IO18,XBAR1_INOUT28,ENET_1G_RX_DATA02,LPSPI3_PCS1,PIT1_TRIGGER3,GPIO8_IO18,,, -GPIO_EMC_B2_09,SEMC_DATA24,GPT3_COMPARE2,SAI2_TX_BCLK,VIDEO_MUX_CSI_DATA16,FLEXSPI2_B_SCLK,GPIO2_IO19,XBAR1_INOUT29,ENET_1G_CRS,LPSPI3_PCS2,TMR1_TIMER0,GPIO8_IO19,,, -GPIO_EMC_B2_10,SEMC_DATA25,GPT3_COMPARE3,SAI2_TX_SYNC,VIDEO_MUX_CSI_FIELD,FLEXSPI2_A_SCLK,GPIO2_IO20,XBAR1_INOUT30,ENET_1G_COL,LPSPI3_PCS3,TMR1_TIMER1,GPIO8_IO20,,, -GPIO_EMC_B2_11,SEMC_DATA26,SPDIF_IN,ENET_1G_TX_DATA00,SAI3_RX_SYNC,FLEXSPI2_A_SS0_B,GPIO2_IO21,XBAR1_INOUT31,,EMVSIM1_IO,TMR1_TIMER2,GPIO8_IO21,,, -GPIO_EMC_B2_12,SEMC_DATA27,SPDIF_OUT,ENET_1G_TX_DATA01,SAI3_RX_BCLK,FLEXSPI2_A_DQS,GPIO2_IO22,XBAR1_INOUT32,,EMVSIM1_CLK,TMR1_TIMER3,GPIO8_IO22,,, -GPIO_EMC_B2_13,SEMC_DATA28,,ENET_1G_TX_EN,SAI3_RX_DATA,FLEXSPI2_A_DATA00,GPIO2_IO23,XBAR1_INOUT33,,EMVSIM1_RST,TMR2_TIMER0,GPIO8_IO23,,, -GPIO_EMC_B2_14,SEMC_DATA29,,ENET_1G_TX_CLK_IO,SAI3_TX_DATA,FLEXSPI2_A_DATA01,GPIO2_IO24,XBAR1_INOUT34,SFA_ipp_do_atx_clk_under_test,EMVSIM1_SVEN,TMR2_TIMER1,GPIO8_IO24,,, -GPIO_EMC_B2_15,SEMC_DATA30,,ENET_1G_RX_DATA00,SAI3_TX_BCLK,FLEXSPI2_A_DATA02,GPIO2_IO25,XBAR1_INOUT35,,EMVSIM1_PD,TMR2_TIMER2,GPIO8_IO25,,, -GPIO_EMC_B2_16,SEMC_DATA31,XBAR1_INOUT14,ENET_1G_RX_DATA01,SAI3_TX_SYNC,FLEXSPI2_A_DATA03,GPIO2_IO26,,,EMVSIM1_POWER_FAIL,TMR2_TIMER3,GPIO8_IO26,,, -GPIO_EMC_B2_17,SEMC_DM03,XBAR1_INOUT15,ENET_1G_RX_EN,SAI3_MCLK,FLEXSPI2_A_DATA04,GPIO2_IO27,,,WDOG1_ANY,TMR3_TIMER0,GPIO8_IO27,,, -GPIO_EMC_B2_18,SEMC_DQS4,XBAR1_INOUT16,ENET_1G_RX_ER,EWM_OUT_B,FLEXSPI2_A_DATA05,GPIO2_IO28,FLEXSPI1_A_DQS,,WDOG1_B,TMR3_TIMER1,GPIO8_IO28,,, -GPIO_EMC_B2_19,SEMC_CLKX00,ENET_MDC,ENET_1G_MDC,ENET_1G_REF_CLK,FLEXSPI2_A_DATA06,GPIO2_IO29,,,ENET_QOS_MDC,TMR3_TIMER2,GPIO8_IO29,,, -GPIO_EMC_B2_20,SEMC_CLKX01,ENET_MDIO,ENET_1G_MDIO,ENET_QOS_REF_CLK,FLEXSPI2_A_DATA07,GPIO2_IO30,,,ENET_QOS_MDIO,TMR3_TIMER3,GPIO8_IO30,,, -GPIO_SNVS_00_DIG,SNVS_TAMPER0,,,,,GPIO13_IO03,,,,,,,, -GPIO_SNVS_01_DIG,SNVS_TAMPER1,,,,,GPIO13_IO04,,,,,,,, -GPIO_SNVS_02_DIG,SNVS_TAMPER2,,,,,GPIO13_IO05,,,,,,,, -GPIO_SNVS_03_DIG,SNVS_TAMPER3,,,,,GPIO13_IO06,,,,,,,, -GPIO_SNVS_04_DIG,SNVS_TAMPER4,,,,,GPIO13_IO07,,,,,,,, -GPIO_SNVS_05_DIG,SNVS_TAMPER5,,,,,GPIO13_IO08,,,,,,,, -GPIO_SNVS_06_DIG,SNVS_TAMPER6,,,,,GPIO13_IO09,,,,,,,, -GPIO_SNVS_07_DIG,SNVS_TAMPER7,,,,,GPIO13_IO10,,,,,,,, -GPIO_SNVS_08_DIG,SNVS_TAMPER8,,,,,GPIO13_IO11,,,,,,,, -GPIO_SNVS_09_DIG,SNVS_TAMPER9,,,,,GPIO13_IO12,,,,,,,, -GPIO_LPSR_00,FLEXCAN3_TX,MIC_CLK,MQS_RIGHT,ARM_CM4_EVENTO,,GPIO6_IO00,LPUART12_TXD,SAI4_MCLK,,,GPIO12_IO00,,, -GPIO_LPSR_01,FLEXCAN3_RX,MIC_BITSTREAM0,MQS_LEFT,ARM_CM4_EVENTI,,GPIO6_IO01,LPUART12_RXD,,,,GPIO12_IO01,,, -GPIO_LPSR_02,SRC_BOOT_MODE00,LPSPI5_SCK,SAI4_TX_DATA,MQS_RIGHT,,GPIO6_IO02,,,,,GPIO12_IO02,,, -GPIO_LPSR_03,SRC_BOOT_MODE01,LPSPI5_PCS0,SAI4_TX_SYNC,MQS_LEFT,,GPIO6_IO03,,,,,GPIO12_IO03,,, -GPIO_LPSR_04,LPI2C5_SDA,LPSPI5_SOUT,SAI4_TX_BCLK,LPUART12_RTS_B,,GPIO6_IO04,LPUART11_TXD,,,,GPIO12_IO04,,, -GPIO_LPSR_05,LPI2C5_SCL,LPSPI5_SIN,SAI4_MCLK,LPUART12_CTS_B,,GPIO6_IO05,LPUART11_RXD,NMI_GLUE_NMI,,,GPIO12_IO05,,, -GPIO_LPSR_06,LPI2C6_SDA,,SAI4_RX_DATA,LPUART12_TXD,LPSPI6_PCS3,GPIO6_IO06,FLEXCAN3_TX,PIT2_TRIGGER3,LPSPI5_PCS1,,GPIO12_IO06,,, -GPIO_LPSR_07,LPI2C6_SCL,,SAI4_RX_BCLK,LPUART12_RXD,LPSPI6_PCS2,GPIO6_IO07,FLEXCAN3_RX,PIT2_TRIGGER2,LPSPI5_PCS2,,GPIO12_IO07,,, -GPIO_LPSR_08,LPUART11_TXD,FLEXCAN3_TX,SAI4_RX_SYNC,MIC_CLK,LPSPI6_PCS1,GPIO6_IO08,LPI2C5_SDA,PIT2_TRIGGER1,LPSPI5_PCS3,,GPIO12_IO08,,, -GPIO_LPSR_09,LPUART11_RXD,FLEXCAN3_RX,PIT2_TRIGGER0,MIC_BITSTREAM0,LPSPI6_PCS0,GPIO6_IO09,LPI2C5_SCL,SAI4_TX_DATA,,,GPIO12_IO09,,, -GPIO_LPSR_10,JTAG_MUX_TRSTB,LPUART11_CTS_B,LPI2C6_SDA,MIC_BITSTREAM1,LPSPI6_SCK,GPIO6_IO10,LPI2C5_SCLS,SAI4_TX_SYNC,LPUART12_TXD,,GPIO12_IO10,,, -GPIO_LPSR_11,JTAG_MUX_TDO,LPUART11_RTS_B,LPI2C6_SCL,MIC_BITSTREAM2,LPSPI6_SOUT,GPIO6_IO11,LPI2C5_SDAS,ARM_TRACE_SWO,LPUART12_RXD,,GPIO12_IO11,,, -GPIO_LPSR_12,JTAG_MUX_TDI,PIT2_TRIGGER0,,MIC_BITSTREAM3,LPSPI6_SIN,GPIO6_IO12,LPI2C5_HREQ,SAI4_TX_BCLK,LPSPI5_SCK,,GPIO12_IO12,,, -GPIO_LPSR_13,JTAG_MUX_MOD,MIC_BITSTREAM1,PIT2_TRIGGER1,,,GPIO6_IO13,,SAI4_RX_DATA,LPSPI5_PCS0,,GPIO12_IO13,,, -GPIO_LPSR_14,JTAG_MUX_TCK,MIC_BITSTREAM2,PIT2_TRIGGER2,,,GPIO6_IO14,,SAI4_RX_BCLK,LPSPI5_SOUT,,GPIO12_IO14,,, -GPIO_LPSR_15,JTAG_MUX_TMS,MIC_BITSTREAM3,PIT2_TRIGGER3,,,GPIO6_IO15,,SAI4_RX_SYNC,LPSPI5_SIN,,GPIO12_IO15,,, -WAKEUP_DIG,,,,,,GPIO13_IO00,,NMI_GLUE_NMI,,,,,, -PMIC_ON_REQ_DIG,SNVS_LP_PMIC_ON_REQ,,,,,GPIO13_IO01,,,,,,,, -PMIC_STBY_REQ_DIG,CCM_PMIC_VSTBY_REQ,,,,,GPIO13_IO02,,,,,,,, -GPIO_DISP_B1_00,VIDEO_MUX_LCDIF_CLK,ENET_1G_RX_EN,,TMR1_TIMER0,XBAR1_INOUT26,GPIO4_IO21,,,ENET_QOS_RX_EN,,GPIO10_IO21,,, -GPIO_DISP_B1_01,VIDEO_MUX_LCDIF_ENABLE,ENET_1G_RX_CLK,ENET_1G_RX_ER,TMR1_TIMER1,XBAR1_INOUT27,GPIO4_IO22,,,ENET_QOS_RX_CLK,ENET_QOS_RX_ER,GPIO10_IO22,,, -GPIO_DISP_B1_02,VIDEO_MUX_LCDIF_HSYNC,ENET_1G_RX_DATA00,LPI2C3_SCL,TMR1_TIMER2,XBAR1_INOUT28,GPIO4_IO23,,,ENET_QOS_RX_DATA00,LPUART1_TXD,GPIO10_IO23,,, -GPIO_DISP_B1_03,VIDEO_MUX_LCDIF_VSYNC,ENET_1G_RX_DATA01,LPI2C3_SDA,TMR2_TIMER0,XBAR1_INOUT29,GPIO4_IO24,,,ENET_QOS_RX_DATA01,LPUART1_RXD,GPIO10_IO24,,, -GPIO_DISP_B1_04,VIDEO_MUX_LCDIF_DATA00,ENET_1G_RX_DATA02,LPUART4_RXD,TMR2_TIMER1,XBAR1_INOUT30,GPIO4_IO25,,,ENET_QOS_RX_DATA02,LPSPI3_SCK,GPIO10_IO25,,, -GPIO_DISP_B1_05,VIDEO_MUX_LCDIF_DATA01,ENET_1G_RX_DATA03,LPUART4_CTS_B,TMR2_TIMER2,XBAR1_INOUT31,GPIO4_IO26,,,ENET_QOS_RX_DATA03,LPSPI3_SIN,GPIO10_IO26,,, -GPIO_DISP_B1_06,VIDEO_MUX_LCDIF_DATA02,ENET_1G_TX_DATA03,LPUART4_TXD,TMR3_TIMER0,XBAR1_INOUT32,GPIO4_IO27,SRC_BT_CFG00,,ENET_QOS_TX_DATA03,LPSPI3_SOUT,GPIO10_IO27,,, -GPIO_DISP_B1_07,VIDEO_MUX_LCDIF_DATA03,ENET_1G_TX_DATA02,LPUART4_RTS_B,TMR3_TIMER1,XBAR1_INOUT33,GPIO4_IO28,SRC_BT_CFG01,,ENET_QOS_TX_DATA02,LPSPI3_PCS0,GPIO10_IO28,,, -GPIO_DISP_B1_08,VIDEO_MUX_LCDIF_DATA04,ENET_1G_TX_DATA01,USDHC1_CD_B,TMR3_TIMER2,XBAR1_INOUT34,GPIO4_IO29,SRC_BT_CFG02,,ENET_QOS_TX_DATA01,LPSPI3_PCS1,GPIO10_IO29,,, -GPIO_DISP_B1_09,VIDEO_MUX_LCDIF_DATA05,ENET_1G_TX_DATA00,USDHC1_WP,TMR4_TIMER0,XBAR1_INOUT35,GPIO4_IO30,SRC_BT_CFG03,,ENET_QOS_TX_DATA00,LPSPI3_PCS2,GPIO10_IO30,,, -GPIO_DISP_B1_10,VIDEO_MUX_LCDIF_DATA06,ENET_1G_TX_EN,USDHC1_RESET_B,TMR4_TIMER1,XBAR1_INOUT36,GPIO4_IO31,SRC_BT_CFG04,,ENET_QOS_TX_EN,LPSPI3_PCS3,GPIO10_IO31,,, -GPIO_DISP_B1_11,VIDEO_MUX_LCDIF_DATA07,ENET_1G_TX_CLK_IO,ENET_1G_REF_CLK,TMR4_TIMER2,XBAR1_INOUT37,GPIO5_IO00,SRC_BT_CFG05,,ENET_QOS_TX_CLK,ENET_QOS_REF_CLK,GPIO11_IO00,,, -GPIO_DISP_B2_00,VIDEO_MUX_LCDIF_DATA08,WDOG1_B,MQS_RIGHT,ENET_1G_TX_ER,SAI1_TX_DATA03,GPIO5_IO01,SRC_BT_CFG06,,ENET_QOS_TX_ER,,GPIO11_IO01,,, -GPIO_DISP_B2_01,VIDEO_MUX_LCDIF_DATA09,USDHC1_VSELECT,MQS_LEFT,WDOG2_B,SAI1_TX_DATA02,GPIO5_IO02,SRC_BT_CFG07,,EWM_OUT_B,CCM_ENET_REF_CLK_25M,GPIO11_IO02,,, -GPIO_DISP_B2_02,VIDEO_MUX_LCDIF_DATA10,ENET_TX_DATA00,PIT1_TRIGGER3,ARM_TRACE00,SAI1_TX_DATA01,GPIO5_IO03,SRC_BT_CFG08,,ENET_QOS_TX_DATA00,,GPIO11_IO03,,, -GPIO_DISP_B2_03,VIDEO_MUX_LCDIF_DATA11,ENET_TX_DATA01,PIT1_TRIGGER2,ARM_TRACE01,SAI1_MCLK,GPIO5_IO04,SRC_BT_CFG09,,ENET_QOS_TX_DATA01,,GPIO11_IO04,,, -GPIO_DISP_B2_04,VIDEO_MUX_LCDIF_DATA12,ENET_TX_EN,PIT1_TRIGGER1,ARM_TRACE02,SAI1_RX_SYNC,GPIO5_IO05,SRC_BT_CFG10,,ENET_QOS_TX_EN,,GPIO11_IO05,,, -GPIO_DISP_B2_05,VIDEO_MUX_LCDIF_DATA13,ENET_TX_CLK,ENET_REF_CLK,ARM_TRACE03,SAI1_RX_BCLK,GPIO5_IO06,SRC_BT_CFG11,,ENET_QOS_TX_CLK,,GPIO11_IO06,,, -GPIO_DISP_B2_06,VIDEO_MUX_LCDIF_DATA14,ENET_RX_DATA00,LPUART7_TXD,ARM_TRACE_CLK,SAI1_RX_DATA00,GPIO5_IO07,,,ENET_QOS_RX_DATA00,,GPIO11_IO07,,, -GPIO_DISP_B2_07,VIDEO_MUX_LCDIF_DATA15,ENET_RX_DATA01,LPUART7_RXD,ARM_TRACE_SWO,SAI1_TX_DATA00,GPIO5_IO08,,,ENET_QOS_RX_DATA01,,GPIO11_IO08,,, -GPIO_DISP_B2_08,VIDEO_MUX_LCDIF_DATA16,ENET_RX_EN,LPUART8_TXD,ARM_CM7_EVENTO,SAI1_TX_BCLK,GPIO5_IO09,,,ENET_QOS_RX_EN,LPUART1_TXD,GPIO11_IO09,,, -GPIO_DISP_B2_09,VIDEO_MUX_LCDIF_DATA17,ENET_RX_ER,LPUART8_RXD,ARM_CM7_EVENTI,SAI1_TX_SYNC,GPIO5_IO10,,,ENET_QOS_RX_ER,LPUART1_RXD,GPIO11_IO10,,, -GPIO_DISP_B2_10,VIDEO_MUX_LCDIF_DATA18,EMVSIM2_IO,LPUART2_TXD,WDOG2_RESET_B_DEB,XBAR1_INOUT38,GPIO5_IO11,LPI2C3_SCL,,ENET_QOS_RX_ER,SPDIF_IN,GPIO11_IO11,,, -GPIO_DISP_B2_11,VIDEO_MUX_LCDIF_DATA19,EMVSIM2_CLK,LPUART2_RXD,WDOG1_RESET_B_DEB,XBAR1_INOUT39,GPIO5_IO12,LPI2C3_SDA,,ENET_QOS_CRS,SPDIF_OUT,GPIO11_IO12,,, -GPIO_DISP_B2_12,VIDEO_MUX_LCDIF_DATA20,EMVSIM2_RST,FLEXCAN1_TX,LPUART2_CTS_B,XBAR1_INOUT40,GPIO5_IO13,LPI2C4_SCL,,ENET_QOS_COL,LPSPI4_SCK,GPIO11_IO13,,, -GPIO_DISP_B2_13,VIDEO_MUX_LCDIF_DATA21,EMVSIM2_SVEN,FLEXCAN1_RX,LPUART2_RTS_B,ENET_REF_CLK,GPIO5_IO14,LPI2C4_SDA,,ENET_QOS_1588_EVENT0_OUT,LPSPI4_SIN,GPIO11_IO14,,, -GPIO_DISP_B2_14,VIDEO_MUX_LCDIF_DATA22,EMVSIM2_PD,WDOG2_B,VIDEO_MUX_EXT_DCIC1,ENET_1G_REF_CLK,GPIO5_IO15,FLEXCAN1_TX,,ENET_QOS_1588_EVENT0_IN,LPSPI4_SOUT,GPIO11_IO15,,, -GPIO_DISP_B2_15,VIDEO_MUX_LCDIF_DATA23,EMVSIM2_POWER_FAIL,WDOG1_B,VIDEO_MUX_EXT_DCIC2,PIT1_TRIGGER0,GPIO5_IO16,FLEXCAN1_RX,,ENET_QOS_1588_EVENT0_AUX_IN,LPSPI4_PCS0,GPIO11_IO16,,, -GPIO_AD_00,EMVSIM1_IO,FLEXCAN2_TX,ENET_1G_1588_EVENT1_IN,GPT2_CAPTURE1,FLEXPWM1_PWM0_A,GPIO2_IO31,LPUART7_TXD,,FLEXIO2_D00,FLEXSPI2_B_SS1_B,GPIO8_IO31,,ACMP1_IN1, -GPIO_AD_01,EMVSIM1_CLK,FLEXCAN2_RX,ENET_1G_1588_EVENT1_OUT,GPT2_CAPTURE2,FLEXPWM1_PWM0_B,GPIO3_IO00,LPUART7_RXD,,FLEXIO2_D01,FLEXSPI2_A_SS1_B,GPIO9_IO00,,ACMP1_IN2, -GPIO_AD_02,EMVSIM1_RST,LPUART7_CTS_B,ENET_1G_1588_EVENT2_IN,GPT2_COMPARE1,FLEXPWM1_PWM1_A,GPIO3_IO01,LPUART8_TXD,,FLEXIO2_D02,VIDEO_MUX_EXT_DCIC1,GPIO9_IO01,,ACMP1_IN3, -GPIO_AD_03,EMVSIM1_SVEN,LPUART7_RTS_B,ENET_1G_1588_EVENT2_OUT,GPT2_COMPARE2,FLEXPWM1_PWM1_B,GPIO3_IO02,LPUART8_RXD,,FLEXIO2_D03,VIDEO_MUX_EXT_DCIC2,GPIO9_IO02,,ACMP1_IN4, -GPIO_AD_04,EMVSIM1_PD,LPUART8_CTS_B,ENET_1G_1588_EVENT3_IN,GPT2_COMPARE3,FLEXPWM1_PWM2_A,GPIO3_IO03,WDOG1_B,,FLEXIO2_D04,TMR4_TIMER0,GPIO9_IO03,,ACMP2_IN1, -GPIO_AD_05,EMVSIM1_POWER_FAIL,LPUART8_RTS_B,ENET_1G_1588_EVENT3_OUT,GPT2_CLK,FLEXPWM1_PWM2_B,GPIO3_IO04,WDOG2_B,,FLEXIO2_D05,TMR4_TIMER1,GPIO9_IO04,,ACMP2_IN2, -GPIO_AD_06,USB_OTG2_OC,FLEXCAN1_TX,EMVSIM2_IO,GPT3_CAPTURE1,VIDEO_MUX_CSI_DATA15,GPIO3_IO05,ENET_1588_EVENT1_IN,,FLEXIO2_D06,TMR4_TIMER2,GPIO9_IO05,ADC1_CH0A,, -GPIO_AD_07,USB_OTG2_PWR,FLEXCAN1_RX,EMVSIM2_CLK,GPT3_CAPTURE2,VIDEO_MUX_CSI_DATA14,GPIO3_IO06,ENET_1588_EVENT1_OUT,,FLEXIO2_D07,TMR4_TIMER3,GPIO9_IO06,ADC1_CH0B,, -GPIO_AD_08,USBPHY2_OTG_ID,LPI2C1_SCL,EMVSIM2_RST,GPT3_COMPARE1,VIDEO_MUX_CSI_DATA13,GPIO3_IO07,ENET_1588_EVENT2_IN,,FLEXIO2_D08,,GPIO9_IO07,ADC1_CH1A,, -GPIO_AD_09,USBPHY1_OTG_ID,LPI2C1_SDA,EMVSIM2_SVEN,GPT3_COMPARE2,VIDEO_MUX_CSI_DATA12,GPIO3_IO08,ENET_1588_EVENT2_OUT,,FLEXIO2_D09,,GPIO9_IO08,ADC1_CH1B,, -GPIO_AD_10,USB_OTG1_PWR,LPI2C1_SCLS,EMVSIM2_PD,GPT3_COMPARE3,VIDEO_MUX_CSI_DATA11,GPIO3_IO09,ENET_1588_EVENT3_IN,,FLEXIO2_D10,,GPIO9_IO09,ADC1_CH2A,, -GPIO_AD_11,USB_OTG1_OC,LPI2C1_SDAS,EMVSIM2_POWER_FAIL,GPT3_CLK,VIDEO_MUX_CSI_DATA10,GPIO3_IO10,ENET_1588_EVENT3_OUT,,FLEXIO2_D11,,GPIO9_IO10,ADC1_CH2B,, -GPIO_AD_12,SPDIF_LOCK,LPI2C1_HREQ,GPT1_CAPTURE1,FLEXSPI1_B_DATA03,VIDEO_MUX_CSI_PIXCLK,GPIO3_IO11,ENET_TX_DATA03,,FLEXIO2_D12,EWM_OUT_B,GPIO9_IO11,"ADC1_CH3A,ADC2_CH3A",, -GPIO_AD_13,SPDIF_SR_CLK,PIT1_TRIGGER0,GPT1_CAPTURE2,FLEXSPI1_B_DATA02,VIDEO_MUX_CSI_MCLK,GPIO3_IO12,ENET_TX_DATA02,,FLEXIO2_D13,REF_CLK_32K,GPIO9_IO12,"ADC1_CH3B,ADC2_CH3B",, -GPIO_AD_14,SPDIF_EXT_CLK,REF_CLK_24M,GPT1_COMPARE1,FLEXSPI1_B_DATA01,VIDEO_MUX_CSI_VSYNC,GPIO3_IO13,ENET_RX_CLK,,FLEXIO2_D14,CCM_ENET_REF_CLK_25M,GPIO9_IO13,"ADC1_CH4A,ADC2_CH4A",, -GPIO_AD_15,SPDIF_IN,LPUART10_TXD,GPT1_COMPARE2,FLEXSPI1_B_DATA00,VIDEO_MUX_CSI_HSYNC,GPIO3_IO14,ENET_TX_ER,,FLEXIO2_D15,,GPIO9_IO14,"ADC1_CH4B,ADC2_CH4B",, -GPIO_AD_16,SPDIF_OUT,LPUART10_RXD,GPT1_COMPARE3,FLEXSPI1_B_SCLK,VIDEO_MUX_CSI_DATA09,GPIO3_IO15,ENET_RX_DATA03,,FLEXIO2_D16,ENET_1G_MDC,GPIO9_IO15,"ADC1_CH5A,ADC2_CH5A",, -GPIO_AD_17,SAI1_MCLK,ACMP1_OUT,GPT1_CLK,FLEXSPI1_A_DQS,VIDEO_MUX_CSI_DATA08,GPIO3_IO16,ENET_RX_DATA02,,FLEXIO2_D17,ENET_1G_MDIO,GPIO9_IO16,"ADC1_CH5B,ADC2_CH5B",ACMP1_OUT, -GPIO_AD_18,SAI1_RX_SYNC,ACMP2_OUT,LPSPI1_PCS1,FLEXSPI1_A_SS0_B,VIDEO_MUX_CSI_DATA07,GPIO3_IO17,ENET_CRS,,FLEXIO2_D18,LPI2C2_SCL,GPIO9_IO17,ADC2_CH0A,ACMP2_OUT, -GPIO_AD_19,SAI1_RX_BCLK,ACMP3_OUT,LPSPI1_PCS2,FLEXSPI1_A_SCLK,VIDEO_MUX_CSI_DATA06,GPIO3_IO18,ENET_COL,,FLEXIO2_D19,LPI2C2_SDA,GPIO9_IO18,ADC2_CH0B,ACMP3_OUT, -GPIO_AD_20,SAI1_RX_DATA00,ACMP4_OUT,LPSPI1_PCS3,FLEXSPI1_A_DATA00,VIDEO_MUX_CSI_DATA05,GPIO3_IO19,KPP_ROW07,,FLEXIO2_D20,ENET_QOS_1588_EVENT2_OUT,GPIO9_IO19,ADC2_CH1A,ACMP4_OUT, -GPIO_AD_21,SAI1_TX_DATA00,,LPSPI2_PCS1,FLEXSPI1_A_DATA01,VIDEO_MUX_CSI_DATA04,GPIO3_IO20,KPP_COL07,,FLEXIO2_D21,ENET_QOS_1588_EVENT2_IN,GPIO9_IO20,ADC2_CH1B,, -GPIO_AD_22,SAI1_TX_BCLK,,LPSPI2_PCS2,FLEXSPI1_A_DATA02,VIDEO_MUX_CSI_DATA03,GPIO3_IO21,KPP_ROW06,,FLEXIO2_D22,ENET_QOS_1588_EVENT3_OUT,GPIO9_IO21,ADC2_CH2A,, -GPIO_AD_23,SAI1_TX_SYNC,,LPSPI2_PCS3,FLEXSPI1_A_DATA03,VIDEO_MUX_CSI_DATA02,GPIO3_IO22,KPP_COL06,,FLEXIO2_D23,ENET_QOS_1588_EVENT3_IN,GPIO9_IO22,ADC2_CH2B,, -GPIO_AD_24,LPUART1_TXD,LPSPI2_SCK,VIDEO_MUX_CSI_DATA00,ENET_RX_EN,FLEXPWM2_PWM0_A,GPIO3_IO23,KPP_ROW05,,FLEXIO2_D24,LPI2C4_SCL,GPIO9_IO23,ADC2_CH6A,, -GPIO_AD_25,LPUART1_RXD,LPSPI2_PCS0,VIDEO_MUX_CSI_DATA01,ENET_RX_ER,FLEXPWM2_PWM0_B,GPIO3_IO24,KPP_COL05,,FLEXIO2_D25,LPI2C4_SDA,GPIO9_IO24,ADC2_CH6B,, -GPIO_AD_26,LPUART1_CTS_B,LPSPI2_SOUT,SEMC_CSX01,ENET_RX_DATA00,FLEXPWM2_PWM1_A,GPIO3_IO25,KPP_ROW04,,FLEXIO2_D26,ENET_QOS_MDC,GPIO9_IO25,,ACMP2_IN3, -GPIO_AD_27,LPUART1_RTS_B,LPSPI2_SIN,SEMC_CSX02,ENET_RX_DATA01,FLEXPWM2_PWM1_B,GPIO3_IO26,KPP_COL04,,FLEXIO2_D27,ENET_QOS_MDIO,GPIO9_IO26,,ACMP2_IN4, -GPIO_AD_28,LPSPI1_SCK,LPUART5_TXD,SEMC_CSX03,ENET_TX_EN,FLEXPWM2_PWM2_A,GPIO3_IO27,KPP_ROW03,,FLEXIO2_D28,VIDEO_MUX_EXT_DCIC1,GPIO9_IO27,,ACMP3_IN1, -GPIO_AD_29,LPSPI1_PCS0,LPUART5_RXD,ENET_REF_CLK,ENET_TX_CLK,FLEXPWM2_PWM2_B,GPIO3_IO28,KPP_COL03,,FLEXIO2_D29,VIDEO_MUX_EXT_DCIC2,GPIO9_IO28,,ACMP3_IN2, -GPIO_AD_30,LPSPI1_SOUT,USB_OTG2_OC,FLEXCAN2_TX,ENET_TX_DATA00,LPUART3_TXD,GPIO3_IO29,KPP_ROW02,,FLEXIO2_D30,WDOG2_RESET_B_DEB,GPIO9_IO29,,ACMP3_IN3, -GPIO_AD_31,LPSPI1_SIN,USB_OTG2_PWR,FLEXCAN2_RX,ENET_TX_DATA01,LPUART3_RXD,GPIO3_IO30,KPP_COL02,,FLEXIO2_D31,WDOG1_RESET_B_DEB,GPIO9_IO30,,ACMP3_IN4, -GPIO_AD_32,LPI2C1_SCL,USBPHY2_OTG_ID,PGMC_PMIC_RDY,ENET_MDC,USDHC1_CD_B,GPIO3_IO31,KPP_ROW01,,LPUART10_TXD,ENET_1G_MDC,GPIO9_IO31,,ACMP4_IN1, -GPIO_AD_33,LPI2C1_SDA,USBPHY1_OTG_ID,XBAR1_INOUT17,ENET_MDIO,USDHC1_WP,GPIO4_IO00,KPP_COL01,,LPUART10_RXD,ENET_1G_MDIO,GPIO10_IO00,,ACMP4_IN2, -GPIO_AD_34,ENET_1G_1588_EVENT0_IN,USB_OTG1_PWR,XBAR1_INOUT18,ENET_1588_EVENT0_IN,USDHC1_VSELECT,GPIO4_IO01,KPP_ROW00,,LPUART10_CTS_B,WDOG1_ANY,GPIO10_IO01,,ACMP4_IN3, -GPIO_AD_35,ENET_1G_1588_EVENT0_OUT,USB_OTG1_OC,XBAR1_INOUT19,ENET_1588_EVENT0_OUT,USDHC1_RESET_B,GPIO4_IO02,KPP_COL00,,LPUART10_RTS_B,FLEXSPI1_B_SS1_B,GPIO10_IO02,,ACMP4_IN4, +Pad,ALT0,ALT1,ALT2,ALT3,ALT4,ALT5,ALT6,ALT7,ALT8,ALT9,ALT10,ALT11,ADC,ACMP,Default +GPIO_SD_B1_00,USDHC1_CMD,,XBAR1_INOUT20,GPT4_CAPTURE1,,GPIO4_IO03,FLEXSPI2_A_SS0_B,,KPP_ROW07,,GPIO10_IO03,,,, +GPIO_SD_B1_01,USDHC1_CLK,,XBAR1_INOUT21,GPT4_CAPTURE2,,GPIO4_IO04,FLEXSPI2_A_SCLK,,KPP_COL07,,GPIO10_IO04,,,, +GPIO_SD_B1_02,USDHC1_DATA0,,XBAR1_INOUT22,GPT4_COMPARE1,,GPIO4_IO05,FLEXSPI2_A_DATA00,,KPP_ROW06,FLEXSPI1_A_SS1_B,GPIO10_IO05,,,, +GPIO_SD_B1_03,USDHC1_DATA1,,XBAR1_INOUT23,GPT4_COMPARE2,,GPIO4_IO06,FLEXSPI2_A_DATA01,,KPP_COL06,FLEXSPI1_B_SS1_B,GPIO10_IO06,,,, +GPIO_SD_B1_04,USDHC1_DATA2,,XBAR1_INOUT24,GPT4_COMPARE3,,GPIO4_IO07,FLEXSPI2_A_DATA02,,FLEXSPI1_B_SS0_B,ENET_QOS_1588_EVENT2_AUX_IN,GPIO10_IO07,,,, +GPIO_SD_B1_05,USDHC1_DATA3,,XBAR1_INOUT25,GPT4_CLK,,GPIO4_IO08,FLEXSPI2_A_DATA03,,FLEXSPI1_B_DQS,ENET_QOS_1588_EVENT3_AUX_IN,GPIO10_IO08,,,, +GPIO_SD_B2_00,USDHC2_DATA3,FLEXSPI1_B_DATA03,ENET_1G_RX_EN,LPUART9_TXD,LPSPI4_SCK,GPIO4_IO09,,,,,GPIO10_IO09,,,, +GPIO_SD_B2_01,USDHC2_DATA2,FLEXSPI1_B_DATA02,ENET_1G_RX_CLK,LPUART9_RXD,LPSPI4_PCS0,GPIO4_IO10,,,,,GPIO10_IO10,,,, +GPIO_SD_B2_02,USDHC2_DATA1,FLEXSPI1_B_DATA01,ENET_1G_RX_DATA00,LPUART9_CTS_B,LPSPI4_SOUT,GPIO4_IO11,,,,,GPIO10_IO11,,,, +GPIO_SD_B2_03,USDHC2_DATA0,FLEXSPI1_B_DATA00,ENET_1G_RX_DATA01,LPUART9_RTS_B,LPSPI4_SIN,GPIO4_IO12,,,,,GPIO10_IO12,,,, +GPIO_SD_B2_04,USDHC2_CLK,FLEXSPI1_B_SCLK,ENET_1G_RX_DATA02,FLEXSPI1_A_SS1_B,LPSPI4_PCS1,GPIO4_IO13,,,,,GPIO10_IO13,,,, +GPIO_SD_B2_05,USDHC2_CMD,FLEXSPI1_A_DQS,ENET_1G_RX_DATA03,FLEXSPI1_B_SS0_B,LPSPI4_PCS2,GPIO4_IO14,,,,,GPIO10_IO14,,,, +GPIO_SD_B2_06,USDHC2_RESET_B,FLEXSPI1_A_SS0_B,ENET_1G_TX_DATA03,LPSPI4_PCS3,GPT6_CAPTURE1,GPIO4_IO15,,,,,GPIO10_IO15,,,, +GPIO_SD_B2_07,USDHC2_STROBE,FLEXSPI1_A_SCLK,ENET_1G_TX_DATA02,LPUART3_CTS_B,GPT6_CAPTURE2,GPIO4_IO16,LPSPI2_SCK,,ENET_TX_ER,ENET_QOS_REF_CLK,GPIO10_IO16,,,, +GPIO_SD_B2_08,USDHC2_DATA4,FLEXSPI1_A_DATA00,ENET_1G_TX_DATA01,LPUART3_RTS_B,GPT6_COMPARE1,GPIO4_IO17,LPSPI2_PCS0,,,,GPIO10_IO17,,,, +GPIO_SD_B2_09,USDHC2_DATA5,FLEXSPI1_A_DATA01,ENET_1G_TX_DATA00,LPUART5_CTS_B,GPT6_COMPARE2,GPIO4_IO18,LPSPI2_SOUT,,,,GPIO10_IO18,,,, +GPIO_SD_B2_10,USDHC2_DATA6,FLEXSPI1_A_DATA02,ENET_1G_TX_EN,LPUART5_RTS_B,GPT6_COMPARE3,GPIO4_IO19,LPSPI2_SIN,,,,GPIO10_IO19,,,, +GPIO_SD_B2_11,USDHC2_DATA7,FLEXSPI1_A_DATA03,ENET_1G_TX_CLK_IO,ENET_1G_REF_CLK,GPT6_CLK,GPIO4_IO20,LPSPI2_PCS1,,,,GPIO10_IO20,,,, +GPIO_EMC_B1_00,SEMC_DATA00,FLEXPWM4_PWM0_A,,,,GPIO1_IO00,,,FLEXIO1_D00,,GPIO7_IO00,,,, +GPIO_EMC_B1_01,SEMC_DATA01,FLEXPWM4_PWM0_B,,,,GPIO1_IO01,,,FLEXIO1_D01,,GPIO7_IO01,,,, +GPIO_EMC_B1_02,SEMC_DATA02,FLEXPWM4_PWM1_A,,,,GPIO1_IO02,,,FLEXIO1_D02,,GPIO7_IO02,,,, +GPIO_EMC_B1_03,SEMC_DATA03,FLEXPWM4_PWM1_B,,,,GPIO1_IO03,,,FLEXIO1_D03,,GPIO7_IO03,,,, +GPIO_EMC_B1_04,SEMC_DATA04,FLEXPWM4_PWM2_A,,,,GPIO1_IO04,,,FLEXIO1_D04,,GPIO7_IO04,,,, +GPIO_EMC_B1_05,SEMC_DATA05,FLEXPWM4_PWM2_B,,,,GPIO1_IO05,,,FLEXIO1_D05,,GPIO7_IO05,,,, +GPIO_EMC_B1_06,SEMC_DATA06,FLEXPWM2_PWM0_A,,,,GPIO1_IO06,,,FLEXIO1_D06,,GPIO7_IO06,,,, +GPIO_EMC_B1_07,SEMC_DATA07,FLEXPWM2_PWM0_B,,,,GPIO1_IO07,,,FLEXIO1_D07,,GPIO7_IO07,,,, +GPIO_EMC_B1_08,SEMC_DM00,FLEXPWM2_PWM1_A,,,,GPIO1_IO08,,,FLEXIO1_D08,,GPIO7_IO08,,,, +GPIO_EMC_B1_09,SEMC_ADDR00,FLEXPWM2_PWM1_B,GPT5_CAPTURE1,,,GPIO1_IO09,,,FLEXIO1_D09,,GPIO7_IO09,,,, +GPIO_EMC_B1_10,SEMC_ADDR01,FLEXPWM2_PWM2_A,GPT5_CAPTURE2,,,GPIO1_IO10,,,FLEXIO1_D10,,GPIO7_IO10,,,, +GPIO_EMC_B1_11,SEMC_ADDR02,FLEXPWM2_PWM2_B,GPT5_COMPARE1,,,GPIO1_IO11,,,FLEXIO1_D11,,GPIO7_IO11,,,, +GPIO_EMC_B1_12,SEMC_ADDR03,XBAR1_INOUT04,GPT5_COMPARE2,,,GPIO1_IO12,,,FLEXIO1_D12,,GPIO7_IO12,,,, +GPIO_EMC_B1_13,SEMC_ADDR04,XBAR1_INOUT05,GPT5_COMPARE3,,,GPIO1_IO13,,,FLEXIO1_D13,,GPIO7_IO13,,,, +GPIO_EMC_B1_14,SEMC_ADDR05,XBAR1_INOUT06,GPT5_CLK,,,GPIO1_IO14,,,FLEXIO1_D14,,GPIO7_IO14,,,, +GPIO_EMC_B1_15,SEMC_ADDR06,XBAR1_INOUT07,,,,GPIO1_IO15,,,FLEXIO1_D15,,GPIO7_IO15,,,, +GPIO_EMC_B1_16,SEMC_ADDR07,XBAR1_INOUT08,,,,GPIO1_IO16,,,FLEXIO1_D16,,GPIO7_IO16,,,, +GPIO_EMC_B1_17,SEMC_ADDR08,FLEXPWM4_PWM3_A,TMR1_TIMER0,,,GPIO1_IO17,,,FLEXIO1_D17,,GPIO7_IO17,,,, +GPIO_EMC_B1_18,SEMC_ADDR09,FLEXPWM4_PWM3_B,TMR2_TIMER0,,,GPIO1_IO18,,,FLEXIO1_D18,,GPIO7_IO18,,,, +GPIO_EMC_B1_19,SEMC_ADDR11,FLEXPWM2_PWM3_A,TMR3_TIMER0,,,GPIO1_IO19,,,FLEXIO1_D19,,GPIO7_IO19,,,, +GPIO_EMC_B1_20,SEMC_ADDR12,FLEXPWM2_PWM3_B,TMR4_TIMER0,,,GPIO1_IO20,,,FLEXIO1_D20,,GPIO7_IO20,,,, +GPIO_EMC_B1_21,SEMC_BA0,FLEXPWM3_PWM3_A,,,,GPIO1_IO21,,,FLEXIO1_D21,,GPIO7_IO21,,,, +GPIO_EMC_B1_22,SEMC_BA1,FLEXPWM3_PWM3_B,,,,GPIO1_IO22,,,FLEXIO1_D22,,GPIO7_IO22,,,, +GPIO_EMC_B1_23,SEMC_ADDR10,FLEXPWM1_PWM0_A,,,,GPIO1_IO23,,,FLEXIO1_D23,,GPIO7_IO23,,,, +GPIO_EMC_B1_24,SEMC_CAS,FLEXPWM1_PWM0_B,,,,GPIO1_IO24,,,FLEXIO1_D24,,GPIO7_IO24,,,, +GPIO_EMC_B1_25,SEMC_RAS,FLEXPWM1_PWM1_A,,,,GPIO1_IO25,,,FLEXIO1_D25,,GPIO7_IO25,,,, +GPIO_EMC_B1_26,SEMC_CLK,FLEXPWM1_PWM1_B,,,,GPIO1_IO26,,,FLEXIO1_D26,,GPIO7_IO26,,,, +GPIO_EMC_B1_27,SEMC_CKE,FLEXPWM1_PWM2_A,,,,GPIO1_IO27,,,FLEXIO1_D27,,GPIO7_IO27,,,, +GPIO_EMC_B1_28,SEMC_WE,FLEXPWM1_PWM2_B,,,,GPIO1_IO28,,,FLEXIO1_D28,,GPIO7_IO28,,,, +GPIO_EMC_B1_29,SEMC_CS0,FLEXPWM3_PWM0_A,,,,GPIO1_IO29,,,FLEXIO1_D29,,GPIO7_IO29,,,, +GPIO_EMC_B1_30,SEMC_DATA08,FLEXPWM3_PWM0_B,,,,GPIO1_IO30,,,FLEXIO1_D30,,GPIO7_IO30,,,, +GPIO_EMC_B1_31,SEMC_DATA09,FLEXPWM3_PWM1_A,,,,GPIO1_IO31,,,FLEXIO1_D31,,GPIO7_IO31,,,, +GPIO_EMC_B1_32,SEMC_DATA10,FLEXPWM3_PWM1_B,,,,GPIO2_IO00,,,,,GPIO8_IO00,,,, +GPIO_EMC_B1_33,SEMC_DATA11,FLEXPWM3_PWM2_A,,,,GPIO2_IO01,,,,,GPIO8_IO01,,,, +GPIO_EMC_B1_34,SEMC_DATA12,FLEXPWM3_PWM2_B,,,,GPIO2_IO02,,,,,GPIO8_IO02,,,, +GPIO_EMC_B1_35,SEMC_DATA13,XBAR1_INOUT09,,,,GPIO2_IO03,,,,,GPIO8_IO03,,,, +GPIO_EMC_B1_36,SEMC_DATA14,XBAR1_INOUT10,,,,GPIO2_IO04,,,,,GPIO8_IO04,,,, +GPIO_EMC_B1_37,SEMC_DATA15,XBAR1_INOUT11,,,,GPIO2_IO05,,,,,GPIO8_IO05,,,, +GPIO_EMC_B1_38,SEMC_DM01,FLEXPWM1_PWM3_A,TMR1_TIMER1,,,GPIO2_IO06,,,,,GPIO8_IO06,,,, +GPIO_EMC_B1_39,SEMC_DQS,FLEXPWM1_PWM3_B,TMR2_TIMER1,,,GPIO2_IO07,,,,,GPIO8_IO07,,,, +GPIO_EMC_B1_40,SEMC_RDY,XBAR1_INOUT12,MQS_RIGHT,LPUART6_TXD,,GPIO2_IO08,,ENET_1G_MDC,,CCM_CLKO1,GPIO8_IO08,,,, +GPIO_EMC_B1_41,SEMC_CSX00,XBAR1_INOUT13,MQS_LEFT,LPUART6_RXD,FLEXSPI2_B_DATA07,GPIO2_IO09,,ENET_1G_MDIO,,CCM_CLKO2,GPIO8_IO09,,,, +GPIO_EMC_B2_00,SEMC_DATA16,CCM_ENET_REF_CLK_25M,TMR3_TIMER1,LPUART6_CTS_B,FLEXSPI2_B_DATA06,GPIO2_IO10,XBAR1_INOUT20,ENET_QOS_1588_EVENT1_OUT,LPSPI1_SCK,LPI2C2_SCL,GPIO8_IO10,FLEXPWM3_PWM0_A,,, +GPIO_EMC_B2_01,SEMC_DATA17,USDHC2_CD_B,TMR4_TIMER1,LPUART6_RTS_B,FLEXSPI2_B_DATA05,GPIO2_IO11,XBAR1_INOUT21,ENET_QOS_1588_EVENT1_IN,LPSPI1_PCS0,LPI2C2_SDA,GPIO8_IO11,FLEXPWM3_PWM0_B,,, +GPIO_EMC_B2_02,SEMC_DATA18,USDHC2_WP,,VIDEO_MUX_CSI_DATA23,FLEXSPI2_B_DATA04,GPIO2_IO12,XBAR1_INOUT22,ENET_QOS_1588_EVENT1_AUX_IN,LPSPI1_SOUT,,GPIO8_IO12,FLEXPWM3_PWM1_A,,, +GPIO_EMC_B2_03,SEMC_DATA19,USDHC2_VSELECT,,VIDEO_MUX_CSI_DATA22,FLEXSPI2_B_DATA03,GPIO2_IO13,XBAR1_INOUT23,ENET_1G_TX_DATA03,LPSPI1_SIN,,GPIO8_IO13,FLEXPWM3_PWM1_B,,, +GPIO_EMC_B2_04,SEMC_DATA20,USDHC2_RESET_B,SAI2_MCLK,VIDEO_MUX_CSI_DATA21,FLEXSPI2_B_DATA02,GPIO2_IO14,XBAR1_INOUT24,ENET_1G_TX_DATA02,LPSPI3_SCK,,GPIO8_IO14,FLEXPWM3_PWM2_A,,, +GPIO_EMC_B2_05,SEMC_DATA21,GPT3_CLK,SAI2_RX_SYNC,VIDEO_MUX_CSI_DATA20,FLEXSPI2_B_DATA01,GPIO2_IO15,XBAR1_INOUT25,ENET_1G_RX_CLK,LPSPI3_PCS0,PIT1_TRIGGER0,GPIO8_IO15,FLEXPWM3_PWM2_B,,, +GPIO_EMC_B2_06,SEMC_DATA22,GPT3_CAPTURE1,SAI2_RX_BCLK,VIDEO_MUX_CSI_DATA19,FLEXSPI2_B_DATA00,GPIO2_IO16,XBAR1_INOUT26,ENET_1G_TX_ER,LPSPI3_SOUT,PIT1_TRIGGER1,GPIO8_IO16,FLEXPWM3_PWM3_A,,, +GPIO_EMC_B2_07,SEMC_DATA23,GPT3_CAPTURE2,SAI2_RX_DATA,VIDEO_MUX_CSI_DATA18,FLEXSPI2_B_DQS,GPIO2_IO17,XBAR1_INOUT27,ENET_1G_RX_DATA03,LPSPI3_SIN,PIT1_TRIGGER2,GPIO8_IO17,FLEXPWM3_PWM3_B,,, +GPIO_EMC_B2_08,SEMC_DM02,GPT3_COMPARE1,SAI2_TX_DATA,VIDEO_MUX_CSI_DATA17,FLEXSPI2_B_SS0_B,GPIO2_IO18,XBAR1_INOUT28,ENET_1G_RX_DATA02,LPSPI3_PCS1,PIT1_TRIGGER3,GPIO8_IO18,,,, +GPIO_EMC_B2_09,SEMC_DATA24,GPT3_COMPARE2,SAI2_TX_BCLK,VIDEO_MUX_CSI_DATA16,FLEXSPI2_B_SCLK,GPIO2_IO19,XBAR1_INOUT29,ENET_1G_CRS,LPSPI3_PCS2,TMR1_TIMER0,GPIO8_IO19,,,, +GPIO_EMC_B2_10,SEMC_DATA25,GPT3_COMPARE3,SAI2_TX_SYNC,VIDEO_MUX_CSI_FIELD,FLEXSPI2_A_SCLK,GPIO2_IO20,XBAR1_INOUT30,ENET_1G_COL,LPSPI3_PCS3,TMR1_TIMER1,GPIO8_IO20,,,, +GPIO_EMC_B2_11,SEMC_DATA26,SPDIF_IN,ENET_1G_TX_DATA00,SAI3_RX_SYNC,FLEXSPI2_A_SS0_B,GPIO2_IO21,XBAR1_INOUT31,,EMVSIM1_IO,TMR1_TIMER2,GPIO8_IO21,,,, +GPIO_EMC_B2_12,SEMC_DATA27,SPDIF_OUT,ENET_1G_TX_DATA01,SAI3_RX_BCLK,FLEXSPI2_A_DQS,GPIO2_IO22,XBAR1_INOUT32,,EMVSIM1_CLK,TMR1_TIMER3,GPIO8_IO22,,,, +GPIO_EMC_B2_13,SEMC_DATA28,,ENET_1G_TX_EN,SAI3_RX_DATA,FLEXSPI2_A_DATA00,GPIO2_IO23,XBAR1_INOUT33,,EMVSIM1_RST,TMR2_TIMER0,GPIO8_IO23,,,, +GPIO_EMC_B2_14,SEMC_DATA29,,ENET_1G_TX_CLK_IO,SAI3_TX_DATA,FLEXSPI2_A_DATA01,GPIO2_IO24,XBAR1_INOUT34,SFA_ipp_do_atx_clk_under_test,EMVSIM1_SVEN,TMR2_TIMER1,GPIO8_IO24,,,, +GPIO_EMC_B2_15,SEMC_DATA30,,ENET_1G_RX_DATA00,SAI3_TX_BCLK,FLEXSPI2_A_DATA02,GPIO2_IO25,XBAR1_INOUT35,,EMVSIM1_PD,TMR2_TIMER2,GPIO8_IO25,,,, +GPIO_EMC_B2_16,SEMC_DATA31,XBAR1_INOUT14,ENET_1G_RX_DATA01,SAI3_TX_SYNC,FLEXSPI2_A_DATA03,GPIO2_IO26,,,EMVSIM1_POWER_FAIL,TMR2_TIMER3,GPIO8_IO26,,,, +GPIO_EMC_B2_17,SEMC_DM03,XBAR1_INOUT15,ENET_1G_RX_EN,SAI3_MCLK,FLEXSPI2_A_DATA04,GPIO2_IO27,,,WDOG1_ANY,TMR3_TIMER0,GPIO8_IO27,,,, +GPIO_EMC_B2_18,SEMC_DQS4,XBAR1_INOUT16,ENET_1G_RX_ER,EWM_OUT_B,FLEXSPI2_A_DATA05,GPIO2_IO28,FLEXSPI1_A_DQS,,WDOG1_B,TMR3_TIMER1,GPIO8_IO28,,,, +GPIO_EMC_B2_19,SEMC_CLKX00,ENET_MDC,ENET_1G_MDC,ENET_1G_REF_CLK,FLEXSPI2_A_DATA06,GPIO2_IO29,,,ENET_QOS_MDC,TMR3_TIMER2,GPIO8_IO29,,,, +GPIO_EMC_B2_20,SEMC_CLKX01,ENET_MDIO,ENET_1G_MDIO,ENET_QOS_REF_CLK,FLEXSPI2_A_DATA07,GPIO2_IO30,,,ENET_QOS_MDIO,TMR3_TIMER3,GPIO8_IO30,,,, +GPIO_SNVS_00_DIG,SNVS_TAMPER0,,,,,GPIO13_IO03,,,,,,,,, +GPIO_SNVS_01_DIG,SNVS_TAMPER1,,,,,GPIO13_IO04,,,,,,,,, +GPIO_SNVS_02_DIG,SNVS_TAMPER2,,,,,GPIO13_IO05,,,,,,,,, +GPIO_SNVS_03_DIG,SNVS_TAMPER3,,,,,GPIO13_IO06,,,,,,,,, +GPIO_SNVS_04_DIG,SNVS_TAMPER4,,,,,GPIO13_IO07,,,,,,,,, +GPIO_SNVS_05_DIG,SNVS_TAMPER5,,,,,GPIO13_IO08,,,,,,,,, +GPIO_SNVS_06_DIG,SNVS_TAMPER6,,,,,GPIO13_IO09,,,,,,,,, +GPIO_SNVS_07_DIG,SNVS_TAMPER7,,,,,GPIO13_IO10,,,,,,,,, +GPIO_SNVS_08_DIG,SNVS_TAMPER8,,,,,GPIO13_IO11,,,,,,,,, +GPIO_SNVS_09_DIG,SNVS_TAMPER9,,,,,GPIO13_IO12,,,,,,,,, +GPIO_LPSR_00,FLEXCAN3_TX,MIC_CLK,MQS_RIGHT,ARM_CM4_EVENTO,,GPIO6_IO00,LPUART12_TXD,SAI4_MCLK,,,GPIO12_IO00,,,, +GPIO_LPSR_01,FLEXCAN3_RX,MIC_BITSTREAM0,MQS_LEFT,ARM_CM4_EVENTI,,GPIO6_IO01,LPUART12_RXD,,,,GPIO12_IO01,,,, +GPIO_LPSR_02,SRC_BOOT_MODE00,LPSPI5_SCK,SAI4_TX_DATA,MQS_RIGHT,,GPIO6_IO02,,,,,GPIO12_IO02,,,, +GPIO_LPSR_03,SRC_BOOT_MODE01,LPSPI5_PCS0,SAI4_TX_SYNC,MQS_LEFT,,GPIO6_IO03,,,,,GPIO12_IO03,,,, +GPIO_LPSR_04,LPI2C5_SDA,LPSPI5_SOUT,SAI4_TX_BCLK,LPUART12_RTS_B,,GPIO6_IO04,LPUART11_TXD,,,,GPIO12_IO04,,,, +GPIO_LPSR_05,LPI2C5_SCL,LPSPI5_SIN,SAI4_MCLK,LPUART12_CTS_B,,GPIO6_IO05,LPUART11_RXD,NMI_GLUE_NMI,,,GPIO12_IO05,,,, +GPIO_LPSR_06,LPI2C6_SDA,,SAI4_RX_DATA,LPUART12_TXD,LPSPI6_PCS3,GPIO6_IO06,FLEXCAN3_TX,PIT2_TRIGGER3,LPSPI5_PCS1,,GPIO12_IO06,,,, +GPIO_LPSR_07,LPI2C6_SCL,,SAI4_RX_BCLK,LPUART12_RXD,LPSPI6_PCS2,GPIO6_IO07,FLEXCAN3_RX,PIT2_TRIGGER2,LPSPI5_PCS2,,GPIO12_IO07,,,, +GPIO_LPSR_08,LPUART11_TXD,FLEXCAN3_TX,SAI4_RX_SYNC,MIC_CLK,LPSPI6_PCS1,GPIO6_IO08,LPI2C5_SDA,PIT2_TRIGGER1,LPSPI5_PCS3,,GPIO12_IO08,,,, +GPIO_LPSR_09,LPUART11_RXD,FLEXCAN3_RX,PIT2_TRIGGER0,MIC_BITSTREAM0,LPSPI6_PCS0,GPIO6_IO09,LPI2C5_SCL,SAI4_TX_DATA,,,GPIO12_IO09,,,, +GPIO_LPSR_10,JTAG_MUX_TRSTB,LPUART11_CTS_B,LPI2C6_SDA,MIC_BITSTREAM1,LPSPI6_SCK,GPIO6_IO10,LPI2C5_SCLS,SAI4_TX_SYNC,LPUART12_TXD,,GPIO12_IO10,,,, +GPIO_LPSR_11,JTAG_MUX_TDO,LPUART11_RTS_B,LPI2C6_SCL,MIC_BITSTREAM2,LPSPI6_SOUT,GPIO6_IO11,LPI2C5_SDAS,ARM_TRACE_SWO,LPUART12_RXD,,GPIO12_IO11,,,, +GPIO_LPSR_12,JTAG_MUX_TDI,PIT2_TRIGGER0,,MIC_BITSTREAM3,LPSPI6_SIN,GPIO6_IO12,LPI2C5_HREQ,SAI4_TX_BCLK,LPSPI5_SCK,,GPIO12_IO12,,,, +GPIO_LPSR_13,JTAG_MUX_MOD,MIC_BITSTREAM1,PIT2_TRIGGER1,,,GPIO6_IO13,,SAI4_RX_DATA,LPSPI5_PCS0,,GPIO12_IO13,,,, +GPIO_LPSR_14,JTAG_MUX_TCK,MIC_BITSTREAM2,PIT2_TRIGGER2,,,GPIO6_IO14,,SAI4_RX_BCLK,LPSPI5_SOUT,,GPIO12_IO14,,,, +GPIO_LPSR_15,JTAG_MUX_TMS,MIC_BITSTREAM3,PIT2_TRIGGER3,,,GPIO6_IO15,,SAI4_RX_SYNC,LPSPI5_SIN,,GPIO12_IO15,,,, +WAKEUP_DIG,,,,,,GPIO13_IO00,,NMI_GLUE_NMI,,,,,,, +PMIC_ON_REQ_DIG,SNVS_LP_PMIC_ON_REQ,,,,,GPIO13_IO01,,,,,,,,, +PMIC_STBY_REQ_DIG,CCM_PMIC_VSTBY_REQ,,,,,GPIO13_IO02,,,,,,,,, +GPIO_DISP_B1_00,VIDEO_MUX_LCDIF_CLK,ENET_1G_RX_EN,,TMR1_TIMER0,XBAR1_INOUT26,GPIO4_IO21,,,ENET_QOS_RX_EN,,GPIO10_IO21,,,, +GPIO_DISP_B1_01,VIDEO_MUX_LCDIF_ENABLE,ENET_1G_RX_CLK,ENET_1G_RX_ER,TMR1_TIMER1,XBAR1_INOUT27,GPIO4_IO22,,,ENET_QOS_RX_CLK,ENET_QOS_RX_ER,GPIO10_IO22,,,, +GPIO_DISP_B1_02,VIDEO_MUX_LCDIF_HSYNC,ENET_1G_RX_DATA00,LPI2C3_SCL,TMR1_TIMER2,XBAR1_INOUT28,GPIO4_IO23,,,ENET_QOS_RX_DATA00,LPUART1_TXD,GPIO10_IO23,,,, +GPIO_DISP_B1_03,VIDEO_MUX_LCDIF_VSYNC,ENET_1G_RX_DATA01,LPI2C3_SDA,TMR2_TIMER0,XBAR1_INOUT29,GPIO4_IO24,,,ENET_QOS_RX_DATA01,LPUART1_RXD,GPIO10_IO24,,,, +GPIO_DISP_B1_04,VIDEO_MUX_LCDIF_DATA00,ENET_1G_RX_DATA02,LPUART4_RXD,TMR2_TIMER1,XBAR1_INOUT30,GPIO4_IO25,,,ENET_QOS_RX_DATA02,LPSPI3_SCK,GPIO10_IO25,,,, +GPIO_DISP_B1_05,VIDEO_MUX_LCDIF_DATA01,ENET_1G_RX_DATA03,LPUART4_CTS_B,TMR2_TIMER2,XBAR1_INOUT31,GPIO4_IO26,,,ENET_QOS_RX_DATA03,LPSPI3_SIN,GPIO10_IO26,,,, +GPIO_DISP_B1_06,VIDEO_MUX_LCDIF_DATA02,ENET_1G_TX_DATA03,LPUART4_TXD,TMR3_TIMER0,XBAR1_INOUT32,GPIO4_IO27,SRC_BT_CFG00,,ENET_QOS_TX_DATA03,LPSPI3_SOUT,GPIO10_IO27,,,, +GPIO_DISP_B1_07,VIDEO_MUX_LCDIF_DATA03,ENET_1G_TX_DATA02,LPUART4_RTS_B,TMR3_TIMER1,XBAR1_INOUT33,GPIO4_IO28,SRC_BT_CFG01,,ENET_QOS_TX_DATA02,LPSPI3_PCS0,GPIO10_IO28,,,, +GPIO_DISP_B1_08,VIDEO_MUX_LCDIF_DATA04,ENET_1G_TX_DATA01,USDHC1_CD_B,TMR3_TIMER2,XBAR1_INOUT34,GPIO4_IO29,SRC_BT_CFG02,,ENET_QOS_TX_DATA01,LPSPI3_PCS1,GPIO10_IO29,,,, +GPIO_DISP_B1_09,VIDEO_MUX_LCDIF_DATA05,ENET_1G_TX_DATA00,USDHC1_WP,TMR4_TIMER0,XBAR1_INOUT35,GPIO4_IO30,SRC_BT_CFG03,,ENET_QOS_TX_DATA00,LPSPI3_PCS2,GPIO10_IO30,,,, +GPIO_DISP_B1_10,VIDEO_MUX_LCDIF_DATA06,ENET_1G_TX_EN,USDHC1_RESET_B,TMR4_TIMER1,XBAR1_INOUT36,GPIO4_IO31,SRC_BT_CFG04,,ENET_QOS_TX_EN,LPSPI3_PCS3,GPIO10_IO31,,,, +GPIO_DISP_B1_11,VIDEO_MUX_LCDIF_DATA07,ENET_1G_TX_CLK_IO,ENET_1G_REF_CLK,TMR4_TIMER2,XBAR1_INOUT37,GPIO5_IO00,SRC_BT_CFG05,,ENET_QOS_TX_CLK,ENET_QOS_REF_CLK,GPIO11_IO00,,,, +GPIO_DISP_B2_00,VIDEO_MUX_LCDIF_DATA08,WDOG1_B,MQS_RIGHT,ENET_1G_TX_ER,SAI1_TX_DATA03,GPIO5_IO01,SRC_BT_CFG06,,ENET_QOS_TX_ER,,GPIO11_IO01,,,, +GPIO_DISP_B2_01,VIDEO_MUX_LCDIF_DATA09,USDHC1_VSELECT,MQS_LEFT,WDOG2_B,SAI1_TX_DATA02,GPIO5_IO02,SRC_BT_CFG07,,EWM_OUT_B,CCM_ENET_REF_CLK_25M,GPIO11_IO02,,,, +GPIO_DISP_B2_02,VIDEO_MUX_LCDIF_DATA10,ENET_TX_DATA00,PIT1_TRIGGER3,ARM_TRACE00,SAI1_TX_DATA01,GPIO5_IO03,SRC_BT_CFG08,,ENET_QOS_TX_DATA00,,GPIO11_IO03,,,, +GPIO_DISP_B2_03,VIDEO_MUX_LCDIF_DATA11,ENET_TX_DATA01,PIT1_TRIGGER2,ARM_TRACE01,SAI1_MCLK,GPIO5_IO04,SRC_BT_CFG09,,ENET_QOS_TX_DATA01,,GPIO11_IO04,,,, +GPIO_DISP_B2_04,VIDEO_MUX_LCDIF_DATA12,ENET_TX_EN,PIT1_TRIGGER1,ARM_TRACE02,SAI1_RX_SYNC,GPIO5_IO05,SRC_BT_CFG10,,ENET_QOS_TX_EN,,GPIO11_IO05,,,, +GPIO_DISP_B2_05,VIDEO_MUX_LCDIF_DATA13,ENET_TX_CLK,ENET_REF_CLK,ARM_TRACE03,SAI1_RX_BCLK,GPIO5_IO06,SRC_BT_CFG11,,ENET_QOS_TX_CLK,,GPIO11_IO06,,,, +GPIO_DISP_B2_06,VIDEO_MUX_LCDIF_DATA14,ENET_RX_DATA00,LPUART7_TXD,ARM_TRACE_CLK,SAI1_RX_DATA00,GPIO5_IO07,,,ENET_QOS_RX_DATA00,,GPIO11_IO07,,,, +GPIO_DISP_B2_07,VIDEO_MUX_LCDIF_DATA15,ENET_RX_DATA01,LPUART7_RXD,ARM_TRACE_SWO,SAI1_TX_DATA00,GPIO5_IO08,,,ENET_QOS_RX_DATA01,,GPIO11_IO08,,,, +GPIO_DISP_B2_08,VIDEO_MUX_LCDIF_DATA16,ENET_RX_EN,LPUART8_TXD,ARM_CM7_EVENTO,SAI1_TX_BCLK,GPIO5_IO09,,,ENET_QOS_RX_EN,LPUART1_TXD,GPIO11_IO09,,,, +GPIO_DISP_B2_09,VIDEO_MUX_LCDIF_DATA17,ENET_RX_ER,LPUART8_RXD,ARM_CM7_EVENTI,SAI1_TX_SYNC,GPIO5_IO10,,,ENET_QOS_RX_ER,LPUART1_RXD,GPIO11_IO10,,,, +GPIO_DISP_B2_10,VIDEO_MUX_LCDIF_DATA18,EMVSIM2_IO,LPUART2_TXD,WDOG2_RESET_B_DEB,XBAR1_INOUT38,GPIO5_IO11,LPI2C3_SCL,,ENET_QOS_RX_ER,SPDIF_IN,GPIO11_IO11,,,, +GPIO_DISP_B2_11,VIDEO_MUX_LCDIF_DATA19,EMVSIM2_CLK,LPUART2_RXD,WDOG1_RESET_B_DEB,XBAR1_INOUT39,GPIO5_IO12,LPI2C3_SDA,,ENET_QOS_CRS,SPDIF_OUT,GPIO11_IO12,,,, +GPIO_DISP_B2_12,VIDEO_MUX_LCDIF_DATA20,EMVSIM2_RST,FLEXCAN1_TX,LPUART2_CTS_B,XBAR1_INOUT40,GPIO5_IO13,LPI2C4_SCL,,ENET_QOS_COL,LPSPI4_SCK,GPIO11_IO13,,,, +GPIO_DISP_B2_13,VIDEO_MUX_LCDIF_DATA21,EMVSIM2_SVEN,FLEXCAN1_RX,LPUART2_RTS_B,ENET_REF_CLK,GPIO5_IO14,LPI2C4_SDA,,ENET_QOS_1588_EVENT0_OUT,LPSPI4_SIN,GPIO11_IO14,,,, +GPIO_DISP_B2_14,VIDEO_MUX_LCDIF_DATA22,EMVSIM2_PD,WDOG2_B,VIDEO_MUX_EXT_DCIC1,ENET_1G_REF_CLK,GPIO5_IO15,FLEXCAN1_TX,,ENET_QOS_1588_EVENT0_IN,LPSPI4_SOUT,GPIO11_IO15,,,, +GPIO_DISP_B2_15,VIDEO_MUX_LCDIF_DATA23,EMVSIM2_POWER_FAIL,WDOG1_B,VIDEO_MUX_EXT_DCIC2,PIT1_TRIGGER0,GPIO5_IO16,FLEXCAN1_RX,,ENET_QOS_1588_EVENT0_AUX_IN,LPSPI4_PCS0,GPIO11_IO16,,,, +GPIO_AD_00,EMVSIM1_IO,FLEXCAN2_TX,ENET_1G_1588_EVENT1_IN,GPT2_CAPTURE1,FLEXPWM1_PWM0_A,GPIO2_IO31,LPUART7_TXD,,FLEXIO2_D00,FLEXSPI2_B_SS1_B,GPIO8_IO31,,,ACMP1_IN1, +GPIO_AD_01,EMVSIM1_CLK,FLEXCAN2_RX,ENET_1G_1588_EVENT1_OUT,GPT2_CAPTURE2,FLEXPWM1_PWM0_B,GPIO3_IO00,LPUART7_RXD,,FLEXIO2_D01,FLEXSPI2_A_SS1_B,GPIO9_IO00,,,ACMP1_IN2, +GPIO_AD_02,EMVSIM1_RST,LPUART7_CTS_B,ENET_1G_1588_EVENT2_IN,GPT2_COMPARE1,FLEXPWM1_PWM1_A,GPIO3_IO01,LPUART8_TXD,,FLEXIO2_D02,VIDEO_MUX_EXT_DCIC1,GPIO9_IO01,,,ACMP1_IN3, +GPIO_AD_03,EMVSIM1_SVEN,LPUART7_RTS_B,ENET_1G_1588_EVENT2_OUT,GPT2_COMPARE2,FLEXPWM1_PWM1_B,GPIO3_IO02,LPUART8_RXD,,FLEXIO2_D03,VIDEO_MUX_EXT_DCIC2,GPIO9_IO02,,,ACMP1_IN4, +GPIO_AD_04,EMVSIM1_PD,LPUART8_CTS_B,ENET_1G_1588_EVENT3_IN,GPT2_COMPARE3,FLEXPWM1_PWM2_A,GPIO3_IO03,WDOG1_B,,FLEXIO2_D04,TMR4_TIMER0,GPIO9_IO03,,,ACMP2_IN1, +GPIO_AD_05,EMVSIM1_POWER_FAIL,LPUART8_RTS_B,ENET_1G_1588_EVENT3_OUT,GPT2_CLK,FLEXPWM1_PWM2_B,GPIO3_IO04,WDOG2_B,,FLEXIO2_D05,TMR4_TIMER1,GPIO9_IO04,,,ACMP2_IN2, +GPIO_AD_06,USB_OTG2_OC,FLEXCAN1_TX,EMVSIM2_IO,GPT3_CAPTURE1,VIDEO_MUX_CSI_DATA15,GPIO3_IO05,ENET_1588_EVENT1_IN,,FLEXIO2_D06,TMR4_TIMER2,GPIO9_IO05,FLEXPWM1_PWM0_X,ADC1_CH0A,, +GPIO_AD_07,USB_OTG2_PWR,FLEXCAN1_RX,EMVSIM2_CLK,GPT3_CAPTURE2,VIDEO_MUX_CSI_DATA14,GPIO3_IO06,ENET_1588_EVENT1_OUT,,FLEXIO2_D07,TMR4_TIMER3,GPIO9_IO06,FLEXPWM1_PWM1_X,ADC1_CH0B,, +GPIO_AD_08,USBPHY2_OTG_ID,LPI2C1_SCL,EMVSIM2_RST,GPT3_COMPARE1,VIDEO_MUX_CSI_DATA13,GPIO3_IO07,ENET_1588_EVENT2_IN,,FLEXIO2_D08,,GPIO9_IO07,FLEXPWM1_PWM2_X,ADC1_CH1A,, +GPIO_AD_09,USBPHY1_OTG_ID,LPI2C1_SDA,EMVSIM2_SVEN,GPT3_COMPARE2,VIDEO_MUX_CSI_DATA12,GPIO3_IO08,ENET_1588_EVENT2_OUT,,FLEXIO2_D09,,GPIO9_IO08,FLEXPWM1_PWM3_X,ADC1_CH1B,, +GPIO_AD_10,USB_OTG1_PWR,LPI2C1_SCLS,EMVSIM2_PD,GPT3_COMPARE3,VIDEO_MUX_CSI_DATA11,GPIO3_IO09,ENET_1588_EVENT3_IN,,FLEXIO2_D10,,GPIO9_IO09,FLEXPWM2_PWM0_X,ADC1_CH2A,, +GPIO_AD_11,USB_OTG1_OC,LPI2C1_SDAS,EMVSIM2_POWER_FAIL,GPT3_CLK,VIDEO_MUX_CSI_DATA10,GPIO3_IO10,ENET_1588_EVENT3_OUT,,FLEXIO2_D11,,GPIO9_IO10,FLEXPWM2_PWM1_X,ADC1_CH2B,, +GPIO_AD_12,SPDIF_LOCK,LPI2C1_HREQ,GPT1_CAPTURE1,FLEXSPI1_B_DATA03,VIDEO_MUX_CSI_PIXCLK,GPIO3_IO11,ENET_TX_DATA03,,FLEXIO2_D12,EWM_OUT_B,GPIO9_IO11,FLEXPWM2_PWM2_X,"ADC1_CH3A,ADC2_CH3A",, +GPIO_AD_13,SPDIF_SR_CLK,PIT1_TRIGGER0,GPT1_CAPTURE2,FLEXSPI1_B_DATA02,VIDEO_MUX_CSI_MCLK,GPIO3_IO12,ENET_TX_DATA02,,FLEXIO2_D13,REF_CLK_32K,GPIO9_IO12,FLEXPWM2_PWM3_X,"ADC1_CH3B,ADC2_CH3B",, +GPIO_AD_14,SPDIF_EXT_CLK,REF_CLK_24M,GPT1_COMPARE1,FLEXSPI1_B_DATA01,VIDEO_MUX_CSI_VSYNC,GPIO3_IO13,ENET_RX_CLK,,FLEXIO2_D14,CCM_ENET_REF_CLK_25M,GPIO9_IO13,FLEXPWM3_PWM0_X,"ADC1_CH4A,ADC2_CH4A",, +GPIO_AD_15,SPDIF_IN,LPUART10_TXD,GPT1_COMPARE2,FLEXSPI1_B_DATA00,VIDEO_MUX_CSI_HSYNC,GPIO3_IO14,ENET_TX_ER,,FLEXIO2_D15,,GPIO9_IO14,FLEXPWM3_PWM1_X,"ADC1_CH4B,ADC2_CH4B",, +GPIO_AD_16,SPDIF_OUT,LPUART10_RXD,GPT1_COMPARE3,FLEXSPI1_B_SCLK,VIDEO_MUX_CSI_DATA09,GPIO3_IO15,ENET_RX_DATA03,,FLEXIO2_D16,ENET_1G_MDC,GPIO9_IO15,FLEXPWM3_PWM2_X,"ADC1_CH5A,ADC2_CH5A",, +GPIO_AD_17,SAI1_MCLK,ACMP1_OUT,GPT1_CLK,FLEXSPI1_A_DQS,VIDEO_MUX_CSI_DATA08,GPIO3_IO16,ENET_RX_DATA02,,FLEXIO2_D17,ENET_1G_MDIO,GPIO9_IO16,FLEXPWM3_PWM3_X,"ADC1_CH5B,ADC2_CH5B",ACMP1_OUT, +GPIO_AD_18,SAI1_RX_SYNC,ACMP2_OUT,LPSPI1_PCS1,FLEXSPI1_A_SS0_B,VIDEO_MUX_CSI_DATA07,GPIO3_IO17,ENET_CRS,,FLEXIO2_D18,LPI2C2_SCL,GPIO9_IO17,FLEXPWM4_PWM0_X,ADC2_CH0A,ACMP2_OUT, +GPIO_AD_19,SAI1_RX_BCLK,ACMP3_OUT,LPSPI1_PCS2,FLEXSPI1_A_SCLK,VIDEO_MUX_CSI_DATA06,GPIO3_IO18,ENET_COL,,FLEXIO2_D19,LPI2C2_SDA,GPIO9_IO18,FLEXPWM4_PWM1_X,ADC2_CH0B,ACMP3_OUT, +GPIO_AD_20,SAI1_RX_DATA00,ACMP4_OUT,LPSPI1_PCS3,FLEXSPI1_A_DATA00,VIDEO_MUX_CSI_DATA05,GPIO3_IO19,KPP_ROW07,,FLEXIO2_D20,ENET_QOS_1588_EVENT2_OUT,GPIO9_IO19,FLEXPWM4_PWM2_X,ADC2_CH1A,ACMP4_OUT, +GPIO_AD_21,SAI1_TX_DATA00,,LPSPI2_PCS1,FLEXSPI1_A_DATA01,VIDEO_MUX_CSI_DATA04,GPIO3_IO20,KPP_COL07,,FLEXIO2_D21,ENET_QOS_1588_EVENT2_IN,GPIO9_IO20,FLEXPWM4_PWM3_X,ADC2_CH1B,, +GPIO_AD_22,SAI1_TX_BCLK,,LPSPI2_PCS2,FLEXSPI1_A_DATA02,VIDEO_MUX_CSI_DATA03,GPIO3_IO21,KPP_ROW06,,FLEXIO2_D22,ENET_QOS_1588_EVENT3_OUT,GPIO9_IO21,,ADC2_CH2A,, +GPIO_AD_23,SAI1_TX_SYNC,,LPSPI2_PCS3,FLEXSPI1_A_DATA03,VIDEO_MUX_CSI_DATA02,GPIO3_IO22,KPP_COL06,,FLEXIO2_D23,ENET_QOS_1588_EVENT3_IN,GPIO9_IO22,,ADC2_CH2B,, +GPIO_AD_24,LPUART1_TXD,LPSPI2_SCK,VIDEO_MUX_CSI_DATA00,ENET_RX_EN,FLEXPWM2_PWM0_A,GPIO3_IO23,KPP_ROW05,,FLEXIO2_D24,LPI2C4_SCL,GPIO9_IO23,,ADC2_CH6A,, +GPIO_AD_25,LPUART1_RXD,LPSPI2_PCS0,VIDEO_MUX_CSI_DATA01,ENET_RX_ER,FLEXPWM2_PWM0_B,GPIO3_IO24,KPP_COL05,,FLEXIO2_D25,LPI2C4_SDA,GPIO9_IO24,,ADC2_CH6B,, +GPIO_AD_26,LPUART1_CTS_B,LPSPI2_SOUT,SEMC_CSX01,ENET_RX_DATA00,FLEXPWM2_PWM1_A,GPIO3_IO25,KPP_ROW04,,FLEXIO2_D26,ENET_QOS_MDC,GPIO9_IO25,USDHC2_CD_B,,ACMP2_IN3, +GPIO_AD_27,LPUART1_RTS_B,LPSPI2_SIN,SEMC_CSX02,ENET_RX_DATA01,FLEXPWM2_PWM1_B,GPIO3_IO26,KPP_COL04,,FLEXIO2_D27,ENET_QOS_MDIO,GPIO9_IO26,USDHC2_WP,,ACMP2_IN4, +GPIO_AD_28,LPSPI1_SCK,LPUART5_TXD,SEMC_CSX03,ENET_TX_EN,FLEXPWM2_PWM2_A,GPIO3_IO27,KPP_ROW03,,FLEXIO2_D28,VIDEO_MUX_EXT_DCIC1,GPIO9_IO27,USDHC2_VSELECT,,ACMP3_IN1, +GPIO_AD_29,LPSPI1_PCS0,LPUART5_RXD,ENET_REF_CLK,ENET_TX_CLK,FLEXPWM2_PWM2_B,GPIO3_IO28,KPP_COL03,,FLEXIO2_D29,VIDEO_MUX_EXT_DCIC2,GPIO9_IO28,USDHC2_RESET_B,,ACMP3_IN2, +GPIO_AD_30,LPSPI1_SOUT,USB_OTG2_OC,FLEXCAN2_TX,ENET_TX_DATA00,LPUART3_TXD,GPIO3_IO29,KPP_ROW02,,FLEXIO2_D30,WDOG2_RESET_B_DEB,GPIO9_IO29,,,ACMP3_IN3, +GPIO_AD_31,LPSPI1_SIN,USB_OTG2_PWR,FLEXCAN2_RX,ENET_TX_DATA01,LPUART3_RXD,GPIO3_IO30,KPP_COL02,,FLEXIO2_D31,WDOG1_RESET_B_DEB,GPIO9_IO30,,,ACMP3_IN4, +GPIO_AD_32,LPI2C1_SCL,USBPHY2_OTG_ID,PGMC_PMIC_RDY,ENET_MDC,USDHC1_CD_B,GPIO3_IO31,KPP_ROW01,,LPUART10_TXD,ENET_1G_MDC,GPIO9_IO31,,,ACMP4_IN1, +GPIO_AD_33,LPI2C1_SDA,USBPHY1_OTG_ID,XBAR1_INOUT17,ENET_MDIO,USDHC1_WP,GPIO4_IO00,KPP_COL01,,LPUART10_RXD,ENET_1G_MDIO,GPIO10_IO00,,,ACMP4_IN2, +GPIO_AD_34,ENET_1G_1588_EVENT0_IN,USB_OTG1_PWR,XBAR1_INOUT18,ENET_1588_EVENT0_IN,USDHC1_VSELECT,GPIO4_IO01,KPP_ROW00,,LPUART10_CTS_B,WDOG1_ANY,GPIO10_IO01,,,ACMP4_IN3, +GPIO_AD_35,ENET_1G_1588_EVENT0_OUT,USB_OTG1_OC,XBAR1_INOUT19,ENET_1588_EVENT0_OUT,USDHC1_RESET_B,GPIO4_IO02,KPP_COL00,,LPUART10_RTS_B,FLEXSPI1_B_SS1_B,GPIO10_IO02,,,ACMP4_IN4, diff --git a/ports/mimxrt/boards/PHYBOARD_RT1170/board.json b/ports/mimxrt/boards/PHYBOARD_RT1170/board.json new file mode 100644 index 0000000000000..6eaafe1f48882 --- /dev/null +++ b/ports/mimxrt/boards/PHYBOARD_RT1170/board.json @@ -0,0 +1,28 @@ +{ + "deploy": [ + "../deploy_mimxrt.md" + ], + "docs": "", + "features": [ + "Audio Codec", + "CAN", + "Camera", + "Display", + "Dual-core", + "Ethernet", + "External Flash", + "External RAM", + "IMU", + "RGB LED", + "USB", + "microSD" + ], + "images": [ + "phyBOARD-RT1170_front.png" + ], + "mcu": "mimxrt", + "product": "phyBOARD-RT1170 Development Kit", + "thumbnail": "", + "url": "https://www.phytec.com/product/phyboard-rt1170-development-kit/", + "vendor": "PHYTEC" +} diff --git a/ports/mimxrt/boards/PHYBOARD_RT1170/manifest.py b/ports/mimxrt/boards/PHYBOARD_RT1170/manifest.py new file mode 100644 index 0000000000000..59866772206a3 --- /dev/null +++ b/ports/mimxrt/boards/PHYBOARD_RT1170/manifest.py @@ -0,0 +1,3 @@ +include("../manifest.py") +require("bundle-networking") +include("$(MPY_DIR)/extmod/asyncio/manifest.py") diff --git a/ports/mimxrt/boards/PHYBOARD_RT1170/mpconfigboard.h b/ports/mimxrt/boards/PHYBOARD_RT1170/mpconfigboard.h new file mode 100644 index 0000000000000..3cb49ab2cc1b5 --- /dev/null +++ b/ports/mimxrt/boards/PHYBOARD_RT1170/mpconfigboard.h @@ -0,0 +1,308 @@ +#define MICROPY_HW_BOARD_NAME "phyBOARD-RT1170 Development Kit" +#define MICROPY_HW_MCU_NAME "MIMXRT1176DVMAA" + +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-phyboard" + +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(bool); \ + mp_handle_pending(true); \ + } while (0); + +// phyBOARD-RT1170 SoM onboard LEDs (red and green from phyCORE SoM) +// Carrier board provides additional RGB LEDs via GPIO +#define MICROPY_HW_LED1_PIN (pin_GPIO_LPSR_07) // SoM Red LED +#define MICROPY_HW_LED2_PIN (pin_GPIO_LPSR_08) // SoM Green LED +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) // LEDs are active low +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) + +// phyBOARD carrier board RGB LEDs +#define MICROPY_HW_LED3_PIN (pin_GPIO_AD_14) // Carrier Red LED +#define MICROPY_HW_LED4_PIN (pin_GPIO_LPSR_13) // Carrier Green LED + +#define MICROPY_HW_NUM_PIN_IRQS (6 * 32) + +// Define mapping hardware UART # to logical UART # +// phyBOARD-RT1170 UART interfaces +// LPUART1 -> 0 (GPIO_AD_24/25) - Primary debug/console (SoM) +// LPUART2 -> 1 (GPIO_DISP_B2_10/11/12/13) - Carrier board +// LPUART3 -> 2 (GPIO_AD_30/31) - General purpose (SoM) +// LPUART5 -> 3 (GPIO_AD_28/29) - Expansion (SoM) +// LPUART6 -> 4 (GPIO_EMC_B1_40/41) - Console UART (FT2232H - Carrier) +// LPUART7 -> 5 (GPIO_DISP_B2_06/07) - General purpose (SoM) +// LPUART8 -> 6 (GPIO_AD_02/03/04/05) - RS-232 (Carrier) + +#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) +#define MICROPY_HW_UART_INDEX { 1, 2, 3, 5, 6, 7, 8 } + +#define IOMUX_TABLE_UART \ + { IOMUXC_GPIO_AD_24_LPUART1_TXD }, { IOMUXC_GPIO_AD_25_LPUART1_RXD }, \ + { IOMUXC_GPIO_DISP_B2_10_LPUART2_TXD }, { IOMUXC_GPIO_DISP_B2_11_LPUART2_RXD }, \ + { IOMUXC_GPIO_AD_30_LPUART3_TXD }, { IOMUXC_GPIO_AD_31_LPUART3_RXD }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_28_LPUART5_TXD }, { IOMUXC_GPIO_AD_29_LPUART5_RXD }, \ + { IOMUXC_GPIO_EMC_B1_40_LPUART6_TXD }, { IOMUXC_GPIO_EMC_B1_41_LPUART6_RXD }, \ + { IOMUXC_GPIO_DISP_B2_06_LPUART7_TXD }, { IOMUXC_GPIO_DISP_B2_07_LPUART7_RXD }, \ + { IOMUXC_GPIO_AD_02_LPUART8_TXD }, { IOMUXC_GPIO_AD_03_LPUART8_RXD }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, + +#define IOMUX_TABLE_UART_CTS_RTS \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_DISP_B2_12_LPUART2_CTS_B }, { IOMUXC_GPIO_DISP_B2_13_LPUART2_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_04_LPUART8_CTS_B }, { IOMUXC_GPIO_AD_05_LPUART8_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, + +// Define the mapping hardware SPI # to logical SPI # +// phyCORE SoM basic SPI interfaces available on connector +// LPSPI1 -> 0 (GPIO_AD_28/29/30/31) +// LPSPI2 -> 1 (GPIO_AD_24/25/26/27) + +#define MICROPY_HW_SPI_INDEX { 1, 2 } + +#define IOMUX_TABLE_SPI \ + { IOMUXC_GPIO_AD_28_LPSPI1_SCK }, { IOMUXC_GPIO_AD_29_LPSPI1_PCS0 }, \ + { IOMUXC_GPIO_AD_30_LPSPI1_SOUT }, { IOMUXC_GPIO_AD_31_LPSPI1_SIN }, \ + { IOMUXC_GPIO_AD_24_LPSPI2_SCK }, { IOMUXC_GPIO_AD_25_LPSPI2_PCS0 }, \ + { IOMUXC_GPIO_AD_26_LPSPI2_SOUT }, { IOMUXC_GPIO_AD_27_LPSPI2_SIN }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, + + +#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ + kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } + +#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ + kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + +// Define the mapping hardware I2C # to logical I2C # +// phyBOARD-RT1170 I2C interfaces +// LPI2C1 -> 0 (GPIO_AD_32/33) - EEPROM (SoM) +// LPI2C2 -> 1 (GPIO_AD_18/19) - EEPROM + Accelerometer (Carrier) +// LPI2C3 -> 2 (GPIO_DISP_B2_10/11) - Reserved (SoM) +// LPI2C5 -> 3 (GPIO_LPSR_08/09, GPIO_AD_26/27) - Audio Codec + Accelerometer (Carrier) + +#define MICROPY_HW_I2C_INDEX { 1, 2, 3, 5 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_AD_32_LPI2C1_SCL }, { IOMUXC_GPIO_AD_33_LPI2C1_SDA }, \ + { IOMUXC_GPIO_AD_18_LPI2C2_SCL }, { IOMUXC_GPIO_AD_19_LPI2C2_SDA }, \ + { IOMUXC_GPIO_DISP_B2_10_LPI2C3_SCL }, { IOMUXC_GPIO_DISP_B2_11_LPI2C3_SDA }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_LPSR_08_LPI2C5_SDA }, { IOMUXC_GPIO_LPSR_09_LPI2C5_SCL }, \ + { 0 }, { 0 }, + +#define MICROPY_PY_MACHINE_I2S (1) +#define MICROPY_HW_I2S_NUM (1) +#define I2S_CLOCK_MUX { 0, kCLOCK_Root_Sai1, kCLOCK_Root_Sai2, kCLOCK_Root_Sai3, kCLOCK_Root_Sai4 } +#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx, kDmaRequestMuxSai3Rx, kDmaRequestMuxSai4Rx } +#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx, kDmaRequestMuxSai3Tx, kDmaRequestMuxSai4Tx } +#define I2S_WM8960_RX_MODE (1) +#define I2S_AUDIO_PLL_CLOCK (4U) +#define DMAMUX DMAMUX0 + +#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \ + { \ + .hw_id = _hwid, \ + .fn = _fn, \ + .mode = _mode, \ + .name = MP_QSTR_##_pin, \ + .iomux = {_iomux}, \ + } + +#define I2S_GPIO_MAP \ + { \ + I2S_GPIO(1, MCK, TX, GPIO_AD_17, IOMUXC_GPIO_AD_17_SAI1_MCLK), \ + I2S_GPIO(1, SCK, RX, GPIO_AD_19, IOMUXC_GPIO_AD_19_SAI1_RX_BCLK), \ + I2S_GPIO(1, WS, RX, GPIO_AD_18, IOMUXC_GPIO_AD_18_SAI1_RX_SYNC), \ + I2S_GPIO(1, SD, RX, GPIO_AD_20, IOMUXC_GPIO_AD_20_SAI1_RX_DATA00), \ + I2S_GPIO(1, SCK, TX, GPIO_AD_22, IOMUXC_GPIO_AD_22_SAI1_TX_BCLK), \ + I2S_GPIO(1, WS, TX, GPIO_AD_23, IOMUXC_GPIO_AD_23_SAI1_TX_SYNC), \ + I2S_GPIO(1, SD, TX, GPIO_AD_21, IOMUXC_GPIO_AD_21_SAI1_TX_DATA00), \ + } + +// USDHC1 (SDCARD) +#define MICROPY_PY_MACHINE_SDCARD 0 +#if MICROPY_PY_MACHINE_SDCARD +#define USDHC_DUMMY_PIN NULL, 0 +#define MICROPY_USDHC1 \ + { \ + .cmd = {GPIO_SD_B1_00_USDHC1_CMD}, \ + .clk = { GPIO_SD_B1_01_USDHC1_CLK }, \ + .cd_b = { USDHC_DUMMY_PIN }, \ + .data0 = { GPIO_SD_B1_02_USDHC1_DATA0 }, \ + .data1 = { GPIO_SD_B1_03_USDHC1_DATA1 }, \ + .data2 = { GPIO_SD_B1_04_USDHC1_DATA2 }, \ + .data3 = { GPIO_SD_B1_05_USDHC1_DATA3 }, \ + } +#define USDHC_DATA3_PULL_DOWN_ON_BOARD (1) +#endif + +// Network definitions + +// phyBOARD-RT1170 Dual Ethernet configuration +// Port 0: KSZ8081 100Mbps RMII PHY on carrier board (PBA-C-26) +// Port 1: DP83867 1Gbps RGMII PHY on phyCORE SoM + +// Primary Ethernet (100M RMII) - KSZ8081 on carrier board +#define ENET_PHY_ADDRESS (1) // KSZ8081 PHY address 001b +#define ENET_PHY KSZ8081 +#define ENET_PHY_OPS phyksz8081_ops + +// ENET RMII pin configuration - connected to carrier board KSZ8081 +#define IOMUX_TABLE_ENET \ + { IOMUXC_GPIO_DISP_B2_06_ENET_RX_DATA00, 0, 0x06u }, \ + { IOMUXC_GPIO_DISP_B2_07_ENET_RX_DATA01, 0, 0x06u }, \ + { IOMUXC_GPIO_DISP_B2_08_ENET_RX_EN, 0, 0x06u }, \ + { IOMUXC_GPIO_DISP_B2_02_ENET_TX_DATA00, 0, 0x02u }, \ + { IOMUXC_GPIO_DISP_B2_03_ENET_TX_DATA01, 0, 0x02u }, \ + { IOMUXC_GPIO_DISP_B2_04_ENET_TX_EN, 0, 0x06u }, \ + { IOMUXC_GPIO_DISP_B2_05_ENET_REF_CLK, 1, 0x03u }, \ + { IOMUXC_GPIO_DISP_B2_09_ENET_RX_ER, 0, 0x06u }, \ + { IOMUXC_GPIO_AD_33_ENET_MDIO, 0, 0x06u }, \ + { IOMUXC_GPIO_AD_32_ENET_MDC, 0, 0x06u }, + +// Secondary Ethernet (1G RGMII) - DP83867 on phyCORE SoM +#define ENET_1_PHY_ADDRESS (0) +#define ENET_1_PHY DP83867 +#define ENET_1_PHY_OPS phydp83867_ops + +// ENET_1G RGMII pin configuration - full RGMII pins for Gigabit operation +#define IOMUX_TABLE_ENET_1 \ + { IOMUXC_GPIO_DISP_B1_00_ENET_1G_RX_EN, 0, 0x08U }, \ + { IOMUXC_GPIO_DISP_B1_01_ENET_1G_RX_CLK, 0, 0x08U }, \ + { IOMUXC_GPIO_DISP_B1_02_ENET_1G_RX_DATA00, 0, 0x08U }, \ + { IOMUXC_GPIO_DISP_B1_03_ENET_1G_RX_DATA01, 0, 0x08U }, \ + { IOMUXC_GPIO_DISP_B1_04_ENET_1G_RX_DATA02, 0, 0x08U }, \ + { IOMUXC_GPIO_DISP_B1_05_ENET_1G_RX_DATA03, 0, 0x08U }, \ + { IOMUXC_GPIO_DISP_B1_06_ENET_1G_TX_DATA03, 0, 0x0CU }, \ + { IOMUXC_GPIO_DISP_B1_07_ENET_1G_TX_DATA02, 0, 0x0CU }, \ + { IOMUXC_GPIO_DISP_B1_08_ENET_1G_TX_DATA01, 0, 0x0CU }, \ + { IOMUXC_GPIO_DISP_B1_09_ENET_1G_TX_DATA00, 0, 0x0CU }, \ + { IOMUXC_GPIO_DISP_B1_10_ENET_1G_TX_EN, 0, 0x0CU }, \ + { IOMUXC_GPIO_DISP_B1_11_ENET_1G_TX_CLK_IO, 0, 0x0CU }, \ + { IOMUXC_GPIO_EMC_B2_20_ENET_1G_MDIO, 0, 0x06u }, \ + { IOMUXC_GPIO_EMC_B2_19_ENET_1G_MDC, 0, 0x06u }, + + +// --- SEMC --- // +#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_B1_00_SEMC_DATA00 +#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_B1_01_SEMC_DATA01 +#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_B1_02_SEMC_DATA02 +#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_B1_03_SEMC_DATA03 +#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_B1_04_SEMC_DATA04 +#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_B1_05_SEMC_DATA05 +#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_B1_06_SEMC_DATA06 +#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_B1_07_SEMC_DATA07 +#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_B1_30_SEMC_DATA08 +#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_B1_31_SEMC_DATA09 +#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_B1_32_SEMC_DATA10 +#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_B1_33_SEMC_DATA11 +#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_B1_34_SEMC_DATA12 +#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_B1_35_SEMC_DATA13 +#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_B1_36_SEMC_DATA14 +#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_B1_37_SEMC_DATA15 + +#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_B1_09_SEMC_ADDR00 +#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_B1_10_SEMC_ADDR01 +#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_B1_11_SEMC_ADDR02 +#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_B1_12_SEMC_ADDR03 +#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_B1_13_SEMC_ADDR04 +#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_B1_14_SEMC_ADDR05 +#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_B1_15_SEMC_ADDR06 +#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_B1_16_SEMC_ADDR07 +#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_B1_17_SEMC_ADDR08 +#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_B1_18_SEMC_ADDR09 +#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_B1_23_SEMC_ADDR10 +#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_B1_19_SEMC_ADDR11 +#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_B1_20_SEMC_ADDR12 + +#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_B1_21_SEMC_BA0 +#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_B1_22_SEMC_BA1 +#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_B1_24_SEMC_CAS +#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_B1_25_SEMC_RAS +#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_B1_26_SEMC_CLK +#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_B1_27_SEMC_CKE +#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_B1_28_SEMC_WE +#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_B1_08_SEMC_DM00 +#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_B1_38_SEMC_DM01 +#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_B1_39_SEMC_DQS + +#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_B1_29_SEMC_CS0 + +#define MIMXRT_IOMUXC_SEMC_DATA16 IOMUXC_GPIO_EMC_B2_00_SEMC_DATA16 +#define MIMXRT_IOMUXC_SEMC_DATA17 IOMUXC_GPIO_EMC_B2_01_SEMC_DATA17 +#define MIMXRT_IOMUXC_SEMC_DATA18 IOMUXC_GPIO_EMC_B2_02_SEMC_DATA18 +#define MIMXRT_IOMUXC_SEMC_DATA19 IOMUXC_GPIO_EMC_B2_03_SEMC_DATA19 +#define MIMXRT_IOMUXC_SEMC_DATA20 IOMUXC_GPIO_EMC_B2_04_SEMC_DATA20 +#define MIMXRT_IOMUXC_SEMC_DATA21 IOMUXC_GPIO_EMC_B2_05_SEMC_DATA21 +#define MIMXRT_IOMUXC_SEMC_DATA22 IOMUXC_GPIO_EMC_B2_06_SEMC_DATA22 +#define MIMXRT_IOMUXC_SEMC_DATA23 IOMUXC_GPIO_EMC_B2_07_SEMC_DATA23 +#define MIMXRT_IOMUXC_SEMC_DM02 IOMUXC_GPIO_EMC_B2_08_SEMC_DM02 + +#define MIMXRT_IOMUXC_SEMC_DATA24 IOMUXC_GPIO_EMC_B2_09_SEMC_DATA24 +#define MIMXRT_IOMUXC_SEMC_DATA25 IOMUXC_GPIO_EMC_B2_10_SEMC_DATA25 +#define MIMXRT_IOMUXC_SEMC_DATA26 IOMUXC_GPIO_EMC_B2_11_SEMC_DATA26 +#define MIMXRT_IOMUXC_SEMC_DATA27 IOMUXC_GPIO_EMC_B2_12_SEMC_DATA27 +#define MIMXRT_IOMUXC_SEMC_DATA28 IOMUXC_GPIO_EMC_B2_13_SEMC_DATA28 +#define MIMXRT_IOMUXC_SEMC_DATA29 IOMUXC_GPIO_EMC_B2_14_SEMC_DATA29 +#define MIMXRT_IOMUXC_SEMC_DATA30 IOMUXC_GPIO_EMC_B2_15_SEMC_DATA30 +#define MIMXRT_IOMUXC_SEMC_DATA31 IOMUXC_GPIO_EMC_B2_16_SEMC_DATA31 +#define MIMXRT_IOMUXC_SEMC_DM03 IOMUXC_GPIO_EMC_B2_17_SEMC_DM03 +#define MIMXRT_IOMUXC_SEMC_DQS4 IOMUXC_GPIO_EMC_B2_18_SEMC_DQS4 + +#if MICROPY_PY_MACHINE_I2S +#define MICROPY_BOARD_ROOT_POINTERS \ + struct _machine_i2s_obj_t *machine_i2s_obj[MICROPY_HW_I2S_NUM]; +#endif + +// AUTOGENERATED by update.py from copier +#define MICROPY_HW_USB_CDC_NUM (2) +#define MICROPY_HW_USB_MSC (0) +#define MICROPY_HW_USB_HID (0) + +#define MICROPY_HW_USB_MANUFACTURER_STRING "PHYTEC" +#define MICROPY_HW_USB_PRODUCT_HS_STRING "phyBOARD-RT1170 Development Kit" +#define MICROPY_HW_USB_PRODUCT_FS_STRING "phyBOARD-RT1170 Development Kit" +#define MICROPY_HW_USB_CONFIGURATION_HS_STRING "phyBOARD Config" +#define MICROPY_HW_USB_INTERFACE_HS_STRING "phyBOARD Interface" +#define MICROPY_HW_USB_CONFIGURATION_FS_STRING "phyBOARD Config" +#define MICROPY_HW_USB_INTERFACE_FS_STRING "phyBOARD Interface" + +#define MBOOT_USBD_MANUFACTURER_STRING "PHYTEC" +#define MBOOT_USBD_PRODUCT_STRING "phyBOARD Boot" + +// phyBOARD-RT1170 Development Kit hardware features + +// Onboard EEPROM (M24C32 - 32Kbit) +#define MICROPY_HW_EEPROM_I2C_BUS (0) // On LPI2C1 (SoM) +#define MICROPY_HW_EEPROM_ADDR (0x50) + +// Carrier board peripherals +// Audio Codec: TLV320AIC3110 on LPI2C5 (I2C address: 0x18) +// Accelerometer: ICM-40627 on LPI2C2 (I2C address: 0x6B) +// CAN Interface: CAN3 (GPIO_LPSR_00/01) +// RS-232 Serial: LPUART8 (GPIO_AD_02/03/04/05) +// User Button: GPIO_AD_35 +// RGB LEDs: GPIO_AD_14 (red), GPIO_LPSR_13 (green) +// microSD Card Slot: USDHC1 +// M.2 Connector (Key E): WiFi/Bluetooth modules + +// Basic ADC channels available on connector +#define MICROPY_HW_ADC_NUM_CHANNELS (16) // GPIO_AD domain pins diff --git a/ports/mimxrt/boards/PHYBOARD_RT1170/mpconfigboard.mk b/ports/mimxrt/boards/PHYBOARD_RT1170/mpconfigboard.mk new file mode 100644 index 0000000000000..9cca7a54ab4bb --- /dev/null +++ b/ports/mimxrt/boards/PHYBOARD_RT1170/mpconfigboard.mk @@ -0,0 +1,31 @@ +MCU_SERIES = MIMXRT1176 +MCU_VARIANT = MIMXRT1176DVMAA +MCU_CORE = _cm7 + +MICROPY_FLOAT_IMPL = double +MICROPY_HW_FLASH_TYPE ?= qspi_nor_flash +MICROPY_HW_FLASH_SIZE ?= 0x1000000 # 16MB +MICROPY_HW_FLASH_RESERVED ?= 0x100000 # 1MB CM4 Code address space +MICROPY_HW_FLASH_CLK = kFlexSpiSerialClk_100MHz +MICROPY_HW_FLASH_QE_CMD = 0x31 +MICROPY_HW_FLASH_QE_ARG = 0x02 +# phyCORE SoM flash timing - use loopback from DQS pad for better signal integrity +MICROPY_HW_FLASH_DQS = kFlexSPIReadSampleClk_LoopbackFromDqsPad + +MICROPY_HW_SDRAM_AVAIL = 1 +MICROPY_HW_SDRAM_SIZE = 0x4000000 # 64MB + +MICROPY_PY_LWIP = 1 +MICROPY_PY_SSL = 1 +MICROPY_SSL_MBEDTLS = 1 +MICROPY_PY_OPENAMP = 1 +MICROPY_PY_OPENAMP_REMOTEPROC = 1 + +FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py + +CFLAGS += -DCPU_MIMXRT1176DVMAA_cm7 \ + -DMIMXRT117x_SERIES \ + -DENET_ENHANCEDBUFFERDESCRIPTOR_MODE=1 \ + -DCPU_HEADER_H='<$(MCU_SERIES)$(MCU_CORE).h>' \ + -DUSB1_BASE=USB_OTG1_BASE \ + -DUSB2_BASE=USB_OTG2_BASE diff --git a/ports/mimxrt/boards/PHYBOARD_RT1170/pins.csv b/ports/mimxrt/boards/PHYBOARD_RT1170/pins.csv new file mode 100644 index 0000000000000..c0222d9b252cc --- /dev/null +++ b/ports/mimxrt/boards/PHYBOARD_RT1170/pins.csv @@ -0,0 +1,127 @@ +# phyBOARD-RT1170 Development Kit Pin Mapping +# phyCORE-i.MX RT1170 SoM + PBA-C-26 Carrier Board + +# LEDs - phyCORE SoM onboard (active low) +LED_SOM_RED,GPIO_LPSR_07 +LED_SOM_GREEN,GPIO_LPSR_08 + +# LEDs - Carrier board RGB LEDs (active low) +LED_CARRIER_RED,GPIO_AD_14 +LED_CARRIER_GREEN,GPIO_LPSR_13 + +# Buttons +USER_BUTTON,GPIO_AD_35 +POWER_BUTTON,GPIO_LPSR_04 +WAKE_BUTTON,GPIO_LPSR_03 +RESET_BUTTON,GPIO_LPSR_02 + +# Primary UART interfaces +UART1_TX,GPIO_AD_24 +UART1_RX,GPIO_AD_25 + +# Additional UART interfaces (Carrier board) +UART2_TX,GPIO_DISP_B2_10 +UART2_RX,GPIO_DISP_B2_11 +UART2_CTS,GPIO_DISP_B2_13 +UART2_RTS,GPIO_DISP_B2_12 + +UART5_TX,GPIO_AD_28 +UART5_RX,GPIO_AD_29 + +UART6_TX,GPIO_EMC_B1_40 +UART6_RX,GPIO_EMC_B1_41 + +UART7_TX,GPIO_DISP_B2_06 +UART7_RX,GPIO_DISP_B2_07 + +UART8_TX_RS232,GPIO_AD_02 +UART8_RX_RS232,GPIO_AD_03 +UART8_CTS,GPIO_AD_04 +UART8_RTS,GPIO_AD_05 + +# I2C interfaces +I2C1_SCL,GPIO_AD_32 +I2C1_SDA,GPIO_AD_33 + +I2C2_SCL,GPIO_AD_18 +I2C2_SDA,GPIO_AD_19 + +I2C3_SCL,GPIO_DISP_B2_10 +I2C3_SDA,GPIO_DISP_B2_11 + +I2C5_SCL,GPIO_LPSR_09 +I2C5_SDA,GPIO_LPSR_08 + +# SPI interface +SPI1_SCK,GPIO_AD_28 +SPI1_CS,GPIO_AD_29 + +# Display interface (MIPI-DSI) +MIPI_DSI_DP0,GPIO_DISP_B1_02 +MIPI_DSI_DN0,GPIO_DISP_B1_03 +MIPI_DSI_DP1,GPIO_DISP_B1_00 +MIPI_DSI_DN1,GPIO_DISP_B1_01 +MIPI_DSI_CKP,GPIO_DISP_B1_05 +MIPI_DSI_CKN,GPIO_DISP_B1_04 + +# Display control pins +LCD_RST_B,GPIO_DISP_B2_14 +LCD_PWR_EN,GPIO_AD_26 +LCD_BACKLIGHT_CTL,GPIO_AD_27 +CTP_INT,GPIO_AD_26 +CTP_RST_B,GPIO_DISP_B2_15 + +# Camera interface (MIPI-CSI) - on SoM connector (via pin definitions) +# Note: MIPI-CSI differential pairs are on SoM - reference schematic for pin assignments + +# Accelerometer (ICM-40627 on LPI2C2) +ACCEL_INT1,GPIO_AD_26 +ACCEL_INT2,GPIO_AD_27 + +# Audio codec (TLV320AIC3110 on LPI2C5 and SAI1) +SAI1_TX_BCLK,GPIO_AD_22 +SAI1_TX_SYNC,GPIO_AD_23 +SAI1_TX_DATA,GPIO_AD_21 +SAI1_RX_DATA,GPIO_AD_20 +SAI1_MCLK,GPIO_AD_17 + +# CAN interface (CAN3) +CAN3_TX,GPIO_LPSR_00 +CAN3_RX,GPIO_LPSR_01 + +# SD Card interface (USDHC1) +SD1_CLK,GPIO_SD_B1_01 +SD1_CMD,GPIO_SD_B1_00 +SD1_DATA0,GPIO_SD_B1_02 +SD1_DATA1,GPIO_SD_B1_03 +SD1_DATA2,GPIO_SD_B1_04 +SD1_DATA3,GPIO_SD_B1_05 + +# Basic ADC channels +ADC1_CH0,GPIO_AD_00 +ADC1_CH1,GPIO_AD_01 +ADC1_CH2,GPIO_AD_02 +ADC1_CH3,GPIO_AD_03 + +# GPIO expansion connector +GPIO_CONN_16,GPIO_AD_16 +GPIO_CONN_17,GPIO_AD_17 +GPIO_CONN_18,GPIO_AD_18 +GPIO_CONN_19,GPIO_AD_19 +GPIO_CONN_20,GPIO_AD_20 +GPIO_CONN_21,GPIO_AD_21 +GPIO_CONN_22,GPIO_AD_22 +GPIO_CONN_23,GPIO_AD_23 +GPIO_CONN_26,GPIO_AD_26 +GPIO_CONN_27,GPIO_AD_27 +GPIO_CONN_LPSR_09,GPIO_LPSR_09 +GPIO_CONN_LPSR_10,GPIO_LPSR_10 +GPIO_CONN_LPSR_11,GPIO_LPSR_11 +GPIO_CONN_LPSR_12,GPIO_LPSR_12 + +# JTAG interface +JTAG_TCK,GPIO_LPSR_14 +JTAG_TMS,GPIO_LPSR_15 +JTAG_TDI,GPIO_LPSR_12 +JTAG_TDO,GPIO_LPSR_11 +JTAG_nTRST,GPIO_LPSR_10 diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk index 1bc38ccbad7b5..1cdfe8fe80582 100644 --- a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk @@ -7,6 +7,7 @@ MICROPY_HW_FLASH_SIZE = 0x800000 # 8MB MICROPY_HW_FLASH_CLK = kFlexSpiSerialClk_133MHz MICROPY_HW_FLASH_QE_CMD = 0x01 MICROPY_HW_FLASH_QE_ARG = 0x40 +MICROPY_HW_ROMFS_BYTES = 0x80000 # 512kB MICROPY_HW_SDRAM_AVAIL = 1 MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h index bff319c6d1576..2eeac0dab001b 100644 --- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h @@ -136,3 +136,6 @@ { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \ { IOMUXC_GPIO_B1_15_ENET_MDIO, 0, 0xB0E9u }, \ { IOMUXC_GPIO_B1_14_ENET_MDC, 0, 0xB0E9u }, + +// Enable PSRAM support +#define MICROPY_HW_ENABLE_PSRAM (1) diff --git a/ports/mimxrt/boards/make-flexram-config.py b/ports/mimxrt/boards/make-flexram-config.py index 4a80fb1d24762..f518746c97910 100644 --- a/ports/mimxrt/boards/make-flexram-config.py +++ b/ports/mimxrt/boards/make-flexram-config.py @@ -55,9 +55,14 @@ # Value parser -def mimxrt_default_parser(defines_file, features_file, ld_script): - with open(ld_script, "r") as input_file: - input_str = input_file.read() +def mimxrt_default_parser(defines_file, features_file, ld_scripts): + input_str = "" + if ld_scripts is None: + # Default linker script + ld_scripts = ["boards/MIMXRT1021.ld"] + for ld_script in ld_scripts: + with open(ld_script, "r") as input_file: + input_str += input_file.read() # ocram_match = re.search(ocram_regex, input_str, re.MULTILINE) dtcm_match = re.search(dtcm_regex, input_str, re.MULTILINE) @@ -249,7 +254,9 @@ def main(defines_file, features_file, ld_script, controller): "--ld_file", dest="linker_file", help="Path to the aggregated linker-script", - default="MIMXRT1021.ld", + action="append", + # Can't specify default here when using 'append' action, see + # https://github.com/python/cpython/issues/60603 ) parser.add_argument( "-c", "--controller", dest="controller", help="Controller name", default="MIMXRT1021" diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py index 55c7f5bd02738..6ad60f0545bcd 100644 --- a/ports/mimxrt/boards/make-pins.py +++ b/ports/mimxrt/boards/make-pins.py @@ -61,18 +61,23 @@ def add_af(self, af_idx, af_name, af): elif af_name == "ADC": adc_regex = r"ADC(?P\d*)_IN(?P\d*)" - lpadc_regex = r"ADC(?P\d*)_CH(?P\d*)" # LPADC for MIMXRT11xx chips + lpadc_regex = r"ADC(?P\d*)_CH(?P\d*)(?P.*)" # LPADC for MIMXRT11xx chips matches = re.finditer(adc_regex, af, re.MULTILINE) for match in matches: self._adc_fns.append( - (int(match.group("instance")), int(match.group("channel")), "ADC") + (int(match.group("instance")), int(match.group("channel")), 0, "ADC") ) matches = re.finditer(lpadc_regex, af, re.MULTILINE) for match in matches: self._adc_fns.append( - (int(match.group("instance")), int(match.group("channel")), "LPADC") + ( + int(match.group("instance")), + int(match.group("channel")), + ord(match.group("channel_group")[0]) - ord("A"), + "LPADC", + ) ) # Use the PIN() macro defined in samd_prefix.c for defining the pin @@ -122,9 +127,11 @@ def print_source(self, out_source): "static const machine_pin_adc_obj_t pin_{:s}_adc[] = {{".format(self.name()), file=out_source, ) - for instance, channel, peripheral in self._adc_fns: + for instance, channel, channel_group, peripheral in self._adc_fns: print( - " PIN_ADC({:s}{:d}, {:d}),".format(peripheral, instance, channel), + " PIN_ADC({:s}{:d}, {:d}, {:d}),".format( + peripheral, instance, channel, channel_group + ), file=out_source, ) print("};", file=out_source) diff --git a/ports/mimxrt/boards/mimxrt_prefix.c b/ports/mimxrt/boards/mimxrt_prefix.c index 49d6e67dc4083..e6bba18b9f12c 100644 --- a/ports/mimxrt/boards/mimxrt_prefix.c +++ b/ports/mimxrt/boards/mimxrt_prefix.c @@ -16,10 +16,11 @@ .pad_config = (uint32_t)(_pad_config), \ } \ -#define PIN_ADC(_instance, _channel) \ +#define PIN_ADC(_instance, _channel, _channel_group) \ { \ .instance = (_instance), \ - .channel = (_channel) \ + .channel = (_channel), \ + .channel_group = (_channel_group), \ } \ #define PIN(_name, _gpio, _pin, _af_list, _adc_list_len, _adc_list) \ diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c index 1fbd9d3895f79..308f5407a2983 100644 --- a/ports/mimxrt/eth.c +++ b/ports/mimxrt/eth.c @@ -31,7 +31,7 @@ #include "py/mperrno.h" #include "ticks.h" -#if defined(IOMUX_TABLE_ENET) +#if defined(ENET_PHY_ADDRESS) || defined(ENET_1_PHY_ADDRESS) #include "pin.h" #include "shared/netutils/netutils.h" @@ -44,6 +44,7 @@ #include "hal/phy/device/phyksz8081/fsl_phyksz8081.h" #include "hal/phy/device/phydp83825/fsl_phydp83825.h" #include "hal/phy/device/phydp83848/fsl_phydp83848.h" +#include "hal/phy/device/phydp83867/fsl_phydp83867.h" #include "hal/phy/device/phylan8720/fsl_phylan8720.h" #include "hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.h" @@ -74,6 +75,8 @@ typedef struct _iomux_table_t { uint32_t configValue; } iomux_table_t; +#if defined(ENET_PHY_ADDRESS) + // ETH0 buffers and handles static AT_NONCACHEABLE_SECTION_ALIGN(enet_rx_bd_struct_t g_rxBuffDescrip[ENET_RXBD_NUM], ENET_BUFF_ALIGNMENT); static AT_NONCACHEABLE_SECTION_ALIGN(enet_tx_bd_struct_t g_txBuffDescrip[ENET_TXBD_NUM], ENET_BUFF_ALIGNMENT); @@ -110,7 +113,9 @@ static const iomux_table_t iomux_table_enet[] = { static uint8_t hw_addr[6]; // The MAC address field -#if defined(ENET_DUAL_PORT) +#endif // defined(ENET_PHY_ADDRESS) + +#if defined(ENET_1_PHY_ADDRESS) // ETH1 buffers and handles static AT_NONCACHEABLE_SECTION_ALIGN(enet_rx_bd_struct_t g_rxBuffDescrip_1[ENET_RXBD_NUM], ENET_BUFF_ALIGNMENT); @@ -147,17 +152,14 @@ static const iomux_table_t iomux_table_enet_1[] = { static uint8_t hw_addr_1[6]; // The MAC address field -#endif - -#if defined(ENET_DUAL_PORT) +// Define ENET_1 to the appropriate controller for this hardware #if defined MIMXRT117x_SERIES #define ENET_1 ENET_1G #else #define ENET_1 ENET2 #endif -#else -#define ENET_1 ENET -#endif + +#endif // defined(ENET_1_PHY_ADDRESS) #define PHY_AUTONEGO_TIMEOUT_US (5000000) #define PHY_SETTLE_TIME_US (1000) @@ -356,6 +358,8 @@ static void eth_phy_init(phy_handle_t *phyHandle, phy_config_t *phy_config, mp_hal_delay_us(phy_settle_time); } +#if defined(ENET_PHY_ADDRESS) + // eth_init: Set up GPIO and the transceiver void eth_init_0(eth_t *self, int eth_id, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock) { // Configuration values @@ -410,7 +414,9 @@ void eth_init_0(eth_t *self, int eth_id, const phy_operations_t *phy_ops, int ph ENET_ActiveRead(ENET); } -#if defined(ENET_DUAL_PORT) +#endif // defined(ENET_PHY_ADDRESS) + +#if defined(ENET_1_PHY_ADDRESS) // eth_init: Set up GPIO and the transceiver void eth_init_1(eth_t *self, int eth_id, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock) { @@ -422,7 +428,7 @@ void eth_init_1(eth_t *self, int eth_id, const phy_operations_t *phy_ops, int ph uint32_t source_clock = eth_clock_init(eth_id, phy_clock); const machine_pin_obj_t *reset_pin = NULL; - #if defined(pin_ENET_1_INT) + #if defined(pin_ENET_1_RESET) reset_pin = pin_ENET_1_RESET; #endif const machine_pin_obj_t *int_pin = NULL; @@ -473,7 +479,8 @@ void eth_init_1(eth_t *self, int eth_id, const phy_operations_t *phy_ops, int ph ENET_ActiveRead(ENET_1); } -#endif +#endif // defined(ENET_1_PHY_ADDRESS) + // Initialize the phy interface static int eth_mac_init(eth_t *self) { return 0; @@ -511,14 +518,26 @@ static err_t eth_send_frame_blocking(ENET_Type *base, enet_handle_t *handle, uin static err_t eth_netif_output(struct netif *netif, struct pbuf *p) { // This function should always be called from a context where PendSV-level IRQs are disabled status_t status; - ENET_Type *enet = ENET; - enet_handle_t *handle = &g_handle; + ENET_Type *enet; + enet_handle_t *handle; - #if defined ENET_DUAL_PORT + #if defined(ENET_PHY_ADDRESS) && defined(ENET_1_PHY_ADDRESS) + // Dual port: select based on netif->state if (netif->state == ð_instance1) { enet = ENET_1; handle = &g_handle_1; + } else { + enet = ENET; + handle = &g_handle; } + #elif defined(ENET_1_PHY_ADDRESS) + // Only ENET_1 available + enet = ENET_1; + handle = &g_handle_1; + #else + // Only ENET available + enet = ENET; + handle = &g_handle; #endif eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE); @@ -561,15 +580,18 @@ static void eth_lwip_init(eth_t *self) { ip_addr_t ipconfig[4]; self->netif.hwaddr_len = 6; + #if defined(ENET_PHY_ADDRESS) if (self == ð_instance0) { memcpy(self->netif.hwaddr, hw_addr, 6); IP4_ADDR(&ipconfig[0], 192, 168, 0, 2); - #if defined ENET_DUAL_PORT - } else { + } + #endif + #if defined(ENET_1_PHY_ADDRESS) + if (self == ð_instance1) { memcpy(self->netif.hwaddr, hw_addr_1, 6); IP4_ADDR(&ipconfig[0], 192, 168, 0, 3); - #endif } + #endif IP4_ADDR(&ipconfig[1], 255, 255, 255, 0); IP4_ADDR(&ipconfig[2], 192, 168, 0, 1); IP4_ADDR(&ipconfig[3], 8, 8, 8, 8); @@ -577,7 +599,11 @@ static void eth_lwip_init(eth_t *self) { MICROPY_PY_LWIP_ENTER n->name[0] = 'e'; + #if defined(ENET_PHY_ADDRESS) n->name[1] = (self == ð_instance0 ? '0' : '1'); + #else + n->name[1] = '1'; + #endif netif_add(n, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, eth_netif_init, ethernet_input); netif_set_hostname(n, mod_network_hostname_data); netif_set_default(n); @@ -619,8 +645,10 @@ int eth_link_status(eth_t *self) { } } else { bool link; - #if defined ENET_DUAL_PORT + #if defined(ENET_PHY_ADDRESS) && defined(ENET_1_PHY_ADDRESS) PHY_GetLinkStatus(self == ð_instance0 ? &phyHandle : &phyHandle_1, &link); + #elif defined(ENET_1_PHY_ADDRESS) + PHY_GetLinkStatus(&phyHandle_1, &link); #else PHY_GetLinkStatus(&phyHandle, &link); #endif @@ -653,10 +681,12 @@ int eth_stop(eth_t *self) { } void eth_low_power_mode(eth_t *self, bool enable) { - #if defined ENET_DUAL_PORT + #if defined(ENET_PHY_ADDRESS) && defined(ENET_1_PHY_ADDRESS) ENET_EnableSleepMode(self == ð_instance0 ? ENET : ENET_1, enable); + #elif defined(ENET_1_PHY_ADDRESS) + ENET_EnableSleepMode(ENET_1, enable); #else ENET_EnableSleepMode(ENET, enable); #endif } -#endif // defined(IOMUX_TABLE_ENET) +#endif // defined(ENET_PHY_ADDRESS) || defined(ENET_1_PHY_ADDRESS) diff --git a/ports/mimxrt/eth.h b/ports/mimxrt/eth.h index afb5d5edf375e..4c87d1b5178d4 100644 --- a/ports/mimxrt/eth.h +++ b/ports/mimxrt/eth.h @@ -28,11 +28,14 @@ #define MICROPY_INCLUDED_MIMXRT_ETH_H typedef struct _eth_t eth_t; + +#if defined(ENET_PHY_ADDRESS) extern eth_t eth_instance0; -extern eth_t eth_instance1; void eth_init_0(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock); +#endif -#if defined(ENET_DUAL_PORT) +#if defined(ENET_1_PHY_ADDRESS) +extern eth_t eth_instance1; void eth_init_1(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock); #endif @@ -47,6 +50,7 @@ enum { PHY_KSZ8081 = 0, PHY_DP83825, PHY_DP83848, + PHY_DP83867, PHY_LAN8720, PHY_RTL8211F, }; diff --git a/ports/mimxrt/fatfs_port.c b/ports/mimxrt/fatfs_port.c index 7b7008667ff3e..5d3b90c28d78f 100644 --- a/ports/mimxrt/fatfs_port.c +++ b/ports/mimxrt/fatfs_port.c @@ -26,14 +26,12 @@ */ #include "lib/oofatfs/ff.h" -#include "fsl_snvs_lp.h" - +#include "shared/timeutils/timeutils.h" +#include "modmachine.h" MP_WEAK DWORD get_fattime(void) { - snvs_lp_srtc_datetime_t srtcDate; - - SNVS_LP_SRTC_GetDatetime(SNVS, &srtcDate); - - return ((srtcDate.year - 1980) << 25) | (srtcDate.month << 21) | (srtcDate.day << 16) | - (srtcDate.hour << 11) | ((srtcDate.minute << 5) | (srtcDate.second / 2)); + uint64_t seconds = machine_rtc_get_seconds(); + timeutils_struct_time_t tm; + timeutils_seconds_since_epoch_to_struct_time(seconds, &tm); + return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) | ((tm.tm_mday) << 16) | ((tm.tm_hour) << 11) | ((tm.tm_min) << 5) | (tm.tm_sec / 2); } diff --git a/ports/mimxrt/hal/fsl_lpuart.c b/ports/mimxrt/hal/fsl_lpuart.c deleted file mode 100644 index 54651c3efbcd4..0000000000000 --- a/ports/mimxrt/hal/fsl_lpuart.c +++ /dev/null @@ -1,2013 +0,0 @@ -/* - * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2020 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "fsl_lpuart.h" - -/******************************************************************************* - * Definitions - ******************************************************************************/ - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.lpuart" -#endif - -/* LPUART transfer state. */ -enum -{ - kLPUART_TxIdle, /*!< TX idle. */ - kLPUART_TxBusy, /*!< TX busy. */ - kLPUART_RxIdle, /*!< RX idle. */ - kLPUART_RxBusy /*!< RX busy. */ -}; - -/******************************************************************************* - * Prototypes - ******************************************************************************/ -/*! - * @brief Check whether the RX ring buffer is full. - * - * @userData handle LPUART handle pointer. - * @retval true RX ring buffer is full. - * @retval false RX ring buffer is not full. - */ -static bool LPUART_TransferIsRxRingBufferFull(LPUART_Type *base, lpuart_handle_t *handle); - -/*! - * @brief Write to TX register using non-blocking method. - * - * This function writes data to the TX register directly, upper layer must make - * sure the TX register is empty or TX FIFO has empty room before calling this function. - * - * @note This function does not check whether all the data has been sent out to bus, - * so before disable TX, check kLPUART_TransmissionCompleteFlag to ensure the TX is - * finished. - * - * @param base LPUART peripheral base address. - * @param data Start address of the data to write. - * @param length Size of the buffer to be sent. - */ -static void LPUART_WriteNonBlocking(LPUART_Type *base, const uint8_t *data, size_t length); - -/*! - * @brief Read RX register using non-blocking method. - * - * This function reads data from the TX register directly, upper layer must make - * sure the RX register is full or TX FIFO has data before calling this function. - * - * @param base LPUART peripheral base address. - * @param data Start address of the buffer to store the received data. - * @param length Size of the buffer. - */ -static void LPUART_ReadNonBlocking(LPUART_Type *base, uint8_t *data, size_t length); - -/******************************************************************************* - * Variables - ******************************************************************************/ -/* Array of LPUART peripheral base address. */ -static LPUART_Type *const s_lpuartBases[] = LPUART_BASE_PTRS; -/* Array of LPUART handle. */ -void *s_lpuartHandle[ARRAY_SIZE(s_lpuartBases)]; -/* Array of LPUART IRQ number. */ -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -static const IRQn_Type s_lpuartRxIRQ[] = LPUART_RX_IRQS; -const IRQn_Type s_lpuartTxIRQ[] = LPUART_TX_IRQS; -#else -const IRQn_Type s_lpuartIRQ[] = LPUART_RX_TX_IRQS; -#endif -#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) -/* Array of LPUART clock name. */ -static const clock_ip_name_t s_lpuartClock[] = LPUART_CLOCKS; - -#if defined(LPUART_PERIPH_CLOCKS) -/* Array of LPUART functional clock name. */ -static const clock_ip_name_t s_lpuartPeriphClocks[] = LPUART_PERIPH_CLOCKS; -#endif - -#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ - -/* LPUART ISR for transactional APIs. */ -#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) -lpuart_isr_t s_lpuartIsr = (lpuart_isr_t)DefaultISR; -#else -lpuart_isr_t s_lpuartIsr; -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -/*! - * brief Get the LPUART instance from peripheral base address. - * - * param base LPUART peripheral base address. - * return LPUART instance. - */ -uint32_t LPUART_GetInstance(LPUART_Type *base) { - uint32_t instance; - - /* Find the instance index from base address mappings. */ - for (instance = 0U; instance < ARRAY_SIZE(s_lpuartBases); instance++) { - if (s_lpuartBases[instance] == base) { - break; - } - } - - assert(instance < ARRAY_SIZE(s_lpuartBases)); - - return instance; -} - -/*! - * brief Get the length of received data in RX ring buffer. - * - * userData handle LPUART handle pointer. - * return Length of received data in RX ring buffer. - */ -size_t LPUART_TransferGetRxRingBufferLength(LPUART_Type *base, lpuart_handle_t *handle) { - assert(NULL != handle); - - size_t size; - size_t tmpRxRingBufferSize = handle->rxRingBufferSize; - uint16_t tmpRxRingBufferTail = handle->rxRingBufferTail; - uint16_t tmpRxRingBufferHead = handle->rxRingBufferHead; - - if (tmpRxRingBufferTail > tmpRxRingBufferHead) { - size = ((size_t)tmpRxRingBufferHead + tmpRxRingBufferSize - (size_t)tmpRxRingBufferTail); - } else { - size = ((size_t)tmpRxRingBufferHead - (size_t)tmpRxRingBufferTail); - } - - return size; -} - -static bool LPUART_TransferIsRxRingBufferFull(LPUART_Type *base, lpuart_handle_t *handle) { - assert(NULL != handle); - - bool full; - - if (LPUART_TransferGetRxRingBufferLength(base, handle) == (handle->rxRingBufferSize - 1U)) { - full = true; - } else { - full = false; - } - return full; -} - -static void LPUART_WriteNonBlocking(LPUART_Type *base, const uint8_t *data, size_t length) { - assert(NULL != data); - - size_t i; - - /* The Non Blocking write data API assume user have ensured there is enough space in - peripheral to write. */ - for (i = 0; i < length; i++) { - base->DATA = data[i]; - } -} - -static void LPUART_ReadNonBlocking(LPUART_Type *base, uint8_t *data, size_t length) { - assert(NULL != data); - - size_t i; - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - uint32_t ctrl = base->CTRL; - bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) || - (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U))); - #endif - - /* The Non Blocking read data API assume user have ensured there is enough space in - peripheral to write. */ - for (i = 0; i < length; i++) { - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - if (isSevenDataBits) { - data[i] = (uint8_t)(base->DATA & 0x7FU); - } else { - data[i] = (uint8_t)base->DATA; - } - #else - data[i] = (uint8_t)(base->DATA); - #endif - } -} - -/*! - * brief Initializes an LPUART instance with the user configuration structure and the peripheral clock. - * - * This function configures the LPUART module with user-defined settings. Call the LPUART_GetDefaultConfig() function - * to configure the configuration structure and get the default configuration. - * The example below shows how to use this API to configure the LPUART. - * code - * lpuart_config_t lpuartConfig; - * lpuartConfig.baudRate_Bps = 115200U; - * lpuartConfig.parityMode = kLPUART_ParityDisabled; - * lpuartConfig.dataBitsCount = kLPUART_EightDataBits; - * lpuartConfig.isMsb = false; - * lpuartConfig.stopBitCount = kLPUART_OneStopBit; - * lpuartConfig.txFifoWatermark = 0; - * lpuartConfig.rxFifoWatermark = 1; - * LPUART_Init(LPUART1, &lpuartConfig, 20000000U); - * endcode - * - * param base LPUART peripheral base address. - * param config Pointer to a user-defined configuration structure. - * param srcClock_Hz LPUART clock source frequency in HZ. - * retval kStatus_LPUART_BaudrateNotSupport Baudrate is not support in current clock source. - * retval kStatus_Success LPUART initialize succeed - */ -status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz) { - assert(NULL != config); - assert(0U < config->baudRate_Bps); - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - assert((uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) >= config->txFifoWatermark); - assert((uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) >= config->rxFifoWatermark); - #endif - - status_t status = kStatus_Success; - uint32_t temp; - uint16_t sbr, sbrTemp; - uint8_t osr, osrTemp; - uint32_t tempDiff, calculatedBaud, baudDiff; - - /* This LPUART instantiation uses a slightly different baud rate calculation - * The idea is to use the best OSR (over-sampling rate) possible - * Note, OSR is typically hard-set to 16 in other LPUART instantiations - * loop to find the best OSR value possible, one that generates minimum baudDiff - * iterate through the rest of the supported values of OSR */ - - baudDiff = config->baudRate_Bps; - osr = 0U; - sbr = 0U; - for (osrTemp = 4U; osrTemp <= 32U; osrTemp++) { - /* calculate the temporary sbr value */ - sbrTemp = (uint16_t)((srcClock_Hz * 10U / (config->baudRate_Bps * (uint32_t)osrTemp) + 5U) / 10U); - /*set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate*/ - if (sbrTemp == 0U) { - sbrTemp = 1U; - } - /* Calculate the baud rate based on the temporary OSR and SBR values */ - calculatedBaud = (srcClock_Hz / ((uint32_t)osrTemp * (uint32_t)sbrTemp)); - tempDiff = calculatedBaud > config->baudRate_Bps ? (calculatedBaud - config->baudRate_Bps) : - (config->baudRate_Bps - calculatedBaud); - - if (tempDiff <= baudDiff) { - baudDiff = tempDiff; - osr = osrTemp; /* update and store the best OSR value calculated */ - sbr = sbrTemp; /* update store the best SBR value calculated */ - } - } - - /* Check to see if actual baud rate is within 3% of desired baud rate - * based on the best calculate OSR value */ - if (baudDiff > ((config->baudRate_Bps / 100U) * 3U)) { - /* Unacceptable baud rate difference of more than 3%*/ - status = kStatus_LPUART_BaudrateNotSupport; - } else { - #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) - - uint32_t instance = LPUART_GetInstance(base); - - /* Enable lpuart clock */ - (void)CLOCK_EnableClock(s_lpuartClock[instance]); - #if defined(LPUART_PERIPH_CLOCKS) - (void)CLOCK_EnableClock(s_lpuartPeriphClocks[instance]); - #endif - - #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ - - #if defined(FSL_FEATURE_LPUART_HAS_GLOBAL) && FSL_FEATURE_LPUART_HAS_GLOBAL - /*Reset all internal logic and registers, except the Global Register */ - LPUART_SoftwareReset(base); - #else - /* Disable LPUART TX RX before setting. */ - base->CTRL &= ~(LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK); - #endif - - temp = base->BAUD; - - /* Acceptable baud rate, check if OSR is between 4x and 7x oversampling. - * If so, then "BOTHEDGE" sampling must be turned on */ - if ((osr > 3U) && (osr < 8U)) { - temp |= LPUART_BAUD_BOTHEDGE_MASK; - } - - /* program the osr value (bit value is one less than actual value) */ - temp &= ~LPUART_BAUD_OSR_MASK; - temp |= LPUART_BAUD_OSR((uint32_t)osr - 1UL); - - /* write the sbr value to the BAUD registers */ - temp &= ~LPUART_BAUD_SBR_MASK; - base->BAUD = temp | LPUART_BAUD_SBR(sbr); - - /* Set bit count and parity mode. */ - base->BAUD &= ~LPUART_BAUD_M10_MASK; - - temp = base->CTRL & ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK | LPUART_CTRL_ILT_MASK | - LPUART_CTRL_IDLECFG_MASK); - - temp |= (uint8_t)config->parityMode | LPUART_CTRL_IDLECFG(config->rxIdleConfig) | - LPUART_CTRL_ILT(config->rxIdleType); - - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - if (kLPUART_SevenDataBits == config->dataBitsCount) { - if (kLPUART_ParityDisabled != config->parityMode) { - temp &= ~LPUART_CTRL_M7_MASK; /* Seven data bits and one parity bit */ - } else { - temp |= LPUART_CTRL_M7_MASK; - } - } else - #endif - { - if (kLPUART_ParityDisabled != config->parityMode) { - temp |= LPUART_CTRL_M_MASK; /* Eight data bits and one parity bit */ - } - } - - base->CTRL = temp; - - #if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT - /* set stop bit per char */ - temp = base->BAUD & ~LPUART_BAUD_SBNS_MASK; - base->BAUD = temp | LPUART_BAUD_SBNS((uint8_t)config->stopBitCount); - #endif - - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - /* Set tx/rx WATER watermark - Note: - Take care of the RX FIFO, RX interrupt request only assert when received bytes - equal or more than RX water mark, there is potential issue if RX water - mark larger than 1. - For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and - 5 bytes are received. the last byte will be saved in FIFO but not trigger - RX interrupt because the water mark is 2. - */ - base->WATER = (((uint32_t)(config->rxFifoWatermark) << 16U) | config->txFifoWatermark); - - /* Enable tx/rx FIFO */ - base->FIFO |= (LPUART_FIFO_TXFE_MASK | LPUART_FIFO_RXFE_MASK); - - /* Flush FIFO */ - base->FIFO |= (LPUART_FIFO_TXFLUSH_MASK | LPUART_FIFO_RXFLUSH_MASK); - #endif - - /* Clear all status flags */ - temp = (LPUART_STAT_RXEDGIF_MASK | LPUART_STAT_IDLE_MASK | LPUART_STAT_OR_MASK | LPUART_STAT_NF_MASK | - LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK); - - #if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT - temp |= LPUART_STAT_LBKDIF_MASK; - #endif - - #if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING - temp |= (LPUART_STAT_MA1F_MASK | LPUART_STAT_MA2F_MASK); - #endif - - #if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT - /* Set the CTS configuration/TX CTS source. */ - base->MODIR |= LPUART_MODIR_TXCTSC(config->txCtsConfig) | LPUART_MODIR_TXCTSSRC(config->txCtsSource); - if (true == config->enableRxRTS) { - /* Enable the receiver RTS(request-to-send) function. */ - base->MODIR |= LPUART_MODIR_RXRTSE_MASK; - } - if (true == config->enableTxCTS) { - /* Enable the CTS(clear-to-send) function. */ - base->MODIR |= LPUART_MODIR_TXCTSE_MASK; - } - #endif - - /* Set data bits order. */ - if (true == config->isMsb) { - temp |= LPUART_STAT_MSBF_MASK; - } else { - temp &= ~LPUART_STAT_MSBF_MASK; - } - - base->STAT |= temp; - - /* Enable TX/RX base on configure structure. */ - temp = base->CTRL; - if (true == config->enableTx) { - temp |= LPUART_CTRL_TE_MASK; - } - - if (true == config->enableRx) { - temp |= LPUART_CTRL_RE_MASK; - } - - base->CTRL = temp; - } - - return status; -} -/*! - * brief Deinitializes a LPUART instance. - * - * This function waits for transmit to complete, disables TX and RX, and disables the LPUART clock. - * - * param base LPUART peripheral base address. - */ -void LPUART_Deinit(LPUART_Type *base) { - uint32_t temp; - - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - /* Wait tx FIFO send out*/ - while (0U != ((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXWATER_SHIFT)) { - } - #endif - /* Wait last char shift out */ - while (0U == (base->STAT & LPUART_STAT_TC_MASK)) { - } - - /* Clear all status flags */ - temp = (LPUART_STAT_RXEDGIF_MASK | LPUART_STAT_IDLE_MASK | LPUART_STAT_OR_MASK | LPUART_STAT_NF_MASK | - LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK); - - #if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT - temp |= LPUART_STAT_LBKDIF_MASK; - #endif - - #if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING - temp |= (LPUART_STAT_MA1F_MASK | LPUART_STAT_MA2F_MASK); - #endif - - base->STAT |= temp; - - /* Disable the module. */ - base->CTRL = 0U; - - #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) - uint32_t instance = LPUART_GetInstance(base); - - /* Disable lpuart clock */ - (void)CLOCK_DisableClock(s_lpuartClock[instance]); - - #if defined(LPUART_PERIPH_CLOCKS) - (void)CLOCK_DisableClock(s_lpuartPeriphClocks[instance]); - #endif - - #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ -} - -/*! - * brief Gets the default configuration structure. - * - * This function initializes the LPUART configuration structure to a default value. The default - * values are: - * lpuartConfig->baudRate_Bps = 115200U; - * lpuartConfig->parityMode = kLPUART_ParityDisabled; - * lpuartConfig->dataBitsCount = kLPUART_EightDataBits; - * lpuartConfig->isMsb = false; - * lpuartConfig->stopBitCount = kLPUART_OneStopBit; - * lpuartConfig->txFifoWatermark = 0; - * lpuartConfig->rxFifoWatermark = 1; - * lpuartConfig->rxIdleType = kLPUART_IdleTypeStartBit; - * lpuartConfig->rxIdleConfig = kLPUART_IdleCharacter1; - * lpuartConfig->enableTx = false; - * lpuartConfig->enableRx = false; - * - * param config Pointer to a configuration structure. - */ -void LPUART_GetDefaultConfig(lpuart_config_t *config) { - assert(NULL != config); - - /* Initializes the configure structure to zero. */ - (void)memset(config, 0, sizeof(*config)); - - config->baudRate_Bps = 115200U; - config->parityMode = kLPUART_ParityDisabled; - config->dataBitsCount = kLPUART_EightDataBits; - config->isMsb = false; - #if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT - config->stopBitCount = kLPUART_OneStopBit; - #endif - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - config->txFifoWatermark = 0U; - config->rxFifoWatermark = 0U; - #endif - #if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT - config->enableRxRTS = false; - config->enableTxCTS = false; - config->txCtsConfig = kLPUART_CtsSampleAtStart; - config->txCtsSource = kLPUART_CtsSourcePin; - #endif - config->rxIdleType = kLPUART_IdleTypeStartBit; - config->rxIdleConfig = kLPUART_IdleCharacter1; - config->enableTx = false; - config->enableRx = false; -} - -/*! - * brief Sets the LPUART instance baudrate. - * - * This function configures the LPUART module baudrate. This function is used to update - * the LPUART module baudrate after the LPUART module is initialized by the LPUART_Init. - * code - * LPUART_SetBaudRate(LPUART1, 115200U, 20000000U); - * endcode - * - * param base LPUART peripheral base address. - * param baudRate_Bps LPUART baudrate to be set. - * param srcClock_Hz LPUART clock source frequency in HZ. - * retval kStatus_LPUART_BaudrateNotSupport Baudrate is not supported in the current clock source. - * retval kStatus_Success Set baudrate succeeded. - */ -status_t LPUART_SetBaudRate(LPUART_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz) { - assert(0U < baudRate_Bps); - - status_t status = kStatus_Success; - uint32_t temp, oldCtrl; - uint16_t sbr, sbrTemp; - uint8_t osr, osrTemp; - uint32_t tempDiff, calculatedBaud, baudDiff; - - /* This LPUART instantiation uses a slightly different baud rate calculation - * The idea is to use the best OSR (over-sampling rate) possible - * Note, OSR is typically hard-set to 16 in other LPUART instantiations - * loop to find the best OSR value possible, one that generates minimum baudDiff - * iterate through the rest of the supported values of OSR */ - - baudDiff = baudRate_Bps; - osr = 0U; - sbr = 0U; - for (osrTemp = 4U; osrTemp <= 32U; osrTemp++) { - /* calculate the temporary sbr value */ - sbrTemp = (uint16_t)((srcClock_Hz * 10U / (baudRate_Bps * (uint32_t)osrTemp) + 5U) / 10U); - /*set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate*/ - if (sbrTemp == 0U) { - sbrTemp = 1U; - } - /* Calculate the baud rate based on the temporary OSR and SBR values */ - calculatedBaud = srcClock_Hz / ((uint32_t)osrTemp * (uint32_t)sbrTemp); - - tempDiff = calculatedBaud > baudRate_Bps ? (calculatedBaud - baudRate_Bps) : (baudRate_Bps - calculatedBaud); - - if (tempDiff <= baudDiff) { - baudDiff = tempDiff; - osr = osrTemp; /* update and store the best OSR value calculated */ - sbr = sbrTemp; /* update store the best SBR value calculated */ - } - } - - /* Check to see if actual baud rate is within 3% of desired baud rate - * based on the best calculate OSR value */ - if (baudDiff < (uint32_t)((baudRate_Bps / 100U) * 3U)) { - /* Store CTRL before disable Tx and Rx */ - oldCtrl = base->CTRL; - - /* Disable LPUART TX RX before setting. */ - base->CTRL &= ~(LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK); - - temp = base->BAUD; - - /* Acceptable baud rate, check if OSR is between 4x and 7x oversampling. - * If so, then "BOTHEDGE" sampling must be turned on */ - if ((osr > 3U) && (osr < 8U)) { - temp |= LPUART_BAUD_BOTHEDGE_MASK; - } - - /* program the osr value (bit value is one less than actual value) */ - temp &= ~LPUART_BAUD_OSR_MASK; - temp |= LPUART_BAUD_OSR((uint32_t)osr - 1UL); - - /* write the sbr value to the BAUD registers */ - temp &= ~LPUART_BAUD_SBR_MASK; - base->BAUD = temp | LPUART_BAUD_SBR(sbr); - - /* Restore CTRL. */ - base->CTRL = oldCtrl; - } else { - /* Unacceptable baud rate difference of more than 3%*/ - status = kStatus_LPUART_BaudrateNotSupport; - } - - return status; -} - -/*! - * brief Enable 9-bit data mode for LPUART. - * - * This function set the 9-bit mode for LPUART module. The 9th bit is not used for parity thus can be modified by user. - * - * param base LPUART peripheral base address. - * param enable true to enable, false to disable. - */ -void LPUART_Enable9bitMode(LPUART_Type *base, bool enable) { - assert(base != NULL); - - uint32_t temp = 0U; - - if (enable) { - /* Set LPUART_CTRL_M for 9-bit mode, clear LPUART_CTRL_PE to disable parity. */ - temp = base->CTRL & ~((uint32_t)LPUART_CTRL_PE_MASK | (uint32_t)LPUART_CTRL_M_MASK); - temp |= (uint32_t)LPUART_CTRL_M_MASK; - base->CTRL = temp; - } else { - /* Clear LPUART_CTRL_M. */ - base->CTRL &= ~(uint32_t)LPUART_CTRL_M_MASK; - } - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - /* Clear LPUART_CTRL_M7 to disable 7-bit mode. */ - base->CTRL &= ~(uint32_t)LPUART_CTRL_M7_MASK; - #endif - #if defined(FSL_FEATURE_LPUART_HAS_10BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_10BIT_DATA_SUPPORT - /* Clear LPUART_BAUD_M10 to disable 10-bit mode. */ - base->BAUD &= ~(uint32_t)LPUART_BAUD_M10_MASK; - #endif -} - -/*! - * brief Transmit an address frame in 9-bit data mode. - * - * param base LPUART peripheral base address. - * param address LPUART slave address. - */ -void LPUART_SendAddress(LPUART_Type *base, uint8_t address) { - assert(base != NULL); - - uint32_t temp = base->DATA & 0xFFFFFC00UL; - temp |= ((uint32_t)address | (1UL << LPUART_DATA_R8T8_SHIFT)); - base->DATA = temp; -} - -/*! - * brief Enables LPUART interrupts according to a provided mask. - * - * This function enables the LPUART interrupts according to a provided mask. The mask - * is a logical OR of enumeration members. See the ref _lpuart_interrupt_enable. - * This examples shows how to enable TX empty interrupt and RX full interrupt: - * code - * LPUART_EnableInterrupts(LPUART1,kLPUART_TxDataRegEmptyInterruptEnable | kLPUART_RxDataRegFullInterruptEnable); - * endcode - * - * param base LPUART peripheral base address. - * param mask The interrupts to enable. Logical OR of ref _uart_interrupt_enable. - */ -void LPUART_EnableInterrupts(LPUART_Type *base, uint32_t mask) { - /* Only consider the real interrupt enable bits. */ - mask &= (uint32_t)kLPUART_AllInterruptEnable; - - /* Check int enable bits in base->BAUD */ - uint32_t tempReg = base->BAUD; - #if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT - tempReg |= ((mask << 8U) & LPUART_BAUD_LBKDIE_MASK); - /* Clear bit 7 from mask */ - mask &= ~(uint32_t)kLPUART_LinBreakInterruptEnable; - #endif - tempReg |= ((mask << 8U) & LPUART_BAUD_RXEDGIE_MASK); - /* Clear bit 6 from mask */ - mask &= ~(uint32_t)kLPUART_RxActiveEdgeInterruptEnable; - base->BAUD = tempReg; - - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - /* Check int enable bits in base->FIFO */ - base->FIFO = (base->FIFO & ~(LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) | - (mask & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK)); - /* Clear bit 9 and bit 8 from mask */ - mask &= ~((uint32_t)kLPUART_TxFifoOverflowInterruptEnable | (uint32_t)kLPUART_RxFifoUnderflowInterruptEnable); - #endif - - /* Check int enable bits in base->CTRL */ - base->CTRL |= mask; -} - -/*! - * brief Disables LPUART interrupts according to a provided mask. - * - * This function disables the LPUART interrupts according to a provided mask. The mask - * is a logical OR of enumeration members. See ref _lpuart_interrupt_enable. - * This example shows how to disable the TX empty interrupt and RX full interrupt: - * code - * LPUART_DisableInterrupts(LPUART1,kLPUART_TxDataRegEmptyInterruptEnable | kLPUART_RxDataRegFullInterruptEnable); - * endcode - * - * param base LPUART peripheral base address. - * param mask The interrupts to disable. Logical OR of ref _lpuart_interrupt_enable. - */ -void LPUART_DisableInterrupts(LPUART_Type *base, uint32_t mask) { - /* Only consider the real interrupt enable bits. */ - mask &= (uint32_t)kLPUART_AllInterruptEnable; - /* Check int enable bits in base->BAUD */ - uint32_t tempReg = base->BAUD; - #if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT - tempReg &= ~((mask << 8U) & LPUART_BAUD_LBKDIE_MASK); - /* Clear bit 7 from mask */ - mask &= ~(uint32_t)kLPUART_LinBreakInterruptEnable; - #endif - tempReg &= ~((mask << 8U) & LPUART_BAUD_RXEDGIE_MASK); - /* Clear bit 6 from mask */ - mask &= ~(uint32_t)kLPUART_RxActiveEdgeInterruptEnable; - base->BAUD = tempReg; - - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - /* Check int enable bits in base->FIFO */ - base->FIFO = (base->FIFO & ~(LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) & - ~(mask & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK)); - /* Clear bit 9 and bit 8 from mask */ - mask &= ~((uint32_t)kLPUART_TxFifoOverflowInterruptEnable | (uint32_t)kLPUART_RxFifoUnderflowInterruptEnable); - #endif - - /* Check int enable bits in base->CTRL */ - base->CTRL &= ~mask; -} - -/*! - * brief Gets enabled LPUART interrupts. - * - * This function gets the enabled LPUART interrupts. The enabled interrupts are returned - * as the logical OR value of the enumerators ref _lpuart_interrupt_enable. To check - * a specific interrupt enable status, compare the return value with enumerators - * in ref _lpuart_interrupt_enable. - * For example, to check whether the TX empty interrupt is enabled: - * code - * uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(LPUART1); - * - * if (kLPUART_TxDataRegEmptyInterruptEnable & enabledInterrupts) - * { - * ... - * } - * endcode - * - * param base LPUART peripheral base address. - * return LPUART interrupt flags which are logical OR of the enumerators in ref _lpuart_interrupt_enable. - */ -uint32_t LPUART_GetEnabledInterrupts(LPUART_Type *base) { - /* Check int enable bits in base->CTRL */ - uint32_t temp = (uint32_t)(base->CTRL & (uint32_t)kLPUART_AllInterruptEnable); - - /* Check int enable bits in base->BAUD */ - temp = (temp & ~(uint32_t)kLPUART_RxActiveEdgeInterruptEnable) | ((base->BAUD & LPUART_BAUD_RXEDGIE_MASK) >> 8U); - #if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT - temp = (temp & ~(uint32_t)kLPUART_LinBreakInterruptEnable) | ((base->BAUD & LPUART_BAUD_LBKDIE_MASK) >> 8U); - #endif - - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - /* Check int enable bits in base->FIFO */ - temp = - (temp & ~((uint32_t)kLPUART_TxFifoOverflowInterruptEnable | (uint32_t)kLPUART_RxFifoUnderflowInterruptEnable)) | - (base->FIFO & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK)); - #endif - - return temp; -} - -/*! - * brief Gets LPUART status flags. - * - * This function gets all LPUART status flags. The flags are returned as the logical - * OR value of the enumerators ref _lpuart_flags. To check for a specific status, - * compare the return value with enumerators in the ref _lpuart_flags. - * For example, to check whether the TX is empty: - * code - * if (kLPUART_TxDataRegEmptyFlag & LPUART_GetStatusFlags(LPUART1)) - * { - * ... - * } - * endcode - * - * param base LPUART peripheral base address. - * return LPUART status flags which are ORed by the enumerators in the _lpuart_flags. - */ -uint32_t LPUART_GetStatusFlags(LPUART_Type *base) { - uint32_t temp; - temp = base->STAT; - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - temp |= (base->FIFO & - (LPUART_FIFO_TXEMPT_MASK | LPUART_FIFO_RXEMPT_MASK | LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) >> - 16U; - #endif - /* Only keeps the status bits */ - temp &= (uint32_t)kLPUART_AllFlags; - return temp; -} - -/*! - * brief Clears status flags with a provided mask. - * - * This function clears LPUART status flags with a provided mask. Automatically cleared flags - * can't be cleared by this function. - * Flags that can only cleared or set by hardware are: - * kLPUART_TxDataRegEmptyFlag, kLPUART_TransmissionCompleteFlag, kLPUART_RxDataRegFullFlag, - * kLPUART_RxActiveFlag, kLPUART_NoiseErrorInRxDataRegFlag, kLPUART_ParityErrorInRxDataRegFlag, - * kLPUART_TxFifoEmptyFlag,kLPUART_RxFifoEmptyFlag - * Note: This API should be called when the Tx/Rx is idle, otherwise it takes no effects. - * - * param base LPUART peripheral base address. - * param mask the status flags to be cleared. The user can use the enumerators in the - * _lpuart_status_flag_t to do the OR operation and get the mask. - * return 0 succeed, others failed. - * retval kStatus_LPUART_FlagCannotClearManually The flag can't be cleared by this function but - * it is cleared automatically by hardware. - * retval kStatus_Success Status in the mask are cleared. - */ -status_t LPUART_ClearStatusFlags(LPUART_Type *base, uint32_t mask) { - uint32_t temp; - status_t status; - - /* Only deal with the clearable flags */ - mask &= (uint32_t)kLPUART_AllClearFlags; - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - /* Status bits in FIFO register */ - if ((mask & ((uint32_t)kLPUART_TxFifoOverflowFlag | (uint32_t)kLPUART_RxFifoUnderflowFlag)) != 0U) { - /* Get the FIFO register value and mask the rx/tx FIFO flush bits and the status bits that can be W1C in case - they are written 1 accidentally. */ - temp = (uint32_t)base->FIFO; - temp &= (uint32_t)( - ~(LPUART_FIFO_TXFLUSH_MASK | LPUART_FIFO_RXFLUSH_MASK | LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)); - temp |= (mask << 16U) & (LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK); - base->FIFO = temp; - } - #endif - /* Status bits in STAT register */ - /* First get the STAT register value and mask all the bits that not represent status, then OR with the status bit - * that is to be W1C */ - temp = (base->STAT & 0x3E000000UL) | mask; - base->STAT = temp; - /* If some flags still pending. */ - if (0U != (mask & LPUART_GetStatusFlags(base))) { - status = kStatus_LPUART_FlagCannotClearManually; - } else { - status = kStatus_Success; - } - - return status; -} - -/*! - * brief Writes to the transmitter register using a blocking method. - * - * This function polls the transmitter register, first waits for the register to be empty or TX FIFO to have room, - * and writes data to the transmitter buffer, then waits for the data to be sent out to bus. - * - * param base LPUART peripheral base address. - * param data Start address of the data to write. - * param length Size of the data to write. - * retval kStatus_LPUART_Timeout Transmission timed out and was aborted. - * retval kStatus_Success Successfully wrote all data. - */ -status_t LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length) { - assert(NULL != data); - - const uint8_t *dataAddress = data; - size_t transferSize = length; - - #if UART_RETRY_TIMES - uint32_t waitTimes; - #endif - - while (0U != transferSize) { - #if UART_RETRY_TIMES - waitTimes = UART_RETRY_TIMES; - while ((0U == (base->STAT & LPUART_STAT_TDRE_MASK)) && (0U != --waitTimes)) - #else - while (0U == (base->STAT & LPUART_STAT_TDRE_MASK)) - #endif - { - } - #if UART_RETRY_TIMES - if (0U == waitTimes) { - return kStatus_LPUART_Timeout; - } - #endif - base->DATA = *(dataAddress); - dataAddress++; - transferSize--; - } - /* Ensure all the data in the transmit buffer are sent out to bus. */ - #if UART_RETRY_TIMES - waitTimes = UART_RETRY_TIMES; - while ((0U == (base->STAT & LPUART_STAT_TC_MASK)) && (0U != --waitTimes)) - #else - while (0U == (base->STAT & LPUART_STAT_TC_MASK)) - #endif - { - } - #if UART_RETRY_TIMES - if (0U == waitTimes) { - return kStatus_LPUART_Timeout; - } - #endif - return kStatus_Success; -} - -/*! - * brief Reads the receiver data register using a blocking method. - * - * This function polls the receiver register, waits for the receiver register full or receiver FIFO - * has data, and reads data from the TX register. - * - * param base LPUART peripheral base address. - * param data Start address of the buffer to store the received data. - * param length Size of the buffer. - * retval kStatus_LPUART_RxHardwareOverrun Receiver overrun happened while receiving data. - * retval kStatus_LPUART_NoiseError Noise error happened while receiving data. - * retval kStatus_LPUART_FramingError Framing error happened while receiving data. - * retval kStatus_LPUART_ParityError Parity error happened while receiving data. - * retval kStatus_LPUART_Timeout Transmission timed out and was aborted. - * retval kStatus_Success Successfully received all data. - */ -status_t LPUART_ReadBlocking(LPUART_Type *base, uint8_t *data, size_t length) { - assert(NULL != data); - - status_t status = kStatus_Success; - uint32_t statusFlag; - uint8_t *dataAddress = data; - - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - uint32_t ctrl = base->CTRL; - bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) || - (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U))); - #endif - - #if UART_RETRY_TIMES - uint32_t waitTimes; - #endif - - while (0U != (length--)) { - #if UART_RETRY_TIMES - waitTimes = UART_RETRY_TIMES; - #endif - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - while (0U == ((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT)) - #else - while (0U == (base->STAT & LPUART_STAT_RDRF_MASK)) - #endif - { - #if UART_RETRY_TIMES - if (0U == --waitTimes) { - status = kStatus_LPUART_Timeout; - break; - } - #endif - statusFlag = LPUART_GetStatusFlags(base); - - if (0U != (statusFlag & (uint32_t)kLPUART_RxOverrunFlag)) { - status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_RxOverrunFlag)) ? - (kStatus_LPUART_RxHardwareOverrun) : - (kStatus_LPUART_FlagCannotClearManually)); - /* Other error flags(FE, NF, and PF) are prevented from setting once OR is set, no need to check other - * error flags*/ - break; - } - - if (0U != (statusFlag & (uint32_t)kLPUART_ParityErrorFlag)) { - status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_ParityErrorFlag)) ? - (kStatus_LPUART_ParityError) : - (kStatus_LPUART_FlagCannotClearManually)); - } - - if (0U != (statusFlag & (uint32_t)kLPUART_FramingErrorFlag)) { - status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_FramingErrorFlag)) ? - (kStatus_LPUART_FramingError) : - (kStatus_LPUART_FlagCannotClearManually)); - } - - if (0U != (statusFlag & (uint32_t)kLPUART_NoiseErrorFlag)) { - status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_NoiseErrorFlag)) ? - (kStatus_LPUART_NoiseError) : - (kStatus_LPUART_FlagCannotClearManually)); - } - if (kStatus_Success != status) { - break; - } - } - - if (kStatus_Success == status) { - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - if (isSevenDataBits) { - *(dataAddress) = (uint8_t)(base->DATA & 0x7FU); - dataAddress++; - } else { - *(dataAddress) = (uint8_t)base->DATA; - dataAddress++; - } - #else - *(dataAddress) = (uint8_t)base->DATA; - dataAddress++; - #endif - } else { - break; - } - } - - return status; -} - -/*! - * brief Initializes the LPUART handle. - * - * This function initializes the LPUART handle, which can be used for other LPUART - * transactional APIs. Usually, for a specified LPUART instance, - * call this API once to get the initialized handle. - * - * The LPUART driver supports the "background" receiving, which means that user can set up - * an RX ring buffer optionally. Data received is stored into the ring buffer even when the - * user doesn't call the LPUART_TransferReceiveNonBlocking() API. If there is already data received - * in the ring buffer, the user can get the received data from the ring buffer directly. - * The ring buffer is disabled if passing NULL as p ringBuffer. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - * param callback Callback function. - * param userData User data. - */ -void LPUART_TransferCreateHandle(LPUART_Type *base, - lpuart_handle_t *handle, - lpuart_transfer_callback_t callback, - void *userData) { - assert(NULL != handle); - - uint32_t instance; - - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - uint32_t ctrl = base->CTRL; - bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) || - (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U))); - #endif - - /* Zero the handle. */ - (void)memset(handle, 0, sizeof(lpuart_handle_t)); - - /* Set the TX/RX state. */ - handle->rxState = (uint8_t)kLPUART_RxIdle; - handle->txState = (uint8_t)kLPUART_TxIdle; - - /* Set the callback and user data. */ - handle->callback = callback; - handle->userData = userData; - - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - /* Initial seven data bits flag */ - handle->isSevenDataBits = isSevenDataBits; - #endif - - /* Get instance from peripheral base address. */ - instance = LPUART_GetInstance(base); - - /* Save the handle in global variables to support the double weak mechanism. */ - s_lpuartHandle[instance] = handle; - - s_lpuartIsr = LPUART_TransferHandleIRQ; - -/* Enable interrupt in NVIC. */ - #if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ - (void)EnableIRQ(s_lpuartRxIRQ[instance]); - (void)EnableIRQ(s_lpuartTxIRQ[instance]); - #else - (void)EnableIRQ(s_lpuartIRQ[instance]); - #endif -} - -/*! - * brief Sets up the RX ring buffer. - * - * This function sets up the RX ring buffer to a specific UART handle. - * - * When the RX ring buffer is used, data received is stored into the ring buffer even when - * the user doesn't call the UART_TransferReceiveNonBlocking() API. If there is already data received - * in the ring buffer, the user can get the received data from the ring buffer directly. - * - * note When using RX ring buffer, one byte is reserved for internal use. In other - * words, if p ringBufferSize is 32, then only 31 bytes are used for saving data. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - * param ringBuffer Start address of ring buffer for background receiving. Pass NULL to disable the ring buffer. - * param ringBufferSize size of the ring buffer. - */ -void LPUART_TransferStartRingBuffer(LPUART_Type *base, - lpuart_handle_t *handle, - uint8_t *ringBuffer, - size_t ringBufferSize) { - assert(NULL != handle); - assert(NULL != ringBuffer); - - /* Setup the ring buffer address */ - handle->rxRingBuffer = ringBuffer; - handle->rxRingBufferSize = ringBufferSize; - handle->rxRingBufferHead = 0U; - handle->rxRingBufferTail = 0U; - - /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte. */ - uint32_t irqMask = DisableGlobalIRQ(); - /* Enable the interrupt to accept the data when user need the ring buffer. */ - base->CTRL |= (uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK); - EnableGlobalIRQ(irqMask); -} - -/*! - * brief Aborts the background transfer and uninstalls the ring buffer. - * - * This function aborts the background transfer and uninstalls the ring buffer. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - */ -void LPUART_TransferStopRingBuffer(LPUART_Type *base, lpuart_handle_t *handle) { - assert(NULL != handle); - - if (handle->rxState == (uint8_t)kLPUART_RxIdle) { - /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte. - */ - uint32_t irqMask = DisableGlobalIRQ(); - base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK); - EnableGlobalIRQ(irqMask); - } - - handle->rxRingBuffer = NULL; - handle->rxRingBufferSize = 0U; - handle->rxRingBufferHead = 0U; - handle->rxRingBufferTail = 0U; -} - -/*! - * brief Transmits a buffer of data using the interrupt method. - * - * This function send data using an interrupt method. This is a non-blocking function, which - * returns directly without waiting for all data written to the transmitter register. When - * all data is written to the TX register in the ISR, the LPUART driver calls the callback - * function and passes the ref kStatus_LPUART_TxIdle as status parameter. - * - * note The kStatus_LPUART_TxIdle is passed to the upper layer when all data are written - * to the TX register. However, there is no check to ensure that all the data sent out. Before disabling the TX, - * check the kLPUART_TransmissionCompleteFlag to ensure that the transmit is finished. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - * param xfer LPUART transfer structure, see #lpuart_transfer_t. - * retval kStatus_Success Successfully start the data transmission. - * retval kStatus_LPUART_TxBusy Previous transmission still not finished, data not all written to the TX register. - * retval kStatus_InvalidArgument Invalid argument. - */ -status_t LPUART_TransferSendNonBlocking(LPUART_Type *base, lpuart_handle_t *handle, lpuart_transfer_t *xfer) { - assert(NULL != handle); - assert(NULL != xfer); - assert(NULL != xfer->txData); - assert(0U != xfer->dataSize); - - status_t status; - - /* Return error if current TX busy. */ - if ((uint8_t)kLPUART_TxBusy == handle->txState) { - status = kStatus_LPUART_TxBusy; - } else { - handle->txData = xfer->txData; - handle->txDataSize = xfer->dataSize; - handle->txDataSizeAll = xfer->dataSize; - handle->txState = (uint8_t)kLPUART_TxBusy; - - /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte. - */ - uint32_t irqMask = DisableGlobalIRQ(); - /* Enable transmitter interrupt. */ - base->CTRL |= (uint32_t)LPUART_CTRL_TIE_MASK; - EnableGlobalIRQ(irqMask); - - status = kStatus_Success; - } - - return status; -} - -/*! - * brief Aborts the interrupt-driven data transmit. - * - * This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out - * how many bytes are not sent out. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - */ -void LPUART_TransferAbortSend(LPUART_Type *base, lpuart_handle_t *handle) { - assert(NULL != handle); - - /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte. */ - uint32_t irqMask = DisableGlobalIRQ(); - base->CTRL &= ~(uint32_t)(LPUART_CTRL_TIE_MASK | LPUART_CTRL_TCIE_MASK); - EnableGlobalIRQ(irqMask); - - handle->txDataSize = 0; - handle->txState = (uint8_t)kLPUART_TxIdle; -} - -/*! - * brief Gets the number of bytes that have been sent out to bus. - * - * This function gets the number of bytes that have been sent out to bus by an interrupt method. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - * param count Send bytes count. - * retval kStatus_NoTransferInProgress No send in progress. - * retval kStatus_InvalidArgument Parameter is invalid. - * retval kStatus_Success Get successfully through the parameter \p count; - */ -status_t LPUART_TransferGetSendCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count) { - assert(NULL != handle); - assert(NULL != count); - - status_t status = kStatus_Success; - size_t tmptxDataSize = handle->txDataSize; - - if ((uint8_t)kLPUART_TxIdle == handle->txState) { - status = kStatus_NoTransferInProgress; - } else { - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - *count = handle->txDataSizeAll - tmptxDataSize - - ((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXCOUNT_SHIFT); - #else - if ((base->STAT & (uint32_t)kLPUART_TxDataRegEmptyFlag) != 0U) { - *count = handle->txDataSizeAll - tmptxDataSize; - } else { - *count = handle->txDataSizeAll - tmptxDataSize - 1U; - } - #endif - } - - return status; -} - -/*! - * brief Receives a buffer of data using the interrupt method. - * - * This function receives data using an interrupt method. This is a non-blocking function - * which returns without waiting to ensure that all data are received. - * If the RX ring buffer is used and not empty, the data in the ring buffer is copied and - * the parameter p receivedBytes shows how many bytes are copied from the ring buffer. - * After copying, if the data in the ring buffer is not enough for read, the receive - * request is saved by the LPUART driver. When the new data arrives, the receive request - * is serviced first. When all data is received, the LPUART driver notifies the upper layer - * through a callback function and passes a status parameter ref kStatus_UART_RxIdle. - * For example, the upper layer needs 10 bytes but there are only 5 bytes in ring buffer. - * The 5 bytes are copied to xfer->data, which returns with the - * parameter p receivedBytes set to 5. For the remaining 5 bytes, the newly arrived data is - * saved from xfer->data[5]. When 5 bytes are received, the LPUART driver notifies the upper layer. - * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt - * to receive data to xfer->data. When all data is received, the upper layer is notified. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - * param xfer LPUART transfer structure, see #uart_transfer_t. - * param receivedBytes Bytes received from the ring buffer directly. - * retval kStatus_Success Successfully queue the transfer into the transmit queue. - * retval kStatus_LPUART_RxBusy Previous receive request is not finished. - * retval kStatus_InvalidArgument Invalid argument. - */ -status_t LPUART_TransferReceiveNonBlocking(LPUART_Type *base, - lpuart_handle_t *handle, - lpuart_transfer_t *xfer, - size_t *receivedBytes) { - assert(NULL != handle); - assert(NULL != xfer); - assert(NULL != xfer->rxData); - assert(0U != xfer->dataSize); - - uint32_t i; - status_t status; - uint32_t irqMask; - /* How many bytes to copy from ring buffer to user memory. */ - size_t bytesToCopy = 0U; - /* How many bytes to receive. */ - size_t bytesToReceive; - /* How many bytes currently have received. */ - size_t bytesCurrentReceived; - - /* How to get data: - 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize - to lpuart handle, enable interrupt to store received data to xfer->data. When - all data received, trigger callback. - 2. If RX ring buffer is enabled and not empty, get data from ring buffer first. - If there are enough data in ring buffer, copy them to xfer->data and return. - If there are not enough data in ring buffer, copy all of them to xfer->data, - save the xfer->data remained empty space to lpuart handle, receive data - to this empty space and trigger callback when finished. */ - - if ((uint8_t)kLPUART_RxBusy == handle->rxState) { - status = kStatus_LPUART_RxBusy; - } else { - bytesToReceive = xfer->dataSize; - bytesCurrentReceived = 0; - - /* If RX ring buffer is used. */ - if (NULL != handle->rxRingBuffer) { - /* Disable and re-enable the global interrupt to protect the interrupt enable register during - * read-modify-wrte. */ - irqMask = DisableGlobalIRQ(); - /* Disable LPUART RX IRQ, protect ring buffer. */ - base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK); - EnableGlobalIRQ(irqMask); - - /* How many bytes in RX ring buffer currently. */ - bytesToCopy = LPUART_TransferGetRxRingBufferLength(base, handle); - - if (0U != bytesToCopy) { - bytesToCopy = MIN(bytesToReceive, bytesToCopy); - - bytesToReceive -= bytesToCopy; - - /* Copy data from ring buffer to user memory. */ - for (i = 0U; i < bytesToCopy; i++) { - xfer->rxData[bytesCurrentReceived] = handle->rxRingBuffer[handle->rxRingBufferTail]; - bytesCurrentReceived++; - - /* Wrap to 0. Not use modulo (%) because it might be large and slow. */ - if (((uint32_t)handle->rxRingBufferTail + 1U) == handle->rxRingBufferSize) { - handle->rxRingBufferTail = 0U; - } else { - handle->rxRingBufferTail++; - } - } - } - - /* If ring buffer does not have enough data, still need to read more data. */ - if (0U != bytesToReceive) { - /* No data in ring buffer, save the request to LPUART handle. */ - handle->rxData = &xfer->rxData[bytesCurrentReceived]; - handle->rxDataSize = bytesToReceive; - handle->rxDataSizeAll = xfer->dataSize; - handle->rxState = (uint8_t)kLPUART_RxBusy; - } - - /* Disable and re-enable the global interrupt to protect the interrupt enable register during - * read-modify-wrte. */ - irqMask = DisableGlobalIRQ(); - /* Re-enable LPUART RX IRQ. */ - base->CTRL |= (uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK); - EnableGlobalIRQ(irqMask); - - /* Call user callback since all data are received. */ - if (0U == bytesToReceive) { - if (NULL != handle->callback) { - handle->callback(base, handle, kStatus_LPUART_RxIdle, handle->userData); - } - } - } - /* Ring buffer not used. */ - else { - handle->rxData = &xfer->rxData[bytesCurrentReceived]; - handle->rxDataSize = bytesToReceive; - handle->rxDataSizeAll = bytesToReceive; - handle->rxState = (uint8_t)kLPUART_RxBusy; - - /* Disable and re-enable the global interrupt to protect the interrupt enable register during - * read-modify-wrte. */ - irqMask = DisableGlobalIRQ(); - /* Enable RX interrupt. */ - base->CTRL |= (uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ILIE_MASK | LPUART_CTRL_ORIE_MASK); - EnableGlobalIRQ(irqMask); - } - - /* Return the how many bytes have read. */ - if (NULL != receivedBytes) { - *receivedBytes = bytesCurrentReceived; - } - - status = kStatus_Success; - } - - return status; -} - -/*! - * brief Aborts the interrupt-driven data receiving. - * - * This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out - * how many bytes not received yet. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - */ -void LPUART_TransferAbortReceive(LPUART_Type *base, lpuart_handle_t *handle) { - assert(NULL != handle); - - /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */ - if (NULL == handle->rxRingBuffer) { - /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte. - */ - uint32_t irqMask = DisableGlobalIRQ(); - /* Disable RX interrupt. */ - base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ILIE_MASK | LPUART_CTRL_ORIE_MASK); - EnableGlobalIRQ(irqMask); - } - - handle->rxDataSize = 0U; - handle->rxState = (uint8_t)kLPUART_RxIdle; -} - -/*! - * brief Gets the number of bytes that have been received. - * - * This function gets the number of bytes that have been received. - * - * param base LPUART peripheral base address. - * param handle LPUART handle pointer. - * param count Receive bytes count. - * retval kStatus_NoTransferInProgress No receive in progress. - * retval kStatus_InvalidArgument Parameter is invalid. - * retval kStatus_Success Get successfully through the parameter \p count; - */ -status_t LPUART_TransferGetReceiveCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count) { - assert(NULL != handle); - assert(NULL != count); - - status_t status = kStatus_Success; - size_t tmprxDataSize = handle->rxDataSize; - - if ((uint8_t)kLPUART_RxIdle == handle->rxState) { - status = kStatus_NoTransferInProgress; - } else { - *count = handle->rxDataSizeAll - tmprxDataSize; - } - - return status; -} - -/*! - * brief LPUART IRQ handle function. - * - * This function handles the LPUART transmit and receive IRQ request. - * - * param base LPUART peripheral base address. - * param irqHandle LPUART handle pointer. - */ -void LPUART_TransferHandleIRQ(LPUART_Type *base, void *irqHandle) { - assert(NULL != irqHandle); - - uint8_t count; - uint8_t tempCount; - uint32_t status = LPUART_GetStatusFlags(base); - uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(base); - uint16_t tpmRxRingBufferHead; - uint32_t tpmData; - uint32_t irqMask; - lpuart_handle_t *handle = (lpuart_handle_t *)irqHandle; - - /* If RX overrun. */ - if ((uint32_t)kLPUART_RxOverrunFlag == ((uint32_t)kLPUART_RxOverrunFlag & status)) { - /* Clear overrun flag, otherwise the RX does not work. */ - base->STAT = ((base->STAT & 0x3FE00000U) | LPUART_STAT_OR_MASK); - - /* Trigger callback. */ - if (NULL != (handle->callback)) { - handle->callback(base, handle, kStatus_LPUART_RxHardwareOverrun, handle->userData); - } - } - /* Receive data register full */ - if ((0U != ((uint32_t)kLPUART_RxDataRegFullFlag & status)) && - (0U != ((uint32_t)kLPUART_RxDataRegFullInterruptEnable & enabledInterrupts))) { - /* Get the size that can be stored into buffer for this interrupt. */ - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - count = ((uint8_t)((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT)); - #else - count = 1; - #endif - - /* If handle->rxDataSize is not 0, first save data to handle->rxData. */ - while ((0U != handle->rxDataSize) && (0U != count)) { - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - tempCount = (uint8_t)MIN(handle->rxDataSize, count); - #else - tempCount = 1; - #endif - - /* Using non block API to read the data from the registers. */ - LPUART_ReadNonBlocking(base, handle->rxData, tempCount); - handle->rxData = &handle->rxData[tempCount]; - handle->rxDataSize -= tempCount; - count -= tempCount; - - /* If all the data required for upper layer is ready, trigger callback. */ - if (0U == handle->rxDataSize) { - handle->rxState = (uint8_t)kLPUART_RxIdle; - - if (NULL != handle->callback) { - handle->callback(base, handle, kStatus_LPUART_RxIdle, handle->userData); - } - } - } - - /* If use RX ring buffer, receive data to ring buffer. */ - if (NULL != handle->rxRingBuffer) { - while (0U != count--) { - /* If RX ring buffer is full, trigger callback to notify over run. */ - if (LPUART_TransferIsRxRingBufferFull(base, handle)) { - if (NULL != handle->callback) { - handle->callback(base, handle, kStatus_LPUART_RxRingBufferOverrun, handle->userData); - } - } - - /* If ring buffer is still full after callback function, the oldest data is overridden. */ - if (LPUART_TransferIsRxRingBufferFull(base, handle)) { - /* Increase handle->rxRingBufferTail to make room for new data. */ - if (((uint32_t)handle->rxRingBufferTail + 1U) == handle->rxRingBufferSize) { - handle->rxRingBufferTail = 0U; - } else { - handle->rxRingBufferTail++; - } - } - - /* Read data. */ - tpmRxRingBufferHead = handle->rxRingBufferHead; - tpmData = base->DATA; - #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT - if (handle->isSevenDataBits) { - handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)(tpmData & 0x7FU); - } else { - handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)tpmData; - } - #else - handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)tpmData; - #endif - - /* Increase handle->rxRingBufferHead. */ - if (((uint32_t)handle->rxRingBufferHead + 1U) == handle->rxRingBufferSize) { - handle->rxRingBufferHead = 0U; - } else { - handle->rxRingBufferHead++; - } - } - } - /* If no receive request pending, stop RX interrupt. */ - else if (0U == handle->rxDataSize) { - /* Disable and re-enable the global interrupt to protect the interrupt enable register during - * read-modify-wrte. */ - irqMask = DisableGlobalIRQ(); - base->CTRL &= ~(uint32_t)(LPUART_CTRL_RIE_MASK | LPUART_CTRL_ORIE_MASK | LPUART_CTRL_ILIE_MASK); - EnableGlobalIRQ(irqMask); - } else { - } - } - - /* Send data register empty and the interrupt is enabled. */ - if ((0U != ((uint32_t)kLPUART_TxDataRegEmptyFlag & status)) && - (0U != ((uint32_t)kLPUART_TxDataRegEmptyInterruptEnable & enabledInterrupts))) { -/* Get the bytes that available at this moment. */ - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - count = (uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) - - (uint8_t)((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXCOUNT_SHIFT); - #else - count = 1; - #endif - - while ((0U != handle->txDataSize) && (0U != count)) { - #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO - tempCount = (uint8_t)MIN(handle->txDataSize, count); - #else - tempCount = 1; - #endif - - /* Using non block API to write the data to the registers. */ - LPUART_WriteNonBlocking(base, handle->txData, tempCount); - handle->txData = &handle->txData[tempCount]; - handle->txDataSize -= tempCount; - count -= tempCount; - - /* If all the data are written to data register, notify user with the callback, then TX finished. */ - if (0U == handle->txDataSize) { - /* Disable and re-enable the global interrupt to protect the interrupt enable register during - * read-modify-wrte. */ - irqMask = DisableGlobalIRQ(); - /* Disable TX register empty interrupt and enable transmission completion interrupt. */ - base->CTRL = (base->CTRL & ~LPUART_CTRL_TIE_MASK) | LPUART_CTRL_TCIE_MASK; - EnableGlobalIRQ(irqMask); - } - } - } - - /* Transmission complete and the interrupt is enabled. */ - if ((0U != ((uint32_t)kLPUART_TransmissionCompleteFlag & status)) && - (0U != ((uint32_t)kLPUART_TransmissionCompleteInterruptEnable & enabledInterrupts))) { - /* Set txState to idle only when all data has been sent out to bus. */ - handle->txState = (uint8_t)kLPUART_TxIdle; - - /* Disable and re-enable the global interrupt to protect the interrupt enable register during read-modify-wrte. - */ - irqMask = DisableGlobalIRQ(); - /* Disable transmission complete interrupt. */ - base->CTRL &= ~(uint32_t)LPUART_CTRL_TCIE_MASK; - EnableGlobalIRQ(irqMask); - - /* Trigger callback. */ - if (NULL != handle->callback) { - handle->callback(base, handle, kStatus_LPUART_TxIdle, handle->userData); - } - } - - /* If IDLE flag is set and the IDLE interrupt is enabled. */ - if ((0U != ((uint32_t)kLPUART_IdleLineFlag & status)) && - (0U != ((uint32_t)kLPUART_IdleLineInterruptEnable & enabledInterrupts))) { - /* Clear IDLE flag.*/ - base->STAT |= LPUART_STAT_IDLE_MASK; - if (NULL != handle->callback) { - handle->callback(base, handle, kStatus_LPUART_IdleLineDetected, handle->userData); - } else { - /* Avoid MISRA 15.7 */ - } - } - -} - -/*! - * brief LPUART Error IRQ handle function. - * - * This function handles the LPUART error IRQ request. - * - * param base LPUART peripheral base address. - * param irqHandle LPUART handle pointer. - */ -void LPUART_TransferHandleErrorIRQ(LPUART_Type *base, void *irqHandle) { - /* To be implemented by User. */ -} -#if defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1 -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART0_LPUART1_RX_DriverIRQHandler(void); -void LPUART0_LPUART1_RX_DriverIRQHandler(void) { - /* If handle is registered, treat the transfer function is enabled. */ - if (NULL != s_lpuartHandle[0]) { - s_lpuartIsr(LPUART0, s_lpuartHandle[0]); - } - if (NULL != s_lpuartHandle[1]) { - s_lpuartIsr(LPUART1, s_lpuartHandle[1]); - } - SDK_ISR_EXIT_BARRIER; -} -void LPUART0_LPUART1_TX_DriverIRQHandler(void); -void LPUART0_LPUART1_TX_DriverIRQHandler(void) { - /* If handle is registered, treat the transfer function is enabled. */ - if (NULL != s_lpuartHandle[0]) { - s_lpuartIsr(LPUART0, s_lpuartHandle[0]); - } - if (NULL != s_lpuartHandle[1]) { - s_lpuartIsr(LPUART1, s_lpuartHandle[1]); - } - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART0_LPUART1_DriverIRQHandler(void); -void LPUART0_LPUART1_DriverIRQHandler(void) { - /* If handle is registered, treat the transfer function is enabled. */ - if (NULL != s_lpuartHandle[0]) { - s_lpuartIsr(LPUART0, s_lpuartHandle[0]); - } - if (NULL != s_lpuartHandle[1]) { - s_lpuartIsr(LPUART1, s_lpuartHandle[1]); - } - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART0) -#if !(defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART0_TX_DriverIRQHandler(void); -void LPUART0_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART0, s_lpuartHandle[0]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART0_RX_DriverIRQHandler(void); -void LPUART0_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART0, s_lpuartHandle[0]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART0_DriverIRQHandler(void); -void LPUART0_DriverIRQHandler(void) { - s_lpuartIsr(LPUART0, s_lpuartHandle[0]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif -#endif - -#if defined(LPUART1) -#if !(defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART1_TX_DriverIRQHandler(void); -void LPUART1_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART1, s_lpuartHandle[1]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART1_RX_DriverIRQHandler(void); -void LPUART1_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART1, s_lpuartHandle[1]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART1_DriverIRQHandler(void); -void LPUART1_DriverIRQHandler(void) { - s_lpuartIsr(LPUART1, s_lpuartHandle[1]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif -#endif - -#if defined(LPUART2) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART2_TX_DriverIRQHandler(void); -void LPUART2_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART2, s_lpuartHandle[2]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART2_RX_DriverIRQHandler(void); -void LPUART2_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART2, s_lpuartHandle[2]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART2_DriverIRQHandler(void); -void LPUART2_DriverIRQHandler(void) { - s_lpuartIsr(LPUART2, s_lpuartHandle[2]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART3) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART3_TX_DriverIRQHandler(void); -void LPUART3_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART3, s_lpuartHandle[3]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART3_RX_DriverIRQHandler(void); -void LPUART3_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART3, s_lpuartHandle[3]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART3_DriverIRQHandler(void); -void LPUART3_DriverIRQHandler(void) { - s_lpuartIsr(LPUART3, s_lpuartHandle[3]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART4) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART4_TX_DriverIRQHandler(void); -void LPUART4_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART4, s_lpuartHandle[4]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART4_RX_DriverIRQHandler(void); -void LPUART4_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART4, s_lpuartHandle[4]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART4_DriverIRQHandler(void); -void LPUART4_DriverIRQHandler(void) { - s_lpuartIsr(LPUART4, s_lpuartHandle[4]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART5) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART5_TX_DriverIRQHandler(void); -void LPUART5_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART5, s_lpuartHandle[5]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART5_RX_DriverIRQHandler(void); -void LPUART5_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART5, s_lpuartHandle[5]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART5_DriverIRQHandler(void); -void LPUART5_DriverIRQHandler(void) { - s_lpuartIsr(LPUART5, s_lpuartHandle[5]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART6) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART6_TX_DriverIRQHandler(void); -void LPUART6_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART6, s_lpuartHandle[6]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART6_RX_DriverIRQHandler(void); -void LPUART6_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART6, s_lpuartHandle[6]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART6_DriverIRQHandler(void); -void LPUART6_DriverIRQHandler(void) { - s_lpuartIsr(LPUART6, s_lpuartHandle[6]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART7) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART7_TX_DriverIRQHandler(void); -void LPUART7_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART7, s_lpuartHandle[7]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART7_RX_DriverIRQHandler(void); -void LPUART7_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART7, s_lpuartHandle[7]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART7_DriverIRQHandler(void); -void LPUART7_DriverIRQHandler(void) { - s_lpuartIsr(LPUART7, s_lpuartHandle[7]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART8) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART8_TX_DriverIRQHandler(void); -void LPUART8_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART8, s_lpuartHandle[8]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART8_RX_DriverIRQHandler(void); -void LPUART8_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART8, s_lpuartHandle[8]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART8_DriverIRQHandler(void); -void LPUART8_DriverIRQHandler(void) { - s_lpuartIsr(LPUART8, s_lpuartHandle[8]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART9) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART9_TX_DriverIRQHandler(void); -void LPUART9_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART9, s_lpuartHandle[9]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART9_RX_DriverIRQHandler(void); -void LPUART9_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART9, s_lpuartHandle[9]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART9_DriverIRQHandler(void); -void LPUART9_DriverIRQHandler(void) { - s_lpuartIsr(LPUART9, s_lpuartHandle[9]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART10) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART10_TX_DriverIRQHandler(void); -void LPUART10_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART10, s_lpuartHandle[10]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART10_RX_DriverIRQHandler(void); -void LPUART10_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART10, s_lpuartHandle[10]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART10_DriverIRQHandler(void); -void LPUART10_DriverIRQHandler(void) { - s_lpuartIsr(LPUART10, s_lpuartHandle[10]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(LPUART11) -#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ -void LPUART11_TX_DriverIRQHandler(void); -void LPUART11_TX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART11, s_lpuartHandle[11]); - SDK_ISR_EXIT_BARRIER; -} -void LPUART11_RX_DriverIRQHandler(void); -void LPUART11_RX_DriverIRQHandler(void) { - s_lpuartIsr(LPUART11, s_lpuartHandle[11]); - SDK_ISR_EXIT_BARRIER; -} -#else -void LPUART11_DriverIRQHandler(void); -void LPUART11_DriverIRQHandler(void) { - s_lpuartIsr(LPUART11, s_lpuartHandle[11]); - SDK_ISR_EXIT_BARRIER; -} -#endif -#endif - -#if defined(CM4_0__LPUART) -void M4_0_LPUART_DriverIRQHandler(void); -void M4_0_LPUART_DriverIRQHandler(void) { - s_lpuartIsr(CM4_0__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4_0__LPUART)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(CM4_1__LPUART) -void M4_1_LPUART_DriverIRQHandler(void); -void M4_1_LPUART_DriverIRQHandler(void) { - s_lpuartIsr(CM4_1__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4_1__LPUART)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(CM4__LPUART) -void M4_LPUART_DriverIRQHandler(void); -void M4_LPUART_DriverIRQHandler(void) { - s_lpuartIsr(CM4__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4__LPUART)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(DMA__LPUART0) -void DMA_UART0_INT_DriverIRQHandler(void); -void DMA_UART0_INT_DriverIRQHandler(void) { - s_lpuartIsr(DMA__LPUART0, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART0)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(DMA__LPUART1) -void DMA_UART1_INT_DriverIRQHandler(void); -void DMA_UART1_INT_DriverIRQHandler(void) { - s_lpuartIsr(DMA__LPUART1, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART1)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(DMA__LPUART2) -void DMA_UART2_INT_DriverIRQHandler(void); -void DMA_UART2_INT_DriverIRQHandler(void) { - s_lpuartIsr(DMA__LPUART2, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART2)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(DMA__LPUART3) -void DMA_UART3_INT_DriverIRQHandler(void); -void DMA_UART3_INT_DriverIRQHandler(void) { - s_lpuartIsr(DMA__LPUART3, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART3)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(DMA__LPUART4) -void DMA_UART4_INT_DriverIRQHandler(void); -void DMA_UART4_INT_DriverIRQHandler(void) { - s_lpuartIsr(DMA__LPUART4, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART4)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(ADMA__LPUART0) -void ADMA_UART0_INT_DriverIRQHandler(void); -void ADMA_UART0_INT_DriverIRQHandler(void) { - s_lpuartIsr(ADMA__LPUART0, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART0)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(ADMA__LPUART1) -void ADMA_UART1_INT_DriverIRQHandler(void); -void ADMA_UART1_INT_DriverIRQHandler(void) { - s_lpuartIsr(ADMA__LPUART1, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART1)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(ADMA__LPUART2) -void ADMA_UART2_INT_DriverIRQHandler(void); -void ADMA_UART2_INT_DriverIRQHandler(void) { - s_lpuartIsr(ADMA__LPUART2, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART2)]); - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(ADMA__LPUART3) -void ADMA_UART3_INT_DriverIRQHandler(void); -void ADMA_UART3_INT_DriverIRQHandler(void) { - s_lpuartIsr(ADMA__LPUART3, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART3)]); - SDK_ISR_EXIT_BARRIER; -} -#endif diff --git a/ports/mimxrt/hal/phy/device/phydp83867/fsl_phydp83867.c b/ports/mimxrt/hal/phy/device/phydp83867/fsl_phydp83867.c new file mode 100644 index 0000000000000..87943881d8e72 --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phydp83867/fsl_phydp83867.c @@ -0,0 +1,302 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Andrew Leech + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "fsl_phydp83867.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the PHY DP83867 vendor defined registers. */ +#define PHY_PHYSTS_REG 0x11U /*!< The PHY Status register. */ + +/*! @brief Defines the PHY DP83867 ID number. */ +#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1 (upper 16 bits). */ +#define PHY_CONTROL_ID2 0xA231U /*!< The PHY ID2 (lower 16 bits). */ +#define PHY_FULL_ID 0x2000A231U /*!< Full PHY ID. */ + +/*! @brief Defines the mask flag in PHYSTS register. */ +#define PHY_PHYSTS_LINKSTATUS_MASK 0x0400U /*!< The PHY link status mask. */ +#define PHY_PHYSTS_LINKSPEED_MASK 0xC000U /*!< The PHY link speed mask. */ +#define PHY_PHYSTS_LINKDUPLEX_MASK 0x2000U /*!< The PHY link duplex mask. */ +#define PHY_PHYSTS_LINKSPEED_SHIFT 14U /*!< The link speed shift */ + +/*! @brief Link speed values from PHYSTS register. */ +#define PHY_PHYSTS_LINKSPEED_10M 0U /*!< 10M link speed. */ +#define PHY_PHYSTS_LINKSPEED_100M 1U /*!< 100M link speed. */ +#define PHY_PHYSTS_LINKSPEED_1000M 2U /*!< 1000M link speed. */ + +/*! @brief Defines the timeout macro. */ +#define PHY_READID_TIMEOUT_COUNT 1000U + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +const phy_operations_t phydp83867_ops = {.phyInit = PHY_DP83867_Init, + .phyWrite = PHY_DP83867_Write, + .phyRead = PHY_DP83867_Read, + .getAutoNegoStatus = PHY_DP83867_GetAutoNegotiationStatus, + .getLinkStatus = PHY_DP83867_GetLinkStatus, + .getLinkSpeedDuplex = PHY_DP83867_GetLinkSpeedDuplex, + .setLinkSpeedDuplex = PHY_DP83867_SetLinkSpeedDuplex, + .enableLoopback = PHY_DP83867_EnableLoopback}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_DP83867_Init(phy_handle_t *handle, const phy_config_t *config) { + uint32_t counter = PHY_READID_TIMEOUT_COUNT; + status_t result; + uint32_t regValue = 0U; + + + /* Init MDIO interface. */ + MDIO_Init(handle->mdioHandle); + + /* Assign phy address. */ + handle->phyAddr = config->phyAddr; + + + /* Check PHY ID. */ + do + { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + counter--; + } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U)); + + if (counter == 0U) { + return kStatus_Fail; + } + + + /* Reset PHY. */ + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result != kStatus_Success) { + return result; + } + + + /* Wait for reset to complete */ + counter = PHY_READID_TIMEOUT_COUNT; + do { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + counter--; + } while ((regValue & PHY_BCTL_RESET_MASK) && (counter != 0U)); + + if (counter == 0U) { + return kStatus_Fail; + } + + + if (config->autoNeg) { + /* Set the auto-negotiation. */ + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG, + PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | PHY_10BASETX_FULLDUPLEX_MASK | + PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK); + if (result == kStatus_Success) { + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_1000BASET_CONTROL_REG, + PHY_1000BASET_FULLDUPLEX_MASK); + if (result == kStatus_Success) { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + } + } else { + /* Disable isolate mode */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + regValue &= ~PHY_BCTL_ISOLATE_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) { + return result; + } + + /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */ + result = PHY_DP83867_SetLinkSpeedDuplex(handle, config->speed, config->duplex); + } + + + return result; +} + +status_t PHY_DP83867_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data); +} + +status_t PHY_DP83867_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) { + return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr); +} + +status_t PHY_DP83867_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + *status = false; + + /* Check auto negotiation complete. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) { + *status = true; + } + } + return result; +} + +status_t PHY_DP83867_GetLinkStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + /* Read the PHY Status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, ®Value); + if (result == kStatus_Success) { + if ((PHY_PHYSTS_LINKSTATUS_MASK & regValue) != 0U) { + /* Link up. */ + *status = true; + } else { + /* Link down. */ + *status = false; + } + } + return result; +} + +status_t PHY_DP83867_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) { + assert(!((speed == NULL) && (duplex == NULL))); + + status_t result; + uint32_t regValue; + + /* Read the status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, ®Value); + if (result == kStatus_Success) { + if (speed != NULL) { + switch ((regValue & PHY_PHYSTS_LINKSPEED_MASK) >> PHY_PHYSTS_LINKSPEED_SHIFT) + { + case PHY_PHYSTS_LINKSPEED_10M: + *speed = kPHY_Speed10M; + break; + case PHY_PHYSTS_LINKSPEED_100M: + *speed = kPHY_Speed100M; + break; + case PHY_PHYSTS_LINKSPEED_1000M: + *speed = kPHY_Speed1000M; + break; + default: + *speed = kPHY_Speed10M; + break; + } + } + + if (duplex != NULL) { + if ((regValue & PHY_PHYSTS_LINKDUPLEX_MASK) != 0U) { + *duplex = kPHY_FullDuplex; + } else { + *duplex = kPHY_HalfDuplex; + } + } + } + return result; +} + +status_t PHY_DP83867_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) { + status_t result; + uint32_t regValue; + + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + /* Disable the auto-negotiation and set according to user-defined configuration. */ + regValue &= ~PHY_BCTL_AUTONEG_MASK; + if (speed == kPHY_Speed1000M) { + regValue &= ~PHY_BCTL_SPEED0_MASK; + regValue |= PHY_BCTL_SPEED1_MASK; + } else if (speed == kPHY_Speed100M) { + regValue |= PHY_BCTL_SPEED0_MASK; + regValue &= ~PHY_BCTL_SPEED1_MASK; + } else { + regValue &= ~PHY_BCTL_SPEED0_MASK; + regValue &= ~PHY_BCTL_SPEED1_MASK; + } + if (duplex == kPHY_FullDuplex) { + regValue |= PHY_BCTL_DUPLEX_MASK; + } else { + regValue &= ~PHY_BCTL_DUPLEX_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + return result; +} + +status_t PHY_DP83867_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) { + /* This PHY only supports local loopback. */ + assert(mode == kPHY_LocalLoop); + + status_t result; + uint32_t regValue; + + /* Set the loop mode. */ + if (enable) { + if (speed == kPHY_Speed1000M) { + regValue = PHY_BCTL_SPEED1_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } else if (speed == kPHY_Speed100M) { + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } else { + regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } else { + /* First read the current status in control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + regValue &= ~PHY_BCTL_LOOP_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + return result; +} diff --git a/ports/mimxrt/hal/phy/device/phydp83867/fsl_phydp83867.h b/ports/mimxrt/hal/phy/device/phydp83867/fsl_phydp83867.h new file mode 100644 index 0000000000000..ba0f27daa9a6c --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phydp83867/fsl_phydp83867.h @@ -0,0 +1,165 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Andrew Leech + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _FSL_PHYDP83867_H_ +#define _FSL_PHYDP83867_H_ + +#include "fsl_phy.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY operations structure. */ +extern const phy_operations_t phydp83867_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83867_Init(phy_handle_t *handle, const phy_config_t *config); + +/*! + * @brief PHY Write function. This function writes data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83867_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface reads data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83867_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83867_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY gets link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83867_GetLinkStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address parameter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY gets link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83867_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83867_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY loopback success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83867_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PHYDP83867_H_ */ diff --git a/ports/mimxrt/machine_adc.c b/ports/mimxrt/machine_adc.c index c332bd703128a..1ebfe528612be 100644 --- a/ports/mimxrt/machine_adc.c +++ b/ports/mimxrt/machine_adc.c @@ -64,7 +64,19 @@ static void mp_machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_p // Get ADC adc id for (int i = 1; i < sizeof(adc_bases) / sizeof(ADC_Type *); ++i) { if (adc_bases[i] == self->adc) { - mp_printf(print, "ADC(%u, channel=%u)", i, self->channel); + mp_printf( + print, + "ADC(%u, channel=%u" + #if defined(MIMXRT117x_SERIES) + ", channel_input=%u" + #endif + ")", + i, + self->channel + #if defined(MIMXRT117x_SERIES) + , self->channel_group + #endif + ); break; } } @@ -83,12 +95,13 @@ static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_args // Extract arguments ADC_Type *adc_instance = pin->adc_list[0].instance; // NOTE: we only use the first ADC assignment - multiple assignments are not supported for now uint8_t channel = pin->adc_list[0].channel; + uint8_t channel_group = pin->adc_list[0].channel_group; // Create ADC Instance machine_adc_obj_t *o = mp_obj_malloc(machine_adc_obj_t, &machine_adc_type); o->adc = adc_instance; o->channel = (uint8_t)channel; - o->channel_group = 0; + o->channel_group = channel_group; o->resolution = 4096; // NOTE: currently only 12bit resolution supported return MP_OBJ_FROM_PTR(o); @@ -104,6 +117,11 @@ static mp_int_t mp_machine_adc_read_u16(machine_adc_obj_t *self) { LPADC_GetDefaultConvCommandConfig(&adc_config); adc_config.channelNumber = self->channel; adc_config.sampleScaleMode = kLPADC_SamplePartScale; + if (self->channel_group == 0) { + adc_config.sampleChannelMode = kLPADC_SampleChannelSingleEndSideA; + } else { + adc_config.sampleChannelMode = kLPADC_SampleChannelSingleEndSideB; + } LPADC_SetConvCommandConfig(self->adc, 1, &adc_config); // Set Trigger mode @@ -126,6 +144,7 @@ void machine_adc_init(void) { adc_config.enableAnalogPreliminary = true; adc_config.referenceVoltageSource = kLPADC_ReferenceVoltageAlt1; LPADC_Init(LPADC1, &adc_config); + LPADC_Init(LPADC2, &adc_config); } #else diff --git a/ports/mimxrt/machine_pwm.c b/ports/mimxrt/machine_pwm.c index df76ed2b8bd34..9a2e39fd82708 100644 --- a/ports/mimxrt/machine_pwm.c +++ b/ports/mimxrt/machine_pwm.c @@ -375,7 +375,7 @@ static void configure_pwm(machine_pwm_obj_t *self) { } } -// Micropython API functions +// MicroPython API functions // static void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/ports/mimxrt/machine_rtc.c b/ports/mimxrt/machine_rtc.c index b025e392612c7..3b7aa6ed86cda 100644 --- a/ports/mimxrt/machine_rtc.c +++ b/ports/mimxrt/machine_rtc.c @@ -73,18 +73,33 @@ void machine_rtc_alarm_on() { machine_rtc_alarm_set_en(); } -uint32_t machine_rtc_get_seconds() { - uint32_t seconds = 0; - uint32_t tmp = 0; +// Returned ticks are in units of 1/32768 seconds. +uint64_t machine_rtc_get_ticks(void) { + uint64_t ticks = 0; + uint64_t tmp = 0; // Do consecutive reads until value is correct + uint32_t state = disable_irq(); do { - seconds = tmp; - tmp = (SNVS->LPSRTCMR << 17U); - tmp |= (SNVS->LPSRTCLR >> 15U); - } while (tmp != seconds); + ticks = tmp; + tmp = (uint64_t)SNVS->LPSRTCMR << 32U; + tmp |= SNVS->LPSRTCLR; + } while (tmp != ticks); + enable_irq(state); - return seconds; + return ticks; +} + +uint64_t machine_rtc_get_seconds(void) { + return machine_rtc_get_ticks() / 32768U; +} + +// Input ticks are in units of 1/32768 seconds. +static void machine_rtc_set_ticks(uint64_t ticks) { + SNVS_LP_SRTC_StopTimer(SNVS); + SNVS->LPSRTCMR = (uint32_t)(ticks >> 32U); + SNVS->LPSRTCLR = (uint32_t)ticks; + SNVS_LP_SRTC_StartTimer(SNVS); } void machine_rtc_alarm_helper(int seconds, bool repeat) { @@ -164,18 +179,9 @@ void machine_rtc_start(void) { SNVS_LP_SRTC_StartTimer(SNVS); // If the date is not set, set it to a more recent start date, // MicroPython's first commit. - snvs_lp_srtc_datetime_t srtc_date; - SNVS_LP_SRTC_GetDatetime(SNVS, &srtc_date); - if (srtc_date.year <= 1970) { - srtc_date = (snvs_lp_srtc_datetime_t) { - .year = 2013, - .month = 10, - .day = 14, - .hour = 19, - .minute = 53, - .second = 11, - }; - SNVS_LP_SRTC_SetDatetime(SNVS, &srtc_date); + if (machine_rtc_get_ticks() < 10) { + mp_timestamp_t seconds = timeutils_seconds_since_epoch(2013, 10, 14, 19, 53, 11); + machine_rtc_set_ticks((uint64_t)seconds * 32768ULL); } } @@ -190,39 +196,34 @@ static mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s static mp_obj_t machine_rtc_datetime_helper(size_t n_args, const mp_obj_t *args, int hour_index) { if (n_args == 1) { // Get date and time. - snvs_lp_srtc_datetime_t srtc_date; - SNVS_LP_SRTC_GetDatetime(SNVS, &srtc_date); - + uint64_t ticks = machine_rtc_get_ticks(); + timeutils_struct_time_t tm; + timeutils_seconds_since_epoch_to_struct_time(ticks / 32768U, &tm); mp_obj_t tuple[8] = { - mp_obj_new_int(srtc_date.year), - mp_obj_new_int(srtc_date.month), - mp_obj_new_int(srtc_date.day), - mp_obj_new_int(timeutils_calc_weekday(srtc_date.year, srtc_date.month, srtc_date.day)), - mp_obj_new_int(srtc_date.hour), - mp_obj_new_int(srtc_date.minute), - mp_obj_new_int(srtc_date.second), - mp_obj_new_int(0), + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int((ticks % 32768) * 15625U / 512U), }; return mp_obj_new_tuple(8, tuple); } else { // Set date and time. mp_obj_t *items; - mp_int_t year; mp_obj_get_array_fixed_n(args[1], 8, &items); - - snvs_lp_srtc_datetime_t srtc_date; - year = mp_obj_get_int(items[0]); - srtc_date.year = year >= 100 ? year : year + 2000; // allow 21 for 2021 - srtc_date.month = mp_obj_get_int(items[1]); - srtc_date.day = mp_obj_get_int(items[2]); - // Ignore weekday at items[3] - srtc_date.hour = mp_obj_get_int(items[hour_index]); - srtc_date.minute = mp_obj_get_int(items[hour_index + 1]); - srtc_date.second = mp_obj_get_int(items[hour_index + 2]); - if (SNVS_LP_SRTC_SetDatetime(SNVS, &srtc_date) != kStatus_Success) { - mp_raise_ValueError(NULL); - } - + timeutils_struct_time_t tm = { + .tm_year = mp_obj_get_int(items[0]), + .tm_mon = mp_obj_get_int(items[1]), + .tm_mday = mp_obj_get_int(items[2]), + .tm_hour = mp_obj_get_int(items[4]), + .tm_min = mp_obj_get_int(items[5]), + .tm_sec = mp_obj_get_int(items[6]), + }; + uint32_t seconds = timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + machine_rtc_set_ticks((uint64_t)seconds * 32768ULL); return mp_const_none; } } diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c index 107af72297d4f..ab5f9b76aa0c9 100644 --- a/ports/mimxrt/machine_uart.c +++ b/ports/mimxrt/machine_uart.c @@ -638,3 +638,75 @@ static mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uint } return ret; } + +// ============================================================================= +// LPUART IRQ Handler Wrapper for UART.IRQ_RXIDLE Support +// ============================================================================= +// +// Problem: SDK 2.16's LPUART_TransferHandleIDLEReady() only invokes the idle line callback +// when rxDataSize != 0. MicroPython uses ring buffer mode where rxDataSize is always 0, +// preventing IRQ_RXIDLE from ever firing. +// +// Solution: Use linker wrapping (see Makefile LDFLAGS) to intercept the IRQ handler and +// handle the idle line interrupt before the SDK processes it. +// +// Why double wrapping is needed: +// - The SDK's LPUART_TransferCreateHandle stores the address of LPUART_TransferHandleIRQ +// into the s_lpuartIsr[] dispatch table (not a direct call). +// - GCC's --wrap flag only intercepts direct function calls, not address-of operations. +// - Therefore we must also wrap CreateHandle to inject our IRQ wrapper's address. +// +// See Makefile: LDFLAGS += --wrap=LPUART_TransferCreateHandle --wrap=LPUART_TransferHandleIRQ +// + +// Linker wrapper declarations - these are provided by --wrap linkage +extern void __real_LPUART_TransferCreateHandle(LPUART_Type *base, lpuart_handle_t *handle, + lpuart_transfer_callback_t callback, void *userData); +extern void __real_LPUART_TransferHandleIRQ(LPUART_Type *base, void *irqHandle); + +// Forward declaration of our IRQ wrapper (defined below) +void __wrap_LPUART_TransferHandleIRQ(LPUART_Type *base, void *irqHandle); + +// SDK's ISR dispatch table - defined in lib/nxp_driver/sdk/drivers/lpuart/fsl_lpuart.c +extern lpuart_isr_t s_lpuartIsr[]; + +// Wrapper for LPUART_TransferCreateHandle to inject our IRQ wrapper into SDK's dispatch table. +// This is called instead of the SDK's function due to --wrap=LPUART_TransferCreateHandle in Makefile. +// After the SDK initializes, we replace s_lpuartIsr[instance] with our wrapper's address. +void __wrap_LPUART_TransferCreateHandle(LPUART_Type *base, lpuart_handle_t *handle, + lpuart_transfer_callback_t callback, void *userData) { + // Call the real SDK function to perform normal initialization + __real_LPUART_TransferCreateHandle(base, handle, callback, userData); + + // Override the ISR dispatch table entry with our wrapper's address + // (SDK stored __real_LPUART_TransferHandleIRQ, we want __wrap_LPUART_TransferHandleIRQ) + uint32_t instance = LPUART_GetInstance(base); + s_lpuartIsr[instance] = __wrap_LPUART_TransferHandleIRQ; +} + +// Wrapper for LPUART_TransferHandleIRQ to handle UART.IRQ_RXIDLE in ring buffer mode. +// This is installed into s_lpuartIsr[] by __wrap_LPUART_TransferCreateHandle above. +// Processes the IDLE line interrupt and invokes the MicroPython callback unconditionally, +// then calls the SDK's handler for remaining interrupt processing. +void __wrap_LPUART_TransferHandleIRQ(LPUART_Type *base, void *irqHandle) { + uint32_t status = LPUART_GetStatusFlags(base); + uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(base); + lpuart_handle_t *handle = (lpuart_handle_t *)irqHandle; + + // Check if IDLE flag is set and IDLE interrupt is enabled + if ((0U != ((uint32_t)kLPUART_IdleLineFlag & status)) && + (0U != ((uint32_t)kLPUART_IdleLineInterruptEnable & enabledInterrupts))) { + // Clear IDLE flag to prevent SDK's handler from seeing it + // (SDK would disable the interrupt due to rxDataSize == 0) + LPUART_ClearStatusFlags(base, kLPUART_IdleLineFlag); + // Invoke MicroPython's idle handler callback + if (NULL != handle->callback) { + handle->callback(base, handle, kStatus_LPUART_IdleLineDetected, handle->userData); + } else { + /* Avoid MISRA 15.7 */ + } + } + + // Call SDK's handler for all other interrupt processing + __real_LPUART_TransferHandleIRQ(base, irqHandle); +} diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index dcb1ede1670db..9f3d47f8cc245 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -37,6 +37,7 @@ #include "ticks.h" #include "led.h" #include "pendsv.h" +#include "psram.h" #include "modmachine.h" #include "modmimxrt.h" @@ -67,6 +68,10 @@ int main(void) { ticks_init(); pendsv_init(); + #if MICROPY_HW_ENABLE_PSRAM + size_t psram_size = configure_external_ram(); + #endif + #if MICROPY_PY_LWIP // lwIP doesn't allow to reinitialise itself by subsequent calls to this function // because the system timeout list (next_timeout) is only ever reset by BSS clearing. @@ -101,7 +106,20 @@ int main(void) { mp_cstack_init_with_top(&_estack, &_estack - &_sstack); + #if MICROPY_HW_ENABLE_PSRAM + if (psram_size) { + #if MICROPY_GC_SPLIT_HEAP + gc_init(&_gc_heap_start, &_gc_heap_end); + gc_add((void *)PSRAM_BASE, (void *)(PSRAM_BASE + psram_size)); + #else + gc_init((void *)PSRAM_BASE, (void *)(PSRAM_BASE + psram_size)); + #endif + } else { + gc_init(&_gc_heap_start, &_gc_heap_end); + } + #else gc_init(&_gc_heap_start, &_gc_heap_end); + #endif mp_init(); #if MICROPY_PY_NETWORK diff --git a/ports/mimxrt/mbedtls/mbedtls_port.c b/ports/mimxrt/mbedtls/mbedtls_port.c index 230e264bf9806..fa2d81001b8c2 100644 --- a/ports/mimxrt/mbedtls/mbedtls_port.c +++ b/ports/mimxrt/mbedtls/mbedtls_port.c @@ -30,8 +30,8 @@ #include "mbedtls_config_port.h" #if defined(MBEDTLS_HAVE_TIME) || defined(MBEDTLS_HAVE_TIME_DATE) -#include "fsl_snvs_lp.h" #include "shared/timeutils/timeutils.h" +#include "modmachine.h" #include "mbedtls/platform_time.h" #endif @@ -49,9 +49,7 @@ int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t #if defined(MBEDTLS_HAVE_TIME) time_t mimxrt_rtctime_seconds(time_t *timer) { // Get date and date in CPython order. - snvs_lp_srtc_datetime_t date; - SNVS_LP_SRTC_GetDatetime(SNVS, &date); - return timeutils_seconds_since_epoch(date.year, date.month, date.day, date.hour, date.minute, date.second); + return machine_rtc_get_seconds(); } mbedtls_ms_time_t mbedtls_ms_time(void) { diff --git a/ports/mimxrt/mimxrt_flash.c b/ports/mimxrt/mimxrt_flash.c index fdd48e280bc15..3819d8b904359 100644 --- a/ports/mimxrt/mimxrt_flash.c +++ b/ports/mimxrt/mimxrt_flash.c @@ -5,6 +5,7 @@ * * Copyright (c) 2020-2021 Damien P. George * Copyright (c) 2021-2023 Philipp Ebensberger + * Copyright (c) 2021-2024 Robert Hammelrath * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,6 +30,7 @@ #include "py/runtime.h" #include "extmod/vfs.h" +#include "py/mperrno.h" #include "modmimxrt.h" #include "flash.h" #include BOARD_FLASH_OPS_HEADER_H @@ -60,6 +62,19 @@ static mp_obj_t mimxrt_flash_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(&mimxrt_flash_obj); } +static mp_int_t mimxrt_flash_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + mimxrt_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (flags == MP_BUFFER_READ) { + bufinfo->buf = (void *)((uintptr_t)&__flash_start + self->flash_base); + bufinfo->len = self->flash_size; + bufinfo->typecode = 'B'; + return 0; + } else { + // Write unsupported. + return 1; + } +} + // readblocks(block_num, buf, [offset]) // read size of buffer number of bytes from block (with offset) into buffer static mp_obj_t mimxrt_flash_readblocks(size_t n_args, const mp_obj_t *args) { @@ -151,5 +166,39 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_QSTR_Flash, MP_TYPE_FLAG_NONE, make_new, mimxrt_flash_make_new, + buffer, mimxrt_flash_get_buffer, locals_dict, &mimxrt_flash_locals_dict ); + +#if MICROPY_VFS_ROM + +extern uint8_t _micropy_hw_romfs_part0_start; +extern uint8_t _micropy_hw_romfs_part0_size; + +// Put VfsRom file system between the code space and the VFS file system. +// The size is defined in Makefile(s) as linker symbol MICROPY_HW_ROMFS_BYTES. +// For machine.mem32 the absolute address is required, for the flash functions +// erase and write the offset to the flash start address. +#define MICROPY_HW_ROMFS_BASE ((uintptr_t)&_micropy_hw_romfs_part0_start - (uintptr_t)&__flash_start) +#define MICROPY_HW_ROMFS_BYTES ((uintptr_t)&_micropy_hw_romfs_part0_size) + +static mimxrt_flash_obj_t mimxrt_flash_romfs_obj = { + .base = { &mimxrt_flash_type }, +}; + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (MICROPY_HW_ROMFS_BYTES <= 0) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + mimxrt_flash_romfs_obj.flash_base = MICROPY_HW_ROMFS_BASE; + mimxrt_flash_romfs_obj.flash_size = MICROPY_HW_ROMFS_BYTES; + return MP_OBJ_FROM_PTR(&mimxrt_flash_romfs_obj); + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} +#endif // MICROPY_VFS_ROM diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h index 34e93260f2dac..398dfb22609ff 100644 --- a/ports/mimxrt/modmachine.h +++ b/ports/mimxrt/modmachine.h @@ -42,6 +42,8 @@ void mimxrt_sdram_init(void); void machine_i2s_init0(); void machine_i2s_deinit_all(void); void machine_rtc_start(void); +uint64_t machine_rtc_get_ticks(void); +uint64_t machine_rtc_get_seconds(void); void machine_rtc_alarm_helper(int seconds, bool repeat); void machine_uart_set_baudrate(mp_obj_t uart, uint32_t baudrate); diff --git a/ports/mimxrt/modtime.c b/ports/mimxrt/modtime.c index fe77b8a733be2..4b439bb17d1ac 100644 --- a/ports/mimxrt/modtime.c +++ b/ports/mimxrt/modtime.c @@ -25,30 +25,17 @@ * THE SOFTWARE. */ -#include "py/obj.h" #include "shared/timeutils/timeutils.h" -#include "fsl_snvs_lp.h" +#include "modmachine.h" // Get the localtime. static void mp_time_localtime_get(timeutils_struct_time_t *tm) { // Get current date and time. - snvs_lp_srtc_datetime_t t; - SNVS_LP_SRTC_GetDatetime(SNVS, &t); - tm->tm_year = t.year; - tm->tm_mon = t.month; - tm->tm_mday = t.day; - tm->tm_hour = t.hour; - tm->tm_min = t.minute; - tm->tm_sec = t.second; - tm->tm_wday = timeutils_calc_weekday(t.year, t.month, t.day); - tm->tm_yday = timeutils_year_day(t.year, t.month, t.day); + uint64_t seconds = machine_rtc_get_seconds(); + timeutils_seconds_since_epoch_to_struct_time(seconds, tm); } // Return the number of seconds since the Epoch. static mp_obj_t mp_time_time_get(void) { - snvs_lp_srtc_datetime_t t; - SNVS_LP_SRTC_GetDatetime(SNVS, &t); - return timeutils_obj_from_timestamp( - timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second) - ); + return timeutils_obj_from_timestamp(machine_rtc_get_seconds()); } diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 0a623a6318700..871713e1cb233 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -35,13 +35,20 @@ uint32_t trng_random_u32(void); // Config level #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES) +#ifndef MICROPY_HW_ENABLE_PSRAM +#define MICROPY_HW_ENABLE_PSRAM (0) +#endif + // Memory allocation policies -#if MICROPY_HW_SDRAM_AVAIL +#if MICROPY_HW_SDRAM_AVAIL || MICROPY_HW_ENABLE_PSRAM #define MICROPY_GC_STACK_ENTRY_TYPE uint32_t #else #define MICROPY_GC_STACK_ENTRY_TYPE uint16_t #endif #define MICROPY_ALLOC_PATH_MAX (256) +#ifndef MICROPY_GC_SPLIT_HEAP +#define MICROPY_GC_SPLIT_HEAP MICROPY_HW_ENABLE_PSRAM +#endif // MicroPython emitters #define MICROPY_PERSISTENT_CODE_LOAD (1) @@ -60,6 +67,9 @@ uint32_t trng_random_u32(void); #define MICROPY_SCHEDULER_DEPTH (8) #define MICROPY_SCHEDULER_STATIC_NODES (1) #define MICROPY_VFS (1) +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (1) +#endif // Control over Python builtins #define MICROPY_PY_BUILTINS_HELP_TEXT mimxrt_help_text @@ -176,7 +186,7 @@ uint32_t trng_random_u32(void); // Hooks to add builtins -#if defined(IOMUX_TABLE_ENET) +#if defined(ENET_PHY_ADDRESS) || defined(ENET_1_PHY_ADDRESS) extern const struct _mp_obj_type_t network_lan_type; #define MICROPY_HW_NIC_ETH { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) }, #else diff --git a/ports/mimxrt/mphalport.c b/ports/mimxrt/mphalport.c index c3802be30f5d7..67612229aebc9 100644 --- a/ports/mimxrt/mphalport.c +++ b/ports/mimxrt/mphalport.c @@ -34,7 +34,7 @@ #include "extmod/misc.h" #include "ticks.h" #include "tusb.h" -#include "fsl_snvs_lp.h" +#include "modmachine.h" #ifndef MICROPY_HW_STDIN_BUFFER_LEN #define MICROPY_HW_STDIN_BUFFER_LEN 512 @@ -96,10 +96,12 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { } uint64_t mp_hal_time_ns(void) { - snvs_lp_srtc_datetime_t t; - SNVS_LP_SRTC_GetDatetime(SNVS, &t); - uint64_t s = timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second); - return s * 1000000000ULL; + uint64_t ticks = machine_rtc_get_ticks(); + // Need to compute: + // nanoseconds = ticks * 1_000_000_000 / 32768 + // = ticks * 5**9 / 64 + // but split it into upper and lower 32-bit values so the multiplication doesn't overflow. + return (((ticks >> 32U) * 1953125ULL) << 26U) + (((ticks & 0xffffffff) * 1953125ULL) >> 6U); } /*******************************************************************************/ diff --git a/ports/mimxrt/network_lan.c b/ports/mimxrt/network_lan.c index 7d6ae2d7277fb..b020d53e6efc7 100644 --- a/ports/mimxrt/network_lan.c +++ b/ports/mimxrt/network_lan.c @@ -28,13 +28,14 @@ #include "py/mphal.h" #include "extmod/modnetwork.h" -#if defined(IOMUX_TABLE_ENET) +#if defined(ENET_PHY_ADDRESS) || defined(ENET_1_PHY_ADDRESS) #include "fsl_phy.h" #include "eth.h" #include "hal/phy/device/phyksz8081/fsl_phyksz8081.h" #include "hal/phy/device/phydp83825/fsl_phydp83825.h" #include "hal/phy/device/phydp83848/fsl_phydp83848.h" +#include "hal/phy/device/phydp83867/fsl_phydp83867.h" #include "hal/phy/device/phylan8720/fsl_phylan8720.h" #include "hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.h" @@ -54,9 +55,13 @@ typedef struct _network_lan_obj_t { eth_t *eth; } network_lan_obj_t; +// Forward declaration of the type +extern const mp_obj_type_t network_lan_type; +#if defined(ENET_PHY_ADDRESS) static const network_lan_obj_t network_lan_eth0 = { { &network_lan_type }, ð_instance0 }; -#if defined(ENET_DUAL_PORT) +#endif +#if defined(ENET_1_PHY_ADDRESS) static const network_lan_obj_t network_lan_eth1 = { { &network_lan_type }, ð_instance1 }; #endif @@ -64,8 +69,19 @@ static void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_prin network_lan_obj_t *self = MP_OBJ_TO_PTR(self_in); struct netif *netif = eth_netif(self->eth); int status = eth_link_status(self->eth); + int eth_id = 0; + #if defined(ENET_PHY_ADDRESS) + if (self->eth == ð_instance0) { + eth_id = 0; + } + #endif + #if defined(ENET_1_PHY_ADDRESS) + if (self->eth == ð_instance1) { + eth_id = 1; + } + #endif mp_printf(print, "", - self->eth == ð_instance0 ? 0 : 1, + eth_id, status, netif->ip_addr.addr & 0xff, netif->ip_addr.addr >> 8 & 0xff, @@ -76,8 +92,18 @@ static void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_prin static mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_id, ARG_phy_type, ARG_phy_addr, ARG_ref_clk_mode}; + + // Default to port 0 if ENET available, else port 1 if only ENET_1 available + #if defined(ENET_PHY_ADDRESS) + #define DEFAULT_ETH_ID 0 + #elif defined(ENET_1_PHY_ADDRESS) + #define DEFAULT_ETH_ID 1 + #else + #error "No Ethernet PHY configured" + #endif + static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_id, MP_ARG_INT, {.u_int = DEFAULT_ETH_ID} }, { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_ref_clk_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, @@ -91,18 +117,21 @@ static mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s bool phy_clock; int mac_id = args[ARG_id].u_int; - // set default + // set default based on which interface is being used + #if defined(ENET_PHY_ADDRESS) if (mac_id == 0) { phy_ops = &ENET_PHY_OPS; phy_addr = ENET_PHY_ADDRESS; phy_clock = ENET_TX_CLK_OUTPUT; - #if defined(ENET_DUAL_PORT) - } else { + } + #endif + #if defined(ENET_1_PHY_ADDRESS) + if (mac_id == 1) { phy_ops = &ENET_1_PHY_OPS; phy_addr = ENET_1_PHY_ADDRESS; phy_clock = ENET_1_TX_CLK_OUTPUT; - #endif } + #endif // Select PHY driver int phy_type = args[ARG_phy_type].u_int; @@ -113,6 +142,8 @@ static mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s phy_ops = &phydp83825_ops; } else if (phy_type == PHY_DP83848) { phy_ops = &phydp83848_ops; + } else if (phy_type == PHY_DP83867) { + phy_ops = &phydp83867_ops; } else if (phy_type == PHY_LAN8720) { phy_ops = &phylan8720_ops; } else if (phy_type == PHY_RTL8211F) { @@ -129,17 +160,21 @@ static mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s phy_clock = args[ARG_ref_clk_mode].u_int; } - // Prepare for two ETH interfaces. - const network_lan_obj_t *self; + // Initialize the appropriate ETH interface + const network_lan_obj_t *self = NULL; + #if defined(ENET_PHY_ADDRESS) if (mac_id == 0) { self = &network_lan_eth0; eth_init_0(self->eth, MP_HAL_MAC_ETH0, phy_ops, phy_addr, phy_clock); - #if defined(ENET_DUAL_PORT) - } else if (mac_id == 1) { + } + #endif + #if defined(ENET_1_PHY_ADDRESS) + if (mac_id == 1) { self = &network_lan_eth1; eth_init_1(self->eth, MP_HAL_MAC_ETH1, phy_ops, phy_addr, phy_clock); + } #endif - } else { + if (self == NULL) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid LAN interface %d"), mac_id); } @@ -254,6 +289,7 @@ static const mp_rom_map_elem_t network_lan_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_PHY_KSZ8081), MP_ROM_INT(PHY_KSZ8081) }, { MP_ROM_QSTR(MP_QSTR_PHY_DP83825), MP_ROM_INT(PHY_DP83825) }, { MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(PHY_DP83848) }, + { MP_ROM_QSTR(MP_QSTR_PHY_DP83867), MP_ROM_INT(PHY_DP83867) }, { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) }, { MP_ROM_QSTR(MP_QSTR_PHY_RTL8211F), MP_ROM_INT(PHY_RTL8211F) }, { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(PHY_TX_CLK_IN) }, @@ -271,4 +307,4 @@ MP_DEFINE_CONST_OBJ_TYPE( ); -#endif // defined(IOMUX_TABLE_ENET) +#endif // defined(ENET_PHY_ADDRESS) || defined(ENET_1_PHY_ADDRESS) diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h index 13b313c41f409..3ed454c54bce9 100644 --- a/ports/mimxrt/pin.h +++ b/ports/mimxrt/pin.h @@ -77,6 +77,7 @@ enum { PIN_AF_MODE_ALT8, PIN_AF_MODE_ALT9, PIN_AF_MODE_ALT10, + PIN_AF_MODE_ALT11, }; enum { @@ -106,7 +107,7 @@ enum { typedef struct { mp_obj_base_t base; - qstr name; // port name + qstr_short_t name; // port name uint8_t af_mode; // alternate function uint8_t input_daisy; void *instance; // pointer to peripheral instance for alternate function @@ -117,19 +118,20 @@ typedef struct { typedef struct { ADC_Type *instance; uint8_t channel; + uint8_t channel_group; } machine_pin_adc_obj_t; typedef struct { mp_obj_base_t base; - qstr name; // pad name GPIO_Type *gpio; // gpio instance for pin uint32_t pin; // pin number uint32_t muxRegister; uint32_t configRegister; - uint8_t af_list_len; // length of available alternate functions list - uint8_t adc_list_len; // length of available ADC options list const machine_pin_af_obj_t *af_list; // pointer to list with alternate functions const machine_pin_adc_obj_t *adc_list; // pointer to list with ADC options + qstr_short_t name; // pad name + uint8_t af_list_len; // length of available alternate functions list + uint8_t adc_list_len; // length of available ADC options list } machine_pin_obj_t; typedef struct _machine_pin_irq_obj_t { diff --git a/ports/mimxrt/psram.c b/ports/mimxrt/psram.c new file mode 100644 index 0000000000000..f19d4f1d26557 --- /dev/null +++ b/ports/mimxrt/psram.c @@ -0,0 +1,265 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Paul Stoffregen + * 2026 Dryw Wade + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This implementation is adapted from here: +// https://github.com/PaulStoffregen/cores/blob/10025393e83ca9f4dc5646643a41cb2f32022ae4/teensy4/startup.c#L421-L615 +#include "py/mphal.h" +#include "fsl_flexspi.h" + +#if MICROPY_HW_ENABLE_PSRAM + +/*! + * @brief Clock divider value. + * + * See https://www.pjrc.com/teensy/IMXRT1060RM_rev3_annotations.pdf (p1010 and p1050) + */ +typedef enum _clock_mux_value { + kCLOCK_Flexspi2Mux_396MHz = 0U, /*!< FLEXSPI2 clock source is PLL2 PFD2. */ + kCLOCK_Flexspi2Mux_720MHz = 1U, /*!< FLEXSPI2 clock source is PLL3 PFD0. */ + kCLOCK_Flexspi2Mux_664_62MHz = 2U, /*!< FLEXSPI2 clock source is PLL3 PFD1. */ + kCLOCK_Flexspi2Mux_528MHz = 3U, /*!< FLEXSPI2 clock source is PLL2 (pll2_main_clk). */ +} clock_mux_value_t; + +static void flexspi2_command(uint32_t index, uint32_t addr, flexspi_port_t port) { + flexspi_transfer_t xfer = { + .deviceAddress = addr, + .port = port, + .cmdType = kFLEXSPI_Command, + .seqIndex = index, + .SeqNumber = 1, + .data = NULL, + .dataSize = 0, + }; + FLEXSPI_TransferBlocking(FLEXSPI2, &xfer); + FLEXSPI_ClearInterruptStatusFlags(FLEXSPI2, kFLEXSPI_IpCommandExecutionDoneFlag); +} + +static uint32_t flexspi2_psram_id(uint32_t addr, flexspi_port_t port) { + uint32_t id = 0; + flexspi_transfer_t xfer = { + .deviceAddress = addr, + .port = port, + .cmdType = kFLEXSPI_Read, + .seqIndex = 3, + .SeqNumber = 1, + .data = &id, + .dataSize = 4, + }; + FLEXSPI_TransferBlocking(FLEXSPI2, &xfer); + FLEXSPI_ClearInterruptStatusFlags(FLEXSPI2, + kFLEXSPI_IpCommandExecutionDoneFlag | kFLEXSPI_IpRxFifoWatermarkAvailableFlag); + return id; +} + +/** + * \return size of PSRAM in MBytes, or 0 if not present + */ +static uint8_t flexspi2_psram_size(uint32_t addr, flexspi_port_t port) { + uint8_t result = 0; // assume we don't have PSRAM at this address + flexspi2_command(0, addr, port); // exit quad mode + flexspi2_command(1, addr, port); // reset enable + flexspi2_command(2, addr, port); // reset (is this really necessary?) + uint32_t id = flexspi2_psram_id(addr, port); + + switch (id & 0xFFFF) + { + default: + break; + + case 0x5D0D: // AP / Ipus / ESP / Lyontek + result = 8; + break; + + case 0x5D9D: // ISSI + switch ((id >> 21) & 0x7) // get size (Datasheet Table 6.2) + { + case 0b011: + result = 8; + break; + case 0b100: + result = 16; + break; + } + break; + } + + return result; +} + +size_t configure_external_ram() { + // initialize pins + IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_22] = 0x1B0F9; // 100K pullup, strong drive, max speed, hyst + IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_23] = 0x110F9; // keeper, strong drive, max speed, hyst + IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_24] = 0x1B0F9; // 100K pullup, strong drive, max speed, hyst + IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_25] = 0x100F9; // strong drive, max speed, hyst + IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_26] = 0x170F9; // 47K pullup, strong drive, max speed, hyst + IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_27] = 0x170F9; // 47K pullup, strong drive, max speed, hyst + IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_28] = 0x170F9; // 47K pullup, strong drive, max speed, hyst + IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_29] = 0x170F9; // 47K pullup, strong drive, max speed, hyst + + IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_22] = 8 | 0x10; // ALT1 = FLEXSPI2_A_SS1_B (Flash) + IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_23] = 8 | 0x10; // ALT1 = FLEXSPI2_A_DQS + IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_24] = 8 | 0x10; // ALT1 = FLEXSPI2_A_SS0_B (RAM) + IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_25] = 8 | 0x10; // ALT1 = FLEXSPI2_A_SCLK + IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_26] = 8 | 0x10; // ALT1 = FLEXSPI2_A_DATA0 + IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_27] = 8 | 0x10; // ALT1 = FLEXSPI2_A_DATA1 + IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_28] = 8 | 0x10; // ALT1 = FLEXSPI2_A_DATA2 + IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_29] = 8 | 0x10; // ALT1 = FLEXSPI2_A_DATA3 + + IOMUXC->SELECT_INPUT_1[kIOMUXC_FLEXSPI2_IPP_IND_DQS_FA_SELECT_INPUT] = 1; // GPIO_EMC_23 for Mode: ALT8, pg 986 + IOMUXC->SELECT_INPUT_1[kIOMUXC_FLEXSPI2_IPP_IND_IO_FA_BIT0_SELECT_INPUT] = 1; // GPIO_EMC_26 for Mode: ALT8 + IOMUXC->SELECT_INPUT_1[kIOMUXC_FLEXSPI2_IPP_IND_IO_FA_BIT1_SELECT_INPUT] = 1; // GPIO_EMC_27 for Mode: ALT8 + IOMUXC->SELECT_INPUT_1[kIOMUXC_FLEXSPI2_IPP_IND_IO_FA_BIT2_SELECT_INPUT] = 1; // GPIO_EMC_28 for Mode: ALT8 + IOMUXC->SELECT_INPUT_1[kIOMUXC_FLEXSPI2_IPP_IND_IO_FA_BIT3_SELECT_INPUT] = 1; // GPIO_EMC_29 for Mode: ALT8 + IOMUXC->SELECT_INPUT_1[kIOMUXC_FLEXSPI2_IPP_IND_SCK_FA_SELECT_INPUT] = 1; // GPIO_EMC_25 for Mode: ALT8 + + // turn on clock (QSPI flash & PSRAM chips usually spec max clock 100 to 133 MHz) + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy6); // 88.0 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_528MHz); // 88.0 MHz + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy4); // 99.0 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_396MHz); // 99.0 MHz + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy7); // 102.9 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_720MHz); // 102.9 MHz + CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy5); // 105.6 MHz + CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_528MHz); // 105.6 MHz + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy6); // 110.8 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_664_62MHz); // 110.8 MHz + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy6); // 120.0 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_720MHz); // 120.0 MHz + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy4); // 132.0 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_528MHz); // 132.0 MHz + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy5); // 144.0 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_720MHz); // 144.0 MHz + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy4); // 166.2 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_664_62MHz); // 166.2 MHz + // CLOCK_SetDiv(kCLOCK_Flexspi2Div, kCLOCK_Flexspi2DivBy3); // 176.0 MHz + // CLOCK_SetMux(kCLOCK_Flexspi2Mux, kCLOCK_Flexspi2Mux_528MHz); // 176.0 MHz + + flexspi_config_t flexspi_config = { + .rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackFromDqsPad, + .enableSckFreeRunning = false, + .enableCombination = false, + .enableDoze = false, + .enableHalfSpeedAccess = false, + .enableSckBDiffOpt = false, + .enableSameConfigForAll = false, + .seqTimeoutCycle = 0xFFFF, + .ipGrantTimeoutCycle = 0xFF, + .txWatermark = 0, + .rxWatermark = 0, + .ahbConfig = { + .enableAHBWriteIpTxFifo = false, + .enableAHBWriteIpRxFifo = false, + .ahbGrantTimeoutCycle = 0xFF, + .ahbBusTimeoutCycle = 0xFFFF, + .resumeWaitCycle = 0x20, + .buffer = { + {.priority = 0, .masterIndex = 0, .bufferSize = 512, .enablePrefetch = true}, + {.priority = 0, .masterIndex = 0, .bufferSize = 512, .enablePrefetch = true}, + {.priority = 0, .masterIndex = 0, .bufferSize = 0, .enablePrefetch = false}, + {.priority = 0, .masterIndex = 0, .bufferSize = 0, .enablePrefetch = false}, + }, + .enableClearAHBBufferOpt = false, + .enableReadAddressOpt = false, + .enableAHBPrefetch = false, + .enableAHBBufferable = false, + .enableAHBCachable = false, + }, + }; + FLEXSPI_Init(FLEXSPI2, &flexspi_config); + + FLEXSPI_DisableInterrupts(FLEXSPI2, kFLEXSPI_AllInterruptFlags); + + flexspi_device_config_t flexspi_device_config = { + .flexspiRootClk = 0, + .isSck2Enabled = false, + .flashSize = 1 << 16, // Default value, will be updated later + .CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle, + .CSInterval = 0, + .CSHoldTime = 1, + .CSSetupTime = 1, + .dataValidTime = 0, + .columnspace = 0, + .enableWordAddress = false, + .AWRSeqIndex = 6, + .AWRSeqNumber = 1, + .ARDSeqIndex = 5, + .ARDSeqNumber = 1, + .AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle, + .AHBWriteWaitInterval = 0, + .enableWriteMask = false, + }; + FLEXSPI_SetFlashConfig(FLEXSPI2, &flexspi_device_config, kFLEXSPI_PortA1); + FLEXSPI_SetFlashConfig(FLEXSPI2, &flexspi_device_config, kFLEXSPI_PortA2); + + uint32_t cmd[64] = {0}; + // cmd index 0 = exit QPI mode + cmd[0] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, 0, 0, 0); + // cmd index 1 = reset enable + cmd[4] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x66, 0, 0, 0); + // cmd index 2 = reset + cmd[8] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x99, 0, 0, 0); + // cmd index 3 = read ID bytes + cmd[12] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 24); + cmd[13] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 1, 0, 0, 0); + // cmd index 4 = enter QPI mode + cmd[16] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, 0, 0, 0); + // cmd index 5 = read QPI + cmd[20] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 24); + cmd[21] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 6, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 1); + // cmd index 6 = write QPI + cmd[24] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0x38, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 24); + cmd[25] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 1, 0, 0, 0); + FLEXSPI_UpdateLUT(FLEXSPI2, 0, cmd, 64); + + // Detected PSRAM size in MB + uint8_t external_psram_size = 0; + + // look for the first PSRAM chip + uint8_t size1 = flexspi2_psram_size(0, kFLEXSPI_PortA1); + if (size1 > 0) { + flexspi_device_config.flashSize = size1 << 10; + FLEXSPI_SetFlashConfig(FLEXSPI2, &flexspi_device_config, kFLEXSPI_PortA1); + flexspi2_command(4, 0, kFLEXSPI_PortA1); // enter QPI mode + // look for a second PSRAM chip + uint8_t size2 = flexspi2_psram_size(size1 << 20, kFLEXSPI_PortA2); + external_psram_size = size1 + size2; + if (size2 > 0) { + flexspi_device_config.flashSize = size2 << 10; + FLEXSPI_SetFlashConfig(FLEXSPI2, &flexspi_device_config, kFLEXSPI_PortA2); + flexspi2_command(4, size1 << 20, kFLEXSPI_PortA2); // enter QPI mode + } + } else { + // No PSRAM + external_psram_size = 0; + } + + // Return the size of the PSRAM in bytes + return external_psram_size * 0x100000; +} + +#endif diff --git a/ports/mimxrt/psram.h b/ports/mimxrt/psram.h new file mode 100644 index 0000000000000..e5ecd5aa1643a --- /dev/null +++ b/ports/mimxrt/psram.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Paul Stoffregen + * 2026 Dryw Wade + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_PSRAM_H +#define MICROPY_INCLUDED_MIMXRT_PSRAM_H + +#define PSRAM_BASE (0x70000000) + +// Configures external PSRAM if available, returns size in bytes (0 if none). +size_t configure_external_ram(); + +#endif // MICROPY_INCLUDED_MIMXRT_PSRAM_H diff --git a/ports/nrf/boards/memory.ld b/ports/nrf/boards/memory.ld index 9c4c9c8bd1267..df95b951b076d 100644 --- a/ports/nrf/boards/memory.ld +++ b/ports/nrf/boards/memory.ld @@ -8,10 +8,12 @@ _head_size = DEFINED(_sd_size) ? _sd_size : _bootloader_head_size; _head_ram = DEFINED(_sd_ram) ? _sd_ram : _bootloader_head_ram_size; _sd_size = DEFINED(_sd_size) ? _sd_size : 0; _sd_ram = DEFINED(_sd_ram) ? _sd_ram : 0; +_micropy_hw_romfs_part0_size = DEFINED(_micropy_hw_romfs_part0_size) ? _micropy_hw_romfs_part0_size : 0; _fs_size = DEFINED(_fs_size) ? _fs_size : 64K; /* TODO: set to 0 if not using the filesystem */ -_app_size = _flash_size - _head_size - _fs_size - _bootloader_tail_size; +_app_size = _flash_size - _head_size - _micropy_hw_romfs_part0_size - _fs_size - _bootloader_tail_size; _app_start = _head_size; -_fs_start = _head_size + _app_size; +_micropy_hw_romfs_part0_start = _head_size + _app_size; +_fs_start = _micropy_hw_romfs_part0_start + _micropy_hw_romfs_part0_size; _fs_end = _fs_start + _fs_size; _app_ram_start = 0x20000000 + _head_ram; _app_ram_size = _ram_size - _head_ram; diff --git a/ports/nrf/boards/nrf51x22_256k_16k.ld b/ports/nrf/boards/nrf51x22_256k_16k.ld index 8a40ae0f17307..4c54def8e803b 100644 --- a/ports/nrf/boards/nrf51x22_256k_16k.ld +++ b/ports/nrf/boards/nrf51x22_256k_16k.ld @@ -6,6 +6,7 @@ GROUP(-lgcc -lc -lnosys) _flash_size = 256K; _ram_size = 16K; +_micropy_hw_romfs_part0_size = 12K; /* Default stack size when there is no SoftDevice */ _stack_size = 4K; diff --git a/ports/nrf/boards/nrf51x22_256k_32k.ld b/ports/nrf/boards/nrf51x22_256k_32k.ld index 06c0914035b4a..b61c2a55056a3 100644 --- a/ports/nrf/boards/nrf51x22_256k_32k.ld +++ b/ports/nrf/boards/nrf51x22_256k_32k.ld @@ -6,6 +6,7 @@ GROUP(-lgcc -lc -lnosys) _flash_size = 256K; _ram_size = 32K; +_micropy_hw_romfs_part0_size = 12K; /* Default stack size when there is no SoftDevice */ _stack_size = 4K; diff --git a/ports/nrf/boards/nrf52832_512k_64k.ld b/ports/nrf/boards/nrf52832_512k_64k.ld index 22804df5cdb5e..0599c9bda3b3b 100644 --- a/ports/nrf/boards/nrf52832_512k_64k.ld +++ b/ports/nrf/boards/nrf52832_512k_64k.ld @@ -4,6 +4,7 @@ _flash_size = 512K; _ram_size = 64K; +_micropy_hw_romfs_part0_size = 128K; /* produce a link error if there is not this amount of RAM for these sections */ _stack_size = 8K; diff --git a/ports/nrf/boards/nrf52840_1M_256k.ld b/ports/nrf/boards/nrf52840_1M_256k.ld index 16d61af6a30b9..21d4518243484 100644 --- a/ports/nrf/boards/nrf52840_1M_256k.ld +++ b/ports/nrf/boards/nrf52840_1M_256k.ld @@ -4,6 +4,7 @@ _flash_size = 1M; _ram_size = 256K; +_micropy_hw_romfs_part0_size = 256K; /* produce a link error if there is not this amount of RAM for these sections */ _stack_size = 8K; diff --git a/ports/nrf/boards/nrf9160_1M_256k.ld b/ports/nrf/boards/nrf9160_1M_256k.ld index 6347095a899ce..d8f0aa5cb01f0 100644 --- a/ports/nrf/boards/nrf9160_1M_256k.ld +++ b/ports/nrf/boards/nrf9160_1M_256k.ld @@ -7,6 +7,7 @@ _ram_size = 256K; _sd_size = 0x00008000; _sd_ram = 0x00020000; _fs_size = 80K; +_micropy_hw_romfs_part0_size = 256K; /* produce a link error if there is not this amount of RAM for these sections */ _stack_size = 32K; diff --git a/ports/nrf/main.c b/ports/nrf/main.c index e5d7828a82a58..1013005e1987d 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -177,22 +177,8 @@ void MP_NORETURN _start(void) { #if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE flashbdev_init(); - - // Try to mount the flash on "/flash" and chdir to it for the boot-up directory. - mp_obj_t mount_point = MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash); - int ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point); - - if ((ret == -MP_ENODEV) || (ret == -MP_EIO)) { - pyexec_frozen_module("_mkfs.py", false); // Frozen script for formatting flash filesystem. - ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point); - } - - if (ret != 0) { - printf("MPY: can't mount flash\n"); - } else { - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash)); - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib)); - } + // Execute _boot.py to set up the filesystem. + pyexec_frozen_module("_boot.py", false); #endif #if MICROPY_MBFS @@ -368,7 +354,7 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c __fatal_error("Assertion failed"); } -#if MICROPY_EMIT_MACHINE_CODE +#if MICROPY_EMIT_INLINE_THUMB || MICROPY_ENABLE_NATIVE_CODE void *nrf_native_code_commit(void *buf, unsigned int len, void *reloc) { (void)len; if (reloc) { diff --git a/ports/nrf/modules/machine/pin.h b/ports/nrf/modules/machine/pin.h index 41579011b5d84..a67c39d2848cf 100644 --- a/ports/nrf/modules/machine/pin.h +++ b/ports/nrf/modules/machine/pin.h @@ -56,7 +56,6 @@ typedef struct { uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT uint32_t adc_num : 3; // 1 bit per ADC const pin_af_obj_t *af; - uint32_t pull; } pin_obj_t; extern const mp_obj_type_t pin_type; diff --git a/ports/nrf/modules/manifest.py b/ports/nrf/modules/manifest.py index 7ba0f80d884d0..631ad19a8db8a 100644 --- a/ports/nrf/modules/manifest.py +++ b/ports/nrf/modules/manifest.py @@ -1,2 +1,2 @@ -module("_mkfs.py", base_path="$(PORT_DIR)/modules/scripts", opt=3) +module("_boot.py", base_path="$(PORT_DIR)/modules/scripts", opt=3) include("$(MPY_DIR)/extmod/asyncio") diff --git a/ports/nrf/modules/nrf/flashbdev.c b/ports/nrf/modules/nrf/flashbdev.c index 41833b228e2ff..b28314b4a62b3 100644 --- a/ports/nrf/modules/nrf/flashbdev.c +++ b/ports/nrf/modules/nrf/flashbdev.c @@ -183,12 +183,26 @@ static mp_obj_t nrf_flashbdev_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(self); } +static mp_int_t nrf_flashbdev_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + nrf_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (flags == MP_BUFFER_READ) { + bufinfo->buf = (void *)self->start; + bufinfo->len = self->len; + bufinfo->typecode = 'B'; + return 0; + } else { + // Unsupported. + return 1; + } +} + MP_DEFINE_CONST_OBJ_TYPE( nrf_flashbdev_type, MP_QSTR_Flash, MP_TYPE_FLAG_NONE, make_new, nrf_flashbdev_make_new, print, nrf_flashbdev_print, + buffer, nrf_flashbdev_get_buffer, locals_dict, &nrf_flashbdev_locals_dict ); @@ -202,4 +216,34 @@ void flashbdev_init(void) { nrf_flash_obj.len = num_pages * FLASH_PAGESIZE; } +#if MICROPY_VFS_ROM + +extern byte _micropy_hw_romfs_part0_start[]; +extern byte _micropy_hw_romfs_part0_size[]; + +#define MICROPY_HW_ROMFS_BASE ((uint32_t)_micropy_hw_romfs_part0_start) +#define MICROPY_HW_ROMFS_BYTES ((uint32_t)_micropy_hw_romfs_part0_size) + +static nrf_flash_obj_t nrf_flash_romfs_obj = { + .base = { &nrf_flashbdev_type }, + .start = MICROPY_HW_ROMFS_BASE, // Get from MCU-Specific loader script. + .len = MICROPY_HW_ROMFS_BYTES, // Get from MCU-Specific loader script. +}; + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (MICROPY_HW_ROMFS_BYTES <= 0) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&nrf_flash_romfs_obj); + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} + +#endif // MICROPY_VFS_ROM + #endif // MICROPY_PY_NRF && MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE diff --git a/ports/nrf/modules/scripts/_boot.py b/ports/nrf/modules/scripts/_boot.py new file mode 100644 index 0000000000000..793c56ee149a3 --- /dev/null +++ b/ports/nrf/modules/scripts/_boot.py @@ -0,0 +1,28 @@ +def setup_fs(): + import gc + import vfs + import sys + import nrf + import os + + fs_type = getattr(vfs, "VfsLfs2", getattr(vfs, "VfsLfs1", getattr(vfs, "VfsFat", None))) + try: + bdev = nrf.Flash() + vfs.mount(bdev, "/flash") + except: + if fs_type is not None: + try: + fs_type.mkfs(bdev) + vfs.mount(bdev, "/flash") + except: + return + + os.chdir("/flash") + sys.path.append("/flash") + sys.path.append("/flash/lib") + + gc.collect() + + +setup_fs() +del setup_fs diff --git a/ports/nrf/modules/scripts/_mkfs.py b/ports/nrf/modules/scripts/_mkfs.py deleted file mode 100644 index 601f9558eb7b5..0000000000000 --- a/ports/nrf/modules/scripts/_mkfs.py +++ /dev/null @@ -1,23 +0,0 @@ -import vfs, nrf - -try: - from vfs import VfsLfs1 - - vfs.VfsLfs1.mkfs(nrf.Flash()) -except ImportError: - try: - from vfs import VfsLfs2 - - vfs.VfsLfs2.mkfs(nrf.Flash()) - except ImportError: - try: - from vfs import VfsFat - - vfs.VfsFat.mkfs(nrf.Flash()) - except ImportError: - pass - except OSError as e: - if e.args[0] == 5: # I/O Error - flashbdev_size = (nrf.Flash.ioctl(4, 0) * nrf.Flash.ioctl(5, 0)) // 1024 - print() - print("Is `FS_SIZE=%iK` enough for FAT filesystem?" % flashbdev_size) diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index cce3f86cfd244..bb517c19c5599 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -69,6 +69,11 @@ #define MICROPY_VFS (CORE_FEAT) #endif +// VfsROM filesystem +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (CORE_FEAT) +#endif + // micro:bit filesystem #ifndef MICROPY_MBFS #define MICROPY_MBFS (!MICROPY_VFS) diff --git a/ports/qemu/Makefile b/ports/qemu/Makefile index ba9c53841aee5..3bc46ffefdc4b 100644 --- a/ports/qemu/Makefile +++ b/ports/qemu/Makefile @@ -153,7 +153,8 @@ endif ################################################################################ # Project specific settings and compiler/linker flags -QEMU_SYSTEM = qemu-system-$(QEMU_ARCH) +QEMU_BASE ?= qemu-system- +QEMU_SYSTEM = $(QEMU_BASE)$(QEMU_ARCH) QEMU_ARGS += -machine $(QEMU_MACHINE) -nographic -monitor null -semihosting QEMU_ARGS += $(QEMU_EXTRA) @@ -163,6 +164,9 @@ QEMU_DEBUG_ARGS ?= -s QEMU_ARGS += -S $(QEMU_DEBUG_ARGS) $(QEMU_DEBUG_EXTRA) endif +# Allow selecting a subset of natmods to test. +TEST_NATMODS ?= btree deflate framebuf heapq random_basic re + INC += -I. INC += -I$(TOP) INC += -I$(BUILD) @@ -264,7 +268,7 @@ test_full: $(BUILD)/firmware.elf test_natmod: $(BUILD)/firmware.elf $(eval DIRNAME=ports/$(notdir $(CURDIR))) cd $(TOP)/tests && \ - for natmod in btree deflate framebuf heapq random_basic re; do \ + for natmod in $(TEST_NATMODS); do \ ./run-natmodtests.py -t execpty:"$(QEMU_SYSTEM) $(QEMU_ARGS) -serial pty -kernel ../$(DIRNAME)/$<" $(RUN_TESTS_EXTRA) extmod/$$natmod*.py; \ done diff --git a/ports/qemu/README.md b/ports/qemu/README.md index bf5788961dbe9..e6c16e3662d95 100644 --- a/ports/qemu/README.md +++ b/ports/qemu/README.md @@ -142,8 +142,7 @@ tests against the serial device, for example: $ ./run-tests.py -t /dev/pts/1 Selected native modules that come as examples with the MicroPython source tree -can also be tested with this command (this is currently not supported for the -`VIRT_RV64` board): +can also be tested with this command: $ make test_natmod @@ -157,11 +156,18 @@ The following options can be specified on the `make` command line: - `CFLAGS_EXTRA`: pass in extra flags for the compiler. - `RUN_TESTS_EXTRA`: pass in extra flags for `run-tests.py` and `run-natmodtests.py` when invoked via `make test` or `make test_natmod`. +- `QEMU_BASE`: pass an optional partial path of the qemu binary to run code with, eg. + `/opt/custom-directory/qemu/bin/qemu-system-`, similar to how a cross compiler name + is passed to the MicroPython makefile. By default it will use the appropriate QEMU + binary found through the system's PATH environment variable. - `QEMU_DEBUG=1`: when running qemu (via `repl`, `run` or `test` target), qemu will block until a debugger is connected. By default it waits for a gdb connection on TCP port 1234. - `QEMU_DEBUG_ARGS`: defaults to `-s` (gdb on TCP port 1234), but can be overridden with different qemu gdb arguments. - `QEMU_DEBUG_EXTRA`: extra options to pass to qemu when `QEMU_DEBUG=1` is used. +- `TEST_NATMODS`: pass an optional list of space-separated names of natmods to test, + so only the given subset of example natmods will be used by `test_natmod` (for + example, `make test_natmod TEST_NATMODS="btree heapq re"`). - `MICROPY_HEAP_SIZE`: pass in an optional value (in bytes) for overriding the GC heap size used by the port. diff --git a/ports/qemu/mpconfigport.h b/ports/qemu/mpconfigport.h index dcaf6a5c51e6f..522c59263285d 100644 --- a/ports/qemu/mpconfigport.h +++ b/ports/qemu/mpconfigport.h @@ -39,10 +39,16 @@ #define MICROPY_EMIT_INLINE_THUMB (1) #endif #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1)) -#elif defined(__riscv) && (__riscv_xlen == 32) +#elif defined(__riscv) +#if (__riscv_xlen == 32) #define MICROPY_EMIT_RV32 (1) #define MICROPY_EMIT_RV32_ZBA (1) #define MICROPY_EMIT_INLINE_RV32 (1) +#elif (__riscv_xlen == 64) +#define MICROPY_PERSISTENT_CODE_LOAD_NATIVE (1) +#else +#error "Unsupported RISC-V platform!" +#endif #endif #define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1) diff --git a/ports/qemu/mphalport.c b/ports/qemu/mphalport.c index bd3d653eed55b..a4fa32e297f4e 100644 --- a/ports/qemu/mphalport.c +++ b/ports/qemu/mphalport.c @@ -25,6 +25,7 @@ */ #include "py/mphal.h" +#include "py/runtime.h" #include "py/stream.h" #include "shared/runtime/semihosting_arm.h" #include "uart.h" @@ -82,8 +83,12 @@ mp_uint_t mp_hal_ticks_us(void) { } void mp_hal_delay_ms(mp_uint_t ms) { - mp_uint_t start = mp_hal_ticks_ms(); - while (mp_hal_ticks_ms() - start < ms) { + if (ms) { + mp_uint_t start = mp_hal_ticks_ms(); + while (mp_hal_ticks_ms() - start < ms) { + } + } else { + mp_handle_pending(true); } } diff --git a/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/mpconfigboard.mk b/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/mpconfigboard.mk index 9bb336d65e9d5..69333eab4abe6 100644 --- a/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/mpconfigboard.mk +++ b/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/mpconfigboard.mk @@ -3,8 +3,9 @@ MCU_SERIES = m33 LD_FILES = boards/ARDUINO_PORTENTA_C33/ra6m5.ld CFLAGS += -DCFG_TUH_MAX_SPEED=OPT_MODE_FULL_SPEED \ -DCFG_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED \ - -DCFG_TUSB_RHPORT0_MODE=0\ - -DCFG_TUSB_RHPORT1_MODE=OPT_MODE_DEVICE + -DCFG_TUSB_RHPORT0_MODE=0 \ + -DCFG_TUSB_RHPORT1_MODE=OPT_MODE_DEVICE \ + -DCFG_TUD_TASK_QUEUE_SZ=128 # MicroPython settings MICROPY_VFS_FAT = 1 diff --git a/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/ra6m5.ld b/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/ra6m5.ld index c1fac5106c37e..a937e01cdf514 100644 --- a/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/ra6m5.ld +++ b/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/ra6m5.ld @@ -6,7 +6,8 @@ MEMORY { FLASH_BOOT (r) : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64K */ - FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 0x000f0000 /* 960KB */ + FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 0x000B0000 /* 704KB/2MB */ + FLASH_ROMFS (r) : ORIGIN = 0x000C0000, LENGTH = 0x00040000 /* 256KB/2MB */ FLASH_FS (r) : ORIGIN = 0x00100000, LENGTH = 0x00100000 /* 1MB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00080000 /* 512KB */ OSPI_RAM (rwx) : ORIGIN = 0x68000000, LENGTH = 0x00800000 /* 8MB/8MB */ @@ -304,3 +305,6 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part0_size = LENGTH(FLASH_ROMFS); diff --git a/ports/renesas-ra/boards/EK_RA4M1/ra4m1_ek.ld b/ports/renesas-ra/boards/EK_RA4M1/ra4m1_ek.ld index 52f8acf93eb33..e6e4cb3d31559 100644 --- a/ports/renesas-ra/boards/EK_RA4M1/ra4m1_ek.ld +++ b/ports/renesas-ra/boards/EK_RA4M1/ra4m1_ek.ld @@ -3,9 +3,14 @@ */ /* Linker script to configure memory regions. */ +/* + * FLASH_ROMFS and FLASH_FS must start and length must be a multiple + * of the physical sector size of that region (2k). + */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00037000 /* 220KB/256KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00034000 /* 208KB/256KB */ + FLASH_ROMFS (r) : ORIGIN = 0x00034000, LENGTH = 0x00003000 /* 12KB/256KB */ FLASH_FS (r) : ORIGIN = 0x00037000, LENGTH = 0x00009000 /* 36KB/256KB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 /* 32KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00002000 /* 8KB */ @@ -300,3 +305,6 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part0_size = LENGTH(FLASH_ROMFS); diff --git a/ports/renesas-ra/boards/EK_RA4W1/ra4w1_ek.ld b/ports/renesas-ra/boards/EK_RA4W1/ra4w1_ek.ld index 1241b5bc2302b..7c021207a40ed 100644 --- a/ports/renesas-ra/boards/EK_RA4W1/ra4w1_ek.ld +++ b/ports/renesas-ra/boards/EK_RA4W1/ra4w1_ek.ld @@ -3,9 +3,14 @@ */ /* Linker script to configure memory regions. */ +/* + * FLASH_ROMFS and FLASH_FS must start and length must be a multiple + * of the physical sector size of that region (2k). + */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00070000 /* 448KB/512KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00060000 /* 384KB/512KB */ + FLASH_ROMFS (r) : ORIGIN = 0x00060000, LENGTH = 0x00010000 /* 64KB/512KB */ FLASH_FS (r) : ORIGIN = 0x00070000, LENGTH = 0x00010000 /* 64KB/512KB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00018000 /* 96KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00002000 /* 8KB */ @@ -300,3 +305,6 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part0_size = LENGTH(FLASH_ROMFS); diff --git a/ports/renesas-ra/boards/EK_RA6M1/ra6m1_ek.ld b/ports/renesas-ra/boards/EK_RA6M1/ra6m1_ek.ld index c7d85ed3db0a1..876525d717b2c 100644 --- a/ports/renesas-ra/boards/EK_RA6M1/ra6m1_ek.ld +++ b/ports/renesas-ra/boards/EK_RA6M1/ra6m1_ek.ld @@ -5,7 +5,8 @@ /* Linker script to configure memory regions. */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00070000 /* 448KB/512KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00060000 /* 384KB/512KB */ + FLASH_ROMFS (r) : ORIGIN = 0x00060000, LENGTH = 0x00010000 /* 64KB/512KB */ FLASH_FS (r) : ORIGIN = 0x00070000, LENGTH = 0x00010000 /* 64KB/512KB */ RAM (rwx) : ORIGIN = 0x1FFE0000, LENGTH = 0x00040000 /* 256KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00002000 /* 8KB */ @@ -300,3 +301,6 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part0_size = LENGTH(FLASH_ROMFS); diff --git a/ports/renesas-ra/boards/EK_RA6M2/ra6m2_ek.ld b/ports/renesas-ra/boards/EK_RA6M2/ra6m2_ek.ld index 086f6630c110a..423cf63b70105 100644 --- a/ports/renesas-ra/boards/EK_RA6M2/ra6m2_ek.ld +++ b/ports/renesas-ra/boards/EK_RA6M2/ra6m2_ek.ld @@ -3,9 +3,15 @@ */ /* Linker script to configure memory regions. */ + +/* + * FLASH_ROMFS and FLASH_FS must start and length must be a multiple + * of the physical sector size of that region (32k). + */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x000e0000 /* 896KB/1MB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x000A0000 /* 768KB/1MB */ + FLASH_ROMFS (r) : ORIGIN = 0x000A0000, LENGTH = 0x00040000 /* 256KB/1MB */ FLASH_FS (r) : ORIGIN = 0x000e0000, LENGTH = 0x00020000 /* 128KB/1MB */ RAM (rwx) : ORIGIN = 0x1FFE0000, LENGTH = 0x00060000 /* 384KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00008000 /* 32KB */ @@ -300,3 +306,6 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part0_size = LENGTH(FLASH_ROMFS); diff --git a/ports/renesas-ra/boards/RA4M1_CLICKER/ra4m1_clicker.ld b/ports/renesas-ra/boards/RA4M1_CLICKER/ra4m1_clicker.ld index 52f8acf93eb33..92d34ba336662 100644 --- a/ports/renesas-ra/boards/RA4M1_CLICKER/ra4m1_clicker.ld +++ b/ports/renesas-ra/boards/RA4M1_CLICKER/ra4m1_clicker.ld @@ -5,7 +5,8 @@ /* Linker script to configure memory regions. */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00037000 /* 220KB/256KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00034000 /* 208KB/256KB */ + FLASH_ROMFS (r) : ORIGIN = 0x00034000, LENGTH = 0x00003000 /* 12KB/256KB */ FLASH_FS (r) : ORIGIN = 0x00037000, LENGTH = 0x00009000 /* 36KB/256KB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 /* 32KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00002000 /* 8KB */ @@ -300,3 +301,6 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part0_size = LENGTH(FLASH_ROMFS); diff --git a/ports/renesas-ra/boards/VK_RA6M5/vk_ra6m5.ld b/ports/renesas-ra/boards/VK_RA6M5/vk_ra6m5.ld index 8363d2e743f24..82e9bbb4bd2b2 100644 --- a/ports/renesas-ra/boards/VK_RA6M5/vk_ra6m5.ld +++ b/ports/renesas-ra/boards/VK_RA6M5/vk_ra6m5.ld @@ -5,7 +5,8 @@ /* Linker script to configure memory regions. */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00100000 /* 1MB/2MB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x000A0000 /* 640KB/2MB */ + FLASH_ROMFS (r) : ORIGIN = 0x000A0000, LENGTH = 0x00060000 /* 384KB/2MB */ FLASH_FS (r) : ORIGIN = 0x00100000, LENGTH = 0x00100000 /* 1MB/2MB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00080000 /* 512KB */ OSPI_RAM (rwx) : ORIGIN = 0x68000000, LENGTH = 0x00800000 /* 8MB/8MB */ @@ -306,3 +307,6 @@ _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); _micropy_hw_external_flash_storage_start = ORIGIN(QSPI_FLASH); _micropy_hw_external_flash_storage_end = ORIGIN(QSPI_FLASH) + LENGTH(QSPI_FLASH); + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part0_size = LENGTH(FLASH_ROMFS); diff --git a/ports/renesas-ra/mpconfigboard_common.h b/ports/renesas-ra/mpconfigboard_common.h index 479c9f61d1a68..a1aa4c0539e03 100644 --- a/ports/renesas-ra/mpconfigboard_common.h +++ b/ports/renesas-ra/mpconfigboard_common.h @@ -154,6 +154,11 @@ #define MICROPY_HW_UART_IS_RESERVED(uart_id) (false) #endif +// Whether to support the VFSROM file system +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (1) +#endif + /*****************************************************************************/ // General configuration diff --git a/ports/renesas-ra/pin.h b/ports/renesas-ra/pin.h index 76d6c0b1e430d..649f1f2fcea75 100644 --- a/ports/renesas-ra/pin.h +++ b/ports/renesas-ra/pin.h @@ -41,9 +41,9 @@ typedef struct { typedef struct { mp_obj_base_t base; - qstr name; - uint8_t pin; const machine_pin_adc_obj_t *ad; + qstr_short_t name; + uint8_t pin; } machine_pin_obj_t; // Include all of the individual pin objects diff --git a/ports/renesas-ra/storage.c b/ports/renesas-ra/storage.c index 12416e4dc7a9f..4262a5ab651e9 100644 --- a/ports/renesas-ra/storage.c +++ b/ports/renesas-ra/storage.c @@ -28,6 +28,7 @@ #include #include +#include "py/objarray.h" #include "py/runtime.h" #include "py/mperrno.h" #include "extmod/vfs_fat.h" @@ -36,6 +37,13 @@ #include "led.h" #include "storage.h" #include "irq.h" +#include "flash.h" + +typedef struct _pyb_flash_obj_t { + mp_obj_base_t base; + uint32_t start; // in bytes + uint32_t len; // in bytes +} pyb_flash_obj_t; #if MICROPY_HW_ENABLE_STORAGE @@ -236,12 +244,6 @@ int storage_readblocks_ext(uint8_t *dest, uint32_t block, uint32_t offset, uint3 } #endif -typedef struct _pyb_flash_obj_t { - mp_obj_base_t base; - uint32_t start; // in bytes - uint32_t len; // in bytes -} pyb_flash_obj_t; - // This Flash object represents the entire available flash, with emulated partition table at start const pyb_flash_obj_t pyb_flash_obj = { { &pyb_flash_type }, @@ -427,3 +429,57 @@ void pyb_flash_init_vfs(fs_user_mount_t *vfs) { } #endif + +#if MICROPY_VFS_ROM + +extern uint32_t _micropy_hw_romfs_part0_start, _micropy_hw_romfs_part0_size; + +#define MICROPY_HW_ROMFS_BASE ((uint32_t)&_micropy_hw_romfs_part0_start) +#define MICROPY_HW_ROMFS_BYTES ((uint32_t)&_micropy_hw_romfs_part0_size) +#define VFSROM_BLOCK_SIZE (2048) + +static const MP_DEFINE_MEMORYVIEW_OBJ(romfs_obj, 'B', 0, MICROPY_HW_ROMFS_BYTES, (void *)MICROPY_HW_ROMFS_BASE); + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (MICROPY_HW_ROMFS_BYTES <= 0) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&romfs_obj); + + case MP_VFS_ROM_IOCTL_WRITE_PREPARE: { + // Erase sectors in given range. + if (n_args < 3) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest = MICROPY_HW_ROMFS_BASE; + uint32_t dest_max = dest + mp_obj_get_int(args[2]); + uint32_t sec_size = sector_size(dest); + for (; dest < dest_max; dest += sec_size) { + flash_erase(dest, sec_size); + } + return MP_OBJ_NEW_SMALL_INT(4); // minimum write size + } + + case MP_VFS_ROM_IOCTL_WRITE: { + // Write data to flash. + if (n_args < 4) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest = MICROPY_HW_ROMFS_BASE + mp_obj_get_int(args[2]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + flash_write(dest, bufinfo.buf, bufinfo.len); + return MP_OBJ_NEW_SMALL_INT(0); + } + + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} + +#endif // MICROPY_VFS_ROM diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index c4a081e2efd54..d88a96d4a7074 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -487,7 +487,16 @@ list(APPEND MICROPY_SOURCE_QSTR ) # Define mpy-cross flags -set(MICROPY_CROSS_FLAGS -march=armv6m) +if (${PICO_PLATFORM} STREQUAL "rp2040") + set(MICROPY_CROSS_FLAGS "-march=armv6m") +elseif (${PICO_PLATFORM} STREQUAL "rp2350-arm-s") + set(MICROPY_CROSS_FLAGS "-march=armv7m") +elseif (${PICO_PLATFORM} STREQUAL "rp2350-riscv") + set(MICROPY_CROSS_FLAGS "-march=rv32imc -march-flags=zba,zcmp") +else() + message(WARNING "Unknown PICO_PLATFORM version (${PICO_PLATFORM}), falling back to rp2040") + set(MICROPY_CROSS_FLAGS "-march=armv6m") +endif() # Set the frozen manifest file if (MICROPY_USER_FROZEN_MANIFEST) diff --git a/ports/rp2/boards/WEACTSTUDIO_RP2350B_CORE/manifest.py b/ports/rp2/boards/WEACTSTUDIO_RP2350B_CORE/manifest.py index 832942f052606..7ae2ed15d9169 100644 --- a/ports/rp2/boards/WEACTSTUDIO_RP2350B_CORE/manifest.py +++ b/ports/rp2/boards/WEACTSTUDIO_RP2350B_CORE/manifest.py @@ -1 +1,2 @@ include("$(PORT_DIR)/boards/manifest.py") +freeze("modules") diff --git a/ports/rp2/boards/WEACTSTUDIO_RP2350B_CORE/modules/board.py b/ports/rp2/boards/WEACTSTUDIO_RP2350B_CORE/modules/board.py new file mode 100644 index 0000000000000..8e3cc2953da88 --- /dev/null +++ b/ports/rp2/boards/WEACTSTUDIO_RP2350B_CORE/modules/board.py @@ -0,0 +1,8 @@ +import deflate +import io + +_compressed_pinout = b'(\x91\xcd\x92\xbdn\xdb0\x10\xc7w\xbdB\x96\x1b\x93M$E\xc9\x82\xa7:Q\x83"A\x1c\xd8\x89;d*\x1a\x0f\x1d\x04\x03A:t\x0b\xbc6F:HA\x91%C\xbb\x14h\x9d\x89amo\xa7\xaf\xde_\xc3\xf8\xfa\xe3\xe5\x87\x19\x8cN)\xe3\xee\x00\xf6gWS\x18\xcc\xde]]\xfe\r\xdc\xb9pc\xc7\x01\x83\x89\xf4\x97Hn\xe4\x82Q4\x8e\xceVqG\xd3O\xb0{(\xab\xeeA\xee\xceV\xba\x94\xf1\xc9|3i0\x1c\x9eUk\xaf\xbd\xffp\xa5KG\x82\xb1^\x9f\xf7\t\x8f\xa58\xd9\x8ey1P?\'\x06\x83\x9b\xaf\xdc\x12\xa4\x88\xa0\xd4\x8d\xc5\xedou\xac9*p\xd2e}\xb3\x81[\xbb\x8d\x12?\x86\xfd\xe3\xa3\xe2:\xd0\x95\xae\x1f)y\xf5/\xf7P0\xa0\xach\xb5!\xbd\x87\xeb\x12\xb4\xd7%\x99\x8b\x9f\xdf\xb3om\x93\xeb"\xff\x986\x07o\x86\xe5\x17uV\x866(CPe\x98\x8b+\x13v\x98\x98g5\x1fO\xf5M\xed\x8aL\tq\xf7\xa0\xae\xc8&J\xa9fV\x8e\xc8\xf7N\x98\x8a\xb6U\r\xc7\x06\x12\xe2\xaa\xe1\xa23\xd2Z5i\xc7\xd1\xc1\xba\x1c\rcq\xffc\xe5\xd9\xae\xc4\xd6\x17Y\xcf\x1c\xe95\xa8\x17\xe0\xeay\xb8z\xac\x83z\xbb\x87\xa7\x94\xef\xc9\x8dx\xfc,\x1e\x17\xb0a\xb6\xb0~\x03,\xc7a\xf1t\xc6\xbb\x8cJn\x125\xff-^\x0e\x16o\r\x10\x86\xc3\xe2\x83\xc1\x82\xae\xb0\x05j\x05\xd7\x16\x966\xc0\x12#,\xed\xc5\xe0\xb98l\xd8\x1dv\xa1\xe1\xb6\x85\xc5_\x0b\x10\xe2\xb0f\xad\x94\x9b\xd8\x8c\xf1\xa2\x82j\r\x0b\xf8\x1c\x02\x048\xac\x87\xc3\xb2\xee\xb0\n\xb7\x84j\x0f\xeb7\xc0r\x1c\xd6\x9c\xae\xdc\xdc\x06\xb6l\xb6\xa0\xe6\xb6\xe4\xa0l\x05\n\xa3\xf3\x130\x01\x05\xff\x0f\x10m\x00"\xc6\xce\x91\x18\xd8\x84\x99\xb2K\xde\xd6\x98"\xb9\x15\xc9Mm}y1l\x17\x9d\xb8\xc9(zm\xc4\xf63\xa0\xbb\x87j\x01\x7f]\x80\xca\x0b\xa2\x13C\x8b\xef\xbf5\xb3\xcf+\x9b\n\xaf\xa6D~\xa4\xe75=X\x13\xd0\x96\xd9\x18\xd0\x0c]\x1cm\r\xdd\xb2\xc9r\xfc\xf8\xc4\xfc\\\xd9\xe2\xc1\xf9\xb8\xc0-\x9bH\x9fu\xa3W_\x89\xee\xf0\xebV\xb9\xe9\x93\xe3\xfc\x01\x83\'\xd6K' + + +def pinout(): + print(str(deflate.DeflateIO(io.BytesIO(_compressed_pinout), deflate.ZLIB).read(), "utf-8")) diff --git a/ports/rp2/boards/make-pins.py b/ports/rp2/boards/make-pins.py index 07ce052bba3ca..9f48806ffca8f 100755 --- a/ports/rp2/boards/make-pins.py +++ b/ports/rp2/boards/make-pins.py @@ -60,7 +60,7 @@ def add_af(self, af_idx, _af_name, af): m = re.match("([A-Z][A-Z0-9][A-Z]+)(([0-9]+)(_.*)?)?", af) af_fn = m.group(1) af_unit = int(m.group(3)) if m.group(3) is not None else 0 - if af_idx == 10: + if af_idx == 11: # AF11 uses UART_AUX in lieu of UART af_fn = "UART_AUX" if af_fn.startswith("QMI"): @@ -74,7 +74,7 @@ def add_af(self, af_idx, _af_name, af): # pin can only be I2C0 _or_ I2C1, both sharing the same AF # index), so each PIO unit has a distinct AF index. af_fn = "{:s}{:d}".format(af_fn, af_unit) - self._afs.append((af_idx + 1, af_fn, af_unit, af)) + self._afs.append((af_idx, af_fn, af_unit, af)) # This will be called at the start of the output (after the prefix). Use # it to emit the af objects (via the AF() macro in rp2_prefix.c). diff --git a/ports/rp2/boards/rp2040_af.csv b/ports/rp2/boards/rp2040_af.csv index 454f7ed2d12ab..13ccca28265ac 100644 --- a/ports/rp2/boards/rp2040_af.csv +++ b/ports/rp2/boards/rp2040_af.csv @@ -1,31 +1,31 @@ -Pin,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9 -GPIO0,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,,USB_OVCUR_DET -GPIO1,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,,USB_VBUS_DET -GPIO2,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,,USB_VBUS_EN -GPIO3,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,,USB_OVCUR_DET -GPIO4,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,,USB_VBUS_DET -GPIO5,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,,USB_VBUS_EN -GPIO6,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,,USB_OVCUR_DET -GPIO7,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,,USB_VBUS_DET -GPIO8,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,,USB_VBUS_EN -GPIO9,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,,USB_OVCUR_DET -GPIO10,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,,USB_VBUS_DET -GPIO11,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,,USB_VBUS_EN -GPIO12,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,,USB_OVCUR_DET -GPIO13,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,,USB_VBUS_DET -GPIO14,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,,USB_VBUS_EN -GPIO15,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,,USB_OVCUR_DET -GPIO16,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,,USB_VBUS_DET -GPIO17,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,,USB_VBUS_EN -GPIO18,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,,USB_OVCUR_DET -GPIO19,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,,USB_VBUS_DET -GPIO20,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,GPCK_GPIN0,USB_VBUS_EN -GPIO21,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,GPCK_GPOUT0,USB_OVCUR_DET -GPIO22,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,GPCK_GPIN1,USB_VBUS_DET -GPIO23,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,GPCK_GPOUT1,USB_VBUS_EN -GPIO24,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,GPCK_GPOUT2,USB_OVCUR_DET -GPIO25,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,GPCK_GPOUT3,USB_VBUS_DET -GPIO26,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,,USB_VBUS_EN -GPIO27,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,,USB_OVCUR_DET -GPIO28,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,,USB_VBUS_DET -GPIO29,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,,USB_VBUS_EN +Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9 +GPIO0,,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO1,,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO2,,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO3,,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO4,,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO5,,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO6,,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO7,,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO8,,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO9,,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO10,,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO11,,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO12,,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO13,,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO14,,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO15,,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO16,,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO17,,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO18,,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO19,,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO20,,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,GPCK_GPIN0,USB_VBUS_EN +GPIO21,,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,GPCK_GPOUT0,USB_OVCUR_DET +GPIO22,,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,GPCK_GPIN1,USB_VBUS_DET +GPIO23,,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,GPCK_GPOUT1,USB_VBUS_EN +GPIO24,,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,GPCK_GPOUT2,USB_OVCUR_DET +GPIO25,,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,GPCK_GPOUT3,USB_VBUS_DET +GPIO26,,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,,USB_VBUS_EN +GPIO27,,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,,USB_OVCUR_DET +GPIO28,,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,,USB_VBUS_DET +GPIO29,,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,,USB_VBUS_EN diff --git a/ports/rp2/boards/rp2350_af.csv b/ports/rp2/boards/rp2350_af.csv index cca30d9e74c8c..285c175bbde7e 100644 --- a/ports/rp2/boards/rp2350_af.csv +++ b/ports/rp2/boards/rp2350_af.csv @@ -1,31 +1,31 @@ -Pin,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11 -GPIO0,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_OVCUR_DET, -GPIO1,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,TRACECLK,USB_VBUS_DET, -GPIO2,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,TRACEDATA0,USB_VBUS_EN,UART0_TX -GPIO3,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,TRACEDATA1,USB_OVCUR_DET,UART0_RX -GPIO4,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,TRACEDATA2,USB_VBUS_DET, -GPIO5,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,TRACEDATA3,USB_VBUS_EN, -GPIO6,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX -GPIO7,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX -GPIO8,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN, -GPIO9,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, -GPIO10,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_TX -GPIO11,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_RX -GPIO12,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_OVCUR_DET, -GPIO13,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_VBUS_DET, -GPIO14,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_EN,UART0_TX -GPIO15,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_OVCUR_DET,UART0_RX -GPIO16,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, -GPIO17,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, -GPIO18,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX -GPIO19,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_DET,UART0_RX -GPIO20,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_VBUS_EN, -GPIO21,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_OVCUR_DET, -GPIO22,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_DET,UART1_TX -GPIO23,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_VBUS_EN,UART1_RX -GPIO24,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT2,USB_OVCUR_DET, -GPIO25,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT3,USB_VBUS_DET, -GPIO26,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX -GPIO27,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX -GPIO28,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, -GPIO29,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, +Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11 +GPIO0,,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_OVCUR_DET, +GPIO1,,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,TRACECLK,USB_VBUS_DET, +GPIO2,,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,TRACEDATA0,USB_VBUS_EN,UART0_TX +GPIO3,,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,TRACEDATA1,USB_OVCUR_DET,UART0_RX +GPIO4,,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,TRACEDATA2,USB_VBUS_DET, +GPIO5,,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,TRACEDATA3,USB_VBUS_EN, +GPIO6,,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX +GPIO7,,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX +GPIO8,,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN, +GPIO9,,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, +GPIO10,,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_TX +GPIO11,,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_RX +GPIO12,HSTX,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_OVCUR_DET, +GPIO13,HSTX,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_VBUS_DET, +GPIO14,HSTX,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_EN,UART0_TX +GPIO15,HSTX,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_OVCUR_DET,UART0_RX +GPIO16,HSTX,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, +GPIO17,HSTX,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, +GPIO18,HSTX,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX +GPIO19,HSTX,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_DET,UART0_RX +GPIO20,,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_VBUS_EN, +GPIO21,,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_OVCUR_DET, +GPIO22,,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_DET,UART1_TX +GPIO23,,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_VBUS_EN,UART1_RX +GPIO24,,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT2,USB_OVCUR_DET, +GPIO25,,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT3,USB_VBUS_DET, +GPIO26,,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX +GPIO27,,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX +GPIO28,,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, +GPIO29,,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, diff --git a/ports/rp2/boards/rp2350b_af.csv b/ports/rp2/boards/rp2350b_af.csv index 3b9053f58cd4d..d30762f5853f7 100644 --- a/ports/rp2/boards/rp2350b_af.csv +++ b/ports/rp2/boards/rp2350b_af.csv @@ -1,49 +1,49 @@ -Pin,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11 -GPIO0,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_OVCUR_DET, -GPIO1,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,TRACECLK,USB_VBUS_DET, -GPIO2,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,TRACEDATA0,USB_VBUS_EN,UART0_TX -GPIO3,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,TRACEDATA1,USB_OVCUR_DET,UART0_RX -GPIO4,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,TRACEDATA2,USB_VBUS_DET, -GPIO5,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,TRACEDATA3,USB_VBUS_EN, -GPIO6,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX -GPIO7,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX -GPIO8,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN, -GPIO9,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, -GPIO10,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_TX -GPIO11,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_RX -GPIO12,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_OVCUR_DET, -GPIO13,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_VBUS_DET, -GPIO14,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_EN,UART0_TX -GPIO15,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_OVCUR_DET,UART0_RX -GPIO16,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, -GPIO17,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, -GPIO18,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX -GPIO19,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_DET,UART0_RX -GPIO20,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_VBUS_EN, -GPIO21,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_OVCUR_DET, -GPIO22,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_DET,UART1_TX -GPIO23,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_VBUS_EN,UART1_RX -GPIO24,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT2,USB_OVCUR_DET, -GPIO25,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT3,USB_VBUS_DET, -GPIO26,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX -GPIO27,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX -GPIO28,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, -GPIO29,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, -GPIO30,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX -GPIO31,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_RX -GPIO32,SPI0_RX,UART0_TX,I2C0_SDA,PWM8_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, -GPIO33,SPI0_CS,UART0_RX,I2C0_SCL,PWM8_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, -GPIO34,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM9_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_TX -GPIO35,SPI0_TX,UART0_RTS,I2C1_SCL,PWM9_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART0_RX -GPIO36,SPI0_RX,UART1_TX,I2C0_SDA,PWM10_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, -GPIO37,SPI0_CS,UART1_RX,I2C0_SCL,PWM10_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, -GPIO38,SPI0_SCK,UART1_CTS,I2C1_SCL,PWM11_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX -GPIO39,SPI0_TX,UART1_RTS,I2C1_SCL,PWM11_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX -GPIO40,SPI1_RX,UART1_TX,I2C0_SDA,PWM8_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, -GPIO41,SPI1_CS,UART1_RX,I2C0_SCL,PWM8_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, -GPIO42,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM9_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX -GPIO43,SPI1_TX,UART1_RTS,I2C1_SCL,PWM9_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX -GPIO44,SPI1_RX,UART0_TX,I2C0_SDA,PWM10_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, -GPIO45,SPI1_CS,UART0_RX,I2C0_SCL,PWM10_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, -GPIO46,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM11_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_TX -GPIO47,SPI1_TX,UART0_RTS,I2C1_SCL,PWM11_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN,UART0_RX +Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11 +GPIO0,,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_OVCUR_DET, +GPIO1,,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,TRACECLK,USB_VBUS_DET, +GPIO2,,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,TRACEDATA0,USB_VBUS_EN,UART0_TX +GPIO3,,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,TRACEDATA1,USB_OVCUR_DET,UART0_RX +GPIO4,,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,TRACEDATA2,USB_VBUS_DET, +GPIO5,,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,TRACEDATA3,USB_VBUS_EN, +GPIO6,,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX +GPIO7,,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX +GPIO8,,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN, +GPIO9,,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, +GPIO10,,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_TX +GPIO11,,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_RX +GPIO12,HSTX,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_OVCUR_DET, +GPIO13,HSTX,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_VBUS_DET, +GPIO14,HSTX,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_EN,UART0_TX +GPIO15,HSTX,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_OVCUR_DET,UART0_RX +GPIO16,HSTX,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, +GPIO17,HSTX,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, +GPIO18,HSTX,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX +GPIO19,HSTX,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_DET,UART0_RX +GPIO20,,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_VBUS_EN, +GPIO21,,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_OVCUR_DET, +GPIO22,,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_DET,UART1_TX +GPIO23,,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_VBUS_EN,UART1_RX +GPIO24,,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT2,USB_OVCUR_DET, +GPIO25,,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT3,USB_VBUS_DET, +GPIO26,,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX +GPIO27,,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX +GPIO28,,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, +GPIO29,,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, +GPIO30,,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX +GPIO31,,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_RX +GPIO32,,SPI0_RX,UART0_TX,I2C0_SDA,PWM8_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, +GPIO33,,SPI0_CS,UART0_RX,I2C0_SCL,PWM8_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, +GPIO34,,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM9_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_TX +GPIO35,,SPI0_TX,UART0_RTS,I2C1_SCL,PWM9_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART0_RX +GPIO36,,SPI0_RX,UART1_TX,I2C0_SDA,PWM10_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, +GPIO37,,SPI0_CS,UART1_RX,I2C0_SCL,PWM10_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, +GPIO38,,SPI0_SCK,UART1_CTS,I2C1_SCL,PWM11_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX +GPIO39,,SPI0_TX,UART1_RTS,I2C1_SCL,PWM11_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX +GPIO40,,SPI1_RX,UART1_TX,I2C0_SDA,PWM8_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET, +GPIO41,,SPI1_CS,UART1_RX,I2C0_SCL,PWM8_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, +GPIO42,,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM9_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX +GPIO43,,SPI1_TX,UART1_RTS,I2C1_SCL,PWM9_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX +GPIO44,,SPI1_RX,UART0_TX,I2C0_SDA,PWM10_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN, +GPIO45,,SPI1_CS,UART0_RX,I2C0_SCL,PWM10_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET, +GPIO46,,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM11_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_TX +GPIO47,,SPI1_TX,UART0_RTS,I2C1_SCL,PWM11_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN,UART0_RX diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c index e1a184f322cbb..336e6ff5a233d 100644 --- a/ports/rp2/machine_pin.c +++ b/ports/rp2/machine_pin.c @@ -521,6 +521,7 @@ static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_ALT_GPCK), MP_ROM_INT(GPIO_FUNC_GPCK) }, { MP_ROM_QSTR(MP_QSTR_ALT_USB), MP_ROM_INT(GPIO_FUNC_USB) }, #if PICO_RP2350 + { MP_ROM_QSTR(MP_QSTR_ALT_HSTX), MP_ROM_INT(GPIO_FUNC_HSTX) }, { MP_ROM_QSTR(MP_QSTR_ALT_XIP_CS1), MP_ROM_INT(GPIO_FUNC_XIP_CS1) }, { MP_ROM_QSTR(MP_QSTR_ALT_CORESIGHT_TRACE), MP_ROM_INT(GPIO_FUNC_CORESIGHT_TRACE) }, { MP_ROM_QSTR(MP_QSTR_ALT_UART_AUX), MP_ROM_INT(GPIO_FUNC_UART_AUX) }, diff --git a/ports/rp2/machine_pin.h b/ports/rp2/machine_pin.h index 2d85bdcadc165..47c0d328e56c1 100644 --- a/ports/rp2/machine_pin.h +++ b/ports/rp2/machine_pin.h @@ -40,7 +40,7 @@ enum { typedef struct _machine_pin_af_obj_t { mp_obj_base_t base; - qstr name; + qstr_short_t name; uint8_t idx : 4; uint8_t fn : 4; uint8_t unit : 8; @@ -48,7 +48,7 @@ typedef struct _machine_pin_af_obj_t { typedef struct _machine_pin_obj_t { mp_obj_base_t base; - qstr name; + qstr_short_t name; uint8_t id : 6; #if MICROPY_HW_PIN_EXT_COUNT uint8_t is_ext : 1; diff --git a/ports/rp2/main.c b/ports/rp2/main.c index f01522f243807..50946b0a5ca2d 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -192,7 +192,9 @@ int main(int argc, char **argv) { machine_pin_init(); rp2_pio_init(); rp2_dma_init(); + #if MICROPY_PY_MACHINE_I2S machine_i2s_init0(); + #endif #if MICROPY_PY_BLUETOOTH mp_bluetooth_hci_init(); diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 6ce90e4f1f473..1bcd7384911b4 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -110,6 +110,7 @@ #elif PICO_RISCV #define MICROPY_EMIT_RV32 (1) #define MICROPY_EMIT_RV32_ZBA (1) +#define MICROPY_EMIT_RV32_ZCMP (1) #define MICROPY_EMIT_INLINE_RV32 (1) #endif @@ -151,6 +152,9 @@ #define MICROPY_PY_OS_URANDOM (1) #define MICROPY_PY_RE_MATCH_GROUPS (1) #define MICROPY_PY_RE_MATCH_SPAN_START_END (1) +#define MICROPY_PY_HASHLIB_MD5 (1) +#define MICROPY_PY_HASHLIB_SHA1 (1) +#define MICROPY_PY_CRYPTOLIB (1) #define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1) #define MICROPY_PY_TIME_TIME_TIME_NS (1) #define MICROPY_PY_TIME_INCLUDEFILE "ports/rp2/modtime.c" diff --git a/ports/rp2/rp2_dma.c b/ports/rp2/rp2_dma.c index 94c61e226e695..471cf24ea2ce5 100644 --- a/ports/rp2/rp2_dma.c +++ b/ports/rp2/rp2_dma.c @@ -427,6 +427,14 @@ static mp_obj_t rp2_dma_close(mp_obj_t self_in) { uint8_t channel = self->channel; if (channel != CHANNEL_CLOSED) { + // Reset this channel's registers to their default values (zeros). + dma_channel_config config = { .ctrl = 0 }; + dma_channel_configure(channel, &config, NULL, NULL, 0, false); + + // Abort this channel. Must be done after clearing EN bit in control + // register due to errata RP2350-E5. + dma_channel_abort(channel); + // Clean up interrupt handler to ensure garbage collection mp_irq_obj_t *irq = MP_STATE_PORT(rp2_dma_irq_obj[channel]); MP_STATE_PORT(rp2_dma_irq_obj[channel]) = MP_OBJ_NULL; diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 611e74a1587d2..81351431cb937 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -271,12 +271,32 @@ static void asm_pio_get_pins(PIO pio, const char *type, mp_obj_t prog_pins, mp_o } } +static inline uint32_t rotl32a(const uint32_t x, const int k) { + return (x << k) | (x >> (32 - k)); +} + static void asm_pio_init_gpio(PIO pio, uint32_t sm, asm_pio_config_t *config) { - uint32_t pinmask = ((1 << config->count) - 1) << (config->base - pio_get_gpio_base(pio)); - pio_sm_set_pins_with_mask(pio, sm, config->pinvals << (config->base - pio_get_gpio_base(pio)), pinmask); - pio_sm_set_pindirs_with_mask(pio, sm, config->pindirs << (config->base - pio_get_gpio_base(pio)), pinmask); - for (size_t i = 0; i < config->count; ++i) { - gpio_set_function(config->base + i, GPIO_FUNC_PIO0 + pio_get_index(pio)); + uint gpio_base = pio_get_gpio_base(pio); + uint32_t pinmask = rotl32a(~(-1 << config->count), config->base - gpio_base); + uint32_t pinvals = rotl32a(config->pinvals, config->base - gpio_base); + uint32_t pindirs = rotl32a(config->pindirs, config->base - gpio_base); + + #if !PICO_PIO_USE_GPIO_BASE + // optimization: avoid 64-bit arithmetic on RP2040 and RP2350A + pio_sm_set_pins_with_mask(pio, sm, pinvals, pinmask); + pio_sm_set_pindirs_with_mask(pio, sm, pindirs, pinmask); + #else + uint64_t pinmask64 = (uint64_t)pinmask << gpio_base; + uint64_t pinvals64 = (uint64_t)pinvals << gpio_base; + uint64_t pindirs64 = (uint64_t)pindirs << gpio_base; + pio_sm_set_pins_with_mask64(pio, sm, pinvals64, pinmask64); + pio_sm_set_pindirs_with_mask64(pio, sm, pindirs64, pinmask64); + #endif + + for (size_t i = 0; i < 32; ++i) { + if (pinmask & (1 << i)) { + gpio_set_function(gpio_base + i, GPIO_FUNC_PIO0 + pio_get_index(pio)); + } } } diff --git a/ports/samd/Makefile b/ports/samd/Makefile index bec530d803f7e..3344be7502637 100644 --- a/ports/samd/Makefile +++ b/ports/samd/Makefile @@ -90,7 +90,7 @@ CFLAGS += $(CFLAGS_EXTRA) CFLAGS += -DMICROPY_HW_CODESIZE=$(strip $(subst K,' ', $(MICROPY_HW_CODESIZE))) LDFLAGS += -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref -LDFLAGS += --defsym=_codesize=$(MICROPY_HW_CODESIZE) +LDFLAGS += --defsym=_codesize=$(MICROPY_HW_CODESIZE) --defsym=_micropy_hw_romfs_part0_size=$(MICROPY_HW_ROMFS_BYTES) LIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) @@ -103,6 +103,10 @@ CFLAGS += -Os -DNDEBUG LDFLAGS += --gc-sections --print-memory-usage CFLAGS += -fdata-sections -ffunction-sections endif +# Disable VFSROM support if the size was set to 0 +ifeq ($(MICROPY_HW_ROMFS_BYTES),0) + CFLAGS += -DMICROPY_VFS_ROM=0 +endif # Flags for optional C++ source code CXXFLAGS += $(filter-out -std=c99,$(CFLAGS)) diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk index e2895c7c0c2f9..6e1c7375a2e6a 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk @@ -5,4 +5,4 @@ TEXT0 = 0x2000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 248K +MICROPY_HW_CODESIZE ?= 236K diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.mk index 6ec2d43dedbd8..dbce935140cc5 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.mk @@ -5,4 +5,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_ROMFS_BYTES +# The default for MICROPY_HW_ROMFS_BYTES is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.mk index e2895c7c0c2f9..6e1c7375a2e6a 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.mk @@ -5,4 +5,4 @@ TEXT0 = 0x2000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 248K +MICROPY_HW_CODESIZE ?= 236K diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk index 740154a6d6825..fb6ec0eb27985 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk @@ -5,4 +5,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_ROMFS_BYTES +# The default for MICROPY_HW_ROMFS_BYTES is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk index 43ca5a59cc636..9ab91a8521e6a 100644 --- a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk @@ -7,4 +7,7 @@ TEXT0 = 0x4000 MICROPY_PY_NETWORK ?= 1 MICROPY_PY_NETWORK_NINAW10 ?= 1 -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_ROMFS_BYTES +# The default for MICROPY_HW_ROMFS_BYTES is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/ADAFRUIT_QTPY_SAMD21/mpconfigvariant_SPIFLASH.mk b/ports/samd/boards/ADAFRUIT_QTPY_SAMD21/mpconfigvariant_SPIFLASH.mk index 69537d5bf3c51..b5d11f7e89969 100644 --- a/ports/samd/boards/ADAFRUIT_QTPY_SAMD21/mpconfigvariant_SPIFLASH.mk +++ b/ports/samd/boards/ADAFRUIT_QTPY_SAMD21/mpconfigvariant_SPIFLASH.mk @@ -1,2 +1,2 @@ CFLAGS += -DMICROPY_HW_SPIFLASH=1 -MICROPY_HW_CODESIZE ?= 232K +MICROPY_HW_CODESIZE ?= 236K diff --git a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk index 54948627d2b67..a1b97af0564b0 100644 --- a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk +++ b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk @@ -6,4 +6,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_ROMFS_BYTES +# The default for MICROPY_HW_ROMFS_BYTES is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk index cc43c22cea588..a396c543a42c8 100644 --- a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk @@ -3,4 +3,4 @@ CMSIS_MCU = SAMD21J18A LD_FILES = boards/samd21x18a.ld sections.ld TEXT0 = 0x2000 -MICROPY_HW_CODESIZE ?= 248K +MICROPY_HW_CODESIZE ?= 236K diff --git a/ports/samd/boards/SAMD_GENERIC_D51X19/mpconfigboard.mk b/ports/samd/boards/SAMD_GENERIC_D51X19/mpconfigboard.mk index 1a20643214f1a..5c3664267de88 100644 --- a/ports/samd/boards/SAMD_GENERIC_D51X19/mpconfigboard.mk +++ b/ports/samd/boards/SAMD_GENERIC_D51X19/mpconfigboard.mk @@ -6,6 +6,6 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings # The size of a MCU flash filesystem will be -# 496k - MICROPY_HW_CODESIZE - MICROPY_HW_VFSROMSIZE -# The default for MICROPY_HW_VFSROMSIZE is 64K +# 496k - MICROPY_HW_CODESIZE - MICROPY_HW_ROMFS_BYTES +# The default for MICROPY_HW_ROMFS_BYTES is 64K MICROPY_HW_CODESIZE ?= 368K diff --git a/ports/samd/boards/SAMD_GENERIC_D51X20/mpconfigboard.mk b/ports/samd/boards/SAMD_GENERIC_D51X20/mpconfigboard.mk index b240c2587f8d0..2e000225d54fd 100644 --- a/ports/samd/boards/SAMD_GENERIC_D51X20/mpconfigboard.mk +++ b/ports/samd/boards/SAMD_GENERIC_D51X20/mpconfigboard.mk @@ -7,5 +7,6 @@ TEXT0 = 0x4000 # MicroPython settings # The size of a MCU flash filesystem will be # 1008k - MICROPY_HW_CODESIZE -# The default for MICROPY_HW_VFSROMSIZE is 64K +# The default for MICROPY_HW_ROMFS_BYTES is 64K MICROPY_HW_CODESIZE ?= 752K +MICROPY_HW_ROMFS_BYTES ?= 256K diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk index 7bf70ac669566..bb14efe7e8013 100644 --- a/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk +++ b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk @@ -5,4 +5,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_ROMFS_BYTES +# The default for MICROPY_HW_ROMFS_BYTES is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/SPARKFUN_REDBOARD_TURBO/mpconfigboard.mk b/ports/samd/boards/SPARKFUN_REDBOARD_TURBO/mpconfigboard.mk index 6ea327a650d40..6e1c7375a2e6a 100644 --- a/ports/samd/boards/SPARKFUN_REDBOARD_TURBO/mpconfigboard.mk +++ b/ports/samd/boards/SPARKFUN_REDBOARD_TURBO/mpconfigboard.mk @@ -5,4 +5,4 @@ TEXT0 = 0x2000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 232K +MICROPY_HW_CODESIZE ?= 236K diff --git a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.mk b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.mk index 263e582694495..2ee0b2cca5e22 100644 --- a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.mk +++ b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.mk @@ -5,4 +5,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 1008K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_ROMFS_BYTES +MICROPY_HW_CODESIZE ?= 752K +MICROPY_HW_ROMFS_BYTES ?= 256K diff --git a/ports/samd/boards/pins_prefix.c b/ports/samd/boards/pins_prefix.c index 4f0095d332130..24378593393bc 100644 --- a/ports/samd/boards/pins_prefix.c +++ b/ports/samd/boards/pins_prefix.c @@ -11,11 +11,11 @@ #if defined(MCU_SAMD21) #define PIN(p_name, p_eic, p_adc0, p_sercom1, p_sercom2, p_tcc1, p_tcc2) \ - {{&machine_pin_type}, PIN_##p_name, MP_QSTR_##p_name, p_eic, p_adc0, p_sercom1, p_sercom2, p_tcc1, p_tcc2 } + {{&machine_pin_type}, MP_QSTR_##p_name, PIN_##p_name, p_eic, p_adc0, p_sercom1, p_sercom2, p_tcc1, p_tcc2 } #elif defined(MCU_SAMD51) #define PIN(p_name, p_eic, p_adc0, p_adc1, p_sercom1, p_sercom2, p_tc, p_tcc1, p_tcc2) \ - {{&machine_pin_type}, PIN_##p_name, MP_QSTR_##p_name, p_eic, p_adc0, p_adc1, p_sercom1, p_sercom2, p_tc, p_tcc1, p_tcc2 } + {{&machine_pin_type}, MP_QSTR_##p_name, PIN_##p_name, p_eic, p_adc0, p_adc1, p_sercom1, p_sercom2, p_tc, p_tcc1, p_tcc2 } #endif diff --git a/ports/samd/boards/samd21x18a.ld b/ports/samd/boards/samd21x18a.ld index 3ab051569fb18..5bb031d9c0713 100644 --- a/ports/samd/boards/samd21x18a.ld +++ b/ports/samd/boards/samd21x18a.ld @@ -3,8 +3,8 @@ */ /* -_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as -MICROPY_HW_CODESIZE and is set in Makefile +_codesize and _micropy_hw_romfs_part0_size are defined in mpconfigmcu.mk or mpconfigboard.mk +as MICROPY_HW_CODESIZE and MICROPY_HW_ROMFS_BYTES and are set in Makefile. */ _flashsize = 256K; /* The physical flash size */ @@ -21,8 +21,17 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM) - 8; _sstack = _estack - 8K; -_oflash_fs = ORIGIN(FLASH) + _codesize; -_sflash_fs = _flashsize - _codesize - _bootloader; +/* +The VfsROM file system is placed at the end of the flash. +For device with SPI flash the number for _sflash_fs might be 0 and +the origin beyond the end of the flash. That does not matter since +these devices do not use the MCU flash file system. +*/ + +_oflash_fs = ORIGIN(FLASH) + _codesize + _micropy_hw_romfs_part0_size; +_sflash_fs = _flashsize - _codesize - _bootloader - _micropy_hw_romfs_part0_size; + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH) + _codesize; _sheap = _ebss; _eheap = _sstack; diff --git a/ports/samd/boards/samd51x19a.ld b/ports/samd/boards/samd51x19a.ld index 30bc8e33281fb..77ae8656d4a78 100644 --- a/ports/samd/boards/samd51x19a.ld +++ b/ports/samd/boards/samd51x19a.ld @@ -3,8 +3,8 @@ */ /* -_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as -MICROPY_HW_CODESIZE and is set in Makefile +_codesize and _micropy_hw_romfs_part0_size are defined in mpconfigmcu.mk or mpconfigboard.mk +as MICROPY_HW_CODESIZE and MICROPY_HW_ROMFS_BYTES and are set in Makefile. */ _flashsize = 512K; /* The physical flash size */ @@ -21,8 +21,17 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM) - 8; _sstack = _estack - 16K; -_oflash_fs = ORIGIN(FLASH) + _codesize; -_sflash_fs = _flashsize - _codesize - _bootloader; +/* +The VfsROM file system is placed at the end of the flash. +For device with SPI flash the number for _sflash_fs might be 0 and +the origin beyond the end of the flash. That does not matter since +these devices do not use the MCU flash file system. +*/ + +_oflash_fs = ORIGIN(FLASH) + _codesize + _micropy_hw_romfs_part0_size; +_sflash_fs = _flashsize - _codesize - _bootloader - _micropy_hw_romfs_part0_size; + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH) + _codesize; _sheap = _ebss; _eheap = _sstack; diff --git a/ports/samd/boards/samd51x20a.ld b/ports/samd/boards/samd51x20a.ld index 472ab316c6fde..595042128d550 100644 --- a/ports/samd/boards/samd51x20a.ld +++ b/ports/samd/boards/samd51x20a.ld @@ -3,8 +3,8 @@ */ /* -_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as -MICROPY_HW_CODESIZE and is set in Makefile +_codesize and _micropy_hw_romfs_part0_size are defined in mpconfigmcu.mk or mpconfigboard.mk +as MICROPY_HW_CODESIZE and MICROPY_HW_ROMFS_BYTES and are set in Makefile. */ _flashsize = 1024K; /* The physical flash size */ @@ -21,8 +21,17 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM) - 8; _sstack = _estack - 16K; -_oflash_fs = ORIGIN(FLASH) + _codesize; -_sflash_fs = _flashsize - _codesize - _bootloader; +/* +The VfsROM file system is placed at the end of the flash. +For device with SPI flash the number for _sflash_fs might be 0 and +the origin beyond the end of the flash. That does not matter since +these devices do not use the MCU flash file system. +*/ + +_oflash_fs = ORIGIN(FLASH) + _codesize + _micropy_hw_romfs_part0_size; +_sflash_fs = _flashsize - _codesize - _bootloader - _micropy_hw_romfs_part0_size; + +_micropy_hw_romfs_part0_start = ORIGIN(FLASH) + _codesize; _sheap = _ebss; _eheap = _sstack; diff --git a/ports/samd/mcu/samd21/manifest.py b/ports/samd/mcu/samd21/manifest.py index 2a19a843f8a9b..8ad1e38ba099a 100644 --- a/ports/samd/mcu/samd21/manifest.py +++ b/ports/samd/mcu/samd21/manifest.py @@ -1,5 +1,2 @@ include("$(PORT_DIR)/boards/manifest.py") include("$(MPY_DIR)/extmod/asyncio") -require("onewire") -require("ds18x20") -require("dht") diff --git a/ports/samd/mcu/samd21/mpconfigmcu.h b/ports/samd/mcu/samd21/mpconfigmcu.h index a29d5c0a04db4..a757893943b73 100644 --- a/ports/samd/mcu/samd21/mpconfigmcu.h +++ b/ports/samd/mcu/samd21/mpconfigmcu.h @@ -2,11 +2,6 @@ #include "samd21.h" #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES) -#if MICROPY_HW_CODESIZE == 248 -#define SAMD21_EXTRA_FEATURES 1 -#else -#define SAMD21_EXTRA_FEATURES 0 -#endif // MicroPython emitters #define MICROPY_EMIT_THUMB (SAMD21_EXTRA_FEATURES) diff --git a/ports/samd/mcu/samd21/mpconfigmcu.mk b/ports/samd/mcu/samd21/mpconfigmcu.mk index 34209775c2565..b809a47679ab2 100644 --- a/ports/samd/mcu/samd21/mpconfigmcu.mk +++ b/ports/samd/mcu/samd21/mpconfigmcu.mk @@ -6,8 +6,13 @@ MPY_CROSS_MCU_ARCH = armv6m MICROPY_HW_CODESIZE ?= 184K -ifeq ($(MICROPY_HW_CODESIZE), 248K) +ifeq ($(MICROPY_HW_CODESIZE), 236K) FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest.py +MICROPY_HW_ROMFS_BYTES ?= 12K +CFLAGS_MCU += -DSAMD21_EXTRA_FEATURES=1 +else +MICROPY_HW_ROMFS_BYTES ?= 0 +CFLAGS_MCU += -DSAMD21_EXTRA_FEATURES=0 endif MICROPY_VFS_LFS1 ?= 1 diff --git a/ports/samd/mcu/samd51/manifest.py b/ports/samd/mcu/samd51/manifest.py index 2a19a843f8a9b..8ad1e38ba099a 100644 --- a/ports/samd/mcu/samd51/manifest.py +++ b/ports/samd/mcu/samd51/manifest.py @@ -1,5 +1,2 @@ include("$(PORT_DIR)/boards/manifest.py") include("$(MPY_DIR)/extmod/asyncio") -require("onewire") -require("ds18x20") -require("dht") diff --git a/ports/samd/mcu/samd51/mpconfigmcu.h b/ports/samd/mcu/samd51/mpconfigmcu.h index a1ff208eb5939..974a40f7aa76c 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.h +++ b/ports/samd/mcu/samd51/mpconfigmcu.h @@ -21,10 +21,10 @@ unsigned long trng_random_u32(void); #endif // fatfs configuration used in ffconf.h -#define MICROPY_FATFS_ENABLE_LFN (1) -#define MICROPY_FATFS_RPATH (2) -#define MICROPY_FATFS_MAX_SS (4096) -#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MAX_SS (4096) +#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define VFS_BLOCK_SIZE_BYTES (2048) // diff --git a/ports/samd/mcu/samd51/mpconfigmcu.mk b/ports/samd/mcu/samd51/mpconfigmcu.mk index 9bef5eca166ab..f10faec47f434 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.mk +++ b/ports/samd/mcu/samd51/mpconfigmcu.mk @@ -5,6 +5,7 @@ CFLAGS_MCU += -DCFG_TUSB_MCU=OPT_MCU_SAMD51 MPY_CROSS_MCU_ARCH = armv7m MICROPY_HW_CODESIZE ?= 368K +MICROPY_HW_ROMFS_BYTES ?= 64K MICROPY_VFS_LFS2 ?= 1 MICROPY_VFS_FAT ?= 1 diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h index 32009ae82f298..131861d2bd8cc 100644 --- a/ports/samd/mpconfigport.h +++ b/ports/samd/mpconfigport.h @@ -86,6 +86,9 @@ #define MICROPY_PY_OS_INCLUDEFILE "ports/samd/modos.c" #define MICROPY_READER_VFS (1) #define MICROPY_VFS (1) +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (1) +#endif #ifndef MICROPY_PY_MACHINE_ADC #define MICROPY_PY_MACHINE_ADC (1) #endif diff --git a/ports/samd/pin_af.h b/ports/samd/pin_af.h index bc65e8ae23bf9..11ef75c63f51e 100644 --- a/ports/samd/pin_af.h +++ b/ports/samd/pin_af.h @@ -32,8 +32,8 @@ typedef struct _machine_pin_obj_t { mp_obj_base_t base; + qstr_short_t name; uint8_t pin_id; - qstr name; uint8_t eic; uint8_t adc0; uint8_t sercom1; @@ -50,8 +50,8 @@ typedef struct _machine_pin_obj_t { typedef struct _machine_pin_obj_t { mp_obj_base_t base; + qstr_short_t name; uint8_t pin_id; - qstr name; uint8_t eic; uint8_t adc0; uint8_t adc1; diff --git a/ports/samd/samd_flash.c b/ports/samd/samd_flash.c index f68bdf140f490..c99df9d0f8990 100644 --- a/ports/samd/samd_flash.c +++ b/ports/samd/samd_flash.c @@ -26,11 +26,13 @@ #include +#include "py/objarray.h" #include "py/runtime.h" #include "extmod/vfs.h" +#include "py/mperrno.h" #include "samd_soc.h" -#if MICROPY_HW_MCUFLASH +#if MICROPY_HW_MCUFLASH || MICROPY_VFS_ROM // ASF 4 #include "hal_flash.h" @@ -45,7 +47,6 @@ #endif static struct flash_descriptor flash_desc; -static mp_int_t BLOCK_SIZE = VFS_BLOCK_SIZE_BYTES; // Board specific: mpconfigboard.h extern const mp_obj_type_t samd_flash_type; typedef struct _samd_flash_obj_t { @@ -54,8 +55,9 @@ typedef struct _samd_flash_obj_t { uint32_t flash_size; } samd_flash_obj_t; +#if MICROPY_HW_MCUFLASH +static mp_int_t BLOCK_SIZE = VFS_BLOCK_SIZE_BYTES; // Board specific: mpconfigboard.h extern uint8_t _oflash_fs, _sflash_fs; - // Build a Flash storage at top. static samd_flash_obj_t samd_flash_obj = { .base = { &samd_flash_type }, @@ -63,9 +65,31 @@ static samd_flash_obj_t samd_flash_obj = { .flash_size = (uint32_t)&_sflash_fs, // Get from MCU-Specific loader script. }; +static mp_obj_t samd_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // No args required. bdev=Flash(). Start Addr & Size defined in samd_flash_obj. + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // Return singleton object. + return MP_OBJ_FROM_PTR(&samd_flash_obj); +} + +static mp_int_t samd_flash_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + samd_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (flags == MP_BUFFER_READ) { + bufinfo->buf = (void *)((uintptr_t)self->flash_base); + bufinfo->len = self->flash_size; + bufinfo->typecode = 'B'; + return 0; + } else { + // Write unsupported. + return 1; + } +} +#endif // MICROPY_HW_MCUFLASH + // Flash init (from cctpy) // Method is needed for when MP starts up in _boot.py -static void samd_flash_init(void) { +void samd_flash_init(void) { #ifdef SAMD51 hri_mclk_set_AHBMASK_NVMCTRL_bit(MCLK); #endif @@ -76,23 +100,14 @@ static void samd_flash_init(void) { flash_init(&flash_desc, NVMCTRL); } -static mp_obj_t samd_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - // No args required. bdev=Flash(). Start Addr & Size defined in samd_flash_obj. - mp_arg_check_num(n_args, n_kw, 0, 0, false); - - samd_flash_init(); - - // Return singleton object. - return MP_OBJ_FROM_PTR(&samd_flash_obj); -} - +#if MICROPY_HW_MCUFLASH // Function for ioctl. static mp_obj_t eraseblock(uint32_t sector_in) { // Destination address aligned with page start to be erased. - uint32_t DEST_ADDR = sector_in; // Number of pages to be erased. - mp_int_t PAGE_SIZE = flash_get_page_size(&flash_desc); // adf4 API call + uint32_t dest_addr = sector_in; // Number of pages to be erased. + mp_int_t page_size = flash_get_page_size(&flash_desc); // adf4 API call - flash_erase(&flash_desc, DEST_ADDR, (BLOCK_SIZE / PAGE_SIZE)); + flash_erase(&flash_desc, dest_addr, (BLOCK_SIZE / page_size)); return mp_const_none; } @@ -131,7 +146,7 @@ static mp_obj_t samd_flash_writeblocks(size_t n_args, const mp_obj_t *args) { } // Write data to flash (adf4 API) flash_write(&flash_desc, offset, bufinfo.buf, bufinfo.len); - // TODO check return value + return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(samd_flash_writeblocks_obj, 3, 4, samd_flash_writeblocks); @@ -176,7 +191,75 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_QSTR_Flash, MP_TYPE_FLAG_NONE, make_new, samd_flash_make_new, + buffer, samd_flash_get_buffer, locals_dict, &samd_flash_locals_dict ); +#endif -#endif // MICROPY_HW_MCUFLASH +#if MICROPY_VFS_ROM +// +// Uses object-based capabilities for devices using the internal flash +// for the regular file system and ioctl function for devices with +// external flash. +// +extern uint8_t _micropy_hw_romfs_part0_start, _micropy_hw_romfs_part0_size; + +#define MICROPY_HW_ROMFS_BASE ((uint32_t)&_micropy_hw_romfs_part0_start) +#define MICROPY_HW_ROMFS_BYTES ((uint32_t)&_micropy_hw_romfs_part0_size) + +#if MICROPY_HW_MCUFLASH +static samd_flash_obj_t samd_flash_romfs_obj = { + .base = { &samd_flash_type }, + .flash_base = MICROPY_HW_ROMFS_BASE, // Get from MCU-Specific loader script. + .flash_size = MICROPY_HW_ROMFS_BYTES, // Get from MCU-Specific loader script. +}; +#else +static const MP_DEFINE_MEMORYVIEW_OBJ(samd_flash_romfs_obj, 'B', 0, MICROPY_HW_ROMFS_BYTES, (void *)MICROPY_HW_ROMFS_BASE); +#endif + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (MICROPY_HW_ROMFS_BYTES <= 0) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&samd_flash_romfs_obj); + + #if !MICROPY_HW_MCUFLASH + + case MP_VFS_ROM_IOCTL_WRITE_PREPARE: { + // Erase sectors in given range. + if (n_args < 3) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest_addr = MICROPY_HW_ROMFS_BASE; + uint32_t bytes_used = mp_obj_get_int(args[2]); + mp_int_t page_size = flash_get_page_size(&flash_desc); // adf4 API call + flash_erase(&flash_desc, dest_addr, (bytes_used + page_size - 1) / page_size); + return MP_OBJ_NEW_SMALL_INT(4); + } + + case MP_VFS_ROM_IOCTL_WRITE: { + // Write data to flash. + if (n_args < 4) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest_addr = MICROPY_HW_ROMFS_BASE + mp_obj_get_int(args[2]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + flash_write(&flash_desc, dest_addr, bufinfo.buf, bufinfo.len); + return MP_OBJ_NEW_SMALL_INT(0); + } + + #endif + + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} +#endif + +#endif // MICROPY_HW_MCUFLASH || MICROPY_VFS_ROM diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c index fb6eb2083a304..761eb8d1aae6a 100644 --- a/ports/samd/samd_soc.c +++ b/ports/samd/samd_soc.c @@ -39,6 +39,7 @@ #include "tusb.h" extern void machine_rtc_start(bool force); +extern void samd_flash_init(void); static void usb_init(void) { // Init USB clock @@ -120,6 +121,9 @@ void samd_init(void) { mp_hal_ticks_cpu_enable(); #endif machine_rtc_start(false); + #if MICROPY_HW_MCUFLASH || MICROPY_VFS_ROM + samd_flash_init(); + #endif } #if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_I2C_TARGET || MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_UART diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index b43f284b1abee..c0bf4be32e93d 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -72,7 +72,7 @@ PYDFU ?= $(TOP)/tools/pydfu.py DFU_UTIL ?= dfu-util BOOTLOADER_DFU_USB_VID ?= 0x0483 BOOTLOADER_DFU_USB_PID ?= 0xDF11 -STFLASH ?= st-flash +STFLASH ?= st-flash --connect-under-reset OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 326fc97b25104..ec55175af7313 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -134,11 +134,13 @@ defined(STM32F407xx) || defined(STM32F417xx) || \ defined(STM32F401xC) || defined(STM32F401xE) #define VBAT_DIV (2) -#elif defined(STM32F411xE) || defined(STM32F412Zx) || \ +#elif defined(STM32F411xE) || \ + defined(STM32F412Cx) || defined(STM32F412Rx) || \ + defined(STM32F412Vx) || defined(STM32F412Zx) || \ defined(STM32F413xx) || defined(STM32F427xx) || \ defined(STM32F429xx) || defined(STM32F437xx) || \ defined(STM32F439xx) || defined(STM32F446xx) || \ - defined(STM32F479xx) + defined(STM32F479xx) || defined(STM32F469xx) #define VBAT_DIV (4) #elif defined(STM32F722xx) || defined(STM32F723xx) || \ defined(STM32F732xx) || defined(STM32F733xx) || \ @@ -154,7 +156,7 @@ defined(STM32H743xx) || defined(STM32H747xx) || \ defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \ defined(STM32H7B3xx) || defined(STM32H7B3xxQ) || \ - defined(STM32H750xx) + defined(STM32H750xx) || defined(STM32H753xx) #define VBAT_DIV (4) #elif defined(STM32L432xx) || \ defined(STM32L451xx) || defined(STM32L452xx) || \ diff --git a/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.mk index 2fbb4ddbe2dd9..1deebe6f1e96c 100644 --- a/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.mk @@ -1,7 +1,7 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F412Zx AF_FILE = boards/stm32f412_af.csv -LD_FILES = boards/stm32f412zx.ld boards/common_ifs.ld +LD_FILES = boards/stm32f412xg.ld boards/common_ifs.ld TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_G474RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_G474RE/mpconfigboard.h index e807a54780d98..66e5339450706 100644 --- a/ports/stm32/boards/NUCLEO_G474RE/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_G474RE/mpconfigboard.h @@ -9,16 +9,6 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (0) // QSPI extflash not mounted -#define MICROPY_PY_ASYNCIO (0) -#define MICROPY_PY_DEFLATE (0) -#define MICROPY_PY_BINASCII (0) -#define MICROPY_PY_HASHLIB (0) -#define MICROPY_PY_JSON (0) -#define MICROPY_PY_RE (0) -#define MICROPY_PY_FRAMEBUF (0) -#define MICROPY_PY_SOCKET (0) -#define MICROPY_PY_NETWORK (0) - // The board has an 24MHz HSE, the following gives 170MHz CPU speed #define MICROPY_HW_CLK_PLLM (6) #define MICROPY_HW_CLK_PLLN (85) diff --git a/ports/stm32/boards/NUCLEO_H723ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H723ZG/mpconfigboard.mk index b05da481f65ee..fcb235c8688df 100644 --- a/ports/stm32/boards/NUCLEO_H723ZG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_H723ZG/mpconfigboard.mk @@ -24,3 +24,6 @@ MICROPY_VFS_LFS2 = 1 MICROPY_HW_ENABLE_ISR_UART_FLASH_FUNCS_IN_RAM = 1 FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py + +# Flash tool configuration +OPENOCD_CONFIG = boards/openocd_stm32h7_dual_bank.cfg diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h index 4c053828fab5e..9078a3ef77ff9 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -17,7 +17,7 @@ void NUCLEO_H743ZI_board_early_init(void); #define MICROPY_HW_CLK_PLLM (4) #define MICROPY_HW_CLK_PLLN (400) #define MICROPY_HW_CLK_PLLP (2) -#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_PLLQ (8) #define MICROPY_HW_CLK_PLLR (2) #define MICROPY_HW_CLK_PLLVCI (RCC_PLL1VCIRANGE_1) #define MICROPY_HW_CLK_PLLVCO (RCC_PLL1VCOWIDE) @@ -37,14 +37,16 @@ void NUCLEO_H743ZI_board_early_init(void); #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 // UART config +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B15) #define MICROPY_HW_UART2_TX (pin_D5) #define MICROPY_HW_UART2_RX (pin_D6) #define MICROPY_HW_UART2_RTS (pin_D4) #define MICROPY_HW_UART2_CTS (pin_D3) #define MICROPY_HW_UART3_TX (pin_D8) #define MICROPY_HW_UART3_RX (pin_D9) -#define MICROPY_HW_UART5_TX (pin_B6) -#define MICROPY_HW_UART5_RX (pin_B12) +// #define MICROPY_HW_UART5_TX (pin_B6) // conflict with UART1_TX +// #define MICROPY_HW_UART5_RX (pin_B12) // conflict with Ethernet MII mode #define MICROPY_HW_UART6_TX (pin_C6) #define MICROPY_HW_UART6_RX (pin_C7) #define MICROPY_HW_UART7_TX (pin_F7) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk index 35e62c470ac5e..0f528939c9d2c 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk @@ -24,3 +24,6 @@ MICROPY_VFS_LFS2 = 1 MICROPY_HW_ENABLE_ISR_UART_FLASH_FUNCS_IN_RAM = 1 FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py + +# Flash tool configuration +OPENOCD_CONFIG = boards/openocd_stm32h7_dual_bank.cfg diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv index d3647ca42a3ea..9c1ad7d71031f 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -105,6 +105,8 @@ USB_VBUS,PA9 USB_ID,PA10 USB_DM,PA11 USB_DP,PA12 +UART1_TX,PB6 +UART1_RX,PB15 UART2_TX,PD5 UART2_RX,PD6 UART2_RTS,PD4 diff --git a/ports/stm32/boards/NUCLEO_H743ZI2/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI2/pins.csv index 450d6e432ae3f..7d964c1ab682d 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI2/pins.csv +++ b/ports/stm32/boards/NUCLEO_H743ZI2/pins.csv @@ -105,6 +105,8 @@ USB_VBUS,PA9 USB_ID,PA10 USB_DM,PA11 USB_DP,PA12 +UART1_TX,PB6 +UART1_RX,PB15 UART2_TX,PD5 UART2_RX,PD6 UART2_RTS,PD4 diff --git a/ports/stm32/boards/NUCLEO_H753ZI/board.json b/ports/stm32/boards/NUCLEO_H753ZI/board.json new file mode 100644 index 0000000000000..ec3e75c0de694 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H753ZI/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_h753zi.jpg" + ], + "mcu": "stm32h7", + "product": "Nucleo H753ZI", + "thumbnail": "", + "url": "https://www.st.com/en/evaluation-tools/nucleo-h753zi.html", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_H753ZI/board_init.c b/ports/stm32/boards/NUCLEO_H753ZI/board_init.c new file mode 100644 index 0000000000000..04caaaca9e4fa --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H753ZI/board_init.c @@ -0,0 +1 @@ +#include "boards/NUCLEO_H743ZI/board_init.c" diff --git a/ports/stm32/boards/NUCLEO_H753ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H753ZI/mpconfigboard.h new file mode 100644 index 0000000000000..a92fd6b0355ea --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H753ZI/mpconfigboard.h @@ -0,0 +1,7 @@ +#include "boards/NUCLEO_H743ZI2/mpconfigboard.h" + +#undef MICROPY_HW_BOARD_NAME +#define MICROPY_HW_BOARD_NAME "NUCLEO_H753ZI" + +#undef MICROPY_HW_MCU_NAME +#define MICROPY_HW_MCU_NAME "STM32H753" diff --git a/ports/stm32/boards/NUCLEO_H753ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H753ZI/mpconfigboard.mk new file mode 100644 index 0000000000000..10c72088217eb --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H753ZI/mpconfigboard.mk @@ -0,0 +1,5 @@ +FROZEN_MANIFEST ?= boards/NUCLEO_H743ZI/manifest.py + +include boards/NUCLEO_H743ZI/mpconfigboard.mk + +CMSIS_MCU = STM32H753xx diff --git a/ports/stm32/boards/NUCLEO_H753ZI/pins.csv b/ports/stm32/boards/NUCLEO_H753ZI/pins.csv new file mode 100644 index 0000000000000..7d964c1ab682d --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H753ZI/pins.csv @@ -0,0 +1,132 @@ +A0,PA3 +A1,PC0 +A2,PC3 +A3,PB1 +A4,PC2 +A5,PF10 +A6,PF4 +A7,PF5 +A8,PF6 +D0,PB7 +D1,PB6 +D2,PG14 +D3,PE13 +D4,PE14 +D5,PE11 +D6,PE9 +D7,PG12 +D8,PF3 +D9,PD15 +D10,PD14 +D11,PB5 +D12,PA6 +D13,PA7 +D14,PB9 +D15,PB8 +D16,PC6 +D17,PB15 +D18,PB13 +D19,PB12 +D20,PA15 +D21,PC7 +D22,PB5 +D23,PB3 +D24,PA4 +D25,PB4 +D26,PG6 +D27,PB2 +D28,PD13 +D29,PD12 +D30,PD11 +D31,PE2 +D32,PA0 +D33,PB0 +D34,PE0 +D35,PB11 +D36,PB10 +D37,PE15 +D38,PE6 +D39,PE12 +D40,PE10 +D41,PE7 +D42,PE8 +D43,PC8 +D44,PC9 +D45,PC10 +D46,PC11 +D47,PC12 +D48,PD2 +D49,PG2 +D50,PG3 +D51,PD7 +D52,PD6 +D53,PD5 +D54,PD4 +D55,PD3 +D56,PE2 +D57,PE4 +D58,PE5 +D59,PE6 +D60,PE3 +D61,PF8 +D62,PF7 +D63,PF9 +D64,PG1 +D65,PG0 +D66,PD1 +D67,PD0 +D68,PF0 +D69,PF1 +D70,PF2 +D71,PE9 +D72,PB2 +DAC1,PA4 +DAC2,PA5 +LED1,PB0 +LED2,PE1 +LED3,PB14 +SW,PC13 +I2C1_SDA,PB9 +I2C1_SCL,PB8 +I2C2_SDA,PF0 +I2C2_SCL,PF1 +I2C4_SCL,PF14 +I2C4_SDA,PF15 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD_SW,PG2 +OTG_FS_POWER,PD10 +OTG_FS_OVER_CURRENT,PG7 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +UART1_TX,PB6 +UART1_RX,PB15 +UART2_TX,PD5 +UART2_RX,PD6 +UART2_RTS,PD4 +UART2_CTS,PD3 +UART3_TX,PD8 +UART3_RX,PD9 +UART5_TX,PB6 +UART5_RX,PB12 +UART6_TX,PC6 +UART6_RX,PC7 +UART7_TX,PF7 +UART7_RX,PF6 +UART8_TX,PE1 +UART8_RX,PE0 +ETH_MDC,PC1 +ETH_MDIO,PA2 +ETH_RMII_REF_CLK,PA1 +ETH_RMII_CRS_DV,PA7 +ETH_RMII_RXD0,PC4 +ETH_RMII_RXD1,PC5 +ETH_RMII_TX_EN,PG11 +ETH_RMII_TXD0,PG13 +ETH_RMII_TXD1,PB13 diff --git a/ports/stm32/boards/NUCLEO_H753ZI/stm32h7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_H753ZI/stm32h7xx_hal_conf.h new file mode 100644 index 0000000000000..61f202e6298b1 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H753ZI/stm32h7xx_hal_conf.h @@ -0,0 +1 @@ +#include "boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h" diff --git a/ports/stm32/boards/STM32F469DISC/bdev.c b/ports/stm32/boards/STM32F469DISC/bdev.c new file mode 100644 index 0000000000000..40e4917e26d21 --- /dev/null +++ b/ports/stm32/boards/STM32F469DISC/bdev.c @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Mike Tolkachev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "storage.h" +#include "qspi.h" + +#if MICROPY_HW_SPIFLASH_ENABLE_CACHE +static mp_spiflash_cache_t spi_bdev_cache; +#endif + +// External SPI flash uses QSPI interface +const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_QSPI, + .bus.u_qspi.data = NULL, + .bus.u_qspi.proto = &qspi_proto, + #if MICROPY_HW_SPIFLASH_ENABLE_CACHE + .cache = &spi_bdev_cache, + #endif +}; + +// SPI flash device instance +spi_bdev_t spi_bdev; diff --git a/ports/stm32/boards/STM32F469DISC/board.json b/ports/stm32/boards/STM32F469DISC/board.json new file mode 100644 index 0000000000000..9530e1e8128e7 --- /dev/null +++ b/ports/stm32/boards/STM32F469DISC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32f469disc.jpg" + ], + "mcu": "stm32f4", + "product": "Discovery F469", + "thumbnail": "", + "url": "https://www.st.com/en/evaluation-tools/32f469idiscovery.html", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32F469DISC/board_init.c b/ports/stm32/boards/STM32F469DISC/board_init.c new file mode 100644 index 0000000000000..e4f75f218f80d --- /dev/null +++ b/ports/stm32/boards/STM32F469DISC/board_init.c @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Mike Tolkachev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "storage.h" +#include "boardctrl.h" +#include "qspi.h" + +// Micron N25Q128A13EF840F of original STM32F469I-DISCO board +static const mp_spiflash_chip_params_t chip_params_n25q128a13ef840f = { + .jedec_id = 0, // Not used for detection + .memory_size_bytes_log2 = MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2, + .qspi_prescaler = MICROPY_HW_QSPI_PRESCALER, + .qread_num_dummy = MICROPY_HW_QSPIFLASH_DUMMY_CYCLES +}; + +// Early board initialization hook called before file system is mounted +void STM32F469DISC_board_early_init(void) { + // Initialize QSPI flash device parameters + MICROPY_HW_BDEV_SPIFLASH->spiflash.chip_params = &chip_params_n25q128a13ef840f; +} diff --git a/ports/stm32/boards/STM32F469DISC/mpconfigboard.h b/ports/stm32/boards/STM32F469DISC/mpconfigboard.h new file mode 100644 index 0000000000000..1668618ce2b43 --- /dev/null +++ b/ports/stm32/boards/STM32F469DISC/mpconfigboard.h @@ -0,0 +1,133 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Mike Tolkachev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This board is configured to communicate over USB port, not ST-Link + +#define MICROPY_HW_BOARD_NAME "F469DISC" +#define MICROPY_HW_MCU_NAME "STM32F469" + +// Use external QSPI flash for storage by default +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SDCARD (1) + +#define MICROPY_BOARD_EARLY_INIT STM32F469DISC_board_early_init +void STM32F469DISC_board_early_init(void); + +// QSPI flash storage configuration +#if !BUILDING_MBOOT +#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1) +#endif +#define MICROPY_HW_SPIFLASH_SOFT_RESET (1) +#define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024) +#define MICROPY_HW_SPIFLASH_CHIP_PARAMS (1) // enable extended parameters +#define MICROPY_HW_QSPI_PRESCALER (3) +#define MICROPY_HW_QSPIFLASH_DUMMY_CYCLES (4) +#define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (27) +#define MICROPY_HW_QSPIFLASH_CS (pyb_pin_QSPI_CS) +#define MICROPY_HW_QSPIFLASH_SCK (pyb_pin_QSPI_CLK) +#define MICROPY_HW_QSPIFLASH_IO0 (pyb_pin_QSPI_D0) +#define MICROPY_HW_QSPIFLASH_IO1 (pyb_pin_QSPI_D1) +#define MICROPY_HW_QSPIFLASH_IO2 (pyb_pin_QSPI_D2) +#define MICROPY_HW_QSPIFLASH_IO3 (pyb_pin_QSPI_D3) + +// QSPI flash block device configuration +extern const struct _mp_spiflash_config_t spiflash_config; +extern struct _spi_bdev_t spi_bdev; +#define MICROPY_HW_BDEV_SPIFLASH (&spi_bdev) +#define MICROPY_HW_BDEV_SPIFLASH_CONFIG (&spiflash_config) +#define MICROPY_HW_BDEV_SPIFLASH_SIZE_BYTES (MICROPY_HW_SPIFLASH_SIZE_BITS / 8) +#define MICROPY_HW_BDEV_SPIFLASH_EXTENDED (&spi_bdev) // for extended block protocol + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_6 + +// UART config +#define MICROPY_HW_UART3_NAME "YB" +#define MICROPY_HW_UART3_TX (pin_B10) +#define MICROPY_HW_UART3_RX (pin_B11) +#define MICROPY_HW_UART6_NAME "YA" +#define MICROPY_HW_UART6_TX (pin_G14) +#define MICROPY_HW_UART6_RX (pin_G9) +#define MICROPY_HW_UART2_NAME "UART2" +#define MICROPY_HW_UART2_TX (pin_A2) // Needed to enable AF +#define MICROPY_HW_UART2_RX (pin_A3) // Dummy, not routed on PCB +#define MICROPY_HW_UART2_CK (pin_A4) + +// I2C buses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) + +// SPI +#define MICROPY_HW_SPI2_NSS (pin_B9) +#define MICROPY_HW_SPI2_SCK (pin_D3) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// CAN buses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_G6) // green +#define MICROPY_HW_LED2 (pin_D4) // orange +#define MICROPY_HW_LED3 (pin_D5) // red +#define MICROPY_HW_LED4 (pin_K3) // blue +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) + +// SD Card SDMMC +#define MICROPY_HW_SDCARD_CK (pin_C12) +#define MICROPY_HW_SDCARD_CMD (pin_D2) +#define MICROPY_HW_SDCARD_D0 (pin_C8) +#define MICROPY_HW_SDCARD_D1 (pin_C9) +#define MICROPY_HW_SDCARD_D2 (pin_C10) +#define MICROPY_HW_SDCARD_D3 (pin_C11) +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_G2) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F469DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F469DISC/mpconfigboard.mk new file mode 100644 index 0000000000000..bc95739c7db11 --- /dev/null +++ b/ports/stm32/boards/STM32F469DISC/mpconfigboard.mk @@ -0,0 +1,20 @@ +# MCU settings +MCU_SERIES = f4 +CMSIS_MCU = STM32F469xx +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32f479_af.csv + +ifeq ($(USE_MBOOT),1) +# When using Mboot all the text goes together after the filesystem +LD_FILES = boards/stm32f469xi.ld boards/common_blifs.ld +TEXT0_ADDR = 0x08020000 +else +# When not using Mboot the ISR text goes first, then the rest after the filesystem +LD_FILES = boards/stm32f469xi.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 +endif + +# MicroPython settings +MICROPY_PY_SSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/stm32/boards/STM32F469DISC/pins.csv b/ports/stm32/boards/STM32F469DISC/pins.csv new file mode 100644 index 0000000000000..055581ba944b1 --- /dev/null +++ b/ports/stm32/boards/STM32F469DISC/pins.csv @@ -0,0 +1,135 @@ +A0,PB1 +A1,PC2 +A2,PC3 +A3,PC4 +A4,PC5 +A5,PA4 +D0,PG9 +D1,PG14 +D2,PG13 +D3,PA1 +D4,PG12 +D5,PA2 +D6,PA6 +D7,PG11 +D8,PG10 +D9,PA7 +D10,PH6 +D11,PB15 +D12,PB14 +D13,PD3 +D14,PB9 +D15,PB8 +LED1,PG6 +LED2,PD4 +LED3,PD5 +LED4,PK3 +SW,PA0 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +EXT_SDA,PB9 +EXT_SCL,PB8 +EXT_RST,PG3 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CK,PC12 +SD_CMD,PD2 +SD_SW,PC2 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +USB_HS_CLK,PA5 +USB_HS_STP,PC0 +USB_HS_NXT,PH4 +USB_HS_DIR,PI11 +USB_HS_D0,PA3 +USB_HS_D1,PB0 +USB_HS_D2,PB1 +USB_HS_D3,PB10 +USB_HS_D4,PB11 +USB_HS_D5,PB12 +USB_HS_D6,PB13 +USB_HS_D7,PB5 +UART1_TX,PB10 +UART1_RX,PB11 +UART6_TX,PG14 +UART6_RX,PG9 +CAN2_TX,PB13 +CAN2_RX,PB12 +QSPI_CS,PB6 +QSPI_CLK,PF10 +QSPI_D0,PF8 +QSPI_D1,PF9 +QSPI_D2,PF7 +QSPI_D3,PF6 +FMC_SDCKE0,PH2 +FMC_SDNE0,PH3 +FMC_SDCLK,PG8 +FMC_SDNCAS,PG15 +FMC_SDNRAS,PF11 +FMC_SDNWE,PH5 +FMC_BA0,PG4 +FMC_BA1,PG5 +FMC_NBL0,PE0 +FMC_NBL1,PE1 +FMC_NBL2,PI4 +FMC_NBL3,PI5 +FMC_A0,PF0 +FMC_A1,PF1 +FMC_A2,PF2 +FMC_A3,PF3 +FMC_A4,PF4 +FMC_A5,PF5 +FMC_A6,PF12 +FMC_A7,PF13 +FMC_A8,PF14 +FMC_A9,PF15 +FMC_A10,PG0 +FMC_A11,PG1 +FMC_A12,PG2 +FMC_D0,PD14 +FMC_D1,PD15 +FMC_D2,PD0 +FMC_D3,PD1 +FMC_D4,PE7 +FMC_D5,PE8 +FMC_D6,PE9 +FMC_D7,PE10 +FMC_D8,PE11 +FMC_D9,PE12 +FMC_D10,PE13 +FMC_D11,PE14 +FMC_D12,PE15 +FMC_D13,PD8 +FMC_D14,PD9 +FMC_D15,PD10 +FMC_D16,PH8 +FMC_D17,PH9 +FMC_D18,PH10 +FMC_D19,PH11 +FMC_D20,PH12 +FMC_D21,PH13 +FMC_D22,PH14 +FMC_D23,PH15 +FMC_D24,PI0 +FMC_D25,PI1 +FMC_D26,PI2 +FMC_D27,PI3 +FMC_D28,PI6 +FMC_D29,PI7 +FMC_D30,PI9 +FMC_D31,PI10 diff --git a/ports/stm32/boards/STM32F469DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F469DISC/stm32f4xx_hal_conf.h new file mode 100644 index 0000000000000..b5a54cbf7c172 --- /dev/null +++ b/ports/stm32/boards/STM32F469DISC/stm32f4xx_hal_conf.h @@ -0,0 +1,41 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2025 Mike Tolkachev + */ + +#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H + +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +#define HAL_DMA2D_MODULE_ENABLED +#define HAL_LTDC_MODULE_ENABLED +#define HAL_QSPI_MODULE_ENABLED +#define HAL_DSI_MODULE_ENABLED + +#include "boards/stm32f4xx_hal_conf_base.h" + +#ifdef HAL_DMA2D_MODULE_ENABLED +#include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED +#include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED +#include "stm32f4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED +#include "stm32f4xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/bdev.c b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/bdev.c new file mode 100644 index 0000000000000..b70142300772c --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/bdev.c @@ -0,0 +1,47 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ + +#include "storage.h" +#include "spi.h" +#include "qspi.h" +#include "py/mpconfig.h" + +static const spi_proto_cfg_t spi_bus = { + .spi = &spi_obj[0], // SPI1 + .baudrate = 25000000, + .polarity = 0, + .phase = 0, + .bits = 8, + .firstbit = SPI_FIRSTBIT_MSB, +}; + +#if MICROPY_HW_SPIFLASH_ENABLE_CACHE +static mp_spiflash_cache_t spi_bdev_cache; +#endif + +const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_SPI, + .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS, + + .bus.u_spi.data = (void *)&spi_bus, + .bus.u_spi.proto = &spi_proto, + #if MICROPY_HW_SPIFLASH_ENABLE_CACHE + .cache = &spi_bdev_cache, + #endif +}; + +spi_bdev_t spi_bdev; + +// Second external SPI flash uses hardware QSPI interface +const mp_spiflash_config_t spiflash2_config = { + .bus_kind = MP_SPIFLASH_BUS_QSPI, + .bus.u_qspi.data = NULL, + .bus.u_qspi.proto = &qspi_proto, + #if MICROPY_HW_SPIFLASH_ENABLE_CACHE + .cache = &spi_bdev_cache, + #endif +}; + +spi_bdev_t spi_bdev2; diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/board.json b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/board.json new file mode 100644 index 0000000000000..11a6e08152f06 --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/board.json @@ -0,0 +1,13 @@ +{ + "deploy": [ + "deploy.md" + ], + "features": ["External Flash", "DAC", "Display","microSD", "USB", "USB-C"], + "images": [ + "weact_stm32h743.jpg" + ], + "mcu": "stm32h7", + "product": "Mini STM32H743", + "url": "https://github.com/WeActStudio/MiniSTM32H7xx", + "vendor": "WeAct Studio" +} diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/board_init.c b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/board_init.c new file mode 100644 index 0000000000000..0adf04982c8a4 --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/board_init.c @@ -0,0 +1,16 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ + +#include "py/mphal.h" +#include "storage.h" + +void WeAct_Core_early_init(void) { + // Turn off the USB switch. + mp_hal_pin_output(pyb_pin_OTG_FS_POWER); + mp_hal_pin_low(pyb_pin_OTG_FS_POWER); + + // Explicitly init SPI2 because it's not enabled as a block device + spi_bdev_ioctl(&spi_bdev2, BDEV_IOCTL_INIT, (uint32_t)&spiflash2_config); +} diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/deploy.md b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/deploy.md new file mode 100644 index 0000000000000..a4572bfe30617 --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/deploy.md @@ -0,0 +1,19 @@ +### WeAct Studio STM32H7xx + +WeAct Studio make a number of STM32H7xx-based boards, they can all be updated +using +[DFU](https://en.wikipedia.org/wiki/USB?useskin=vector#Device_Firmware_Upgrade_mechanism). + +### DFU update + +Hold the Boot button - the middle of the cluster of three buttons - while the +board is reset (either by connecting USB or by pressing reset). Release the Boot +button shortly after the board has reset. The board ought to now be in DFU mode +and detectable as such from a connected computer. + +Use a tool like [`dfu-util`](https://dfu-util.sourceforge.net/) to update the +firmware: + +```bash +dfu-util --alt 0 -D firmware.dfu +``` diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/manifest.py b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/manifest.py new file mode 100644 index 0000000000000..7d163e1847964 --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/manifest.py @@ -0,0 +1,4 @@ +include("$(PORT_DIR)/boards/manifest.py") + +# Currently this file is a placeholder. +# It would be good to extend to add an LCD driver. diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/mpconfigboard.h b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/mpconfigboard.h new file mode 100644 index 0000000000000..ad9f3bc45ee08 --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/mpconfigboard.h @@ -0,0 +1,171 @@ +#define MICROPY_HW_BOARD_NAME "WEACTSTUDIO_MINI_STM32H743" +#define MICROPY_HW_MCU_NAME "STM32H743VIT6" + +#define MICROPY_FATFS_EXFAT (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_ADC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_SERVO (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_SDCARD (1) +#define MICROPY_HW_ENABLE_MMCARD (0) + +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (1) +#define MICROPY_HW_ROMFS_QSPI_SPIFLASH_OBJ (&spi_bdev2.spiflash) +#define MICROPY_HW_ROMFS_ENABLE_PART0 (1) + +// Flash storage config +#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1) +// Disable internal filesystem to use spiflash. +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) + +// W25Q64 for storage +#define MICROPY_HW_SPIFLASH_SIZE_BYTES (8 * 1024 * 1024) + +// SPI flash #1, for R/W storage +#define MICROPY_HW_SPIFLASH_CS (pin_D6) +#define MICROPY_HW_SPIFLASH_SCK (pin_B3) +#define MICROPY_HW_SPIFLASH_MOSI (pin_D7) +#define MICROPY_HW_SPIFLASH_MISO (pin_B4) + +// External SPI Flash configuration +#define MICROPY_HW_SPI_IS_RESERVED(id) (id == 1) + +// SPI flash #1, block device config +extern const struct _mp_spiflash_config_t spiflash_config; +extern struct _spi_bdev_t spi_bdev; + +#define MICROPY_HW_BDEV_SPIFLASH (&spi_bdev) +#define MICROPY_HW_BDEV_SPIFLASH_CONFIG (&spiflash_config) +#define MICROPY_HW_BDEV_SPIFLASH_SIZE_BYTES (MICROPY_HW_SPIFLASH_SIZE_BITS / 8) +#define MICROPY_HW_BDEV_SPIFLASH_EXTENDED (&spi_bdev) // for extended block protocol +#define MICROPY_HW_SPIFLASH_SIZE_BITS (MICROPY_HW_SPIFLASH_SIZE_BYTES * 8) + +// SPI flash #2, to be memory mapped +#define MICROPY_HW_QSPI_PRESCALER (2) // 120 MHz +#define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (26) +#define MICROPY_HW_QSPIFLASH_CS (pin_B6) +#define MICROPY_HW_QSPIFLASH_SCK (pin_B2) +#define MICROPY_HW_QSPIFLASH_IO0 (pin_D11) +#define MICROPY_HW_QSPIFLASH_IO1 (pin_D12) +#define MICROPY_HW_QSPIFLASH_IO2 (pin_E2) +#define MICROPY_HW_QSPIFLASH_IO3 (pin_D13) + +// SPI flash #2, block device config +extern const struct _mp_spiflash_config_t spiflash2_config; +extern struct _spi_bdev_t spi_bdev2; + +#define MICROPY_BOARD_EARLY_INIT WeAct_Core_early_init + +// This board has 25MHz HSE. +// The following gives a 480MHz CPU speed. +#define MICROPY_HW_CLK_USE_HSE (1) +#define MICROPY_HW_CLK_PLLM (5) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (2) +#define MICROPY_HW_CLK_PLLQ (20) +#define MICROPY_HW_CLK_PLLR (2) +#define MICROPY_HW_CLK_PLLVCI (RCC_PLL1VCIRANGE_2) +#define MICROPY_HW_CLK_PLLVCO (RCC_PLL1VCOWIDE) +#define MICROPY_HW_CLK_PLLFRAC (0) + +// The USB clock is set using PLL3 +#define MICROPY_HW_CLK_PLL3M (5) +#define MICROPY_HW_CLK_PLL3N (192) +#define MICROPY_HW_CLK_PLL3P (2) +#define MICROPY_HW_CLK_PLL3Q (20) +#define MICROPY_HW_CLK_PLL3R (2) +#define MICROPY_HW_CLK_PLL3VCI (RCC_PLL3VCIRANGE_2) +#define MICROPY_HW_CLK_PLL3VCO (RCC_PLL3VCOWIDE) +#define MICROPY_HW_CLK_PLL3FRAC (0) + +// 32kHz crystal for RTC +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) + +// 6 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_6 + +// UART +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART3_TX (pin_B10) +#define MICROPY_HW_UART3_RX (pin_B11) +#define MICROPY_HW_UART4_TX (pin_C11) +#define MICROPY_HW_UART4_RX (pin_C10) +#define MICROPY_HW_UART5_TX (pin_B12) // or SPI2 +#define MICROPY_HW_UART5_RX (pin_B13) // or SPI2 +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) +#define MICROPY_HW_UART7_TX (pin_E8) +#define MICROPY_HW_UART7_RX (pin_E7) + +// I2C buses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) + +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI buses +// NOTE: SPI1 is used for the SPI flash. +#define MICROPY_HW_SPI1_NSS (pin_D6) +#define MICROPY_HW_SPI1_SCK (pin_B3) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_D7) + +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) +// NOTE: SPI3 is used for the QSPI flash. +#define MICROPY_HW_SPI3_NSS (pin_A4) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) +// NOTE: SPI4 is used for the ST7735 LCD. +#define MICROPY_HW_SPI4_NSS (pin_E11) +#define MICROPY_HW_SPI4_SCK (pin_E12) +#define MICROPY_HW_SPI4_MISO (pin_E13) +#define MICROPY_HW_SPI4_MOSI (pin_E14) + +// CAN buses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) // K1 on the board. +#define MICROPY_HW_USRSW_PULL (GPIO_PULLDOWN) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_E3) // the only controllable LED on the board. +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD Card SDMMC +#define MICROPY_HW_SDCARD_SDMMC (1) +#define MICROPY_HW_SDCARD_CK (pin_C12) +#define MICROPY_HW_SDCARD_CMD (pin_D2) +#define MICROPY_HW_SDCARD_D0 (pin_C8) +#define MICROPY_HW_SDCARD_D1 (pin_C9) +#define MICROPY_HW_SDCARD_D2 (pin_C10) +#define MICROPY_HW_SDCARD_D3 (pin_C11) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_D4) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET) + +// USB config +#define MICROPY_HW_USB_FS (1) + +void WeAct_Core_early_init(void); diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/mpconfigboard.mk b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/mpconfigboard.mk new file mode 100644 index 0000000000000..c13c3ddad72cc --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/mpconfigboard.mk @@ -0,0 +1,22 @@ +USE_MBOOT ?= 0 + +# MCU settings +MCU_SERIES = h7 +CMSIS_MCU = STM32H743xx +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32h743_af.csv + +ifeq ($(USE_MBOOT),1) +# When using Mboot everything goes after the bootloader +LD_FILES = boards/stm32h723.ld boards/common_bl.ld +TEXT0_ADDR = 0x08020000 +else +# When not using Mboot everything goes at the start of flash +LD_FILES = boards/WEACTSTUDIO_MINI_STM32H743/weact_stm32h743.ld boards/common_basic.ld +TEXT0_ADDR = 0x08000000 +endif + +# MicroPython settings +MICROPY_VFS_LFS2 = 1 + +FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/pins.csv b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/pins.csv new file mode 100644 index 0000000000000..61b188cc6b68d --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/pins.csv @@ -0,0 +1,100 @@ +A0,PA0 +A1,PA1 +A2,PA2 +A3,PA3 +A4,PA4 +A5,PA5 +A6,PA6 +A7,PA7 +A8,PA8 +A9,PA9 +A10,PA10 +A11,PA11 +A12,PA12 +A15,PA15 +B0,PB0 +B1,PB1 +B2,PB2 +B3,PB3 +B4,PB4 +B5,PB5 +B6,PB6 +B7,PB7 +B8,PB8 +B9,PB9 +B10,PB10 +B11,PB11 +B12,PB12 +B13,PB13 +B14,PB14 +B15,PB15 +C0,PC0 +C1,PC1 +C2,PC2 +C3,PC3 +C4,PC4 +C5,PC5 +C6,PC6 +C7,PC7 +C8,PC8 +C9,PC9 +C10,PC10 +C11,PC11 +C12,PC12 +C13,PC13 +D0,PD0 +D1,PD1 +D2,PD2 +D3,PD3 +D4,PD4 +D5,PD5 +D6,PD6 +D7,PD7 +D8,PD8 +D9,PD9 +D10,PD10 +D11,PD11 +D12,PD12 +D13,PD13 +D14,PD14 +D15,PD15 +E0,PE0 +E1,PE1 +E2,PE2 +E3,PE3 +E4,PE4 +E5,PE5 +E6,PE6 +E7,PE7 +E8,PE8 +E9,PE9 +E10,PE10 +E11,PE11 +E11,PE11 +E12,PE12 +E13,PE13 +E14,PE14 +E15,PE15 +LED_BLUE,PE3 +KEY_1,PC13 +QSPI_CS,PB6 +QSPI_CLK,PB2 +QSPI_D0,PD11 +QSPI_D1,PD12 +QSPI_D2,PE2 +QSPI_D3,PD13 +USB_DM,PA11 +USB_DP,PA12 +OSC32_IN,PC14 +OSC32_OUT,PC15 +SDIO_D0,PC8 +SDIO_D1,PC9 +SDIO_D2,PC10 +SDIO_D3,PC11 +SDIO_CMD,PD2 +SDIO_CK,PC12 +SD_SW,PD4 +OTG_FS_POWER,PD10 +OTG_FS_OVER_CURRENT,PG7 +USB_VBUS,PA9 +USB_ID,PA10 diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/stm32h7xx_hal_conf.h b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/stm32h7xx_hal_conf.h new file mode 100644 index 0000000000000..c8f60c56055ef --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/stm32h7xx_hal_conf.h @@ -0,0 +1,19 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2019 Damien P. George + */ +#ifndef MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H + +// Oscillator values in Hz +#define HSE_VALUE (25000000) +#define LSE_VALUE (32768) +#define EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (5000) +#define LSE_STARTUP_TIMEOUT (5000) + +#include "boards/stm32h7xx_hal_conf_base.h" + +#endif // MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H diff --git a/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/weact_stm32h743.ld b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/weact_stm32h743.ld new file mode 100644 index 0000000000000..356d69171a5e0 --- /dev/null +++ b/ports/stm32/boards/WEACTSTUDIO_MINI_STM32H743/weact_stm32h743.ld @@ -0,0 +1,33 @@ +/* + GNU linker script for WeAct Studio STM32H743 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* sectors (0-15) */ + FLASH_APP (rx) : ORIGIN = 0x08020000, LENGTH = 1920K /* sectors (1-15) */ + FLASH_ROMFS (rx): ORIGIN = 0x90000000, LENGTH = 8192K /* external QSPI */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */ + RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the stack. The stack is full descending so begins just above last byte + of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; +_sstack = _estack - 16K; /* tunable */ + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = _sstack; + +/* ROMFS location */ +_micropy_hw_romfs_part0_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part0_size = LENGTH(FLASH_ROMFS); diff --git a/ports/stm32/boards/openocd_stm32h7_dual_bank.cfg b/ports/stm32/boards/openocd_stm32h7_dual_bank.cfg new file mode 100644 index 0000000000000..8bb3116990bb1 --- /dev/null +++ b/ports/stm32/boards/openocd_stm32h7_dual_bank.cfg @@ -0,0 +1,46 @@ +# This script configures OpenOCD for use with an ST-Link V3 programmer/debugger +# and an STM32H7 target microcontroller with 2MB RAM (dual bank). +# +# To flash your firmware: +# +# $ openocd -f boards/openocd_stm32h7_dual_bank.cfg \ +# -c "stm_flash build-BOARD/firmware.bin 0x08000000 +# +# For a gdb server on port 3333: +# +# $ openocd -f boards/openocd_stm32h7_dual_bank.cfg + + +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd +source [find target/stm32h7x_dual_bank.cfg] +reset_config srst_only connect_assert_srst +init + +proc stm_flash { BIN0 ADDR0 {BIN1 ""} {ADDR1 ""} } { + reset halt + sleep 100 + wait_halt 2 + flash write_image erase $BIN0 $ADDR0 + sleep 100 + verify_image $BIN0 $ADDR0 + sleep 100 + if {$BIN1 ne ""} { + flash write_image erase $BIN1 $ADDR1 + sleep 100 + verify_image $BIN1 $ADDR1 + sleep 100 + } + reset run + shutdown +} + +proc stm_erase {} { + reset halt + sleep 100 + stm32h7x mass_erase 0 + sleep 100 + stm32h7x mass_erase 1 + sleep 100 + shutdown +} diff --git a/ports/stm32/boards/plli2svalues.py b/ports/stm32/boards/plli2svalues.py index e5ea4e8dfd49b..f872c60ebb5c5 100644 --- a/ports/stm32/boards/plli2svalues.py +++ b/ports/stm32/boards/plli2svalues.py @@ -24,6 +24,9 @@ def __init__(self, range_plli2sn, range_plli2sr): "stm32f401xe", "stm32f407xx", "stm32f411xe", + "stm32f412cx", + "stm32f412rx", + "stm32f412vx", "stm32f412zx", "stm32f413xx", "stm32f427xx", @@ -163,7 +166,7 @@ def main(): if mcu_series in mcu_support_plli2s: if len(argv) not in (1, 2): - print("usage: pllvalues.py [-c] [-m ] ") + print("usage: plli2svalues.py [-c] [-m ] ") sys.exit(1) if argv[0].startswith("hse:"): diff --git a/ports/stm32/boards/stm32f412xe.ld b/ports/stm32/boards/stm32f412xe.ld new file mode 100644 index 0000000000000..15b8d78f15f6b --- /dev/null +++ b/ports/stm32/boards/stm32f412xe.ld @@ -0,0 +1,35 @@ +/* + GNU linker script for STM32F412xe (512kB flash, 256kB RAM) +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* entire flash */ + FLASH_START (rx): ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 64K /* sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 384K /* sectors 5,6,7 are 128K */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 240K + FS_CACHE (xrw) : ORIGIN = 0x2003c000, LENGTH = 16K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the stack. The stack is full descending so begins just above last byte + of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; +_sstack = _estack - 16K; /* tunable */ + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = _sstack; + +/* Filesystem cache in RAM, and storage in flash */ +_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(FS_CACHE); +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32f412zx.ld b/ports/stm32/boards/stm32f412xg.ld similarity index 96% rename from ports/stm32/boards/stm32f412zx.ld rename to ports/stm32/boards/stm32f412xg.ld index b67f1c3e25353..5b5ccb1d42317 100644 --- a/ports/stm32/boards/stm32f412zx.ld +++ b/ports/stm32/boards/stm32f412xg.ld @@ -1,5 +1,5 @@ /* - GNU linker script for STM32F412zx (1MB flash, 256kB RAM) + GNU linker script for STM32F412xg (1MB flash, 256kB RAM) */ /* Specify the memory areas */ diff --git a/ports/stm32/boards/stm32f469xi.ld b/ports/stm32/boards/stm32f469xi.ld new file mode 100644 index 0000000000000..4da9bf16f1a8f --- /dev/null +++ b/ports/stm32/boards/stm32f469xi.ld @@ -0,0 +1,35 @@ +/* + GNU linker script for STM32F469xI (2Mbyte) +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* Entire flash */ + FLASH_START (rx): ORIGIN = 0x08000000, LENGTH = 16K /* Sector 0 */ + FLASH_FS (r) : ORIGIN = 0x08004000, LENGTH = 112K /* Sectors 1, 2, 3, 4 */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 1920K /* Sectors 5 - 23 */ + CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K /* CCM RAM used for storage cache */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K /* SRAM1, SRAM2, SRAM3 */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the stack. The stack is full descending so begins just above last byte + of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; +_sstack = _estack - 16K; /* tunable */ + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = _sstack; + +/* Filesystem cache in RAM, and storage in flash */ +_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(CCMRAM); +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c index 60f2a23deca07..7baaa89c6274f 100644 --- a/ports/stm32/eth.c +++ b/ports/stm32/eth.c @@ -370,11 +370,6 @@ static int eth_mac_init(eth_t *self) { __HAL_RCC_ETH1RX_CLK_SLEEP_ENABLE(); #elif defined(STM32N6) __HAL_RCC_ETH1_RELEASE_RESET(); - - __HAL_RCC_ETH1_CLK_SLEEP_ENABLE(); - __HAL_RCC_ETH1MAC_CLK_SLEEP_ENABLE(); - __HAL_RCC_ETH1TX_CLK_SLEEP_ENABLE(); - __HAL_RCC_ETH1RX_CLK_SLEEP_ENABLE(); #else __HAL_RCC_ETHMAC_RELEASE_RESET(); diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 6f7413694b0b4..6ae8061c4135f 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -409,13 +409,13 @@ void stm32_main(uint32_t reset_mode) { LL_MEM_EnableClockLowPower(LL_MEM_AXISRAM1 | LL_MEM_AXISRAM2 | LL_MEM_AXISRAM3 | LL_MEM_AXISRAM4 | LL_MEM_AXISRAM5 | LL_MEM_AXISRAM6 | LL_MEM_AHBSRAM1 | LL_MEM_AHBSRAM2 | LL_MEM_BKPSRAM | LL_MEM_FLEXRAM | LL_MEM_CACHEAXIRAM | LL_MEM_VENCRAM | LL_MEM_BOOTROM); - LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_XSPI2 | LL_AHB5_GRP1_PERIPH_XSPIM); LL_APB4_GRP1_EnableClock(LL_APB4_GRP1_PERIPH_RTC | LL_APB4_GRP1_PERIPH_RTCAPB); LL_APB4_GRP1_EnableClockLowPower(LL_APB4_GRP1_PERIPH_RTC | LL_APB4_GRP1_PERIPH_RTCAPB); // Enable some AHB peripherals during sleep. LL_AHB1_GRP1_EnableClockLowPower(LL_AHB1_GRP1_PERIPH_ALL); // GPDMA1, ADC12 LL_AHB4_GRP1_EnableClockLowPower(LL_AHB4_GRP1_PERIPH_ALL); // GPIOA-Q, PWR, CRC + LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_ALL); // DMA2D, ETH, FMC, GFXMMU, GPU2D, HPDMA, XSPI, JPEG, MCE, CACHEAXI, NPU, OTG, PSSI, SDMMC // Enable some APB peripherals during sleep. LL_APB1_GRP1_EnableClockLowPower(LL_APB1_GRP1_PERIPH_ALL); // I2C, I3C, LPTIM, SPI, TIM, UART, WWDG @@ -611,14 +611,9 @@ void stm32_main(uint32_t reset_mode) { pyb_can_init0(); #endif - #if MICROPY_HW_ENABLE_USB - #if MICROPY_HW_TINYUSB_STACK - pyb_usbd_init(); - mp_usbd_init(); - #else + #if MICROPY_HW_STM_USB_STACK && MICROPY_HW_ENABLE_USB pyb_usb_init0(); #endif - #endif #if MICROPY_PY_MACHINE_I2S machine_i2s_init0(); @@ -690,6 +685,10 @@ void stm32_main(uint32_t reset_mode) { } #endif + #if MICROPY_HW_TINYUSB_STACK && MICROPY_HW_ENABLE_USBDEV + mp_usbd_init(); + #endif + #if MICROPY_HW_HAS_MMA7660 // MMA accel: init and reset accel_init(); diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 7226dd353f399..c049017734feb 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -54,7 +54,7 @@ DFU=$(TOP)/tools/dfu.py PYDFU ?= $(TOP)/tools/pydfu.py BOOTLOADER_DFU_USB_VID ?= 0x0483 BOOTLOADER_DFU_USB_PID ?= 0xDF11 -STFLASH ?= st-flash +STFLASH ?= st-flash --connect-under-reset OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index e40413e4e7a27..7251bc1562e90 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -443,7 +443,7 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) { #elif defined(STM32H5) #define INTERNAL_FLASH_LAYOUT "@Internal Flash /0x08000000/???*08Kg" #define INTERNAL_FLASH_LAYOUT_HAS_TEMPLATE (1) -#elif defined(STM32H743xx) +#elif defined(STM32H743xx) || defined(STM32H753xx) #define INTERNAL_FLASH_LAYOUT "@Internal Flash /0x08000000/16*128Kg" #elif defined(STM32H750xx) #define INTERNAL_FLASH_LAYOUT "@Internal Flash /0x08000000/01*128Kg" diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index eefd5c05c1b2b..e21f474d7afb6 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -261,6 +261,7 @@ #if MICROPY_HW_TINYUSB_STACK #ifndef MICROPY_HW_ENABLE_USBDEV #define MICROPY_HW_ENABLE_USBDEV (1) +#define MICROPY_HW_TINYUSB_LL_INIT mp_usbd_ll_init #endif #ifndef MICROPY_HW_USB_CDC @@ -542,6 +543,9 @@ #define MICROPY_HW_MAX_UART (10) #define MICROPY_HW_MAX_LPUART (1) +#define CFG_TUSB_MCU OPT_MCU_STM32N6 +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) + // Configuration for STM32U5 series #elif defined(STM32U5) diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 098a848fb843b..50aa456971181 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -1,6 +1,7 @@ // We use the ST Cube HAL library for most hardware peripherals #include STM32_HAL_H #include "pin.h" +#include "usbd_conf.h" #include "py/ringbuf.h" #include "shared/runtime/interrupt_char.h" diff --git a/ports/stm32/mpu.h b/ports/stm32/mpu.h index 8713fe8370c5b..1d43e87f8d7b1 100644 --- a/ports/stm32/mpu.h +++ b/ports/stm32/mpu.h @@ -28,7 +28,7 @@ #include "irq.h" -#if (defined(STM32F4) && defined(MICROPY_HW_ETH_MDC)) || defined(STM32F7) || defined(STM32G4) || defined(STM32H7) || defined(STM32WB) +#if (defined(STM32F4) && defined(MICROPY_HW_ETH_MDC)) || defined(STM32F469xx) || defined(STM32F7) || defined(STM32G4) || defined(STM32H7) || defined(STM32WB) #define MPU_REGION_ETH (MPU_REGION_NUMBER0) #define MPU_REGION_QSPI1 (MPU_REGION_NUMBER1) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 7211ef873cd52..a63c57f4a78bb 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -798,13 +798,13 @@ void powerctrl_enter_stop_mode(void) { #if defined(STM32H7) || \ defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx) || \ + defined(STM32F429xx) || defined(STM32F439xx) || defined(STM32F469xx) || \ defined(STM32WB55xx) || defined(STM32WB35xx) // Disable SysTick Interrupt // Note: This seems to be required at least on the H7 REV Y, // otherwise the MCU will leave stop mode immediately on entry. // Note: According to ST Errata ES0206 Rev 18, Section 2.2.1 this is needed - // for STM32F427xx, STM32F437xx, STM32F429xx and STM32F439xx + // for STM32F427xx, STM32F437xx, STM32F429xx, STM32F439xx, and STM32F469xx // Note: According to ST Errata ES0394 Rev 11, Section 2.2.17 this is needed // for STM32WB55xx and STM32WB35xx SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; @@ -1039,7 +1039,7 @@ void powerctrl_enter_stop_mode(void) { #if defined(STM32H7) || \ defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx) || \ + defined(STM32F429xx) || defined(STM32F439xx) || defined(STM32F469xx) || \ defined(STM32WB55xx) || defined(STM32WB35xx) // Enable SysTick Interrupt SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 72abcd75f9936..ae33f834cbf71 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -134,19 +134,27 @@ void rtc_init_start(bool force_init) { if (!force_init) { bool rtc_running = false; #if defined(STM32N6) + // Note: the low-level boot on the N6 seems to always enable the RTC and the LSI, and + // switch the RTC to LSI mode. So the logic below needs to account for that: + // - if LSE is ready then switch back to the LSE + // - even if LSI is ready, don't use it if the board is configured to use LSE + uint32_t rtc_clock_source = LL_RCC_GetRTCClockSource(); if (LL_RCC_IsEnabledRTC() - && LL_RCC_GetRTCClockSource() == LL_RCC_RTC_CLKSOURCE_LSE && LL_RCC_LSE_IsReady()) { // LSE is enabled & ready --> no need to (re-)init RTC rtc_running = true; + if (rtc_clock_source != LL_RCC_RTC_CLKSOURCE_LSE) { + LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); + } // remove Backup Domain write protection HAL_PWR_EnableBkUpAccess(); // Clear source Reset Flag __HAL_RCC_CLEAR_RESET_FLAGS(); // provide some status information rtc_info |= 0x40000; - } else if (LL_RCC_IsEnabledRTC() - && LL_RCC_GetRTCClockSource() == LL_RCC_RTC_CLKSOURCE_LSI) { + } else if (!rtc_use_lse + && LL_RCC_IsEnabledRTC() + && rtc_clock_source == LL_RCC_RTC_CLKSOURCE_LSI) { // LSI configured as the RTC clock source --> no need to (re-)init RTC rtc_running = true; // remove Backup Domain write protection diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index b91fa3a9c284e..3e755bf9f2602 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -105,7 +105,7 @@ #define SDIO_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_HARDWARE_FLOW_CONTROL_ENABLE #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6) -#define SDIO_TRANSFER_CLK_DIV SDMMC_NSpeed_CLK_DIV +#define SDIO_TRANSFER_CLK_DIV SDMMC_HSPEED_CLK_DIV #define SDIO_USE_GPDMA 0 #else #define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV diff --git a/ports/stm32/sdio.c b/ports/stm32/sdio.c index de82ceadc5f33..4d18102e1542f 100644 --- a/ports/stm32/sdio.c +++ b/ports/stm32/sdio.c @@ -131,10 +131,6 @@ void sdio_init(uint32_t irq_pri) { mp_hal_pin_config_alt_static(MICROPY_HW_SDIO_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_CMD); SDMMC_CLK_ENABLE(); // enable SDIO peripheral - #if defined(STM32N6) - LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_SDMMC1); - LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_SDMMC2); - #endif SDMMC_TypeDef *SDIO = SDMMC; #if defined(STM32F7) diff --git a/ports/stm32/stm32.mk b/ports/stm32/stm32.mk index b63cb0cc51b31..a1532d2776d32 100644 --- a/ports/stm32/stm32.mk +++ b/ports/stm32/stm32.mk @@ -43,7 +43,7 @@ ifneq ($(BUILDING_MBOOT),1) # Select hardware floating-point support. SUPPORTS_HARDWARE_FP_SINGLE = 0 SUPPORTS_HARDWARE_FP_DOUBLE = 0 -ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx STM32H747xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ STM32N657xx)) +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx STM32H747xx STM32H750xx STM32H753xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ STM32N657xx)) CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard -mfp16-format=ieee SUPPORTS_HARDWARE_FP_SINGLE = 1 SUPPORTS_HARDWARE_FP_DOUBLE = 1 diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 19778020d9aff..17b95326460e4 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -301,6 +301,8 @@ void DebugMon_Handler(void) { /* file (startup_stm32f4xx.s). */ /******************************************************************************/ +#if MICROPY_HW_STM_USB_STACK || MICROPY_HW_TINYUSB_STACK + #if defined(STM32G0) #if MICROPY_HW_USB_FS @@ -499,6 +501,8 @@ void OTG_HS_WKUP_IRQHandler(void) { #endif // !defined(STM32L0) +#endif // MICROPY_HW_STM_USB_STACK || MICROPY_HW_TINYUSB_STACK + /** * @brief This function handles PPP interrupt request. * @param None diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 514bf91786c13..5386771991524 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -535,13 +535,14 @@ MP_WEAK void SystemClock_Config(void) { MICROPY_BOARD_FATAL_ERROR("HAL_RCC_ClockConfig"); } PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_LPUART1 - | RCC_PERIPHCLK_RNG | RCC_PERIPHCLK_ADC12 + | RCC_PERIPHCLK_RNG | RCC_PERIPHCLK_ADC12 | RCC_PERIPHCLK_ADC345 | RCC_PERIPHCLK_FDCAN | RCC_PERIPHCLK_USB; PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48; PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1; PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_HSE; PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_HSI48; PeriphClkInitStruct.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK; + PeriphClkInitStruct.Adc345ClockSelection = RCC_ADC345CLKSOURCE_SYSCLK; PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { MICROPY_BOARD_FATAL_ERROR("HAL_RCCEx_PeriphCLKConfig"); diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index aa41092829809..5308061732428 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -889,7 +889,7 @@ static const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { #endif #if defined(TIM6) - #if defined(STM32F412Zx) || defined(STM32L1) + #if defined(STM32F412Cx) || defined(STM32F412Rx) || defined(STM32F412Vx) || defined(STM32F412Zx) || defined(STM32L1) TIM_ENTRY(6, TIM6_IRQn), #elif defined(STM32G0) TIM_ENTRY(6, TIM6_DAC_LPTIM1_IRQn), diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index 76142789d413a..d481aec1e490b 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -32,10 +32,11 @@ #include "usbd_core.h" #include "py/obj.h" #include "py/mphal.h" +#include "shared/tinyusb/mp_usbd.h" #include "irq.h" #include "usb.h" -#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS +#if MICROPY_HW_STM_USB_STACK || MICROPY_HW_TINYUSB_STACK #if BUILDING_MBOOT // TinyUSB not used in mboot @@ -62,16 +63,8 @@ PCD_HandleTypeDef pcd_hs_handle; #define OTG_HS_IRQn USB1_OTG_HS_IRQn #endif -#if MICROPY_HW_TINYUSB_STACK -void pyb_usbd_init(void) -#else -void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) -#endif -{ - #if MICROPY_HW_USB_FS - #if MICROPY_HW_STM_USB_STACK - if (hpcd->Instance == USB_OTG_FS) - #endif +#if MICROPY_HW_USB_FS +static void mp_usbd_ll_init_fs(void) { { // Configure USB GPIO's. @@ -192,17 +185,12 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) #endif #endif #endif - - #if MICROPY_HW_STM_USB_STACK - return; - #endif } - #endif +} +#endif // MICROPY_HW_USB_FS - #if MICROPY_HW_USB_HS - #if MICROPY_HW_STM_USB_STACK - if (hpcd->Instance == USB_OTG_HS) - #endif +#if MICROPY_HW_USB_HS +static void mp_usbd_ll_init_hs(void) { { #if MICROPY_HW_USB_HS_IN_FS @@ -291,8 +279,6 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_OTG1); LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_OTGPHY1); - LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_OTG1); - LL_AHB5_GRP1_EnableClockLowPower(LL_AHB5_GRP1_PERIPH_OTGPHY1); // Select 24MHz clock. MODIFY_REG(USB1_HS_PHYC->USBPHYC_CR, USB_USBPHYC_CR_FSEL, 2 << USB_USBPHYC_CR_FSEL_Pos); @@ -342,10 +328,41 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS); HAL_NVIC_EnableIRQ(OTG_HS_IRQn); } - #endif // MICROPY_HW_USB_HS } +#endif // MICROPY_HW_USB_HS + +#if MICROPY_HW_TINYUSB_STACK + +void mp_usbd_ll_init(void) { + // Only initialize the USB hardware once. + if (tusb_inited()) { + return; + } -#if MICROPY_HW_STM_USB_STACK + #if MICROPY_HW_USB_FS + mp_usbd_ll_init_fs(); + #endif + + #if MICROPY_HW_USB_HS + mp_usbd_ll_init_hs(); + #endif +} + +#elif MICROPY_HW_STM_USB_STACK + +void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { + #if MICROPY_HW_USB_FS + if (hpcd->Instance == USB_OTG_FS) { + mp_usbd_ll_init_fs(); + } + #endif + + #if MICROPY_HW_USB_HS + if (hpcd->Instance == USB_OTG_HS) { + mp_usbd_ll_init_hs(); + } + #endif +} /** * @brief DeInitializes the PCD MSP. diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index cb0457982d5eb..5829d68701088 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -65,7 +65,7 @@ #define USBD_HS_NUM_FIFO (1 + USBD_HS_NUM_TX_FIFO) #if MICROPY_HW_TINYUSB_STACK -void pyb_usbd_init(void); +void mp_usbd_ll_init(void); #endif #endif // MICROPY_INCLUDED_STM32_USBD_CONF_H diff --git a/ports/unix/alloc.c b/ports/unix/alloc.c index 9ab2ca04ebc97..7e1b261261e2b 100644 --- a/ports/unix/alloc.c +++ b/ports/unix/alloc.c @@ -32,7 +32,7 @@ #include "py/mpstate.h" -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE #if defined(__OpenBSD__) || defined(__MACH__) #define MAP_ANONYMOUS MAP_ANON @@ -80,4 +80,4 @@ void mp_unix_free_exec(void *ptr, size_t size) { MP_REGISTER_ROOT_POINTER(void *mmap_region_head); -#endif // MICROPY_EMIT_NATIVE +#endif // MICROPY_ENABLE_NATIVE_CODE diff --git a/ports/unix/modsocket.c b/ports/unix/modsocket.c index e7f25cdd43db7..660ace79b52ce 100644 --- a/ports/unix/modsocket.c +++ b/ports/unix/modsocket.c @@ -709,6 +709,9 @@ static const mp_rom_map_elem_t mp_module_socket_globals_table[] = { C(SO_KEEPALIVE), C(SO_LINGER), C(SO_REUSEADDR), + + C(IP_ADD_MEMBERSHIP), + C(IP_DROP_MEMBERSHIP), #undef C }; diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index 4f0550dbea765..1a9bfcd18e985 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -95,6 +95,7 @@ static mp_obj_t mp_time_sleep(mp_obj_t arg) { tv.tv_sec = (suseconds_t)ipart; int res; while (1) { + mp_handle_pending(true); MP_THREAD_GIL_EXIT(); res = sleep_select(0, NULL, NULL, NULL, &tv); MP_THREAD_GIL_ENTER(); @@ -104,7 +105,6 @@ static mp_obj_t mp_time_sleep(mp_obj_t arg) { if (res != -1 || errno != EINTR) { break; } - mp_handle_pending(true); // printf("select: EINTR: %ld:%ld\n", tv.tv_sec, tv.tv_usec); #else break; @@ -114,13 +114,13 @@ static mp_obj_t mp_time_sleep(mp_obj_t arg) { #else int seconds = mp_obj_get_int(arg); for (;;) { + mp_handle_pending(true); MP_THREAD_GIL_EXIT(); seconds = sleep(seconds); MP_THREAD_GIL_ENTER(); if (seconds == 0) { break; } - mp_handle_pending(true); } #endif return mp_const_none; diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 854da1dbd4217..e290935bca93b 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -72,6 +72,12 @@ #if !defined(MICROPY_EMIT_ARM) && defined(__arm__) && !defined(__thumb2__) #define MICROPY_EMIT_ARM (1) #endif +#if !defined(MICROPY_EMIT_RV32) && defined(__riscv) && __riscv_xlen == 32 + #define MICROPY_EMIT_RV32 (1) +#endif +#if !defined(MICROPY_PERSISTENT_CODE_LOAD_NATIVE) && defined(__riscv) && __riscv_xlen == 64 + #define MICROPY_PERSISTENT_CODE_LOAD_NATIVE (1) +#endif // Cannot include , as it may lead to symbol name clashes #if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) @@ -93,7 +99,7 @@ typedef long mp_off_t; // Always enable GC. #define MICROPY_ENABLE_GC (1) -#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__) || (defined(__riscv) && (__riscv_xlen == 64))) +#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__) || (defined(__riscv) && __riscv_xlen <= 64)) // Fall back to setjmp() implementation for discovery of GC pointers in registers. #define MICROPY_GCREGS_SETJMP (1) #endif diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index 5f5abc2e056f6..39311c98729f5 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -242,9 +242,13 @@ uint64_t mp_hal_time_ns(void) { #ifndef mp_hal_delay_ms void mp_hal_delay_ms(mp_uint_t ms) { - mp_uint_t start = mp_hal_ticks_ms(); - while (mp_hal_ticks_ms() - start < ms) { - mp_event_wait_ms(1); + if (ms) { + mp_uint_t start = mp_hal_ticks_ms(); + while (mp_hal_ticks_ms() - start < ms) { + mp_event_wait_ms(1); + } + } else { + mp_handle_pending(true); } } #endif diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt index 9db0a95c663de..cf35ba73da278 100644 --- a/ports/zephyr/CMakeLists.txt +++ b/ports/zephyr/CMakeLists.txt @@ -35,6 +35,8 @@ string(TOUPPER ZEPHYR_${BOARD} MICROPY_BOARD) include(${MICROPY_DIR}/py/py.cmake) include(${MICROPY_DIR}/extmod/extmod.cmake) +list(APPEND DTS_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/dts) + if (CONFIG_MICROPY_FROZEN_MODULES) cmake_path(ABSOLUTE_PATH CONFIG_MICROPY_FROZEN_MANIFEST BASE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) set(MICROPY_FROZEN_MANIFEST ${CONFIG_MICROPY_FROZEN_MANIFEST}) diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index f3fcd8f70d3a5..be5e322ca5598 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -211,8 +211,8 @@ run the following after you built an image with the previous command: File Systems ------------ -The Zephyr Micropython port provides 2 options for handling filesystems on the device: -The first is the Micropython filesystem management, which uses Micropython's filesystem code and +The Zephyr MicroPython port provides 2 options for handling filesystems on the device: +The first is the MicroPython filesystem management, which uses MicroPython's filesystem code and relies on zephyr's FlashArea API, this is enabled by default when `CONFIG_FLASH` and `CONFIG_FLASH_MAP` are turned on. The second option is using Zephyr's Filesystem management: @@ -241,13 +241,13 @@ Then, a fstab must be added to the dts overlay, for example: }; }; -It is then possible to use the FS like a normal Micropython filesystem: +It is then possible to use the FS like a normal MicroPython filesystem: import vfs, zephyr zfs = zephyr.FileSystem(zephyr.FileSystem.fstab()[0]) vfs.mount(zfs, "/zephyr") -You may disable Micropython's File system code to save space: +You may disable MicroPython's File system code to save space: CONFIG_MICROPY_VFS_FAT=n CONFIG_MICROPY_VFS_LFS1=n diff --git a/ports/zephyr/dts/bindings/micropython/micropython,heap.yaml b/ports/zephyr/dts/bindings/micropython/micropython,heap.yaml new file mode 100644 index 0000000000000..333baa96686ac --- /dev/null +++ b/ports/zephyr/dts/bindings/micropython/micropython,heap.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: | + MicroPython Heap + Used to define micropython heap areas. + +compatible: "micropython,heap" + +include: [base.yaml] + +properties: + size: + type: int + required: true + description: | + Size of the heap + + memory-region: + type: phandle + required: true + description: | + Memory region to place the heap in diff --git a/ports/zephyr/dts/bindings/vendor-prefixes.txt b/ports/zephyr/dts/bindings/vendor-prefixes.txt new file mode 100644 index 0000000000000..f2dc741d997d6 --- /dev/null +++ b/ports/zephyr/dts/bindings/vendor-prefixes.txt @@ -0,0 +1,15 @@ +# Device tree binding vendor prefix registry. Keep this list in +# alphabetical order. +# +# This isn't an exhaustive list, but you should add new prefixes to it +# before using them to avoid name-space collisions. +# +# The contents of this file are parsed during documentation generation. +# Anything that starts with a '#' is treated as a comment and ignored. +# Non-empty lines should be in this format: +# +# + +# zephyr-keep-sorted-start +micropython MicroPython Project +# zephyr-keep-sorted-stop diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index 0fa4e97b24186..c82814e04b5d0 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -58,6 +58,28 @@ #include "extmod/vfs.h" #endif +#if MICROPY_ENABLE_GC +#if MICROPY_GC_SPLIT_HEAP && DT_HAS_COMPAT_STATUS_OKAY(micropython_heap) + +#include + +#define MICROPY_HEAP_NAME(node) CONCAT(DT_NODE_FULL_NAME_TOKEN(node), _heap) + +#define MICROPY_HEAP_DEFINE(node) \ + static char MICROPY_HEAP_NAME(node)[DT_PROP(node, size)] \ + Z_GENERIC_SECTION(LINKER_DT_NODE_REGION_NAME(DT_PROP(node, memory_region))); + +DT_FOREACH_STATUS_OKAY(micropython_heap, MICROPY_HEAP_DEFINE) + +#define MICROPY_HEAP_ADD(node) \ + gc_add((void *)&MICROPY_HEAP_NAME(node), \ + (void *)&(MICROPY_HEAP_NAME(node)[DT_PROP(node, size) - 1])); + +#elif DT_HAS_COMPAT_STATUS_OKAY(micropython_heap) +#error Has additional Heap but split heap is not enabled +#endif +#endif + #include "modmachine.h" #include "modzephyr.h" @@ -107,6 +129,9 @@ int real_main(void) { mp_cstack_init_with_sp_here(CONFIG_MAIN_STACK_SIZE); #if MICROPY_ENABLE_GC gc_init(heap, heap + sizeof(heap)); + #if MICROPY_GC_SPLIT_HEAP && DT_HAS_COMPAT_STATUS_OKAY(micropython_heap) + DT_FOREACH_STATUS_OKAY(micropython_heap, MICROPY_HEAP_ADD) + #endif #endif mp_init(); diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index 7f84973488786..56a442c26972e 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -151,6 +151,10 @@ void mp_hal_signal_event(void); #define MICROPY_PY_MACHINE_ADC_READ_UV (1) #endif +#if DT_HAS_COMPAT_STATUS_OKAY(micropython_heap) +#define MICROPY_GC_SPLIT_HEAP (1) +#endif + typedef long mp_off_t; #define MP_STATE_PORT MP_STATE_VM diff --git a/ports/zephyr/src/usbd.c b/ports/zephyr/src/usbd.c index 36b07a8638fd0..118463a0756a5 100644 --- a/ports/zephyr/src/usbd.c +++ b/ports/zephyr/src/usbd.c @@ -56,7 +56,7 @@ USBD_DEVICE_DEFINE(mp_usbd, USBD_DESC_LANG_DEFINE(mp_lang); USBD_DESC_MANUFACTURER_DEFINE(mp_mfr, "Zephyr Project"); -USBD_DESC_PRODUCT_DEFINE(mp_product, "Micropython on Zephyr RTOS"); +USBD_DESC_PRODUCT_DEFINE(mp_product, "MicroPython on Zephyr RTOS"); USBD_DESC_SERIAL_NUMBER_DEFINE(mp_sn); USBD_DESC_CONFIG_DEFINE(fs_cfg_desc, "FS Configuration"); diff --git a/py/asmarm.h b/py/asmarm.h index 405457d4408a8..5ae952ee8a7db 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -230,6 +230,8 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); #define ASM_STORE16_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_arm_strh_reg_reg_reg((as), (reg_val), (reg_base), (reg_index)) #define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_arm_str_reg_reg_reg((as), (reg_val), (reg_base), (reg_index)) +#define ASM_CLR_REG(as, reg_dest) asm_arm_eor_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_dest)) + #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMARM_H diff --git a/py/asmbase.c b/py/asmbase.c index f1b823fa368f8..07dbf4430f9db 100644 --- a/py/asmbase.c +++ b/py/asmbase.c @@ -102,7 +102,7 @@ void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) { // align must be a multiple of 2 void mp_asm_base_align(mp_asm_base_t *as, unsigned int align) { - as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); + as->code_offset = (as->code_offset + align - 1) & (~(size_t)(align - 1)); } // this function assumes a little endian machine diff --git a/py/asmrv32.c b/py/asmrv32.c index 1d0cea6c02616..8b643af562386 100644 --- a/py/asmrv32.c +++ b/py/asmrv32.c @@ -53,6 +53,14 @@ ((((value) & ~((1U << ((bits) - 1)) - 1)) == 0) || \ (((value) & ~((1U << ((bits) - 1)) - 1)) == ~((1U << ((bits) - 1)) - 1))) +static bool asm_rv32_allow_zba_opcodes(void) { + return asm_rv32_allowed_extensions() & RV32_EXT_ZBA; +} + +static bool asm_rv32_allow_zcmp_opcodes(void) { + return asm_rv32_allowed_extensions() & RV32_EXT_ZCMP; +} + /////////////////////////////////////////////////////////////////////////////// void asm_rv32_emit_word_opcode(asm_rv32_t *state, mp_uint_t word) { @@ -214,6 +222,14 @@ static void adjust_stack(asm_rv32_t *state, mp_int_t stack_size) { return; } + // WARNING: If REG_TEMP0 is not set to a caller-saved register, then this + // bit has to be rewritten to avoid clobbering the temporary + // register when performing the stack adjustment. + + MP_STATIC_ASSERT(((REG_TEMP0 >= ASM_RV32_REG_T0) && (REG_TEMP0 <= ASM_RV32_REG_T2)) || \ + ((REG_TEMP0 >= ASM_RV32_REG_A0) && (REG_TEMP0 <= ASM_RV32_REG_A7)) || \ + ((REG_TEMP0 >= ASM_RV32_REG_T3) && (REG_TEMP0 <= ASM_RV32_REG_T6))); + // li temporary, stack_size // c.add sp, temporary load_full_immediate(state, REG_TEMP0, stack_size); @@ -245,6 +261,45 @@ static void emit_function_epilogue(asm_rv32_t *state, mp_uint_t registers) { state->saved_registers_mask = old_saved_registers_mask; } +static mp_uint_t compute_zcmp_sequence_length(mp_uint_t registers) { + // Can only handle RA and S0..S11 and must have at least one entry. + assert((registers != 0) && (registers & (~0x0FFC0302U)) == 0 && "Invalid Zcmp registers set."); + mp_uint_t length = 32 - mp_clz(((registers & 0x00000002) >> 1) | ((registers & 0x00000300) >> 7) | ((registers & 0x0FFC0000) >> 15)); + return length == 12 ? 13 : length; +} + +#define EMIT_ASSERT(state, condition, message) assert((((state)->base.pass != MP_ASM_PASS_EMIT) ? true : (condition)) && (message)) + +static void emit_compressed_function_prologue(asm_rv32_t *state, mp_uint_t registers_mask) { + mp_uint_t sequence_length = compute_zcmp_sequence_length(registers_mask); + mp_uint_t allocated_stack = (sequence_length + 3) & (mp_uint_t)-4; + EMIT_ASSERT(state, allocated_stack >= sequence_length, "Incorrect allocated stack calculation."); + mp_uint_t tail_slack = allocated_stack - sequence_length; + mp_uint_t locals_left = (state->locals_count < tail_slack) ? 0 : (state->locals_count - tail_slack); + mp_uint_t adjustment_chunks = MIN(3, locals_left / 4); + EMIT_ASSERT(state, (adjustment_chunks * 4) <= locals_left, "Incorrect adjustment chunks rounding."); + locals_left -= adjustment_chunks * 4; + EMIT_ASSERT(state, locals_left <= (MP_INT_MAX / sizeof(uint32_t)), "Too many locals."); + mp_int_t stack_size = (mp_int_t)(locals_left * sizeof(uint32_t)); + asm_rv32_opcode_cmpush(state, MIN(3 + sequence_length, 15), adjustment_chunks); + // CM.PUSH allocates a stack block and then puts the registers *at the end* + // of the block, so for example "CM.PUSH {RA, S0-S11}, -64" will put RA at + // SP + 60, not at SP + 0. + adjust_stack(state, -stack_size); + // The stack size is expressed in bytes and as a multiple of 4, hence the + // bottom two bits are not used. Since there can be up to three adjustment + // chunks, that number can be expressed in two bits, fitting nicely in the + // existing variable. + state->stack_size = ((mp_uint_t)stack_size) | adjustment_chunks; +} + +static void emit_compressed_function_epilogue(asm_rv32_t *state, mp_uint_t registers_mask) { + mp_uint_t sequence_length = compute_zcmp_sequence_length(registers_mask); + mp_uint_t stack_size = state->stack_size & (mp_uint_t)(~0x03U); + adjust_stack(state, stack_size); + asm_rv32_opcode_cmpopret(state, MIN(3 + sequence_length, 15), state->stack_size & 0x03); +} + static bool calculate_displacement_for_label(asm_rv32_t *state, mp_uint_t label, ptrdiff_t *displacement) { assert(displacement != NULL && "Displacement pointer is NULL"); @@ -256,16 +311,24 @@ static bool calculate_displacement_for_label(asm_rv32_t *state, mp_uint_t label, /////////////////////////////////////////////////////////////////////////////// void asm_rv32_entry(asm_rv32_t *state, mp_uint_t locals) { + state->locals_count = locals; state->saved_registers_mask |= (1U << REG_FUN_TABLE) | (1U << REG_LOCAL_1) | \ (1U << REG_LOCAL_2) | (1U << REG_LOCAL_3); - state->locals_count = locals; - emit_function_prologue(state, state->saved_registers_mask); + if (asm_rv32_allow_zcmp_opcodes()) { + emit_compressed_function_prologue(state, state->saved_registers_mask); + } else { + emit_function_prologue(state, state->saved_registers_mask); + } } void asm_rv32_exit(asm_rv32_t *state) { - emit_function_epilogue(state, state->saved_registers_mask); - // c.jr ra - asm_rv32_opcode_cjr(state, ASM_RV32_REG_RA); + if (asm_rv32_allow_zcmp_opcodes()) { + emit_compressed_function_epilogue(state, state->saved_registers_mask); + } else { + emit_function_epilogue(state, state->saved_registers_mask); + // c.jr ra + asm_rv32_opcode_cjr(state, ASM_RV32_REG_RA); + } } void asm_rv32_end_pass(asm_rv32_t *state) { @@ -557,10 +620,6 @@ void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) asm_rv32_opcode_xor(state, rd, rd, rs); } -static bool asm_rv32_allow_zba_opcodes(void) { - return asm_rv32_allowed_extensions() & RV32_EXT_ZBA; -} - static void asm_rv32_fix_up_scaled_reg_reg_reg(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size) { assert(operation_size <= 2 && "Operation size value out of range."); diff --git a/py/asmrv32.h b/py/asmrv32.h index 6f709daa11bce..c25b1aa4e2622 100644 --- a/py/asmrv32.h +++ b/py/asmrv32.h @@ -125,8 +125,9 @@ typedef struct _asm_rv32_t { enum { RV32_EXT_NONE = 0, RV32_EXT_ZBA = 1 << 0, + RV32_EXT_ZCMP = 1 << 1, - RV32_EXT_ALL = RV32_EXT_ZBA + RV32_EXT_ALL = RV32_EXT_ZBA | RV32_EXT_ZCMP }; typedef struct _asm_rv32_backend_options_t { @@ -196,6 +197,10 @@ void asm_rv32_end_pass(asm_rv32_t *state); ((rs & 0x07) << 7) | ((imm & 0x40) >> 1) | ((imm & 0x38) << 7) | \ ((imm & 0x04) << 4)) +#define RV32_ENCODE_TYPE_CMPP(op, ft6, ft2, rlist, imm) \ + ((op & 0x03) | ((ft6 & 0x3F) << 10) | ((ft2 & 0x03) << 8) | \ + ((rlist & 0x0F) << 4) | ((imm & 0x03) << 2)) + #define RV32_ENCODE_TYPE_CR(op, ft4, rs1, rs2) \ ((op & 0x03) | ((rs2 & 0x1F) << 2) | ((rs1 & 0x1F) << 7) | ((ft4 & 0x0F) << 12)) @@ -439,6 +444,18 @@ static inline void asm_rv32_opcode_cxor(asm_rv32_t *state, mp_uint_t rd, mp_uint asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CA(0x01, 0x23, 0x01, rd, rs)); } +// CM.POPRET {REG_LIST}, IMMEDIATE +static inline void asm_rv32_opcode_cmpopret(asm_rv32_t *state, mp_uint_t reg_list, mp_uint_t immediate) { + // CMPP: 10111110 ... .. 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CMPP(0x02, 0x2F, 0x02, reg_list, immediate)); +} + +// CM.PUSH {REG_LIST}, -IMMEDIATE +static inline void asm_rv32_opcode_cmpush(asm_rv32_t *state, mp_uint_t reg_list, mp_uint_t immediate) { + // CMPP: 10111000 .... .. 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CMPP(0x02, 0x2E, 0x00, reg_list, immediate)); +} + // CSRRC RD, RS, IMMEDIATE static inline void asm_rv32_opcode_csrrc(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t immediate) { // I: ............ ..... 011 ..... 1110011 @@ -710,7 +727,8 @@ static inline void asm_rv32_opcode_xori(asm_rv32_t *state, mp_uint_t rd, mp_uint } #define MICROPY_RV32_EXTENSIONS \ - (MICROPY_EMIT_RV32_ZBA ? RV32_EXT_ZBA : 0) + ((MICROPY_EMIT_RV32_ZBA ? RV32_EXT_ZBA : 0) | \ + (MICROPY_EMIT_RV32_ZCMP ? RV32_EXT_ZCMP : 0)) static inline uint8_t asm_rv32_allowed_extensions(void) { uint8_t extensions = MICROPY_RV32_EXTENSIONS; @@ -735,8 +753,8 @@ static inline uint8_t asm_rv32_allowed_extensions(void) { #define REG_TEMP2 ASM_RV32_REG_T3 #define REG_FUN_TABLE ASM_RV32_REG_S1 #define REG_LOCAL_1 ASM_RV32_REG_S3 -#define REG_LOCAL_2 ASM_RV32_REG_S4 -#define REG_LOCAL_3 ASM_RV32_REG_S5 +#define REG_LOCAL_2 ASM_RV32_REG_S2 +#define REG_LOCAL_3 ASM_RV32_REG_S4 #define REG_ZERO ASM_RV32_REG_ZERO void asm_rv32_meta_comparison_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd); @@ -804,7 +822,7 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_ #define ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 2) #define ASM_SUB_REG_REG(state, rd, rs) asm_rv32_opcode_sub(state, rd, rd, rs) #define ASM_XOR_REG_REG(state, rd, rs) asm_rv32_emit_optimised_xor(state, rd, rs) -#define ASM_CLR_REG(state, rd) +#define ASM_CLR_REG(state, rd) asm_rv32_emit_optimised_xor(state, rd, rd) #define ASM_LOAD8_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 0) #define ASM_LOAD16_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 1) #define ASM_LOAD32_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 2) diff --git a/py/asmthumb.h b/py/asmthumb.h index 5edf6573e1a6a..88f4e399bc85e 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -485,6 +485,8 @@ void asm_thumb_b_rel12(asm_thumb_t *as, int rel); asm_thumb_str_rlo_rlo_rlo((as), (reg_val), (reg_base), (reg_index)); \ } while (0) +#define ASM_CLR_REG(as, reg_dest) asm_thumb_mov_rlo_i8((as), (reg_dest), 0) + #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMTHUMB_H diff --git a/py/asmx64.h b/py/asmx64.h index d80c5dcc13f1a..efc3027b170ce 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -221,6 +221,8 @@ void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32); #define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) #define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (dword_offset)) +#define ASM_CLR_REG(as, reg_dest) asm_x64_xor_r64_r64((as), (reg_dest), (reg_dest)) + #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMX64_H diff --git a/py/asmx86.h b/py/asmx86.h index d2e078ad51d29..80a67794d2044 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -216,6 +216,8 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r #define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) #define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (dword_offset)) +#define ASM_CLR_REG(as, reg_dest) asm_x86_xor_r32_r32((as), (reg_dest), (reg_dest)) + #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMX86_H diff --git a/py/asmxtensa.h b/py/asmxtensa.h index 559b3cacd5d45..15f8b4d92e2c6 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -464,6 +464,8 @@ void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label); asm_xtensa_op_s32i_n((as), (reg_val), (reg_base), 0); \ } while (0) +#define ASM_CLR_REG(as, reg_dest) asm_xtensa_op_movi_n((as), (reg_dest), 0) + #endif // GENERIC_ASM_API #endif // MICROPY_INCLUDED_PY_ASMXTENSA_H diff --git a/py/bc.c b/py/bc.c index cea31c93bd8a0..777ff66fcd446 100644 --- a/py/bc.c +++ b/py/bc.c @@ -332,7 +332,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw mp_setup_code_state_helper(code_state, n_args, n_kw, args); } -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE // On entry code_state should be allocated somewhere (stack/heap) and // contain the following valid entries: // - code_state->fun_bc should contain a pointer to the function object diff --git a/py/builtinhelp.c b/py/builtinhelp.c index dc4fe582f75ef..5a84b3d7d2456 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -152,9 +152,8 @@ static void mp_help_print_obj(const mp_obj_t obj) { } if (map != NULL) { for (uint i = 0; i < map->alloc; i++) { - mp_obj_t key = map->table[i].key; - if (key != MP_OBJ_NULL) { - mp_help_print_info_about_object(key, map->table[i].value); + if (mp_map_slot_is_filled(map, i)) { + mp_help_print_info_about_object(map->table[i].key, map->table[i].value); } } } diff --git a/py/compile.c b/py/compile.c index 945ee2b2dee85..6d7e9c4a14643 100644 --- a/py/compile.c +++ b/py/compile.c @@ -103,6 +103,7 @@ static const emit_method_table_t *emit_native_table[] = { &emit_native_xtensa_method_table, &emit_native_xtensawin_method_table, &emit_native_rv32_method_table, + NULL, &emit_native_debug_method_table, }; @@ -3571,6 +3572,13 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool case MP_EMIT_OPT_NATIVE_PYTHON: case MP_EMIT_OPT_VIPER: if (emit_native == NULL) { + // The check looks like this to work around a false + // warning in GCC 13 (and possibly later), where it + // assumes that the check will always fail. + if ((uintptr_t)NATIVE_EMITTER_TABLE == (uintptr_t)NULL) { + comp->compile_error = mp_obj_new_exception_msg(&mp_type_NotImplementedError, MP_ERROR_TEXT("cannot emit native code for this architecture")); + goto emit_finished; + } emit_native = NATIVE_EMITTER(new)(&comp->emit_common, &comp->compile_error, &comp->next_label, max_num_labels); } comp->emit_method_table = NATIVE_EMITTER_TABLE; @@ -3603,6 +3611,10 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool } } + #if MICROPY_EMIT_NATIVE +emit_finished: + #endif + if (comp->compile_error != MP_OBJ_NULL) { // if there is no line number for the error then use the line // number for the start of this scope diff --git a/py/dynruntime.mk b/py/dynruntime.mk index 030728cfc9adf..3902acbd0b32a 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -106,7 +106,7 @@ else ifeq ($(ARCH),rv32imc) # rv32imc CROSS = riscv64-unknown-elf- CFLAGS_ARCH += -march=rv32imac -mabi=ilp32 -mno-relax -# If Picolibc is available then select it explicitly. Ubuntu 22.04 ships its +# If Picolibc is available then select it explicitly. Ubuntu 24.04 ships its # bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default # is "nosys" so a value must be provided. To avoid having per-distro # workarounds, always select Picolibc if available. @@ -120,6 +120,25 @@ endif MICROPY_FLOAT_IMPL ?= none +else ifeq ($(ARCH),rv64imc) + +# rv64imc +CROSS = riscv64-unknown-elf- +CFLAGS_ARCH += -march=rv64imac -mabi=lp64 -mno-relax +# If Picolibc is available then select it explicitly. Ubuntu 24.04 ships its +# bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default +# is "nosys" so a value must be provided. To avoid having per-distro +# workarounds, always select Picolibc if available. +PICOLIBC_SPECS := $(shell $(CROSS)gcc --print-file-name=picolibc.specs) +ifneq ($(PICOLIBC_SPECS),picolibc.specs) +CFLAGS_ARCH += -specs=$(PICOLIBC_SPECS) +USE_PICOLIBC := 1 +PICOLIBC_ARCH := rv64imac +PICOLIBC_ABI := lp64 +endif + +MICROPY_FLOAT_IMPL ?= none + else $(error architecture '$(ARCH)' not supported) endif @@ -175,6 +194,9 @@ endif ifneq ($(MPY_EXTERN_SYM_FILE),) MPY_LD_FLAGS += --externs "$(realpath $(MPY_EXTERN_SYM_FILE))" endif +ifneq ($(ARCH_FLAGS),) +MPY_LD_FLAGS += --arch-flags "$(ARCH_FLAGS)" +endif CFLAGS += $(CFLAGS_EXTRA) diff --git a/py/emitglue.c b/py/emitglue.c index 27cbb349ef602..6a1816c2c7962 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -32,6 +32,7 @@ #include #include "py/emitglue.h" +#include "py/mphal.h" #include "py/runtime0.h" #include "py/bc.h" #include "py/objfun.h" @@ -91,7 +92,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, #endif } -#if MICROPY_EMIT_MACHINE_CODE +#if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, const void *fun_data, mp_uint_t fun_len, mp_raw_code_t **children, #if MICROPY_PERSISTENT_CODE_SAVE @@ -106,14 +107,14 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, cons // Some architectures require flushing/invalidation of the I/D caches, // so that the generated native code which was created in data RAM will // be available for execution from instruction RAM. - #if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB + #if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB || (MP_NATIVE_ARCH_ARMV6M <= MPY_FEATURE_ARCH && MPY_FEATURE_ARCH <= MP_NATIVE_ARCH_ARMV7EMDP) #if __ICACHE_PRESENT == 1 // Flush D-cache, so the code emitted is stored in RAM. MP_HAL_CLEAN_DCACHE(fun_data, fun_len); // Invalidate I-cache, so the newly-created code is reloaded from RAM. SCB_InvalidateICache(); #endif - #elif MICROPY_EMIT_ARM + #elif MICROPY_EMIT_ARM || (MPY_FEATURE_ARCH == MP_NATIVE_ARCH_ARMV6) #if (defined(__linux__) && defined(__GNUC__)) || __ARM_ARCH == 7 __builtin___clear_cache((void *)fun_data, (char *)fun_data + fun_len); #elif defined(__arm__) @@ -126,6 +127,9 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, cons "mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache : : : "r0", "cc"); #endif + #elif (MICROPY_EMIT_RV32 || MICROPY_EMIT_INLINE_RV32 || (MPY_FEATURE_ARCH == MP_NATIVE_ARCH_RV32IMC)) && defined(MP_HAL_CLEAN_DCACHE) + // Flush the D-cache. + MP_HAL_CLEAN_DCACHE(fun_data, fun_len); #endif rc->kind = kind; @@ -179,7 +183,7 @@ mp_obj_t mp_make_function_from_proto_fun(mp_proto_fun_t proto_fun, const mp_modu // def_kw_args must be MP_OBJ_NULL or a dict assert(def_args == NULL || def_args[1] == MP_OBJ_NULL || mp_obj_is_type(def_args[1], &mp_type_dict)); - #if MICROPY_MODULE_FROZEN_MPY + #if MICROPY_MODULE_FROZEN_MPY || MICROPY_PY_FUNCTION_ATTRS_CODE if (mp_proto_fun_is_bytecode(proto_fun)) { const uint8_t *bc = proto_fun; mp_obj_t fun = mp_obj_new_fun_bc(def_args, bc, context, NULL); @@ -197,7 +201,7 @@ mp_obj_t mp_make_function_from_proto_fun(mp_proto_fun_t proto_fun, const mp_modu // make the function, depending on the raw code kind mp_obj_t fun; switch (rc->kind) { - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE case MP_CODE_NATIVE_PY: fun = mp_obj_new_fun_native(def_args, rc->fun_data, context, rc->children); // Check for a generator function, and if so change the type of the object diff --git a/py/emitglue.h b/py/emitglue.h index 126462671b003..6e2add803391a 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -80,7 +80,7 @@ typedef struct _mp_raw_code_t { #if MICROPY_PERSISTENT_CODE_SAVE uint32_t fun_data_len; // for mp_raw_code_save uint16_t n_children; - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE uint16_t prelude_offset; #endif #if MICROPY_PY_SYS_SETTRACE @@ -110,7 +110,7 @@ typedef struct _mp_raw_code_truncated_t { #if MICROPY_PERSISTENT_CODE_SAVE uint32_t fun_data_len; uint16_t n_children; - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE uint16_t prelude_offset; #endif #if MICROPY_PY_SYS_SETTRACE diff --git a/py/emitinlinerv32.c b/py/emitinlinerv32.c index a5f4c49c29409..e81b152087de3 100644 --- a/py/emitinlinerv32.c +++ b/py/emitinlinerv32.c @@ -390,9 +390,9 @@ static const opcode_t OPCODES[] = { // These two checks assume the bitmasks are contiguous. -static bool is_in_signed_mask(mp_uint_t mask, mp_uint_t value) { - mp_uint_t leading_zeroes = mp_clz(mask); - if (leading_zeroes == 0 || leading_zeroes > 32) { +static bool is_in_signed_mask(uint32_t mask, mp_uint_t value) { + uint32_t leading_zeroes = mp_clz(mask); + if (leading_zeroes == 0) { return true; } mp_uint_t positive_mask = ~(mask & ~(1U << (31 - leading_zeroes))); diff --git a/py/emitnative.c b/py/emitnative.c index a33ec01ec0f94..6cf01dcab1328 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -282,17 +282,13 @@ struct _emit_t { ASM_T *as; }; -#ifndef REG_ZERO -#define REG_ZERO REG_TEMP0 -#define ASM_CLR_REG(state, rd) ASM_XOR_REG_REG(state, rd, rd) -#endif - -#if N_RV32 +#ifdef REG_ZERO #define ASM_MOV_LOCAL_MP_OBJ_NULL(as, local_num, reg_temp) \ ASM_MOV_LOCAL_REG(as, local_num, REG_ZERO) #else +#define REG_ZERO REG_TEMP0 #define ASM_MOV_LOCAL_MP_OBJ_NULL(as, local_num, reg_temp) \ - ASM_MOV_REG_IMM(as, reg_temp, (mp_uint_t)MP_OBJ_NULL); \ + ASM_CLR_REG(as, reg_temp); \ ASM_MOV_LOCAL_REG(as, local_num, reg_temp) #endif @@ -1145,7 +1141,7 @@ static void emit_native_leave_exc_stack(emit_t *emit, bool start_of_handler) { // Optimisation: PC is already cleared by global exc handler return; } - ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET); + ASM_CLR_REG(emit->as, REG_RET); } else { // Found new active handler, get its PC ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label); @@ -1242,8 +1238,7 @@ static void emit_native_global_exc_entry(emit_t *emit) { ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, true); } else { // Clear the unwind state - ASM_CLR_REG(emit->as, REG_ZERO); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_ZERO); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_ZERO); // clear nlr.ret_val, because it's passed to mp_native_raise regardless // of whether there was an exception or not @@ -1263,8 +1258,7 @@ static void emit_native_global_exc_entry(emit_t *emit) { ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, global_except_label, true); // Clear PC of current code block, and jump there to resume execution - ASM_CLR_REG(emit->as, REG_ZERO); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_ZERO); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_ZERO); ASM_JUMP_REG(emit->as, REG_LOCAL_1); // Global exception handler: check for valid exception handler @@ -1945,7 +1939,7 @@ static void emit_native_delete_attr(emit_t *emit, qstr qst) { vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base assert(vtype_base == VTYPE_PYOBJ); - ASM_XOR_REG_REG(emit->as, REG_ARG_3, REG_ARG_3); // arg3 = value (null for delete) + ASM_CLR_REG(emit->as, REG_ARG_3); // arg3 = value (null for delete) emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name emit_post(emit); } @@ -2091,7 +2085,7 @@ static void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t exc // No finally, handle the jump ourselves // First, restore the exception handler address for the jump if (e < emit->exc_stack) { - ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET); + ASM_CLR_REG(emit->as, REG_RET); } else { ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label); } diff --git a/py/emitndebug.c b/py/emitndebug.c index e49c5cdbffa7b..2144d14e6b57a 100644 --- a/py/emitndebug.c +++ b/py/emitndebug.c @@ -271,6 +271,9 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #define ASM_STORE32_REG_REG(as, reg_src, reg_base) \ asm_debug_reg_reg(as, "store32", reg_src, reg_base) +#define ASM_CLR_REG(as, reg_dest) \ + asm_debug_reg(as, "clr", reg_dest) + // Word indices of REG_LOCAL_x in nlr_buf_t #define NLR_BUF_IDX_LOCAL_1 (5) // rbx diff --git a/py/misc.h b/py/misc.h index 5188b8030db5c..ab266084c8bd9 100644 --- a/py/misc.h +++ b/py/misc.h @@ -411,11 +411,6 @@ static inline uint32_t mp_ctz(uint32_t x) { return _BitScanForward(&tz, x) ? tz : 0; } -// Workaround for 'warning C4127: conditional expression is constant'. -static inline bool mp_check(bool value) { - return value; -} - static inline uint32_t mp_popcount(uint32_t x) { return __popcnt(x); } @@ -424,7 +419,6 @@ static inline uint32_t mp_popcount(uint32_t x) { #define mp_clzl(x) __builtin_clzl(x) #define mp_clzll(x) __builtin_clzll(x) #define mp_ctz(x) __builtin_ctz(x) -#define mp_check(x) (x) #if __has_builtin(__builtin_popcount) #define mp_popcount(x) __builtin_popcount(x) #else @@ -559,4 +553,30 @@ static inline bool mp_sub_ll_overflow(long long int lhs, long long int rhs, long #define MP_SANITIZER_BUILD (MP_UBSAN || MP_ASAN) #endif +// halfword/word/longword swapping macros + +#if __has_builtin(__builtin_bswap16) +#define MP_BSWAP16(x) __builtin_bswap16(x) +#else +#define MP_BSWAP16(x) ((uint16_t)((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF))) +#endif + +#if __has_builtin(__builtin_bswap32) +#define MP_BSWAP32(x) __builtin_bswap32(x) +#else +#define MP_BSWAP32(x) \ + ((uint32_t)((((x) & 0xFF) << 24) | (((x) & 0xFF00) << 8) | \ + (((x) >> 8) & 0xFF00) | (((x) >> 24) & 0xFF))) +#endif + +#if __has_builtin(__builtin_bswap64) +#define MP_BSWAP64(x) __builtin_bswap64(x) +#else +#define MP_BSWAP64(x) \ + ((uint64_t)((((x) & 0xFF) << 56) | (((x) & 0xFF00) << 40) | \ + (((x) & 0xFF0000) << 24) | (((x) & 0xFF000000) << 8) | \ + (((x) >> 8) & 0xFF000000) | (((x) >> 24) & 0xFF0000) | \ + (((x) >> 40) & 0xFF00) | (((x) >> 56) & 0xFF))) +#endif + #endif // MICROPY_INCLUDED_PY_MISC_H diff --git a/py/mpconfig.h b/py/mpconfig.h index 97c40389b32f0..9a2c753462e60 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -39,7 +39,7 @@ // as well as a fallback to generate MICROPY_GIT_TAG if the git repo or tags // are unavailable. #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 27 +#define MICROPY_VERSION_MINOR 28 #define MICROPY_VERSION_MICRO 0 #define MICROPY_VERSION_PRERELEASE 1 @@ -411,6 +411,11 @@ typedef uint64_t mp_uint_t; #define MICROPY_PERSISTENT_CODE_LOAD (0) #endif +// Whether to support loading of persistent native code +#ifndef MICROPY_PERSISTENT_CODE_LOAD_NATIVE +#define MICROPY_PERSISTENT_CODE_LOAD_NATIVE (MICROPY_EMIT_MACHINE_CODE) +#endif + // Whether to support saving of persistent code, i.e. for mpy-cross to // generate .mpy files. Enabling this enables additional metadata on raw code // objects which is also required for sys.settrace. @@ -431,7 +436,7 @@ typedef uint64_t mp_uint_t; // Whether generated code can persist independently of the VM/runtime instance // This is enabled automatically when needed by other features #ifndef MICROPY_PERSISTENT_CODE -#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY) +#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_LOAD_NATIVE || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY) #endif // Whether bytecode uses a qstr_table to map internal qstr indices in the bytecode @@ -507,6 +512,11 @@ typedef uint64_t mp_uint_t; #define MICROPY_EMIT_RV32_ZBA (0) #endif +// Whether to emit RISC-V RV32 Zcmp opcodes in native code +#ifndef MICROPY_EMIT_RV32_ZCMP +#define MICROPY_EMIT_RV32_ZCMP (0) +#endif + // Whether to enable the RISC-V RV32 inline assembler #ifndef MICROPY_EMIT_INLINE_RV32 #define MICROPY_EMIT_INLINE_RV32 (0) @@ -531,6 +541,10 @@ typedef uint64_t mp_uint_t; // Convenience definition for whether any native or inline assembler emitter is enabled #define MICROPY_EMIT_MACHINE_CODE (MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM) +// Convenience definition for whether native code has to be dealt with (either +// generated or loaded from a file). This does not cover inline asm code. +#define MICROPY_ENABLE_NATIVE_CODE (MICROPY_EMIT_NATIVE || MICROPY_PERSISTENT_CODE_LOAD_NATIVE) + /*****************************************************************************/ /* Compiler configuration */ @@ -1267,7 +1281,7 @@ typedef time_t mp_timestamp_t; // Whether to implement the __code__ attribute on functions, and function constructor #ifndef MICROPY_PY_FUNCTION_ATTRS_CODE -#define MICROPY_PY_FUNCTION_ATTRS_CODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES) +#define MICROPY_PY_FUNCTION_ATTRS_CODE (MICROPY_PY_MARSHAL || MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES) #endif // Whether bound_method can just use == (feature disabled), or requires a call to @@ -2271,7 +2285,7 @@ typedef time_t mp_timestamp_t; // can be overridden if needed by defining both MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA // and MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA. #ifndef MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA -#if MICROPY_EMIT_MACHINE_CODE && MICROPY_PERSISTENT_CODE_LOAD +#if (MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE) && MICROPY_PERSISTENT_CODE_LOAD // Pointer tracking is required when loading native code is enabled. #if defined(MP_PLAT_ALLOC_EXEC) || defined(MP_PLAT_COMMIT_EXEC) // If a port defined a custom allocator or commit function for native text, then the @@ -2292,7 +2306,7 @@ typedef time_t mp_timestamp_t; #define MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA (1) #define MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA (0) #endif -#else // MICROPY_EMIT_MACHINE_CODE && MICROPY_PERSISTENT_CODE_LOAD +#else // (MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE) && MICROPY_PERSISTENT_CODE_LOAD // Pointer tracking not needed when loading native code is disabled. #define MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA (0) #define MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA (0) @@ -2380,7 +2394,7 @@ typedef time_t mp_timestamp_t; #ifndef MP_HTOBE16 #if MP_ENDIANNESS_LITTLE -#define MP_HTOBE16(x) ((uint16_t)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))) +#define MP_HTOBE16(x) MP_BSWAP16(x) #define MP_BE16TOH(x) MP_HTOBE16(x) #else #define MP_HTOBE16(x) (x) @@ -2390,7 +2404,7 @@ typedef time_t mp_timestamp_t; #ifndef MP_HTOBE32 #if MP_ENDIANNESS_LITTLE -#define MP_HTOBE32(x) ((uint32_t)((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff))) +#define MP_HTOBE32(x) MP_BSWAP32(x) #define MP_BE32TOH(x) MP_HTOBE32(x) #else #define MP_HTOBE32(x) (x) diff --git a/py/nativeglue.c b/py/nativeglue.c index 6bf16f1acc29a..e4aa635cf1c64 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -41,7 +41,7 @@ #define DEBUG_printf(...) (void)0 #endif -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE int mp_native_type_from_qstr(qstr qst) { switch (qst) { @@ -91,7 +91,7 @@ mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { #endif -#if MICROPY_EMIT_MACHINE_CODE +#if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE // convert a native value to a MicroPython object based on type mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { @@ -115,7 +115,7 @@ mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { #endif -#if MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER +#if MICROPY_ENABLE_NATIVE_CODE && !MICROPY_DYNAMIC_COMPILER #if !MICROPY_PY_BUILTINS_SET mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) { @@ -354,8 +354,8 @@ const mp_fun_table_t mp_fun_table = { &mp_stream_write_obj, }; -#elif MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER +#elif MICROPY_ENABLE_NATIVE_CODE && MICROPY_DYNAMIC_COMPILER const int mp_fun_table; -#endif // MICROPY_EMIT_NATIVE +#endif // MICROPY_ENABLE_NATIVE_CODE diff --git a/py/nativeglue.h b/py/nativeglue.h index 2c7923c56df85..92d3889df393a 100644 --- a/py/nativeglue.h +++ b/py/nativeglue.h @@ -181,9 +181,9 @@ typedef struct _mp_fun_table_t { const mp_obj_fun_builtin_var_t *stream_write_obj; } mp_fun_table_t; -#if (MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER) || MICROPY_ENABLE_DYNRUNTIME +#if (MICROPY_ENABLE_NATIVE_CODE && !MICROPY_DYNAMIC_COMPILER) || MICROPY_ENABLE_DYNRUNTIME extern const mp_fun_table_t mp_fun_table; -#elif MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER +#elif MICROPY_ENABLE_NATIVE_CODE && MICROPY_DYNAMIC_COMPILER // In dynamic-compiler mode eliminate dependency on entries in mp_fun_table. // This only needs to be an independent pointer, content doesn't matter. extern const int mp_fun_table; diff --git a/py/objfun.c b/py/objfun.c index a742c5267254c..996ac8616001b 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -136,7 +136,7 @@ qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) { const mp_obj_fun_bc_t *fun = MP_OBJ_TO_PTR(fun_in); const byte *bc = fun->bytecode; - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE if (fun->base.type == &mp_type_fun_native || fun->base.type == &mp_type_native_gen_wrap) { bc = mp_obj_fun_native_get_prelude_ptr(fun); } @@ -369,11 +369,24 @@ void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { #if MICROPY_PY_FUNCTION_ATTRS_CODE if (attr == MP_QSTR___code__) { const mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); - if ((self->base.type == &mp_type_fun_bc - || self->base.type == &mp_type_gen_wrap) - && self->child_table == NULL) { + if (self->base.type == &mp_type_fun_bc + || self->base.type == &mp_type_gen_wrap) { #if MICROPY_PY_BUILTINS_CODE <= MICROPY_PY_BUILTINS_CODE_BASIC - dest[0] = mp_obj_new_code(self->context->constants, self->bytecode); + #if MICROPY_PERSISTENT_CODE_SAVE + #error "MICROPY_PERSISTENT_CODE_SAVE can't be enabled at this level of MICROPY_PY_BUILTINS_CODE" + #endif + mp_proto_fun_t proto_fun; + if (self->child_table != NULL) { + mp_raw_code_truncated_t *rc = m_new0(mp_raw_code_truncated_t, 1); + rc->kind = MP_CODE_BYTECODE; + rc->is_generator = self->base.type == &mp_type_gen_wrap; + rc->fun_data = self->bytecode; + rc->children = (mp_raw_code_t **)self->child_table; + proto_fun = rc; + } else { + proto_fun = self->bytecode; + } + dest[0] = mp_obj_new_code(self->context->constants, proto_fun); #else dest[0] = mp_obj_new_code(self->context, self->rc, true); #endif @@ -443,7 +456,7 @@ mp_obj_t mp_obj_new_fun_bc(const mp_obj_t *def_args, const byte *code, const mp_ /******************************************************************************/ /* native functions */ -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE static mp_obj_t fun_native_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_cstack_check(); @@ -472,13 +485,9 @@ MP_DEFINE_CONST_OBJ_TYPE( call, fun_native_call ); -#endif // MICROPY_EMIT_NATIVE - /******************************************************************************/ /* viper functions */ -#if MICROPY_EMIT_NATIVE - static mp_obj_t fun_viper_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_cstack_check(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); @@ -493,7 +502,7 @@ MP_DEFINE_CONST_OBJ_TYPE( call, fun_viper_call ); -#endif // MICROPY_EMIT_NATIVE +#endif // MICROPY_ENABLE_NATIVE_CODE /******************************************************************************/ /* inline assembler functions */ diff --git a/py/objfun.h b/py/objfun.h index f16ef76b80e70..8494eb4bf6608 100644 --- a/py/objfun.h +++ b/py/objfun.h @@ -53,7 +53,7 @@ typedef struct _mp_obj_fun_asm_t { mp_obj_t mp_obj_new_fun_bc(const mp_obj_t *def_args, const byte *code, const mp_module_context_t *cm, struct _mp_raw_code_t *const *raw_code_table); void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE static inline mp_obj_t mp_obj_new_fun_native(const mp_obj_t *def_args, const void *fun_data, const mp_module_context_t *mc, struct _mp_raw_code_t *const *child_table) { mp_obj_fun_bc_t *o = (mp_obj_fun_bc_t *)MP_OBJ_TO_PTR(mp_obj_new_fun_bc(def_args, (const byte *)fun_data, mc, child_table)); diff --git a/py/objgenerator.c b/py/objgenerator.c index df9701094b80c..e2a02d494ed1c 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -87,7 +87,7 @@ MP_DEFINE_CONST_OBJ_TYPE( /******************************************************************************/ // native generator wrapper -#if MICROPY_EMIT_NATIVE +#if MICROPY_ENABLE_NATIVE_CODE // Based on mp_obj_gen_instance_t. typedef struct _mp_obj_gen_instance_native_t { @@ -139,7 +139,7 @@ MP_DEFINE_CONST_OBJ_TYPE( NATIVE_GEN_WRAP_TYPE_ATTR ); -#endif // MICROPY_EMIT_NATIVE +#endif // MICROPY_ENABLE_NATIVE_CODE /******************************************************************************/ /* generator instance */ @@ -175,7 +175,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ // If the generator is started, allow sending a value. void *state_start = self->code_state.state - 1; - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { state_start = ((mp_obj_gen_instance_native_t *)self)->code_state.state - 1; } @@ -197,7 +197,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ mp_vm_return_kind_t ret_kind; - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { // A native generator. typedef uintptr_t (*mp_fun_native_gen_t)(void *, mp_obj_t); @@ -235,7 +235,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ case MP_VM_RETURN_EXCEPTION: { self->code_state.ip = 0; - #if MICROPY_EMIT_NATIVE + #if MICROPY_ENABLE_NATIVE_CODE if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { *ret_val = ((mp_obj_gen_instance_native_t *)self)->code_state.state[0]; } else diff --git a/py/persistentcode.c b/py/persistentcode.c index b12c100743392..2c7a425656623 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -76,7 +76,7 @@ typedef struct _bytecode_prelude_t { static int read_byte(mp_reader_t *reader); static size_t read_uint(mp_reader_t *reader); -#if MICROPY_EMIT_MACHINE_CODE +#if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA @@ -222,7 +222,7 @@ static mp_obj_t mp_obj_new_str_static(const mp_obj_type_t *type, const byte *dat static mp_obj_t load_obj(mp_reader_t *reader) { byte obj_type = read_byte(reader); - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE if (obj_type == MP_PERSISTENT_OBJ_FUN_TABLE) { return MP_OBJ_FROM_PTR(&mp_fun_table); } else @@ -295,14 +295,14 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co bool has_children = !!(kind_len & 4); size_t fun_data_len = kind_len >> 3; - #if !MICROPY_EMIT_MACHINE_CODE + #if !(MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE) if (kind != MP_CODE_BYTECODE) { mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); } #endif uint8_t *fun_data = NULL; - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE size_t prelude_offset = 0; mp_uint_t native_scope_flags = 0; mp_uint_t native_n_pos_args = 0; @@ -322,7 +322,7 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co read_bytes(reader, fun_data, fun_data_len); } - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE } else { // Allocate memory for native data and load it size_t fun_alloc; @@ -349,7 +349,7 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co size_t n_children = 0; mp_raw_code_t **children = NULL; - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE // Load optional BSS/rodata for viper. uint8_t *rodata = NULL; uint8_t *bss = NULL; @@ -404,7 +404,7 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co #endif scope_flags); - #if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE } else { const uint8_t *prelude_ptr = NULL; #if MICROPY_EMIT_NATIVE_PRELUDE_SEPARATE_FROM_MACHINE_CODE @@ -844,8 +844,28 @@ static mp_opcode_t mp_opcode_decode(const uint8_t *ip) { return op; } -mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, const uint8_t *bytecode) { - const uint8_t *fun_data = bytecode; +typedef struct _mp_raw_code_simplified_t { + const uint8_t *fun_data; + struct _mp_raw_code_simplified_t *children; + size_t fun_data_len; + size_t n_children; +} mp_raw_code_simplified_t; + +static void proto_fun_to_raw_code_simplified(const void *proto_fun, bit_vector_t *qstr_table_used, bit_vector_t *obj_table_used, mp_raw_code_simplified_t *rcs) { + const uint8_t *fun_data; + mp_raw_code_t **children; + if (mp_proto_fun_is_bytecode(proto_fun)) { + fun_data = proto_fun; + children = NULL; + } else { + const mp_raw_code_t *rc = proto_fun; + if (rc->kind != MP_CODE_BYTECODE) { + mp_raise_ValueError(MP_ERROR_TEXT("function must be bytecode")); + } + fun_data = rc->fun_data; + children = rc->children; + } + const uint8_t *fun_data_top = fun_data + gc_nbytes(fun_data); // Extract function information. @@ -853,20 +873,12 @@ mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, cons MP_BC_PRELUDE_SIG_DECODE(ip); MP_BC_PRELUDE_SIZE_DECODE(ip); - // Track the qstrs used by the function. - bit_vector_t qstr_table_used; - bit_vector_init(&qstr_table_used); - - // Track the objects used by the function. - bit_vector_t obj_table_used; - bit_vector_init(&obj_table_used); - const byte *ip_names = ip; mp_uint_t simple_name = mp_decode_uint(&ip_names); - bit_vector_set(&qstr_table_used, simple_name); + bit_vector_set(qstr_table_used, simple_name); for (size_t i = 0; i < n_pos_args + n_kwonly_args; ++i) { mp_uint_t arg_name = mp_decode_uint(&ip_names); - bit_vector_set(&qstr_table_used, arg_name); + bit_vector_set(qstr_table_used, arg_name); } // Skip pass source code info and cell info. @@ -874,20 +886,74 @@ mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, cons ip += n_info + n_cell; // Decode bytecode. + size_t n_children = 0; while (ip < fun_data_top) { mp_opcode_t op = mp_opcode_decode(ip); if (op.opcode == MP_BC_BASE_RESERVED) { // End of opcodes. fun_data_top = ip; - } else if (op.opcode == MP_BC_LOAD_CONST_OBJ) { - bit_vector_set(&obj_table_used, op.arg); } else if (op.format == MP_BC_FORMAT_QSTR) { - bit_vector_set(&qstr_table_used, op.arg); + bit_vector_set(qstr_table_used, op.arg); + } else if (op.opcode == MP_BC_LOAD_CONST_OBJ) { + bit_vector_set(obj_table_used, op.arg); + } else if (op.opcode == MP_BC_MAKE_FUNCTION + || op.opcode == MP_BC_MAKE_FUNCTION_DEFARGS + || op.opcode == MP_BC_MAKE_CLOSURE + || op.opcode == MP_BC_MAKE_CLOSURE_DEFARGS) { + if ((mp_uint_t)op.arg + 1 > n_children) { + n_children = (mp_uint_t)op.arg + 1; + } } ip += op.size; } - mp_uint_t fun_data_len = fun_data_top - fun_data; + rcs->fun_data = fun_data; + rcs->fun_data_len = fun_data_top - fun_data; + rcs->n_children = n_children; + rcs->children = NULL; + + if (n_children) { + rcs->children = m_new(mp_raw_code_simplified_t, n_children); + for (size_t i = 0; i < n_children; ++i) { + proto_fun_to_raw_code_simplified(children[i], qstr_table_used, obj_table_used, &rcs->children[i]); + } + } +} + +static void save_raw_code_simplified(mp_print_t *print, const mp_raw_code_simplified_t *rcs) { + // Save function kind and data length. + mp_print_uint(print, rcs->fun_data_len << 3 | (rcs->n_children != 0) << 2); + + // Save function code. + mp_print_bytes(print, rcs->fun_data, rcs->fun_data_len); + + // Save (and free) children. + if (rcs->n_children) { + mp_print_uint(print, rcs->n_children); + for (size_t i = 0; i < rcs->n_children; ++i) { + save_raw_code_simplified(print, &rcs->children[i]); + } + m_del(mp_raw_code_simplified_t, rcs->children, rcs->n_children); + } +} + +mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, mp_proto_fun_t proto_fun) { + // Track the qstrs used by the function. + bit_vector_t qstr_table_used; + bit_vector_init(&qstr_table_used); + + // Track the objects used by the function. + bit_vector_t obj_table_used; + bit_vector_init(&obj_table_used); + + #if MICROPY_PY_BUILTINS_CODE >= MICROPY_PY_BUILTINS_CODE_FULL + // Make sure the filename appears in the qstr table. + bit_vector_set(&qstr_table_used, 0); + #endif + + // Convert function into a simplified raw code tree. + mp_raw_code_simplified_t rcs; + proto_fun_to_raw_code_simplified(proto_fun, &qstr_table_used, &obj_table_used, &rcs); mp_print_t print; vstr_t vstr; @@ -922,11 +988,8 @@ mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, cons bit_vector_clear(&qstr_table_used); bit_vector_clear(&obj_table_used); - // Save function kind and data length. - mp_print_uint(&print, fun_data_len << 3); - - // Save function code. - mp_print_bytes(&print, fun_data, fun_data_len); + // Save the bytecode data (also free the simplified raw code tree at the same time). + save_raw_code_simplified(&print, &rcs); // Create and return bytes representing the .mpy data. return mp_obj_new_bytes_from_vstr(&vstr); diff --git a/py/persistentcode.h b/py/persistentcode.h index 8fd7068e3cd52..23cb0936f2f08 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -48,31 +48,44 @@ #define MPY_FEATURE_DECODE_ARCH(feat) (((feat) >> 2) & 0x2F) // Define the host architecture -#if MICROPY_EMIT_X86 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) -#elif MICROPY_EMIT_X64 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) -#elif MICROPY_EMIT_THUMB - #if defined(__thumb2__) - #if defined(__ARM_FP) && (__ARM_FP & 8) == 8 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMDP) - #elif defined(__ARM_FP) && (__ARM_FP & 4) == 4 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMSP) +#if MICROPY_PERSISTENT_CODE_LOAD_NATIVE + #if defined(__i386__) || defined(_M_IX86) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) + #elif defined(__x86_64__) || defined(_M_X64) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) + #elif defined(__thumb2__) || defined(__thumb__) + #if defined(__thumb2__) + #if defined(__ARM_FP) && (__ARM_FP & 8) == 8 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMDP) + #elif defined(__ARM_FP) && (__ARM_FP & 4) == 4 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMSP) + #else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EM) + #endif #else - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EM) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6M) + #endif + #define MPY_FEATURE_ARCH_TEST(x) (MP_NATIVE_ARCH_ARMV6M <= (x) && (x) <= MPY_FEATURE_ARCH) + #elif defined(__arm__) + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) + #elif defined(__xtensa__) + #include + #if XCHAL_HAVE_WINDOWED + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) + #else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) + #endif + #elif defined(__riscv) + #if __riscv_xlen == 32 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_RV32IMC) + #elif __riscv_xlen == 64 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_RV64IMC) + #else + #error "Unsupported RISC-V architecture." #endif #else - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6M) + #error "Unsupported native architecture." #endif - #define MPY_FEATURE_ARCH_TEST(x) (MP_NATIVE_ARCH_ARMV6M <= (x) && (x) <= MPY_FEATURE_ARCH) -#elif MICROPY_EMIT_ARM - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) -#elif MICROPY_EMIT_XTENSA - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) -#elif MICROPY_EMIT_XTENSAWIN - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) -#elif MICROPY_EMIT_RV32 - #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_RV32IMC) #else #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) #endif @@ -126,7 +139,7 @@ void mp_raw_code_load_file(qstr filename, mp_compiled_module_t *ctx); void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print); void mp_raw_code_save_file(mp_compiled_module_t *cm, qstr filename); -mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, const uint8_t *bytecode); +mp_obj_t mp_raw_code_save_fun_to_bytes(const mp_module_constants_t *consts, mp_proto_fun_t proto_fun); void mp_native_relocate(void *reloc, uint8_t *text, uintptr_t reloc_text); diff --git a/py/runtime.c b/py/runtime.c index ddc1ef7d3ead0..8d7e11e5f0dab 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -123,7 +123,7 @@ void mp_init(void) { MP_STATE_VM(mp_module_builtins_override_dict) = NULL; #endif - #if MICROPY_EMIT_MACHINE_CODE && (MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA) + #if (MICROPY_EMIT_INLINE_ASM || MICROPY_ENABLE_NATIVE_CODE) && (MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA) MP_STATE_VM(persistent_code_root_pointers) = MP_OBJ_NULL; #endif diff --git a/pyproject.toml b/pyproject.toml index f3693eae1b420..2f71058f60759 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.codespell] count = "" ignore-regex = '\b[A-Z]{3}\b' -ignore-words-list = "ans,asend,deques,dout,emac,extint,hsi,iput,mis,notin,numer,ser,shft,synopsys,technic,ure,curren" +ignore-words-list = "ans,asend,deques,dout,emac,extint,hsi,iput,mis,notin,numer,ser,shft,som,synopsys,technic,ure,curren" quiet-level = 3 skip = """ */build*,\ @@ -22,11 +22,17 @@ ACKNOWLEDGEMENTS,\ [tool.ruff] # Exclude third-party code from linting and formatting -extend-exclude = ["lib"] +extend-exclude = [ + "lib", + "esp-idf", + "pico-sdk", + "emsdk", + "tests/cpydiff/syntax_assign_expr.py" # intentionally incorrect CPython code +] # Include Python source files that don't end with .py extend-include = ["tools/cc1"] line-length = 99 -target-version = "py37" +target-version = "py38" [tool.ruff.lint] exclude = [ # Ruff finds Python SyntaxError in these files @@ -44,7 +50,7 @@ exclude = [ # Ruff finds Python SyntaxError in these files "tests/micropython/viper_args.py", ] extend-select = ["C9", "PLC"] -ignore = [ +extend-ignore = [ "E401", "E402", "E722", @@ -54,6 +60,7 @@ ignore = [ "F403", "F405", "PLC0206", + "PLC0415", # conditional imports are common in MicroPython ] mccabe.max-complexity = 40 @@ -64,6 +71,8 @@ mccabe.max-complexity = 40 # manifest.py files are evaluated with some global names pre-defined "**/manifest.py" = ["F821"] "ports/**/boards/**/manifest_*.py" = ["F821"] +# Uses assignment expressions. +"tests/cpydiff/syntax_assign_expr.py" = ["F821"] [tool.ruff.format] # Exclude third-party code, and exclude the following tests: diff --git a/shared/tinyusb/mp_usbd.h b/shared/tinyusb/mp_usbd.h index 311575b3ad8ba..d73cb5ade828c 100644 --- a/shared/tinyusb/mp_usbd.h +++ b/shared/tinyusb/mp_usbd.h @@ -45,6 +45,10 @@ #define MICROPY_WRAP_TUD_EVENT_HOOK_CB(name) name #endif +#ifndef MICROPY_HW_TINYUSB_LL_INIT +#define MICROPY_HW_TINYUSB_LL_INIT() +#endif + #if MICROPY_HW_ENABLE_USBDEV #include "py/obj.h" @@ -102,6 +106,7 @@ void mp_usbd_task_callback(mp_sched_node_t *node); static inline void mp_usbd_init(void) { // Without runtime USB support, this can be a thin wrapper wrapper around tusb_init() // which is called in the below helper function. + MICROPY_HW_TINYUSB_LL_INIT(); mp_usbd_init_tud(); } diff --git a/shared/tinyusb/mp_usbd_runtime.c b/shared/tinyusb/mp_usbd_runtime.c index 72e011732d400..ef6bd87eddac1 100644 --- a/shared/tinyusb/mp_usbd_runtime.c +++ b/shared/tinyusb/mp_usbd_runtime.c @@ -44,6 +44,8 @@ #include "device/usbd_pvt.h" #endif +#define RHPORT TUD_OPT_RHPORT + static bool in_usbd_task; // Flags if mp_usbd_task() is currently running // Some top-level functions that manage global TinyUSB USBD state, not the @@ -233,7 +235,7 @@ static uint16_t _runtime_dev_claim_itfs(tusb_desc_interface_t const *itf_desc, u } else if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { // Open any endpoints that we come across if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { - bool r = usbd_edpt_open(USBD_RHPORT, (const void *)p_desc); + bool r = usbd_edpt_open(RHPORT, (const void *)p_desc); if (!r) { mp_obj_t exc = mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENODEV)); usbd_pend_exception(exc); @@ -322,7 +324,7 @@ static bool runtime_dev_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_cont // Check if callback returned any data to submit if (mp_get_buffer(cb_res, &buf_info, dir == TUSB_DIR_IN ? MP_BUFFER_READ : MP_BUFFER_RW)) { - result = tud_control_xfer(USBD_RHPORT, + result = tud_control_xfer(RHPORT, request, buf_info.buf, buf_info.len); @@ -430,6 +432,8 @@ void mp_usbd_init(void) { } if (need_usb) { + // Call any port-specific initialization code. + MICROPY_HW_TINYUSB_LL_INIT(); // The following will call tusb_init(), which is safe to call redundantly. mp_usbd_init_tud(); // Reconnect if mp_usbd_deinit() has disconnected. @@ -466,7 +470,7 @@ static void mp_usbd_disconnect(mp_obj_usb_device_t *usbd) { for (int epnum = 0; epnum < CFG_TUD_ENDPPOINT_MAX; epnum++) { for (int dir = 0; dir < 2; dir++) { if (usbd->xfer_data[epnum][dir] != mp_const_none) { - usbd_edpt_stall(USBD_RHPORT, tu_edpt_addr(epnum, dir)); + usbd_edpt_stall(RHPORT, tu_edpt_addr(epnum, dir)); usbd->xfer_data[epnum][dir] = mp_const_none; } } @@ -477,7 +481,7 @@ static void mp_usbd_disconnect(mp_obj_usb_device_t *usbd) { // Ensure no pending static CDC writes, as these can cause TinyUSB to crash tud_cdc_write_clear(); // Prevent cdc write flush from initiating any new transfers while disconnecting - usbd_edpt_stall(USBD_RHPORT, USBD_CDC_EP_IN); + usbd_edpt_stall(RHPORT, USBD_CDC_EP_IN); #endif bool was_connected = tud_connected(); diff --git a/shared/tinyusb/tusb_config.h b/shared/tinyusb/tusb_config.h index 0cc5ef03985ef..8abd021548d5d 100644 --- a/shared/tinyusb/tusb_config.h +++ b/shared/tinyusb/tusb_config.h @@ -59,7 +59,7 @@ #define MICROPY_HW_USB_MSC_INQUIRY_REVISION_STRING "1.00" #endif -#ifndef CFG_TUSB_RHPORT0_MODE +#if !defined(CFG_TUSB_RHPORT0_MODE) && !defined(CFG_TUSB_RHPORT1_MODE) #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE) #endif @@ -83,7 +83,7 @@ #ifndef CFG_TUD_CDC_TX_BUFSIZE #define CFG_TUD_CDC_TX_BUFSIZE ((CFG_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED) ? 512 : 256) #endif -#endif +#endif // CFG_TUD_CDC // MSC Configuration #if CFG_TUD_MSC @@ -92,9 +92,7 @@ #endif // Set MSC EP buffer size to FatFS block size to avoid partial read/writes (offset arg). #define CFG_TUD_MSC_BUFSIZE (MICROPY_FATFS_MAX_SS) -#endif - -#define USBD_RHPORT (0) // Currently only one port is supported +#endif // CFG_TUD_MSC // Define built-in interface, string and endpoint numbering based on the above config diff --git a/tests/basics/builtin_help.py b/tests/basics/builtin_help.py index 6ec39653fe993..3d4e4f26bd2bb 100644 --- a/tests/basics/builtin_help.py +++ b/tests/basics/builtin_help.py @@ -14,4 +14,10 @@ help(micropython) # help for a module help('modules') # list available modules +class A: + x = 1 + y = 2 + del x +help(A) + print('done') # so last bit of output is predictable diff --git a/tests/basics/fun_code.py b/tests/basics/fun_code.py index 59e1f7ec0483d..841357e8aadde 100644 --- a/tests/basics/fun_code.py +++ b/tests/basics/fun_code.py @@ -34,3 +34,8 @@ def f(): ftype(f.__code__, None) except TypeError: print("TypeError") + +# Test __code__ on functions with children functions. +code = (lambda: (lambda: a)).__code__ +print(ftype(code, {"a": 1})()()) +print(ftype(code, {"a": 2})()()) diff --git a/tests/basics/fun_code_micropython.py b/tests/basics/fun_code_micropython.py deleted file mode 100644 index 2c319a2db8c75..0000000000000 --- a/tests/basics/fun_code_micropython.py +++ /dev/null @@ -1,19 +0,0 @@ -# Test MicroPython-specific restrictions of function.__code__ attribute. - -try: - (lambda: 0).__code__ -except AttributeError: - print("SKIP") - raise SystemExit - - -def f_with_children(): - def g(): - pass - - -# Can't access __code__ when function has children. -try: - f_with_children.__code__ -except AttributeError: - print("AttributeError") diff --git a/tests/basics/fun_code_micropython.py.exp b/tests/basics/fun_code_micropython.py.exp deleted file mode 100644 index d169edffb4cfb..0000000000000 --- a/tests/basics/fun_code_micropython.py.exp +++ /dev/null @@ -1 +0,0 @@ -AttributeError diff --git a/tests/basics/string_fstring.py b/tests/basics/string_fstring.py index d94cc0cd3e630..200065e9d9d1f 100644 --- a/tests/basics/string_fstring.py +++ b/tests/basics/string_fstring.py @@ -79,3 +79,14 @@ def foo(a, b): # Raw f-strings. print(rf"\r\a\w {'f'} \s\t\r\i\n\g") print(fr"\r{x}") + +# Format specifiers with nested replacement fields +space = 5 +prec = 2 +print(f"{3.14:{space}.{prec}}") + +space_prec = "5.2" +print(f"{3.14:{space_prec}}") + +radix = "x" +print(f"{314:{radix}}") diff --git a/tests/basics/try_finally_break.py.exp b/tests/basics/try_finally_break.py.exp new file mode 100644 index 0000000000000..d0b3698548968 --- /dev/null +++ b/tests/basics/try_finally_break.py.exp @@ -0,0 +1,25 @@ +1 +2 +5 +a 1 +1 +iter 0 +1 +None +1 +2 +None +1 +2 +None +1 +3 +4 +7 +1 +2 +4 +7 +1 +4 +7 diff --git a/tests/basics/try_finally_break2.py.exp b/tests/basics/try_finally_break2.py.exp new file mode 100644 index 0000000000000..bc5e931fdb4fd --- /dev/null +++ b/tests/basics/try_finally_break2.py.exp @@ -0,0 +1,17 @@ +4 0 0 1 +4 0 0 2 +4 0 0 3 +4 0 0 4 +4 1 0 1 +4 1 0 2 +4 1 0 3 +4 1 0 4 +4 2 0 1 +4 2 0 2 +4 2 0 3 +4 2 0 4 +4 3 0 1 +4 3 0 2 +4 3 0 3 +4 3 0 4 +None diff --git a/tests/basics/try_finally_continue.py.exp b/tests/basics/try_finally_continue.py.exp new file mode 100644 index 0000000000000..2901997b1aa18 --- /dev/null +++ b/tests/basics/try_finally_continue.py.exp @@ -0,0 +1,9 @@ +4 0 +continue +4 1 +continue +4 2 +continue +4 3 +continue +None diff --git a/tests/basics/try_finally_return2.py.exp b/tests/basics/try_finally_return2.py.exp new file mode 100644 index 0000000000000..b4c364f81d9b7 --- /dev/null +++ b/tests/basics/try_finally_return2.py.exp @@ -0,0 +1,19 @@ +finally +0 +finally 1 +finally 2 +2 +finally 1 +finally 2 +1 +finally 1 +finally 2 +2 +finally +0 +finally +0 +finally +0 +finally +0 diff --git a/tests/basics/try_finally_return3.py.exp b/tests/basics/try_finally_return3.py.exp new file mode 100644 index 0000000000000..5fef648ea6769 --- /dev/null +++ b/tests/basics/try_finally_return3.py.exp @@ -0,0 +1,23 @@ +1 +42 +1 +2 +42 +1 +2 +3 +42 +2 +1 +42 +2 +1 +42 +1 +3 +2 +42 +1 +3 +2 +42 diff --git a/tests/basics/try_finally_return4.py.exp b/tests/basics/try_finally_return4.py.exp new file mode 100644 index 0000000000000..f92572ff6111a --- /dev/null +++ b/tests/basics/try_finally_return4.py.exp @@ -0,0 +1,38 @@ +1 +2 +3 +4 +5 +None +1 +2 +3 +5 +42 +1 +2 +5 +43 +1 +2 +5 +43 +1 +2 +5 +caught +1 +2 +5 +caught +1 +2 +3 +4 +5 +None +1 +2 +3 +5 +42 diff --git a/tests/basics/try_finally_return5.py.exp b/tests/basics/try_finally_return5.py.exp new file mode 100644 index 0000000000000..dfa403cfd47db --- /dev/null +++ b/tests/basics/try_finally_return5.py.exp @@ -0,0 +1,3 @@ +4 0 +return +43 diff --git a/tests/extmod/machine_uart_tx.py b/tests/extmod/machine_uart_tx.py index 70d57be46477c..1ff9af64bd4ce 100644 --- a/tests/extmod/machine_uart_tx.py +++ b/tests/extmod/machine_uart_tx.py @@ -19,6 +19,8 @@ bit_margin = 1 elif "esp32" in sys.platform: timing_margin_us = 400 +elif "esp8266" in sys.platform: + timing_margin_us = 4100 elif "mimxrt" in sys.platform: initial_delay_ms = 20 # UART sends idle frame after init, so wait for that bit_margin = 1 diff --git a/tests/extmod/marshal_fun_nested.py b/tests/extmod/marshal_fun_nested.py new file mode 100644 index 0000000000000..fcf8f9a0fa450 --- /dev/null +++ b/tests/extmod/marshal_fun_nested.py @@ -0,0 +1,79 @@ +# Test the marshal module, with functions that have children. + +try: + import marshal + + (lambda: 0).__code__ +except (AttributeError, ImportError): + print("SKIP") + raise SystemExit + + +def f_with_child(): + def child(): + return a + + return child + + +def f_with_child_defargs(): + def child(a="default"): + return a + + return child + + +def f_with_child_closure(): + a = "closure 1" + + def child(): + return a + + a = "closure 2" + return child + + +def f_with_child_closure_defargs(): + a = "closure defargs 1" + + def child(b="defargs default"): + return (a, b) + + a = "closure defargs 1" + return child + + +def f_with_list_comprehension(a): + return [i + a for i in range(4)] + + +ftype = type(lambda: 0) + +# Test function with a child. +f = ftype(marshal.loads(marshal.dumps(f_with_child.__code__)), {"a": "global"}) +print(f()()) + +# Test function with a child that has default arguments. +f = ftype(marshal.loads(marshal.dumps(f_with_child_defargs.__code__)), {}) +print(f()()) +print(f()("non-default")) + +# Test function with a child that is a closure. +f = ftype(marshal.loads(marshal.dumps(f_with_child_closure.__code__)), {}) +print(f()()) + +# Test function with a child that is a closure and has default arguments. +f = ftype(marshal.loads(marshal.dumps(f_with_child_closure_defargs.__code__)), {}) +print(f()()) +print(f()("defargs non-default")) + +# Test function with a list comprehension (which will be an anonymous child). +f = ftype(marshal.loads(marshal.dumps(f_with_list_comprehension.__code__)), {}) +print(f(10)) + +# Test child within a module (the outer scope). +code = compile("def child(a): return a", "", "exec") +f = marshal.loads(marshal.dumps(code)) +ctx = {} +exec(f, ctx) +print(ctx["child"]("arg")) diff --git a/tests/extmod/marshal_micropython.py b/tests/extmod/marshal_micropython.py deleted file mode 100644 index 213b3bf31895d..0000000000000 --- a/tests/extmod/marshal_micropython.py +++ /dev/null @@ -1,21 +0,0 @@ -# Test the marshal module, MicroPython-specific functionality. - -try: - import marshal -except ImportError: - print("SKIP") - raise SystemExit - -import unittest - - -class Test(unittest.TestCase): - def test_function_with_children(self): - # Can't marshal a function with children (in this case the module has a child function f). - code = compile("def f(): pass", "", "exec") - with self.assertRaises(ValueError): - marshal.dumps(code) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/extmod/vfs_blockdev_invalid.py b/tests/extmod/vfs_blockdev_invalid.py index 29d6bd6b2f9f7..955f8495b3f14 100644 --- a/tests/extmod/vfs_blockdev_invalid.py +++ b/tests/extmod/vfs_blockdev_invalid.py @@ -46,12 +46,16 @@ def ioctl(self, op, arg): try: bdev = RAMBlockDevice(50) except MemoryError: - print("SKIP") + print("SKIP-TOO-LARGE") raise SystemExit -def test(vfs_class): - print(vfs_class) +ERROR_EIO = (OSError, "[Errno 5] EIO") +ERROR_EINVAL = (OSError, "[Errno 22] EINVAL") +ERROR_TYPE = (TypeError, "can't convert str to int") + + +def test(vfs_class, test_data): bdev.read_res = 0 # reset function results bdev.write_res = 0 @@ -61,17 +65,15 @@ def test(vfs_class): with fs.open("test", "w") as f: f.write("a" * 64) - for res in (0, -5, 5, 33, "invalid"): - # -5 is a legitimate negative failure (EIO), positive integer - # is not - + for res, error_open, error_read in test_data: # This variant will fail on open bdev.read_res = res try: with fs.open("test", "r") as f: - print("opened") + assert error_open is None except Exception as e: - print(type(e), e) + assert error_open is not None + assert (type(e), str(e)) == error_open # This variant should succeed on open, may fail on read # unless the filesystem cached the contents already @@ -79,11 +81,35 @@ def test(vfs_class): try: with fs.open("test", "r") as f: bdev.read_res = res - print("read 1", f.read(1)) - print("read rest", f.read()) + assert f.read(1) == "a" + assert f.read() == "a" * 63 + assert error_read is None except Exception as e: - print(type(e), e) + assert error_read is not None + assert (type(e), str(e)) == error_read -test(vfs.VfsLfs2) -test(vfs.VfsFat) +try: + test( + vfs.VfsLfs2, + ( + (0, None, None), + (-5, ERROR_EIO, None), + (5, ERROR_EINVAL, None), + (33, ERROR_EINVAL, None), + ("invalid", ERROR_TYPE, None), + ), + ) + test( + vfs.VfsFat, + ( + (0, None, None), + (-5, ERROR_EIO, ERROR_EIO), + (5, ERROR_EIO, ERROR_EIO), + (33, ERROR_EIO, ERROR_EIO), + ("invalid", ERROR_TYPE, ERROR_TYPE), + ), + ) + print("OK") +except MemoryError: + print("SKIP-TOO-LARGE") diff --git a/tests/extmod/vfs_blockdev_invalid.py.exp b/tests/extmod/vfs_blockdev_invalid.py.exp index 0ea0353501de3..d86bac9de59ab 100644 --- a/tests/extmod/vfs_blockdev_invalid.py.exp +++ b/tests/extmod/vfs_blockdev_invalid.py.exp @@ -1,28 +1 @@ - -opened -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - [Errno 5] EIO -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - [Errno 22] EINVAL -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - [Errno 22] EINVAL -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - can't convert str to int -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - -opened -read 1 a -read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - [Errno 5] EIO - [Errno 5] EIO - [Errno 5] EIO - [Errno 5] EIO - [Errno 5] EIO - [Errno 5] EIO - can't convert str to int - can't convert str to int +OK diff --git a/tests/float/complex1.py b/tests/float/complex1.py index 0a1d98b9af3eb..4decea2ac6bf1 100644 --- a/tests/float/complex1.py +++ b/tests/float/complex1.py @@ -20,7 +20,6 @@ print(complex("nanj")) print(complex("nan-infj")) print(complex(1, 2)) -print(complex(1j, 2j)) # unary ops print(bool(1j)) diff --git a/tests/float/complex1_micropython.py b/tests/float/complex1_micropython.py new file mode 100644 index 0000000000000..6b92f593ef2b2 --- /dev/null +++ b/tests/float/complex1_micropython.py @@ -0,0 +1,6 @@ +# test basic complex number functionality + +# CPython 3.14 marks this constructor as deprecated, but it is still currently +# supported by MicroPython. + +print(complex(1j, 2j)) diff --git a/tests/float/complex1_micropython.py.exp b/tests/float/complex1_micropython.py.exp new file mode 100644 index 0000000000000..1defdb822cdc5 --- /dev/null +++ b/tests/float/complex1_micropython.py.exp @@ -0,0 +1 @@ +(-2+1j) diff --git a/tests/float/math_fun.py b/tests/float/math_fun.py index 789158c0e2b66..05f8be08fa0f4 100644 --- a/tests/float/math_fun.py +++ b/tests/float/math_fun.py @@ -43,6 +43,9 @@ ans = "{:.5g}".format(function(value)) except ValueError as e: ans = str(e) + if ans.startswith("expected a "): + # CPython 3.14 changed messages to be more detailed; convert them back to simple ones + ans = "math domain error" print("{}({:.5g}) = {}".format(function_name, value, ans)) tuple_functions = [ diff --git a/tests/float/math_fun_special.py b/tests/float/math_fun_special.py index ecacedec552ec..fcf6175af73a0 100644 --- a/tests/float/math_fun_special.py +++ b/tests/float/math_fun_special.py @@ -51,6 +51,9 @@ ans = "{:.4g}".format(function(value)) except ValueError as e: ans = str(e) + if ans.startswith("expected a "): + # CPython 3.14 changed messages to be more detailed; convert them back to simple ones + ans = "math domain error" # a tiny error in REPR_C value for 1.5204998778 causes a wrong rounded value if is_REPR_C and function_name == "erfc" and ans == "1.521": ans = "1.52" diff --git a/tests/inlineasm/rv32/asmzba.py b/tests/inlineasm/rv32/asm_ext_zba.py similarity index 100% rename from tests/inlineasm/rv32/asmzba.py rename to tests/inlineasm/rv32/asm_ext_zba.py diff --git a/tests/inlineasm/rv32/asmzba.py.exp b/tests/inlineasm/rv32/asm_ext_zba.py.exp similarity index 100% rename from tests/inlineasm/rv32/asmzba.py.exp rename to tests/inlineasm/rv32/asm_ext_zba.py.exp diff --git a/tests/micropython/native_marshal.py b/tests/micropython/native_marshal.py new file mode 100644 index 0000000000000..09a27a374b8cf --- /dev/null +++ b/tests/micropython/native_marshal.py @@ -0,0 +1,45 @@ +# Test the marshal module in combination with native/viper functions. + +try: + import marshal + + (lambda: 0).__code__ +except (AttributeError, ImportError): + print("SKIP") + raise SystemExit + +import unittest + + +def f_native(): + @micropython.native + def g(): + pass + + return g + + +def f_viper(): + @micropython.viper + def g(): + pass + + return g + + +class Test(unittest.TestCase): + def test_native_function(self): + # Can't marshal a function with native code. + code = f_native.__code__ + with self.assertRaises(ValueError): + marshal.dumps(code) + + def test_viper_function(self): + # Can't marshal a function with viper code. + code = f_viper.__code__ + with self.assertRaises(ValueError): + marshal.dumps(code) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/micropython/schedule.py b/tests/micropython/schedule.py index f3dd32661267b..e629edb3eb3e9 100644 --- a/tests/micropython/schedule.py +++ b/tests/micropython/schedule.py @@ -1,4 +1,6 @@ # test micropython.schedule() function +# this test should be manually kept in synch with +# tests/micrpython/schedule_sleep.py. try: import micropython diff --git a/tests/micropython/schedule_sleep.py b/tests/micropython/schedule_sleep.py new file mode 100644 index 0000000000000..9aadde7b0848c --- /dev/null +++ b/tests/micropython/schedule_sleep.py @@ -0,0 +1,72 @@ +# test micropython.schedule() function +# this is the same as tests/micropython/schedule.py but the busy loops are +# replaced with sleep/sleep_ms which allows the test to succeed when run under +# the native emitter. + +try: + import micropython + import time + + micropython.schedule +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +# Basic test of scheduling a function. + + +def callback(arg): + global done + print(arg) + done = True + + +done = False +micropython.schedule(callback, 1) +while not done: + time.sleep(0) + +# Test that callbacks can be scheduled from within a callback, but +# that they don't execute until the outer callback is finished. + + +def callback_inner(arg): + global done + print("inner") + done += 1 + + +def callback_outer(arg): + global done + micropython.schedule(callback_inner, 0) + # need a loop so that the VM can check for pending events + for i in range(2): + pass + print("outer") + done += 1 + + +done = 0 +micropython.schedule(callback_outer, 0) +while done != 2: + time.sleep(0) + +# Test that scheduling too many callbacks leads to an exception. To do this we +# must schedule from within a callback to guarantee that the scheduler is locked. + + +def callback(arg): + global done + try: + for i in range(100): + micropython.schedule(lambda x: x, None) + except RuntimeError: + print("RuntimeError") + done = True + + +done = False +micropython.schedule(callback, None) +while not done: + time.sleep_ms(0) diff --git a/tests/micropython/schedule_sleep.py.exp b/tests/micropython/schedule_sleep.py.exp new file mode 100644 index 0000000000000..c4a3e1227e275 --- /dev/null +++ b/tests/micropython/schedule_sleep.py.exp @@ -0,0 +1,4 @@ +1 +outer +inner +RuntimeError diff --git a/tests/multi_espnow/75_rate.py b/tests/multi_espnow/75_rate.py new file mode 100644 index 0000000000000..9c05a24bd0098 --- /dev/null +++ b/tests/multi_espnow/75_rate.py @@ -0,0 +1,92 @@ +# Test configuring transmit rates for ESP-NOW on ESP32 + +import sys +import time + +try: + import network + import espnow +except ImportError: + print("SKIP") + raise SystemExit + +# ESP8266 doesn't support multiple ESP-NOW data rates +if sys.platform == "esp8266": + print("SKIP") + raise SystemExit + +# Currently the config(rate=...) implementation is not compatible with ESP32-C6 +# (this test passes when C6 is receiver, but not if C6 is sender.) +if "ESP32C6" in sys.implementation._machine: + print("SKIP") + raise SystemExit + +# ESP32-C2 doesn't support Long Range mode. This test is currently written assuming +# LR mode can be enabled. +if "ESP32C2" in sys.implementation._machine: + print("SKIP") + raise SystemExit + + +timeout_ms = 1000 +default_pmk = b"MicroPyth0nRules" +CHANNEL = 9 + + +def init_sta(): + sta = network.WLAN(network.WLAN.IF_STA) + e = espnow.ESPNow() + e.active(True) + sta.active(True) + sta.disconnect() # Force AP disconnect for any saved config, important so the channel doesn't change + sta.config(channel=CHANNEL) + e.set_pmk(default_pmk) + # Enable both default 802.11 modes and Long Range modes + sta.config(protocol=network.WLAN.PROTOCOL_LR | network.WLAN.PROTOCOL_DEFAULT) + return sta, e + + +# Receiver +def instance0(): + sta, e = init_sta() + multitest.globals(PEER=sta.config("mac")) + multitest.next() + while True: + peer, msg = e.recv(timeout_ms) + if peer is None: + print("Timeout") + break + # Note that we don't have any way in Python to tell what data rate this message + # was received with, so we're assuming the rate was correct. + print(msg) + e.active(False) + + +# Sender +def instance1(): + sta, e = init_sta() + multitest.next() + peer = PEER + + e.add_peer(peer) + # Test normal, non-LR rates + for msg, rate in ( + (b"default rate", None), + (b"5Mbit", espnow.RATE_5M), + (b"11Mbit", espnow.RATE_11M), + (b"24Mbit", espnow.RATE_24M), + (b"54Mbit", espnow.RATE_54M), + (b"250K LR", espnow.RATE_LORA_250K), + (b"500K LR", espnow.RATE_LORA_500K), + # switch back to non-LR rates to check it's all OK + (b"1Mbit again", espnow.RATE_1M), + (b"11Mbit again", espnow.RATE_11M), + ): + if rate is not None: + e.config(rate=rate) + for _ in range(3): + e.send(peer, msg) + time.sleep_ms(50) # give messages some time to be received before continuing + e.del_peer(peer) + + e.active(False) diff --git a/tests/multi_espnow/75_rate.py.exp b/tests/multi_espnow/75_rate.py.exp new file mode 100644 index 0000000000000..5a275ee6b28bc --- /dev/null +++ b/tests/multi_espnow/75_rate.py.exp @@ -0,0 +1,31 @@ +--- instance0 --- +b'default rate' +b'default rate' +b'default rate' +b'5Mbit' +b'5Mbit' +b'5Mbit' +b'11Mbit' +b'11Mbit' +b'11Mbit' +b'24Mbit' +b'24Mbit' +b'24Mbit' +b'54Mbit' +b'54Mbit' +b'54Mbit' +b'250K LR' +b'250K LR' +b'250K LR' +b'500K LR' +b'500K LR' +b'500K LR' +b'1Mbit again' +b'1Mbit again' +b'1Mbit again' +b'11Mbit again' +b'11Mbit again' +b'11Mbit again' +Timeout +--- instance1 --- + diff --git a/tests/multi_net/tcp_client_rst.py b/tests/multi_net/tcp_client_rst.py index 1fe994f36ceb1..6e74edc194d25 100644 --- a/tests/multi_net/tcp_client_rst.py +++ b/tests/multi_net/tcp_client_rst.py @@ -2,6 +2,12 @@ import struct, time, socket, select +try: + import errno +except ImportError: + print("SKIP") + raise SystemExit + PORT = 8000 @@ -18,27 +24,49 @@ def instance0(): s.bind(socket.getaddrinfo("0.0.0.0", PORT)[0][-1]) s.listen(1) multitest.next() - s2, _ = s.accept() - s2.setblocking(False) - poll = select.poll() - poll.register(s2, select.POLLIN) - time.sleep(0.4) - print(convert_poll_list(poll.poll(1000))) - # TODO: the following recv don't work with lwip, it abandons data upon TCP RST - try: - print(s2.recv(10)) + + for iteration in range(2): + print("server iteration", iteration) + + # Accept a connection from the client. + s2, _ = s.accept() + s2.setblocking(False) + + # Create a poller for the connected socket. + poll = select.poll() + poll.register(s2, select.POLLIN) + + # Wait for the client to send data and issue a TCP RST. + for _ in range(10): + if select.POLLIN | select.POLLERR | select.POLLHUP in convert_poll_list( + poll.poll(1000) + ): + break + time.sleep(0.1) print(convert_poll_list(poll.poll(1000))) - print(s2.recv(10)) + + # On the second test, drain the incoming data. + if iteration == 1: + for _ in range(5): + try: + print(s2.recv(10)) + except OSError as er: + # This error should only happen on the 3rd recv. + print("ECONNRESET:", er.errno == errno.ECONNRESET) + print(convert_poll_list(poll.poll(1000))) + + # Close the connection to the client. + s2.close() print(convert_poll_list(poll.poll(1000))) - print(s2.recv(10)) + + # Try to read more data from the closed socket, to make sure the error code is correct. + try: + print(s2.recv(10)) + except OSError as er: + print("EBADF:", er.errno == errno.EBADF) print(convert_poll_list(poll.poll(1000))) - except OSError as er: - print(er.errno) - print(convert_poll_list(poll.poll(1000))) - # TODO lwip raises here but apparently it shouldn't - print(s2.recv(10)) - print(convert_poll_list(poll.poll(1000))) - s2.close() + + # Close the listening socket. s.close() @@ -47,11 +75,13 @@ def instance1(): if not hasattr(socket, "SO_LINGER"): multitest.skip() multitest.next() - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - s.connect(socket.getaddrinfo(IP, PORT)[0][-1]) - lgr_onoff = 1 - lgr_linger = 0 - s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", lgr_onoff, lgr_linger)) - s.send(b"GET / HTTP/1.0\r\n\r\n") - time.sleep(0.2) - s.close() # This issues a TCP RST since we've set the linger option + for iteration in range(2): + print("client iteration", iteration) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + s.connect(socket.getaddrinfo(IP, PORT)[0][-1]) + lgr_onoff = 1 + lgr_linger = 0 + s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", lgr_onoff, lgr_linger)) + s.send(b"GET / HTTP/1.0\r\n\r\n") + time.sleep(0.2) + s.close() # This issues a TCP RST since we've set the linger option diff --git a/tests/net_inet/mpycert.der b/tests/net_inet/mpycert.der index 0b0eabc9bc813..f583b217ae5d9 100644 Binary files a/tests/net_inet/mpycert.der and b/tests/net_inet/mpycert.der differ diff --git a/tests/net_inet/ssl_cert.py b/tests/net_inet/ssl_cert.py index 4f065c5657ee2..7d64236a02832 100644 --- a/tests/net_inet/ssl_cert.py +++ b/tests/net_inet/ssl_cert.py @@ -8,7 +8,7 @@ # This certificate was obtained from micropython.org using openssl: # $ openssl s_client -showcerts -connect micropython.org:443 /dev/null # The certificate is from Let's Encrypt: -# 1 s:C=US, O=Let's Encrypt, CN=R11 +# 1 s:C=US, O=Let's Encrypt, CN=R12 # i:C=US, O=Internet Security Research Group, CN=ISRG Root X1 # a:PKEY: RSA, 2048 (bit); sigalg: sha256WithRSAEncryption # v:NotBefore: Mar 13 00:00:00 2024 GMT; NotAfter: Mar 12 23:59:59 2027 GMT @@ -17,39 +17,39 @@ # Then convert to hex format using: for i in range(0,len(data),40):print(data[i:i+40].hex()) ca_cert_chain = bytes.fromhex( - "30820506308202eea0030201020211008a7d3e13d62f30ef2386bd29076b34f8300d06092a864886" + "30820506308202eea003020102021100c212324b70a9b49171dc40f7e285263c300d06092a864886" "f70d01010b0500304f310b300906035504061302555331293027060355040a1320496e7465726e65" "742053656375726974792052657365617263682047726f7570311530130603550403130c49535247" "20526f6f74205831301e170d3234303331333030303030305a170d3237303331323233353935395a" "3033310b300906035504061302555331163014060355040a130d4c6574277320456e637279707431" - "0c300a0603550403130352313130820122300d06092a864886f70d01010105000382010f00308201" - "0a0282010100ba87bc5c1b0039cbca0acdd46710f9013ca54ea561cb26ca52fb1501b7b928f5281e" - "ed27b324183967090c08ece03ab03b770ebdf3e53954410c4eae41d69974de51dbef7bff58bda8b7" - "13f6de31d5f272c9726a0b8374959c4600641499f3b1d922d9cda892aa1c267a3ffeef58057b0895" - "81db710f8efbe33109bb09be504d5f8f91763d5a9d9e83f2e9c466b3e106664348188065a037189a" - "9b843297b1b2bdc4f815009d2788fbe26317966c9b27674bc4db285e69c279f0495ce02450e1c4bc" - "a105ac7b406d00b4c2413fa758b82fc55c9ba5bb099ef1feebb08539fda80aef45c478eb652ac2cf" - "5f3cdee35c4d1bf70b272baa0b4277534f796a1d87d90203010001a381f83081f5300e0603551d0f" + "0c300a0603550403130352313230820122300d06092a864886f70d01010105000382010f00308201" + "0a0282010100da982874adbe94fe3be01ee2e54b75ab2c127feda703327e3697ece8318fa5138d0b" + "992e1ecd01513d4ce5286e095531aaa5225d72f42d07c24d403cdf0123b97837f51a653234e68671" + "9d04ef84085bbd021a99eba601009a73906d8fa207a0d097d3da456181353d14f9c4c05f6adc0b96" + "1ab09fe32aeabd2ad698c79b71ab3b740f3cdbb260be5a4b4e18e9db2a735c8961659efeed3ca6cb" + "4e6fe49ef90046b3ff194d2a63b38e66c6188570c750656f3b74e548830f08585d2d239d5ea3fee8" + "db00a1d2f4e3194df2ee7af6279ee5cd9c2da2f27f9c17adef133739d1b4c82c41d686c0e9ec21f8" + "591b7fb93a7c9f5c019d6204c228bd0aad3cca10ec1b0203010001a381f83081f5300e0603551d0f" "0101ff040403020186301d0603551d250416301406082b0601050507030206082b06010505070301" - "30120603551d130101ff040830060101ff020100301d0603551d0e04160414c5cf46a4eaf4c3c07a" - "6c95c42db05e922f26e3b9301f0603551d2304183016801479b459e67bb6e5e40173800888c81a58" + "30120603551d130101ff040830060101ff020100301d0603551d0e0416041400b529f22d8e6f31e8" + "9b4cad783efadce90cd1d2301f0603551d2304183016801479b459e67bb6e5e40173800888c81a58" "f6e99b6e303206082b0601050507010104263024302206082b060105050730028616687474703a2f" "2f78312e692e6c656e63722e6f72672f30130603551d20040c300a3008060667810c010201302706" "03551d1f0420301e301ca01aa0188616687474703a2f2f78312e632e6c656e63722e6f72672f300d" - "06092a864886f70d01010b050003820201004ee2895d0a031c9038d0f51ff9715cf8c38fb237887a" - "6fb0251fedbeb7d886068ee90984cd72bf81f3fccacf5348edbdf66942d4a5113e35c813b2921d05" - "5fea2ed4d8f849c3adf599969cef26d8e1b4240b48204dfcd354b4a9c621c8e1361bff77642917b9" - "f04bef5deacd79d0bf90bfbe23b290da4aa9483174a9440be1e2f62d8371a4757bd294c10519461c" - "b98ff3c47448252a0de5f5db43e2db939bb919b41f2fdf6a0e8f31d3630fbb29dcdd662c3fb01b67" - "51f8413ce44db9acb8a49c6663f5ab85231dcc53b6ab71aedcc50171da36ee0a182a32fd09317c8f" - "f673e79c9cb54a156a77825acfda8d45fe1f2a6405303e73c2c60cb9d63b634aab4603fe99c04640" - "276063df503a0747d8154a9fea471f995a08620cb66c33084dd738ed482d2e0568ae805def4cdcd8" - "20415f68f1bb5acde30eb00c31879b43de4943e1c8043fd13c1b87453069a8a9720e79121c31d83e" - "2357dda74fa0f01c81d1771f6fd6d2b9a8b3031681394b9f55aed26ae4b3bfeaa5d59f4ba3c9d63b" - "72f34af654ab0cfc38f76080df6e35ca75a154e42fbc6e17c91aa537b5a29abaecf4c075464f77a8" - "e8595691662d6ede2981d6a697055e6445be2cceea644244b0c34fadf0b4dc03ca999b098295820d" - "638a66f91972f8d5b98910e289980935f9a21cbe92732374e99d1fd73b4a9a845810c2f3a7e235ec" - "7e3b45ce3046526bc0c0" + "06092a864886f70d01010b050003820201008f75d009cf6a7648653292deb544c88576f415848c02" + "bf76ebb3f1e2f96e84a85691e1924bf7e1ea0078488f7592e3e4467b1b602b20afa0ce14e5450d6a" + "e05286a4f3da1414a9a95ff16d46f952501740e9e41e7de61558fea98bfceff59e63e066e2c3773b" + "1f01872694ed4010dcb799ecdd57d35c7141ee30200004dc954b5028879992feaa8094b6060814f8" + "1c837e7440c5085a0c4f5cd1849dc4fddb59deee796e234d95f292d498296a5ceb02c142f0f8f54e" + "64207ba8e331c4c06809478bd8b978a0ca4e4abe69242a4b377b51036b3a3f528bb3d4d2ad584e93" + "eecb5f6f0d314948bac43f9f12c9203d11840785b4f8f23823ac710040e77f8d4634826a4ecfe00e" + "635fba699a47091022fe4b48b7917554cb931ee416eb53cf7bde364dbff6b1ebe64ae9333c8d69a2" + "98bea87fa3ab5fb654e84d96a9acf3b05acb1b7a3693249bce5852809f350a5e2dbf749b6226179c" + "9131290bf37fcdc3628b68c777f47f0bfbc659f503664ba6509bd0efa5fc02b4604d034b614fc520" + "078b48b031f5b69cd1c9ad7718dcb2c70fbee04608dee04bdeb9b8b6c716be36693f86684b748113" + "8950c56a7a02acc548a50e7d5d61e4cdd166a075c7055ee889b5631923bb50b490ecc275373e75a6" + "1b83252800214ec0d33acb9ceac08ff75fae51164610af0206eec0b657d40dac8cd8d7a0f3876ec3" + "e2cbe94ed4a17cfd763b" ) diff --git a/tests/ports/esp32/check_err_str.py b/tests/ports/esp32/check_err_str.py index 055eecf7476ae..9efe1afa1961b 100644 --- a/tests/ports/esp32/check_err_str.py +++ b/tests/ports/esp32/check_err_str.py @@ -1,3 +1,5 @@ +# This tests checks the behaviour of the `check_esp_err`/`check_esp_err_` C function. + try: from esp32 import Partition as p import micropython @@ -23,6 +25,7 @@ # same but with out of memory condition by locking the heap exc = "FAILED TO RAISE" +e = None # preallocate entry in globals dict micropython.heap_lock() try: fun(part) @@ -34,6 +37,7 @@ # same again but having an emergency buffer micropython.alloc_emergency_exception_buf(256) exc = "FAILED TO RAISE" +e = None # preallocate entry in globals dict micropython.heap_lock() try: fun(part) diff --git a/tests/run-internalbench.py b/tests/run-internalbench.py index 99c6304afe9d6..4f2d29525deb9 100755 --- a/tests/run-internalbench.py +++ b/tests/run-internalbench.py @@ -8,9 +8,14 @@ from glob import glob from collections import defaultdict -run_tests_module = __import__("run-tests") -sys.path.append(run_tests_module.base_path("../tools")) -import pyboard +from test_utils import ( + base_path, + pyboard, + test_instance_description, + test_instance_epilog, + test_directory_description, + get_test_instance, +) if os.name == "nt": MICROPYTHON = os.getenv( @@ -97,10 +102,10 @@ def main(): formatter_class=argparse.RawDescriptionHelpFormatter, description=f"""Run and manage tests for MicroPython. -{run_tests_module.test_instance_description} -{run_tests_module.test_directory_description} +{test_instance_description} +{test_directory_description} """, - epilog=run_tests_module.test_instance_epilog, + epilog=test_instance_epilog, ) cmd_parser.add_argument( "-t", "--test-instance", default="unix", help="the MicroPython instance to test" @@ -124,9 +129,7 @@ def main(): args = cmd_parser.parse_args() # Note pyboard support is copied over from run-tests.py, not tests, and likely needs revamping - pyb = run_tests_module.get_test_instance( - args.test_instance, args.baudrate, args.user, args.password - ) + pyb = get_test_instance(args.test_instance, args.baudrate, args.user, args.password) if len(args.files) == 0: if args.test_dirs: diff --git a/tests/run-multitests.py b/tests/run-multitests.py index e5458ffe0d00c..c5bb8011e76d9 100755 --- a/tests/run-multitests.py +++ b/tests/run-multitests.py @@ -15,7 +15,13 @@ import subprocess import tempfile -run_tests_module = __import__("run-tests") +from test_utils import ( + base_path, + pyboard, + test_instance_epilog, + convert_device_shortcut_to_real_device, + create_test_report, +) test_dir = os.path.abspath(os.path.dirname(__file__)) @@ -24,9 +30,6 @@ # accidentally importing tests like micropython/const.py sys.path.pop(0) -sys.path.insert(0, test_dir + "/../tools") -import pyboard - if os.name == "nt": CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3.exe") MICROPYTHON = os.path.abspath( @@ -554,7 +557,7 @@ def main(): cmd_parser = argparse.ArgumentParser( description="Run network tests for MicroPython", epilog=( - run_tests_module.test_instance_epilog + test_instance_epilog + "Each instance arg can optionally have custom env provided, eg. ,ENV=VAR,ENV=VAR...\n" ), formatter_class=argparse.RawTextHelpFormatter, @@ -582,7 +585,7 @@ def main(): cmd_parser.add_argument( "-r", "--result-dir", - default=run_tests_module.base_path("results"), + default=base_path("results"), help="directory for test results", ) cmd_parser.add_argument("files", nargs="+", help="input test files") @@ -612,7 +615,7 @@ def main(): print("unsupported instance string: {}".format(cmd), file=sys.stderr) sys.exit(2) else: - device = run_tests_module.convert_device_shortcut_to_real_device(cmd) + device = convert_device_shortcut_to_real_device(cmd) instances_test.append(PyInstancePyboard(device)) for _ in range(max_instances - len(instances_test)): @@ -626,7 +629,7 @@ def main(): break test_results = run_tests(test_files, instances_truth, instances_test_permutation) - all_pass &= run_tests_module.create_test_report(cmd_args, test_results) + all_pass &= create_test_report(cmd_args, test_results) finally: for i in instances_truth: diff --git a/tests/run-natmodtests.py b/tests/run-natmodtests.py index 50e8d1272914e..cb0877e2cb089 100755 --- a/tests/run-natmodtests.py +++ b/tests/run-natmodtests.py @@ -9,7 +9,13 @@ import sys import argparse -run_tests_module = __import__("run-tests") +from test_utils import ( + base_path, + pyboard, + test_instance_epilog, + get_test_instance, + create_test_report, +) # Paths for host executables CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") @@ -40,6 +46,7 @@ "xtensa", "xtensawin", "rv32imc", + "rv64imc", ) ARCH_MAPPINGS = {"armv7em": "armv7m"} @@ -109,7 +116,7 @@ def run_script(self, script): output = self.pyb.exec_(script) output = output.replace(b"\r\n", b"\n") return output, None - except run_tests_module.pyboard.PyboardError as er: + except pyboard.PyboardError as er: return b"", er @@ -133,13 +140,6 @@ def detect_architecture(target): def run_tests(target_truth, target, args, resolved_arch): - global injected_import_hook_code - - prelude = "" - if args.begin: - prelude = args.begin.read() - injected_import_hook_code = injected_import_hook_code.replace("{import_prelude}", prelude) - test_results = [] for test_file in args.files: # Find supported test @@ -223,9 +223,11 @@ def run_tests(target_truth, target, args, resolved_arch): def main(): + global injected_import_hook_code + cmd_parser = argparse.ArgumentParser( description="Run dynamic-native-module tests under MicroPython", - epilog=run_tests_module.test_instance_epilog, + epilog=test_instance_epilog, formatter_class=argparse.RawDescriptionHelpFormatter, ) cmd_parser.add_argument( @@ -240,24 +242,28 @@ def main(): cmd_parser.add_argument( "-b", "--begin", - type=argparse.FileType("rt"), + metavar="PROLOGUE", default=None, help="prologue python file to execute before module import", ) cmd_parser.add_argument( "-r", "--result-dir", - default=run_tests_module.base_path("results"), + default=base_path("results"), help="directory for test results", ) cmd_parser.add_argument("files", nargs="*", help="input test files") args = cmd_parser.parse_args() + prologue = "" + if args.begin: + with open(args.begin, "rt") as source: + prologue = source.read() + injected_import_hook_code = injected_import_hook_code.replace("{import_prelude}", prologue) + target_truth = TargetSubprocess([CPYTHON3]) - target = run_tests_module.get_test_instance( - args.test_instance, args.baudrate, args.user, args.password - ) + target = get_test_instance(args.test_instance, args.baudrate, args.user, args.password) if target is None: # Use the unix port of MicroPython. target = TargetSubprocess([MICROPYTHON]) @@ -281,7 +287,7 @@ def main(): os.makedirs(args.result_dir, exist_ok=True) test_results = run_tests(target_truth, target, args, target_arch) - res = run_tests_module.create_test_report(args, test_results) + res = create_test_report(args, test_results) target.close() target_truth.close() diff --git a/tests/run-perfbench.py b/tests/run-perfbench.py index 039d11a36111e..16182bc8a9f73 100755 --- a/tests/run-perfbench.py +++ b/tests/run-perfbench.py @@ -10,9 +10,13 @@ import argparse from glob import glob -run_tests_module = __import__("run-tests") - -prepare_script_for_target = run_tests_module.prepare_script_for_target +from test_utils import ( + base_path, + pyboard, + get_test_instance, + prepare_script_for_target, + create_test_report, +) # Paths for host executables if os.name == "nt": @@ -49,7 +53,7 @@ def run_script_on_target(target, script): try: target.enter_raw_repl() output = target.exec_(script) - except run_tests_module.pyboard.PyboardError as er: + except pyboard.PyboardError as er: err = er else: # Run local executable @@ -277,7 +281,7 @@ def main(): cmd_parser.add_argument( "-r", "--result-dir", - default=run_tests_module.base_path("results"), + default=base_path("results"), help="directory for test results", ) cmd_parser.add_argument( @@ -298,9 +302,7 @@ def main(): M = int(args.M[0]) n_average = int(args.average) - target = run_tests_module.get_test_instance( - args.test_instance, args.baudrate, args.user, args.password - ) + target = get_test_instance(args.test_instance, args.baudrate, args.user, args.password) if target is None: # Use the unix port of MicroPython. target = [MICROPYTHON, "-X", "emit=" + args.emit] @@ -328,7 +330,7 @@ def main(): os.makedirs(args.result_dir, exist_ok=True) test_results = run_benchmarks(args, target, N, M, n_average, tests) - res = run_tests_module.create_test_report(args, test_results) + res = create_test_report(args, test_results) if hasattr(target, "exit_raw_repl"): target.exit_raw_repl() diff --git a/tests/run-tests.py b/tests/run-tests.py index fba011fb54cb6..0ff358c06e219 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -6,7 +6,6 @@ import sysconfig import platform import argparse -import inspect import json import re from glob import glob @@ -15,19 +14,28 @@ import threading import tempfile -# Maximum time to run a single test, in seconds. -TEST_TIMEOUT = float(os.environ.get("MICROPY_TEST_TIMEOUT", 30)) - -# See stackoverflow.com/questions/2632199: __file__ nor sys.argv[0] -# are guaranteed to always work, this one should though. -BASEPATH = os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: None))) - -RV32_ARCH_FLAGS = {"zba": 1 << 0} - - -def base_path(*p): - return os.path.abspath(os.path.join(BASEPATH, *p)).replace("\\", "/") +from test_utils import ( + base_path, + pyboard, + TEST_TIMEOUT, + MPYCROSS, + test_instance_description, + test_instance_epilog, + test_directory_description, + rm_f, + normalize_newlines, + set_injected_prologue, + get_results_filename, + convert_device_shortcut_to_real_device, + get_test_instance, + prepare_script_for_target, + create_test_report, +) +RV32_ARCH_FLAGS = { + "zba": 1 << 0, + "zcmp": 1 << 1, +} # Tests require at least CPython 3.3. If your default python3 executable # is of lower version, you can point MICROPY_CPYTHON3 environment var @@ -37,88 +45,22 @@ def base_path(*p): MICROPYTHON = os.getenv( "MICROPY_MICROPYTHON", base_path("../ports/windows/build-standard/micropython.exe") ) - # mpy-cross is only needed if --via-mpy command-line arg is passed - MPYCROSS = os.getenv("MICROPY_MPYCROSS", base_path("../mpy-cross/build/mpy-cross.exe")) else: CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") MICROPYTHON = os.getenv( "MICROPY_MICROPYTHON", base_path("../ports/unix/build-standard/micropython") ) - # mpy-cross is only needed if --via-mpy command-line arg is passed - MPYCROSS = os.getenv("MICROPY_MPYCROSS", base_path("../mpy-cross/build/mpy-cross")) # Use CPython options to not save .pyc files, to only access the core standard library # (not site packages which may clash with u-module names), and improve start up time. CPYTHON3_CMD = [CPYTHON3, "-BS"] -# File with the test results. -RESULTS_FILE = "_results.json" - # For diff'ing test output DIFF = os.getenv("MICROPY_DIFF", "diff -u") # Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale os.environ["PYTHONIOENCODING"] = "utf-8" - -def normalize_newlines(data): - """Normalize newline variations to \\n. - - Only normalizes actual line endings, not literal \\r characters in strings. - Handles \\r\\r\\n and \\r\\n cases to ensure consistent comparison - across different platforms and terminals. - """ - if isinstance(data, bytes): - # Handle PTY double-newline issue first - data = data.replace(b"\r\r\n", b"\n") - # Then handle standard Windows line endings - data = data.replace(b"\r\n", b"\n") - # Don't convert standalone \r as it might be literal content - return data - - -# Code to allow a target MicroPython to import an .mpy from RAM -# Note: the module is named `__injected_test` but it needs to have `__name__` set to -# `__main__` so that the test sees itself as the main module, eg so unittest works. -injected_import_hook_code = """\ -import sys, os, io, vfs -class __File(io.IOBase): - def __init__(self): - module = sys.modules['__injected_test'] - module.__name__ = '__main__' - sys.modules['__main__'] = module - self.off = 0 - def ioctl(self, request, arg): - if request == 4: # MP_STREAM_CLOSE - return 0 - return -1 - def readinto(self, buf): - buf[:] = memoryview(__buf)[self.off:self.off + len(buf)] - self.off += len(buf) - return len(buf) -class __FS: - def mount(self, readonly, mkfs): - pass - def umount(self): - pass - def chdir(self, path): - pass - def getcwd(self): - return "" - def stat(self, path): - if path == '__injected_test.mpy': - return (0,0,0,0,0,0,0,0,0,0) - else: - raise OSError(2) # ENOENT - def open(self, path, mode): - self.stat(path) - return __File() -vfs.mount(__FS(), '/__vfstest') -os.chdir('/__vfstest') -{import_prologue} -__import__('__injected_test') -""" - # Platforms associated with the unix port, values of `sys.platform`. PC_PLATFORMS = ("darwin", "linux", "win32") @@ -161,10 +103,8 @@ def open(self, path, mode): "basics/exception_chain.py", # These require stack-allocated slice optimisation. "micropython/heapalloc_slice.py", - # These require running the scheduler. + # These require implicitly running the scheduler between bytecodes. "micropython/schedule.py", - "extmod/asyncio_event_queue.py", - "extmod/asyncio_iterator_event.py", # These require sys.exc_info(). "misc/sys_exc_info.py", # These require sys.settrace(). @@ -180,6 +120,9 @@ def open(self, path, mode): # Tests to skip on specific targets. # These are tests that are difficult to detect that they should not be run on the given target. platform_tests_to_skip = { + "esp8266": ( + "stress/list_sort.py", # watchdog kicks in because it takes too long + ), "minimal": ( "basics/class_inplace_op.py", # all special methods not supported "basics/subclass_native_init.py", # native subclassing corner cases not support @@ -333,11 +276,6 @@ def open(self, path, mode): ) -def rm_f(fname): - if os.path.exists(fname): - os.remove(fname) - - # unescape wanted regex chars and escape unwanted ones def convert_regex_escapes(line): cs = [] @@ -362,38 +300,6 @@ def platform_to_port(platform): return platform_to_port_map.get(platform, platform) -def convert_device_shortcut_to_real_device(device): - if device.startswith("port:"): - return device.split(":", 1)[1] - elif device.startswith("a") and device[1:].isdigit(): - return "/dev/ttyACM" + device[1:] - elif device.startswith("u") and device[1:].isdigit(): - return "/dev/ttyUSB" + device[1:] - elif device.startswith("c") and device[1:].isdigit(): - return "COM" + device[1:] - else: - return device - - -def get_test_instance(test_instance, baudrate, user, password): - if test_instance == "unix": - return None - elif test_instance == "webassembly": - return PyboardNodeRunner() - else: - # Assume it's a device path. - port = convert_device_shortcut_to_real_device(test_instance) - - global pyboard - sys.path.append(base_path("../tools")) - import pyboard - - pyb = pyboard.Pyboard(port, baudrate, user, password) - pyboard.Pyboard.run_script_on_remote_target = run_script_on_remote_target - pyb.enter_raw_repl() - return pyb - - def detect_inline_asm_arch(pyb, args): for arch in ("rv32", "thumb", "xtensa"): output = run_feature_check(pyb, args, "inlineasm_{}.py".format(arch)) @@ -499,90 +405,6 @@ def detect_target_wiring_script(pyb, args): pyb.target_wiring_script = tw_data -def prepare_script_for_target(args, *, script_text=None, force_plain=False): - if force_plain or (not args.via_mpy and args.emit == "bytecode"): - # A plain test to run as-is, no processing needed. - pass - elif args.via_mpy: - tempname = tempfile.mktemp(dir="") - mpy_filename = tempname + ".mpy" - - script_filename = tempname + ".py" - with open(script_filename, "wb") as f: - f.write(script_text) - - try: - subprocess.check_output( - [MPYCROSS] - + args.mpy_cross_flags.split() - + ["-o", mpy_filename, "-X", "emit=" + args.emit, script_filename], - stderr=subprocess.STDOUT, - ) - except subprocess.CalledProcessError as er: - return True, b"mpy-cross crash\n" + er.output - - with open(mpy_filename, "rb") as f: - script_text = b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n" - - rm_f(mpy_filename) - rm_f(script_filename) - - script_text += bytes(injected_import_hook_code, "ascii") - else: - print("error: using emit={} must go via .mpy".format(args.emit)) - sys.exit(1) - - return False, script_text - - -def run_script_on_remote_target(pyb, args, test_file, is_special): - with open(test_file, "rb") as f: - script = f.read() - - # If the test is not a special test, prepend it with a print to indicate that it started. - # If the print does not execute this means that the test did not even start, eg it was - # too large for the target. - prepend_start_test = not is_special - if prepend_start_test: - if script.startswith(b"#"): - script = b"print('START TEST')" + script - else: - script = b"print('START TEST')\n" + script - - had_crash, script = prepare_script_for_target(args, script_text=script, force_plain=is_special) - - if had_crash: - return True, script - - try: - had_crash = False - pyb.enter_raw_repl() - if test_file.endswith(tests_requiring_target_wiring) and pyb.target_wiring_script: - pyb.exec_( - "import sys;sys.modules['target_wiring']=__build_class__(lambda:exec(" - + repr(pyb.target_wiring_script) - + "),'target_wiring')" - ) - output_mupy = pyb.exec_(script, timeout=TEST_TIMEOUT) - except pyboard.PyboardError as e: - had_crash = True - if not is_special and e.args[0] == "exception": - if prepend_start_test and e.args[1] == b"" and b"MemoryError" in e.args[2]: - output_mupy = b"SKIP-TOO-LARGE\n" - else: - output_mupy = e.args[1] + e.args[2] + b"CRASH" - else: - output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH" - - if prepend_start_test: - if output_mupy.startswith(b"START TEST\r\n"): - output_mupy = output_mupy.removeprefix(b"START TEST\r\n") - else: - had_crash = True - - return had_crash, output_mupy - - tests_with_regex_output = [ base_path(file) for file in ( @@ -718,8 +540,9 @@ def send_get(what): else: # run via pyboard interface + requires_target_wiring = test_file.endswith(tests_requiring_target_wiring) had_crash, output_mupy = pyb.run_script_on_remote_target( - args, test_file_abspath, is_special + args, test_file_abspath, is_special, requires_target_wiring ) # canonical form for all ports/platforms is to use \n for end-of-line @@ -809,51 +632,6 @@ def value(self): return self._value -class PyboardNodeRunner: - def __init__(self): - mjs = os.getenv("MICROPY_MICROPYTHON_MJS") - if mjs is None: - mjs = base_path("../ports/webassembly/build-standard/micropython.mjs") - else: - mjs = os.path.abspath(mjs) - self.micropython_mjs = mjs - - def close(self): - pass - - def run_script_on_remote_target(self, args, test_file, is_special): - cwd = os.path.dirname(test_file) - - # Create system command list. - cmdlist = ["node"] - if test_file.endswith(".py"): - # Run a Python script indirectly via "node micropython.mjs ". - cmdlist.append(self.micropython_mjs) - if args.heapsize is not None: - cmdlist.extend(["-X", "heapsize=" + args.heapsize]) - cmdlist.append(test_file) - else: - # Run a js/mjs script directly with Node, passing in the path to micropython.mjs. - cmdlist.append(test_file) - cmdlist.append(self.micropython_mjs) - - # Run the script. - try: - had_crash = False - output_mupy = subprocess.check_output( - cmdlist, stderr=subprocess.STDOUT, timeout=TEST_TIMEOUT, cwd=cwd - ) - except subprocess.CalledProcessError as er: - had_crash = True - output_mupy = er.output + b"CRASH" - except subprocess.TimeoutExpired as er: - had_crash = True - output_mupy = (er.output or b"") + b"TIMEOUT" - - # Return the results. - return had_crash, output_mupy - - def run_tests(pyb, tests, args, result_dir, num_threads=1): testcase_count = ThreadSafeCounter() test_results = ThreadSafeCounter([]) @@ -947,10 +725,15 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add("inlineasm/thumb/asmfpsqrt.py") if args.inlineasm_arch == "rv32": - # Check if @micropython.asm_rv32 supports Zba instructions, and skip such tests if it doesn't - output = run_feature_check(pyb, args, "inlineasm_rv32_zba.py") - if output != b"rv32_zba\n": - skip_tests.add("inlineasm/rv32/asmzba.py") + # Discover extension-specific inlineasm tests and add them to the + # list of tests to run if applicable. + for extension in RV32_ARCH_FLAGS: + try: + output = run_feature_check(pyb, args, "inlineasm_rv32_{}.py".format(extension)) + if output.strip() != "rv32_{}".format(extension).encode(): + skip_tests.add("inlineasm/rv32/asm_ext_{}.py".format(extension)) + except FileNotFoundError: + pass # Check if emacs repl is supported, and skip such tests if it's not t = run_feature_check(pyb, args, "repl_emacs_check.py") @@ -974,8 +757,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): # Some tests shouldn't be run on GitHub Actions if os.getenv("GITHUB_ACTIONS") == "true": - skip_tests.add("thread/stress_schedule.py") # has reliability issues - if os.getenv("RUNNER_OS") == "Windows" and os.getenv("CI_BUILD_CONFIGURATION") == "Debug": # fails with stack overflow on Debug builds skip_tests.add("misc/sys_settrace_features.py") @@ -1008,6 +789,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): if not has_complex: skip_tests.add("float/complex1.py") skip_tests.add("float/complex1_intbig.py") + skip_tests.add("float/complex1_micropython.py") skip_tests.add("float/complex_reverse_op.py") skip_tests.add("float/complex_special_methods.py") skip_tests.add("float/int_big_float.py") @@ -1249,70 +1031,6 @@ def run_one_test(test_file): return test_results.value, testcase_count.value -# Print a summary of the results and save them to a JSON file. -# Returns True if everything succeeded, False otherwise. -def create_test_report(args, test_results, testcase_count=None): - passed_tests = list(r for r in test_results if r[1] == "pass") - skipped_tests = list(r for r in test_results if r[1] == "skip" and r[2] != "too large") - skipped_tests_too_large = list( - r for r in test_results if r[1] == "skip" and r[2] == "too large" - ) - failed_tests = list(r for r in test_results if r[1] == "fail") - - num_tests_performed = len(passed_tests) + len(failed_tests) - - testcase_count_info = "" - if testcase_count is not None: - testcase_count_info = " ({} individual testcases)".format(testcase_count) - print("{} tests performed{}".format(num_tests_performed, testcase_count_info)) - - print("{} tests passed".format(len(passed_tests))) - - if len(skipped_tests) > 0: - print( - "{} tests skipped: {}".format( - len(skipped_tests), " ".join(test[0] for test in skipped_tests) - ) - ) - - if len(skipped_tests_too_large) > 0: - print( - "{} tests skipped because they are too large: {}".format( - len(skipped_tests_too_large), " ".join(test[0] for test in skipped_tests_too_large) - ) - ) - - if len(failed_tests) > 0: - print( - "{} tests failed: {}".format( - len(failed_tests), " ".join(test[0] for test in failed_tests) - ) - ) - - # Serialize regex added by append_filter. - def to_json(obj): - if isinstance(obj, re.Pattern): - return obj.pattern - return obj - - with open(os.path.join(args.result_dir, RESULTS_FILE), "w") as f: - json.dump( - { - # The arguments passed on the command-line. - "args": vars(args), - # A list of all results of the form [(test, result, reason), ...]. - "results": list(test for test in test_results), - # A list of failed tests. This is deprecated, use the "results" above instead. - "failed_tests": [test[0] for test in failed_tests], - }, - f, - default=to_json, - ) - - # Return True only if all tests succeeded. - return len(failed_tests) == 0 - - class append_filter(argparse.Action): def __init__(self, option_strings, dest, **kwargs): super().__init__(option_strings, dest, default=[], **kwargs) @@ -1327,39 +1045,7 @@ def __call__(self, parser, args, value, option): args.filters.append((option, re.compile(value))) -test_instance_description = """\ -By default the tests are run against the unix port of MicroPython. To run it -against something else, use the -t option. See below for details. -""" -test_instance_epilog = """\ -The -t option accepts the following for the test instance: -- unix - use the unix port of MicroPython, specified by the MICROPY_MICROPYTHON - environment variable (which defaults to the standard variant of either the unix - or windows ports, depending on the host platform) -- webassembly - use the webassembly port of MicroPython, specified by the - MICROPY_MICROPYTHON_MJS environment variable (which defaults to the standard - variant of the webassembly port) -- port: - connect to and use the given serial port device -- a - connect to and use /dev/ttyACM -- u - connect to and use /dev/ttyUSB -- c - connect to and use COM -- exec: - execute a command and attach to its stdin/stdout -- execpty: - execute a command and attach to the printed /dev/pts/ device -- ... - connect to the given IPv4 address -- anything else specifies a serial port -""" - -test_directory_description = """\ -Tests are discovered by scanning test directories for .py files or using the -specified test files. If test files nor directories are specified, the script -expects to be ran in the tests directory (where this file is located) and the -builtin tests suitable for the target platform are ran. -""" - - def main(): - global injected_import_hook_code - cmd_parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=f"""Run and manage tests for MicroPython. @@ -1466,7 +1152,7 @@ def main(): if args.begin: with open(args.begin, "rt") as source: prologue = source.read() - injected_import_hook_code = injected_import_hook_code.replace("{import_prologue}", prologue) + set_injected_prologue(prologue) if args.print_failures: for out in glob(os.path.join(args.result_dir, "*.out")): @@ -1489,7 +1175,7 @@ def main(): os.path.join(args.result_dir, "*.out") ): os.remove(f) - rm_f(os.path.join(args.result_dir, RESULTS_FILE)) + rm_f(get_results_filename(args)) sys.exit(0) @@ -1505,7 +1191,7 @@ def main(): ) if args.run_failures: - results_file = os.path.join(args.result_dir, RESULTS_FILE) + results_file = get_results_filename(args) if os.path.exists(results_file): with open(results_file, "r") as f: tests = list(test[0] for test in json.load(f)["results"] if test[1] == "fail") diff --git a/tests/serial_test.py b/tests/serial_test.py index 455d2277f64dd..eebea402fa4c9 100755 --- a/tests/serial_test.py +++ b/tests/serial_test.py @@ -8,11 +8,24 @@ # The `serial-device` will default to /dev/ttyACM0. import argparse +import random import serial import sys import time -run_tests_module = __import__("run-tests") +from test_utils import test_instance_epilog, convert_device_shortcut_to_real_device + +echo_test_script = """ +import sys +bytes_min=%u +bytes_max=%u +repeat=%u +b=memoryview(bytearray(bytes_max)) +for n in range(bytes_min,bytes_max+1): + for _ in range(repeat): + n2 = sys.stdin.readinto(b[:n]) + sys.stdout.write(b[:n2]) +""" read_test_script = """ bin = True @@ -86,6 +99,8 @@ def drain_input(ser): def send_script(ser, script): + ser.write(b"\x03\x01\x04") # break, raw-repl, soft-reboot + drain_input(ser) chunk_size = 32 for i in range(0, len(script), chunk_size): ser.write(script[i : i + chunk_size]) @@ -98,6 +113,59 @@ def send_script(ser, script): raise TestError("could not send script", response) +def echo_test(ser_repl, ser_data): + global test_passed + + # Make the test data deterministic. + random.seed(0) + + # Set parameters for the test. + # Go just a bit above the size of a USB high-speed packet. + bytes_min = 1 + bytes_max = 520 + num_repeat = 1 + + # Load and run the write_test_script. + script = bytes(echo_test_script % (bytes_min, bytes_max, num_repeat), "ascii") + send_script(ser_repl, script) + + # A selection of printable bytes for echo data. + printable_bytes = list(range(48, 58)) + list(range(65, 91)) + list(range(97, 123)) + + # Write data to the device and record the echo'd data. + # Use a different selection of random printable characters for each + # echo, to make it easier to debug when the echo doesn't match. + num_errors = 0 + echo_results = [] + for num_bytes in range(bytes_min, bytes_max + 1): + print(f"DATA ECHO: {num_bytes} / {bytes_max}", end="\r") + for repeat in range(num_repeat): + rand_bytes = list(random.choice(printable_bytes) for _ in range(8)) + buf = bytes(random.choice(rand_bytes) for _ in range(num_bytes)) + ser_data.write(buf) + buf2 = ser_data.read(len(buf)) + match = buf == buf2 + num_errors += not match + echo_results.append((match, buf, buf2)) + if num_errors > 8: + # Stop early if there are too many errors. + break + ser_repl.write(b"\x03") + + # Print results. + if all(match for match, _, _ in echo_results): + print("DATA ECHO: OK for {}-{} bytes at a time".format(bytes_min, bytes_max)) + else: + test_passed = False + print("DATA ECHO: FAIL ") + for match, buf, buf2 in echo_results: + print(" sent", len(buf), buf) + if match: + print(" echo match") + else: + print(" echo", len(buf), buf2) + + def read_test(ser_repl, ser_data, bufsize, nbuf): global test_passed @@ -109,8 +177,6 @@ def read_test(ser_repl, ser_data, bufsize, nbuf): READ_TIMEOUT_S = 2 # Load and run the read_test_script. - ser_repl.write(b"\x03\x01\x04") # break, raw-repl, soft-reboot - drain_input(ser_repl) script = bytes(read_test_script % (bufsize, nbuf), "ascii") send_script(ser_repl, script) @@ -166,8 +232,6 @@ def write_test(ser_repl, ser_data, bufsize, nbuf, verified): global test_passed # Load and run the write_test_script. - ser_repl.write(b"\x03\x01\x04") # break, raw-repl, soft-reboot - drain_input(ser_repl) if verified: script = write_test_script_verified else: @@ -214,6 +278,12 @@ def do_test(dev_repl, dev_data=None, time_per_subtest=1): ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=1) ser_data = serial.Serial(dev_data, baudrate=115200, timeout=1) + # Do echo test first, and abort if it doesn't pass. + echo_test(ser_repl, ser_data) + if not test_passed: + return + + # Do read and write throughput test. for test_func, test_args, bufsize in ( (read_test, (), 256), (write_test, (True,), 128), @@ -237,7 +307,7 @@ def main(): cmd_parser = argparse.ArgumentParser( description="Test performance and reliability of serial port communication.", - epilog=run_tests_module.test_instance_epilog, + epilog=test_instance_epilog, formatter_class=argparse.RawTextHelpFormatter, ) cmd_parser.add_argument( @@ -251,7 +321,7 @@ def main(): ) args = cmd_parser.parse_args() - dev_repl = run_tests_module.convert_device_shortcut_to_real_device(args.test_instance) + dev_repl = convert_device_shortcut_to_real_device(args.test_instance) test_passed = True try: diff --git a/tests/target_wiring/esp8266.py b/tests/target_wiring/esp8266.py new file mode 100644 index 0000000000000..336deb3dda018 --- /dev/null +++ b/tests/target_wiring/esp8266.py @@ -0,0 +1,7 @@ +# Target wiring for general esp8266 board. +# +# Connect: +# - GPIO4 to GPIO5 + +uart_loopback_args = (1,) +uart_loopback_kwargs = {} diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000000000..abbc670c12521 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,358 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# The MIT License (MIT) +# Copyright (c) 2019-2025 Damien P. George + +import inspect +import json +import os +import re +import subprocess +import sys +import tempfile + +# See stackoverflow.com/questions/2632199: __file__ nor sys.argv[0] +# are guaranteed to always work, this one should though. +_BASEPATH = os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: None))) + + +def base_path(*p): + return os.path.abspath(os.path.join(_BASEPATH, *p)).replace("\\", "/") + + +sys.path.append(base_path("../tools")) +import pyboard + +# File with the test results. +_RESULTS_FILE = "_results.json" + +# Maximum time to run a single test, in seconds. +TEST_TIMEOUT = float(os.environ.get("MICROPY_TEST_TIMEOUT", 30)) + +# mpy-cross is only needed if --via-mpy command-line arg is passed +if os.name == "nt": + MPYCROSS = os.getenv("MICROPY_MPYCROSS", base_path("../mpy-cross/build/mpy-cross.exe")) +else: + MPYCROSS = os.getenv("MICROPY_MPYCROSS", base_path("../mpy-cross/build/mpy-cross")) + +test_instance_description = """\ +By default the tests are run against the unix port of MicroPython. To run it +against something else, use the -t option. See below for details. +""" + +test_instance_epilog = """\ +The -t option accepts the following for the test instance: +- unix - use the unix port of MicroPython, specified by the MICROPY_MICROPYTHON + environment variable (which defaults to the standard variant of either the unix + or windows ports, depending on the host platform) +- webassembly - use the webassembly port of MicroPython, specified by the + MICROPY_MICROPYTHON_MJS environment variable (which defaults to the standard + variant of the webassembly port) +- port: - connect to and use the given serial port device +- a - connect to and use /dev/ttyACM +- u - connect to and use /dev/ttyUSB +- c - connect to and use COM +- exec: - execute a command and attach to its stdin/stdout +- execpty: - execute a command and attach to the printed /dev/pts/ device +- ... - connect to the given IPv4 address +- anything else specifies a serial port +""" + +test_directory_description = """\ +Tests are discovered by scanning test directories for .py files or using the +specified test files. If test files nor directories are specified, the script +expects to be ran in the tests directory (where this file is located) and the +builtin tests suitable for the target platform are ran. +""" + +# Code to allow a target MicroPython to import an .mpy from RAM +# Note: the module is named `__injected_test` but it needs to have `__name__` set to +# `__main__` so that the test sees itself as the main module, eg so unittest works. +_injected_import_hook_code = """\ +import sys, os, io, vfs +class __File(io.IOBase): + def __init__(self): + module = sys.modules['__injected_test'] + module.__name__ = '__main__' + sys.modules['__main__'] = module + self.off = 0 + def ioctl(self, request, arg): + if request == 4: # MP_STREAM_CLOSE + return 0 + return -1 + def readinto(self, buf): + buf[:] = memoryview(__buf)[self.off:self.off + len(buf)] + self.off += len(buf) + return len(buf) +class __FS: + def mount(self, readonly, mkfs): + pass + def umount(self): + pass + def chdir(self, path): + pass + def getcwd(self): + return "" + def stat(self, path): + if path == '__injected_test.mpy': + return (0,0,0,0,0,0,0,0,0,0) + else: + raise OSError(2) # ENOENT + def open(self, path, mode): + self.stat(path) + return __File() +vfs.mount(__FS(), '/__vfstest') +os.chdir('/__vfstest') +{import_prologue} +__import__('__injected_test') +""" + + +class PyboardNodeRunner: + def __init__(self): + mjs = os.getenv("MICROPY_MICROPYTHON_MJS") + if mjs is None: + mjs = base_path("../ports/webassembly/build-standard/micropython.mjs") + else: + mjs = os.path.abspath(mjs) + self.micropython_mjs = mjs + + def close(self): + pass + + def run_script_on_remote_target(self, args, test_file, is_special, requires_target_wiring): + cwd = os.path.dirname(test_file) + + # Create system command list. + cmdlist = ["node"] + if test_file.endswith(".py"): + # Run a Python script indirectly via "node micropython.mjs ". + cmdlist.append(self.micropython_mjs) + if args.heapsize is not None: + cmdlist.extend(["-X", "heapsize=" + args.heapsize]) + cmdlist.append(test_file) + else: + # Run a js/mjs script directly with Node, passing in the path to micropython.mjs. + cmdlist.append(test_file) + cmdlist.append(self.micropython_mjs) + + # Run the script. + try: + had_crash = False + output_mupy = subprocess.check_output( + cmdlist, stderr=subprocess.STDOUT, timeout=TEST_TIMEOUT, cwd=cwd + ) + except subprocess.CalledProcessError as er: + had_crash = True + output_mupy = er.output + b"CRASH" + except subprocess.TimeoutExpired as er: + had_crash = True + output_mupy = (er.output or b"") + b"TIMEOUT" + + # Return the results. + return had_crash, output_mupy + + +def rm_f(fname): + if os.path.exists(fname): + os.remove(fname) + + +def normalize_newlines(data): + """Normalize newline variations to \\n. + + Only normalizes actual line endings, not literal \\r characters in strings. + Handles \\r\\r\\n and \\r\\n cases to ensure consistent comparison + across different platforms and terminals. + """ + if isinstance(data, bytes): + # Handle PTY double-newline issue first + data = data.replace(b"\r\r\n", b"\n") + # Then handle standard Windows line endings + data = data.replace(b"\r\n", b"\n") + # Don't convert standalone \r as it might be literal content + return data + + +def set_injected_prologue(prologue): + global _injected_import_hook_code + _injected_import_hook_code = _injected_import_hook_code.replace("{import_prologue}", prologue) + + +def get_results_filename(args): + return os.path.join(args.result_dir, _RESULTS_FILE) + + +def convert_device_shortcut_to_real_device(device): + if device.startswith("port:"): + return device.split(":", 1)[1] + elif device.startswith("a") and device[1:].isdigit(): + return "/dev/ttyACM" + device[1:] + elif device.startswith("u") and device[1:].isdigit(): + return "/dev/ttyUSB" + device[1:] + elif device.startswith("c") and device[1:].isdigit(): + return "COM" + device[1:] + else: + return device + + +def get_test_instance(test_instance, baudrate, user, password): + if test_instance == "unix": + return None + elif test_instance == "webassembly": + return PyboardNodeRunner() + else: + # Assume it's a device path. + port = convert_device_shortcut_to_real_device(test_instance) + + pyb = pyboard.Pyboard(port, baudrate, user, password) + pyboard.Pyboard.run_script_on_remote_target = run_script_on_remote_target + pyb.enter_raw_repl() + return pyb + + +def prepare_script_for_target(args, *, script_text=None, force_plain=False): + if force_plain or (not args.via_mpy and args.emit == "bytecode"): + # A plain test to run as-is, no processing needed. + pass + elif args.via_mpy: + tempname = tempfile.mktemp(dir="") + mpy_filename = tempname + ".mpy" + + script_filename = tempname + ".py" + with open(script_filename, "wb") as f: + f.write(script_text) + + try: + subprocess.check_output( + [MPYCROSS] + + args.mpy_cross_flags.split() + + ["-o", mpy_filename, "-X", "emit=" + args.emit, script_filename], + stderr=subprocess.STDOUT, + ) + except subprocess.CalledProcessError as er: + return True, b"mpy-cross crash\n" + er.output + + with open(mpy_filename, "rb") as f: + script_text = b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n" + + rm_f(mpy_filename) + rm_f(script_filename) + + script_text += bytes(_injected_import_hook_code, "ascii") + else: + print("error: using emit={} must go via .mpy".format(args.emit)) + sys.exit(1) + + return False, script_text + + +def run_script_on_remote_target(pyb, args, test_file, is_special, requires_target_wiring): + with open(test_file, "rb") as f: + script = f.read() + + # If the test is not a special test, prepend it with a print to indicate that it started. + # If the print does not execute this means that the test did not even start, eg it was + # too large for the target. + prepend_start_test = not is_special + if prepend_start_test: + if script.startswith(b"#"): + script = b"print('START TEST')" + script + else: + script = b"print('START TEST')\n" + script + + had_crash, script = prepare_script_for_target(args, script_text=script, force_plain=is_special) + + if had_crash: + return True, script + + try: + had_crash = False + pyb.enter_raw_repl() + if requires_target_wiring and pyb.target_wiring_script: + pyb.exec_( + "import sys;sys.modules['target_wiring']=__build_class__(lambda:exec(" + + repr(pyb.target_wiring_script) + + "),'target_wiring')" + ) + output_mupy = pyb.exec_(script, timeout=TEST_TIMEOUT) + except pyboard.PyboardError as e: + had_crash = True + if not is_special and e.args[0] == "exception": + if prepend_start_test and e.args[1] == b"" and b"MemoryError" in e.args[2]: + output_mupy = b"SKIP-TOO-LARGE\n" + else: + output_mupy = e.args[1] + e.args[2] + b"CRASH" + else: + output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH" + + if prepend_start_test: + if output_mupy.startswith(b"START TEST\r\n"): + output_mupy = output_mupy.removeprefix(b"START TEST\r\n") + else: + had_crash = True + + return had_crash, output_mupy + + +# Print a summary of the results and save them to a JSON file. +# Returns True if everything succeeded, False otherwise. +def create_test_report(args, test_results, testcase_count=None): + passed_tests = list(r for r in test_results if r[1] == "pass") + skipped_tests = list(r for r in test_results if r[1] == "skip" and r[2] != "too large") + skipped_tests_too_large = list( + r for r in test_results if r[1] == "skip" and r[2] == "too large" + ) + failed_tests = list(r for r in test_results if r[1] == "fail") + + num_tests_performed = len(passed_tests) + len(failed_tests) + + testcase_count_info = "" + if testcase_count is not None: + testcase_count_info = " ({} individual testcases)".format(testcase_count) + print("{} tests performed{}".format(num_tests_performed, testcase_count_info)) + + print("{} tests passed".format(len(passed_tests))) + + if len(skipped_tests) > 0: + print( + "{} tests skipped: {}".format( + len(skipped_tests), " ".join(test[0] for test in skipped_tests) + ) + ) + + if len(skipped_tests_too_large) > 0: + print( + "{} tests skipped because they are too large: {}".format( + len(skipped_tests_too_large), " ".join(test[0] for test in skipped_tests_too_large) + ) + ) + + if len(failed_tests) > 0: + print( + "{} tests failed: {}".format( + len(failed_tests), " ".join(test[0] for test in failed_tests) + ) + ) + + # Serialize regex added by append_filter. + def to_json(obj): + if isinstance(obj, re.Pattern): + return obj.pattern + return obj + + with open(get_results_filename(args), "w") as f: + json.dump( + { + # The arguments passed on the command-line. + "args": vars(args), + # A list of all results of the form [(test, result, reason), ...]. + "results": list(test for test in test_results), + # A list of failed tests. This is deprecated, use the "results" above instead. + "failed_tests": [test[0] for test in failed_tests], + }, + f, + default=to_json, + ) + + # Return True only if all tests succeeded. + return len(failed_tests) == 0 diff --git a/tests/thread/stress_schedule.py b/tests/thread/stress_schedule.py index 362d71aa12e38..fca9b38df89fa 100644 --- a/tests/thread/stress_schedule.py +++ b/tests/thread/stress_schedule.py @@ -27,15 +27,13 @@ def task(x): n += 1 -# This function must always use the bytecode emitter so it bounces the GIL when running. -@micropython.bytecode def thread(): while thread_run: try: micropython.schedule(task, None) except RuntimeError: # Queue full, back off. - time.sleep_ms(10) + time.sleep_ms(1) for i in range(8): diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh index 9c94d887f045e..ed748fc01e179 100755 --- a/tools/autobuild/autobuild.sh +++ b/tools/autobuild/autobuild.sh @@ -7,6 +7,9 @@ # - IDF_PATH_V50 must be set # - MICROPY_AUTOBUILD_MICROPYTHON_REPO must be set to location of micropython repository # - MICROPY_AUTOBUILD_MAKE must be set to the make command to use, eg "make -j2" +# - MICROPY_AUTOBUILD_DEST must be set to a directory name to place the output firmware +# (this directory will be created, and removed at the end if firmware is copied to a +# remote machine using MICROPY_AUTOBUILD_REMOTE_MACHINE and MICROPY_AUTOBUILD_REMOTE_DIR) # # Optional settings: # - MICROPY_AUTOBUILD_REMOTE_MACHINE can be set to a remote ssh machine to copy files to @@ -27,6 +30,11 @@ if [ -z "$MICROPY_AUTOBUILD_MAKE" ]; then exit 1 fi +if [ -z "$MICROPY_AUTOBUILD_DEST" ]; then + echo "must set MICROPY_AUTOBUILD_DEST" + exit 1 +fi + ######################################## # Initialisation @@ -37,7 +45,7 @@ AUTODIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source ${AUTODIR}/build-boards.sh # make local directory to put firmware -LOCAL_FIRMWARE=/tmp/autobuild-firmware-$$ +LOCAL_FIRMWARE=${MICROPY_AUTOBUILD_DEST} mkdir -p ${LOCAL_FIRMWARE} # get latest MicroPython diff --git a/tools/ci.sh b/tools/ci.sh index 63eed15bea2be..588bb31638c56 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -87,7 +87,7 @@ function _ci_is_git_merge { function ci_code_size_build { # check the following ports for the change in their code size # Override the list by setting PORTS_TO_CHECK in the environment before invoking ci. - : ${PORTS_TO_CHECK:=bmusxpdv} + : ${PORTS_TO_CHECK:=bmus3xpdv} SUBMODULES="lib/asf4 lib/berkeley-db-1.xx lib/btstack lib/cyw43-driver lib/lwip lib/mbedtls lib/micropython-lib lib/nxp_driver lib/pico-sdk lib/stm32lib lib/tinyusb" @@ -173,6 +173,15 @@ function ci_mpy_format_test { $micropython ./tools/mpy-tool.py -x -d examples/natmod/features1/features1.mpy } +function ci_mpy_cross_debug_emitter { + make ${MAKEOPTS} -C mpy-cross + mpy_cross=./mpy-cross/build/mpy-cross + + # Make sure the debug emitter does not crash or fail for simple files + $mpy_cross -X emit=native -march=debug ./tests/basics/0prelim.py | \ + grep -E "ENTRY|EXIT" | wc -l | grep "^2$" +} + ######################################################################################## # ports/cc3200 @@ -185,6 +194,15 @@ function ci_cc3200_build { make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release } +######################################################################################## +# ports/embed + +function ci_embedding_build { + make ${MAKEOPTS} -C examples/embedding -f micropython_embed.mk + make ${MAKEOPTS} -C examples/embedding + ./examples/embedding/embed | grep "hello world" +} + ######################################################################################## # ports/esp32 @@ -197,6 +215,10 @@ PYTHON_VER=$(${PYTHON:-python} --version | cut -d' ' -f2) export IDF_CCACHE_ENABLE=1 +function ci_esp32_idf_ver { + echo "IDF_VER=${IDF_VER}-py${PYTHON_VER}" +} + function ci_esp32_idf_setup { echo "Using ESP-IDF version $IDF_VER" git clone --depth 1 --branch $IDF_VER https://github.com/espressif/esp-idf.git @@ -245,6 +267,13 @@ function ci_esp32_build_c2_c5_c6 { make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C6 } +function ci_esp32_build_p4 { + ci_esp32_build_common + + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_P4 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_P4 BOARD_VARIANT=C6_WIFI +} + ######################################################################################## # ports/esp8266 @@ -362,6 +391,8 @@ function ci_qemu_setup_rv64 { ci_gcc_riscv_setup sudo apt-get update sudo apt-get install qemu-system + sudo pip3 install pyelftools + sudo pip3 install ar qemu-system-riscv64 --version } @@ -420,6 +451,10 @@ function ci_qemu_build_rv64 { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 submodules make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 test + + # Test building and running native .mpy with rv64imc architecture. + ci_native_mpy_modules_build rv64imc + make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 test_natmod } ######################################################################################## @@ -485,13 +520,22 @@ function ci_samd_build { # ports/stm32 function ci_stm32_setup { - ci_gcc_arm_setup + # Use a recent version of the ARM toolchain, to work with Cortex-M55. + wget https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz + xzcat arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz | tar x + pip3 install pyelftools pip3 install ar pip3 install pyhy } +function ci_stm32_path { + echo $(pwd)/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin +} + function ci_stm32_pyb_build { + # This function builds the following MCU families: F4, F7. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 MICROPY_PY_NETWORK_WIZNET5K=5200 submodules make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 submodules @@ -506,6 +550,8 @@ function ci_stm32_pyb_build { } function ci_stm32_nucleo_build { + # This function builds the following MCU families: F0, H5, H7, L0, L4, WB. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI submodules git submodule update --init lib/mynewt-nimble @@ -532,9 +578,17 @@ function ci_stm32_nucleo_build { } function ci_stm32_misc_build { + # This function builds the following MCU families: G0, G4, H7, L1, N6, U5, WL. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 BOARD=ARDUINO_GIGA submodules make ${MAKEOPTS} -C ports/stm32 BOARD=ARDUINO_GIGA + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_G0B1RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_G474RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L152RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_N657X0 + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_U5A5ZJ_Q + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_WL55 } ######################################################################################## @@ -634,9 +688,9 @@ function ci_native_mpy_modules_build { make -C examples/natmod/$natmod ARCH=$arch done - # features2 requires soft-float on rv32imc and xtensa. + # features2 requires soft-float on rv32imc, rv64imc, and xtensa. make -C examples/natmod/features2 ARCH=$arch clean - if [ $arch = "rv32imc" ] || [ $arch = "xtensa" ]; then + if [ $arch = "rv32imc" ] || [ $arch = "rv64imc" ] || [ $arch = "xtensa" ]; then make -C examples/natmod/features2 ARCH=$arch MICROPY_FLOAT_IMPL=float else make -C examples/natmod/features2 ARCH=$arch @@ -723,9 +777,8 @@ function ci_unix_32bit_setup { sudo dpkg --add-architecture i386 sudo apt-get update sudo apt-get install gcc-multilib g++-multilib libffi-dev:i386 - sudo pip3 install setuptools - sudo pip3 install pyelftools - sudo pip3 install ar + python -m pip install pyelftools + python -m pip install ar gcc --version python3 --version } @@ -859,11 +912,11 @@ function ci_unix_macos_run_tests { function ci_unix_qemu_mips_setup { sudo apt-get update - sudo apt-get install gcc-mips-linux-gnu g++-mips-linux-gnu libc6-mips-cross - sudo apt-get install qemu-user - qemu-mips --version - sudo mkdir /etc/qemu-binfmt - sudo ln -s /usr/mips-linux-gnu/ /etc/qemu-binfmt/mips + sudo apt-get install gcc-mips-linux-gnu g++-mips-linux-gnu libc6-mips-cross libltdl-dev + sudo apt-get install qemu-user-static + qemu-mips-static --version + sudo mkdir -p /usr/gnemul + sudo ln -s /usr/mips-linux-gnu /usr/gnemul/qemu-mips } function ci_unix_qemu_mips_build { @@ -873,20 +926,20 @@ function ci_unix_qemu_mips_build { function ci_unix_qemu_mips_run_tests { # Issues with MIPS tests: - # - thread/stress_aes.py takes around 50 seconds + # - thread/stress_aes.py takes around 90 seconds # - thread/stress_recurse.py is flaky # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=90 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py') + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=180 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py') } function ci_unix_qemu_arm_setup { sudo apt-get update - sudo apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi - sudo apt-get install qemu-user - qemu-arm --version - sudo mkdir /etc/qemu-binfmt - sudo ln -s /usr/arm-linux-gnueabi/ /etc/qemu-binfmt/arm + sudo apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libltdl-dev + sudo apt-get install qemu-user-static + qemu-arm-static --version + sudo mkdir -p /usr/gnemul + sudo ln -s /usr/arm-linux-gnueabi /usr/gnemul/qemu-arm } function ci_unix_qemu_arm_build { @@ -896,35 +949,41 @@ function ci_unix_qemu_arm_build { function ci_unix_qemu_arm_run_tests { # Issues with ARM tests: - # - (i)listdir does not work, it always returns the empty list (it's an issue with the underlying C call) # - thread/stress_aes.py takes around 70 seconds # - thread/stress_recurse.py is flaky # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=90 ./run-tests.py --exclude 'vfs_posix.*\.py|thread/stress_recurse.py|thread/thread_gc1.py') + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=90 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py') } function ci_unix_qemu_riscv64_setup { + ci_gcc_riscv_setup sudo apt-get update - sudo apt-get install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu - sudo apt-get install qemu-user - qemu-riscv64 --version - sudo mkdir /etc/qemu-binfmt - sudo ln -s /usr/riscv64-linux-gnu/ /etc/qemu-binfmt/riscv64 + sudo apt-get install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu libltdl-dev + python3 -m pip install pyelftools + python3 -m pip install ar + sudo apt-get install qemu-user-static + qemu-riscv64-static --version + sudo mkdir -p /usr/gnemul + sudo ln -s /usr/riscv64-linux-gnu /usr/gnemul/qemu-riscv64 } function ci_unix_qemu_riscv64_build { ci_unix_build_helper "${CI_UNIX_OPTS_QEMU_RISCV64[@]}" ci_unix_build_ffi_lib_helper riscv64-linux-gnu-gcc + ci_native_mpy_modules_build rv64imc } function ci_unix_qemu_riscv64_run_tests { # Issues with RISCV-64 tests: - # - thread/stress_aes.py takes around 140 seconds + # - thread/stress_aes.py takes around 180 seconds # - thread/stress_recurse.py is flaky # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=180 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py') + pushd tests + MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=200 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py' + MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-natmodtests.py extmod/btree*.py extmod/deflate*.py extmod/framebuf*.py extmod/heapq*.py extmod/random_basic*.py extmod/re*.py + popd } function ci_unix_repr_b_build { @@ -1049,6 +1108,14 @@ function _ci_bash_completion { echo "alias ci=\"$(readlink -f "$0")\"; complete -W '$(grep '^function ci_' $0 | awk '{print $2}' | sed 's/^ci_//')' ci" } +function _ci_zsh_completion { + echo "alias ci=\"$(readlink -f "$0"\"); _complete_mpy_ci_zsh() { compadd $(grep '^function ci_' $0 | awk '{sub(/^ci_/,"",$2); print $2}' | tr '\n' ' ') }; autoload -Uz compinit; compinit; compdef _complete_mpy_ci_zsh $(readlink -f "$0")" +} + +function _ci_fish_completion { + echo "alias ci=\"$(readlink -f "$0"\"); complete -c ci -p $(readlink -f "$0") -f -a '$(grep '^function ci_' $(readlink -f "$0") | awk '{sub(/^ci_/,"",$2); print $2}' | tr '\n' ' ')'" +} + function _ci_main { case "$1" in (-h|-?|--help) @@ -1057,6 +1124,12 @@ function _ci_main { (--bash-completion) _ci_bash_completion ;; + (--zsh-completion) + _ci_zsh_completion + ;; + (--fish-completion) + _ci_fish_completion + ;; (-*) echo "Unknown option: $1" 1>&2 exit 1 diff --git a/tools/make_pinout_diagram/README.md b/tools/make_pinout_diagram/README.md new file mode 100644 index 0000000000000..bebd7df7c8c4a --- /dev/null +++ b/tools/make_pinout_diagram/README.md @@ -0,0 +1,43 @@ +# Pinout diagram + +Pinout diagrams can be a helpful tool to display the pin layout for a board. + +Rendering them using ANSI and building them into a board's firmware means they +are always conveniently available, even over a serial connection. + +![WeAct RP2350B Core pinout diagram](weact_pinout.png) + +## Overview + +`pinout.py` generates a unicode pinout diagram that uses ANSI escape characters +to add colour. It currently generates the pinout diagram for the WeActStudio +RP2350B board but is an example that could be extended for any board. + +Display the output by executing the script: + +```bash +python pinout.py +``` + + +## Compression + +`compress.py` uses zlib to _compress input_ and output a _byte string_. + +The output from `pinout.py` can be large but compresses efficiently, so the +intent is that the byte string output from `compress.py` can then be copied to +`../modules/board.py` so that the _compressed_ pinout will be included in the +firmware. + +To execute: + +```bash +python pinout.py | python compress.py +``` + +## Reference + +[Build your own Command Line with ANSI escape +codes](https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html) +provides a good reference of how to use ANSI codes, including helpful colour +lookups. diff --git a/tools/make_pinout_diagram/compress.py b/tools/make_pinout_diagram/compress.py new file mode 100644 index 0000000000000..7e95ab0352775 --- /dev/null +++ b/tools/make_pinout_diagram/compress.py @@ -0,0 +1,10 @@ +import sys +import zlib + +data_str = sys.stdin.read() +compressed = zlib.compress(bytes(data_str, "utf-8"), wbits=10) +print( + f"{len(data_str) / len(compressed):.1f}x smaller: uncompressed={len(data_str)}, compressed={len(compressed)}", + file=sys.stderr, +) +print(compressed) diff --git a/tools/make_pinout_diagram/pinout.py b/tools/make_pinout_diagram/pinout.py new file mode 100644 index 0000000000000..569f40510ccfe --- /dev/null +++ b/tools/make_pinout_diagram/pinout.py @@ -0,0 +1,104 @@ +import re + +pinout_str = """ + \u001b[44;1m WeAct Studio RP2350B Core Board \u001b[0m + + ╭── RESET + Key (GP23) ───╮ │ ╭── BOOT + ╭────────────────────────────────╮ + [26 ] [25 ] │⌾ ⌾ ╭─╮╭─╮╭─╮ ╭─[CLK] ⌾ ⌾│ [24 ] [ 23 ] + [28 ] [27 ] │⌾ ⌾ │⬤││⬤││⬤│ │ ╭─[DIO] ⌾ ⌾│ [22 ] [ 21 ] + [30 ] [29 ] │⌾ ⌾ ╰─╯╰─╯╰─╯[⏚]╮ │ │ ╭─[3V3]⌾ ⌾│ [20 ] [ 19 ] + [32 ] [31 ] │⌾ ⌾ LED ▩ ⌾ ⌾ ⌾ ⌾ ⌾ ⌾│ [18 ] [ 17 ] + [34 ] [33 ] │⌾ ⌾ (GP25) ⟋⟍ ⌾ ⌾│ [16 ] [ 15 ] + [36 ] [35 ] │⌾ ⌾ ⟋ ⟍ ⌾ ⌾│ [14 ] [ 13 ] + [38 ] [37 ] │⌾ ⌾ ⟋ ⟍ ⌾ ⌾│ [12 ] [ 11 ] + [40 ] [39 ] │⌾ ⌾ ⟍ ⟋ ⌾ ⌾│ [10 ] [ 9 ] + [42 ] [41 ] │⌾ ⌾ ⟍ ⟋ ⌾ ⌾│ [ 8 ] [ 7 ] + [44 ] [43 ] │⌾ ⌾ ⟍⟋ ⌾ ⌾│ [ 6 ] [ 5 ] + [46 ] [45 ] │⌾ ⌾ ⌾ ⌾│ [ 4 ] [ 3 ] + [RUN] [47 ] │⌾ ⌾ ⌾ ⌾│ [ 2 ] [ 1 ] + [3V3] [3V3] │⌾ ⌾ ┌──────┐ ⌾ ⌾│ [ 0 ] [VREF] + [ ⏚ ] [EN ] │▣ ⌾ │ │ ▣ ▣│ [ ⏚ ] [ ⏚ ] + [ ⏚ ] [ ⏚ ] │▣ ▣ │ │ ⌾ ⌾│ [5V ] [VBUS] + ╰────────────└──────┘────────────╯ +""" + + +def ansi_colour(wrap_str: str, colours: tuple[int | None, int | None]) -> str: + """Wrap a string in the ANSI foreground and background colour escape sequences.""" + wrapped_str = "" + + wrapped_str += "\u001b[38;5;" + str(colours[0]) + "m" if colours[0] else "" + wrapped_str += "\u001b[48;5;" + str(colours[1]) + "m" if colours[1] else "" + wrapped_str += wrap_str + wrapped_str += "\u001b[0m" if colours[0] or colours[1] else "" + + return wrapped_str + + +def add_colour(pinout_str): + symbol_colours = { + "⌾": (220, None), # Pin (Yellow) + "▣": (220, None), # Ground pin (Yellow) + "↺": (15, None), # Reset (White) + "▩": (129, None), # LED (Purple) + } + + for symbol, colours in symbol_colours.items(): + pinout_str = pinout_str.replace(symbol, ansi_colour(symbol, colours)) + return pinout_str + + +def colour_tags(matchobj: re.Match) -> str: + white_on_red = (15, 1) + white_on_peach = (15, 216) + white_on_dark_green = (15, 28) + white_on_black = (15, 16) + black_on_pink = (16, 224) + + tag_colours = { + "5V": white_on_red, + "VBUS": white_on_red, + "VREF": white_on_dark_green, + "3V3": white_on_red, + "⏚": white_on_black, + "EN": black_on_pink, + "CLK": white_on_peach, + "DIO": white_on_peach, + } + + if matchobj.group(2) not in tag_colours.keys(): + return matchobj.group(0) + + pin_colours = tag_colours[matchobj.group(2)] + + return ansi_colour(matchobj.group(1), pin_colours) + + +def replace_tags(pinout_str): + return re.sub(r"(\[\s*(\S+)\s*\])", colour_tags, pinout_str) + + +def colour_pins(matchobj: re.Match) -> str: + # Regular GPIO is green, ADC pins (40-47) are darker greeen + gpio_colours = (15, 34) # White on green + adc_colours = (15, 28) # White on dark green + pin_number = int(matchobj.group(2)) + + pin_colours = gpio_colours if pin_number < 40 else adc_colours + + return ansi_colour(matchobj.group(1), pin_colours) + + +def replace_gpio(pinout_str) -> str: + return re.sub(r"(\[\s*(\d+)\s*\])", colour_pins, pinout_str) + + +pinout_str = replace_gpio(replace_tags(add_colour(pinout_str))) +# Colours include a square bracket; temporarily change them! +pinout_str = pinout_str.replace("\u001b[", "~") +pinout_str = pinout_str.replace("[", " ").replace("]", " ") +pinout_str = pinout_str.replace("~", "\u001b[") # Put them back + +print(pinout_str) diff --git a/tools/make_pinout_diagram/weact_pinout.png b/tools/make_pinout_diagram/weact_pinout.png new file mode 100644 index 0000000000000..35240ed9e16d0 Binary files /dev/null and b/tools/make_pinout_diagram/weact_pinout.png differ diff --git a/tools/mpremote/mpremote/mip.py b/tools/mpremote/mpremote/mip.py index fa7974053f44d..0d12ae651ecca 100644 --- a/tools/mpremote/mpremote/mip.py +++ b/tools/mpremote/mpremote/mip.py @@ -1,4 +1,4 @@ -# Micropython package installer +# MicroPython package installer # Ported from micropython-lib/micropython/mip/mip.py. # MIT license; Copyright (c) 2022 Jim Mussared diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index af8450a842432..02d2431c4ee1c 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -38,6 +38,7 @@ # MicroPython constants MPY_VERSION = 6 MPY_SUB_VERSION = 3 +MPY_ARCH_FLAGS = 0x40 MP_CODE_BYTECODE = 2 MP_CODE_NATIVE_VIPER = 4 MP_NATIVE_ARCH_X86 = 1 @@ -49,6 +50,7 @@ MP_NATIVE_ARCH_XTENSA = 9 MP_NATIVE_ARCH_XTENSAWIN = 10 MP_NATIVE_ARCH_RV32IMC = 11 +MP_NATIVE_ARCH_RV64IMC = 12 MP_PERSISTENT_OBJ_STR = 5 MP_SCOPE_FLAG_VIPERRELOC = 0x10 MP_SCOPE_FLAG_VIPERRODATA = 0x20 @@ -62,6 +64,7 @@ R_X86_64_64 = 1 R_XTENSA_32 = 1 R_386_PC32 = 2 +R_RISCV_64 = 2 R_X86_64_PC32 = 2 R_ARM_ABS32 = 2 R_386_GOT32 = 3 @@ -121,7 +124,7 @@ R_RISCV_SET_ULEB128 = 60 R_RISCV_SUB_ULEB128 = 61 R_RISCV_TLSDESC_HI20 = 62 -R_RISCC_TLSDESC_LOAD_LO12 = 63 +R_RISCV_TLSDESC_LOAD_LO12 = 63 R_RISCV_TLSDESC_ADD_LO12 = 64 R_RISCV_TLSDESC_CALL = 65 @@ -129,66 +132,93 @@ # Architecture configuration +def fit_signed(bits, value): + return (value >> bits) == 0 or (value >> bits) == -1 + + +# Note: all trampoline jump function arguments are raw offsets calculated from +# the start of the text segment with no relocation applied beforehand. + + def asm_jump_x86(entry): - return struct.pack("> 11 == 0 or b_off >> 11 == -1: + if fit_signed(11, entry): # Signed value fits in 12 bits. - b0 = 0xE000 | (b_off >> 1 & 0x07FF) - b1 = 0 - b2 = 0 - b3 = 0 + b0 = 0xE000 | ((entry >> 1) & 0x07FF) + return struct.pack(" # pop {r0, pc} - b_off -= 2 # skip "push {r0, lr}" + entry += 2 # skip "push {r0, lr}" b0 = 0xB400 | 0x0100 | 0x0001 # push, lr, r0 - b1 = 0xF000 | (((b_off) >> 12) & 0x07FF) - b2 = 0xF800 | (((b_off) >> 1) & 0x07FF) + b1 = 0xF000 | ((entry >> 12) & 0x07FF) + b2 = 0xF800 | ((entry >> 1) & 0x07FF) b3 = 0xBC00 | 0x0100 | 0x0001 # pop, pc, r0 - return struct.pack("> 11 == 0 or b_off >> 11 == -1: + if fit_signed(11, entry): # Signed value fits in 12 bits - b0 = 0xE000 | (b_off >> 1 & 0x07FF) - b1 = 0 + b0 = 0xE000 | ((entry >> 1) & 0x07FF) + return struct.pack("> 12 & 0x07FF) - b1 = 0xB800 | (b_off >> 1 & 0x7FF) - return struct.pack("> 12) & 0x07FF) + b1 = 0xB800 | ((entry >> 1) & 0x07FF) + return struct.pack("> 8) - + if fit_signed(17, entry): + jump_op = (entry - 4) << 6 | 6 + return struct.pack("> 8) + else: + raise LinkError("Large jumps are not yet supported on Xtensa") -def asm_jump_rv32(entry): - # This could be 6 bytes shorter, but the code currently cannot - # support a trampoline with varying length depending on the offset. - # auipc t6, HI(entry) - # jalr zero, t6, LO(entry) - upper, lower = split_riscv_address(entry) - return struct.pack( - "> 2) + | ((entry & 0x80) >> 1) + | ((entry & 0x40) << 1) + | ((entry & 0x20) >> 3) + | ((entry & 0x10) << 7), + ) + else: + # auipc t6, HI(entry) + # jalr zero, t6, LO(entry) + upper, lower = split_riscv_address(entry + 8) + return struct.pack( + " 2) or args.arch_flags.isdigit(): + if args.arch_flags[1] in "bB": + base = 2 + elif args.arch_flags[1] in "xX": + base = 16 + else: + base = 10 + args.arch_flags = int(args.arch_flags, base) + else: + flags_value = 0 + for flag in args.arch_flags.lower().split(","): + if flag not in RV32_EXTENSIONS: + raise ValueError('Invalid architecture flags value "{}"'.format(flag)) + flags_value |= RV32_EXTENSIONS[flag] + args.arch_flags = flags_value + + def main(): import argparse @@ -1560,6 +1645,7 @@ def main(): "--verbose", "-v", action="count", default=1, help="increase verbosity" ) cmd_parser.add_argument("--arch", default="x64", help="architecture") + cmd_parser.add_argument("--arch-flags", default=None, help="optional architecture flags") cmd_parser.add_argument("--preprocess", action="store_true", help="preprocess source files") cmd_parser.add_argument("--qstrs", default=None, help="file defining additional qstrs") cmd_parser.add_argument( @@ -1581,6 +1667,8 @@ def main(): global log_level log_level = args.verbose + validate_arch_flags(args) + if args.preprocess: do_preprocess(args) else: