From 1ab8176e1dcfb8eccead10927b65f914a237bfa2 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 27 May 2025 17:04:03 +0200 Subject: [PATCH 01/78] mpconfig: Use RUN_BACKGROUND_TASKS as the micropython event hook This is a newer abstraction in micropython; it'll for instance allow background tasks to be checked once per ms in the internal select module modselect. Because `MICROPY_INTERNAL_EVENT_HOOK` is used in a few locations, our own CIRCUITPY-CHANGE call to `RUN_BACKGROUND_TASKS` can be nixed. Specifically, `mp_event_handle_nowait` calls `MICROPY_INTERNAL_EVENT_HOOK` so paths from it don't need `RUN_BACKGROUND_TASKS` anymore. --- py/circuitpy_mpconfig.h | 1 + py/scheduler.c | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index d6658867b7d1d..73d6d682e8c5b 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -452,6 +452,7 @@ void background_callback_run_all(void); #define MICROPY_VM_HOOK_LOOP RUN_BACKGROUND_TASKS; #define MICROPY_VM_HOOK_RETURN RUN_BACKGROUND_TASKS; +#define MICROPY_INTERNAL_EVENT_HOOK (RUN_BACKGROUND_TASKS) // CIRCUITPY_AUTORELOAD_DELAY_MS = 0 will completely disable autoreload. #ifndef CIRCUITPY_AUTORELOAD_DELAY_MS diff --git a/py/scheduler.c b/py/scheduler.c index 91ef7e63b38f1..99952d28aca61 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -271,10 +271,6 @@ void mp_event_wait_indefinite(void) { MICROPY_EVENT_POLL_HOOK #else mp_event_handle_nowait(); - - // CIRCUITPY-CHANGE: don't starve CircuitPython background tasks - RUN_BACKGROUND_TASKS; - MICROPY_INTERNAL_WFE(-1); #endif } @@ -287,10 +283,6 @@ void mp_event_wait_ms(mp_uint_t timeout_ms) { MICROPY_EVENT_POLL_HOOK #else mp_event_handle_nowait(); - - // CIRCUITPY-CHANGE: don't starve CircuitPython background tasks - RUN_BACKGROUND_TASKS; - MICROPY_INTERNAL_WFE(timeout_ms); #endif } From 96636cfd85c1c710d868e8b63d056303fe5e7abf Mon Sep 17 00:00:00 2001 From: eightycc Date: Wed, 4 Jun 2025 13:24:04 -0700 Subject: [PATCH 02/78] Fix typo in https address of cortex toolchain. --- .devcontainer/cortex-m-toolchain.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/cortex-m-toolchain.sh b/.devcontainer/cortex-m-toolchain.sh index 782b472fec2e2..38ecdb72a7b96 100755 --- a/.devcontainer/cortex-m-toolchain.sh +++ b/.devcontainer/cortex-m-toolchain.sh @@ -14,7 +14,7 @@ echo -e "[cortex-m-toolchain.sh] downloading and installing gcc-arm-non-eabi too cd /workspaces wget -qO gcc-arm-none-eabi.tar.xz \ - https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz + https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz tar -xJf gcc-arm-none-eabi.tar.xz ln -s arm-gnu-toolchain-14.2.Rel1-x86_64-arm-none-eabi gcc-arm-none-eabi From 313f826e0cebf4bcaa03bf90b21d2bb6d20d4ffb Mon Sep 17 00:00:00 2001 From: eightycc Date: Wed, 4 Jun 2025 13:25:22 -0700 Subject: [PATCH 03/78] atmel-samd: Release SERCOM with I2C deinit. --- ports/atmel-samd/common-hal/busio/I2C.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index e13b5410ae32a..da108709feaff 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -135,6 +135,7 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { if (common_hal_busio_i2c_deinited(self)) { return; } + allow_reset_sercom(self->i2c_desc.device.hw); i2c_m_sync_disable(&self->i2c_desc); i2c_m_sync_deinit(&self->i2c_desc); From c097441cb8fce14a9b44c1b00525d36d02b0bedd Mon Sep 17 00:00:00 2001 From: CDarius Date: Fri, 8 Aug 2025 16:59:49 +0200 Subject: [PATCH 04/78] Refactor/fix M5Bus pins definitions --- ports/espressif/boards/m5stack_cores3/pins.c | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/ports/espressif/boards/m5stack_cores3/pins.c b/ports/espressif/boards/m5stack_cores3/pins.c index 2ebb225277ded..223a6932c4c05 100644 --- a/ports/espressif/boards/m5stack_cores3/pins.c +++ b/ports/espressif/boards/m5stack_cores3/pins.c @@ -28,7 +28,7 @@ CIRCUITPY_BOARD_BUS_SINGLETON(porta_i2c, i2c, 1) static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - // M5 Bus (except I2S & PORT B) + // M5 Bus (except I2S) { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, @@ -36,33 +36,37 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_PORTC_RX), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_A18), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO12) }, - { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, { MP_ROM_QSTR(MP_QSTR_PORTA_SDA), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO6) }, - { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_PORTB_IN), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_PORTB_OUT), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, { MP_ROM_QSTR(MP_QSTR_D43), MP_ROM_PTR(&pin_GPIO43) }, { MP_ROM_QSTR(MP_QSTR_PORTC_TX), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_A17), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO11) }, { MP_ROM_QSTR(MP_QSTR_PORTA_SCL), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO7) }, - // Port B - { MP_ROM_QSTR(MP_QSTR_PORTB_IN), MP_ROM_PTR(&pin_GPIO8) }, - { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, - { MP_ROM_QSTR(MP_QSTR_PORTB_OUT), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, - // I2S { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_ROM_PTR(&pin_GPIO34) }, { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_ROM_PTR(&pin_GPIO33) }, - { MP_ROM_QSTR(MP_QSTR_IS2_DATA), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IS2_DATA_OUT), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IS2_DATA_IN), MP_ROM_PTR(&pin_GPIO14) }, { MP_ROM_QSTR(MP_QSTR_IS2_MASTER_CLOCK), MP_ROM_PTR(&pin_GPIO0) }, // Camera From c3e38623758cf53f2755d7011a285da15c5c4c09 Mon Sep 17 00:00:00 2001 From: CDarius Date: Tue, 12 Aug 2025 12:06:00 +0200 Subject: [PATCH 05/78] Fixed I2S spelling and separated pin aliases --- ports/espressif/boards/m5stack_cores3/pins.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/ports/espressif/boards/m5stack_cores3/pins.c b/ports/espressif/boards/m5stack_cores3/pins.c index 223a6932c4c05..8b40d9e84842a 100644 --- a/ports/espressif/boards/m5stack_cores3/pins.c +++ b/ports/espressif/boards/m5stack_cores3/pins.c @@ -32,42 +32,55 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_PORTC_RX), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_A18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_SDA), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_PORTB_IN), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_PORTB_OUT), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, { MP_ROM_QSTR(MP_QSTR_D43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_PORTC_TX), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_A17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_SCL), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO7) }, // I2S { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_ROM_PTR(&pin_GPIO34) }, { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_ROM_PTR(&pin_GPIO33) }, - { MP_ROM_QSTR(MP_QSTR_IS2_DATA_OUT), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_IS2_DATA_IN), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_IS2_MASTER_CLOCK), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DATA_OUT), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DATA_IN), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MASTER_CLOCK), MP_ROM_PTR(&pin_GPIO0) }, // Camera { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA), MP_ROM_PTR(&camera_data_tuple) }, From c74929a3d4576b29f4269a4bc448263833693336 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 29 Aug 2025 09:48:33 -0500 Subject: [PATCH 06/78] moving cron workflows from adabot repo --- .github/workflows/bundle_cron.yml | 58 +++++++++++++++++++ .github/workflows/learn_cron.yml | 41 ++++++++++++++ .github/workflows/reports_cron.yml | 91 ++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 .github/workflows/bundle_cron.yml create mode 100644 .github/workflows/learn_cron.yml create mode 100644 .github/workflows/reports_cron.yml diff --git a/.github/workflows/bundle_cron.yml b/.github/workflows/bundle_cron.yml new file mode 100644 index 0000000000000..cf1d51a3aa8fb --- /dev/null +++ b/.github/workflows/bundle_cron.yml @@ -0,0 +1,58 @@ +# SPDX-FileCopyrightText: 2019 Michael Schroeder +# +# SPDX-License-Identifier: MIT + +name: Update Bundles + +on: + schedule: + - cron: 0 5 * * * + workflow_dispatch: + +jobs: + check-repo-owner: + # This job is so the entire workflow will end successfully and give some + # output to explain why it hasn't run on a non-Adafruit fork. + runs-on: ubuntu-latest + steps: + - name: repository + env: + OWNER_IS_ADAFRUIT: ${{ startswith(github.repository, 'adafruit/') }} + run: | + echo "This workflow will only run if Adafruit is the repository owner." + echo "Repository owner is Adafruit: $OWNER_IS_ADAFRUIT" + update-bundles: + runs-on: ubuntu-latest + # Only run the build on Adafruit's repository. Forks won't have the secrets. + # Its necessary to do this here, since 'schedule' events cannot (currently) + # be limited (they run on all forks' default branches). + if: startswith(github.repository, 'adafruit/') + steps: + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: 3.12 + - name: Load contributor cache + uses: actions/cache@v4 + with: + key: "contributor-cache" + path: "contributors.json" + - name: Versions + run: | + python3 --version + - uses: actions/checkout@v4 + with: + repository: 'adafruit/adabot' + submodules: true + - name: Install deps + run: | + pip install -r requirements.txt + - name: Run adabot.circuitpython_bundle + env: + ADABOT_EMAIL: ${{ secrets.ADABOT_EMAIL }} + ADABOT_GITHUB_USER: ${{ secrets.ADABOT_GITHUB_USER }} + ADABOT_GITHUB_ACCESS_TOKEN: ${{ secrets.ADABOT_GITHUB_ACCESS_TOKEN }} + BIGQUERY_PRIVATE_KEY: ${{ secrets.BIGQUERY_PRIVATE_KEY }} + BIGQUERY_CLIENT_EMAIL: ${{ secrets.BIGQUERY_CLIENT_EMAIL }} + run: | + python3 -u -m adabot.circuitpython_bundle diff --git a/.github/workflows/learn_cron.yml b/.github/workflows/learn_cron.yml new file mode 100644 index 0000000000000..540b95a63b5f3 --- /dev/null +++ b/.github/workflows/learn_cron.yml @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: 2021 Jeff Epler for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: Tag Learning System Guides + +on: + schedule: + - cron: 0 5 * * * + +jobs: + check-repo-owner: + # This job is so the entire workflow will end successfully and give some + # output to explain why it hasn't run on a non-Adafruit fork. + runs-on: ubuntu-latest + if: ${{ (github.repository_owner != 'adafruit') }} + steps: + - run: | + echo "This workflow is only intended to run in the adafruit fork" + + update-learn: + runs-on: ubuntu-latest + # Only run the build if the access token has been configured. THs will be + # the case on Adafruit's repository. Its necessary to do this here, since + # 'schedule' events cannot (currently) be limited (they run on all forks' + # default branches). + if: ${{ (github.repository_owner == 'adafruit') }} + steps: + - uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/Adafruit_Learning_System_Guides + token: ${{ secrets.ADABOT_GITHUB_ACCESS_TOKEN }} + - name: Tag a release + env: + ADABOT_EMAIL: ${{ secrets.ADABOT_EMAIL }} + run: | + git config --global user.name adabot + git config --global user.email "$ADABOT_EMAIL" + TAG_NAME=`date +%Y%m%d` + git tag $TAG_NAME + git push origin $TAG_NAME diff --git a/.github/workflows/reports_cron.yml b/.github/workflows/reports_cron.yml new file mode 100644 index 0000000000000..652e0379fd2ca --- /dev/null +++ b/.github/workflows/reports_cron.yml @@ -0,0 +1,91 @@ +# SPDX-FileCopyrightText: 2019 Michael Schroeder +# +# SPDX-License-Identifier: MIT + +name: Run Daily Reports + +on: + schedule: + # The actor (github.actor) that runs the cron job may be the user who created the cron job + # initially. It does not appear to be settable via a secret or environment variable. + - cron: 15 5 * * * + workflow_dispatch: + + +jobs: + check-repo-owner: + # This job is so the entire workflow will end successfully and give some + # output to explain why it hasn't run on a non-Adafruit fork. + runs-on: ubuntu-latest + steps: + - name: repository + env: + OWNER_IS_ADAFRUIT: ${{ startswith(github.repository, 'adafruit/') }} + run: | + echo "This workflow will only run if Adafruit is the repository owner." + echo "Repository owner is Adafruit: $OWNER_IS_ADAFRUIT" + run-reports: + runs-on: ubuntu-latest + # Only run the build on Adafruit's repository. Forks won't have the secrets. + # Its necessary to do this here, since 'schedule' events cannot (currently) + # be limited (they run on all forks' default branches). + if: startswith(github.repository, 'adafruit/') + env: + ADABOT_GITHUB_USER: ${{ secrets.ADABOT_GITHUB_USER }} + ADABOT_GITHUB_ACCESS_TOKEN: ${{ secrets.ADABOT_GITHUB_ACCESS_TOKEN }} + RTD_TOKEN: ${{ secrets.RTD_TOKEN }} + BIGQUERY_PRIVATE_KEY: ${{ secrets.BIGQUERY_PRIVATE_KEY }} + BIGQUERY_CLIENT_EMAIL: ${{ secrets.BIGQUERY_CLIENT_EMAIL }} + steps: + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: Versions + run: | + python3 --version + - uses: actions/checkout@v4 + with: + repository: 'adafruit/adabot' + submodules: true + - name: Install deps + run: | + pip install -r requirements.txt + - name: Make Directory For Report Files + run: mkdir -p bin/adabot + - name: Set Date Variable + id: today + run: | + echo date=$( + date +%Y%m%d + ) >> $GITHUB_OUTPUT + - name: Run adabot.circuitpython_libraries + env: + # LIB_CHECK_CP_FILE is for circuitpython_libraries.py output + LIB_CHECK_CP_FILE: bin/adabot/circuitpython_library_report_${{ steps.today.outputs.date }}.txt + run: | + python3 -u -m adabot.circuitpython_libraries -o $LIB_CHECK_CP_FILE + continue-on-error: true + - name: Run adabot.circuitpython_library_download_stats + env: + # LIB_DL_STATS_FILE is for future Bundle and PyPi download stats script + LIB_DL_STATS_FILE: bin/adabot/library_download_stats_${{ steps.today.outputs.date }}.txt + run: | + python3 -u -m adabot.circuitpython_library_download_stats -o $LIB_DL_STATS_FILE + continue-on-error: true + - name: Run adabot.arduino_libraries + env: + # LIB_CHECK_ARD_FILE is for arduino_libraries.py output + LIB_CHECK_ARD_FILE: bin/adabot/arduino_library_report_${{ steps.today.outputs.date }}.txt + run: | + python3 -u -m adabot.arduino_libraries -o $LIB_CHECK_ARD_FILE + continue-on-error: true + - name: Check For Files + run: | + ls bin/adabot + - name: Upload Reports To AWS S3 + if: ${{ github.event_name != 'workflow_dispatch' }} + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: "[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp bin/adabot/ s3://adafruit-circuit-python/adabot/bin/reports/ --recursive --no-progress --region us-east-1" From 92a87a4c834e992d021ef8d445cb512d63eb51a8 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 29 Aug 2025 09:55:55 -0500 Subject: [PATCH 07/78] spelling fixes --- .github/workflows/bundle_cron.yml | 2 +- .github/workflows/learn_cron.yml | 4 ++-- .github/workflows/reports_cron.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/bundle_cron.yml b/.github/workflows/bundle_cron.yml index cf1d51a3aa8fb..606707d4102f1 100644 --- a/.github/workflows/bundle_cron.yml +++ b/.github/workflows/bundle_cron.yml @@ -24,7 +24,7 @@ jobs: update-bundles: runs-on: ubuntu-latest # Only run the build on Adafruit's repository. Forks won't have the secrets. - # Its necessary to do this here, since 'schedule' events cannot (currently) + # It's necessary to do this here, since 'schedule' events cannot (currently) # be limited (they run on all forks' default branches). if: startswith(github.repository, 'adafruit/') steps: diff --git a/.github/workflows/learn_cron.yml b/.github/workflows/learn_cron.yml index 540b95a63b5f3..6100e6637c20e 100644 --- a/.github/workflows/learn_cron.yml +++ b/.github/workflows/learn_cron.yml @@ -20,8 +20,8 @@ jobs: update-learn: runs-on: ubuntu-latest - # Only run the build if the access token has been configured. THs will be - # the case on Adafruit's repository. Its necessary to do this here, since + # Only run the build if the access token has been configured. This will be + # the case on Adafruit's repository. It's necessary to do this here, since # 'schedule' events cannot (currently) be limited (they run on all forks' # default branches). if: ${{ (github.repository_owner == 'adafruit') }} diff --git a/.github/workflows/reports_cron.yml b/.github/workflows/reports_cron.yml index 652e0379fd2ca..b4e9a43024e27 100644 --- a/.github/workflows/reports_cron.yml +++ b/.github/workflows/reports_cron.yml @@ -27,7 +27,7 @@ jobs: run-reports: runs-on: ubuntu-latest # Only run the build on Adafruit's repository. Forks won't have the secrets. - # Its necessary to do this here, since 'schedule' events cannot (currently) + # It's necessary to do this here, since 'schedule' events cannot (currently) # be limited (they run on all forks' default branches). if: startswith(github.repository, 'adafruit/') env: From dd44278f778ee1c714f31fe8b9e7aff3a9dc6b5b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 29 Aug 2025 12:37:39 -0400 Subject: [PATCH 08/78] update frozen libraries --- frozen/Adafruit_CircuitPython_DotStar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frozen/Adafruit_CircuitPython_DotStar b/frozen/Adafruit_CircuitPython_DotStar index 163f2f166aee1..4b0ba649e5abd 160000 --- a/frozen/Adafruit_CircuitPython_DotStar +++ b/frozen/Adafruit_CircuitPython_DotStar @@ -1 +1 @@ -Subproject commit 163f2f166aee11d82303492bb1e5af4937e57b62 +Subproject commit 4b0ba649e5abdebead5b9a47a6c695d67c2c25fa From 91f6426c0f2ee5bae3a379a49ea29d3c8be1ce07 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 29 Aug 2025 10:06:06 -0700 Subject: [PATCH 09/78] Fix DVI blanking during SPI transactions SPI was using DMA to transfer to PSRAM. When a cache miss occurs, the DMA can't switch to another transfer and throws off DVI timing. So, only use DMA with SPI when the buffers are in SRAM. This will slow down SPI transactions when the FIFOs are empty and the CPU is busy running a background task. It will still be correct though since we control the SPI clock. Fixes #10557 --- ports/raspberrypi/common-hal/busio/SPI.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/common-hal/busio/SPI.c b/ports/raspberrypi/common-hal/busio/SPI.c index d20bc4d7d10aa..4735d1284f98e 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.c +++ b/ports/raspberrypi/common-hal/busio/SPI.c @@ -182,7 +182,10 @@ static bool _transfer(busio_spi_obj_t *self, chan_tx = dma_claim_unused_channel(false); chan_rx = dma_claim_unused_channel(false); } - bool use_dma = chan_rx >= 0 && chan_tx >= 0; + bool has_dma_channels = chan_rx >= 0 && chan_tx >= 0; + // Only use DMA if both data buffers are in SRAM. Otherwise, we'll stall the DMA with PSRAM or flash cache misses. + bool data_in_sram = data_in >= (uint8_t *)SRAM_BASE && data_out >= (uint8_t *)SRAM_BASE; + bool use_dma = has_dma_channels && data_in_sram; if (use_dma) { dma_channel_config c = dma_channel_get_default_config(chan_tx); channel_config_set_transfer_data_size(&c, DMA_SIZE_8); From 7fd8b4835789f4a9b2d6bb60b55eac445b9f744f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 29 Aug 2025 11:00:43 -0700 Subject: [PATCH 10/78] Fix lvfontio memory allocation with fixed width fonts There was a branch of the loading that failed to set max_slots. This led to unpredicatable allocation failures. Fixes #10560 --- shared-module/lvfontio/OnDiskFont.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-module/lvfontio/OnDiskFont.c b/shared-module/lvfontio/OnDiskFont.c index 0cf65301d2270..368bd381475b1 100644 --- a/shared-module/lvfontio/OnDiskFont.c +++ b/shared-module/lvfontio/OnDiskFont.c @@ -253,9 +253,10 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max *max_slots = advance_count[1] * 2 + advance_count[0]; } } + } else { + *max_slots = advance_count[0] + advance_count[1]; } - found_glyf = true; } From 059b0e712aa3b496d747187f9b4d7e7a35495afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brad=C3=A1n=20Lane?= Date: Fri, 29 Aug 2025 14:28:39 -0400 Subject: [PATCH 11/78] force neopixel_write into build --- .../atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk b/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk index 33165c8cfc5d0..11f090ed76305 100644 --- a/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk @@ -38,7 +38,7 @@ CIRCUITPY_ROTARYIO = 0 CIRCUITPY_RTC = 0 CIRCUITPY_USB_HID = 1 CIRCUITPY_USB_MIDI = 0 - +CIRCUITPY_NEOPIXEL_WRITE = 1 # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HID From 81afa660785ceb18a501b059cb3f0133d97e4db7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 29 Aug 2025 11:56:36 -0700 Subject: [PATCH 12/78] Fix display glitch during neopixel update The DMA can get stalled by DMA to/from PSRAM. So, copy the data into SRAM when we need to. Fail if we can't. Fixes #10564 --- .../common-hal/rp2pio/StateMachine.c | 90 +++++++++++++++---- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index fefecf05ff715..74b9a7f0c31b0 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -853,25 +853,64 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, // This implementation is based on SPI but varies because the tx and rx buffers // may be different lengths and occur at different times or speeds. - // Use DMA for large transfers if channels are available. - // Don't exceed FIFO size. - const size_t dma_min_size_threshold = self->fifo_depth; int chan_tx = -1; int chan_rx = -1; size_t len = MAX(out_len, in_len); bool tx = data_out != NULL; bool rx = data_in != NULL; - bool use_dma = len >= dma_min_size_threshold || swap_out || swap_in; + bool free_data_out = false; + bool free_data_in = false; + uint8_t *sram_data_out = (uint8_t *)data_out; + uint8_t *sram_data_in = data_in; + bool tx_fits_in_fifo = (out_len / out_stride_in_bytes) <= self->fifo_depth; + bool rx_fits_in_fifo = (in_len / in_stride_in_bytes) <= self->fifo_depth; + bool use_dma = !(tx_fits_in_fifo && rx_fits_in_fifo) || swap_out || swap_in; + if (use_dma) { - // Use DMA channels to service the two FIFOs + // We can only reliably use DMA for SRAM buffers. So, if we're given PSRAM buffers, + // then copy them to SRAM first. If we can't, then fail. + // Use DMA channels to service the two FIFOs. Fail if we can't allocate DMA channels. if (tx) { + if (data_out < (uint8_t *)SRAM_BASE) { + // Try to allocate a temporary buffer for DMA transfer + uint8_t *temp_buffer = (uint8_t *)port_malloc(len, true); + if (temp_buffer == NULL) { + mp_printf(&mp_plat_print, "Failed to allocate temporary buffer for DMA tx\n"); + return false; + } + memcpy(temp_buffer, data_out, len); + sram_data_out = temp_buffer; + free_data_out = true; + } chan_tx = dma_claim_unused_channel(false); // DMA allocation failed... if (chan_tx < 0) { + if (free_data_out) { + port_free(sram_data_out); + } + if (free_data_in) { + port_free(sram_data_in); + } return false; } } if (rx) { + if (data_in < (uint8_t *)SRAM_BASE) { + // Try to allocate a temporary buffer for DMA transfer + uint8_t *temp_buffer = (uint8_t *)port_malloc(len, true); + if (temp_buffer == NULL) { + mp_printf(&mp_plat_print, "Failed to allocate temporary buffer for DMA rx\n"); + if (chan_tx >= 0) { + dma_channel_unclaim(chan_tx); + } + if (free_data_out) { + port_free(sram_data_out); + } + return false; + } + sram_data_in = temp_buffer; + free_data_in = true; + } chan_rx = dma_claim_unused_channel(false); // DMA allocation failed... if (chan_rx < 0) { @@ -879,6 +918,12 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, if (chan_tx >= 0) { dma_channel_unclaim(chan_tx); } + if (free_data_out) { + port_free(sram_data_out); + } + if (free_data_in) { + port_free(sram_data_in); + } return false; } } @@ -910,7 +955,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, channel_config_set_bswap(&c, swap_out); dma_channel_configure(chan_tx, &c, tx_destination, - data_out, + sram_data_out, out_len / out_stride_in_bytes, false); channel_mask |= 1u << chan_tx; @@ -923,7 +968,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, channel_config_set_write_increment(&c, true); channel_config_set_bswap(&c, swap_in); dma_channel_configure(chan_rx, &c, - data_in, + sram_data_in, rx_source, in_len / in_stride_in_bytes, false); @@ -950,8 +995,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, self->pio->fdebug = stall_mask; } - // If we have claimed only one channel successfully, we should release immediately. This also - // releases the DMA after use_dma has been done. + // Release the DMA channels after use_dma has been done. if (chan_rx >= 0) { dma_channel_unclaim(chan_rx); } @@ -960,31 +1004,31 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, } if (!use_dma && !(self->user_interruptible && mp_hal_is_interrupted())) { - // Use software for small transfers, or if couldn't claim two DMA channels + // Use software for small transfers size_t rx_remaining = in_len / in_stride_in_bytes; size_t tx_remaining = out_len / out_stride_in_bytes; while (rx_remaining || tx_remaining) { while (tx_remaining && !pio_sm_is_tx_fifo_full(self->pio, self->state_machine)) { if (out_stride_in_bytes == 1) { - *tx_destination = *data_out; + *tx_destination = *sram_data_out; } else if (out_stride_in_bytes == 2) { - *((uint16_t *)tx_destination) = *((uint16_t *)data_out); + *((uint16_t *)tx_destination) = *((uint16_t *)sram_data_out); } else if (out_stride_in_bytes == 4) { - *((uint32_t *)tx_destination) = *((uint32_t *)data_out); + *((uint32_t *)tx_destination) = *((uint32_t *)sram_data_out); } - data_out += out_stride_in_bytes; + sram_data_out += out_stride_in_bytes; --tx_remaining; } while (rx_remaining && !pio_sm_is_rx_fifo_empty(self->pio, self->state_machine)) { if (in_stride_in_bytes == 1) { - *data_in = (uint8_t)*rx_source; + *sram_data_in = (uint8_t)*rx_source; } else if (in_stride_in_bytes == 2) { - *((uint16_t *)data_in) = *((uint16_t *)rx_source); + *((uint16_t *)sram_data_in) = *((uint16_t *)rx_source); } else if (in_stride_in_bytes == 4) { - *((uint32_t *)data_in) = *((uint32_t *)rx_source); + *((uint32_t *)sram_data_in) = *((uint32_t *)rx_source); } - data_in += in_stride_in_bytes; + sram_data_in += in_stride_in_bytes; --rx_remaining; } RUN_BACKGROUND_TASKS; @@ -996,7 +1040,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, self->pio->fdebug = stall_mask; } // Wait for the state machine to finish transmitting the data we've queued - // up. + // up (either from the CPU or via DMA.) if (tx) { while (!pio_sm_is_tx_fifo_empty(self->pio, self->state_machine) || (self->wait_for_txstall && (self->pio->fdebug & stall_mask) == 0)) { @@ -1006,6 +1050,14 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, } } } + if (free_data_out) { + port_free(sram_data_out); + } + if (free_data_in) { + // Copy the data from the SRAM buffer to the user PSRAM buffer. + memcpy(data_in, sram_data_in, len); + port_free(sram_data_in); + } return true; } From 4b2624a27baabe499efb5b46805cdd82599f2f58 Mon Sep 17 00:00:00 2001 From: bradanlane Date: Fri, 29 Aug 2025 16:35:32 -0400 Subject: [PATCH 13/78] Enable CIRCUITPY_PIXELBUF in mpconfigboard.mk --- .../atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk b/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk index 11f090ed76305..894037ec0148a 100644 --- a/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk @@ -39,6 +39,7 @@ CIRCUITPY_RTC = 0 CIRCUITPY_USB_HID = 1 CIRCUITPY_USB_MIDI = 0 CIRCUITPY_NEOPIXEL_WRITE = 1 +CIRCUITPY_PIXELBUF = 1 # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HID From 3c44c9d908952305349bb79ce032249a4e505835 Mon Sep 17 00:00:00 2001 From: bradanlane Date: Fri, 29 Aug 2025 17:41:57 -0400 Subject: [PATCH 14/78] Update mpconfigboard.mk to incorporate limited changes suggested by halbert. --- .../boards/bradanlanestudio_coin_m0/mpconfigboard.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk b/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk index 894037ec0148a..9a2cdcd668ed2 100644 --- a/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk @@ -18,7 +18,7 @@ CHIP_FAMILY = samd21 SPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" -LONGINT_IMPL = NONE +LONGINT_IMPL = MPZ # the M0 Coin has limited functionality and many modules can be eliminated @@ -26,7 +26,7 @@ LONGINT_IMPL = NONE # Disable modules that are unusable on this special-purpose board. -CIRCUITPY_FULL_BUILD = 0 +CIRCUITPY_FULL_BUILD = 1 CIRCUITPY_AUDIOIO = 1 CIRCUITPY_DISPLAYIO = 0 From a4a383630267c8fecf216900aec4b1e8b4f00642 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Sun, 31 Aug 2025 00:09:32 -0500 Subject: [PATCH 15/78] Fix radio union types --- shared-bindings/wifi/Radio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index a267dea11c1ff..9a7d445fd0473 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -99,7 +99,7 @@ MP_PROPERTY_GETSET(wifi_radio_enabled_obj, (mp_obj_t)&wifi_radio_get_enabled_obj, (mp_obj_t)&wifi_radio_set_enabled_obj); -//| hostname: Union[str | ReadableBuffer] +//| hostname: Union[str, ReadableBuffer] //| """Hostname for wifi interface. When the hostname is altered after interface started/connected //| the changes would only be reflected once the interface restarts/reconnects.""" static mp_obj_t wifi_radio_get_hostname(mp_obj_t self_in) { @@ -325,8 +325,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_station_obj, wifi_radio_stop_station); //| def start_ap( //| self, -//| ssid: Union[str | ReadableBuffer], -//| password: Union[str | ReadableBuffer] = b"", +//| ssid: Union[str, ReadableBuffer], +//| password: Union[str, ReadableBuffer] = b"", //| *, //| channel: int = 1, //| authmode: Iterable[AuthMode] = (), @@ -438,11 +438,11 @@ MP_PROPERTY_GETTER(wifi_radio_ap_active_obj, //| def connect( //| self, -//| ssid: Union[str | ReadableBuffer], -//| password: Union[str | ReadableBuffer] = b"", +//| ssid: Union[str, ReadableBuffer], +//| password: Union[str, ReadableBuffer] = b"", //| *, //| channel: int = 0, -//| bssid: Optional[Union[str | ReadableBuffer]] = None, +//| bssid: Optional[Union[str, ReadableBuffer]] = None, //| timeout: Optional[float] = None, //| ) -> None: //| """Connects to the given ssid and waits for an ip address. Reconnections are handled From 36feb41bf5d3b15a43532ba0ec6b218cf2067f94 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Sun, 31 Aug 2025 00:29:41 -0500 Subject: [PATCH 16/78] Fix struct_time type hints --- shared-bindings/time/__init__.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 504cd07d90111..8a591da368858 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -83,6 +83,16 @@ static mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, s } //| class struct_time: +//| tm_year: int +//| tm_mon: int +//| tm_mday: int +//| tm_hour: int +//| tm_min: int +//| tm_sec: int +//| tm_wday: int +//| tm_yday: int +//| tm_isdst: int +//| //| def __init__(self, time_tuple: Sequence[int]) -> None: //| """Structure used to capture a date and time. Can be constructed from a `struct_time`, `tuple`, `list`, or `namedtuple` with 9 elements. //| @@ -210,7 +220,7 @@ static mp_obj_t time_monotonic_ns(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_ns_obj, time_monotonic_ns); -//| def localtime(secs: int) -> struct_time: +//| def localtime(secs: Optional[int] = None) -> struct_time: //| """Convert a time expressed in seconds since Jan 1, 1970 to a struct_time in //| local time. If secs is not provided or None, the current time as returned //| by time() is used. From 5480bd47684b0e0b3537a2f365bc94b2c0361633 Mon Sep 17 00:00:00 2001 From: allexok Date: Tue, 2 Sep 2025 17:28:09 +0200 Subject: [PATCH 17/78] Add Ai-On-The-Edge-Cam board --- .../prokyber_ai_on_the_edge_cam/board.c | 9 ++ .../mpconfigboard.h | 22 +++++ .../mpconfigboard.mk | 14 +++ .../boards/prokyber_ai_on_the_edge_cam/pins.c | 99 +++++++++++++++++++ .../prokyber_ai_on_the_edge_cam/sdkconfig | 14 +++ 5 files changed, 158 insertions(+) create mode 100644 ports/espressif/boards/prokyber_ai_on_the_edge_cam/board.c create mode 100644 ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.h create mode 100644 ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.mk create mode 100644 ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c create mode 100644 ports/espressif/boards/prokyber_ai_on_the_edge_cam/sdkconfig diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/board.c b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/board.c new file mode 100644 index 0000000000000..a3a9eec047145 --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.h b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.h new file mode 100644 index 0000000000000..2114fecf373a4 --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Prokyber Ai-On-The-Edge-Cam" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO12) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO48) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO5, .sda = &pin_GPIO4}} diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.mk b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.mk new file mode 100644 index 0000000000000..82419bb80745c --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x1209 +USB_PID = 0xDABB +USB_PRODUCT = "AI-ON-THE-EDGE-CAM" +USB_MANUFACTURER = "Prokyber" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m +CIRCUITPY_ESP_PSRAM_SIZE = 8MB diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c new file mode 100644 index 0000000000000..b11b33877c34b --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c @@ -0,0 +1,99 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/objtuple.h" +#include "shared-bindings/board/__init__.h" + +static const mp_rom_obj_tuple_t camera_data_tuple = { + {&mp_type_tuple}, + 8, + { + MP_ROM_PTR(&pin_GPIO11), + MP_ROM_PTR(&pin_GPIO9), + MP_ROM_PTR(&pin_GPIO8), + MP_ROM_PTR(&pin_GPIO10), + MP_ROM_PTR(&pin_GPIO47), + MP_ROM_PTR(&pin_GPIO18), + MP_ROM_PTR(&pin_GPIO17), + MP_ROM_PTR(&pin_GPIO16), + } +}; + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_PER_EN), MP_ROM_PTR(&pin_GPIO46) }, + + // SD + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + + // Ethernet + { MP_ROM_QSTR(MP_QSTR_ETH_RST), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_ETH_INT), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_ETH_MOSI), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_ETH_MISO), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_ETH_CLK), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_ETH_CS), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + + // LEDs + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + + // UART + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + + //I2C + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA), MP_ROM_PTR(&camera_data_tuple) }, + + { MP_ROM_QSTR(MP_QSTR_CAMERA_VSYNC), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_HREF), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA9), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_XCLK), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA8), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA7), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_PCLK), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA6), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA2), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA5), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA3), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA4), MP_ROM_PTR(&pin_GPIO8) }, + // { MP_ROM_QSTR(MP_QSTR_CAMERA_RESET), MP_ROM_PTR(&pin_GPIO47) }, + // { MP_ROM_QSTR(MP_QSTR_CAMERA_PWDN), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_SIOD), MP_ROM_PTR(&pin_GPIO4) }, // SDA + { MP_ROM_QSTR(MP_QSTR_CAMERA_SIOC), MP_ROM_PTR(&pin_GPIO5) }, // SCL + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/sdkconfig b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/sdkconfig new file mode 100644 index 0000000000000..ac1c535717672 --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP +CONFIG_OV2640_SUPPORT=y +# end of Component config + +# end of Espressif IoT Development Framework Configuration From 5493a6a1bde5538a4bfedad502f3ca3834b79b65 Mon Sep 17 00:00:00 2001 From: allexok Date: Tue, 2 Sep 2025 17:38:23 +0200 Subject: [PATCH 18/78] prettier text after 'pre-commit run --all-files' --- ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c index b11b33877c34b..305bdb3e0b69a 100644 --- a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c @@ -68,7 +68,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, - //I2C + // I2C { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, From de2efe0c2cceefa1a5ae5d14e6145ec8716a66f4 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 2 Sep 2025 20:43:39 -0400 Subject: [PATCH 19/78] Fix cardputer boot loop, and do some cleanup. - For `cardputer_keyboard.c`, allocate `DemuxKeyMatrix` it creates and the objects it holds (all the way down) on the port heap, because it lives past VM's. - To do the above, add support for non-VM heap for `DemuxKeyMatrix` and the `keypad` allocations it needs by passing an arg `use_gc_allocator`, as is done in `lvfontio`. - Add `mp_obj_port_malloc()`, `mp_obj_port_malloc_var()`, `mp_obj_new_port_tuple()`, all of which allocate on the port heap, not the VM heap. - Add `port_malloc_zero()`, because `port_malloc()` did not zero out its allocation, unlike VM heap allocations. I got caught by this. - Move `port_gc_collect()` from `main.c` to `supervisor/port.c` for consistency. This function is not actually used by anyone, but I was considering using it. - Add an `MP_WEAK` `mp_board_init()`, for board-specific initializations needed when a VM starts. Also considered, but not used. Added anyway for possible future use. - Add an `MP_WEAK` `board_gc_collect()`, for board-specific gc. Not used. - Add an `MP_WEAK` `port_gc_collect()`, for port-specific gc. Not used. - Don't duplicate keyboard code between `boards/m5stack_cardputer` and `boards/m5stack_cardputer_ros`. Instead, add a `ports/espressif/module` directory for this code, in the style of a port-specific `module` directory, like the port-specific `bindings` directories. --- main.c | 8 +- .../boards/m5stack_cardputer/mpconfigboard.mk | 2 +- .../cardputer_keyboard.c | 238 ------------------ .../boards/m5stack_cardputer_ros/keymap.h | 214 ---------------- .../m5stack_cardputer_ros/mpconfigboard.mk | 2 +- .../cardputer_keyboard.c | 59 ++--- .../keymap.h => module/cardputer_keymap.h} | 0 py/objtuple.c | 3 + shared-bindings/keypad/EventQueue.h | 2 +- shared-bindings/keypad_demux/DemuxKeyMatrix.c | 3 +- shared-bindings/keypad_demux/DemuxKeyMatrix.h | 2 +- shared-module/keypad/EventQueue.c | 9 +- shared-module/keypad/KeyMatrix.c | 2 +- shared-module/keypad/Keys.c | 2 +- shared-module/keypad/ShiftRegisterKeys.c | 2 +- shared-module/keypad/__init__.c | 14 +- shared-module/keypad/__init__.h | 2 +- shared-module/keypad_demux/DemuxKeyMatrix.c | 25 +- supervisor/board.h | 7 + supervisor/port.h | 8 + supervisor/port_heap.h | 1 + supervisor/shared/board.c | 8 + supervisor/shared/port.c | 36 +++ 23 files changed, 140 insertions(+), 509 deletions(-) delete mode 100644 ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c delete mode 100644 ports/espressif/boards/m5stack_cardputer_ros/keymap.h rename ports/espressif/{boards/m5stack_cardputer => module}/cardputer_keyboard.c (83%) rename ports/espressif/{boards/m5stack_cardputer/keymap.h => module/cardputer_keymap.h} (100%) diff --git a/main.c b/main.c index 1f387b7ca3ceb..cf9cf377d690b 100644 --- a/main.c +++ b/main.c @@ -207,6 +207,9 @@ static void start_mp(safe_mode_t safe_mode) { // Always return to root common_hal_os_chdir("/"); + + // Initialization for individual boards when a VM starts. + mp_board_init(); } static void stop_mp(void) { @@ -1149,6 +1152,7 @@ void gc_collect(void) { gc_collect_root((void **)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t)); port_gc_collect(); + board_gc_collect(); background_callback_gc_collect(); @@ -1179,10 +1183,6 @@ void gc_collect(void) { gc_collect_end(); } -// Ports may provide an implementation of this function if it is needed -MP_WEAK void port_gc_collect(void) { -} - size_t gc_get_max_new_split(void) { return port_heap_get_largest_free_size(); } diff --git a/ports/espressif/boards/m5stack_cardputer/mpconfigboard.mk b/ports/espressif/boards/m5stack_cardputer/mpconfigboard.mk index cd18ccf8a5a81..bc30ae3afd5e9 100644 --- a/ports/espressif/boards/m5stack_cardputer/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_cardputer/mpconfigboard.mk @@ -13,4 +13,4 @@ CIRCUITPY_ESP_FLASH_SIZE = 8MB CIRCUITPY_ESPCAMERA = 0 CIRCUITPY_MAX3421E = 0 -SRC_C += boards/$(BOARD)/cardputer_keyboard.c +SRC_C += module/cardputer_keyboard.c diff --git a/ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c b/ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c deleted file mode 100644 index 73880f66e19d9..0000000000000 --- a/ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c +++ /dev/null @@ -1,238 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft -// -// SPDX-License-Identifier: MIT - -#include "py/obj.h" -#include "py/objstr.h" -#include "py/runtime.h" - -#include "supervisor/shared/serial.h" -#include "shared-bindings/keypad/EventQueue.h" -#include "shared-bindings/keypad_demux/DemuxKeyMatrix.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-module/keypad/EventQueue.h" -#include "shared-module/keypad_demux/DemuxKeyMatrix.h" -#include "supervisor/shared/reload.h" - -#include "keymap.h" - -//| """M5Stack Cardputer keyboard integration. -//| """ -//| -//| """The KEYBOARD object is an instance of DemuxKeyMatrix, configured with correct pins. -//| The pins cannot be used for any other purposes (even though exposed in the board module). -//| By default all keyboard events are consumed and routed to the standard input - there is -//| not much use of the KEYBOARD object in this configuration - just read the input via sys.stdin. -//| -//| If you need to manually process individual key up / key down events via KEYBOARD.events, -//| call `detach_serial()`. -//| """" -//| KEYBOARD: keypad_demux.DemuxKeymatrix -//| -keypad_demux_demuxkeymatrix_obj_t cardputer_keyboard_obj; -bool cardputer_keyboard_serial_attached = false; - -void cardputer_keyboard_init(void); -void keyboard_seq(const char *seq); -void update_keyboard(keypad_eventqueue_obj_t *queue); - -//| def detach_serial() -> None: -//| """Stops consuming keyboard events and routing them to sys.stdin.""" -//| ... -//| -static mp_obj_t detach_serial(void) { - cardputer_keyboard_serial_attached = false; - common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, NULL); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(detach_serial_obj, detach_serial); - -//| def attach_serial() -> None: -//| """Starts consuming keyboard events and routing them to sys.stdin.""" -//| ... -//| -static mp_obj_t attach_serial(void) { - common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, update_keyboard); - cardputer_keyboard_serial_attached = true; - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(attach_serial_obj, attach_serial); - -//| def key_to_char(key: int, shifted: bool) -> str | None: -//| """Converts a key index to the respective key (with or without shift modifier). -//| Returns None for functional & modifier keys or whenever not 0 <= key < 56. -//| """ -//| ... -//| -static mp_obj_t key_to_char(mp_obj_t key_obj, mp_obj_t shifted_obj) { - mp_int_t key = mp_obj_get_int(key_obj); - if (key < 0 || key > (mp_int_t)(sizeof keymap / sizeof *keymap) || keymap[key] == 0) { - return mp_const_none; - } else if (shifted_obj == mp_const_true) { - return mp_obj_new_str(&keymap_shifted[key], 1); - } else { - return mp_obj_new_str(&keymap[key], 1); - } -} -static MP_DEFINE_CONST_FUN_OBJ_2(key_to_char_obj, key_to_char); - -// Ring buffer of characters consumed from keyboard events (when serial attached) -ringbuf_t keyqueue; -char keybuf[32]; - -keypad_event_obj_t event; -char keystate[56]; - -// Keyboard pins -const mcu_pin_obj_t *row_addr_pins[] = { - &pin_GPIO8, - &pin_GPIO9, - &pin_GPIO11, -}; - -const mcu_pin_obj_t *column_pins[] = { - &pin_GPIO13, - &pin_GPIO15, - &pin_GPIO3, - &pin_GPIO4, - &pin_GPIO5, - &pin_GPIO6, - &pin_GPIO7 -}; - -void cardputer_keyboard_init(void) { - cardputer_keyboard_obj.base.type = &keypad_demux_demuxkeymatrix_type; - common_hal_keypad_demux_demuxkeymatrix_construct( - &cardputer_keyboard_obj, // self - 3, // num_row_addr_pins - row_addr_pins, // row_addr_pins - 7, // num_column_pins - column_pins, // column_pins - true, // columns_to_anodes - false, // transpose - 0.01f, // interval - 20, // max_events - 2 // debounce_threshold - ); - demuxkeymatrix_never_reset(&cardputer_keyboard_obj); - - ringbuf_init(&keyqueue, (uint8_t *)keybuf, sizeof(keybuf)); - attach_serial(); -} - -// Overrides the weakly linked function from supervisor/shared/serial.c -void board_serial_init(void) { - cardputer_keyboard_init(); -} - -// Overrides the weakly linked function from supervisor/shared/serial.c -bool board_serial_connected(void) { - return cardputer_keyboard_serial_attached; -} - -// Overrides the weakly linked function from supervisor/shared/serial.c -uint32_t board_serial_bytes_available(void) { - if (cardputer_keyboard_serial_attached) { - return ringbuf_num_filled(&keyqueue); - } else { - return 0; - } -} - -// Overrides the weakly linked function from supervisor/shared/serial.c -char board_serial_read(void) { - if (cardputer_keyboard_serial_attached) { - return ringbuf_get(&keyqueue); - } else { - return 0; - } -} - -void keyboard_seq(const char *seq) { - while (*seq) { - ringbuf_put(&keyqueue, *seq++); - } -} - -void update_keyboard(keypad_eventqueue_obj_t *queue) { - uint8_t ascii = 0; - - if (common_hal_keypad_eventqueue_get_length(queue) == 0) { - return; - } - - while (common_hal_keypad_eventqueue_get_into(queue, &event)) { - if (event.pressed) { - keystate[event.key_number] = 1; - - if (keystate[KEY_CTRL]) { - if (keystate[KEY_ALT] && keystate[KEY_BACKSPACE]) { - reload_initiate(RUN_REASON_REPL_RELOAD); - } - ascii = keymap[event.key_number]; - if (ascii >= 'a' && ascii <= 'z') { - ascii -= 'a' - 1; - } - - if (ascii == mp_interrupt_char) { - mp_sched_keyboard_interrupt(); - } - } else if (keystate[KEY_SHIFT]) { - ascii = keymap_shifted[event.key_number]; - } else if (keystate[KEY_FN] && event.key_number != KEY_FN) { - switch (event.key_number | FN_MOD) - { - case KEY_DOWN: - keyboard_seq("\e[B"); - break; - case KEY_UP: - keyboard_seq("\e[A"); - break; - case KEY_DELETE: - keyboard_seq("\e[3~"); - break; - case KEY_LEFT: - keyboard_seq("\e[D"); - break; - case KEY_RIGHT: - keyboard_seq("\e[C"); - break; - case KEY_ESC: - ringbuf_put(&keyqueue, '\e'); - break; - } - } else { - ascii = keymap[event.key_number]; - } - - if (ascii > 0) { - if (keystate[KEY_ALT]) { - ringbuf_put(&keyqueue, '\e'); - } else if (keystate[KEY_OPT]) { - ringbuf_put(&keyqueue, '\x10'); - } - ringbuf_put(&keyqueue, ascii); - } - } else { - keystate[event.key_number] = 0; - } - } -} - -static const mp_rom_map_elem_t cardputer_keyboard_module_globals_table[] = { - {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cardputer_keyboard)}, - {MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&cardputer_keyboard_obj)}, - {MP_ROM_QSTR(MP_QSTR_attach_serial), MP_ROM_PTR(&attach_serial_obj)}, - {MP_ROM_QSTR(MP_QSTR_detach_serial), MP_ROM_PTR(&detach_serial_obj)}, - {MP_ROM_QSTR(MP_QSTR_key_to_char), MP_ROM_PTR(&key_to_char_obj)}, -}; -MP_DEFINE_CONST_DICT(cardputer_keyboard_module_globals, cardputer_keyboard_module_globals_table); - -const mp_obj_module_t cardputer_keyboard_module = { - .base = {&mp_type_module}, - .globals = (mp_obj_dict_t *)&cardputer_keyboard_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_cardputer_keyboard, cardputer_keyboard_module); diff --git a/ports/espressif/boards/m5stack_cardputer_ros/keymap.h b/ports/espressif/boards/m5stack_cardputer_ros/keymap.h deleted file mode 100644 index 0256fafaa0f57..0000000000000 --- a/ports/espressif/boards/m5stack_cardputer_ros/keymap.h +++ /dev/null @@ -1,214 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#define SHIFT_MOD 0x40 -#define FN_MOD 0x80 - -#define KEY_OPT 0 -#define KEY_Z 1 -#define KEY_C 2 -#define KEY_B 3 -#define KEY_M 4 -#define KEY_DOT 5 -#define KEY_SPACE 6 -#define KEY_SHIFT 7 -#define KEY_S 8 -#define KEY_F 9 -#define KEY_H 10 -#define KEY_K 11 -#define KEY_SEMICOLON 12 -#define KEY_ENTER 13 -#define KEY_Q 14 -#define KEY_E 15 -#define KEY_T 16 -#define KEY_U 17 -#define KEY_O 18 -#define KEY_LEFT_BRACKET 19 -#define KEY_BACKSLASH 20 -#define KEY_1 21 -#define KEY_3 22 -#define KEY_5 23 -#define KEY_7 24 -#define KEY_9 25 -#define KEY_UNDERSCORE 26 -#define KEY_BACKSPACE 27 -#define KEY_CTRL 28 -#define KEY_ALT 29 -#define KEY_X 30 -#define KEY_V 31 -#define KEY_N 32 -#define KEY_COMMA 33 -#define KEY_SLASH 34 -#define KEY_FN 35 -#define KEY_A 36 -#define KEY_D 37 -#define KEY_G 38 -#define KEY_J 39 -#define KEY_L 40 -#define KEY_APOSTROPHE 41 -#define KEY_TAB 42 -#define KEY_W 43 -#define KEY_R 44 -#define KEY_Y 45 -#define KEY_I 46 -#define KEY_P 47 -#define KEY_RIGHT_BRACKET 48 -#define KEY_GRAVE 49 -#define KEY_2 50 -#define KEY_4 51 -#define KEY_6 52 -#define KEY_8 53 -#define KEY_0 54 -#define KEY_EQUALS 55 - -#define KEY_GREATER (5 | SHIFT_MOD) -#define KEY_COLON (12 | SHIFT_MOD) -#define KEY_LEFT_CURLY_BRACKET (19 | SHIFT_MOD) -#define KEY_PIPE (20 | SHIFT_MOD) -#define KEY_EXCLAMATION (21 | SHIFT_MOD) -#define KEY_HASH (22 | SHIFT_MOD) -#define KEY_PERCENT (23 | SHIFT_MOD) -#define KEY_AMPERSAND (24 | SHIFT_MOD) -#define KEY_OPEN_PARENTHESIS (25 | SHIFT_MOD) -#define KEY_MINUS (26 | SHIFT_MOD) -#define KEY_LESS (33 | SHIFT_MOD) -#define KEY_QUESTION (34 | SHIFT_MOD) -#define KEY_DOUBLE_QUOTE (41 | SHIFT_MOD) -#define KEY_RIGHT_CURLY_BRACKET (48 | SHIFT_MOD) -#define KEY_TILDE (49 | SHIFT_MOD) -#define KEY_AT (50 | SHIFT_MOD) -#define KEY_DOLLAR (51 | SHIFT_MOD) -#define KEY_CARET (52 | SHIFT_MOD) -#define KEY_ASTERISK (53 | SHIFT_MOD) -#define KEY_CLOSE_PARENTHESIS (54 | SHIFT_MOD) -#define KEY_PLUS (55 | SHIFT_MOD) - -#define KEY_DOWN (5 | FN_MOD) -#define KEY_UP (12 | FN_MOD) -#define KEY_DELETE (27 | FN_MOD) -#define KEY_LEFT (33 | FN_MOD) -#define KEY_RIGHT (34 | FN_MOD) -#define KEY_ESC (49 | FN_MOD) - -const char keymap[56] = { - 0, // KEY_OPT - 'z', // KEY_Z - 'c', // KEY_C - 'b', // KEY_B - 'm', // KEY_M - '.', // KEY_DOT - ' ', // KEY_SPACE - 0, // KEY_SHIFT - 's', // KEY_S - 'f', // KEY_F - 'h', // KEY_H - 'k', // KEY_K - ';', // KEY_SEMICOLON - '\r',// KEY_ENTER - 'q', // KEY_Q - 'e', // KEY_E - 't', // KEY_T - 'u', // KEY_U - 'o', // KEY_O - '[', // KEY_LEFT_BRACKET - '\\',// KEY_BACKSLASH - '1', // KEY_1 - '3', // KEY_3 - '5', // KEY_5 - '7', // KEY_7 - '9', // KEY_9 - '_', // KEY_UNDERSCORE - '\b',// KEY_BACKSPACE - 0, // KEY_CTRL - 0, // KEY_ALT - 'x', // KEY_X - 'v', // KEY_V - 'n', // KEY_N - ',', // KEY_COMMA - '/', // KEY_SLASH - 0, // KEY_FN - 'a', // KEY_A - 'd', // KEY_D - 'g', // KEY_G - 'j', // KEY_J - 'l', // KEY_L - '\'',// KEY_APOSTROPHE - '\t',// KEY_TAB - 'w', // KEY_W - 'r', // KEY_R - 'y', // KEY_Y - 'i', // KEY_I - 'p', // KEY_P - ']', // KEY_RIGHT_BRACKET - '`', // KEY_GRAVE - '2', // KEY_2 - '4', // KEY_4 - '6', // KEY_6 - '8', // KEY_8 - '0', // KEY_0 - '=' // KEY_EQUALS -}; - -const char keymap_shifted[56] = { - 0, // KEY_OPT - 'Z', // KEY_Z - 'C', // KEY_C - 'B', // KEY_B - 'M', // KEY_M - '>', // KEY_DOT -> '>' - ' ', // KEY_SPACE - 0, // KEY_SHIFT - 'S', // KEY_S - 'F', // KEY_F - 'H', // KEY_H - 'K', // KEY_K - ':', // KEY_SEMICOLON -> ':' - '\r',// KEY_ENTER - 'Q', // KEY_Q - 'E', // KEY_E - 'T', // KEY_T - 'U', // KEY_U - 'O', // KEY_O - '{', // KEY_LEFT_BRACKET -> '{' - '|', // KEY_BACKSLASH -> '|' - '!', // KEY_1 -> '!' - '#', // KEY_3 -> '#' - '%', // KEY_5 -> '%' - '&', // KEY_7 -> '&' - '(', // KEY_9 -> '(' - '-', // KEY_UNDERSCORE -> '-' - '\b',// KEY_BACKSPACE - 0, // KEY_CTRL - 0, // KEY_ALT - 'X', // KEY_X - 'V', // KEY_V - 'N', // KEY_N - '<', // KEY_COMMA -> '<' - '?', // KEY_SLASH -> '?' - 0, // KEY_FN - 'A', // KEY_A - 'D', // KEY_D - 'G', // KEY_G - 'J', // KEY_J - 'L', // KEY_L - '"', // KEY_APOSTROPHE -> '"' - '\t',// KEY_TAB - 'W', // KEY_W - 'R', // KEY_R - 'Y', // KEY_Y - 'I', // KEY_I - 'P', // KEY_P - '}', // KEY_RIGHT_BRACKET -> '}' - '~', // KEY_GRAVE -> '~' - '@', // KEY_2 -> '@' - '$', // KEY_4 -> '$' - '^', // KEY_6 -> '^' - '*', // KEY_8 -> '*' - ')', // KEY_0 -> ')' - '+' // KEY_EQUALS -> '+' -}; diff --git a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk index 573f947f0a8f5..ede48c2f01523 100644 --- a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk @@ -15,4 +15,4 @@ CIRCUITPY_RCLCPY = 1 CIRCUITPY_ESPCAMERA = 0 CIRCUITPY_MAX3421E = 0 -SRC_C += boards/$(BOARD)/cardputer_keyboard.c +SRC_C += module/cardputer_keyboard.c diff --git a/ports/espressif/boards/m5stack_cardputer/cardputer_keyboard.c b/ports/espressif/module/cardputer_keyboard.c similarity index 83% rename from ports/espressif/boards/m5stack_cardputer/cardputer_keyboard.c rename to ports/espressif/module/cardputer_keyboard.c index 73880f66e19d9..548275001acc5 100644 --- a/ports/espressif/boards/m5stack_cardputer/cardputer_keyboard.c +++ b/ports/espressif/module/cardputer_keyboard.c @@ -16,7 +16,7 @@ #include "shared-module/keypad_demux/DemuxKeyMatrix.h" #include "supervisor/shared/reload.h" -#include "keymap.h" +#include "cardputer_keymap.h" //| """M5Stack Cardputer keyboard integration. //| """ @@ -31,12 +31,13 @@ //| """" //| KEYBOARD: keypad_demux.DemuxKeymatrix //| -keypad_demux_demuxkeymatrix_obj_t cardputer_keyboard_obj; -bool cardputer_keyboard_serial_attached = false; -void cardputer_keyboard_init(void); -void keyboard_seq(const char *seq); -void update_keyboard(keypad_eventqueue_obj_t *queue); +keypad_demux_demuxkeymatrix_obj_t cardputer_keyboard; +static bool cardputer_keyboard_serial_attached = false; + +// Forward declarations. +static void keyboard_seq(const char *seq); +static void update_keyboard(keypad_eventqueue_obj_t *queue); //| def detach_serial() -> None: //| """Stops consuming keyboard events and routing them to sys.stdin.""" @@ -44,7 +45,7 @@ void update_keyboard(keypad_eventqueue_obj_t *queue); //| static mp_obj_t detach_serial(void) { cardputer_keyboard_serial_attached = false; - common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, NULL); + common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard.events, NULL); return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_0(detach_serial_obj, detach_serial); @@ -54,7 +55,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(detach_serial_obj, detach_serial); //| ... //| static mp_obj_t attach_serial(void) { - common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, update_keyboard); + common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard.events, update_keyboard); cardputer_keyboard_serial_attached = true; return mp_const_none; } @@ -79,20 +80,20 @@ static mp_obj_t key_to_char(mp_obj_t key_obj, mp_obj_t shifted_obj) { static MP_DEFINE_CONST_FUN_OBJ_2(key_to_char_obj, key_to_char); // Ring buffer of characters consumed from keyboard events (when serial attached) -ringbuf_t keyqueue; -char keybuf[32]; +static ringbuf_t keyqueue; +static char keybuf[32]; keypad_event_obj_t event; -char keystate[56]; +static char keystate[56] = {0}; // Keyboard pins -const mcu_pin_obj_t *row_addr_pins[] = { +static const mcu_pin_obj_t *row_addr_pins[] = { &pin_GPIO8, &pin_GPIO9, &pin_GPIO11, }; -const mcu_pin_obj_t *column_pins[] = { +static const mcu_pin_obj_t *column_pins[] = { &pin_GPIO13, &pin_GPIO15, &pin_GPIO3, @@ -102,22 +103,22 @@ const mcu_pin_obj_t *column_pins[] = { &pin_GPIO7 }; -void cardputer_keyboard_init(void) { - cardputer_keyboard_obj.base.type = &keypad_demux_demuxkeymatrix_type; +static void cardputer_keyboard_init(void) { common_hal_keypad_demux_demuxkeymatrix_construct( - &cardputer_keyboard_obj, // self - 3, // num_row_addr_pins - row_addr_pins, // row_addr_pins - 7, // num_column_pins - column_pins, // column_pins - true, // columns_to_anodes - false, // transpose - 0.01f, // interval - 20, // max_events - 2 // debounce_threshold + &cardputer_keyboard, // self + MP_ARRAY_SIZE(row_addr_pins), // num_row_addr_pins + row_addr_pins, // row_addr_pins + MP_ARRAY_SIZE(column_pins), // num_column_pins + column_pins, // column_pins + true, // columns_to_anodes + false, // transpose + 0.01f, // interval + 20, // max_events + 2, // debounce_threshold + false // use_gc_allocator ); - demuxkeymatrix_never_reset(&cardputer_keyboard_obj); + demuxkeymatrix_never_reset(&cardputer_keyboard); ringbuf_init(&keyqueue, (uint8_t *)keybuf, sizeof(keybuf)); attach_serial(); } @@ -150,13 +151,13 @@ char board_serial_read(void) { } } -void keyboard_seq(const char *seq) { +static void keyboard_seq(const char *seq) { while (*seq) { ringbuf_put(&keyqueue, *seq++); } } -void update_keyboard(keypad_eventqueue_obj_t *queue) { +static void update_keyboard(keypad_eventqueue_obj_t *queue) { uint8_t ascii = 0; if (common_hal_keypad_eventqueue_get_length(queue) == 0) { @@ -223,7 +224,7 @@ void update_keyboard(keypad_eventqueue_obj_t *queue) { static const mp_rom_map_elem_t cardputer_keyboard_module_globals_table[] = { {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cardputer_keyboard)}, - {MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&cardputer_keyboard_obj)}, + {MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&cardputer_keyboard)}, {MP_ROM_QSTR(MP_QSTR_attach_serial), MP_ROM_PTR(&attach_serial_obj)}, {MP_ROM_QSTR(MP_QSTR_detach_serial), MP_ROM_PTR(&detach_serial_obj)}, {MP_ROM_QSTR(MP_QSTR_key_to_char), MP_ROM_PTR(&key_to_char_obj)}, diff --git a/ports/espressif/boards/m5stack_cardputer/keymap.h b/ports/espressif/module/cardputer_keymap.h similarity index 100% rename from ports/espressif/boards/m5stack_cardputer/keymap.h rename to ports/espressif/module/cardputer_keymap.h diff --git a/py/objtuple.c b/py/objtuple.c index 42e8d56a806cc..e0b31edaf2376 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -250,6 +250,9 @@ MP_DEFINE_CONST_OBJ_TYPE( // the zero-length tuple const mp_obj_tuple_t mp_const_empty_tuple_obj = {{&mp_type_tuple}, 0}; +// CIRCUITPY-CHANGE: No change here, but implementation was copied for +// mp_obj_new_port_tuple in supervisor/shared/port.c, which allocates using port_malloc(). +// Change that to match if this changes. mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { if (n == 0) { return mp_const_empty_tuple; diff --git a/shared-bindings/keypad/EventQueue.h b/shared-bindings/keypad/EventQueue.h index 893165e3220f1..02c3414b0764c 100644 --- a/shared-bindings/keypad/EventQueue.h +++ b/shared-bindings/keypad/EventQueue.h @@ -11,7 +11,7 @@ extern const mp_obj_type_t keypad_eventqueue_type; -void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events); +void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events, bool use_gc_allocator); void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self); size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self); diff --git a/shared-bindings/keypad_demux/DemuxKeyMatrix.c b/shared-bindings/keypad_demux/DemuxKeyMatrix.c index d76a20aec9d01..f1b5ecae9ceb6 100644 --- a/shared-bindings/keypad_demux/DemuxKeyMatrix.c +++ b/shared-bindings/keypad_demux/DemuxKeyMatrix.c @@ -123,7 +123,8 @@ static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type, column_pins_array[column] = pin; } - common_hal_keypad_demux_demuxkeymatrix_construct(self, num_row_addr_pins, row_addr_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, args[ARG_transpose].u_bool, interval, max_events, debounce_threshold); + // Last arg is use_gc_allocator, true during VM use. + common_hal_keypad_demux_demuxkeymatrix_construct(self, num_row_addr_pins, row_addr_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, args[ARG_transpose].u_bool, interval, max_events, debounce_threshold, true); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/keypad_demux/DemuxKeyMatrix.h b/shared-bindings/keypad_demux/DemuxKeyMatrix.h index 8bdaa597dc035..25d36283e90fc 100644 --- a/shared-bindings/keypad_demux/DemuxKeyMatrix.h +++ b/shared-bindings/keypad_demux/DemuxKeyMatrix.h @@ -11,7 +11,7 @@ extern const mp_obj_type_t keypad_demux_demuxkeymatrix_type; -void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold); +void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold, bool use_gc_allocator); void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_obj_t *self); diff --git a/shared-module/keypad/EventQueue.c b/shared-module/keypad/EventQueue.c index e5b362a045ddf..3130d8b59a1d7 100644 --- a/shared-module/keypad/EventQueue.c +++ b/shared-module/keypad/EventQueue.c @@ -15,9 +15,14 @@ #define EVENT_SIZE_BYTES (sizeof(uint16_t) + sizeof(mp_obj_t)) -void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events) { +void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events, bool use_gc_allocator) { // Event queue is 16-bit values. - ringbuf_alloc(&self->encoded_events, max_events * EVENT_SIZE_BYTES); + const size_t size = max_events * EVENT_SIZE_BYTES; + if (use_gc_allocator) { + ringbuf_alloc(&self->encoded_events, size); + } else { + ringbuf_init(&self->encoded_events, port_malloc(size, false), size); + } self->overflowed = false; self->event_handler = NULL; } diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 67a5546853552..28830f591b129 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -56,7 +56,7 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint self->columns_to_anodes = columns_to_anodes; self->funcs = &keymatrix_funcs; - keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold); + keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold, true); } void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) { diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index 39d50f95e3238..80dcf36e163ad 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -41,7 +41,7 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin self->value_when_pressed = value_when_pressed; self->funcs = &keys_funcs; - keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold); + keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold, true); } diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c index 97917434ff81b..aa0c14dd36b50 100644 --- a/shared-module/keypad/ShiftRegisterKeys.c +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -71,7 +71,7 @@ void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_ self->value_when_pressed = value_when_pressed; self->funcs = &shiftregisterkeys_funcs; - keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold); + keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold, true); } void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self) { diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c index 3ffa0433174cf..f1d5d395df789 100644 --- a/shared-module/keypad/__init__.c +++ b/shared-module/keypad/__init__.c @@ -85,14 +85,20 @@ void keypad_deregister_scanner(keypad_scanner_obj_t *scanner) { supervisor_release_lock(&keypad_scanners_linked_list_lock); } -void keypad_construct_common(keypad_scanner_obj_t *self, mp_float_t interval, size_t max_events, uint8_t debounce_threshold) { +void keypad_construct_common(keypad_scanner_obj_t *self, mp_float_t interval, size_t max_events, uint8_t debounce_threshold, bool use_gc_allocator) { size_t key_count = common_hal_keypad_generic_get_key_count(self); - self->debounce_counter = (int8_t *)m_malloc_without_collect(sizeof(int8_t) * key_count); + self->debounce_counter = + use_gc_allocator + ? (int8_t *)m_malloc_without_collect(sizeof(int8_t) * key_count) + : (int8_t *)port_malloc_zero(sizeof(int8_t) * key_count, false); self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000) - keypad_eventqueue_obj_t *events = mp_obj_malloc(keypad_eventqueue_obj_t, &keypad_eventqueue_type); - common_hal_keypad_eventqueue_construct(events, max_events); + keypad_eventqueue_obj_t *events = + use_gc_allocator + ? mp_obj_malloc(keypad_eventqueue_obj_t, &keypad_eventqueue_type) + : mp_obj_port_malloc(keypad_eventqueue_obj_t, &keypad_eventqueue_type); + common_hal_keypad_eventqueue_construct(events, max_events, use_gc_allocator); self->events = events; self->debounce_threshold = debounce_threshold; diff --git a/shared-module/keypad/__init__.h b/shared-module/keypad/__init__.h index a7d21753f6625..66fea4878543b 100644 --- a/shared-module/keypad/__init__.h +++ b/shared-module/keypad/__init__.h @@ -39,7 +39,7 @@ void keypad_reset(void); void keypad_register_scanner(keypad_scanner_obj_t *scanner); void keypad_deregister_scanner(keypad_scanner_obj_t *scanner); -void keypad_construct_common(keypad_scanner_obj_t *scanner, mp_float_t interval, size_t max_events, uint8_t debounce_cycles); +void keypad_construct_common(keypad_scanner_obj_t *scanner, mp_float_t interval, size_t max_events, uint8_t debounce_cycles, bool use_gc_allocator); bool keypad_debounce(keypad_scanner_obj_t *self, mp_uint_t key_number, bool current); void keypad_never_reset(keypad_scanner_obj_t *self); diff --git a/shared-module/keypad_demux/DemuxKeyMatrix.c b/shared-module/keypad_demux/DemuxKeyMatrix.c index b90669d772fcd..329f7679d3f76 100644 --- a/shared-module/keypad_demux/DemuxKeyMatrix.c +++ b/shared-module/keypad_demux/DemuxKeyMatrix.c @@ -31,38 +31,45 @@ static mp_uint_t row_column_to_key_number(keypad_demux_demuxkeymatrix_obj_t *sel return row * common_hal_keypad_demux_demuxkeymatrix_get_column_count(self) + column; } -void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold) { - +void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold, bool use_gc_allocator) { // the multiplexed pins are outputs so we can set the address for the target row // the sense of the address pins themselves doesn't change with columns_to_anodes // but the value output on the selected row line will be !columns_to_anodes mp_obj_t row_addr_dios[num_row_addr_pins]; for (size_t row = 0; row < num_row_addr_pins; row++) { digitalio_digitalinout_obj_t *dio = - mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); + use_gc_allocator + ? mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type) + : mp_obj_port_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); common_hal_digitalio_digitalinout_construct(dio, row_addr_pins[row]); common_hal_digitalio_digitalinout_switch_to_output(dio, false, DRIVE_MODE_PUSH_PULL); row_addr_dios[row] = dio; } - self->row_addr_digitalinouts = mp_obj_new_tuple(num_row_addr_pins, row_addr_dios); + self->row_addr_digitalinouts = + use_gc_allocator + ? mp_obj_new_tuple(num_row_addr_pins, row_addr_dios) + : mp_obj_new_port_tuple(num_row_addr_pins, row_addr_dios); // the column pins are always inputs, with default state based on columns_to_anodes mp_obj_t column_dios[num_column_pins]; for (size_t column = 0; column < num_column_pins; column++) { digitalio_digitalinout_obj_t *dio = - mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); - dio->base.type = &digitalio_digitalinout_type; + use_gc_allocator + ? mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type) + : mp_obj_port_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); common_hal_digitalio_digitalinout_construct(dio, column_pins[column]); common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN); column_dios[column] = dio; } - self->column_digitalinouts = mp_obj_new_tuple(num_column_pins, column_dios); - + self->column_digitalinouts = + use_gc_allocator + ? mp_obj_new_tuple(num_column_pins, column_dios) + : mp_obj_new_port_tuple(num_column_pins, column_dios); self->columns_to_anodes = columns_to_anodes; self->transpose = transpose; self->funcs = &keymatrix_funcs; - keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold); + keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold, use_gc_allocator); } void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_obj_t *self) { diff --git a/supervisor/board.h b/supervisor/board.h index 0920bf4e5777b..1200eccc9b68c 100644 --- a/supervisor/board.h +++ b/supervisor/board.h @@ -25,3 +25,10 @@ void reset_board(void); // state. It should not prevent the user access method from working (such as // disabling USB, BLE or flash) because CircuitPython may continue to run. void board_deinit(void); + +// Initialization for individual boards when a VM starts. +void mp_board_init(void); + +// Some boards may want to mark additional pointers as gc roots. +// A default weak implementation is provided that does nothing. +void board_gc_collect(void); diff --git a/supervisor/port.h b/supervisor/port.h index cc49538218fac..0bf8fd8d01350 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -9,6 +9,7 @@ #include #include +#include "py/obj.h" #include "supervisor/shared/safe_mode.h" // Provided by the linker; @@ -107,3 +108,10 @@ void port_gc_collect(void); // this function to sense the button. Ports that need to can override this // function to provide their own implementation. bool port_boot_button_pressed(void); + +// Allocating objects on the port heap, not the VM heap. +#define mp_obj_port_malloc(struct_type, obj_type) ((struct_type *)mp_obj_port_malloc_helper(sizeof(struct_type), obj_type)) +#define mp_obj_port_malloc_var(struct_type, var_field, var_type, var_num, obj_type) ((struct_type *)mp_obj_port_malloc_helper(offsetof(struct_type, var_field) + sizeof(var_type) * (var_num), obj_type)) + +void *mp_obj_port_malloc_helper(size_t num_bytes, const mp_obj_type_t *type); +mp_obj_t mp_obj_new_port_tuple(size_t n, const mp_obj_t *items); diff --git a/supervisor/port_heap.h b/supervisor/port_heap.h index 07a3c884e241e..40abd21438741 100644 --- a/supervisor/port_heap.h +++ b/supervisor/port_heap.h @@ -21,6 +21,7 @@ void port_heap_init(void); void *port_malloc(size_t size, bool dma_capable); +void *port_malloc_zero(size_t size, bool dma_capable); void port_free(void *ptr); diff --git a/supervisor/shared/board.c b/supervisor/shared/board.c index 192bf7a65c806..40bc1e45a1049 100644 --- a/supervisor/shared/board.c +++ b/supervisor/shared/board.c @@ -44,3 +44,11 @@ MP_WEAK void board_deinit(void) { // Do-nothing so not all boards need to provide this function. MP_WEAK void reset_board(void) { } + +// Do-nothing so not all boards need to provide this function. +MP_WEAK void mp_board_init(void) { +} + +// Do-nothing so not all boards need to provide this function. +MP_WEAK void board_gc_collect(void) { +} diff --git a/supervisor/shared/port.c b/supervisor/shared/port.c index 3b9f0c8718161..aabf003fb302d 100644 --- a/supervisor/shared/port.c +++ b/supervisor/shared/port.c @@ -43,6 +43,15 @@ MP_WEAK void *port_malloc(size_t size, bool dma_capable) { return block; } +// Ensure allocated memory is zero. +MP_WEAK void *port_malloc_zero(size_t size, bool dma_capable) { + void *ptr = port_malloc(size, dma_capable); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; +} + MP_WEAK void port_free(void *ptr) { tlsf_free(heap, ptr); } @@ -80,3 +89,30 @@ MP_WEAK bool port_boot_button_pressed(void) { return false; #endif } + +// Ports may provide an implementation of this function if it is needed +MP_WEAK void port_gc_collect(void) { +} + +// Allocates an object in the port heap, not the VM heap, and also sets type, for mp_obj_malloc{,_var} macros. +MP_NOINLINE void *mp_obj_port_malloc_helper(size_t num_bytes, const mp_obj_type_t *type) { + mp_obj_base_t *base = (mp_obj_base_t *)port_malloc_zero(num_bytes, false); + base->type = type; + return base; +} + +// Creates a tuple on the port heap, not the VM heap. +// Implementation copied from py/objtuple.c. +mp_obj_t mp_obj_new_port_tuple(size_t n, const mp_obj_t *items) { + if (n == 0) { + return mp_const_empty_tuple; + } + mp_obj_tuple_t *o = mp_obj_port_malloc_var(mp_obj_tuple_t, items, mp_obj_t, n, &mp_type_tuple); + o->len = n; + if (items) { + for (size_t i = 0; i < n; i++) { + o->items[i] = items[i]; + } + } + return MP_OBJ_FROM_PTR(o); +} From 1d8352845684fefb22fd888bcf255ef23dc28791 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 9 May 2025 14:34:09 +1000 Subject: [PATCH 20/78] lib/littlefs: Fix string initializer in lfs1.c. Avoids the new Wunterminated-string-literal when compiled with gcc 15.1. It would be preferable to just disable this warning, but Clang -Wunknown-warning-option kicks in even when disabling warnings so this becomes fiddly to apply. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- lib/littlefs/lfs1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/littlefs/lfs1.c b/lib/littlefs/lfs1.c index 6a3fd670012cc..ec18dc470258c 100644 --- a/lib/littlefs/lfs1.c +++ b/lib/littlefs/lfs1.c @@ -2141,7 +2141,7 @@ int lfs1_format(lfs1_t *lfs1, const struct lfs1_config *cfg) { .d.elen = sizeof(superblock.d) - sizeof(superblock.d.magic) - 4, .d.nlen = sizeof(superblock.d.magic), .d.version = LFS1_DISK_VERSION, - .d.magic = {"littlefs"}, + .d.magic = {'l', 'i', 't', 't', 'l', 'e', 'f', 's'}, .d.block_size = lfs1->cfg->block_size, .d.block_count = lfs1->cfg->block_count, .d.root = {lfs1->root[0], lfs1->root[1]}, From 1630f215b709da2c98a4aa521833b1ccbf7e0c3d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 9 May 2025 13:36:05 +1000 Subject: [PATCH 21/78] py/emitinlinethumb: Refactor string literal as array initializer. Avoids the new Wunterminated-string-literal when compiled with gcc 15.1. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- py/emitinlinethumb.c | 108 +++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 7818bb4f46da8..d6596337ae5a6 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -150,27 +150,27 @@ typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t; static const reg_name_t reg_name_table[] = { - {0, "r0\0"}, - {1, "r1\0"}, - {2, "r2\0"}, - {3, "r3\0"}, - {4, "r4\0"}, - {5, "r5\0"}, - {6, "r6\0"}, - {7, "r7\0"}, - {8, "r8\0"}, - {9, "r9\0"}, - {10, "r10"}, - {11, "r11"}, - {12, "r12"}, - {13, "r13"}, - {14, "r14"}, - {15, "r15"}, - {10, "sl\0"}, - {11, "fp\0"}, - {13, "sp\0"}, - {14, "lr\0"}, - {15, "pc\0"}, + {0, {'r', '0' }}, + {1, {'r', '1' }}, + {2, {'r', '2' }}, + {3, {'r', '3' }}, + {4, {'r', '4' }}, + {5, {'r', '5' }}, + {6, {'r', '6' }}, + {7, {'r', '7' }}, + {8, {'r', '8' }}, + {9, {'r', '9' }}, + {10, {'r', '1', '0' }}, + {11, {'r', '1', '1' }}, + {12, {'r', '1', '2' }}, + {13, {'r', '1', '3' }}, + {14, {'r', '1', '4' }}, + {15, {'r', '1', '5' }}, + {10, {'s', 'l' }}, + {11, {'f', 'p' }}, + {13, {'s', 'p' }}, + {14, {'l', 'r' }}, + {15, {'p', 'c' }}, }; #define MAX_SPECIAL_REGISTER_NAME_LENGTH 7 @@ -368,20 +368,20 @@ typedef struct _cc_name_t { byte cc; byte name[2]; } cc_name_t; static const cc_name_t cc_name_table[] = { - { ASM_THUMB_CC_EQ, "eq" }, - { ASM_THUMB_CC_NE, "ne" }, - { ASM_THUMB_CC_CS, "cs" }, - { ASM_THUMB_CC_CC, "cc" }, - { ASM_THUMB_CC_MI, "mi" }, - { ASM_THUMB_CC_PL, "pl" }, - { ASM_THUMB_CC_VS, "vs" }, - { ASM_THUMB_CC_VC, "vc" }, - { ASM_THUMB_CC_HI, "hi" }, - { ASM_THUMB_CC_LS, "ls" }, - { ASM_THUMB_CC_GE, "ge" }, - { ASM_THUMB_CC_LT, "lt" }, - { ASM_THUMB_CC_GT, "gt" }, - { ASM_THUMB_CC_LE, "le" }, + { ASM_THUMB_CC_EQ, { 'e', 'q' }}, + { ASM_THUMB_CC_NE, { 'n', 'e' }}, + { ASM_THUMB_CC_CS, { 'c', 's' }}, + { ASM_THUMB_CC_CC, { 'c', 'c' }}, + { ASM_THUMB_CC_MI, { 'm', 'i' }}, + { ASM_THUMB_CC_PL, { 'p', 'l' }}, + { ASM_THUMB_CC_VS, { 'v', 's' }}, + { ASM_THUMB_CC_VC, { 'v', 'c' }}, + { ASM_THUMB_CC_HI, { 'h', 'i' }}, + { ASM_THUMB_CC_LS, { 'l', 's' }}, + { ASM_THUMB_CC_GE, { 'g', 'e' }}, + { ASM_THUMB_CC_LT, { 'l', 't' }}, + { ASM_THUMB_CC_GT, { 'g', 't' }}, + { ASM_THUMB_CC_LE, { 'l', 'e' }}, }; typedef struct _format_4_op_t { byte op; @@ -389,21 +389,21 @@ typedef struct _format_4_op_t { byte op; } format_4_op_t; #define X(x) (((x) >> 4) & 0xff) // only need 1 byte to distinguish these ops static const format_4_op_t format_4_op_table[] = { - { X(ASM_THUMB_FORMAT_4_EOR), "eor" }, - { X(ASM_THUMB_FORMAT_4_LSL), "lsl" }, - { X(ASM_THUMB_FORMAT_4_LSR), "lsr" }, - { X(ASM_THUMB_FORMAT_4_ASR), "asr" }, - { X(ASM_THUMB_FORMAT_4_ADC), "adc" }, - { X(ASM_THUMB_FORMAT_4_SBC), "sbc" }, - { X(ASM_THUMB_FORMAT_4_ROR), "ror" }, - { X(ASM_THUMB_FORMAT_4_TST), "tst" }, - { X(ASM_THUMB_FORMAT_4_NEG), "neg" }, - { X(ASM_THUMB_FORMAT_4_CMP), "cmp" }, - { X(ASM_THUMB_FORMAT_4_CMN), "cmn" }, - { X(ASM_THUMB_FORMAT_4_ORR), "orr" }, - { X(ASM_THUMB_FORMAT_4_MUL), "mul" }, - { X(ASM_THUMB_FORMAT_4_BIC), "bic" }, - { X(ASM_THUMB_FORMAT_4_MVN), "mvn" }, + { X(ASM_THUMB_FORMAT_4_EOR), {'e', 'o', 'r' }}, + { X(ASM_THUMB_FORMAT_4_LSL), {'l', 's', 'l' }}, + { X(ASM_THUMB_FORMAT_4_LSR), {'l', 's', 'r' }}, + { X(ASM_THUMB_FORMAT_4_ASR), {'a', 's', 'r' }}, + { X(ASM_THUMB_FORMAT_4_ADC), {'a', 'd', 'c' }}, + { X(ASM_THUMB_FORMAT_4_SBC), {'s', 'b', 'c' }}, + { X(ASM_THUMB_FORMAT_4_ROR), {'r', 'o', 'r' }}, + { X(ASM_THUMB_FORMAT_4_TST), {'t', 's', 't' }}, + { X(ASM_THUMB_FORMAT_4_NEG), {'n', 'e', 'g' }}, + { X(ASM_THUMB_FORMAT_4_CMP), {'c', 'm', 'p' }}, + { X(ASM_THUMB_FORMAT_4_CMN), {'c', 'm', 'n' }}, + { X(ASM_THUMB_FORMAT_4_ORR), {'o', 'r', 'r' }}, + { X(ASM_THUMB_FORMAT_4_MUL), {'m', 'u', 'l' }}, + { X(ASM_THUMB_FORMAT_4_BIC), {'b', 'i', 'c' }}, + { X(ASM_THUMB_FORMAT_4_MVN), {'m', 'v', 'n' }}, }; #undef X @@ -428,10 +428,10 @@ typedef struct _format_vfp_op_t { char name[3]; } format_vfp_op_t; static const format_vfp_op_t format_vfp_op_table[] = { - { 0x30, "add" }, - { 0x34, "sub" }, - { 0x20, "mul" }, - { 0x80, "div" }, + { 0x30, {'a', 'd', 'd' }}, + { 0x34, {'s', 'u', 'b' }}, + { 0x20, {'m', 'u', 'l' }}, + { 0x80, {'d', 'i', 'v' }}, }; // shorthand alias for whether we allow ARMv7-M instructions From 8e6cf02761e39801e9f9bca9fb7f86e724716b53 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 3 Sep 2025 12:37:56 -0400 Subject: [PATCH 22/78] Remove unused pins; group aliased pins --- .../boards/prokyber_ai_on_the_edge_cam/pins.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c index 305bdb3e0b69a..68dc40781a480 100644 --- a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c @@ -34,24 +34,32 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { // SD { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO41) }, { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO42) }, { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, // Ethernet { MP_ROM_QSTR(MP_QSTR_ETH_RST), MP_ROM_PTR(&pin_GPIO45) }, { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_ETH_INT), MP_ROM_PTR(&pin_GPIO38) }, { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_ETH_MOSI), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_ETH_MISO), MP_ROM_PTR(&pin_GPIO14) }, { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_ETH_CLK), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_ETH_CS), MP_ROM_PTR(&pin_GPIO39) }, { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, @@ -65,6 +73,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { // UART { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, @@ -86,8 +95,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA5), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA3), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA4), MP_ROM_PTR(&pin_GPIO8) }, - // { MP_ROM_QSTR(MP_QSTR_CAMERA_RESET), MP_ROM_PTR(&pin_GPIO47) }, - // { MP_ROM_QSTR(MP_QSTR_CAMERA_PWDN), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_CAMERA_SIOD), MP_ROM_PTR(&pin_GPIO4) }, // SDA { MP_ROM_QSTR(MP_QSTR_CAMERA_SIOC), MP_ROM_PTR(&pin_GPIO5) }, // SCL From a16137f9619e70e26bef27e3c676796f2c2ba5d9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 3 Sep 2025 14:42:49 -0400 Subject: [PATCH 23/78] sdkconfig.defaults: use standard defaults --- ports/espressif/esp-idf-config/sdkconfig.defaults | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ports/espressif/esp-idf-config/sdkconfig.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults index b54f599b2a5b7..dd766675136d9 100644 --- a/ports/espressif/esp-idf-config/sdkconfig.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig.defaults @@ -71,16 +71,6 @@ CONFIG_LWIP_IPV6_AUTOCONFIG=y CONFIG_LWIP_IPV6_RDNSS_MAX_DNS_SERVERS=0 CONFIG_LWIP_IPV6_DHCP6=y # -# TCP -# -CONFIG_LWIP_MAX_ACTIVE_TCP=4 -CONFIG_LWIP_MAX_LISTENING_TCP=4 -CONFIG_LWIP_TCP_SYNMAXRTX=6 -CONFIG_LWIP_TCP_SND_BUF_DEFAULT=2880 -CONFIG_LWIP_TCP_WND_DEFAULT=2880 -CONFIG_LWIP_TCP_RTO_TIME=3000 -# end of TCP - # end of LWIP # From 8993356f0532c345b70f07c72e218fceea27bce9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 3 Sep 2025 19:54:33 -0400 Subject: [PATCH 24/78] remove unused mp_board_init() and board_gc_collect() per review comments --- main.c | 4 ---- supervisor/board.h | 7 ------- supervisor/shared/board.c | 8 -------- 3 files changed, 19 deletions(-) diff --git a/main.c b/main.c index cf9cf377d690b..6c8e9c8804906 100644 --- a/main.c +++ b/main.c @@ -207,9 +207,6 @@ static void start_mp(safe_mode_t safe_mode) { // Always return to root common_hal_os_chdir("/"); - - // Initialization for individual boards when a VM starts. - mp_board_init(); } static void stop_mp(void) { @@ -1152,7 +1149,6 @@ void gc_collect(void) { gc_collect_root((void **)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t)); port_gc_collect(); - board_gc_collect(); background_callback_gc_collect(); diff --git a/supervisor/board.h b/supervisor/board.h index 1200eccc9b68c..0920bf4e5777b 100644 --- a/supervisor/board.h +++ b/supervisor/board.h @@ -25,10 +25,3 @@ void reset_board(void); // state. It should not prevent the user access method from working (such as // disabling USB, BLE or flash) because CircuitPython may continue to run. void board_deinit(void); - -// Initialization for individual boards when a VM starts. -void mp_board_init(void); - -// Some boards may want to mark additional pointers as gc roots. -// A default weak implementation is provided that does nothing. -void board_gc_collect(void); diff --git a/supervisor/shared/board.c b/supervisor/shared/board.c index 40bc1e45a1049..192bf7a65c806 100644 --- a/supervisor/shared/board.c +++ b/supervisor/shared/board.c @@ -44,11 +44,3 @@ MP_WEAK void board_deinit(void) { // Do-nothing so not all boards need to provide this function. MP_WEAK void reset_board(void) { } - -// Do-nothing so not all boards need to provide this function. -MP_WEAK void mp_board_init(void) { -} - -// Do-nothing so not all boards need to provide this function. -MP_WEAK void board_gc_collect(void) { -} From eaca0bb751e2dd07deb4e1e1233f1677502580d3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 5 Sep 2025 15:05:50 -0400 Subject: [PATCH 25/78] ports/raspberrypi/lwip_src/lwip_mem.c: put storage ops in a critical section --- ports/raspberrypi/lwip_src/lwip_mem.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/lwip_src/lwip_mem.c b/ports/raspberrypi/lwip_src/lwip_mem.c index 244f51e289bc9..d7d5468a42011 100644 --- a/ports/raspberrypi/lwip_src/lwip_mem.c +++ b/ports/raspberrypi/lwip_src/lwip_mem.c @@ -8,14 +8,20 @@ #include #include "lib/tlsf/tlsf.h" #include "lwip_mem.h" +#include "shared-bindings/microcontroller/__init__.h" #include "supervisor/port_heap.h" void *lwip_heap_malloc(size_t size) { - return port_malloc(size, true); + common_hal_mcu_disable_interrupts(); + void *ptr = port_malloc(size, true); + common_hal_mcu_enable_interrupts(); + return ptr; } void lwip_heap_free(void *ptr) { + common_hal_mcu_disable_interrupts(); port_free(ptr); + common_hal_mcu_enable_interrupts(); } void *lwip_heap_calloc(size_t num, size_t size) { From 05db6eefb2f08e579d5c03d462e507a1ba5c8a57 Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Tue, 2 Sep 2025 22:16:35 +0000 Subject: [PATCH 26/78] fix bad xfer_result_t enum values shared-module/usb/core/Device.c was using its own 0xff value for the xfer_result_t enum defined by tinyusb/src/common/tusb_types.h. The 0xff value served the same purpose as the already exisiting XFER_RESULT_INVALID enum value (a placeholder to mark in-progress transactions). This commit standardizes on XFER_RESULT_INVALID in usb.core.Device consistent with the usage in tinyusb. Making this change allows implementing `switch(result){...}` style result code checks without compiler errors about 0xff not being a valid value for the enum. --- shared-module/usb/core/Device.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index c9df0cf73805f..f6cd03ebcd40a 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -45,7 +45,7 @@ bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t d } self->device_address = device_address; self->first_langid = 0; - _xfer_result = 0xff; + _xfer_result = XFER_RESULT_INVALID; return true; } @@ -91,13 +91,13 @@ static void _transfer_done_cb(tuh_xfer_t *xfer) { static bool _wait_for_callback(void) { while (!mp_hal_is_interrupted() && - _xfer_result == 0xff) { + _xfer_result == XFER_RESULT_INVALID) { // The background tasks include TinyUSB which will call the function // we provided above. In other words, the callback isn't in an interrupt. RUN_BACKGROUND_TASKS; } xfer_result_t result = _xfer_result; - _xfer_result = 0xff; + _xfer_result = XFER_RESULT_INVALID; return result == XFER_RESULT_SUCCESS; } @@ -225,7 +225,7 @@ void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, m } static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout) { - _xfer_result = 0xff; + _xfer_result = XFER_RESULT_INVALID; xfer->complete_cb = _transfer_done_cb; if (!tuh_edpt_xfer(xfer)) { mp_raise_usb_core_USBError(NULL); @@ -234,7 +234,7 @@ static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout) { uint32_t start_time = supervisor_ticks_ms32(); while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) && !mp_hal_is_interrupted() && - _xfer_result == 0xff) { + _xfer_result == XFER_RESULT_INVALID) { // The background tasks include TinyUSB which will call the function // we provided above. In other words, the callback isn't in an interrupt. RUN_BACKGROUND_TASKS; @@ -244,11 +244,11 @@ static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout) { return 0; } xfer_result_t result = _xfer_result; - _xfer_result = 0xff; + _xfer_result = XFER_RESULT_INVALID; if (result == XFER_RESULT_STALLED) { mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); } - if (result == 0xff) { + if (result == XFER_RESULT_INVALID) { tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); mp_raise_usb_core_USBTimeoutError(); } @@ -355,7 +355,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, .complete_cb = _transfer_done_cb, }; - _xfer_result = 0xff; + _xfer_result = XFER_RESULT_INVALID; if (!tuh_control_xfer(&xfer)) { mp_raise_usb_core_USBError(NULL); @@ -364,7 +364,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, uint32_t start_time = supervisor_ticks_ms32(); while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) && !mp_hal_is_interrupted() && - _xfer_result == 0xff) { + _xfer_result == XFER_RESULT_INVALID) { // The background tasks include TinyUSB which will call the function // we provided above. In other words, the callback isn't in an interrupt. RUN_BACKGROUND_TASKS; @@ -374,11 +374,11 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, return 0; } xfer_result_t result = _xfer_result; - _xfer_result = 0xff; + _xfer_result = XFER_RESULT_INVALID; if (result == XFER_RESULT_STALLED) { mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); } - if (result == 0xff) { + if (result == XFER_RESULT_INVALID) { tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); mp_raise_usb_core_USBTimeoutError(); } From b0760773077aaab556394061fde17168cbf52df3 Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Tue, 2 Sep 2025 22:40:46 +0000 Subject: [PATCH 27/78] use switch for ctrl_transfer result check This directly translates the Device.ctrl_transfer() result check logic from its old if-statements to an equivalent switch-statement. The point is to make it clear how each possible result code is handled. Note that XFER_RESULT_FAILED and XFER_RESULT_TIMEOUT both return 0 without generating any exception. (but also, tinyusb may not actually use XFER_RESULT_TIMOUT if its comments are still accurate) --- shared-module/usb/core/Device.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index f6cd03ebcd40a..87d1141bfde39 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -375,17 +375,21 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, } xfer_result_t result = _xfer_result; _xfer_result = XFER_RESULT_INVALID; - if (result == XFER_RESULT_STALLED) { - mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); - } - if (result == XFER_RESULT_INVALID) { - tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); - mp_raise_usb_core_USBTimeoutError(); - } - if (result == XFER_RESULT_SUCCESS) { - return len; + switch (result) { + case XFER_RESULT_SUCCESS: + return len; + case XFER_RESULT_FAILED: + break; + case XFER_RESULT_STALLED: + mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); + break; + case XFER_RESULT_TIMEOUT: + break; + case XFER_RESULT_INVALID: + tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); + mp_raise_usb_core_USBTimeoutError(); + break; } - return 0; } From e9da6bce6dd037f4befe9c5966cd81b4960f9a7d Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Tue, 2 Sep 2025 23:02:39 +0000 Subject: [PATCH 28/78] return actual length from ctrl_transfer Previously this returned the requested transfer length argument, ignoring the actual length of transferred bytes. This changes to returning the actual length. --- shared-module/usb/core/Device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index 87d1141bfde39..517eb5f357a07 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -355,7 +355,11 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, .complete_cb = _transfer_done_cb, }; + // Prepare for transfer. Unless there is a timeout, these static globals will + // get modified by the _transfer_done_cb() callback when tinyusb finishes the + // transfer or encounters an error condition. _xfer_result = XFER_RESULT_INVALID; + _actual_len = 0; if (!tuh_control_xfer(&xfer)) { mp_raise_usb_core_USBError(NULL); @@ -377,7 +381,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, _xfer_result = XFER_RESULT_INVALID; switch (result) { case XFER_RESULT_SUCCESS: - return len; + return _actual_len; case XFER_RESULT_FAILED: break; case XFER_RESULT_STALLED: From f3560f98b5527e469977b5d450b3dd813df06d1e Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Wed, 3 Sep 2025 00:41:44 +0000 Subject: [PATCH 29/78] handle XFER_RESULT_FAILED with exception Previously, usb.core.Device.ctrl_transfer() did not raise an exception when TinyUSB returned an XFER_RESULT_FAILED result code. This change raises an exception which prevents a failed transfer from returning an all zero result buffer. --- shared-module/usb/core/Device.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index 517eb5f357a07..79b6775dd0c1a 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -374,22 +374,30 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, RUN_BACKGROUND_TASKS; } if (mp_hal_is_interrupted()) { + // Handle case of VM being interrupted by Ctrl-C or autoreload tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); return 0; } + // Handle control transfer result code from TinyUSB xfer_result_t result = _xfer_result; _xfer_result = XFER_RESULT_INVALID; switch (result) { case XFER_RESULT_SUCCESS: return _actual_len; case XFER_RESULT_FAILED: + mp_raise_usb_core_USBError(NULL); break; case XFER_RESULT_STALLED: mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); break; case XFER_RESULT_TIMEOUT: + // This timeout comes from TinyUSB, so assume that it has stopped the + // transfer (note: timeout logic may be unimplemented on TinyUSB side) + mp_raise_usb_core_USBTimeoutError(); break; case XFER_RESULT_INVALID: + // This timeout comes from CircuitPython, not TinyUSB, so tell TinyUSB + // to stop the transfer tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); mp_raise_usb_core_USBTimeoutError(); break; From 7d26fe986600718ac687f7bc2230c679ef3d6f2a Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Wed, 3 Sep 2025 01:50:48 +0000 Subject: [PATCH 30/78] factor out timed transfer setup & err handling The code for endpoint transfers and control transfers previously had a bunch of duplicated logic for setup, timeout checking, and result code error handling. This change factors that stuff out into functions, using my new transfer result error handling code from the last commit. Now the endpoint and control transfers can share the setup, timeout, and error check logic. For me, this refactor reduced the firmware image size by 176 bytes. --- shared-module/usb/core/Device.c | 128 ++++++++++++++------------------ 1 file changed, 57 insertions(+), 71 deletions(-) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index 79b6775dd0c1a..f71ac8844bb73 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -101,6 +101,59 @@ static bool _wait_for_callback(void) { return result == XFER_RESULT_SUCCESS; } +static void _prepare_for_transfer(void) { + // Prepare for transfer. Unless there is a timeout, these static globals will + // get modified by the _transfer_done_cb() callback when tinyusb finishes the + // transfer or encounters an error condition. + _xfer_result = XFER_RESULT_INVALID; + _actual_len = 0; +} + +static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout) { + if (xfer == NULL) { + mp_raise_usb_core_USBError(NULL); + return 0; + } + uint32_t start_time = supervisor_ticks_ms32(); + while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) && + !mp_hal_is_interrupted() && + _xfer_result == XFER_RESULT_INVALID) { + // The background tasks include TinyUSB which will call the function + // we provided above. In other words, the callback isn't in an interrupt. + RUN_BACKGROUND_TASKS; + } + if (mp_hal_is_interrupted()) { + // Handle case of VM being interrupted by Ctrl-C or autoreload + tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); + return 0; + } + // Handle control transfer result code from TinyUSB + xfer_result_t result = _xfer_result; + _xfer_result = XFER_RESULT_INVALID; + switch (result) { + case XFER_RESULT_SUCCESS: + return _actual_len; + case XFER_RESULT_FAILED: + mp_raise_usb_core_USBError(NULL); + break; + case XFER_RESULT_STALLED: + mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); + break; + case XFER_RESULT_TIMEOUT: + // This timeout comes from TinyUSB, so assume that it has stopped the + // transfer (note: timeout logic may be unimplemented on TinyUSB side) + mp_raise_usb_core_USBTimeoutError(); + break; + case XFER_RESULT_INVALID: + // This timeout comes from CircuitPython, not TinyUSB, so tell TinyUSB + // to stop the transfer + tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); + mp_raise_usb_core_USBTimeoutError(); + break; + } + return 0; +} + static mp_obj_t _get_string(const uint16_t *temp_buf) { size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t); if (utf16_len == 0) { @@ -225,38 +278,13 @@ void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, m } static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout) { - _xfer_result = XFER_RESULT_INVALID; + _prepare_for_transfer(); xfer->complete_cb = _transfer_done_cb; if (!tuh_edpt_xfer(xfer)) { mp_raise_usb_core_USBError(NULL); return 0; } - uint32_t start_time = supervisor_ticks_ms32(); - while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) && - !mp_hal_is_interrupted() && - _xfer_result == XFER_RESULT_INVALID) { - // The background tasks include TinyUSB which will call the function - // we provided above. In other words, the callback isn't in an interrupt. - RUN_BACKGROUND_TASKS; - } - if (mp_hal_is_interrupted()) { - tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); - return 0; - } - xfer_result_t result = _xfer_result; - _xfer_result = XFER_RESULT_INVALID; - if (result == XFER_RESULT_STALLED) { - mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); - } - if (result == XFER_RESULT_INVALID) { - tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); - mp_raise_usb_core_USBTimeoutError(); - } - if (result == XFER_RESULT_SUCCESS) { - return _actual_len; - } - - return 0; + return _handle_timed_transfer_callback(xfer, timeout); } static bool _open_endpoint(usb_core_device_obj_t *self, mp_int_t endpoint) { @@ -355,54 +383,12 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, .complete_cb = _transfer_done_cb, }; - // Prepare for transfer. Unless there is a timeout, these static globals will - // get modified by the _transfer_done_cb() callback when tinyusb finishes the - // transfer or encounters an error condition. - _xfer_result = XFER_RESULT_INVALID; - _actual_len = 0; - + _prepare_for_transfer(); if (!tuh_control_xfer(&xfer)) { mp_raise_usb_core_USBError(NULL); return 0; } - uint32_t start_time = supervisor_ticks_ms32(); - while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) && - !mp_hal_is_interrupted() && - _xfer_result == XFER_RESULT_INVALID) { - // The background tasks include TinyUSB which will call the function - // we provided above. In other words, the callback isn't in an interrupt. - RUN_BACKGROUND_TASKS; - } - if (mp_hal_is_interrupted()) { - // Handle case of VM being interrupted by Ctrl-C or autoreload - tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); - return 0; - } - // Handle control transfer result code from TinyUSB - xfer_result_t result = _xfer_result; - _xfer_result = XFER_RESULT_INVALID; - switch (result) { - case XFER_RESULT_SUCCESS: - return _actual_len; - case XFER_RESULT_FAILED: - mp_raise_usb_core_USBError(NULL); - break; - case XFER_RESULT_STALLED: - mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); - break; - case XFER_RESULT_TIMEOUT: - // This timeout comes from TinyUSB, so assume that it has stopped the - // transfer (note: timeout logic may be unimplemented on TinyUSB side) - mp_raise_usb_core_USBTimeoutError(); - break; - case XFER_RESULT_INVALID: - // This timeout comes from CircuitPython, not TinyUSB, so tell TinyUSB - // to stop the transfer - tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); - mp_raise_usb_core_USBTimeoutError(); - break; - } - return 0; + return (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout); } bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface) { From e8a6d38ec4396a4ed0987829e01db9deabbfc84f Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Sat, 6 Sep 2025 00:52:51 +0000 Subject: [PATCH 31/78] fix idVendor and idProduct error check Previously these weren't checking to see if TinyUSB reported a failure. Now they check. --- shared-module/usb/core/Device.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index f71ac8844bb73..df108776fd446 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2022 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Sam Blenny // // SPDX-License-Identifier: MIT @@ -70,14 +71,18 @@ void common_hal_usb_core_device_deinit(usb_core_device_obj_t *self) { uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self) { uint16_t vid; uint16_t pid; - tuh_vid_pid_get(self->device_address, &vid, &pid); + if (!tuh_vid_pid_get(self->device_address, &vid, &pid)) { + mp_raise_usb_core_USBError(NULL); + } return vid; } uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self) { uint16_t vid; uint16_t pid; - tuh_vid_pid_get(self->device_address, &vid, &pid); + if (!tuh_vid_pid_get(self->device_address, &vid, &pid)) { + mp_raise_usb_core_USBError(NULL); + } return pid; } From 99f244e033d08c7ae862a52e8eccc831661608ed Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Sat, 6 Sep 2025 07:46:34 +0000 Subject: [PATCH 32/78] fix comment --- shared-module/usb/core/Device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index df108776fd446..604e945f1db96 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -132,7 +132,7 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); return 0; } - // Handle control transfer result code from TinyUSB + // Handle transfer result code from TinyUSB xfer_result_t result = _xfer_result; _xfer_result = XFER_RESULT_INVALID; switch (result) { From ad745c2c33a9e91fcbda22b9b58a08a56eb25fc4 Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Sun, 7 Sep 2025 01:00:31 +0000 Subject: [PATCH 33/78] error checks for usb device string properties Improve the error handling for usb.core.Device string properties: .serial_number, .product, .manufacturer Previously, the property getters didn't check the device descriptor to see if the device actually had the requested string. Instead, they relied on TinyUSB to return a failure result if the string was not available. That made it impossible to distinguish missing strings from other more serious USB errors (e.g. unplugged device). These changes make it possible to return None for a missing string or raise a USBError exception in case of a more serious problem. --- shared-module/usb/core/Device.c | 87 ++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 17 deletions(-) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index 604e945f1db96..c07ffda1149c9 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -101,9 +101,28 @@ static bool _wait_for_callback(void) { // we provided above. In other words, the callback isn't in an interrupt. RUN_BACKGROUND_TASKS; } + if (mp_hal_is_interrupted()) { + // Handle case of VM being interrupted by Ctrl-C or autoreload + return false; + } + // Handle callback result code from TinyUSB xfer_result_t result = _xfer_result; _xfer_result = XFER_RESULT_INVALID; - return result == XFER_RESULT_SUCCESS; + switch (result) { + case XFER_RESULT_SUCCESS: + return true; + case XFER_RESULT_FAILED: + mp_raise_usb_core_USBError(NULL); + break; + case XFER_RESULT_STALLED: + mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); + break; + case XFER_RESULT_TIMEOUT: + case XFER_RESULT_INVALID: + mp_raise_usb_core_USBTimeoutError(); + break; + } + return false; } static void _prepare_for_transfer(void) { @@ -173,41 +192,75 @@ static void _get_langid(usb_core_device_obj_t *self) { } // Two control bytes and one uint16_t language code. uint16_t temp_buf[2]; - if (!tuh_descriptor_get_string(self->device_address, 0, 0, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0) || - !_wait_for_callback()) { - return; + _prepare_for_transfer(); + if (!tuh_descriptor_get_string(self->device_address, 0, 0, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0)) { + mp_raise_usb_core_USBError(NULL); + } else if (_wait_for_callback()) { + self->first_langid = temp_buf[1]; } - self->first_langid = temp_buf[1]; } mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self) { uint16_t temp_buf[127]; - _get_langid(self); - if (!tuh_descriptor_get_serial_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0) || - !_wait_for_callback()) { + tusb_desc_device_t descriptor; + // First, be sure not to ask TinyUSB for a non-existent string (avoid error) + if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) { + return mp_const_none; + } + if (descriptor.iSerialNumber == 0) { return mp_const_none; } - return _get_string(temp_buf); + // Device does provide this string, so continue + _get_langid(self); + _prepare_for_transfer(); + if (!tuh_descriptor_get_serial_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0)) { + mp_raise_usb_core_USBError(NULL); + } else if (_wait_for_callback()) { + return _get_string(temp_buf); + } + return mp_const_none; } mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self) { uint16_t temp_buf[127]; - _get_langid(self); - if (!tuh_descriptor_get_product_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0) || - !_wait_for_callback()) { + tusb_desc_device_t descriptor; + // First, be sure not to ask TinyUSB for a non-existent string (avoid error) + if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) { return mp_const_none; } - return _get_string(temp_buf); + if (descriptor.iProduct == 0) { + return mp_const_none; + } + // Device does provide this string, so continue + _get_langid(self); + _prepare_for_transfer(); + if (!tuh_descriptor_get_product_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0)) { + mp_raise_usb_core_USBError(NULL); + } else if (_wait_for_callback()) { + return _get_string(temp_buf); + } + return mp_const_none; } mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self) { uint16_t temp_buf[127]; - _get_langid(self); - if (!tuh_descriptor_get_manufacturer_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0) || - !_wait_for_callback()) { + tusb_desc_device_t descriptor; + // First, be sure not to ask TinyUSB for a non-existent string (avoid error) + if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) { return mp_const_none; } - return _get_string(temp_buf); + if (descriptor.iManufacturer == 0) { + return mp_const_none; + } + // Device does provide this string, so continue + _get_langid(self); + _prepare_for_transfer(); + if (!tuh_descriptor_get_manufacturer_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0)) { + mp_raise_usb_core_USBError(NULL); + } else if (_wait_for_callback()) { + return _get_string(temp_buf); + } + return mp_const_none; } From 5d1bbca8ec1ea2a72b250a081b4233293f1a17fe Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 9 Sep 2025 13:42:09 -0400 Subject: [PATCH 34/78] Better error when mistakenly importing MicroPython .mpy file --- locale/circuitpython.pot | 4 ++++ py/persistentcode.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 262b5de769c89..7cb03d45088cc 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1394,6 +1394,10 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" diff --git a/py/persistentcode.c b/py/persistentcode.c index 1976729f4d879..93f4c33deb4e2 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -471,6 +471,9 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { read_bytes(reader, header, sizeof(header)); byte arch = MPY_FEATURE_DECODE_ARCH(header[2]); // CIRCUITPY-CHANGE: 'C', not 'M' + if (header[0] == 'M') { + mp_raise_ValueError(MP_ERROR_TEXT("MicroPython .mpy file; use CircuitPython mpy-cross")); + } if (header[0] != 'C' || header[1] != MPY_VERSION || (arch != MP_NATIVE_ARCH_NONE && MPY_FEATURE_DECODE_SUB_VERSION(header[2]) != MPY_SUB_VERSION) From 8d6bd4b746017eedf31ac1d40ef32928d78b2949 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 9 Sep 2025 21:20:33 +0200 Subject: [PATCH 35/78] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 4 ++++ locale/el.po | 4 ++++ locale/hi.po | 4 ++++ locale/ko.po | 4 ++++ locale/ru.po | 4 ++++ locale/tr.po | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/locale/cs.po b/locale/cs.po index 58785e0a5d75a..67ece22664d76 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1414,6 +1414,10 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" diff --git a/locale/el.po b/locale/el.po index 082ae20351e3b..9e31051bcc03b 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1420,6 +1420,10 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" diff --git a/locale/hi.po b/locale/hi.po index 8e4aa0990aee7..7ab47ff0953b5 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1396,6 +1396,10 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" diff --git a/locale/ko.po b/locale/ko.po index 8bde494eeec78..30205cad930e0 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1447,6 +1447,10 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "매핑은 투플이어야 합니다" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" diff --git a/locale/ru.po b/locale/ru.po index d3d9415230455..49fb1eccdedef 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1435,6 +1435,10 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "Сопоставление должно быть кортежом" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" diff --git a/locale/tr.po b/locale/tr.po index 10a288553a698..1bb304eaba6ca 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1415,6 +1415,10 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "Map tuple olmalıdır" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" From 77b613769d9432562caea23e375fefc3bc9cc45d Mon Sep 17 00:00:00 2001 From: gychang Date: Tue, 9 Sep 2025 15:44:01 -0700 Subject: [PATCH 36/78] Initial support for ESP32-C3-Lyra-V2 dev board See https://docs.espressif.com/projects/esp-adf/en/latest/design-guide/dev-boards/user-guide-esp32-c3-lyra.html This commit adds support for the status LED. It's not 100% clear to me why the default neopixel_write implementation doesn't work, but it seems that deleting the RMT channel triggers some sort of glitch signal that clears the WS2812C LED. Tested on this board: - console/REPL over USB/UART (connection works but is not stable) - web interface and editor over wifi - audiomp3 playback (sounds terrible) - neopixel library --- .../boards/espressif_esp32c3_lyra_v2/board.c | 9 ++++ .../espressif_esp32c3_lyra_v2/mpconfigboard.h | 23 +++++++++++ .../mpconfigboard.mk | 14 +++++++ .../boards/espressif_esp32c3_lyra_v2/pins.c | 41 +++++++++++++++++++ .../espressif_esp32c3_lyra_v2/sdkconfig | 0 .../common-hal/neopixel_write/__init__.c | 10 +++++ 6 files changed, 97 insertions(+) create mode 100644 ports/espressif/boards/espressif_esp32c3_lyra_v2/board.c create mode 100644 ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.h create mode 100644 ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk create mode 100644 ports/espressif/boards/espressif_esp32c3_lyra_v2/pins.c create mode 100644 ports/espressif/boards/espressif_esp32c3_lyra_v2/sdkconfig diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/board.c b/ports/espressif/boards/espressif_esp32c3_lyra_v2/board.c new file mode 100644 index 0000000000000..b3b20cfe2d3f0 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.h b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.h new file mode 100644 index 0000000000000..d38d4f4d09fdf --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.h @@ -0,0 +1,23 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Board setup +#define MICROPY_HW_BOARD_NAME "ESP32-C3-Lyra-V2" +#define MICROPY_HW_MCU_NAME "ESP32-C3N4" + +// Status LED +#define MICROPY_HW_NEOPIXEL (&pin_GPIO10) +#define MICROPY_HW_NEOPIXEL_COUNT (1) + +// Default bus pins +#define DEFAULT_UART_BUS_RX (&pin_GPIO20) +#define DEFAULT_UART_BUS_TX (&pin_GPIO21) + +// Serial over UART +#define CIRCUITPY_CONSOLE_UART_RX DEFAULT_UART_BUS_RX +#define CIRCUITPY_CONSOLE_UART_TX DEFAULT_UART_BUS_TX diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk new file mode 100644 index 0000000000000..a233eb526fdbd --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk @@ -0,0 +1,14 @@ +CIRCUITPY_CREATOR_ID = 0x000C303A +CIRCUITPY_CREATION_ID = 0x00C3A000 + +IDF_TARGET = esp32c3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 4MB + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 + +ESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD = 1 + +CFLAGS += -DESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD=$(ESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD) diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/pins.c b/ports/espressif/boards/espressif_esp32c3_lyra_v2/pins.c new file mode 100644 index 0000000000000..5f7c3d084dd3f --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/pins.c @@ -0,0 +1,41 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/sdkconfig b/ports/espressif/boards/espressif_esp32c3_lyra_v2/sdkconfig new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/ports/espressif/common-hal/neopixel_write/__init__.c b/ports/espressif/common-hal/neopixel_write/__init__.c index d0d46a3179787..945b309372ac7 100644 --- a/ports/espressif/common-hal/neopixel_write/__init__.c +++ b/ports/espressif/common-hal/neopixel_write/__init__.c @@ -126,6 +126,11 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, // Update the next start to +2 ticks. It ensures that we've gone 300+ us. next_start_raw_ticks = port_get_raw_ticks(NULL) + 2; + #if defined(ESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD) + // Hold the pin, deleting the channel seems to glitch pixels into turning off. + gpio_hold_en(digitalinout->pin->number); + #endif + // Free channel again rmt_del_encoder(encoder); rmt_disable(channel); @@ -133,4 +138,9 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, CHECK_ESP_RESULT(result); // Swap pin back to GPIO mode gpio_set_direction(digitalinout->pin->number, GPIO_MODE_OUTPUT); + + #if defined(ESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD) + // Release hold + gpio_hold_dis(digitalinout->pin->number); + #endif } From 146c199f34624add97a6287875a7287022accd3c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 10 Sep 2025 09:57:30 -0400 Subject: [PATCH 37/78] ports/raspberrypi/rp2pio/StateMachine.c: fix wait pin validation --- ports/raspberrypi/common-hal/rp2pio/StateMachine.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 74b9a7f0c31b0..8d7f7f2ed6f7e 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -523,9 +523,10 @@ static void consider_instruction(introspect_t *state, uint16_t full_instruction, } } if (instruction == pio_instr_bits_wait) { - uint16_t wait_source = (full_instruction & 0x0060) >> 5; - uint16_t wait_index = (full_instruction & 0x001f) + state->inputs.pio_gpio_offset; - if (wait_source == 0 && !PIO_PINMASK_IS_SET(state->inputs.pins_we_use, wait_index)) { // GPIO + const uint16_t wait_source = (full_instruction & 0x0060) >> 5; + const uint16_t wait_index = full_instruction & 0x001f; + const uint16_t wait_pin = wait_index + state->inputs.pio_gpio_offset; + if (wait_source == 0 && !PIO_PINMASK_IS_SET(state->inputs.pins_we_use, wait_pin)) { // GPIO mp_raise_ValueError_varg(MP_ERROR_TEXT("%q[%u] uses extra pin"), what_program, i); } else if (wait_source == 1) { // Input pin if (!state->inputs.has_in_pin) { From 0013b48091424e0beaac2d704fe7a1be4a951f82 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 11 Sep 2025 16:22:09 -0400 Subject: [PATCH 38/78] py/builtinimport.c: always name module in error msg when an import fails --- py/builtinimport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/py/builtinimport.c b/py/builtinimport.c index 17b3f11c4a001..e4e06d8e2cc8b 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -451,7 +451,9 @@ static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, if (stat == MP_IMPORT_STAT_NO_EXIST) { // Not found -- fail. - #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE + // CIRCUITPY-CHANGE: always the use more verbose error message that names missing module. + // Otherwise `import a` where `a` imports `b`, but `b` is missing will give a confusing error. + #if 0 && (MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE) mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found")); #else mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), full_mod_name); From 64b9c05779dd3db85fda5227ea31130e733bf4df Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 13 Sep 2025 15:44:51 -0400 Subject: [PATCH 39/78] Use critical sections for port_* storage operations, not just in LWIP --- .../common-hal/socketpool/Socket.c | 25 ++++++++++++++----- ports/raspberrypi/lwip_src/lwip_mem.c | 4 --- ports/raspberrypi/supervisor/port.c | 13 +++++++++- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/ports/raspberrypi/common-hal/socketpool/Socket.c b/ports/raspberrypi/common-hal/socketpool/Socket.c index 018365def8c75..aeab1498510a0 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.c +++ b/ports/raspberrypi/common-hal/socketpool/Socket.c @@ -89,7 +89,7 @@ static mp_obj_t socketpool_ip_addr_and_port_to_tuple(const ip_addr_t *addr, int // socket API. // Extension to lwIP error codes -// Matches lwIP 2.0.3 +// Matches lwIP 2.2.1 #undef _ERR_BADF #define _ERR_BADF -17 static const int error_lookup_table[] = { @@ -473,7 +473,12 @@ static mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf, MICROPY_PY_LWIP_ENTER - u16_t available = tcp_sndbuf(socket->pcb.tcp); + // If the socket is still connecting then don't let data be written to it. + // Otherwise, get the number of available bytes in the output buffer. + u16_t available = 0; + if (socket->state != STATE_CONNECTING) { + available = tcp_sndbuf(socket->pcb.tcp); + } if (available == 0) { // Non-blocking socket @@ -490,7 +495,8 @@ static mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf, // If peer fully closed socket, we would have socket->state set to ERR_RST (connection // reset) by error callback. // Avoid sending too small packets, so wait until at least 16 bytes available - while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) { + while (socket->state == STATE_CONNECTING + || (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16)) { MICROPY_PY_LWIP_EXIT if (socket->timeout != (unsigned)-1 && mp_hal_ticks_ms() - start > socket->timeout) { *_errno = MP_ETIMEDOUT; @@ -531,9 +537,10 @@ static mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf, MICROPY_PY_LWIP_REENTER } - // If the output buffer is getting full then send the data to the lower layers - if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) { - err = tcp_output(socket->pcb.tcp); + // Use nagle algorithm to determine when to send segment buffer (can be + // disabled with TCP_NODELAY socket option) + if (err == ERR_OK) { + err = tcp_output_nagle(socket->pcb.tcp); } MICROPY_PY_LWIP_EXIT @@ -551,6 +558,12 @@ static mp_uint_t lwip_tcp_receive(socketpool_socket_obj_t *socket, byte *buf, mp // 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; + return -1; + } + if (socket->incoming.pbuf == NULL) { // Non-blocking socket diff --git a/ports/raspberrypi/lwip_src/lwip_mem.c b/ports/raspberrypi/lwip_src/lwip_mem.c index d7d5468a42011..23b185354b072 100644 --- a/ports/raspberrypi/lwip_src/lwip_mem.c +++ b/ports/raspberrypi/lwip_src/lwip_mem.c @@ -12,16 +12,12 @@ #include "supervisor/port_heap.h" void *lwip_heap_malloc(size_t size) { - common_hal_mcu_disable_interrupts(); void *ptr = port_malloc(size, true); - common_hal_mcu_enable_interrupts(); return ptr; } void lwip_heap_free(void *ptr) { - common_hal_mcu_disable_interrupts(); port_free(ptr); - common_hal_mcu_enable_interrupts(); } void *lwip_heap_calloc(size_t num, size_t size) { diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 4be42380491cb..25b0bb6650f0c 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -264,31 +264,42 @@ void port_heap_init(void) { void *port_malloc(size_t size, bool dma_capable) { if (!dma_capable && _psram_size > 0) { + common_hal_mcu_disable_interrupts(); void *block = tlsf_malloc(_psram_heap, size); + common_hal_mcu_enable_interrupts(); if (block) { return block; } } + common_hal_mcu_disable_interrupts(); void *block = tlsf_malloc(_heap, size); + common_hal_mcu_enable_interrupts(); return block; } void port_free(void *ptr) { + common_hal_mcu_disable_interrupts(); if (((size_t)ptr) < SRAM_BASE) { tlsf_free(_psram_heap, ptr); } else { tlsf_free(_heap, ptr); } + common_hal_mcu_enable_interrupts(); } void *port_realloc(void *ptr, size_t size, bool dma_capable) { if (_psram_size > 0 && ((ptr != NULL && ((size_t)ptr) < SRAM_BASE) || (ptr == NULL && !dma_capable))) { + common_hal_mcu_disable_interrupts(); void *block = tlsf_realloc(_psram_heap, ptr, size); + common_hal_mcu_enable_interrupts(); if (block) { return block; } } - return tlsf_realloc(_heap, ptr, size); + common_hal_mcu_disable_interrupts(); + void *new_ptr = tlsf_realloc(_heap, ptr, size); + common_hal_mcu_enable_interrupts(); + return new_ptr; } static bool max_size_walker(void *ptr, size_t size, int used, void *user) { From 4008e1499735bb789d8cc95af2628d7327eb29aa Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 13 Sep 2025 15:46:00 -0400 Subject: [PATCH 40/78] espressif/common-hal/socketpool/Socket.c: return correct errno connect failure --- ports/espressif/common-hal/socketpool/Socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/common-hal/socketpool/Socket.c b/ports/espressif/common-hal/socketpool/Socket.c index 0a36eff95b454..5128e93c8589e 100644 --- a/ports/espressif/common-hal/socketpool/Socket.c +++ b/ports/espressif/common-hal/socketpool/Socket.c @@ -483,7 +483,7 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, socklen_t socklen = sizeof(error_code); result = getsockopt(self->num, SOL_SOCKET, SO_ERROR, &error_code, &socklen); if (result < 0 || error_code != 0) { - mp_raise_OSError(errno); + mp_raise_OSError(error_code); } self->connected = true; return; From a2c4dfa1ea5442b6416bc3be0c4a17c2ce89ec52 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 15 Sep 2025 12:20:20 -0700 Subject: [PATCH 41/78] Ensure USB host buffers are allocated in internal RAM --- locale/circuitpython.pot | 4 + ports/raspberrypi/mpconfigport.mk | 3 + ports/raspberrypi/supervisor/port.c | 8 ++ py/circuitpy_mpconfig.mk | 5 ++ shared-module/usb/core/Device.c | 116 ++++++++++++++++++++++++++-- shared-module/usb/core/Device.h | 4 + supervisor/port_heap.h | 6 ++ 7 files changed, 141 insertions(+), 5 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 7cb03d45088cc..98fc54741eb39 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -844,6 +844,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 1404b2b06777c..bbce13d13811f 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -59,6 +59,9 @@ CIRCUITPY_CYW43_INIT_DELAY ?= 1000 endif ifeq ($(CHIP_VARIANT),RP2350) +# RP2350 has PSRAM that is not DMA-capable +CIRCUITPY_ALL_MEMORY_DMA_CAPABLE = 0 + # This needs to be implemented. CIRCUITPY_ALARM = 0 # Default PICODVI on because it doesn't require much code in RAM to talk to HSTX. diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 25b0bb6650f0c..66e63248c4810 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -302,6 +302,14 @@ void *port_realloc(void *ptr, size_t size, bool dma_capable) { return new_ptr; } +#if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE +bool port_buffer_is_dma_capable(const void *ptr) { + // For RP2350, DMA can only access SRAM, not PSRAM + // PSRAM addresses are below SRAM_BASE + return ptr != NULL && ((size_t)ptr) >= SRAM_BASE; +} +#endif + static bool max_size_walker(void *ptr, size_t size, int used, void *user) { size_t *max_size = (size_t *)user; if (!used && *max_size < size) { diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 2009c4e177da6..8c838a41218a3 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -98,6 +98,11 @@ CFLAGS += -DCIRCUITPY_ALARM=$(CIRCUITPY_ALARM) CIRCUITPY_ALARM_TOUCH ?= $(CIRCUITPY_ALARM) CFLAGS += -DCIRCUITPY_ALARM_TOUCH=$(CIRCUITPY_ALARM_TOUCH) +# Enable DMA buffer management for platforms where not all memory is DMA-capable +# Platforms with PSRAM or other non-DMA memory should set this to 0 +CIRCUITPY_ALL_MEMORY_DMA_CAPABLE ?= 1 +CFLAGS += -DCIRCUITPY_ALL_MEMORY_DMA_CAPABLE=$(CIRCUITPY_ALL_MEMORY_DMA_CAPABLE) + CIRCUITPY_ANALOGBUFIO ?= 0 CFLAGS += -DCIRCUITPY_ANALOGBUFIO=$(CIRCUITPY_ANALOGBUFIO) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index c07ffda1149c9..c4342e10d1d65 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -8,6 +8,8 @@ #include "shared-bindings/usb/core/Device.h" #include "tusb_config.h" +#include "supervisor/port.h" +#include "supervisor/port_heap.h" #include "lib/tinyusb/src/host/hcd.h" #include "lib/tinyusb/src/host/usbh.h" @@ -33,6 +35,39 @@ void tuh_umount_cb(uint8_t dev_addr) { static xfer_result_t _xfer_result; static size_t _actual_len; + +#if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE +// Helper to ensure buffer is DMA-capable for transfer operations +static uint8_t *_ensure_dma_buffer(usb_core_device_obj_t *self, const uint8_t *buffer, size_t len, bool for_write) { + if (port_buffer_is_dma_capable(buffer)) { + return (uint8_t *)buffer; // Already DMA-capable, use directly + } + + // Need to allocate/reallocate temporary buffer in DMA-capable memory + if (self->temp_buffer_size < len) { + self->temp_buffer = port_realloc(self->temp_buffer, len, true); // true = DMA capable + if (self->temp_buffer == NULL) { + self->temp_buffer_size = 0; + return NULL; // Allocation failed + } + self->temp_buffer_size = len; + } + + // Copy data to DMA buffer if writing + if (for_write && buffer != NULL) { + memcpy(self->temp_buffer, buffer, len); + } + + return self->temp_buffer; +} + +// Copy data back from DMA buffer to original buffer after read +static void _copy_from_dma_buffer(usb_core_device_obj_t *self, uint8_t *original_buffer, size_t len) { + if (!port_buffer_is_dma_capable(original_buffer) && self->temp_buffer != NULL) { + memcpy(original_buffer, self->temp_buffer, len); + } +} +#endif bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_address) { if (!tuh_inited()) { mp_raise_RuntimeError(MP_ERROR_TEXT("No usb host port initialized")); @@ -46,6 +81,10 @@ bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t d } self->device_address = device_address; self->first_langid = 0; + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + self->temp_buffer = NULL; + self->temp_buffer_size = 0; + #endif _xfer_result = XFER_RESULT_INVALID; return true; } @@ -65,6 +104,14 @@ void common_hal_usb_core_device_deinit(usb_core_device_obj_t *self) { self->open_endpoints[i] = 0; } } + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Clean up temporary buffer + if (self->temp_buffer != NULL) { + port_free(self->temp_buffer); + self->temp_buffer = NULL; + self->temp_buffer_size = 0; + } + #endif self->device_address = 0; } @@ -399,10 +446,22 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t mp_raise_usb_core_USBError(NULL); return 0; } + + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Ensure buffer is in DMA-capable memory + uint8_t *dma_buffer = _ensure_dma_buffer(self, buffer, len, true); // true = for write + if (dma_buffer == NULL) { + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); + return 0; + } + #else + uint8_t *dma_buffer = (uint8_t *)buffer; // All memory is DMA-capable + #endif + tuh_xfer_t xfer; xfer.daddr = self->device_address; xfer.ep_addr = endpoint; - xfer.buffer = (uint8_t *)buffer; + xfer.buffer = dma_buffer; xfer.buflen = len; return _xfer(&xfer, timeout); } @@ -412,12 +471,33 @@ mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t e mp_raise_usb_core_USBError(NULL); return 0; } + + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Ensure buffer is in DMA-capable memory + uint8_t *dma_buffer = _ensure_dma_buffer(self, buffer, len, false); // false = for read + if (dma_buffer == NULL) { + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); + return 0; + } + #else + uint8_t *dma_buffer = buffer; // All memory is DMA-capable + #endif + tuh_xfer_t xfer; xfer.daddr = self->device_address; xfer.ep_addr = endpoint; - xfer.buffer = buffer; + xfer.buffer = dma_buffer; xfer.buflen = len; - return _xfer(&xfer, timeout); + mp_int_t result = _xfer(&xfer, timeout); + + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Copy data back to original buffer if needed + if (result > 0) { + _copy_from_dma_buffer(self, buffer, result); + } + #endif + + return result; } mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, @@ -426,6 +506,23 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, uint8_t *buffer, mp_int_t len, mp_int_t timeout) { // Timeout is in ms. + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Determine if this is a write (host-to-device) or read (device-to-host) transfer + bool is_write = (bmRequestType & 0x80) == 0; // Bit 7: 0=host-to-device, 1=device-to-host + + // Ensure buffer is in DMA-capable memory + uint8_t *dma_buffer = NULL; + if (len > 0 && buffer != NULL) { + dma_buffer = _ensure_dma_buffer(self, buffer, len, is_write); + if (dma_buffer == NULL) { + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); + return 0; + } + } + #else + uint8_t *dma_buffer = buffer; // All memory is DMA-capable + #endif + tusb_control_request_t request = { .bmRequestType = bmRequestType, .bRequest = bRequest, @@ -437,7 +534,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, .daddr = self->device_address, .ep_addr = 0, .setup = &request, - .buffer = buffer, + .buffer = dma_buffer, .complete_cb = _transfer_done_cb, }; @@ -446,7 +543,16 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, mp_raise_usb_core_USBError(NULL); return 0; } - return (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout); + mp_int_t result = (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout); + + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Copy data back to original buffer if this was a read transfer and we got data + if ((bmRequestType & 0x80) != 0 && result > 0 && buffer != NULL) { // Read transfer (device-to-host) + _copy_from_dma_buffer(self, buffer, result); + } + #endif + + return result; } bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface) { diff --git a/shared-module/usb/core/Device.h b/shared-module/usb/core/Device.h index c7392a04ba7bc..8737eeaf86bf7 100644 --- a/shared-module/usb/core/Device.h +++ b/shared-module/usb/core/Device.h @@ -15,4 +15,8 @@ typedef struct { uint8_t *configuration_descriptor; // Contains the length of the all descriptors. uint8_t open_endpoints[8]; uint16_t first_langid; + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + uint8_t *temp_buffer; // Temporary buffer for PSRAM data + size_t temp_buffer_size; // Size of temporary buffer + #endif } usb_core_device_obj_t; diff --git a/supervisor/port_heap.h b/supervisor/port_heap.h index 40abd21438741..3e6b5a660fa79 100644 --- a/supervisor/port_heap.h +++ b/supervisor/port_heap.h @@ -27,4 +27,10 @@ void port_free(void *ptr); void *port_realloc(void *ptr, size_t size, bool dma_capable); +#if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE +// Check if a buffer pointer is in DMA-capable memory. DMA-capable memory is also accessible during +// flash operations. +bool port_buffer_is_dma_capable(const void *ptr); +#endif + size_t port_heap_get_largest_free_size(void); From 989a857a335643fa280f6e72a39da3ad6b31e2fb Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 15 Sep 2025 23:10:38 -0400 Subject: [PATCH 42/78] rotaryio.IncrementalEncoder deinit fix and improvements --- .../common-hal/rotaryio/IncrementalEncoder.c | 13 ++++++++++--- .../common-hal/rotaryio/IncrementalEncoder.c | 8 ++++++++ .../common-hal/rotaryio/IncrementalEncoder.c | 10 ++++++++-- .../nordic/common-hal/rotaryio/IncrementalEncoder.c | 9 ++++++++- ports/raspberrypi/bindings/rp2pio/StateMachine.h | 1 + .../common-hal/rotaryio/IncrementalEncoder.c | 9 +++++++++ ports/raspberrypi/common-hal/rp2pio/StateMachine.c | 9 ++++++++- shared-bindings/rotaryio/IncrementalEncoder.h | 4 ++++ 8 files changed, 56 insertions(+), 7 deletions(-) diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c index c6cd4605784ab..a8c87d82ed268 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c @@ -17,6 +17,10 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self, const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) { + + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + if (!pin_a->has_extint) { raise_ValueError_invalid_pin_name(MP_QSTR_pin_a); } @@ -83,10 +87,13 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o turn_off_eic_channel(self->eic_channel_b); reset_pin_number(self->pin_a); - self->pin_a = NO_PIN; - reset_pin_number(self->pin_b); - self->pin_b = NO_PIN; + + common_hal_rotaryio_incrementalencoder_mark_deinit(self); +} + +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { + self->pin_a = NO_PIN; } void incrementalencoder_interrupt_handler(uint8_t channel) { diff --git a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c index ba8b70221b729..f65c7fdd9f110 100644 --- a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c @@ -21,6 +21,10 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode // // These routines also implicitly configure the weak internal pull-ups, as expected // in CircuitPython. + + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + pcnt_unit_config_t unit_config = { // Set counter limit .low_limit = INT16_MIN, @@ -87,6 +91,10 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o pcnt_del_channel(self->channel_a); pcnt_del_channel(self->channel_b); pcnt_del_unit(self->unit); + common_hal_rotaryio_incrementalencoder_mark_deinit(self); +} + +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { self->unit = NULL; } diff --git a/ports/mimxrt10xx/common-hal/rotaryio/IncrementalEncoder.c b/ports/mimxrt10xx/common-hal/rotaryio/IncrementalEncoder.c index c71f8b212e183..211b5c186f3fa 100644 --- a/ports/mimxrt10xx/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/mimxrt10xx/common-hal/rotaryio/IncrementalEncoder.c @@ -26,6 +26,9 @@ static void encoder_change(void *self_in) { void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self, const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) { + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + self->pin_a = pin_a; self->pin_b = pin_b; @@ -49,7 +52,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode } bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self) { - return !self->pin_a; + return self->pin_a == NULL; } void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t *self) { @@ -62,6 +65,9 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o common_hal_reset_pin(self->pin_a); common_hal_reset_pin(self->pin_b); + common_hal_rotaryio_incrementalencoder_mark_deinit(self); +} + +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { self->pin_a = NULL; - self->pin_b = NULL; } diff --git a/ports/nordic/common-hal/rotaryio/IncrementalEncoder.c b/ports/nordic/common-hal/rotaryio/IncrementalEncoder.c index b0617fae7e566..2e8b308ff64d9 100644 --- a/ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/nordic/common-hal/rotaryio/IncrementalEncoder.c @@ -32,6 +32,9 @@ static void _intr_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self, const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) { + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + self->pin_a = pin_a->number; self->pin_b = pin_b->number; @@ -78,6 +81,10 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o nrfx_gpiote_in_uninit(self->pin_b); reset_pin_number(self->pin_a); reset_pin_number(self->pin_b); + + common_hal_rotaryio_incrementalencoder_mark_deinit(self); +} + +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { self->pin_a = NO_PIN; - self->pin_b = NO_PIN; } diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.h b/ports/raspberrypi/bindings/rp2pio/StateMachine.h index afdffd1eccd3b..16f884bcfca32 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.h +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -42,6 +42,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self); bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self); +void common_hal_rp2pio_statemachine_mark_deinit(rp2pio_statemachine_obj_t *self); void common_hal_rp2pio_statemachine_never_reset(rp2pio_statemachine_obj_t *self); diff --git a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c index 113bd1900dd88..d71ff60b2ebc3 100644 --- a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c @@ -43,6 +43,9 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) { const mcu_pin_obj_t *pins[] = { pin_a, pin_b }; + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + // Start out with swapped to match behavior with other ports. self->swapped = true; if (!common_hal_rp2pio_pins_are_sequential(2, pins)) { @@ -89,6 +92,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode } bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self) { + // Use the deinit state of the PIO state machine. return common_hal_rp2pio_statemachine_deinited(&self->state_machine); } @@ -100,6 +104,11 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o common_hal_rp2pio_statemachine_deinit(&self->state_machine); } +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { + // Use the deinit state of the PIO state machine. + common_hal_rp2pio_statemachine_mark_deinit(&self->state_machine); +} + static void incrementalencoder_interrupt_handler(void *self_in) { rotaryio_incrementalencoder_obj_t *self = self_in; diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 8d7f7f2ed6f7e..71050677f225f 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -628,6 +628,9 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, int mov_status_type, int mov_status_n) { + // Ensure object starts in its deinit state. + common_hal_rp2pio_statemachine_mark_deinit(self); + // First, check that all pins are free OR already in use by any PIO if exclusive_pin_use is false. pio_pinmask_t pins_we_use = wait_gpio_mask; PIO_PINMASK_MERGE(pins_we_use, _check_pins_free(first_out_pin, out_pin_count, exclusive_pin_use)); @@ -744,7 +747,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, mov_status_type, mov_status_n); if (!ok) { // indicate state machine never inited - self->state_machine = NUM_PIO_STATE_MACHINES; + common_hal_rp2pio_statemachine_mark_deinit(self); mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); } } @@ -827,6 +830,10 @@ void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self) { rp2pio_statemachine_deinit(self, false); } +void common_hal_rp2pio_statemachine_mark_deinit(rp2pio_statemachine_obj_t *self) { + self->state_machine = NUM_PIO_STATE_MACHINES; +} + void common_hal_rp2pio_statemachine_never_reset(rp2pio_statemachine_obj_t *self) { rp2pio_statemachine_never_reset(self->pio, self->state_machine); // TODO: never reset all the pins diff --git a/shared-bindings/rotaryio/IncrementalEncoder.h b/shared-bindings/rotaryio/IncrementalEncoder.h index 1c60dd69a1937..b3ceb3eeb1513 100644 --- a/shared-bindings/rotaryio/IncrementalEncoder.h +++ b/shared-bindings/rotaryio/IncrementalEncoder.h @@ -13,11 +13,15 @@ extern const mp_obj_type_t rotaryio_incrementalencoder_type; extern void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self, const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b); + extern void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t *self); extern bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self); +extern void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self); + extern mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t *self); extern void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self, mp_int_t new_position); + extern mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self); extern void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self, mp_int_t new_divisor); From 908e1341c152c383316fb96aebe11700d222057a Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 16 Sep 2025 08:33:17 -0500 Subject: [PATCH 43/78] Return self object from `play` methods to allow for chaining --- shared-bindings/audiodelays/Chorus.c | 4 ++-- shared-bindings/audiodelays/Echo.c | 4 ++-- shared-bindings/audiodelays/MultiTapDelay.c | 4 ++-- shared-bindings/audiodelays/PitchShift.c | 4 ++-- shared-bindings/audiofilters/Distortion.c | 4 ++-- shared-bindings/audiofilters/Filter.c | 4 ++-- shared-bindings/audiofilters/Phaser.c | 4 ++-- shared-bindings/audiofreeverb/Freeverb.c | 4 ++-- shared-bindings/audiomixer/Mixer.c | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/shared-bindings/audiodelays/Chorus.c b/shared-bindings/audiodelays/Chorus.c index c6bfa2ffa7eb1..67b9bc32745c4 100644 --- a/shared-bindings/audiodelays/Chorus.c +++ b/shared-bindings/audiodelays/Chorus.c @@ -206,7 +206,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_chorus_get_playing_obj, audiodelays_chorus MP_PROPERTY_GETTER(audiodelays_chorus_playing_obj, (mp_obj_t)&audiodelays_chorus_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Chorus: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -228,7 +228,7 @@ static mp_obj_t audiodelays_chorus_obj_play(size_t n_args, const mp_obj_t *pos_a mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_chorus_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_chorus_play_obj, 1, audiodelays_chorus_obj_play); diff --git a/shared-bindings/audiodelays/Echo.c b/shared-bindings/audiodelays/Echo.c index 5ae849b19aa41..68216d2355b70 100644 --- a/shared-bindings/audiodelays/Echo.c +++ b/shared-bindings/audiodelays/Echo.c @@ -230,7 +230,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_echo_get_playing_obj, audiodelays_echo_obj MP_PROPERTY_GETTER(audiodelays_echo_playing_obj, (mp_obj_t)&audiodelays_echo_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Echo: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -252,7 +252,7 @@ static mp_obj_t audiodelays_echo_obj_play(size_t n_args, const mp_obj_t *pos_arg mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_echo_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_echo_play_obj, 1, audiodelays_echo_obj_play); diff --git a/shared-bindings/audiodelays/MultiTapDelay.c b/shared-bindings/audiodelays/MultiTapDelay.c index 5b057eaf80d1b..ce11b2f1d3c61 100644 --- a/shared-bindings/audiodelays/MultiTapDelay.c +++ b/shared-bindings/audiodelays/MultiTapDelay.c @@ -233,7 +233,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_multi_tap_delay_get_playing_obj, audiodela MP_PROPERTY_GETTER(audiodelays_multi_tap_delay_playing_obj, (mp_obj_t)&audiodelays_multi_tap_delay_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> MultiTapDelay: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -255,7 +255,7 @@ static mp_obj_t audiodelays_multi_tap_delay_obj_play(size_t n_args, const mp_obj mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_multi_tap_delay_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_multi_tap_delay_play_obj, 1, audiodelays_multi_tap_delay_obj_play); diff --git a/shared-bindings/audiodelays/PitchShift.c b/shared-bindings/audiodelays/PitchShift.c index df2189945aa5d..e595beec6b8de 100644 --- a/shared-bindings/audiodelays/PitchShift.c +++ b/shared-bindings/audiodelays/PitchShift.c @@ -190,7 +190,7 @@ MP_PROPERTY_GETTER(audiodelays_pitch_shift_playing_obj, (mp_obj_t)&audiodelays_pitch_shift_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> PitchShift: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -211,7 +211,7 @@ static mp_obj_t audiodelays_pitch_shift_obj_play(size_t n_args, const mp_obj_t * mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_pitch_shift_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_pitch_shift_play_obj, 1, audiodelays_pitch_shift_obj_play); diff --git a/shared-bindings/audiofilters/Distortion.c b/shared-bindings/audiofilters/Distortion.c index cb888d0c71b7b..3120111ca9a80 100644 --- a/shared-bindings/audiofilters/Distortion.c +++ b/shared-bindings/audiofilters/Distortion.c @@ -309,7 +309,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_distortion_get_playing_obj, audiofilters_ MP_PROPERTY_GETTER(audiofilters_distortion_playing_obj, (mp_obj_t)&audiofilters_distortion_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Distortion: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -331,7 +331,7 @@ static mp_obj_t audiofilters_distortion_obj_play(size_t n_args, const mp_obj_t * mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_distortion_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_distortion_play_obj, 1, audiofilters_distortion_obj_play); diff --git a/shared-bindings/audiofilters/Filter.c b/shared-bindings/audiofilters/Filter.c index 2a4887a4d42a2..2d8829d8a815d 100644 --- a/shared-bindings/audiofilters/Filter.c +++ b/shared-bindings/audiofilters/Filter.c @@ -179,7 +179,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_filter_get_playing_obj, audiofilters_filt MP_PROPERTY_GETTER(audiofilters_filter_playing_obj, (mp_obj_t)&audiofilters_filter_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Filter: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -201,7 +201,7 @@ static mp_obj_t audiofilters_filter_obj_play(size_t n_args, const mp_obj_t *pos_ mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_filter_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_filter_play_obj, 1, audiofilters_filter_obj_play); diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c index e7ddd986176b3..daff50e983492 100644 --- a/shared-bindings/audiofilters/Phaser.c +++ b/shared-bindings/audiofilters/Phaser.c @@ -214,7 +214,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_get_playing_obj, audiofilters_phas MP_PROPERTY_GETTER(audiofilters_phaser_playing_obj, (mp_obj_t)&audiofilters_phaser_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Phaser: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -236,7 +236,7 @@ static mp_obj_t audiofilters_phaser_obj_play(size_t n_args, const mp_obj_t *pos_ mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_phaser_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_phaser_play_obj, 1, audiofilters_phaser_obj_play); diff --git a/shared-bindings/audiofreeverb/Freeverb.c b/shared-bindings/audiofreeverb/Freeverb.c index 62c9237a0d271..5e4c9644d2e8d 100644 --- a/shared-bindings/audiofreeverb/Freeverb.c +++ b/shared-bindings/audiofreeverb/Freeverb.c @@ -196,7 +196,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiofreeverb_freeverb_get_playing_obj, audiofreeverb_ MP_PROPERTY_GETTER(audiofreeverb_freeverb_playing_obj, (mp_obj_t)&audiofreeverb_freeverb_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Freeverb: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -218,7 +218,7 @@ static mp_obj_t audiofreeverb_freeverb_obj_play(size_t n_args, const mp_obj_t *p mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofreeverb_freeverb_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiofreeverb_freeverb_play_obj, 1, audiofreeverb_freeverb_obj_play); diff --git a/shared-bindings/audiomixer/Mixer.c b/shared-bindings/audiomixer/Mixer.c index dda6d06bd500c..0944f58ddbe45 100644 --- a/shared-bindings/audiomixer/Mixer.c +++ b/shared-bindings/audiomixer/Mixer.c @@ -160,7 +160,7 @@ MP_PROPERTY_GETTER(audiomixer_mixer_voice_obj, //| def play( //| self, sample: circuitpython_typing.AudioSample, *, voice: int = 0, loop: bool = False -//| ) -> None: +//| ) -> Mixer: //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| @@ -189,7 +189,7 @@ static mp_obj_t audiomixer_mixer_obj_play(size_t n_args, const mp_obj_t *pos_arg mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiomixer_mixervoice_play(voice, sample, args[ARG_loop].u_bool); - return mp_const_none; + return pos_args[0]; } MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixer_play_obj, 1, audiomixer_mixer_obj_play); From 2e6dbaf5a00be4429592a8240c2f95c0e1add8ac Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 16 Sep 2025 10:09:22 -0500 Subject: [PATCH 44/78] Improve clarity of self reference --- shared-bindings/audiodelays/Chorus.c | 2 +- shared-bindings/audiodelays/Echo.c | 2 +- shared-bindings/audiodelays/MultiTapDelay.c | 2 +- shared-bindings/audiodelays/PitchShift.c | 2 +- shared-bindings/audiofilters/Distortion.c | 2 +- shared-bindings/audiofilters/Filter.c | 2 +- shared-bindings/audiofilters/Phaser.c | 2 +- shared-bindings/audiofreeverb/Freeverb.c | 2 +- shared-bindings/audiomixer/Mixer.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/shared-bindings/audiodelays/Chorus.c b/shared-bindings/audiodelays/Chorus.c index 67b9bc32745c4..94360ee558d5a 100644 --- a/shared-bindings/audiodelays/Chorus.c +++ b/shared-bindings/audiodelays/Chorus.c @@ -228,7 +228,7 @@ static mp_obj_t audiodelays_chorus_obj_play(size_t n_args, const mp_obj_t *pos_a mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_chorus_play(self, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_chorus_play_obj, 1, audiodelays_chorus_obj_play); diff --git a/shared-bindings/audiodelays/Echo.c b/shared-bindings/audiodelays/Echo.c index 68216d2355b70..273d0e8e18dcb 100644 --- a/shared-bindings/audiodelays/Echo.c +++ b/shared-bindings/audiodelays/Echo.c @@ -252,7 +252,7 @@ static mp_obj_t audiodelays_echo_obj_play(size_t n_args, const mp_obj_t *pos_arg mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_echo_play(self, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_echo_play_obj, 1, audiodelays_echo_obj_play); diff --git a/shared-bindings/audiodelays/MultiTapDelay.c b/shared-bindings/audiodelays/MultiTapDelay.c index ce11b2f1d3c61..75b029600a2c0 100644 --- a/shared-bindings/audiodelays/MultiTapDelay.c +++ b/shared-bindings/audiodelays/MultiTapDelay.c @@ -255,7 +255,7 @@ static mp_obj_t audiodelays_multi_tap_delay_obj_play(size_t n_args, const mp_obj mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_multi_tap_delay_play(self, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_multi_tap_delay_play_obj, 1, audiodelays_multi_tap_delay_obj_play); diff --git a/shared-bindings/audiodelays/PitchShift.c b/shared-bindings/audiodelays/PitchShift.c index e595beec6b8de..c8b4ea4b81c79 100644 --- a/shared-bindings/audiodelays/PitchShift.c +++ b/shared-bindings/audiodelays/PitchShift.c @@ -211,7 +211,7 @@ static mp_obj_t audiodelays_pitch_shift_obj_play(size_t n_args, const mp_obj_t * mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_pitch_shift_play(self, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_pitch_shift_play_obj, 1, audiodelays_pitch_shift_obj_play); diff --git a/shared-bindings/audiofilters/Distortion.c b/shared-bindings/audiofilters/Distortion.c index 3120111ca9a80..956a14e97e345 100644 --- a/shared-bindings/audiofilters/Distortion.c +++ b/shared-bindings/audiofilters/Distortion.c @@ -331,7 +331,7 @@ static mp_obj_t audiofilters_distortion_obj_play(size_t n_args, const mp_obj_t * mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_distortion_play(self, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_distortion_play_obj, 1, audiofilters_distortion_obj_play); diff --git a/shared-bindings/audiofilters/Filter.c b/shared-bindings/audiofilters/Filter.c index 2d8829d8a815d..d82208d11ed81 100644 --- a/shared-bindings/audiofilters/Filter.c +++ b/shared-bindings/audiofilters/Filter.c @@ -201,7 +201,7 @@ static mp_obj_t audiofilters_filter_obj_play(size_t n_args, const mp_obj_t *pos_ mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_filter_play(self, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_filter_play_obj, 1, audiofilters_filter_obj_play); diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c index daff50e983492..8472b01505cec 100644 --- a/shared-bindings/audiofilters/Phaser.c +++ b/shared-bindings/audiofilters/Phaser.c @@ -236,7 +236,7 @@ static mp_obj_t audiofilters_phaser_obj_play(size_t n_args, const mp_obj_t *pos_ mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_phaser_play(self, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_phaser_play_obj, 1, audiofilters_phaser_obj_play); diff --git a/shared-bindings/audiofreeverb/Freeverb.c b/shared-bindings/audiofreeverb/Freeverb.c index 5e4c9644d2e8d..de061734997a0 100644 --- a/shared-bindings/audiofreeverb/Freeverb.c +++ b/shared-bindings/audiofreeverb/Freeverb.c @@ -218,7 +218,7 @@ static mp_obj_t audiofreeverb_freeverb_obj_play(size_t n_args, const mp_obj_t *p mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofreeverb_freeverb_play(self, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiofreeverb_freeverb_play_obj, 1, audiofreeverb_freeverb_obj_play); diff --git a/shared-bindings/audiomixer/Mixer.c b/shared-bindings/audiomixer/Mixer.c index 0944f58ddbe45..5e5bfdc1f3df9 100644 --- a/shared-bindings/audiomixer/Mixer.c +++ b/shared-bindings/audiomixer/Mixer.c @@ -189,7 +189,7 @@ static mp_obj_t audiomixer_mixer_obj_play(size_t n_args, const mp_obj_t *pos_arg mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiomixer_mixervoice_play(voice, sample, args[ARG_loop].u_bool); - return pos_args[0]; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixer_play_obj, 1, audiomixer_mixer_obj_play); From 734209078660bc06103cb48eee460b1625323546 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 16 Sep 2025 10:15:47 -0500 Subject: [PATCH 45/78] Add return type documentation --- shared-bindings/audiodelays/Chorus.c | 6 +++++- shared-bindings/audiodelays/Echo.c | 6 +++++- shared-bindings/audiodelays/MultiTapDelay.c | 6 +++++- shared-bindings/audiodelays/PitchShift.c | 6 +++++- shared-bindings/audiofilters/Distortion.c | 6 +++++- shared-bindings/audiofilters/Filter.c | 6 +++++- shared-bindings/audiofilters/Phaser.c | 6 +++++- shared-bindings/audiofreeverb/Freeverb.c | 6 +++++- shared-bindings/audiomixer/Mixer.c | 6 +++++- 9 files changed, 45 insertions(+), 9 deletions(-) diff --git a/shared-bindings/audiodelays/Chorus.c b/shared-bindings/audiodelays/Chorus.c index 94360ee558d5a..87922ff110b1b 100644 --- a/shared-bindings/audiodelays/Chorus.c +++ b/shared-bindings/audiodelays/Chorus.c @@ -210,7 +210,11 @@ MP_PROPERTY_GETTER(audiodelays_chorus_playing_obj, //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| The sample must match the encoding settings given in the constructor.""" +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: Chorus""" //| ... //| static mp_obj_t audiodelays_chorus_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/audiodelays/Echo.c b/shared-bindings/audiodelays/Echo.c index 273d0e8e18dcb..dbb496c61b975 100644 --- a/shared-bindings/audiodelays/Echo.c +++ b/shared-bindings/audiodelays/Echo.c @@ -234,7 +234,11 @@ MP_PROPERTY_GETTER(audiodelays_echo_playing_obj, //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| The sample must match the encoding settings given in the constructor.""" +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: Echo""" //| ... //| static mp_obj_t audiodelays_echo_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/audiodelays/MultiTapDelay.c b/shared-bindings/audiodelays/MultiTapDelay.c index 75b029600a2c0..2126dbf990435 100644 --- a/shared-bindings/audiodelays/MultiTapDelay.c +++ b/shared-bindings/audiodelays/MultiTapDelay.c @@ -237,7 +237,11 @@ MP_PROPERTY_GETTER(audiodelays_multi_tap_delay_playing_obj, //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| The sample must match the encoding settings given in the constructor.""" +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: MultiTapDelay""" //| ... //| static mp_obj_t audiodelays_multi_tap_delay_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/audiodelays/PitchShift.c b/shared-bindings/audiodelays/PitchShift.c index c8b4ea4b81c79..b94df7d9edd08 100644 --- a/shared-bindings/audiodelays/PitchShift.c +++ b/shared-bindings/audiodelays/PitchShift.c @@ -194,7 +194,11 @@ MP_PROPERTY_GETTER(audiodelays_pitch_shift_playing_obj, //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| The sample must match the encoding settings given in the constructor.""" +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: PitchShift""" //| ... //| static mp_obj_t audiodelays_pitch_shift_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/audiofilters/Distortion.c b/shared-bindings/audiofilters/Distortion.c index 956a14e97e345..8de4c1d1ea331 100644 --- a/shared-bindings/audiofilters/Distortion.c +++ b/shared-bindings/audiofilters/Distortion.c @@ -313,7 +313,11 @@ MP_PROPERTY_GETTER(audiofilters_distortion_playing_obj, //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| The sample must match the encoding settings given in the constructor.""" +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: Distortion""" //| ... //| static mp_obj_t audiofilters_distortion_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/audiofilters/Filter.c b/shared-bindings/audiofilters/Filter.c index d82208d11ed81..426fff226168f 100644 --- a/shared-bindings/audiofilters/Filter.c +++ b/shared-bindings/audiofilters/Filter.c @@ -183,7 +183,11 @@ MP_PROPERTY_GETTER(audiofilters_filter_playing_obj, //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| The sample must match the encoding settings given in the constructor.""" +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: Filter""" //| ... //| static mp_obj_t audiofilters_filter_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c index 8472b01505cec..9f713afce5f72 100644 --- a/shared-bindings/audiofilters/Phaser.c +++ b/shared-bindings/audiofilters/Phaser.c @@ -218,7 +218,11 @@ MP_PROPERTY_GETTER(audiofilters_phaser_playing_obj, //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| The sample must match the encoding settings given in the constructor.""" +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: Phaser""" //| ... //| static mp_obj_t audiofilters_phaser_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/audiofreeverb/Freeverb.c b/shared-bindings/audiofreeverb/Freeverb.c index de061734997a0..12eb7ef70ab79 100644 --- a/shared-bindings/audiofreeverb/Freeverb.c +++ b/shared-bindings/audiofreeverb/Freeverb.c @@ -200,7 +200,11 @@ MP_PROPERTY_GETTER(audiofreeverb_freeverb_playing_obj, //| """Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| The sample must match the encoding settings given in the constructor.""" +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: Freeverb""" //| ... //| static mp_obj_t audiofreeverb_freeverb_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/audiomixer/Mixer.c b/shared-bindings/audiomixer/Mixer.c index 5e5bfdc1f3df9..516d079cd2a09 100644 --- a/shared-bindings/audiomixer/Mixer.c +++ b/shared-bindings/audiomixer/Mixer.c @@ -166,7 +166,11 @@ MP_PROPERTY_GETTER(audiomixer_mixer_voice_obj, //| //| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. //| -//| The sample must match the Mixer's encoding settings given in the constructor.""" +//| The sample must match the Mixer's encoding settings given in the constructor. +//| +//| :return: The mixer object itself. Can be used for chaining, ie: +//| ``audio.play(mixer.play(sample))``. +//| :rtype: Chorus""" //| ... //| static mp_obj_t audiomixer_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { From 9f771b37ba6ca319828c98f4793618cebece32dc Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 19 Sep 2025 11:08:04 -0700 Subject: [PATCH 46/78] Free dma capable temporary buffer immediately This reduces memory use and prevents long term fragmentation. --- shared-module/usb/core/Device.c | 98 +++++++++++++++++++-------------- shared-module/usb/core/Device.h | 4 -- 2 files changed, 56 insertions(+), 46 deletions(-) diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index c4342e10d1d65..83def37de914e 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -43,30 +43,19 @@ static uint8_t *_ensure_dma_buffer(usb_core_device_obj_t *self, const uint8_t *b return (uint8_t *)buffer; // Already DMA-capable, use directly } - // Need to allocate/reallocate temporary buffer in DMA-capable memory - if (self->temp_buffer_size < len) { - self->temp_buffer = port_realloc(self->temp_buffer, len, true); // true = DMA capable - if (self->temp_buffer == NULL) { - self->temp_buffer_size = 0; - return NULL; // Allocation failed - } - self->temp_buffer_size = len; + uint8_t *dma_buffer = port_malloc(len, true); // true = DMA capable + if (dma_buffer == NULL) { + return NULL; // Allocation failed } // Copy data to DMA buffer if writing if (for_write && buffer != NULL) { - memcpy(self->temp_buffer, buffer, len); + memcpy(dma_buffer, buffer, len); } - return self->temp_buffer; + return dma_buffer; } -// Copy data back from DMA buffer to original buffer after read -static void _copy_from_dma_buffer(usb_core_device_obj_t *self, uint8_t *original_buffer, size_t len) { - if (!port_buffer_is_dma_capable(original_buffer) && self->temp_buffer != NULL) { - memcpy(original_buffer, self->temp_buffer, len); - } -} #endif bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_address) { if (!tuh_inited()) { @@ -81,10 +70,6 @@ bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t d } self->device_address = device_address; self->first_langid = 0; - #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE - self->temp_buffer = NULL; - self->temp_buffer_size = 0; - #endif _xfer_result = XFER_RESULT_INVALID; return true; } @@ -104,14 +89,6 @@ void common_hal_usb_core_device_deinit(usb_core_device_obj_t *self) { self->open_endpoints[i] = 0; } } - #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE - // Clean up temporary buffer - if (self->temp_buffer != NULL) { - port_free(self->temp_buffer); - self->temp_buffer = NULL; - self->temp_buffer_size = 0; - } - #endif self->device_address = 0; } @@ -180,7 +157,24 @@ static void _prepare_for_transfer(void) { _actual_len = 0; } -static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout) { +static void _abort_transfer(tuh_xfer_t *xfer) { + bool aborted = tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); + if (aborted) { + // If the transfer was aborted, then we can continue. + return; + } + uint32_t start_time = supervisor_ticks_ms32(); + // If not, we need to wait for it to finish, otherwise we may free memory out from under it. + // Limit the wait time to 10 milliseconds to avoid blocking indefinitely. + while (_xfer_result == XFER_RESULT_INVALID && (supervisor_ticks_ms32() - start_time < 10)) { + // The background tasks include TinyUSB which will call the function + // we provided above. In other words, the callback isn't in an interrupt. + RUN_BACKGROUND_TASKS; + } +} + +// Only frees the transfer buffer on error. +static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer) { if (xfer == NULL) { mp_raise_usb_core_USBError(NULL); return 0; @@ -195,12 +189,15 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout } if (mp_hal_is_interrupted()) { // Handle case of VM being interrupted by Ctrl-C or autoreload - tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); + _abort_transfer(xfer); return 0; } // Handle transfer result code from TinyUSB xfer_result_t result = _xfer_result; _xfer_result = XFER_RESULT_INVALID; + if (our_buffer && result != XFER_RESULT_SUCCESS && result != XFER_RESULT_INVALID) { + port_free(xfer->buffer); + } switch (result) { case XFER_RESULT_SUCCESS: return _actual_len; @@ -217,8 +214,11 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout break; case XFER_RESULT_INVALID: // This timeout comes from CircuitPython, not TinyUSB, so tell TinyUSB - // to stop the transfer - tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); + // to stop the transfer and then wait to free the buffer. + _abort_transfer(xfer); + if (our_buffer) { + port_free(xfer->buffer); + } mp_raise_usb_core_USBTimeoutError(); break; } @@ -382,14 +382,18 @@ void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, m _wait_for_callback(); } -static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout) { +// Raises an exception on failure. Returns the number of bytes transferred (maybe zero) on success. +static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer) { _prepare_for_transfer(); xfer->complete_cb = _transfer_done_cb; if (!tuh_edpt_xfer(xfer)) { + if (our_buffer) { + port_free(xfer->buffer); + } mp_raise_usb_core_USBError(NULL); return 0; } - return _handle_timed_transfer_callback(xfer, timeout); + return _handle_timed_transfer_callback(xfer, timeout, our_buffer); } static bool _open_endpoint(usb_core_device_obj_t *self, mp_int_t endpoint) { @@ -463,7 +467,13 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t xfer.ep_addr = endpoint; xfer.buffer = dma_buffer; xfer.buflen = len; - return _xfer(&xfer, timeout); + size_t result = _xfer(&xfer, timeout, dma_buffer != buffer); + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + if (dma_buffer != buffer) { + port_free(dma_buffer); + } + #endif + return result; } mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout) { @@ -488,12 +498,13 @@ mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t e xfer.ep_addr = endpoint; xfer.buffer = dma_buffer; xfer.buflen = len; - mp_int_t result = _xfer(&xfer, timeout); + mp_int_t result = _xfer(&xfer, timeout, dma_buffer != buffer); #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE // Copy data back to original buffer if needed - if (result > 0) { - _copy_from_dma_buffer(self, buffer, result); + if (dma_buffer != buffer) { + memcpy(buffer, dma_buffer, result); + port_free(dma_buffer); } #endif @@ -543,12 +554,15 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, mp_raise_usb_core_USBError(NULL); return 0; } - mp_int_t result = (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout); + mp_int_t result = (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout, dma_buffer != buffer); #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE - // Copy data back to original buffer if this was a read transfer and we got data - if ((bmRequestType & 0x80) != 0 && result > 0 && buffer != NULL) { // Read transfer (device-to-host) - _copy_from_dma_buffer(self, buffer, result); + if (dma_buffer != buffer) { + // Copy data back to original buffer if this was a read transfer + if (buffer != NULL && !is_write) { + memcpy(buffer, dma_buffer, result); + } + port_free(dma_buffer); } #endif diff --git a/shared-module/usb/core/Device.h b/shared-module/usb/core/Device.h index 8737eeaf86bf7..c7392a04ba7bc 100644 --- a/shared-module/usb/core/Device.h +++ b/shared-module/usb/core/Device.h @@ -15,8 +15,4 @@ typedef struct { uint8_t *configuration_descriptor; // Contains the length of the all descriptors. uint8_t open_endpoints[8]; uint16_t first_langid; - #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE - uint8_t *temp_buffer; // Temporary buffer for PSRAM data - size_t temp_buffer_size; // Size of temporary buffer - #endif } usb_core_device_obj_t; From 9d006d42604eaffc2782389f34287eeea5f9ef13 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Mon, 22 Sep 2025 19:40:55 +0200 Subject: [PATCH 47/78] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 4 ++++ locale/el.po | 4 ++++ locale/hi.po | 4 ++++ locale/ko.po | 4 ++++ locale/ru.po | 4 ++++ locale/tr.po | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/locale/cs.po b/locale/cs.po index 67ece22664d76..eab928c2aaaf6 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -861,6 +861,10 @@ msgstr "Pole souřadnic mají různé délky" msgid "Coordinate arrays types have different sizes" msgstr "" +#: shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" diff --git a/locale/el.po b/locale/el.po index 9e31051bcc03b..871ce82f6725c 100644 --- a/locale/el.po +++ b/locale/el.po @@ -867,6 +867,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index 7ab47ff0953b5..f8408f6c119a5 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -846,6 +846,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 30205cad930e0..4a74ec9003488 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -890,6 +890,10 @@ msgstr "좌표 배열의 길이가 다릅니다" msgid "Coordinate arrays types have different sizes" msgstr "좌표 배열 유형은 크기가 다릅니다" +#: shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 49fb1eccdedef..24b880972cb42 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -870,6 +870,10 @@ msgstr "Координатные массивы имеют разные длин msgid "Coordinate arrays types have different sizes" msgstr "Типы массивов координат имеют разные размеры" +#: shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" diff --git a/locale/tr.po b/locale/tr.po index 1bb304eaba6ca..f51ad3e8c12ee 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -860,6 +860,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" From 493f078739d1e5ce93dfc5ef9d0a52a29c63b4ba Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Thu, 26 Dec 2024 13:25:26 -0800 Subject: [PATCH 48/78] Setup files for busio --- ports/analog/common-hal/busio/I2C.c | 210 ++++++++++++++++++ ports/analog/common-hal/busio/I2C.h | 24 ++ ports/analog/common-hal/busio/SPI.c | 254 ++++++++++++++++++++++ ports/analog/common-hal/busio/SPI.h | 35 +++ ports/analog/common-hal/busio/UART.c | 76 +++++++ ports/analog/common-hal/busio/UART.h | 31 +++ ports/analog/common-hal/busio/__init__.c | 5 + ports/analog/peripherals/max32690/gpios.h | 2 + 8 files changed, 637 insertions(+) create mode 100644 ports/analog/common-hal/busio/I2C.c create mode 100644 ports/analog/common-hal/busio/I2C.h create mode 100644 ports/analog/common-hal/busio/SPI.c create mode 100644 ports/analog/common-hal/busio/SPI.h create mode 100644 ports/analog/common-hal/busio/UART.c create mode 100644 ports/analog/common-hal/busio/UART.h create mode 100644 ports/analog/common-hal/busio/__init__.c diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c new file mode 100644 index 0000000000000..ae18f561c502f --- /dev/null +++ b/ports/analog/common-hal/busio/I2C.c @@ -0,0 +1,210 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * 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 "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" + +static I2CSPM_Init_TypeDef i2cspm_init; +static bool in_used = false; + +// Construct I2C protocol, this function init i2c peripheral +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, + const mcu_pin_obj_t *scl, + const mcu_pin_obj_t *sda, + uint32_t frequency, uint32_t timeout) { + + // Ensure the object starts in its deinit state. + common_hal_busio_i2c_mark_deinit(self); + + if ((scl != NULL) && (sda != NULL)) { + if (scl->function_list[ DEFAULT_I2C_PERIPHERAL == I2C1? + FN_I2C1_SCL : FN_I2C0_SCL] == 1 && + scl->function_list[DEFAULT_I2C_PERIPHERAL == I2C1? + FN_I2C1_SDA : FN_I2C0_SDA] == 1) { + self->scl = scl; + self->sda = sda; + self->has_lock = false; + i2cspm_init.sclPort = self->scl->port; + i2cspm_init.sclPin = self->scl->number; + i2cspm_init.sdaPort = self->sda->port; + i2cspm_init.sdaPin = self->sda->number; + i2cspm_init.port = DEFAULT_I2C_PERIPHERAL; + i2cspm_init.i2cRefFreq = 0; + i2cspm_init.i2cMaxFreq = I2C_FREQ_STANDARD_MAX; + i2cspm_init.i2cClhr = i2cClockHLRStandard; + + self->i2cspm = i2cspm_init.port; + I2CSPM_Init(&i2cspm_init); + common_hal_mcu_pin_claim(scl); + common_hal_mcu_pin_claim(sda); + in_used = true; + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); + } + } else { + raise_ValueError_invalid_pins(); + } +} + +// Never reset I2C obj when reload +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + common_hal_never_reset_pin(self->sda); + common_hal_never_reset_pin(self->scl); +} + +// Check I2C status, deinited or not +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + return self->sda == NULL; +} + +// Deinit i2c obj, reset I2C pin +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } + I2C_Reset(self->i2cspm); + common_hal_reset_pin(self->sda); + common_hal_reset_pin(self->scl); + self->i2cspm = NULL; + in_used = false; + common_hal_busio_i2c_mark_deinit(self); +} + +void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { + self->sda = NULL; +} + +// Probe device in I2C bus +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + I2C_TransferSeq_TypeDef seq; + I2C_TransferReturn_TypeDef ret; + uint8_t data = 0; + + seq.addr = addr << 1; + seq.flags = I2C_FLAG_READ; + + seq.buf[0].data = &data; + seq.buf[0].len = 1; + + ret = I2CSPM_Transfer(self->i2cspm, &seq); + if (ret != i2cTransferDone) { + return false; + } + return true; +} + +// Lock I2C bus +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return false; + } + bool grabbed_lock = false; + + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + + return grabbed_lock; +} + +// Check I2C lock status +bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { + return self->has_lock; +} + +// Unlock I2C bus +void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + self->has_lock = false; +} + +// Write data to the device selected by address +uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, + const uint8_t *data, size_t len) { + + I2C_TransferSeq_TypeDef seq; + I2C_TransferReturn_TypeDef ret; + + seq.addr = addr << 1; + seq.flags = I2C_FLAG_WRITE; + + seq.buf[0].data = (uint8_t *)data; + seq.buf[0].len = len; + + ret = I2CSPM_Transfer(self->i2cspm, &seq); + if (ret != i2cTransferDone) { + return MP_EIO; + } + return 0; +} + +// Read into buffer from the device selected by address +uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, + uint16_t addr, + uint8_t *data, size_t len) { + + I2C_TransferSeq_TypeDef seq; + I2C_TransferReturn_TypeDef ret; + + seq.addr = addr << 1; + seq.flags = I2C_FLAG_READ; + + seq.buf[0].data = data; + seq.buf[0].len = len; + + ret = I2CSPM_Transfer(self->i2cspm, &seq); + if (ret != i2cTransferDone) { + return MP_EIO; + } + return 0; +} + +// Write the bytes from out_data to the device selected by address, +uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, + uint8_t *out_data, size_t out_len, + uint8_t *in_data, size_t in_len) { + + I2C_TransferSeq_TypeDef seq; + I2C_TransferReturn_TypeDef ret; + + seq.addr = addr << 1; + seq.flags = I2C_FLAG_WRITE_READ; + // Select command to issue + seq.buf[0].data = out_data; + seq.buf[0].len = out_len; + // Select location/length of data to be read + seq.buf[1].data = in_data; + seq.buf[1].len = in_len; + + ret = I2CSPM_Transfer(self->i2cspm, &seq); + if (ret != i2cTransferDone) { + return MP_EIO; + } + return 0; +} diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h new file mode 100644 index 0000000000000..c92283d6c53b6 --- /dev/null +++ b/ports/analog/common-hal/busio/I2C.h @@ -0,0 +1,24 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +// FIXME: Silabs includes "peripherals/periph.h. Figure out what's in this file. " +#include "py/obj.h" + +// HAL-specific +#include "i2c.h" +#include "gpio.h" + +// Define a struct for what BUSIO.I2C should carry +typedef struct { + mp_obj_base_t base; + mxc_i2c_regs_t* i2c_regs; + bool has_lock; + const mcu_pin_obj_t *scl; + const mcu_pin_obj_t *sda; +} busio_i2c_obj_t; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c new file mode 100644 index 0000000000000..74cfc69bfb2a0 --- /dev/null +++ b/ports/analog/common-hal/busio/SPI.c @@ -0,0 +1,254 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * 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 "shared-bindings/busio/SPI.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "supervisor/board.h" +#include "shared-bindings/microcontroller/Pin.h" + +// Note that any bugs introduced in this file can cause crashes +// at startupfor chips using external SPI flash. + +static SPIDRV_HandleData_t spidrv_eusart_handle; +static SPIDRV_Init_t spidrv_eusart_init = SPIDRV_MASTER_EUSART1; +static bool in_used = false; +static bool never_reset = false; + +// Reset SPI when reload +void spi_reset(void) { + if (!never_reset && in_used) { + SPIDRV_DeInit(&spidrv_eusart_handle); + in_used = false; + } + return; +} + +// Construct SPI protocol, this function init SPI peripheral +void common_hal_busio_spi_construct(busio_spi_obj_t *self, + const mcu_pin_obj_t *sck, + const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso, + bool half_duplex) { + Ecode_t sc = ECODE_OK; + + if (half_duplex) { + mp_raise_NotImplementedError( + MP_ERROR_TEXT("Half duplex SPI is not implemented")); + } + + if ((sck != NULL) && (mosi != NULL) && (miso != NULL)) { + if (sck->function_list[FN_EUSART1_SCLK] == 1 + && miso->function_list[FN_EUSART1_RX] == 1 + && mosi->function_list[FN_EUSART1_TX] == 1) { + + self->sck = sck; + self->mosi = mosi; + self->miso = miso; + self->handle = &spidrv_eusart_handle; + self->polarity = 0; + self->phase = 0; + self->bits = 8; + + spidrv_eusart_init.portTx = mosi->port; + spidrv_eusart_init.portRx = miso->port; + spidrv_eusart_init.portClk = sck->port; + spidrv_eusart_init.pinTx = mosi->number; + spidrv_eusart_init.pinRx = miso->number; + spidrv_eusart_init.pinClk = sck->number; + spidrv_eusart_init.bitRate = 1000000; + spidrv_eusart_init.frameLength = 8; + spidrv_eusart_init.dummyTxValue = 0; + spidrv_eusart_init.type = spidrvMaster; + spidrv_eusart_init.bitOrder = spidrvBitOrderMsbFirst; + spidrv_eusart_init.clockMode = spidrvClockMode0; + spidrv_eusart_init.csControl = spidrvCsControlApplication; + spidrv_eusart_init.slaveStartMode = spidrvSlaveStartImmediate; + + sc = SPIDRV_Init(self->handle, &spidrv_eusart_init); + if (sc != ECODE_EMDRV_SPIDRV_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("SPI init error")); + } + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); + } + } else { + raise_ValueError_invalid_pins(); + } + + in_used = true; + common_hal_mcu_pin_claim(sck); + common_hal_mcu_pin_claim(mosi); + common_hal_mcu_pin_claim(miso); +} + +// Never reset SPI when reload +void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { + never_reset = true; + common_hal_never_reset_pin(self->mosi); + common_hal_never_reset_pin(self->miso); + common_hal_never_reset_pin(self->sck); +} + +// Check SPI status, deinited or not +bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { + return self->sck == NULL; +} + +// Deinit SPI obj +void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { + + if (common_hal_busio_spi_deinited(self)) { + return; + } + + Ecode_t sc = SPIDRV_DeInit(self->handle); + if (sc != ECODE_EMDRV_SPIDRV_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); + } + + in_used = false; + self->sck = NULL; + self->mosi = NULL; + self->miso = NULL; + self->handle = NULL; + common_hal_reset_pin(self->mosi); + common_hal_reset_pin(self->miso); + common_hal_reset_pin(self->sck); +} + +// Configures the SPI bus. The SPI object must be locked. +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, + uint32_t baudrate, + uint8_t polarity, + uint8_t phase, + uint8_t bits) { + Ecode_t sc; + // This resets the SPI, so check before updating it redundantly + if (baudrate == self->baudrate && polarity == self->polarity + && phase == self->phase && bits == self->bits) { + return true; + } + + sc = SPIDRV_DeInit(self->handle); + if (sc != ECODE_EMDRV_SPIDRV_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); + } + in_used = false; + self->baudrate = baudrate; + self->phase = phase; + self->bits = bits; + self->polarity = polarity; + + spidrv_eusart_init.bitRate = baudrate; + spidrv_eusart_init.frameLength = 8; + if (polarity == 0 && phase == 0) { + spidrv_eusart_init.clockMode = spidrvClockMode0; + } else if (polarity == 0 && phase == 1) { + spidrv_eusart_init.clockMode = spidrvClockMode1; + } else if (polarity == 1 && phase == 0) { + spidrv_eusart_init.clockMode = spidrvClockMode2; + } else if (polarity == 1 && phase == 1) { + spidrv_eusart_init.clockMode = spidrvClockMode3; + } + + sc = SPIDRV_Init(self->handle, &spidrv_eusart_init); + if (sc != ECODE_EMDRV_SPIDRV_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); + } + in_used = true; + return true; +} + +// Lock SPI bus +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + + return grabbed_lock; +} + +// Check SPI lock status +bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { + return self->has_lock; +} + +// Unlock SPI bus +void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + self->has_lock = false; +} + +// Write the data contained in buffer +bool common_hal_busio_spi_write(busio_spi_obj_t *self, + const uint8_t *data, + size_t len) { + + Ecode_t result = SPIDRV_MTransmitB(self->handle, data, len); + return result == ECODE_EMDRV_SPIDRV_OK; +} + +// Read data into buffer +bool common_hal_busio_spi_read(busio_spi_obj_t *self, + uint8_t *data, size_t len, + uint8_t write_value) { + + self->handle->initData.dummyTxValue = write_value; + Ecode_t result = SPIDRV_MReceiveB(self->handle, data, len); + return result == ECODE_EMDRV_SPIDRV_OK; +} + +// Write out the data in data_out +// while simultaneously reading data into data_in +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, + const uint8_t *data_out, + uint8_t *data_in, + size_t len) { + + Ecode_t result = SPIDRV_MTransferB(self->handle, data_out, data_in, len); + return result == ECODE_EMDRV_SPIDRV_OK; +} + +// Get SPI baudrate +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) { + return self->baudrate; +} + +// Get SPI phase +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self) { + return self->phase; +} + +// Get SPI polarity +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { + return self->polarity; +} diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h new file mode 100644 index 0000000000000..8c48147ff6c77 --- /dev/null +++ b/ports/analog/common-hal/busio/SPI.h @@ -0,0 +1,35 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H +#define MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H + +#include "common-hal/microcontroller/Pin.h" +// FIXME: Silabs includes "peripherals/periph.h. Figure out what's in this file. " +#include "py/obj.h" + +// HAL-specific +#include "spi.h" + +// Define a struct for what BUSIO.SPI should carry +typedef struct { + mp_obj_base_t base; + mxc_spi_regs_t* spi_regs; + bool has_lock; + const mcu_pin_obj_t *sck; + const mcu_pin_obj_t *mosi; + const mcu_pin_obj_t *miso; + const mcu_pin_obj_t *nss; + uint32_t baudrate; + uint16_t prescaler; + uint8_t polarity; + uint8_t phase; + uint8_t bits; +} busio_spi_obj_t; + +void spi_reset(void); + +#endif // MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c new file mode 100644 index 0000000000000..6d1507b78c696 --- /dev/null +++ b/ports/analog/common-hal/busio/UART.c @@ -0,0 +1,76 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * 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 "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/UART.h" + +#include "mpconfigport.h" +#include "shared/readline/readline.h" +#include "shared/runtime/interrupt_char.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "uart.h" +#include "UART.h" + +typedef enum { + BUSIO_UART_PARITY_NONE, + BUSIO_UART_PARITY_EVEN, + BUSIO_UART_PARITY_ODD +} busio_uart_parity_t; + +// Construct an underlying UART object. +extern void common_hal_busio_uart_construct(busio_uart_obj_t *self, + const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, + const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, + const mcu_pin_obj_t *rs485_dir, bool rs485_invert, + uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, + mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, + bool sigint_enabled); + +extern void common_hal_busio_uart_deinit(busio_uart_obj_t *self); +extern bool common_hal_busio_uart_deinited(busio_uart_obj_t *self); + +// Read characters. len is in characters NOT bytes! +extern size_t common_hal_busio_uart_read(busio_uart_obj_t *self, + uint8_t *data, size_t len, int *errcode); + +// Write characters. len is in characters NOT bytes! +extern size_t common_hal_busio_uart_write(busio_uart_obj_t *self, + const uint8_t *data, size_t len, int *errcode); + +extern uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self); +extern void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate); +extern mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self); +extern void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout); + +extern uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self); +extern void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self); +extern bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self); + +extern void common_hal_busio_uart_never_reset(busio_uart_obj_t *self); diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h new file mode 100644 index 0000000000000..a8d294de222d3 --- /dev/null +++ b/ports/analog/common-hal/busio/UART.h @@ -0,0 +1,31 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H +#define MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H + +#include "common-hal/microcontroller/Pin.h" +#include "peripherals/periph.h" +#include "py/obj.h" +#include "py/ringbuf.h" + +#include "uart.h" + +// Define a struct for what BUSIO.UART should contain +typedef struct { + mp_obj_base_t base; + mxc_uart_regs_t* uart_regs; + const mcu_pin_obj_t *rx; + const mcu_pin_obj_t *tx; + uint32_t baudrate; + bool parity; + uint8_t stop_bits; + uint8_t bits; +} busio_uart_obj_t; + +void uart_reset(void); + +#endif // MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H diff --git a/ports/analog/common-hal/busio/__init__.c b/ports/analog/common-hal/busio/__init__.c new file mode 100644 index 0000000000000..ff05be051bb25 --- /dev/null +++ b/ports/analog/common-hal/busio/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT diff --git a/ports/analog/peripherals/max32690/gpios.h b/ports/analog/peripherals/max32690/gpios.h index 4677bf8f33dbe..fe91227728291 100644 --- a/ports/analog/peripherals/max32690/gpios.h +++ b/ports/analog/peripherals/max32690/gpios.h @@ -4,6 +4,8 @@ // // SPDX-License-Identifier: MIT +#pragma once + #include "py/obj.h" #include "py/mphal.h" From f4c21716f5385b62a4400312c8de53abc195ab00 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 14 Jan 2025 15:19:04 -0800 Subject: [PATCH 49/78] Add default build for analog ports for apard32690 board. --- Makefile | 3 +++ ports/analog/Makefile | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f2fc070a6331d..c2aebc61f1c0b 100644 --- a/Makefile +++ b/Makefile @@ -299,6 +299,9 @@ update-frozen-libraries: one-of-each: samd21 litex mimxrt10xx nordic stm +analog: + $(MAKE) -C ports/analog/ BOARD=apard32690 + samd21: $(MAKE) -C ports/atmel-samd BOARD=trinket_m0 diff --git a/ports/analog/Makefile b/ports/analog/Makefile index ce9082c5e255a..96f9037aae924 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -6,12 +6,13 @@ # # SPDX-License-Identifier: MIT +BOARD ?= apard32690 +CROSS_COMPILE = arm-none-eabi- + # Includes mpconfigboard.mk & mpconfigport.mk, # along with numerous other shared environment makefiles. include ../../py/circuitpy_mkenv.mk -CROSS_COMPILE = arm-none-eabi- - # MCU_SERIES e.g. "max32" # MCU_VARIANT e.g. "max32690" # defined in mpconfigboard.mk @@ -20,6 +21,7 @@ MCU_SERIES_UPPER := $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') MCU_VARIANT_LOWER := $(shell echo $(MCU_VARIANT) | tr '[:upper:]' '[:lower:]') MCU_VARIANT_UPPER := $(shell echo $(MCU_VARIANT) | tr '[:lower:]' '[:upper:]') + # ******************************************************************************* #### MSDK INCLUDES #### # Necessary for msdk makefiles @@ -59,6 +61,7 @@ DIE_TYPE=me18 endif PERIPH_SRC = $(ADI_PERIPH)/Source +PERIPH_INC = $(ADI_PERIPH)/Include/$(MCU_VARIANT_UPPER) INC += -I. INC += -I../.. @@ -75,7 +78,7 @@ INC += \ -I$(TOP)/lib/cmsis/inc \ -I$(CMSIS_ROOT)/Include \ -I$(CMSIS_ROOT)/Device/Maxim/$(MCU_VARIANT_UPPER)/Include \ - -I$(ADI_PERIPH)/Include/$(MCU_VARIANT_UPPER) \ + -I$(PERIPH_INC) \ -I$(PERIPH_SRC)/SYS \ -I$(PERIPH_SRC)/CTB \ -I$(PERIPH_SRC)/DMA \ @@ -126,7 +129,8 @@ SRC_C += $(SRC_MAX32) \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/pins.c \ - peripherals/$(MCU_VARIANT_LOWER)/gpios.c + peripherals/$(MCU_VARIANT_LOWER)/gpios.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c # ******************************************************************************* ### Compiler & Linker Flags ### From 1380af79aae33182845c869e0a7c40829bf0d315 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 14 Jan 2025 15:22:10 -0800 Subject: [PATCH 50/78] Add preliminary busio.UART support - Enabled BUSIO in mpconfigport.mk - Stubs added for busio.I2C & busio.SPI - Implemented busio.UART to basic working functionality - Added MCU-specific UART data in peripherals//max32_uart.c & max32_uart.h - Still have a couple issues where UART generates garbage characters or does not respond to timeouts / generate asynchronous IRQs --- ports/analog/common-hal/busio/I2C.c | 116 +---- ports/analog/common-hal/busio/SPI.c | 147 +------ ports/analog/common-hal/busio/UART.c | 406 +++++++++++++++++- ports/analog/common-hal/busio/UART.h | 33 +- ports/analog/max32_port.h | 52 +-- ports/analog/mpconfigport.mk | 3 +- .../analog/peripherals/max32690/max32_uart.c | 47 ++ .../analog/peripherals/max32690/max32_uart.h | 16 + 8 files changed, 527 insertions(+), 293 deletions(-) create mode 100644 ports/analog/peripherals/max32690/max32_uart.c create mode 100644 ports/analog/peripherals/max32690/max32_uart.h diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index ae18f561c502f..a8080fa5bc10d 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -30,7 +30,6 @@ #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -static I2CSPM_Init_TypeDef i2cspm_init; static bool in_used = false; // Construct I2C protocol, this function init i2c peripheral @@ -39,37 +38,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - // Ensure the object starts in its deinit state. - common_hal_busio_i2c_mark_deinit(self); - - if ((scl != NULL) && (sda != NULL)) { - if (scl->function_list[ DEFAULT_I2C_PERIPHERAL == I2C1? - FN_I2C1_SCL : FN_I2C0_SCL] == 1 && - scl->function_list[DEFAULT_I2C_PERIPHERAL == I2C1? - FN_I2C1_SDA : FN_I2C0_SDA] == 1) { - self->scl = scl; - self->sda = sda; - self->has_lock = false; - i2cspm_init.sclPort = self->scl->port; - i2cspm_init.sclPin = self->scl->number; - i2cspm_init.sdaPort = self->sda->port; - i2cspm_init.sdaPin = self->sda->number; - i2cspm_init.port = DEFAULT_I2C_PERIPHERAL; - i2cspm_init.i2cRefFreq = 0; - i2cspm_init.i2cMaxFreq = I2C_FREQ_STANDARD_MAX; - i2cspm_init.i2cClhr = i2cClockHLRStandard; - - self->i2cspm = i2cspm_init.port; - I2CSPM_Init(&i2cspm_init); - common_hal_mcu_pin_claim(scl); - common_hal_mcu_pin_claim(sda); - in_used = true; - } else { - mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); - } - } else { - raise_ValueError_invalid_pins(); - } + } // Never reset I2C obj when reload @@ -85,53 +54,26 @@ bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { // Deinit i2c obj, reset I2C pin void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { - if (common_hal_busio_i2c_deinited(self)) { - return; - } - I2C_Reset(self->i2cspm); - common_hal_reset_pin(self->sda); - common_hal_reset_pin(self->scl); - self->i2cspm = NULL; - in_used = false; - common_hal_busio_i2c_mark_deinit(self); + // FIXME: Implement } void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { - self->sda = NULL; + // FIXME: Implement } // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - I2C_TransferSeq_TypeDef seq; - I2C_TransferReturn_TypeDef ret; - uint8_t data = 0; - - seq.addr = addr << 1; - seq.flags = I2C_FLAG_READ; - - seq.buf[0].data = &data; - seq.buf[0].len = 1; + // FIXME: Implement - ret = I2CSPM_Transfer(self->i2cspm, &seq); - if (ret != i2cTransferDone) { - return false; - } return true; } // Lock I2C bus bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { - if (common_hal_busio_i2c_deinited(self)) { - return false; - } - bool grabbed_lock = false; - if (!self->has_lock) { - grabbed_lock = true; - self->has_lock = true; - } + // FIXME: Implement - return grabbed_lock; + return false; } // Check I2C lock status @@ -148,19 +90,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { - I2C_TransferSeq_TypeDef seq; - I2C_TransferReturn_TypeDef ret; - - seq.addr = addr << 1; - seq.flags = I2C_FLAG_WRITE; - - seq.buf[0].data = (uint8_t *)data; - seq.buf[0].len = len; - - ret = I2CSPM_Transfer(self->i2cspm, &seq); - if (ret != i2cTransferDone) { - return MP_EIO; - } + // FIXME: Implement return 0; } @@ -169,19 +99,7 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - I2C_TransferSeq_TypeDef seq; - I2C_TransferReturn_TypeDef ret; - - seq.addr = addr << 1; - seq.flags = I2C_FLAG_READ; - - seq.buf[0].data = data; - seq.buf[0].len = len; - - ret = I2CSPM_Transfer(self->i2cspm, &seq); - if (ret != i2cTransferDone) { - return MP_EIO; - } + // FIXME: Implement return 0; } @@ -190,21 +108,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - I2C_TransferSeq_TypeDef seq; - I2C_TransferReturn_TypeDef ret; - - seq.addr = addr << 1; - seq.flags = I2C_FLAG_WRITE_READ; - // Select command to issue - seq.buf[0].data = out_data; - seq.buf[0].len = out_len; - // Select location/length of data to be read - seq.buf[1].data = in_data; - seq.buf[1].len = in_len; - - ret = I2CSPM_Transfer(self->i2cspm, &seq); - if (ret != i2cTransferDone) { - return MP_EIO; - } + // FIXME: Implement + return 0; } diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 74cfc69bfb2a0..083403b12bbe3 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -34,17 +34,9 @@ // Note that any bugs introduced in this file can cause crashes // at startupfor chips using external SPI flash. -static SPIDRV_HandleData_t spidrv_eusart_handle; -static SPIDRV_Init_t spidrv_eusart_init = SPIDRV_MASTER_EUSART1; -static bool in_used = false; -static bool never_reset = false; - // Reset SPI when reload void spi_reset(void) { - if (!never_reset && in_used) { - SPIDRV_DeInit(&spidrv_eusart_handle); - in_used = false; - } + // FIXME: Implement return; } @@ -54,64 +46,14 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { - Ecode_t sc = ECODE_OK; - - if (half_duplex) { - mp_raise_NotImplementedError( - MP_ERROR_TEXT("Half duplex SPI is not implemented")); - } - - if ((sck != NULL) && (mosi != NULL) && (miso != NULL)) { - if (sck->function_list[FN_EUSART1_SCLK] == 1 - && miso->function_list[FN_EUSART1_RX] == 1 - && mosi->function_list[FN_EUSART1_TX] == 1) { - - self->sck = sck; - self->mosi = mosi; - self->miso = miso; - self->handle = &spidrv_eusart_handle; - self->polarity = 0; - self->phase = 0; - self->bits = 8; - - spidrv_eusart_init.portTx = mosi->port; - spidrv_eusart_init.portRx = miso->port; - spidrv_eusart_init.portClk = sck->port; - spidrv_eusart_init.pinTx = mosi->number; - spidrv_eusart_init.pinRx = miso->number; - spidrv_eusart_init.pinClk = sck->number; - spidrv_eusart_init.bitRate = 1000000; - spidrv_eusart_init.frameLength = 8; - spidrv_eusart_init.dummyTxValue = 0; - spidrv_eusart_init.type = spidrvMaster; - spidrv_eusart_init.bitOrder = spidrvBitOrderMsbFirst; - spidrv_eusart_init.clockMode = spidrvClockMode0; - spidrv_eusart_init.csControl = spidrvCsControlApplication; - spidrv_eusart_init.slaveStartMode = spidrvSlaveStartImmediate; - - sc = SPIDRV_Init(self->handle, &spidrv_eusart_init); - if (sc != ECODE_EMDRV_SPIDRV_OK) { - mp_raise_ValueError(MP_ERROR_TEXT("SPI init error")); - } - } else { - mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); - } - } else { - raise_ValueError_invalid_pins(); - } - - in_used = true; - common_hal_mcu_pin_claim(sck); - common_hal_mcu_pin_claim(mosi); - common_hal_mcu_pin_claim(miso); + + + // FIXME: Implement } // Never reset SPI when reload void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset = true; - common_hal_never_reset_pin(self->mosi); - common_hal_never_reset_pin(self->miso); - common_hal_never_reset_pin(self->sck); + // FIXME: Implement } // Check SPI status, deinited or not @@ -122,23 +64,7 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { - if (common_hal_busio_spi_deinited(self)) { - return; - } - - Ecode_t sc = SPIDRV_DeInit(self->handle); - if (sc != ECODE_EMDRV_SPIDRV_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); - } - - in_used = false; - self->sck = NULL; - self->mosi = NULL; - self->miso = NULL; - self->handle = NULL; - common_hal_reset_pin(self->mosi); - common_hal_reset_pin(self->miso); - common_hal_reset_pin(self->sck); + // FIXME: Implement } // Configures the SPI bus. The SPI object must be locked. @@ -147,55 +73,15 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint8_t polarity, uint8_t phase, uint8_t bits) { - Ecode_t sc; - // This resets the SPI, so check before updating it redundantly - if (baudrate == self->baudrate && polarity == self->polarity - && phase == self->phase && bits == self->bits) { - return true; - } - - sc = SPIDRV_DeInit(self->handle); - if (sc != ECODE_EMDRV_SPIDRV_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); - } - in_used = false; - self->baudrate = baudrate; - self->phase = phase; - self->bits = bits; - self->polarity = polarity; - - spidrv_eusart_init.bitRate = baudrate; - spidrv_eusart_init.frameLength = 8; - if (polarity == 0 && phase == 0) { - spidrv_eusart_init.clockMode = spidrvClockMode0; - } else if (polarity == 0 && phase == 1) { - spidrv_eusart_init.clockMode = spidrvClockMode1; - } else if (polarity == 1 && phase == 0) { - spidrv_eusart_init.clockMode = spidrvClockMode2; - } else if (polarity == 1 && phase == 1) { - spidrv_eusart_init.clockMode = spidrvClockMode3; - } - - sc = SPIDRV_Init(self->handle, &spidrv_eusart_init); - if (sc != ECODE_EMDRV_SPIDRV_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); - } - in_used = true; + + // FIXME: Implement return true; } // Lock SPI bus bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { - if (common_hal_busio_spi_deinited(self)) { - return false; - } - bool grabbed_lock = false; - if (!self->has_lock) { - grabbed_lock = true; - self->has_lock = true; - } - - return grabbed_lock; + // FIXME: Implement + return false; } // Check SPI lock status @@ -213,8 +99,8 @@ bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { - Ecode_t result = SPIDRV_MTransmitB(self->handle, data, len); - return result == ECODE_EMDRV_SPIDRV_OK; + // FIXME: Implement + return false; } // Read data into buffer @@ -222,9 +108,8 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { - self->handle->initData.dummyTxValue = write_value; - Ecode_t result = SPIDRV_MReceiveB(self->handle, data, len); - return result == ECODE_EMDRV_SPIDRV_OK; + // FIXME: Implement + return false; } // Write out the data in data_out @@ -234,8 +119,8 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_in, size_t len) { - Ecode_t result = SPIDRV_MTransferB(self->handle, data_out, data_in, len); - return result == ECODE_EMDRV_SPIDRV_OK; + // FIXME: Implement + return false; } // Get SPI baudrate diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 6d1507b78c696..ddffc8f55b9c3 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -26,8 +26,11 @@ #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/shared/tick.h" #include "shared-bindings/busio/UART.h" +#include "shared-bindings/microcontroller/Pin.h" + #include "mpconfigport.h" #include "shared/readline/readline.h" #include "shared/runtime/interrupt_char.h" @@ -35,42 +38,403 @@ #include "py/mperrno.h" #include "py/runtime.h" -#include "uart.h" +#include "max32_port.h" #include "UART.h" +#include "nvic_table.h" + +// UART IRQ Priority +#define UART_PRIORITY 1 + +/** + * +// Define a struct for what BUSIO.UART should contain +typedef struct { + mp_obj_base_t base; + int uart_id; + mxc_uart_regs_t* uart_regs; + + const mcu_pin_obj_t *rx_pin; + const mcu_pin_obj_t *tx_pin; + const mcu_pin_obj_t *rts_pin; + const mcu_pin_obj_t *cts_pin; + + uint8_t bits; + uint32_t baudrate; + bool parity; + uint8_t stop_bits; + + uint32_t timeout_ms; + bool error; +} busio_uart_obj_t; + */ + +typedef enum { + UART_9600 = 9600, + UART_14400 = 14400, + UART_19200 = 19200, + UART_38400 = 38400, + UART_57600 = 57600, + UART_115200 = 115200, + UART_230400 = 230400, + UART_460800 = 460800, + UART_921600 = 921600, +} uart_valid_baudrates; + typedef enum { - BUSIO_UART_PARITY_NONE, - BUSIO_UART_PARITY_EVEN, - BUSIO_UART_PARITY_ODD -} busio_uart_parity_t; + UART_FREE = 0, + UART_BUSY, + UART_NEVER_RESET, +} uart_status_t; + +static uint32_t timeout_ms=0; + +// Set each bit to indicate an active UART +// will be checked by ISR Handler for which ones to call +static uint8_t uarts_active = 0; +static uart_status_t uart_status[NUM_UARTS]; +// static uint8_t uart_never_reset_mask = 0; + +static int isValidBaudrate(uint32_t baudrate) { + switch(baudrate) { + case UART_9600: + return 1; + break; + case UART_14400: + return 1; + break; + case UART_19200: + return 1; + break; + case UART_38400: + return 1; + break; + case UART_57600: + return 1; + break; + case UART_115200: + return 1; + break; + case UART_230400: + return 1; + break; + case UART_460800: + return 1; + break; + case UART_921600: + return 1; + break; + default: + return 0; + break; + } +} + +static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) +{ + switch(busio_parity) { + case BUSIO_UART_PARITY_NONE: + return MXC_UART_PARITY_DISABLE; + case BUSIO_UART_PARITY_EVEN: + return MXC_UART_PARITY_EVEN_0; + case BUSIO_UART_PARITY_ODD: + return MXC_UART_PARITY_ODD_0; + default: + mp_raise_ValueError(MP_ERROR_TEXT("Parity must be ODD, EVEN, or NONE\n")); + } +} + +// FIXME: Find a better way of doing t his without a for loop +void UartISR(void) { + for (int i=0; i< NUM_UARTS; i++) { + if (uarts_active & (1 << i) ) { + MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); + uart_status[i] = UART_FREE; + } + } +} + +void uartCallback(mxc_uart_req_t *req, int error) { + +} // Construct an underlying UART object. -extern void common_hal_busio_uart_construct(busio_uart_obj_t *self, +void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, const mcu_pin_obj_t *rs485_dir, bool rs485_invert, uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, - bool sigint_enabled); + bool sigint_enabled) +{ + int err, temp; + + // Check for NULL Pointers && valid UART settings + assert( self ); + + // Assign UART ID based on pins + temp = pinsToUart(tx, rx); + if (temp == -1) { + // Error will be indicated by pinsToUart(tx, rx) function + return; + } + else { + self->uart_id = temp; + self->uart_regs = MXC_UART_GET_UART(temp); + } + + assert( (self->uart_id >= 0) && (self->uart_id < NUM_UARTS) ); + + // Indicate RS485 not implemented + if ( (rs485_dir != NULL) || (rs485_invert) ) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("RS485")); + } + + if ((rx != NULL) && (tx != NULL)) { + err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); + if (err != E_NO_ERROR) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to initialize UART.\n")); + } + + // attach & configure pins + self->tx_pin = tx; + self->rx_pin = rx; + common_hal_mcu_pin_claim(self->tx_pin); + common_hal_mcu_pin_claim(self->rx_pin); + } + else if (tx != NULL) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); + } + else if (rx != NULL) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); + } + else { + // Should not get here, as shared-bindings API should not call this way + } + + if ((cts) && (rts)) { + MXC_UART_SetFlowCtrl(self->uart_regs, MXC_UART_FLOW_EN, 8); + self->cts_pin = cts; + self->rts_pin = rts; + common_hal_mcu_pin_claim(self->cts_pin); + common_hal_mcu_pin_claim(self->rts_pin); + } + else if (cts || rts) { + mp_raise_ValueError(MP_ERROR_TEXT("Flow Ctrl needs both CTS & RTS")); + } + + // Set stop bits & data size + assert( (stop == 1) || (stop == 2) ); + mp_arg_validate_int(bits, 8, MP_QSTR_bits); + MXC_UART_SetDataSize(self->uart_regs, bits); + MXC_UART_SetStopBits(self->uart_regs, stop); + + // Set parity + MXC_UART_SetParity(self->uart_regs, convertParity(parity)); + + // attach UART parameters + self->stop_bits = stop; // must be 1 or 2 + self->bits = bits; + self->parity = parity; + self->baudrate = baudrate; + self->error = E_NO_ERROR; -extern void common_hal_busio_uart_deinit(busio_uart_obj_t *self); -extern bool common_hal_busio_uart_deinited(busio_uart_obj_t *self); + // Initialize ringbuffer for receiving data + if (self->rx_pin) { + // if given a ringbuff, use that + if (receiver_buffer) { + ringbuf_init(&self->ringbuf, receiver_buffer, receiver_buffer_size); + } + // else create one and attach it + else { + if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size)) { + m_malloc_fail(receiver_buffer_size); + } + } + } + // Indicate to this module that the UART is active + uarts_active |= (1 << self->uart_id); + + MXC_UART_ClearFlags(self->uart_regs, self->uart_regs->int_fl); + + /* Enable UART interrupt */ + NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); + NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)UartISR); + + // FIXME: UART ISRs are NOT WORKING! + // MXC_UART_EnableInt(self->uart_regs, ???) + // NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + + return; +} + +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) +{ + assert(self); + + if (!common_hal_busio_uart_deinited(self)) { + // First disable the ISR to avoid pre-emption + NVIC_DisableIRQ(UART0_IRQn); + + MXC_UART_Shutdown(self->uart_regs); + self->error = E_UNINITIALIZED; + + assert(self->rx_pin && self->tx_pin); + reset_pin_number(self->rx_pin->port, self->rx_pin->mask); + reset_pin_number(self->tx_pin->port, self->tx_pin->mask); + + if (self->cts_pin && self->rts_pin) { + reset_pin_number(self->cts_pin->port, self->cts_pin->mask); + reset_pin_number(self->rts_pin->port, self->rts_pin->mask); + } + + self->tx_pin = NULL; + self->rx_pin = NULL; + self->cts_pin = NULL; + self->rts_pin = NULL; + + // Indicate to this module that the UART is not active + uarts_active &= ~(1 << self->uart_id); + } +} + +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) +{ + if (uarts_active & (1 << self->uart_id)) { + return false; + } + else { + return true; + }; +} + +// todo: test // Read characters. len is in characters NOT bytes! -extern size_t common_hal_busio_uart_read(busio_uart_obj_t *self, - uint8_t *data, size_t len, int *errcode); +size_t common_hal_busio_uart_read(busio_uart_obj_t *self, + uint8_t *data, size_t len, int *errcode) +{ + int err; + static size_t bytes_remaining; + + bytes_remaining = len * 4; + while(bytes_remaining > 0) { + mxc_uart_req_t uart_wr_req; + uart_wr_req.rxCnt = 0; + uart_wr_req.txCnt = 0; + uart_wr_req.rxData = data; + uart_wr_req.txData = NULL; + uart_wr_req.rxLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); + uart_wr_req.txLen = 0; + uart_wr_req.uart = self->uart_regs; + + err = MXC_UART_Transaction(&uart_wr_req); + if (err != E_NO_ERROR) { + *errcode = err; + return ((len * 4) - bytes_remaining); + } + bytes_remaining -= uart_wr_req.rxLen; + } + return len; +} + +//todo: test // Write characters. len is in characters NOT bytes! -extern size_t common_hal_busio_uart_write(busio_uart_obj_t *self, - const uint8_t *data, size_t len, int *errcode); + size_t common_hal_busio_uart_write(busio_uart_obj_t *self, + const uint8_t *data, size_t len, int *errcode) +{ + int err; + uint32_t start_time=0; + static size_t bytes_remaining; + + bytes_remaining = len * 4; + + while(bytes_remaining > 0) { + mxc_uart_req_t uart_wr_req; + uart_wr_req.rxCnt = 0; + uart_wr_req.txCnt = 0; + uart_wr_req.rxData = NULL; + uart_wr_req.txData = data; + uart_wr_req.txLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); + uart_wr_req.rxLen = 0; + uart_wr_req.uart = self->uart_regs; + + uart_status[self->uart_id] = UART_BUSY; + start_time = supervisor_ticks_ms64(); + err = MXC_UART_Transaction(&uart_wr_req); + if (err != E_NO_ERROR) { + *errcode = err; + return ((len * 4) - bytes_remaining); + } + + // FIXME: NOT ENTERING ISR, NOT HANDLING TIMEOUT + // Wait for transaction completion + // FIXME: Test timeout & status flags + while ( (supervisor_ticks_ms64() - start_time < 500) + && (uart_status[self->uart_id] != UART_FREE) + ) {}; + + bytes_remaining -= uart_wr_req.txLen; + } + return len; +} + + uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) +{ + return self->baudrate; +} + +// Validate baudrate +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) +{ + if ( isValidBaudrate(baudrate) ) { + self->baudrate = baudrate; + } + else { + mp_raise_ValueError(MP_ERROR_TEXT("Baudrate invalid. Must be a standard UART baudrate.\n")); + } +} + +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) +{ + return self->timeout; +} + +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) +{ + if (timeout > 100.0) { + mp_raise_ValueError(MP_ERROR_TEXT("Timeout must be < 100 seconds")); + } + + timeout_ms = 1000 * (uint32_t)timeout; + self->timeout = (uint32_t)timeout; + + return; +} + +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) +{ + return MXC_UART_GetRXFIFOAvailable(self->uart_regs); +} -extern uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self); -extern void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate); -extern mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self); -extern void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout); +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) +{ + MXC_UART_ClearRXFIFO(self->uart_regs); +} -extern uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self); -extern void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self); -extern bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self); +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) +{ + return !(MXC_UART_GetStatus(self->uart_regs) & (MXC_F_UART_STATUS_TX_BUSY)); +} -extern void common_hal_busio_uart_never_reset(busio_uart_obj_t *self); +void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) +{ + common_hal_never_reset_pin(self->tx_pin); + common_hal_never_reset_pin(self->rx_pin); + common_hal_never_reset_pin(self->cts_pin); + common_hal_never_reset_pin(self->rts_pin); + // uart_never_reset_mask |= ( 1 << (self->uart_id) ); +} diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index a8d294de222d3..3c76efc720e78 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -4,28 +4,43 @@ // // SPDX-License-Identifier: MIT -#ifndef MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H -#define MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H +#ifndef MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H +#define MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H #include "common-hal/microcontroller/Pin.h" -#include "peripherals/periph.h" #include "py/obj.h" #include "py/ringbuf.h" -#include "uart.h" +// #include "uart.h" +// #include "uart_regs.h" +// #include "mxc_sys.h" + +#include "max32_port.h" // Define a struct for what BUSIO.UART should contain typedef struct { mp_obj_base_t base; + + int uart_id; + int uart_map; mxc_uart_regs_t* uart_regs; - const mcu_pin_obj_t *rx; - const mcu_pin_obj_t *tx; - uint32_t baudrate; + bool parity; - uint8_t stop_bits; uint8_t bits; + uint8_t stop_bits; + uint32_t baudrate; + + int error; + float timeout; + + ringbuf_t ringbuf; + + const mcu_pin_obj_t *rx_pin; + const mcu_pin_obj_t *tx_pin; + const mcu_pin_obj_t *rts_pin; + const mcu_pin_obj_t *cts_pin; } busio_uart_obj_t; void uart_reset(void); -#endif // MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H +#endif // MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index 5d92fcfe6d3ee..5c3811b651554 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -22,31 +22,35 @@ #include "system_max32690.h" #include "max32690.h" +// UART Ports & pins +#include "peripherals/max32690/max32_uart.h" +#define NUM_UARTS 4 + /** START: GPIO4 Handling specific to MAX32690 */ -#define GPIO4_PIN_MASK 0x00000003 -#define GPIO4_RESET_MASK 0xFFFFFF77 -#define GPIO4_OUTEN_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) -#define GPIO4_PULLDIS_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) -#define GPIO4_DATAOUT_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) -#define GPIO4_DATAOUT_GET_MASK(mask) \ - ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ - ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ - (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ - mask) -#define GPIO4_DATAIN_MASK(mask) \ - ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ - ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ - (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ - mask) -#define GPIO4_AFEN_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ - ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) + #define GPIO4_PIN_MASK 0x00000003 + #define GPIO4_RESET_MASK 0xFFFFFF77 + #define GPIO4_OUTEN_MASK(mask) \ + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) + #define GPIO4_PULLDIS_MASK(mask) \ + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) + #define GPIO4_DATAOUT_MASK(mask) \ + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) + #define GPIO4_DATAOUT_GET_MASK(mask) \ + ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ + ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ + (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ + mask) + #define GPIO4_DATAIN_MASK(mask) \ + ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ + ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ + (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ + mask) + #define GPIO4_AFEN_MASK(mask) \ + (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ + ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) /** END: GPIO4 Handling specific to MAX32690 */ #endif diff --git a/ports/analog/mpconfigport.mk b/ports/analog/mpconfigport.mk index 97ead8efdfb0f..f1cd0bb2901e9 100644 --- a/ports/analog/mpconfigport.mk +++ b/ports/analog/mpconfigport.mk @@ -22,8 +22,7 @@ INTERNAL_FLASH_FILESYSTEM = 1 #################################################################################### # These modules are implemented in ports//common-hal: -# Plan to implement -CIRCUITPY_BUSIO ?= 0 +CIRCUITPY_BUSIO ?= 1 CIRCUITPY_RTC ?= 1 # Other modules (may or may not implement): diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c new file mode 100644 index 0000000000000..f8c53dc63218e --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/UART.h" +#include "max32_uart.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + +// FIXME: Remove upon test! +// mxc_uart_regs_t max32_uarts[NUM_UARTS] = { +// MXC_UART0, +// MXC_UART1, +// MXC_UART2, +// MXC_UART3, +// }; + +const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { + { MXC_GPIO2, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, + MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, + MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } +}; + +int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { + for (int i = 0; i < NUM_UARTS; i++) { + if ( (uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) + && (uart_maps[i].mask == (( tx->mask) | (rx->mask))) ) { + return i; + } + } + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find a uart matching pins...\nTX: port %d mask %d\nRX: port %d mask %d\n"), + tx->port, tx->mask, rx->port, rx->mask); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_uart.h b/ports/analog/peripherals/max32690/max32_uart.h new file mode 100644 index 0000000000000..f03b500a3c507 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_uart.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "uart_regs.h" +#include "mxc_sys.h" +#include "uart.h" +#include "peripherals/pins.h" + +#define NUM_UARTS 4 + +int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx); From 451e152d5b3d785b7e81a2fb575f4d22c33217c3 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 14 Jan 2025 15:26:49 -0800 Subject: [PATCH 51/78] Add tools files for debugging - Add debug-dap.sh to spawn OpenOCD process & gdb-multiarch process for debugging. Requires MaximSDK install & path settings inside this script. Also depends on gdb-multiarch and connected CMSIS-DAP probe over USB. - debug-dap.gdb simply holds the gdb commands for this script + small style fix on common-hal/microcontroller/Pin.c --- ports/analog/common-hal/microcontroller/Pin.c | 2 +- ports/analog/tools/debug-dap.gdb | 3 +++ ports/analog/tools/debug-dap.sh | 23 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 ports/analog/tools/debug-dap.gdb create mode 100644 ports/analog/tools/debug-dap.sh diff --git a/ports/analog/common-hal/microcontroller/Pin.c b/ports/analog/common-hal/microcontroller/Pin.c index 4545aa039c2fa..6816054153e72 100644 --- a/ports/analog/common-hal/microcontroller/Pin.c +++ b/ports/analog/common-hal/microcontroller/Pin.c @@ -37,7 +37,7 @@ void reset_all_pins(void) { } void reset_pin_number(uint8_t pin_port, uint8_t pin_pad) { - if (pin_port == INVALID_PIN || pin_port > NUM_GPIO_PORTS) { + if ( (pin_port == INVALID_PIN) || (pin_port > NUM_GPIO_PORTS) ) { return; } diff --git a/ports/analog/tools/debug-dap.gdb b/ports/analog/tools/debug-dap.gdb new file mode 100644 index 0000000000000..d0aa7e2b13fa0 --- /dev/null +++ b/ports/analog/tools/debug-dap.gdb @@ -0,0 +1,3 @@ +target remote :3333 +break main +continue diff --git a/ports/analog/tools/debug-dap.sh b/ports/analog/tools/debug-dap.sh new file mode 100644 index 0000000000000..df2964fcb122a --- /dev/null +++ b/ports/analog/tools/debug-dap.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Primer on taking cmd line args in Linux shell scripts +# $0 is the script itself +# $1 $2 $3 are arg1, arg2, arg3, etc + +# Export OCD Path +### USER ACTION: Replace with your path to OpenOCD ### +OCD_PATH="~/MaximSDK/Tools/OpenOCD" + +# Call openocd to setup the debug server, storing the PID for OpenOCD +sh -c "openocd -s $OCD_PATH/scripts -f interface/cmsis-dap.cfg -f target/$1.cfg -c \"init; reset halt\" " & + +# Allow enough time for OCD server to set up +# + wait for the sleep to finish +sleep 3 & +wait $! + +# spawn the gdb process and store the gdb_pid +gdb-multiarch build-apard32690/firmware.elf -x "tools/debug-dap.gdb" + +# when gdb exits, kill all openocd processes +killall openocd From 13fb8f3d8f6d2d523f760c036a0d7cadcac2b312 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Fri, 24 Jan 2025 13:42:42 -0800 Subject: [PATCH 52/78] Fixed most UART write issues. - Graceful recovery from timeouts added - Remaining issue still exists where a timeout occurs after a while --- ports/analog/common-hal/busio/UART.c | 86 +++++++++++++++++----------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index ddffc8f55b9c3..4b0c8bfba6a81 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#if CIRCUITPY_BUSIO_UART + #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "supervisor/shared/tick.h" @@ -144,18 +146,21 @@ static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) } } -// FIXME: Find a better way of doing t his without a for loop -void UartISR(void) { - for (int i=0; i< NUM_UARTS; i++) { +// FIXME: Find a better way of doing this without a for loop +// FIXME: Fixed @ UART0 for TESTING BUGFIXES!!! +void UART0_IRQHandler(void) { + // MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); + for (int i=0; i < NUM_UARTS; i++) { if (uarts_active & (1 << i) ) { MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); - uart_status[i] = UART_FREE; } } } -void uartCallback(mxc_uart_req_t *req, int error) { - +// Callback gets called when AsyncRequest is COMPLETE +// (e.g. txLen == txCnt) +static volatile void uartCallback(mxc_uart_req_t *req, int error) { + uart_status[MXC_UART_GET_IDX(req->uart)] = UART_FREE; } // Construct an underlying UART object. @@ -256,17 +261,12 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, // Indicate to this module that the UART is active uarts_active |= (1 << self->uart_id); - MXC_UART_ClearFlags(self->uart_regs, self->uart_regs->int_fl); /* Enable UART interrupt */ NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); - NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)UartISR); - - // FIXME: UART ISRs are NOT WORKING! - // MXC_UART_EnableInt(self->uart_regs, ???) - // NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)&UART0_IRQHandler); return; } @@ -321,23 +321,30 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, bytes_remaining = len * 4; - while(bytes_remaining > 0) { - mxc_uart_req_t uart_wr_req; - uart_wr_req.rxCnt = 0; - uart_wr_req.txCnt = 0; - uart_wr_req.rxData = data; - uart_wr_req.txData = NULL; - uart_wr_req.rxLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); - uart_wr_req.txLen = 0; - uart_wr_req.uart = self->uart_regs; + MXC_UART_ClearFlags(self->uart_regs, 0xFFFFFFFF); + NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - err = MXC_UART_Transaction(&uart_wr_req); + while(bytes_remaining > 0) { + mxc_uart_req_t uart_rd_req; + uart_rd_req.rxCnt = 0; + uart_rd_req.txCnt = 0; + uart_rd_req.rxData = data; + uart_rd_req.txData = NULL; + uart_rd_req.rxLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); + uart_rd_req.txLen = 0; + uart_rd_req.uart = self->uart_regs; + uart_rd_req.callback = (void *)uartCallback; + + err = MXC_UART_TransactionAsync(&uart_rd_req); if (err != E_NO_ERROR) { *errcode = err; + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); return ((len * 4) - bytes_remaining); } - bytes_remaining -= uart_wr_req.rxLen; + bytes_remaining -= uart_rd_req.rxLen; } + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + return len; } @@ -350,7 +357,10 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint32_t start_time=0; static size_t bytes_remaining; - bytes_remaining = len * 4; + bytes_remaining = len; + + MXC_UART_ClearFlags(self->uart_regs, 0xFFFFFFFF); + NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); while(bytes_remaining > 0) { mxc_uart_req_t uart_wr_req; @@ -358,28 +368,38 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uart_wr_req.txCnt = 0; uart_wr_req.rxData = NULL; uart_wr_req.txData = data; - uart_wr_req.txLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); + uart_wr_req.txLen = bytes_remaining; uart_wr_req.rxLen = 0; uart_wr_req.uart = self->uart_regs; + uart_wr_req.callback = (void *)uartCallback; uart_status[self->uart_id] = UART_BUSY; start_time = supervisor_ticks_ms64(); - err = MXC_UART_Transaction(&uart_wr_req); + err = MXC_UART_TransactionAsync(&uart_wr_req); if (err != E_NO_ERROR) { *errcode = err; - return ((len * 4) - bytes_remaining); + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Requested bus is busy\n")); } - // FIXME: NOT ENTERING ISR, NOT HANDLING TIMEOUT // Wait for transaction completion - // FIXME: Test timeout & status flags - while ( (supervisor_ticks_ms64() - start_time < 500) - && (uart_status[self->uart_id] != UART_FREE) + while ( (uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000)) ) {}; - bytes_remaining -= uart_wr_req.txLen; + // If the timeout gets hit, abort and error out + if (uart_status[self->uart_id] != UART_FREE) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + } + + bytes_remaining -= uart_wr_req.txCnt; } + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); return len; + } uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) @@ -438,3 +458,5 @@ void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) common_hal_never_reset_pin(self->rts_pin); // uart_never_reset_mask |= ( 1 << (self->uart_id) ); } + +#endif // CIRCUITPY_BUSIO_UART From 0f1d915f7c3521d877ce589c01e465c4b48be781 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Fri, 24 Jan 2025 17:08:32 -0800 Subject: [PATCH 53/78] Fix issues with UART reads and unreliable UART writes. - No ISR for UART writes, but uses timeouts - Reads use ISRs, but also incorporate timeouts --- ports/analog/common-hal/busio/UART.c | 162 ++++++++++++++++----------- 1 file changed, 98 insertions(+), 64 deletions(-) diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 4b0c8bfba6a81..ad5425d62ea31 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -95,6 +95,7 @@ static uint32_t timeout_ms=0; // will be checked by ISR Handler for which ones to call static uint8_t uarts_active = 0; static uart_status_t uart_status[NUM_UARTS]; +static volatile int uart_err; // static uint8_t uart_never_reset_mask = 0; static int isValidBaudrate(uint32_t baudrate) { @@ -146,12 +147,9 @@ static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) } } -// FIXME: Find a better way of doing this without a for loop -// FIXME: Fixed @ UART0 for TESTING BUGFIXES!!! void UART0_IRQHandler(void) { - // MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); - for (int i=0; i < NUM_UARTS; i++) { - if (uarts_active & (1 << i) ) { + for (int i = 0; i < NUM_UARTS; i++) { + if (uarts_active & (1 << i)) { MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); } } @@ -161,6 +159,7 @@ void UART0_IRQHandler(void) { // (e.g. txLen == txCnt) static volatile void uartCallback(mxc_uart_req_t *req, int error) { uart_status[MXC_UART_GET_IDX(req->uart)] = UART_FREE; + uart_err = error; } // Construct an underlying UART object. @@ -262,7 +261,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, uarts_active |= (1 << self->uart_id); - /* Enable UART interrupt */ + /* Setup UART interrupt */ NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); @@ -311,45 +310,67 @@ bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) }; } -// todo: test // Read characters. len is in characters NOT bytes! size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { int err; + uint32_t start_time=0; static size_t bytes_remaining; - bytes_remaining = len * 4; + // Setup globals & status tracking + uart_err = E_NO_ERROR; + uarts_active |= (1 << self->uart_id); + uart_status[self->uart_id] = UART_BUSY; + bytes_remaining = len; - MXC_UART_ClearFlags(self->uart_regs, 0xFFFFFFFF); NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - while(bytes_remaining > 0) { - mxc_uart_req_t uart_rd_req; - uart_rd_req.rxCnt = 0; - uart_rd_req.txCnt = 0; - uart_rd_req.rxData = data; - uart_rd_req.txData = NULL; - uart_rd_req.rxLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); - uart_rd_req.txLen = 0; - uart_rd_req.uart = self->uart_regs; - uart_rd_req.callback = (void *)uartCallback; - - err = MXC_UART_TransactionAsync(&uart_rd_req); - if (err != E_NO_ERROR) { - *errcode = err; - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - return ((len * 4) - bytes_remaining); - } - bytes_remaining -= uart_rd_req.rxLen; + mxc_uart_req_t uart_rd_req; + uart_rd_req.rxCnt = 0; + uart_rd_req.txCnt = 0; + uart_rd_req.rxData = data; + uart_rd_req.txData = NULL; + uart_rd_req.rxLen = bytes_remaining; + uart_rd_req.txLen = 0; + uart_rd_req.uart = self->uart_regs; + uart_rd_req.callback = (void *)uartCallback; + + // Initiate the read transaction + start_time = supervisor_ticks_ms64(); + err = MXC_UART_TransactionAsync(&uart_rd_req); + if (err != E_NO_ERROR) { + *errcode = err; + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("\nERR: Error starting trasaction: %d\n"), err); } - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + // Wait for transaction completion or timeout + while ( (uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { + } + + // If the timeout gets hit, abort and error out + if (uart_status[self->uart_id] != UART_FREE) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + } + + // Check for errors from the callback + else if (uart_err != E_NO_ERROR) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); + } + + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); return len; } -//todo: test // Write characters. len is in characters NOT bytes! +// This function blocks until the timeout finishes size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { @@ -357,49 +378,62 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint32_t start_time=0; static size_t bytes_remaining; + // Setup globals & status tracking + uart_err = E_NO_ERROR; + uarts_active |= (1 << self->uart_id); + uart_status[self->uart_id] = UART_BUSY; bytes_remaining = len; - MXC_UART_ClearFlags(self->uart_regs, 0xFFFFFFFF); - NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - - while(bytes_remaining > 0) { - mxc_uart_req_t uart_wr_req; - uart_wr_req.rxCnt = 0; - uart_wr_req.txCnt = 0; - uart_wr_req.rxData = NULL; - uart_wr_req.txData = data; - uart_wr_req.txLen = bytes_remaining; - uart_wr_req.rxLen = 0; - uart_wr_req.uart = self->uart_regs; - uart_wr_req.callback = (void *)uartCallback; - - uart_status[self->uart_id] = UART_BUSY; - start_time = supervisor_ticks_ms64(); - err = MXC_UART_TransactionAsync(&uart_wr_req); - if (err != E_NO_ERROR) { - *errcode = err; - MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Requested bus is busy\n")); - } + mxc_uart_req_t uart_wr_req = {}; + + // Setup transaction + uart_wr_req.rxCnt = 0; + uart_wr_req.txCnt = 0; + uart_wr_req.rxData = NULL; + uart_wr_req.txData = data; + uart_wr_req.txLen = bytes_remaining; + uart_wr_req.rxLen = 0; + uart_wr_req.uart = self->uart_regs; + uart_wr_req.callback = (void *)uartCallback; + + // Start the transaction + start_time = supervisor_ticks_ms64(); + err = MXC_UART_TransactionAsync(&uart_wr_req); + if (err != E_NO_ERROR) { + *errcode = err; + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Requested bus is busy\n")); + } - // Wait for transaction completion - while ( (uart_status[self->uart_id] != UART_FREE) && - (supervisor_ticks_ms64() - start_time < (self->timeout * 1000)) - ) {}; + // Wait for transaction completion or timeout + while ( (uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { - // If the timeout gets hit, abort and error out - if (uart_status[self->uart_id] != UART_FREE) { - MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + // Call the handler and abort if errors + uart_err = MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); + if (uart_err != E_NO_ERROR) { + MXC_UART_AbortAsync(MXC_UART_GET_UART(0)); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(0)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); } + } - bytes_remaining -= uart_wr_req.txCnt; + // If the timeout gets hit, abort and error out + if (uart_status[self->uart_id] != UART_FREE) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); } - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - return len; + // Check for errors from the callback + else if (uart_err != E_NO_ERROR) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); + } + + return len; } uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) From 72c4d438e19b9b76f4e68b06194dd8cc92ae4f88 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Mon, 27 Jan 2025 13:50:52 -0800 Subject: [PATCH 54/78] Add pre-commit changes to UART - Formatting & codespell fixes from pre-commit --- ports/analog/common-hal/busio/I2C.h | 2 +- ports/analog/common-hal/busio/SPI.h | 2 +- ports/analog/common-hal/busio/UART.c | 115 +++++++----------- ports/analog/common-hal/busio/UART.h | 2 +- ports/analog/common-hal/microcontroller/Pin.c | 2 +- ports/analog/max32_port.h | 32 ++--- .../analog/peripherals/max32690/max32_uart.c | 16 +-- 7 files changed, 74 insertions(+), 97 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h index c92283d6c53b6..9571a8ab694f4 100644 --- a/ports/analog/common-hal/busio/I2C.h +++ b/ports/analog/common-hal/busio/I2C.h @@ -17,7 +17,7 @@ // Define a struct for what BUSIO.I2C should carry typedef struct { mp_obj_base_t base; - mxc_i2c_regs_t* i2c_regs; + mxc_i2c_regs_t *i2c_regs; bool has_lock; const mcu_pin_obj_t *scl; const mcu_pin_obj_t *sda; diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h index 8c48147ff6c77..d90f55da111a0 100644 --- a/ports/analog/common-hal/busio/SPI.h +++ b/ports/analog/common-hal/busio/SPI.h @@ -17,7 +17,7 @@ // Define a struct for what BUSIO.SPI should carry typedef struct { mp_obj_base_t base; - mxc_spi_regs_t* spi_regs; + mxc_spi_regs_t *spi_regs; bool has_lock; const mcu_pin_obj_t *sck; const mcu_pin_obj_t *mosi; diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index ad5425d62ea31..b4b17126e60e9 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -89,7 +89,7 @@ typedef enum { UART_NEVER_RESET, } uart_status_t; -static uint32_t timeout_ms=0; +static uint32_t timeout_ms = 0; // Set each bit to indicate an active UART // will be checked by ISR Handler for which ones to call @@ -99,7 +99,7 @@ static volatile int uart_err; // static uint8_t uart_never_reset_mask = 0; static int isValidBaudrate(uint32_t baudrate) { - switch(baudrate) { + switch (baudrate) { case UART_9600: return 1; break; @@ -133,17 +133,16 @@ static int isValidBaudrate(uint32_t baudrate) { } } -static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) -{ - switch(busio_parity) { - case BUSIO_UART_PARITY_NONE: - return MXC_UART_PARITY_DISABLE; - case BUSIO_UART_PARITY_EVEN: - return MXC_UART_PARITY_EVEN_0; - case BUSIO_UART_PARITY_ODD: - return MXC_UART_PARITY_ODD_0; - default: - mp_raise_ValueError(MP_ERROR_TEXT("Parity must be ODD, EVEN, or NONE\n")); +static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) { + switch (busio_parity) { + case BUSIO_UART_PARITY_NONE: + return MXC_UART_PARITY_DISABLE; + case BUSIO_UART_PARITY_EVEN: + return MXC_UART_PARITY_EVEN_0; + case BUSIO_UART_PARITY_ODD: + return MXC_UART_PARITY_ODD_0; + default: + mp_raise_ValueError(MP_ERROR_TEXT("Parity must be ODD, EVEN, or NONE\n")); } } @@ -169,33 +168,31 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t *rs485_dir, bool rs485_invert, uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, - bool sigint_enabled) -{ + bool sigint_enabled) { int err, temp; // Check for NULL Pointers && valid UART settings - assert( self ); + assert(self); // Assign UART ID based on pins temp = pinsToUart(tx, rx); if (temp == -1) { // Error will be indicated by pinsToUart(tx, rx) function return; - } - else { + } else { self->uart_id = temp; self->uart_regs = MXC_UART_GET_UART(temp); } - assert( (self->uart_id >= 0) && (self->uart_id < NUM_UARTS) ); + assert((self->uart_id >= 0) && (self->uart_id < NUM_UARTS)); // Indicate RS485 not implemented - if ( (rs485_dir != NULL) || (rs485_invert) ) { + if ((rs485_dir != NULL) || (rs485_invert)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("RS485")); } if ((rx != NULL) && (tx != NULL)) { - err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); + err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); if (err != E_NO_ERROR) { mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to initialize UART.\n")); } @@ -205,14 +202,11 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->rx_pin = rx; common_hal_mcu_pin_claim(self->tx_pin); common_hal_mcu_pin_claim(self->rx_pin); - } - else if (tx != NULL) { + } else if (tx != NULL) { mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); - } - else if (rx != NULL) { + } else if (rx != NULL) { mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); - } - else { + } else { // Should not get here, as shared-bindings API should not call this way } @@ -222,13 +216,12 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->rts_pin = rts; common_hal_mcu_pin_claim(self->cts_pin); common_hal_mcu_pin_claim(self->rts_pin); - } - else if (cts || rts) { + } else if (cts || rts) { mp_raise_ValueError(MP_ERROR_TEXT("Flow Ctrl needs both CTS & RTS")); } // Set stop bits & data size - assert( (stop == 1) || (stop == 2) ); + assert((stop == 1) || (stop == 2)); mp_arg_validate_int(bits, 8, MP_QSTR_bits); MXC_UART_SetDataSize(self->uart_regs, bits); MXC_UART_SetStopBits(self->uart_regs, stop); @@ -270,8 +263,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, return; } -void common_hal_busio_uart_deinit(busio_uart_obj_t *self) -{ +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { assert(self); if (!common_hal_busio_uart_deinited(self)) { @@ -300,22 +292,19 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) } } -bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) -{ +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { if (uarts_active & (1 << self->uart_id)) { return false; - } - else { + } else { return true; }; } // Read characters. len is in characters NOT bytes! size_t common_hal_busio_uart_read(busio_uart_obj_t *self, - uint8_t *data, size_t len, int *errcode) -{ + uint8_t *data, size_t len, int *errcode) { int err; - uint32_t start_time=0; + uint32_t start_time = 0; static size_t bytes_remaining; // Setup globals & status tracking @@ -343,12 +332,12 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, *errcode = err; MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("\nERR: Error starting trasaction: %d\n"), err); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("\nERR: Error starting transaction: %d\n"), err); } // Wait for transaction completion or timeout - while ( (uart_status[self->uart_id] != UART_FREE) && - (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { + while ((uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { } // If the timeout gets hit, abort and error out @@ -357,7 +346,6 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); mp_raise_RuntimeError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); } - // Check for errors from the callback else if (uart_err != E_NO_ERROR) { MXC_UART_AbortAsync(self->uart_regs); @@ -371,11 +359,10 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, // Write characters. len is in characters NOT bytes! // This function blocks until the timeout finishes - size_t common_hal_busio_uart_write(busio_uart_obj_t *self, - const uint8_t *data, size_t len, int *errcode) -{ +size_t common_hal_busio_uart_write(busio_uart_obj_t *self, + const uint8_t *data, size_t len, int *errcode) { int err; - uint32_t start_time=0; + uint32_t start_time = 0; static size_t bytes_remaining; // Setup globals & status tracking @@ -407,8 +394,8 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, } // Wait for transaction completion or timeout - while ( (uart_status[self->uart_id] != UART_FREE) && - (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { + while ((uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { // Call the handler and abort if errors uart_err = MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); @@ -425,7 +412,6 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); } - // Check for errors from the callback else if (uart_err != E_NO_ERROR) { MXC_UART_AbortAsync(self->uart_regs); @@ -436,29 +422,24 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, return len; } - uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) -{ +uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) { return self->baudrate; } // Validate baudrate -void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) -{ - if ( isValidBaudrate(baudrate) ) { +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) { + if (isValidBaudrate(baudrate)) { self->baudrate = baudrate; - } - else { + } else { mp_raise_ValueError(MP_ERROR_TEXT("Baudrate invalid. Must be a standard UART baudrate.\n")); } } -mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) -{ +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { return self->timeout; } -void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) -{ +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { if (timeout > 100.0) { mp_raise_ValueError(MP_ERROR_TEXT("Timeout must be < 100 seconds")); } @@ -469,23 +450,19 @@ void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeou return; } -uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) -{ +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { return MXC_UART_GetRXFIFOAvailable(self->uart_regs); } -void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) -{ +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { MXC_UART_ClearRXFIFO(self->uart_regs); } -bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) -{ +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { return !(MXC_UART_GetStatus(self->uart_regs) & (MXC_F_UART_STATUS_TX_BUSY)); } -void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) -{ +void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { common_hal_never_reset_pin(self->tx_pin); common_hal_never_reset_pin(self->rx_pin); common_hal_never_reset_pin(self->cts_pin); diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index 3c76efc720e78..f24f310fe3a52 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -23,7 +23,7 @@ typedef struct { int uart_id; int uart_map; - mxc_uart_regs_t* uart_regs; + mxc_uart_regs_t *uart_regs; bool parity; uint8_t bits; diff --git a/ports/analog/common-hal/microcontroller/Pin.c b/ports/analog/common-hal/microcontroller/Pin.c index 6816054153e72..83e2f3b9c3a76 100644 --- a/ports/analog/common-hal/microcontroller/Pin.c +++ b/ports/analog/common-hal/microcontroller/Pin.c @@ -37,7 +37,7 @@ void reset_all_pins(void) { } void reset_pin_number(uint8_t pin_port, uint8_t pin_pad) { - if ( (pin_port == INVALID_PIN) || (pin_port > NUM_GPIO_PORTS) ) { + if ((pin_port == INVALID_PIN) || (pin_port > NUM_GPIO_PORTS)) { return; } diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index 5c3811b651554..3b4fe7bc87d90 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -30,27 +30,27 @@ #define GPIO4_PIN_MASK 0x00000003 #define GPIO4_RESET_MASK 0xFFFFFF77 #define GPIO4_OUTEN_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) #define GPIO4_PULLDIS_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) #define GPIO4_DATAOUT_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) #define GPIO4_DATAOUT_GET_MASK(mask) \ - ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ - ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ - (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ - mask) + ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ + ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ + (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ + mask) #define GPIO4_DATAIN_MASK(mask) \ - ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ - ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ - (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ - mask) + ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ + ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ + (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ + mask) #define GPIO4_AFEN_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ - ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) + (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ + ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) /** END: GPIO4 Handling specific to MAX32690 */ #endif diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c index f8c53dc63218e..3ccb930d85c14 100644 --- a/ports/analog/peripherals/max32690/max32_uart.c +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -23,21 +23,21 @@ const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { { MXC_GPIO2, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), - MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, - MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, + MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), - MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, - MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, + MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } }; int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { for (int i = 0; i < NUM_UARTS; i++) { - if ( (uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) - && (uart_maps[i].mask == (( tx->mask) | (rx->mask))) ) { + if ((uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) + && (uart_maps[i].mask == ((tx->mask) | (rx->mask)))) { return i; } } From b741b3a7519011d6f4619a85b18b433bea511292 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Fri, 31 Jan 2025 16:45:13 -0800 Subject: [PATCH 55/78] Resolve UART ISR naming issues - Call NVIC_SetRAM in supervisor/port.c to move NVIC table to RAM, enabling ISR RAM remapping. - Rename UART ISR to be generic for any UART IRQn. - Remove background led writes from background.c. --- ports/analog/background.c | 10 ++-------- ports/analog/common-hal/busio/UART.c | 11 +++++++++-- ports/analog/supervisor/port.c | 8 ++++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/ports/analog/background.c b/ports/analog/background.c index ffad007ffa51c..ad840c6dcdabc 100644 --- a/ports/analog/background.c +++ b/ports/analog/background.c @@ -19,19 +19,13 @@ extern const mxc_gpio_cfg_t led_pin[]; extern const int num_leds; /** NOTE: ALL "ticks" refer to a 1/1024 s period */ -static int status_led_ticks = 0; +static int status_ticks = 0; // This function is where port-specific background // tasks should be performed // Execute port specific actions during background tick. Only if ticks are enabled. void port_background_tick(void) { - status_led_ticks++; - - // Set an LED approx. 1/s - if (status_led_ticks > 1024) { - MXC_GPIO_OutToggle(led_pin[2].port, led_pin[2].mask); - status_led_ticks = 0; - } + status_ticks++; } // Execute port specific actions during background tasks. This is before the diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index b4b17126e60e9..310965e34609b 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -146,7 +146,7 @@ static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) { } } -void UART0_IRQHandler(void) { +void uart_isr(void) { for (int i = 0; i < NUM_UARTS; i++) { if (uarts_active & (1 << i)) { MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); @@ -237,6 +237,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->error = E_NO_ERROR; // Initialize ringbuffer for receiving data + // FIXME: Either the use the ringbuf or get rid of it! if (self->rx_pin) { // if given a ringbuff, use that if (receiver_buffer) { @@ -253,12 +254,18 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, // Indicate to this module that the UART is active uarts_active |= (1 << self->uart_id); + // Set the timeout to a default value + if (((timeout < 0.0) || (timeout > 100.0))) { + self->timeout = 1.0; + } else { + self->timeout = timeout; + } /* Setup UART interrupt */ NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); - NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)&UART0_IRQHandler); + NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)uart_isr); return; } diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index ff05ff2d28709..de83b011bdf0d 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -39,6 +39,7 @@ // Sys includes #include "max32_port.h" +#include "nvic_table.h" // Timers #include "mxc_delay.h" @@ -78,6 +79,13 @@ void SysTick_Handler(void) { safe_mode_t port_init(void) { int err = E_NO_ERROR; + // Set Vector Table to RAM & configure ARM core to use RAM-based ISRs + // This allows definition of ISRs with custom names + // + // Useful for mapping ISRs with names not related to a specific IRQn. + // Source: https://arm-software.github.io/CMSIS_5/Core/html/using_VTOR_pg.html + NVIC_SetRAM(); + // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); NVIC_EnableIRQ(SysTick_IRQn); From aaeee4db835e9575ef5fc683f73d6a82c4552a02 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Thu, 6 Mar 2025 23:57:59 -0800 Subject: [PATCH 56/78] Add BUSIO.I2C and MAX32690 I2C structure - Data structure and constructor for I2C (tested) - Lock and probing functions complete and tested TODO: Implement I2C Write, Read, Wr/Rd Signed-off-by: Brandon-Hurst --- ports/analog/Makefile | 15 +- ports/analog/common-hal/busio/I2C.c | 131 ++++++++++++++++-- ports/analog/common-hal/busio/I2C.h | 7 +- ports/analog/max32_port.h | 2 +- ports/analog/peripherals/max32690/max32_i2c.c | 35 +++++ ports/analog/peripherals/max32690/max32_i2c.h | 16 +++ 6 files changed, 194 insertions(+), 12 deletions(-) create mode 100644 ports/analog/peripherals/max32690/max32_i2c.c create mode 100644 ports/analog/peripherals/max32690/max32_i2c.h diff --git a/ports/analog/Makefile b/ports/analog/Makefile index 96f9037aae924..cba5608feaad6 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -88,7 +88,11 @@ INC += \ -I$(PERIPH_SRC)/TMR \ -I$(PERIPH_SRC)/RTC \ -I$(PERIPH_SRC)/UART \ +<<<<<<< HEAD -I$(PERIPH_SRC)/TRNG +======= + -I$(PERIPH_SRC)/I2C +>>>>>>> edf069d0e7 (Add BUSIO.I2C and MAX32690 I2C structure) INC += -I$(CMSIS_ROOT)/Device/Maxim/$(MCU_VARIANT_UPPER)/Source/GCC @@ -124,13 +128,17 @@ SRC_MAX32 += \ $(PERIPH_SRC)/UART/uart_revb.c \ $(PERIPH_SRC)/TRNG/trng_revb.c \ $(PERIPH_SRC)/TRNG/trng_$(DIE_TYPE).c + $(PERIPH_SRC)/I2C/i2c_$(DIE_TYPE).c \ + $(PERIPH_SRC)/I2C/i2c_reva.c SRC_C += $(SRC_MAX32) \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/gpios.c \ - peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c + peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_i2c.c + # ******************************************************************************* ### Compiler & Linker Flags ### @@ -271,6 +279,11 @@ flash-msdk: -f interface/cmsis-dap.cfg -f target/$(MCU_VARIANT_LOWER).cfg \ -c "program $(BUILD)/firmware.elf verify; init; reset; exit" +flash-openocd-jlink: + $(OPENOCD) -s $(OPENOCD_SCRIPTS) \ + -f interface/jlink.cfg -f target/$(MCU_VARIANT_LOWER).cfg \ + -c "program $(BUILD)/firmware.elf verify; init; reset; exit" + # flash target using JLink JLINK_DEVICE = $(MCU_VARIANT_LOWER) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index a8080fa5bc10d..306b4bc8f4ab1 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -30,7 +30,38 @@ #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -static bool in_used = false; +#include "max32_port.h" + +#define I2C_PRIORITY 1 + +typedef enum { + I2C_FREE = 0, + I2C_BUSY, + I2C_NEVER_RESET, +} i2c_status_t; + +// Set each bit to indicate an active UART +// will be checked by ISR Handler for which ones to call +static uint8_t i2c_active = 0; +static i2c_status_t i2c_status[NUM_I2C]; +static volatile int i2c_err; + +// I2C Interrupt Handler +void i2c_isr(void) { + for (int i = 0; i < NUM_I2C; i++) { + if (i2c_active & (1 << i)) { + // NOTE: I2C_GET_TMR actually returns the I2C registers + MXC_I2C_AsyncHandler(MXC_I2C_GET_I2C(i)); + } + } +} + +// Callback gets called when AsyncRequest is COMPLETE +// (e.g. txLen == txCnt) +// static volatile void i2cCallback(mxc_i2c_req_t *req, int error) { +// i2c_status[MXC_I2C_GET_IDX(req->i2c)] = I2C_FREE; +// i2c_err = error; +// } // Construct I2C protocol, this function init i2c peripheral void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, @@ -38,7 +69,64 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - + int temp, err = 0; + + // Check for NULL Pointers && valid I2C settings + assert(self); + + // Assign I2C ID based on pins + temp = pinsToI2c(sda, scl); + if (temp == -1) { + // Error will be indicated by pinsToUart(tx, rx) function + return; + } else { + self->i2c_id = temp; + self->i2c_regs = MXC_I2C_GET_I2C(temp); + } + + assert((self->i2c_id >= 0) && (self->i2c_id < NUM_I2C)); + + // Init I2C as main / controller node (0x00 is ignored) + if ((scl != NULL) && (sda != NULL)) { + err = MXC_I2C_Init(self->i2c_regs, 1, 0x00); + if (err) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init I2C.\n")); + } + err = MXC_I2C_SetFrequency(self->i2c_regs, frequency); + if (err < 0) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to set I2C frequency\n")); + } + } else if (scl != NULL) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); + } else if (sda != NULL) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); + } else { + // Should not get here, as shared-bindings API should not call this way + } + + // Attach I2C pins + self->sda = sda; + self->scl = scl; + common_hal_mcu_pin_claim(self->sda); + common_hal_mcu_pin_claim(self->scl); + + // Indicate to this module that the I2C is active + i2c_active |= (1 << self->i2c_id); + + // Set the timeout to a default value + if (((timeout < 0.0) || (timeout > 100.0))) { + self->timeout = 1.0; + } else { + self->timeout = timeout; + } + + /* Setup I2C interrupt */ + NVIC_ClearPendingIRQ(MXC_I2C_GET_IRQ(self->i2c_id)); + NVIC_DisableIRQ(MXC_I2C_GET_IRQ(self->i2c_id)); + NVIC_SetPriority(MXC_I2C_GET_IRQ(self->i2c_id), I2C_PRIORITY); + NVIC_SetVector(MXC_I2C_GET_IRQ(self->i2c_id), (uint32_t)i2c_isr); + + return; } // Never reset I2C obj when reload @@ -54,7 +142,13 @@ bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { // Deinit i2c obj, reset I2C pin void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { - // FIXME: Implement + MXC_I2C_Shutdown(self->i2c_regs); + + common_hal_reset_pin(self->sda); + common_hal_reset_pin(self->scl); + + self->sda = NULL; + self->scl = NULL; } void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { @@ -63,17 +157,36 @@ void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - // FIXME: Implement - - return true; + int nack = 0; + + mxc_i2c_req_t addr_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_len = 0, + .tx_buf = NULL, + .rx_len = 0, + .rx_buf = NULL, + .callback = NULL + }; + + // Probe the address + nack = MXC_I2C_MasterTransaction(&addr_req); + if (nack) { + return false; + } else { + return true; + } } // Lock I2C bus bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { - // FIXME: Implement - - return false; + if (self->i2c_regs->status & MXC_F_I2C_STATUS_BUSY) { + return false; + } else { + self->has_lock = true; + return true; + } } // Check I2C lock status diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h index 9571a8ab694f4..2c7ffec20785e 100644 --- a/ports/analog/common-hal/busio/I2C.h +++ b/ports/analog/common-hal/busio/I2C.h @@ -17,8 +17,13 @@ // Define a struct for what BUSIO.I2C should carry typedef struct { mp_obj_base_t base; + + int i2c_id; mxc_i2c_regs_t *i2c_regs; - bool has_lock; const mcu_pin_obj_t *scl; const mcu_pin_obj_t *sda; + const int frequency; + + uint32_t timeout; + bool has_lock; } busio_i2c_obj_t; diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index 3b4fe7bc87d90..fcab5b5976238 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -24,7 +24,7 @@ // UART Ports & pins #include "peripherals/max32690/max32_uart.h" -#define NUM_UARTS 4 +#include "peripherals/max32690/max32_i2c.h" /** START: GPIO4 Handling specific to MAX32690 */ #define GPIO4_PIN_MASK 0x00000003 diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c new file mode 100644 index 0000000000000..8a13cf7a9a5a3 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -0,0 +1,35 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/I2C.h" +#include "max32_i2c.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + +const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { + // I2C0A + { MXC_GPIO0, (MXC_GPIO_PIN_30 | MXC_GPIO_PIN_31), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // I2C1A + { MXC_GPIO2, (MXC_GPIO_PIN_17 | MXC_GPIO_PIN_18), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, +}; + +int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { + for (int i = 0; i < NUM_I2C; i++) { + if ((i2c_maps[i].port == (MXC_GPIO_GET_GPIO(sda->port))) + && (i2c_maps[i].mask == ((sda->mask) | (scl->mask)))) { + return i; + } + } + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an I2C matching pins...\nSCL: port %d mask %d\nSDA: port %d mask %d\n"), + sda->port, sda->mask, scl->port, scl->mask); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_i2c.h b/ports/analog/peripherals/max32690/max32_i2c.h new file mode 100644 index 0000000000000..3e554da5abcde --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_i2c.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "i2c_regs.h" +#include "mxc_sys.h" +#include "i2c.h" +#include "peripherals/pins.h" + +#define NUM_I2C 2 + +int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl); From 00c53ea87d3da15e53843ba1177f140bab4bed2b Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Fri, 7 Mar 2025 00:37:46 -0800 Subject: [PATCH 57/78] Add hardware mapping for BUSIO.SPI for MAX32690 Currently coupled a bit to APARD32690-SL board. Will refactor after testing BUSIO.SPI Signed-off-by: Brandon-Hurst --- ports/analog/Makefile | 16 +++--- ports/analog/peripherals/max32690/max32_spi.c | 49 +++++++++++++++++++ ports/analog/peripherals/max32690/max32_spi.h | 17 +++++++ 3 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 ports/analog/peripherals/max32690/max32_spi.c create mode 100644 ports/analog/peripherals/max32690/max32_spi.h diff --git a/ports/analog/Makefile b/ports/analog/Makefile index cba5608feaad6..bd26cdd80f295 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -88,11 +88,9 @@ INC += \ -I$(PERIPH_SRC)/TMR \ -I$(PERIPH_SRC)/RTC \ -I$(PERIPH_SRC)/UART \ -<<<<<<< HEAD - -I$(PERIPH_SRC)/TRNG -======= - -I$(PERIPH_SRC)/I2C ->>>>>>> edf069d0e7 (Add BUSIO.I2C and MAX32690 I2C structure) + -I$(PERIPH_SRC)/TRNG \ + -I$(PERIPH_SRC)/I2C \ + -I$(PERIPH_SRC)/SPI INC += -I$(CMSIS_ROOT)/Device/Maxim/$(MCU_VARIANT_UPPER)/Source/GCC @@ -129,7 +127,9 @@ SRC_MAX32 += \ $(PERIPH_SRC)/TRNG/trng_revb.c \ $(PERIPH_SRC)/TRNG/trng_$(DIE_TYPE).c $(PERIPH_SRC)/I2C/i2c_$(DIE_TYPE).c \ - $(PERIPH_SRC)/I2C/i2c_reva.c + $(PERIPH_SRC)/I2C/i2c_reva.c \ + $(PERIPH_SRC)/SPI/spi_$(DIE_TYPE).c \ + $(PERIPH_SRC)/SPI/spi_reva1.c SRC_C += $(SRC_MAX32) \ boards/$(BOARD)/board.c \ @@ -137,8 +137,8 @@ SRC_C += $(SRC_MAX32) \ peripherals/$(MCU_VARIANT_LOWER)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/gpios.c \ peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c \ - peripherals/$(MCU_VARIANT_LOWER)/max32_i2c.c - + peripherals/$(MCU_VARIANT_LOWER)/max32_i2c.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_spi.c # ******************************************************************************* ### Compiler & Linker Flags ### diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c new file mode 100644 index 0000000000000..587349b7e2140 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -0,0 +1,49 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/SPI.h" +#include "max32_spi.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + +// TODO Decouple from APARD board +const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { + // DUMMY entry for SPI0 (not on APARD board) + { MXC_GPIO0, 0xFFFFFFFF, 0, 0, 0, 0}, + + // SPI1A + { MXC_GPIO1, (MXC_GPIO_PIN_23 | MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI2A + { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4 | MXC_GPIO_PIN_5), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI3A + { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_19 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI4A + { MXC_GPIO1, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, +}; + +int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, + const mcu_pin_obj_t *sck, const mcu_pin_obj_t *cs) { + for (int i = 0; i < NUM_SPI; i++) { + if ((spi_maps[i].port == (MXC_GPIO_GET_GPIO(mosi->port))) + && (spi_maps[i].mask == ((cs->mask) | (mosi->mask) | (miso->mask) | (sck->mask)))) { + return i; + } + } + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an SPI matching pins... \ + \nMOSI: port %d mask %d\nMISO: port %d mask %d\n \ + \nSCK: port %d mask %d\nCS: port %d mask%d\n"), + mosi->port, mosi->mask, miso->port, miso->mask, + sck->port, sck->mask, cs->port, cs->mask); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_spi.h b/ports/analog/peripherals/max32690/max32_spi.h new file mode 100644 index 0000000000000..d0b9c83201c2b --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_spi.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "spi_regs.h" +#include "mxc_sys.h" +#include "spi.h" +#include "peripherals/pins.h" + +#define NUM_SPI 5 + +int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, + const mcu_pin_obj_t *sck, const mcu_pin_obj_t *cs); From 1d30ce794d1499168c08930f37d73e3e95e33596 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Fri, 7 Mar 2025 02:16:40 -0800 Subject: [PATCH 58/78] Add complete BUSIO driver structure for SPI & I2C. TODO: - Figure out assigning CS Pins for SPI - Test & Debug SPI / I2C Signed-off-by: Brandon-Hurst --- ports/analog/common-hal/busio/I2C.c | 50 +++- ports/analog/common-hal/busio/SPI.c | 214 +++++++++++++++++- ports/analog/common-hal/busio/SPI.h | 9 +- ports/analog/max32_port.h | 1 + ports/analog/peripherals/max32690/max32_spi.c | 17 +- ports/analog/peripherals/max32690/max32_spi.h | 2 +- 6 files changed, 267 insertions(+), 26 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 306b4bc8f4ab1..1834db0e4a3d4 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -200,28 +200,72 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address +// todo test uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { - // FIXME: Implement + int ret; + mxc_i2c_req_t wr_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = (uint8_t *)data, + .tx_len = len, + .rx_buf = NULL, + .rx_len = 0, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&wr_req); + if (ret) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + } + return 0; } // Read into buffer from the device selected by address +// todo test uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - // FIXME: Implement + int ret; + mxc_i2c_req_t rd_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = NULL, + .tx_len = 0, + .rx_buf = data, + .rx_len = len, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&rd_req); + if (ret) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + } + return 0; } // Write the bytes from out_data to the device selected by address, +// todo test uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - // FIXME: Implement + int ret; + mxc_i2c_req_t wr_rd_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = out_data, + .tx_len = out_len, + .rx_buf = in_data, + .rx_len = in_len, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&wr_rd_req); + if (ret) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + } return 0; } diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 083403b12bbe3..0c882d3ecc991 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -31,9 +31,35 @@ #include "supervisor/board.h" #include "shared-bindings/microcontroller/Pin.h" +#include "max32_port.h" +#include "spi_reva1.h" + // Note that any bugs introduced in this file can cause crashes // at startupfor chips using external SPI flash. +#define SPI_PRIORITY 1 + +typedef enum { + SPI_FREE = 0, + SPI_BUSY, + SPI_NEVER_RESET, +} spi_status_t; + +// Set each bit to indicate an active SPI +// will be checked by ISR Handler for which ones to call +static uint8_t spi_active = 0; +static spi_status_t spi_status[NUM_SPI]; +static volatile int spi_err; + +// SPI Interrupt Handler +void spi_isr(void) { + for (int i = 0; i < NUM_SPI; i++) { + if (spi_active & (1 << i)) { + MXC_SPI_AsyncHandler(MXC_SPI_GET_SPI(i)); + } + } +} + // Reset SPI when reload void spi_reset(void) { // FIXME: Implement @@ -41,19 +67,69 @@ void spi_reset(void) { } // Construct SPI protocol, this function init SPI peripheral +// todo: figure out Chip select behavior void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + int temp, err = 0; + // Check for NULL Pointers && valid I2C settings + assert(self); - // FIXME: Implement + // Assign I2C ID based on pins + temp = pinsToSpi(mosi, miso, sck); + if (temp == -1) { + // Error will be indicated by pinsToUart(tx, rx) function + return; + } else { + self->spi_id = temp; + self->spi_regs = MXC_SPI_GET_SPI(temp); + } + + assert((self->spi_id >= 0) && (self->spi_id < NUM_SPI)); + + // Init I2C as main / controller node (0x00 is ignored) + // FIXME: MUST map the SPI pins to a spi_pins_t struct + if ((mosi != NULL) && (miso != NULL) && (sck != NULL)) { + // spi, mastermode, quadModeUsed, numSubs, ssPolarity, frequency + err = MXC_SPI_RevA1_Init((mxc_spi_reva_regs_t *)self->spi_regs, 1, 0, 1, 0x00, 1000000); + if (err) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init SPI.\n")); + } + } else { + mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); + } + + // Attach SPI pins + self->mosi = mosi; + self->miso = miso; + self->sck = sck; + common_hal_mcu_pin_claim(self->mosi); + common_hal_mcu_pin_claim(self->miso); + common_hal_mcu_pin_claim(self->sck); + + // Indicate to this module that the SPI is active + spi_active |= (1 << self->spi_id); + + /* Setup I2C interrupt */ + NVIC_ClearPendingIRQ(MXC_SPI_GET_IRQ(self->spi_id)); + NVIC_DisableIRQ(MXC_SPI_GET_IRQ(self->spi_id)); + NVIC_SetPriority(MXC_SPI_GET_IRQ(self->spi_id), SPI_PRIORITY); + NVIC_SetVector(MXC_SPI_GET_IRQ(self->spi_id), (uint32_t)spi_isr); + + return; } // Never reset SPI when reload void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - // FIXME: Implement + common_hal_never_reset_pin(self->mosi); + common_hal_never_reset_pin(self->miso); + common_hal_never_reset_pin(self->sck); + common_hal_never_reset_pin(self->nss); + + spi_status[self->spi_id] = SPI_NEVER_RESET; } // Check SPI status, deinited or not @@ -64,7 +140,16 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { - // FIXME: Implement + MXC_SPI_Shutdown(self->spi_regs); + common_hal_reset_pin(self->mosi); + common_hal_reset_pin(self->miso); + common_hal_reset_pin(self->sck); + common_hal_reset_pin(self->nss); + + self->mosi = NULL; + self->miso = NULL; + self->sck = NULL; + self->nss = NULL; } // Configures the SPI bus. The SPI object must be locked. @@ -74,14 +159,58 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint8_t phase, uint8_t bits) { - // FIXME: Implement + mxc_spi_clkmode_t clk_mode; + int ret; + + self->baudrate = baudrate; + self->polarity = polarity; + self->phase = phase; + self->bits = bits; + + switch ((polarity << 1) | (phase)) { + case 0b00: + clk_mode = MXC_SPI_CLKMODE_0; + break; + case 0b01: + clk_mode = MXC_SPI_CLKMODE_1; + break; + case 0b10: + clk_mode = MXC_SPI_CLKMODE_2; + break; + case 0b11: + clk_mode = MXC_SPI_CLKMODE_3; + break; + default: + mp_raise_ValueError(MP_ERROR_TEXT("CPOL / CPHA must both be either 0 or 1\n")); + return false; + } + + ret = MXC_SPI_SetFrequency(self->spi_regs, baudrate); + if (ret) { + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Frequency\n")); + return false; + } + ret = MXC_SPI_SetDataSize(self->spi_regs, bits); + if (ret) { + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Frame Size\n")); + return false; + } + ret = MXC_SPI_SetMode(self->spi_regs, clk_mode); + if (ret) { + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Clock Mode\n")); + return false; + } return true; } // Lock SPI bus bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { - // FIXME: Implement - return false; + if (spi_status[self->spi_id] != SPI_BUSY) { + self->has_lock = true; + return true; + } else { + return false; + } } // Check SPI lock status @@ -98,9 +227,27 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { + int ret = 0; - // FIXME: Implement - return false; + mxc_spi_req_t wr_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = (uint8_t *)data, + .txLen = len, + .rxData = NULL, + .rxLen = 0, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = 0xFF, + }; + ret = MXC_SPI_MasterTransaction(&wr_req); + if (ret) { + return false; + } else { + return true; + } } // Read data into buffer @@ -108,8 +255,32 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { - // FIXME: Implement - return false; + int ret = 0; + // uint8_t tx_buffer[len] = {0x0}; + + // for (int i = 0; i < len; i++) { + // tx_buffer[i] = write_value; + // } + + mxc_spi_req_t rd_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = NULL, + .txLen = len, + .rxData = data, + .rxLen = len, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = write_value, + }; + ret = MXC_SPI_MasterTransaction(&rd_req); + if (ret) { + return false; + } else { + return true; + } } // Write out the data in data_out @@ -119,8 +290,27 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_in, size_t len) { - // FIXME: Implement - return false; + int ret = 0; + + mxc_spi_req_t rd_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = (uint8_t *)data_out, + .txLen = len, + .rxData = data_in, + .rxLen = len, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = 0xFF, + }; + ret = MXC_SPI_MasterTransaction(&rd_req); + if (ret) { + return false; + } else { + return true; + } } // Get SPI baudrate diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h index d90f55da111a0..e70d4234d9407 100644 --- a/ports/analog/common-hal/busio/SPI.h +++ b/ports/analog/common-hal/busio/SPI.h @@ -17,17 +17,24 @@ // Define a struct for what BUSIO.SPI should carry typedef struct { mp_obj_base_t base; + + // Spi regs & pins + int spi_id; mxc_spi_regs_t *spi_regs; - bool has_lock; const mcu_pin_obj_t *sck; const mcu_pin_obj_t *mosi; const mcu_pin_obj_t *miso; const mcu_pin_obj_t *nss; + + // Configuration uint32_t baudrate; uint16_t prescaler; uint8_t polarity; uint8_t phase; uint8_t bits; + + // Synch data + bool has_lock; } busio_spi_obj_t; void spi_reset(void); diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index fcab5b5976238..89830e96b0a49 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -25,6 +25,7 @@ // UART Ports & pins #include "peripherals/max32690/max32_uart.h" #include "peripherals/max32690/max32_i2c.h" +#include "peripherals/max32690/max32_spi.h" /** START: GPIO4 Handling specific to MAX32690 */ #define GPIO4_PIN_MASK 0x00000003 diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c index 587349b7e2140..5a1dc8a9dc2f1 100644 --- a/ports/analog/peripherals/max32690/max32_spi.c +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -19,31 +19,30 @@ const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { { MXC_GPIO0, 0xFFFFFFFF, 0, 0, 0, 0}, // SPI1A - { MXC_GPIO1, (MXC_GPIO_PIN_23 | MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), + { MXC_GPIO1, (MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // SPI2A - { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4 | MXC_GPIO_PIN_5), + { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // SPI3A - { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_19 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), + { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // SPI4A - { MXC_GPIO1, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), + { MXC_GPIO1, (MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, }; int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, - const mcu_pin_obj_t *sck, const mcu_pin_obj_t *cs) { + const mcu_pin_obj_t *sck) { for (int i = 0; i < NUM_SPI; i++) { if ((spi_maps[i].port == (MXC_GPIO_GET_GPIO(mosi->port))) - && (spi_maps[i].mask == ((cs->mask) | (mosi->mask) | (miso->mask) | (sck->mask)))) { + && (spi_maps[i].mask == ((mosi->mask) | (miso->mask) | (sck->mask)))) { return i; } } mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an SPI matching pins... \ - \nMOSI: port %d mask %d\nMISO: port %d mask %d\n \ - \nSCK: port %d mask %d\nCS: port %d mask%d\n"), + \nMOSI: port %d mask %d\nMISO: port %d mask %d\n"), mosi->port, mosi->mask, miso->port, miso->mask, - sck->port, sck->mask, cs->port, cs->mask); + sck->port, sck->mask); return -1; } diff --git a/ports/analog/peripherals/max32690/max32_spi.h b/ports/analog/peripherals/max32690/max32_spi.h index d0b9c83201c2b..76bb48a59a7e5 100644 --- a/ports/analog/peripherals/max32690/max32_spi.h +++ b/ports/analog/peripherals/max32690/max32_spi.h @@ -14,4 +14,4 @@ #define NUM_SPI 5 int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, - const mcu_pin_obj_t *sck, const mcu_pin_obj_t *cs); + const mcu_pin_obj_t *sck); From 7cccb66c2a9ea426eeff6d468f9ecd2b10da337f Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Fri, 7 Mar 2025 13:28:36 -0800 Subject: [PATCH 59/78] Add call to MXC_DelayHandler in SysTick ISR Signed-off-by: Brandon-Hurst --- ports/analog/supervisor/port.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index de83b011bdf0d..40e8e1d605038 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -73,6 +73,8 @@ volatile uint32_t system_ticks = 0; void SysTick_Handler(void) { system_ticks++; + + MXC_DelayHandler(); } From ebfbd01ce103d56655052efd5d6b3b71f5d49c85 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Fri, 7 Mar 2025 14:35:50 -0800 Subject: [PATCH 60/78] Corrected I2C & SPI. Tested with example scripts; works with real peripherals. Signed-off-by: Brandon-Hurst --- ports/analog/Makefile | 2 +- ports/analog/common-hal/busio/I2C.c | 8 ++++++-- ports/analog/common-hal/busio/SPI.c | 20 ++++++++++++++++++- ports/analog/peripherals/max32690/max32_i2c.c | 4 ++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/ports/analog/Makefile b/ports/analog/Makefile index bd26cdd80f295..4a758eff9c46d 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -288,7 +288,7 @@ flash-openocd-jlink: JLINK_DEVICE = $(MCU_VARIANT_LOWER) JLINKEXE ?= JLink.exe -JLINKEXE += -if SWD -device ${JLINK_DEVICE} -speed 10000 +JLINKEXE += -if SWD -device ${JLINK_DEVICE} -speed 4000 COMMAND_FILE := tools/flash_max32.jlink flash-jlink: $(BUILD)/firmware.bin diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 1834db0e4a3d4..cba8fca94f50e 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -46,6 +46,9 @@ static uint8_t i2c_active = 0; static i2c_status_t i2c_status[NUM_I2C]; static volatile int i2c_err; +// I2C struct for configuring GPIO pins +extern const mxc_gpio_cfg_t i2c_maps[NUM_I2C]; + // I2C Interrupt Handler void i2c_isr(void) { for (int i = 0; i < NUM_I2C; i++) { @@ -88,13 +91,14 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // Init I2C as main / controller node (0x00 is ignored) if ((scl != NULL) && (sda != NULL)) { + MXC_GPIO_Config(&i2c_maps[self->i2c_id]); err = MXC_I2C_Init(self->i2c_regs, 1, 0x00); if (err) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init I2C.\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to init I2C. ERR: %d\n"), err); } err = MXC_I2C_SetFrequency(self->i2c_regs, frequency); if (err < 0) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to set I2C frequency\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to set I2C frequency. ERR: %d\n"), err); } } else if (scl != NULL) { mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 0c882d3ecc991..7f19ebd1f945c 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -88,13 +88,28 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, self->spi_regs = MXC_SPI_GET_SPI(temp); } + // Other pins default to true + mxc_spi_pins_t spi_pins = { + .clock = TRUE, + .mosi = TRUE, + .miso = TRUE, + .ss0 = FALSE, + .ss1 = FALSE, + .ss2 = FALSE, + .vddioh = true, + .drvstr = MXC_GPIO_DRVSTR_0 + }; + assert((self->spi_id >= 0) && (self->spi_id < NUM_SPI)); // Init I2C as main / controller node (0x00 is ignored) // FIXME: MUST map the SPI pins to a spi_pins_t struct if ((mosi != NULL) && (miso != NULL) && (sck != NULL)) { // spi, mastermode, quadModeUsed, numSubs, ssPolarity, frequency - err = MXC_SPI_RevA1_Init((mxc_spi_reva_regs_t *)self->spi_regs, 1, 0, 1, 0x00, 1000000); + // err = MXC_SPI_Init((mxc_spi_reva_regs_t *)self->spi_regs, 1, 0, 1, 0x00, 1000000, &spi_pins); + err = MXC_SPI_Init(self->spi_regs, MXC_SPI_TYPE_CONTROLLER, MXC_SPI_INTERFACE_STANDARD, + 1, 0x01, 1000000, spi_pins); + MXC_GPIO_SetVSSEL(MXC_GPIO_GET_GPIO(sck->port), MXC_GPIO_VSSEL_VDDIOH, (sck->mask | miso->mask | mosi->mask | MXC_GPIO_PIN_0)); if (err) { mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init SPI.\n")); } @@ -102,6 +117,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); } + // FIXME: Debugging + + // Attach SPI pins self->mosi = mosi; self->miso = miso; diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c index 8a13cf7a9a5a3..2dabc9b16a768 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.c +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -16,10 +16,10 @@ const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { // I2C0A { MXC_GPIO0, (MXC_GPIO_PIN_30 | MXC_GPIO_PIN_31), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, // I2C1A { MXC_GPIO2, (MXC_GPIO_PIN_17 | MXC_GPIO_PIN_18), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, }; int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { From 558eb93a590229c2eeff5c93b30500d8a8b90990 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Mon, 17 Mar 2025 17:14:08 -0700 Subject: [PATCH 61/78] Add extra I2C options for MAX32690 non-TQFN packages Also reformatted pinmaps for SPI/I2C/UART on MAX32690 Signed-off-by: Brandon Hurst --- ports/analog/peripherals/max32690/max32_i2c.c | 41 +++++++++++++++++++ ports/analog/peripherals/max32690/max32_spi.c | 15 ++++--- .../analog/peripherals/max32690/max32_uart.c | 20 +++------ 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c index 2dabc9b16a768..d5c8da0743129 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.c +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -13,14 +13,44 @@ #include "py/runtime.h" #include "py/mperrno.h" + +/* Note: The MAX32690 assigns the same alternate function to multiple sets + * of pins. The drivers will enable both sets so that either can be used. + * Users should ensure the unused set is left unconnected. + * + * See MAX32690 Rev A2 Errata #16: + * https://www.analog.com/media/en/technical-documentation/data-sheets/max32690_a2_errata_rev2.pdf + * + * Additionally, note that the TQFN package does not expose some of the duplicate pins. For this package, + * enabling the un-routed GPIOs has been shown to cause initialization issues with the I2C block. + * To work around this, "MAX32690GTK_PACKAGE_TQFN" can be defined by the build system. The recommend place + * to do it is in the "board.mk" file of the BSP. This will prevent the inaccessible pins from being configured. + */ + const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { + // I2C0 + { MXC_GPIO2, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + // I2C1 + { MXC_GPIO0, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + // I2C2 + { MXC_GPIO1, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT3, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 };, +}; +#ifndef MAX32690GTK_PACKAGE_TQFN +const mxc_gpio_cfg_t i2c_maps_extra[NUM_I2C] = { // I2C0A { MXC_GPIO0, (MXC_GPIO_PIN_30 | MXC_GPIO_PIN_31), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, // I2C1A { MXC_GPIO2, (MXC_GPIO_PIN_17 | MXC_GPIO_PIN_18), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, + // I2C2C + { MXC_GPIO0, (MXC_GPIO_PIN_13 | MXC_GPIO_PIN_14), MXC_GPIO_FUNC_ALT3, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 };, }; +#endif int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { for (int i = 0; i < NUM_I2C; i++) { @@ -29,6 +59,17 @@ int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { return i; } } + + // Additional for loop to cover alternate potential I2C maps + #ifndef MAX32690GTK_PACKAGE_TQFN + for (int i = 0; i < NUM_I2C; i++) { + if ((i2c_maps_extra[i].port == (MXC_GPIO_GET_GPIO(sda->port))) + && (i2c_maps_extra[i].mask == ((sda->mask) | (scl->mask)))) { + return i; + } + } + #endif + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an I2C matching pins...\nSCL: port %d mask %d\nSDA: port %d mask %d\n"), sda->port, sda->mask, scl->port, scl->mask); return -1; diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c index 5a1dc8a9dc2f1..ecd197036a49d 100644 --- a/ports/analog/peripherals/max32690/max32_spi.c +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -13,21 +13,20 @@ #include "py/runtime.h" #include "py/mperrno.h" -// TODO Decouple from APARD board const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { - // DUMMY entry for SPI0 (not on APARD board) - { MXC_GPIO0, 0xFFFFFFFF, 0, 0, 0, 0}, - - // SPI1A + // SPI0 + { MXC_GPIO2, (MXC_GPIO_PIN_27 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + // SPI1 { MXC_GPIO1, (MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - // SPI2A + // SPI2 { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - // SPI3A + // SPI3 { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - // SPI4A + // SPI4 { MXC_GPIO1, (MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, }; diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c index 3ccb930d85c14..3cfcc75ca0dc0 100644 --- a/ports/analog/peripherals/max32690/max32_uart.c +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -13,29 +13,19 @@ #include "py/runtime.h" #include "py/mperrno.h" -// FIXME: Remove upon test! -// mxc_uart_regs_t max32_uarts[NUM_UARTS] = { -// MXC_UART0, -// MXC_UART1, -// MXC_UART2, -// MXC_UART3, -// }; - const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { { MXC_GPIO2, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), - MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, - MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), - MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, - MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } + { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), MXC_GPIO_FUNC_ALT2, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } }; int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { - for (int i = 0; i < NUM_UARTS; i++) { + for (int i = 0; i < uart_entries; i++) { if ((uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) && (uart_maps[i].mask == ((tx->mask) | (rx->mask)))) { return i; From 479e0e181122c8888acd0c79151ce0e2c88bf28f Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Thu, 1 May 2025 17:23:33 -0700 Subject: [PATCH 62/78] Clean up MAX32 BUSIO drivers - Fixed errors with peripheral bus hardware descriptions in MAX32690 "peripherals/" - Resolved all FIXME comments - Removed unused ringbuf API from common-hal/busio/UART.c Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/I2C.c | 4 --- ports/analog/common-hal/busio/SPI.c | 13 +--------- ports/analog/common-hal/busio/UART.c | 25 ++++--------------- ports/analog/common-hal/busio/UART.h | 2 -- ports/analog/peripherals/max32690/max32_i2c.c | 10 ++++---- ports/analog/peripherals/max32690/max32_i2c.h | 2 +- ports/analog/peripherals/max32690/max32_spi.c | 2 +- .../analog/peripherals/max32690/max32_uart.c | 6 ++--- 8 files changed, 16 insertions(+), 48 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index cba8fca94f50e..f8a5a8bd20971 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -155,10 +155,6 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { self->scl = NULL; } -void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { - // FIXME: Implement -} - // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { int nack = 0; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 7f19ebd1f945c..d158f09673189 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -60,12 +60,6 @@ void spi_isr(void) { } } -// Reset SPI when reload -void spi_reset(void) { - // FIXME: Implement - return; -} - // Construct SPI protocol, this function init SPI peripheral // todo: figure out Chip select behavior void common_hal_busio_spi_construct(busio_spi_obj_t *self, @@ -102,11 +96,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, assert((self->spi_id >= 0) && (self->spi_id < NUM_SPI)); - // Init I2C as main / controller node (0x00 is ignored) - // FIXME: MUST map the SPI pins to a spi_pins_t struct + // Init SPI controller if ((mosi != NULL) && (miso != NULL) && (sck != NULL)) { // spi, mastermode, quadModeUsed, numSubs, ssPolarity, frequency - // err = MXC_SPI_Init((mxc_spi_reva_regs_t *)self->spi_regs, 1, 0, 1, 0x00, 1000000, &spi_pins); err = MXC_SPI_Init(self->spi_regs, MXC_SPI_TYPE_CONTROLLER, MXC_SPI_INTERFACE_STANDARD, 1, 0x01, 1000000, spi_pins); MXC_GPIO_SetVSSEL(MXC_GPIO_GET_GPIO(sck->port), MXC_GPIO_VSSEL_VDDIOH, (sck->mask | miso->mask | mosi->mask | MXC_GPIO_PIN_0)); @@ -117,9 +109,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); } - // FIXME: Debugging - - // Attach SPI pins self->mosi = mosi; self->miso = miso; diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 310965e34609b..408ae8452352e 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -96,7 +96,7 @@ static uint32_t timeout_ms = 0; static uint8_t uarts_active = 0; static uart_status_t uart_status[NUM_UARTS]; static volatile int uart_err; -// static uint8_t uart_never_reset_mask = 0; +static uint8_t uart_never_reset_mask = 0; static int isValidBaudrate(uint32_t baudrate) { switch (baudrate) { @@ -167,8 +167,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, const mcu_pin_obj_t *rs485_dir, bool rs485_invert, uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, - mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, - bool sigint_enabled) { + mp_float_t timeout, bool sigint_enabled) { int err, temp; // Check for NULL Pointers && valid UART settings @@ -236,21 +235,6 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->baudrate = baudrate; self->error = E_NO_ERROR; - // Initialize ringbuffer for receiving data - // FIXME: Either the use the ringbuf or get rid of it! - if (self->rx_pin) { - // if given a ringbuff, use that - if (receiver_buffer) { - ringbuf_init(&self->ringbuf, receiver_buffer, receiver_buffer_size); - } - // else create one and attach it - else { - if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size)) { - m_malloc_fail(receiver_buffer_size); - } - } - } - // Indicate to this module that the UART is active uarts_active |= (1 << self->uart_id); @@ -277,6 +261,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { // First disable the ISR to avoid pre-emption NVIC_DisableIRQ(UART0_IRQn); + // Shutdown the UART Controller MXC_UART_Shutdown(self->uart_regs); self->error = E_UNINITIALIZED; @@ -307,7 +292,7 @@ bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { }; } -// Read characters. len is in characters NOT bytes! +// Read characters. len is in characters. size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { int err; @@ -474,7 +459,7 @@ void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { common_hal_never_reset_pin(self->rx_pin); common_hal_never_reset_pin(self->cts_pin); common_hal_never_reset_pin(self->rts_pin); - // uart_never_reset_mask |= ( 1 << (self->uart_id) ); + uart_never_reset_mask |= (1 << (self->uart_id)); } #endif // CIRCUITPY_BUSIO_UART diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index f24f310fe3a52..c2c2d837ca8a5 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -33,8 +33,6 @@ typedef struct { int error; float timeout; - ringbuf_t ringbuf; - const mcu_pin_obj_t *rx_pin; const mcu_pin_obj_t *tx_pin; const mcu_pin_obj_t *rts_pin; diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c index d5c8da0743129..daf665bbee741 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.c +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -20,7 +20,7 @@ * * See MAX32690 Rev A2 Errata #16: * https://www.analog.com/media/en/technical-documentation/data-sheets/max32690_a2_errata_rev2.pdf - * + * * Additionally, note that the TQFN package does not expose some of the duplicate pins. For this package, * enabling the un-routed GPIOs has been shown to cause initialization issues with the I2C block. * To work around this, "MAX32690GTK_PACKAGE_TQFN" can be defined by the build system. The recommend place @@ -30,13 +30,13 @@ const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { // I2C0 { MXC_GPIO2, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // I2C1 { MXC_GPIO0, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // I2C2 { MXC_GPIO1, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT3, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 };, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, }; #ifndef MAX32690GTK_PACKAGE_TQFN const mxc_gpio_cfg_t i2c_maps_extra[NUM_I2C] = { @@ -48,7 +48,7 @@ const mxc_gpio_cfg_t i2c_maps_extra[NUM_I2C] = { MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, // I2C2C { MXC_GPIO0, (MXC_GPIO_PIN_13 | MXC_GPIO_PIN_14), MXC_GPIO_FUNC_ALT3, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 };, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, }; #endif diff --git a/ports/analog/peripherals/max32690/max32_i2c.h b/ports/analog/peripherals/max32690/max32_i2c.h index 3e554da5abcde..b64cfd308dcf5 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.h +++ b/ports/analog/peripherals/max32690/max32_i2c.h @@ -11,6 +11,6 @@ #include "i2c.h" #include "peripherals/pins.h" -#define NUM_I2C 2 +#define NUM_I2C 3 int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl); diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c index ecd197036a49d..f2594787598b2 100644 --- a/ports/analog/peripherals/max32690/max32_spi.c +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -16,7 +16,7 @@ const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { // SPI0 { MXC_GPIO2, (MXC_GPIO_PIN_27 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), - MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // SPI1 { MXC_GPIO1, (MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c index 3cfcc75ca0dc0..5f7a8568fb426 100644 --- a/ports/analog/peripherals/max32690/max32_uart.c +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -18,14 +18,14 @@ const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), MXC_GPIO_FUNC_ALT1, + { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), MXC_GPIO_FUNC_ALT2, + { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } }; int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { - for (int i = 0; i < uart_entries; i++) { + for (int i = 0; i < NUM_UARTS; i++) { if ((uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) && (uart_maps[i].mask == ((tx->mask) | (rx->mask)))) { return i; From 3a8e56d0c8c5dacd664a0483217b85b189c5b0a9 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Thu, 1 May 2025 17:39:22 -0700 Subject: [PATCH 63/78] Cleanup copy-paste comments in MAX32 busio files Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/I2C.c | 27 +-------------------------- ports/analog/common-hal/busio/I2C.h | 1 - ports/analog/common-hal/busio/SPI.c | 22 ++-------------------- ports/analog/common-hal/busio/SPI.h | 1 - ports/analog/common-hal/busio/UART.c | 3 ++- ports/analog/common-hal/busio/UART.h | 5 ----- 6 files changed, 5 insertions(+), 54 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index f8a5a8bd20971..9fe903428f5b9 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -40,8 +40,7 @@ typedef enum { I2C_NEVER_RESET, } i2c_status_t; -// Set each bit to indicate an active UART -// will be checked by ISR Handler for which ones to call +// Set each bit to indicate an active I2c static uint8_t i2c_active = 0; static i2c_status_t i2c_status[NUM_I2C]; static volatile int i2c_err; @@ -49,23 +48,6 @@ static volatile int i2c_err; // I2C struct for configuring GPIO pins extern const mxc_gpio_cfg_t i2c_maps[NUM_I2C]; -// I2C Interrupt Handler -void i2c_isr(void) { - for (int i = 0; i < NUM_I2C; i++) { - if (i2c_active & (1 << i)) { - // NOTE: I2C_GET_TMR actually returns the I2C registers - MXC_I2C_AsyncHandler(MXC_I2C_GET_I2C(i)); - } - } -} - -// Callback gets called when AsyncRequest is COMPLETE -// (e.g. txLen == txCnt) -// static volatile void i2cCallback(mxc_i2c_req_t *req, int error) { -// i2c_status[MXC_I2C_GET_IDX(req->i2c)] = I2C_FREE; -// i2c_err = error; -// } - // Construct I2C protocol, this function init i2c peripheral void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, @@ -80,7 +62,6 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // Assign I2C ID based on pins temp = pinsToI2c(sda, scl); if (temp == -1) { - // Error will be indicated by pinsToUart(tx, rx) function return; } else { self->i2c_id = temp; @@ -124,12 +105,6 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, self->timeout = timeout; } - /* Setup I2C interrupt */ - NVIC_ClearPendingIRQ(MXC_I2C_GET_IRQ(self->i2c_id)); - NVIC_DisableIRQ(MXC_I2C_GET_IRQ(self->i2c_id)); - NVIC_SetPriority(MXC_I2C_GET_IRQ(self->i2c_id), I2C_PRIORITY); - NVIC_SetVector(MXC_I2C_GET_IRQ(self->i2c_id), (uint32_t)i2c_isr); - return; } diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h index 2c7ffec20785e..55c230ee2f97f 100644 --- a/ports/analog/common-hal/busio/I2C.h +++ b/ports/analog/common-hal/busio/I2C.h @@ -7,7 +7,6 @@ #pragma once #include "common-hal/microcontroller/Pin.h" -// FIXME: Silabs includes "peripherals/periph.h. Figure out what's in this file. " #include "py/obj.h" // HAL-specific diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index d158f09673189..999eb8490b0eb 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -46,22 +46,11 @@ typedef enum { } spi_status_t; // Set each bit to indicate an active SPI -// will be checked by ISR Handler for which ones to call static uint8_t spi_active = 0; static spi_status_t spi_status[NUM_SPI]; static volatile int spi_err; -// SPI Interrupt Handler -void spi_isr(void) { - for (int i = 0; i < NUM_SPI; i++) { - if (spi_active & (1 << i)) { - MXC_SPI_AsyncHandler(MXC_SPI_GET_SPI(i)); - } - } -} - // Construct SPI protocol, this function init SPI peripheral -// todo: figure out Chip select behavior void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi, @@ -69,13 +58,12 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, bool half_duplex) { int temp, err = 0; - // Check for NULL Pointers && valid I2C settings + // Check for NULL Pointer assert(self); - // Assign I2C ID based on pins + // Assign SPI ID based on pins temp = pinsToSpi(mosi, miso, sck); if (temp == -1) { - // Error will be indicated by pinsToUart(tx, rx) function return; } else { self->spi_id = temp; @@ -120,12 +108,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Indicate to this module that the SPI is active spi_active |= (1 << self->spi_id); - /* Setup I2C interrupt */ - NVIC_ClearPendingIRQ(MXC_SPI_GET_IRQ(self->spi_id)); - NVIC_DisableIRQ(MXC_SPI_GET_IRQ(self->spi_id)); - NVIC_SetPriority(MXC_SPI_GET_IRQ(self->spi_id), SPI_PRIORITY); - NVIC_SetVector(MXC_SPI_GET_IRQ(self->spi_id), (uint32_t)spi_isr); - return; } diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h index e70d4234d9407..d10601876fb5e 100644 --- a/ports/analog/common-hal/busio/SPI.h +++ b/ports/analog/common-hal/busio/SPI.h @@ -8,7 +8,6 @@ #define MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H #include "common-hal/microcontroller/Pin.h" -// FIXME: Silabs includes "peripherals/periph.h. Figure out what's in this file. " #include "py/obj.h" // HAL-specific diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 408ae8452352e..3b159c7b29026 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -167,7 +167,8 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, const mcu_pin_obj_t *rs485_dir, bool rs485_invert, uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, - mp_float_t timeout, bool sigint_enabled) { + mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, + bool sigint_enabled) { int err, temp; // Check for NULL Pointers && valid UART settings diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index c2c2d837ca8a5..a727116f7b882 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -9,11 +9,6 @@ #include "common-hal/microcontroller/Pin.h" #include "py/obj.h" -#include "py/ringbuf.h" - -// #include "uart.h" -// #include "uart_regs.h" -// #include "mxc_sys.h" #include "max32_port.h" From ba301159140b562debb10504af8eaba087a8e60a Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Mon, 5 May 2025 10:31:25 -0700 Subject: [PATCH 64/78] Correct ringbuffer code for ports/analog BUSIO - Add correct ringbuffer handling code to ports/analog/common-hal/UART.c Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/UART.c | 103 +++++++++++++++------------ ports/analog/common-hal/busio/UART.h | 8 +-- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 3b159c7b29026..f781da8705545 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -24,20 +24,27 @@ * THE SOFTWARE. */ +/** TODO: + * - Fix readline issue + * +*/ + #if CIRCUITPY_BUSIO_UART +#include "mpconfigport.h" +#include "supervisor/shared/tick.h" + #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -#include "supervisor/shared/tick.h" #include "shared-bindings/busio/UART.h" - #include "shared-bindings/microcontroller/Pin.h" - -#include "mpconfigport.h" #include "shared/readline/readline.h" #include "shared/runtime/interrupt_char.h" + #include "py/gc.h" +#include "py/ringbuf.h" #include "py/mperrno.h" +#include "py/mpprint.h" #include "py/runtime.h" #include "max32_port.h" @@ -47,29 +54,6 @@ // UART IRQ Priority #define UART_PRIORITY 1 -/** - * -// Define a struct for what BUSIO.UART should contain -typedef struct { - mp_obj_base_t base; - int uart_id; - mxc_uart_regs_t* uart_regs; - - const mcu_pin_obj_t *rx_pin; - const mcu_pin_obj_t *tx_pin; - const mcu_pin_obj_t *rts_pin; - const mcu_pin_obj_t *cts_pin; - - uint8_t bits; - uint32_t baudrate; - bool parity; - uint8_t stop_bits; - - uint32_t timeout_ms; - bool error; -} busio_uart_obj_t; - */ - typedef enum { UART_9600 = 9600, UART_14400 = 14400, @@ -82,7 +66,6 @@ typedef enum { UART_921600 = 921600, } uart_valid_baudrates; - typedef enum { UART_FREE = 0, UART_BUSY, @@ -97,6 +80,7 @@ static uint8_t uarts_active = 0; static uart_status_t uart_status[NUM_UARTS]; static volatile int uart_err; static uint8_t uart_never_reset_mask = 0; +static busio_uart_obj_t *context; static int isValidBaudrate(uint32_t baudrate) { switch (baudrate) { @@ -159,6 +143,10 @@ void uart_isr(void) { static volatile void uartCallback(mxc_uart_req_t *req, int error) { uart_status[MXC_UART_GET_IDX(req->uart)] = UART_FREE; uart_err = error; + + MXC_SYS_Crit_Enter(); + ringbuf_put_n(context->ringbuf, req->rxData, req->rxLen); + MXC_SYS_Crit_Exit(); } // Construct an underlying UART object. @@ -183,9 +171,15 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->uart_id = temp; self->uart_regs = MXC_UART_GET_UART(temp); } - assert((self->uart_id >= 0) && (self->uart_id < NUM_UARTS)); + // Check for size of ringbuffer, desire powers of 2 + // At least use 1 byte if no size is given + assert((receiver_buffer_size & (receiver_buffer_size - 1)) == 0); + if (receiver_buffer_size == 0) { + receiver_buffer_size += 1; + } + // Indicate RS485 not implemented if ((rs485_dir != NULL) || (rs485_invert)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("RS485")); @@ -246,12 +240,31 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->timeout = timeout; } - /* Setup UART interrupt */ + // Initialize ringbuffer + if (receiver_buffer == NULL) { + self->ringbuf = gc_alloc(receiver_buffer_size, false); + if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { + m_malloc_fail(receiver_buffer_size); + mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); + } + } else { + if (!(ringbuf_init(self->ringbuf, receiver_buffer, receiver_buffer_size))) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); + } + ; + } + + context = self; + + // Setup UART interrupt + NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)uart_isr); + NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + return; } @@ -260,7 +273,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { if (!common_hal_busio_uart_deinited(self)) { // First disable the ISR to avoid pre-emption - NVIC_DisableIRQ(UART0_IRQn); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); // Shutdown the UART Controller MXC_UART_Shutdown(self->uart_regs); @@ -280,6 +293,8 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { self->cts_pin = NULL; self->rts_pin = NULL; + ringbuf_deinit(self->ringbuf); + // Indicate to this module that the UART is not active uarts_active &= ~(1 << self->uart_id); } @@ -306,8 +321,6 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uart_status[self->uart_id] = UART_BUSY; bytes_remaining = len; - NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mxc_uart_req_t uart_rd_req; uart_rd_req.rxCnt = 0; uart_rd_req.txCnt = 0; @@ -341,13 +354,16 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { + mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); } - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - return len; + // Copy the data from the ringbuf (or return error) + MXC_SYS_Crit_Enter(); + err = ringbuf_get_n(context->ringbuf, data, len); + MXC_SYS_Crit_Exit(); + + return err; } // Write characters. len is in characters NOT bytes! @@ -391,11 +407,10 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { // Call the handler and abort if errors - uart_err = MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); + uart_err = MXC_UART_AsyncHandler(self->uart_regs); if (uart_err != E_NO_ERROR) { - MXC_UART_AbortAsync(MXC_UART_GET_UART(0)); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(0)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); + mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); + MXC_UART_AbortAsync(self->uart_regs); } } @@ -407,9 +422,8 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { + mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); } return len; @@ -444,11 +458,12 @@ void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeou } uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { - return MXC_UART_GetRXFIFOAvailable(self->uart_regs); + return ringbuf_num_filled(self->ringbuf); } void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { MXC_UART_ClearRXFIFO(self->uart_regs); + ringbuf_clear(self->ringbuf); } bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index a727116f7b882..296c738772e68 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -9,25 +9,25 @@ #include "common-hal/microcontroller/Pin.h" #include "py/obj.h" +#include "py/ringbuf.h" #include "max32_port.h" // Define a struct for what BUSIO.UART should contain typedef struct { mp_obj_base_t base; + int error; + float timeout; int uart_id; int uart_map; mxc_uart_regs_t *uart_regs; - + ringbuf_t *ringbuf; bool parity; uint8_t bits; uint8_t stop_bits; uint32_t baudrate; - int error; - float timeout; - const mcu_pin_obj_t *rx_pin; const mcu_pin_obj_t *tx_pin; const mcu_pin_obj_t *rts_pin; From b9dd6a043941063c50ad2d2313366ed3f53b21d1 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Mon, 5 May 2025 10:34:22 -0700 Subject: [PATCH 65/78] Update jlink script for ports/analog Signed-off-by: Brandon Hurst --- ports/analog/tools/flash_max32.jlink | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/analog/tools/flash_max32.jlink b/ports/analog/tools/flash_max32.jlink index 4c9cbacb96fee..8e3647cb0afc7 100644 --- a/ports/analog/tools/flash_max32.jlink +++ b/ports/analog/tools/flash_max32.jlink @@ -1,6 +1,7 @@ si 1 erase -loadbin build-APARD/firmware.bin 0x10000000 -r -g +loadbin build-apard32690/firmware.bin 0x10000000 +reset +halt +go exit From 0ffcc782969f0eb4cde6eaba45a1d8676e515325 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 6 May 2025 09:19:43 -0700 Subject: [PATCH 66/78] Refactor ports/analog/common-hal/busio i2c probe function. - Used direct hardware values to rely on common HW implementation - Accounted for TX Lockout conditions in Transmit FIFO causing errors Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/I2C.c | 54 +++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 9fe903428f5b9..ca114d337ede0 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -132,25 +132,49 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - int nack = 0; + int32_t flags = 0x0; + bool ret = false; + + MXC_I2C_ClearFlags(self->i2c_regs, 0xFF, 0xFF); + MXC_I2C_EnableInt(self->i2c_regs, 0xFF, 0xFF); + + // Pre-load target address into transmit FIFO + addr = (addr << 1); + self->i2c_regs->fifo = addr; + + // Set start bit & wait for it to clear + self->i2c_regs->mstctrl |= MXC_F_I2C_MSTCTRL_START; + + // wait for ACK/NACK + // if tx_lockout occurs, clear the error and re-load the target address + while (!(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_ACK) && + !(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_NACK_ERR)) { + if (self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_TX_LOCKOUT) { + self->i2c_regs->intfl0 |= MXC_F_I2C_INTFL0_TX_LOCKOUT; + self->i2c_regs->fifo = addr; + } + } + flags = self->i2c_regs->intfl0; + self->i2c_regs->intfl0 = MXC_F_I2C_INTFL0_ADDR_ACK | MXC_F_I2C_INTFL0_ADDR_NACK_ERR - mxc_i2c_req_t addr_req = { - .addr = addr, - .i2c = self->i2c_regs, - .tx_len = 0, - .tx_buf = NULL, - .rx_len = 0, - .rx_buf = NULL, - .callback = NULL - }; + // Set / Wait for stop + self->i2c_regs->mstctrl |= MXC_F_I2C_MSTCTRL_STOP; + while ((self->i2c_regs->mstctrl & MXC_F_I2C_MSTCTRL_STOP)) { + ; + } - // Probe the address - nack = MXC_I2C_MasterTransaction(&addr_req); - if (nack) { - return false; + // Wait for controller not busy, then clear flags + while (self->i2c_regs->status & MXC_F_I2C_STATUS_BUSY) { + ; + } + + if (flags & MXC_F_I2C_INTFL0_ADDR_ACK) { + ret = true; } else { - return true; + ret = false; } + MXC_I2C_ClearFlags(self->i2c_regs, 0xff, 0xff); + return ret; } // Lock I2C bus From 94eafa5d0ce45ada21c30b6f270c0895f04c1e2d Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 6 May 2025 09:21:14 -0700 Subject: [PATCH 67/78] Expand command in ports/analog/tools/flash_max32.jlink for clarity. Signed-off-by: Brandon Hurst --- ports/analog/tools/flash_max32.jlink | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/analog/tools/flash_max32.jlink b/ports/analog/tools/flash_max32.jlink index 8e3647cb0afc7..0453f4cb077fd 100644 --- a/ports/analog/tools/flash_max32.jlink +++ b/ports/analog/tools/flash_max32.jlink @@ -1,4 +1,4 @@ -si 1 +selectinterface swd erase loadbin build-apard32690/firmware.bin 0x10000000 reset From 4cb58b64f75aa9e6df9bbf74ce53d573106c2a9a Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 6 May 2025 14:08:22 -0700 Subject: [PATCH 68/78] Fix i2c scan bug with ports/analog/ BUSIO. - Probe function caused infinite loops / unreliable ACK values - Replaced with probe-function with low-level routines Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/I2C.c | 42 +++++++++++------------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index ca114d337ede0..c1b1d9efe1b17 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -34,15 +34,8 @@ #define I2C_PRIORITY 1 -typedef enum { - I2C_FREE = 0, - I2C_BUSY, - I2C_NEVER_RESET, -} i2c_status_t; - // Set each bit to indicate an active I2c static uint8_t i2c_active = 0; -static i2c_status_t i2c_status[NUM_I2C]; static volatile int i2c_err; // I2C struct for configuring GPIO pins @@ -68,7 +61,9 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, self->i2c_regs = MXC_I2C_GET_I2C(temp); } + // Check for valid I2C controller assert((self->i2c_id >= 0) && (self->i2c_id < NUM_I2C)); + assert(!(i2c_active & (1 << self->i2c_id))); // Init I2C as main / controller node (0x00 is ignored) if ((scl != NULL) && (sda != NULL)) { @@ -132,48 +127,43 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - int32_t flags = 0x0; - bool ret = false; + uint32_t int_fl0, int_fl1; + bool ret = 0; - MXC_I2C_ClearFlags(self->i2c_regs, 0xFF, 0xFF); - MXC_I2C_EnableInt(self->i2c_regs, 0xFF, 0xFF); + // Clear FIFOs & all interrupt flags + MXC_I2C_ClearRXFIFO(self->i2c_regs); + MXC_I2C_ClearTXFIFO(self->i2c_regs); + MXC_I2C_ClearFlags(self->i2c_regs, 0xFFFFFF, 0xFFFFFF); // Pre-load target address into transmit FIFO addr = (addr << 1); self->i2c_regs->fifo = addr; // Set start bit & wait for it to clear - self->i2c_regs->mstctrl |= MXC_F_I2C_MSTCTRL_START; + MXC_I2C_Start(self->i2c_regs); // wait for ACK/NACK - // if tx_lockout occurs, clear the error and re-load the target address while (!(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_ACK) && !(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_NACK_ERR)) { - if (self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_TX_LOCKOUT) { - self->i2c_regs->intfl0 |= MXC_F_I2C_INTFL0_TX_LOCKOUT; - self->i2c_regs->fifo = addr; - } } - flags = self->i2c_regs->intfl0; - self->i2c_regs->intfl0 = MXC_F_I2C_INTFL0_ADDR_ACK | MXC_F_I2C_INTFL0_ADDR_NACK_ERR - // Set / Wait for stop - self->i2c_regs->mstctrl |= MXC_F_I2C_MSTCTRL_STOP; - while ((self->i2c_regs->mstctrl & MXC_F_I2C_MSTCTRL_STOP)) { - ; - } + // Save interrupt flags for ACK/NACK checking + int_fl0 = self->i2c_regs->intfl0; + + // Set / Wait for stop + MXC_I2C_Stop(self->i2c_regs); // Wait for controller not busy, then clear flags while (self->i2c_regs->status & MXC_F_I2C_STATUS_BUSY) { ; } + MXC_I2C_ClearFlags(self->i2c_regs, 0xFFFFFF, 0xFFFFFF); - if (flags & MXC_F_I2C_INTFL0_ADDR_ACK) { + if (int_fl0 & MXC_F_I2C_INTFL0_ADDR_ACK) { ret = true; } else { ret = false; } - MXC_I2C_ClearFlags(self->i2c_regs, 0xff, 0xff); return ret; } From 814047d60fcd4fad5334cd204f6346fff5504a56 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 6 May 2025 14:41:26 -0700 Subject: [PATCH 69/78] Add translations for ports/analog/busio Signed-off-by: Brandon Hurst --- locale/circuitpython.pot | 114 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 98fc54741eb39..5b9e9afed76bf 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -28,6 +28,25 @@ msgid "" "Code stopped by auto-reload. Reloading soon.\n" msgstr "" +#: ports/analog/common-hal/busio/UART.c +#, c-format +msgid "" +"\n" +"ERR: Error starting transaction: %d\n" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "" +"\n" +"ERR: Requested bus is busy\n" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "" +"\n" +"ERR: Uart transaction timed out.\n" +msgstr "" + #: supervisor/shared/safe_mode.c msgid "" "\n" @@ -628,6 +647,10 @@ msgid "" "disable.\n" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Baudrate invalid. Must be a standard UART baudrate.\n" +msgstr "" + #: ports/espressif/common-hal/canio/CAN.c msgid "Baudrate not supported by peripheral" msgstr "" @@ -717,6 +740,10 @@ msgstr "" msgid "CIRCUITPY drive could not be found or created." msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "CPOL / CPHA must both be either 0 or 1\n" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -943,6 +970,38 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "ERR: Could not init ringbuffer\n" +msgstr "" + +#: ports/analog/peripherals/max32690/max32_uart.c +#, c-format +msgid "" +"ERR: Unable to find a uart matching pins...\n" +"TX: port %d mask %d\n" +"RX: port %d mask %d\n" +msgstr "" + +#: ports/analog/peripherals/max32690/max32_i2c.c +#, c-format +msgid "" +"ERR: Unable to find an I2C matching pins...\n" +"SCL: port %d mask %d\n" +"SDA: port %d mask %d\n" +msgstr "" + +#: ports/analog/peripherals/max32690/max32_spi.c +#, c-format +msgid "" +"ERR: Unable to find an SPI matching pins... \n" +"MOSI: port %d mask %d\n" +"MISO: port %d mask %d\n" +msgstr "" + +#: ports/analog/common-hal/busio/I2C.c +msgid "ERROR during I2C Transaction\n" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c msgid "ESP-IDF memory allocation failed" @@ -1036,6 +1095,19 @@ msgstr "" msgid "Failed to enable continuous" msgstr "" +#: ports/analog/common-hal/busio/I2C.c +#, c-format +msgid "Failed to init I2C. ERR: %d\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to init SPI.\n" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "Failed to initialize UART.\n" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" msgstr "" @@ -1049,6 +1121,23 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" +#: ports/analog/common-hal/busio/I2C.c +#, c-format +msgid "Failed to set I2C frequency. ERR: %d\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Frame Size\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Frequency\n" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1089,6 +1178,10 @@ msgstr "" msgid "Firmware is too big" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Flow Ctrl needs both CTS & RTS" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" @@ -1148,6 +1241,10 @@ msgstr "" msgid "I2C init error" msgstr "" +#: ports/analog/common-hal/busio/I2C.c +msgid "I2C needs SDA & SCL" +msgstr "" + #: ports/raspberrypi/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c msgid "I2C peripheral in use" @@ -1765,6 +1862,10 @@ msgstr "" msgid "Parameter error" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Parity must be ODD, EVEN, or NONE\n" +msgstr "" + #: ports/espressif/common-hal/audiobusio/__init__.c msgid "Peripheral in use" msgstr "" @@ -1902,6 +2003,7 @@ msgstr "" msgid "ROS topic failed to initialize" msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -1994,6 +2096,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2125,6 +2231,10 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" @@ -2168,6 +2278,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" From b19a86111cd736c5a65a5bb5354bfba9e4e277b7 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Sat, 5 Jul 2025 12:32:20 -0700 Subject: [PATCH 70/78] Fix error reporting on ports/analog BUSIO for PR 10413 - Use existing error messages from locale/circuitpython.pot for most error messages - Replace ConnectionError (networking specific) calls with others (usually RuntimeError) - Remove '\n' from mp error calls (since they add it already) - Remove some redundant validation code that repeats checks done by shared-bindings/common-hal/busio code. e.g. pin validation Signed-off-by: Brandon-Hurst --- ports/analog/common-hal/busio/I2C.c | 35 +++++---------- ports/analog/common-hal/busio/SPI.c | 5 ++- ports/analog/common-hal/busio/UART.c | 45 ++++++++++--------- ports/analog/peripherals/max32690/max32_i2c.c | 3 +- ports/analog/peripherals/max32690/max32_spi.c | 5 +-- .../analog/peripherals/max32690/max32_uart.c | 3 +- 6 files changed, 39 insertions(+), 57 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index c1b1d9efe1b17..b75d916c9faf0 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -52,6 +52,11 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // Check for NULL Pointers && valid I2C settings assert(self); + /* NOTE: The validate_obj_is_free_pin() calls in shared-bindings/busio/I2C.c + will ensure that scl and sda are both pins and cannot be null + ref: https://github.com/adafruit/circuitpython/pull/10413 + */ + // Assign I2C ID based on pins temp = pinsToI2c(sda, scl); if (temp == -1) { @@ -65,25 +70,6 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, assert((self->i2c_id >= 0) && (self->i2c_id < NUM_I2C)); assert(!(i2c_active & (1 << self->i2c_id))); - // Init I2C as main / controller node (0x00 is ignored) - if ((scl != NULL) && (sda != NULL)) { - MXC_GPIO_Config(&i2c_maps[self->i2c_id]); - err = MXC_I2C_Init(self->i2c_regs, 1, 0x00); - if (err) { - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to init I2C. ERR: %d\n"), err); - } - err = MXC_I2C_SetFrequency(self->i2c_regs, frequency); - if (err < 0) { - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to set I2C frequency. ERR: %d\n"), err); - } - } else if (scl != NULL) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); - } else if (sda != NULL) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); - } else { - // Should not get here, as shared-bindings API should not call this way - } - // Attach I2C pins self->sda = sda; self->scl = scl; @@ -94,8 +80,8 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, i2c_active |= (1 << self->i2c_id); // Set the timeout to a default value - if (((timeout < 0.0) || (timeout > 100.0))) { - self->timeout = 1.0; + if (timeout > 100) { + self->timeout = 1; } else { self->timeout = timeout; } @@ -212,7 +198,6 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, } // Read into buffer from the device selected by address -// todo test uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { @@ -229,14 +214,14 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, }; ret = MXC_I2C_MasterTransaction(&rd_req); if (ret) { - mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + // Return I/O error + return MP_EIO; } return 0; } // Write the bytes from out_data to the device selected by address, -// todo test uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { @@ -253,7 +238,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, }; ret = MXC_I2C_MasterTransaction(&wr_rd_req); if (ret) { - mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + return MP_EIO; } return 0; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 999eb8490b0eb..95ad1851a59ed 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -91,7 +91,8 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, 1, 0x01, 1000000, spi_pins); MXC_GPIO_SetVSSEL(MXC_GPIO_GET_GPIO(sck->port), MXC_GPIO_VSSEL_VDDIOH, (sck->mask | miso->mask | mosi->mask | MXC_GPIO_PIN_0)); if (err) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init SPI.\n")); + // NOTE: Reuse existing messages from locales/circuitpython.pot to save space + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_SPI); } } else { mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); @@ -170,7 +171,7 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, clk_mode = MXC_SPI_CLKMODE_3; break; default: - mp_raise_ValueError(MP_ERROR_TEXT("CPOL / CPHA must both be either 0 or 1\n")); + // should not be reachable; validated in shared-bindings/busio/SPI.c return false; } diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index f781da8705545..80feebfb8f4b6 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -82,37 +82,37 @@ static volatile int uart_err; static uint8_t uart_never_reset_mask = 0; static busio_uart_obj_t *context; -static int isValidBaudrate(uint32_t baudrate) { +static bool isValidBaudrate(uint32_t baudrate) { switch (baudrate) { case UART_9600: - return 1; + return true; break; case UART_14400: - return 1; + return true; break; case UART_19200: - return 1; + return true; break; case UART_38400: - return 1; + return true; break; case UART_57600: - return 1; + return true; break; case UART_115200: - return 1; + return true; break; case UART_230400: - return 1; + return true; break; case UART_460800: - return 1; + return true; break; case UART_921600: - return 1; + return true; break; default: - return 0; + return false; break; } } @@ -126,7 +126,8 @@ static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) { case BUSIO_UART_PARITY_ODD: return MXC_UART_PARITY_ODD_0; default: - mp_raise_ValueError(MP_ERROR_TEXT("Parity must be ODD, EVEN, or NONE\n")); + // not reachable due to validation in shared-bindings/busio/SPI.c + return MXC_UART_PARITY_DISABLE; } } @@ -188,7 +189,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, if ((rx != NULL) && (tx != NULL)) { err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); if (err != E_NO_ERROR) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to initialize UART.\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_UART); } // attach & configure pins @@ -211,7 +212,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, common_hal_mcu_pin_claim(self->cts_pin); common_hal_mcu_pin_claim(self->rts_pin); } else if (cts || rts) { - mp_raise_ValueError(MP_ERROR_TEXT("Flow Ctrl needs both CTS & RTS")); + mp_raise_ValueError(MP_ERROR_TEXT("Both RX and TX required for flow control")); } // Set stop bits & data size @@ -338,7 +339,7 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, *errcode = err; MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("\nERR: Error starting transaction: %d\n"), err); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("UART read error")); } // Wait for transaction completion or timeout @@ -350,11 +351,11 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, if (uart_status[self->uart_id] != UART_FREE) { MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + mp_raise_RuntimeError(MP_ERROR_TEXT("UART transaction timeout")); } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { - mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); + // todo: indicate error? MXC_UART_AbortAsync(self->uart_regs); } @@ -399,7 +400,7 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, *errcode = err; MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Requested bus is busy\n")); + mp_raise_ValueError(MP_ERROR_TEXT("All UART peripherals are in use")); } // Wait for transaction completion or timeout @@ -409,7 +410,7 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, // Call the handler and abort if errors uart_err = MXC_UART_AsyncHandler(self->uart_regs); if (uart_err != E_NO_ERROR) { - mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); + // todo: indicate error? MXC_UART_AbortAsync(self->uart_regs); } } @@ -418,11 +419,11 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, if (uart_status[self->uart_id] != UART_FREE) { MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Uart transaction timed out.")); } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { - mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); + // todo: indicate error? MXC_UART_AbortAsync(self->uart_regs); } @@ -438,7 +439,7 @@ void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrat if (isValidBaudrate(baudrate)) { self->baudrate = baudrate; } else { - mp_raise_ValueError(MP_ERROR_TEXT("Baudrate invalid. Must be a standard UART baudrate.\n")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_baudrate); } } diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c index daf665bbee741..4b9ec8b4db264 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.c +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -70,7 +70,6 @@ int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { } #endif - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an I2C matching pins...\nSCL: port %d mask %d\nSDA: port %d mask %d\n"), - sda->port, sda->mask, scl->port, scl->mask); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); return -1; } diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c index f2594787598b2..c78fd64dbd705 100644 --- a/ports/analog/peripherals/max32690/max32_spi.c +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -39,9 +39,6 @@ int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, return i; } } - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an SPI matching pins... \ - \nMOSI: port %d mask %d\nMISO: port %d mask %d\n"), - mosi->port, mosi->mask, miso->port, miso->mask, - sck->port, sck->mask); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); return -1; } diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c index 5f7a8568fb426..7d37708797415 100644 --- a/ports/analog/peripherals/max32690/max32_uart.c +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -31,7 +31,6 @@ int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { return i; } } - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find a uart matching pins...\nTX: port %d mask %d\nRX: port %d mask %d\n"), - tx->port, tx->mask, rx->port, rx->mask); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); return -1; } From 85410e22084c7b660301ba0812974d3bc3dc37ff Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Sat, 5 Jul 2025 12:38:42 -0700 Subject: [PATCH 71/78] Minor changes in ports/analog/ busio UART. - Use m_malloc_without_collect storage API change from CircuitPython - Remove err number for asynchronous read error; just report it Signed-off-by: Brandon-Hurst --- ports/analog/common-hal/busio/UART.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 80feebfb8f4b6..71da89652af39 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -197,12 +197,8 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->rx_pin = rx; common_hal_mcu_pin_claim(self->tx_pin); common_hal_mcu_pin_claim(self->rx_pin); - } else if (tx != NULL) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); - } else if (rx != NULL) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); } else { - // Should not get here, as shared-bindings API should not call this way + mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); } if ((cts) && (rts)) { @@ -243,7 +239,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, // Initialize ringbuffer if (receiver_buffer == NULL) { - self->ringbuf = gc_alloc(receiver_buffer_size, false); + self->ringbuf = m_malloc_without_collect(receiver_buffer_size, false); if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { m_malloc_fail(receiver_buffer_size); mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); From f395fadeb59d4aa45632ac936fed6dd1507c734a Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Sat, 5 Jul 2025 12:44:05 -0700 Subject: [PATCH 72/78] Fix UART malloc for ports/analog BUSIO - Remove excess argument from UART ringbuf malloc call - Remove unused err and intfl0 in I2C driver to remove warnings Signed-off-by: Brandon-Hurst --- ports/analog/common-hal/busio/I2C.c | 4 ++-- ports/analog/common-hal/busio/UART.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index b75d916c9faf0..19c71034eea4c 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -47,7 +47,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - int temp, err = 0; + int temp = 0; // Check for NULL Pointers && valid I2C settings assert(self); @@ -113,7 +113,7 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - uint32_t int_fl0, int_fl1; + uint32_t int_fl0; bool ret = 0; // Clear FIFOs & all interrupt flags diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 71da89652af39..633ecb1684005 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -239,7 +239,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, // Initialize ringbuffer if (receiver_buffer == NULL) { - self->ringbuf = m_malloc_without_collect(receiver_buffer_size, false); + self->ringbuf = m_malloc_without_collect(receiver_buffer_size); if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { m_malloc_fail(receiver_buffer_size); mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); From e5437cd688120e1c7bdfc90a42afd16b9addf84b Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Sat, 5 Jul 2025 13:03:03 -0700 Subject: [PATCH 73/78] Commit locale changes from ports/analog BUSIO updates Signed-off-by: Brandon-Hurst --- locale/circuitpython.pot | 106 +++++++++------------------------------ 1 file changed, 24 insertions(+), 82 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 5b9e9afed76bf..a0477d71abc19 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -28,25 +28,6 @@ msgid "" "Code stopped by auto-reload. Reloading soon.\n" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#, c-format -msgid "" -"\n" -"ERR: Error starting transaction: %d\n" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "" -"\n" -"ERR: Requested bus is busy\n" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "" -"\n" -"ERR: Uart transaction timed out.\n" -msgstr "" - #: supervisor/shared/safe_mode.c msgid "" "\n" @@ -149,6 +130,7 @@ msgstr "" msgid "%q indices must be integers, not %s" msgstr "" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-module/bitbangio/SPI.c msgid "%q init failed" msgstr "" @@ -177,6 +159,10 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" +#: py/runtime.c +msgid "%q moved from %q to %q" +msgstr "" + #: py/argcheck.c msgid "%q must be %d" msgstr "" @@ -517,7 +503,8 @@ msgstr "" msgid "All SPI peripherals are in use" msgstr "" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c msgid "All UART peripherals are in use" msgstr "" @@ -647,10 +634,6 @@ msgid "" "disable.\n" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Baudrate invalid. Must be a standard UART baudrate.\n" -msgstr "" - #: ports/espressif/common-hal/canio/CAN.c msgid "Baudrate not supported by peripheral" msgstr "" @@ -672,6 +655,7 @@ msgstr "" msgid "Boot device must be first (interface #0)." msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "" @@ -740,10 +724,6 @@ msgstr "" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "CPOL / CPHA must both be either 0 or 1\n" -msgstr "" - #: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -974,30 +954,6 @@ msgstr "" msgid "ERR: Could not init ringbuffer\n" msgstr "" -#: ports/analog/peripherals/max32690/max32_uart.c -#, c-format -msgid "" -"ERR: Unable to find a uart matching pins...\n" -"TX: port %d mask %d\n" -"RX: port %d mask %d\n" -msgstr "" - -#: ports/analog/peripherals/max32690/max32_i2c.c -#, c-format -msgid "" -"ERR: Unable to find an I2C matching pins...\n" -"SCL: port %d mask %d\n" -"SDA: port %d mask %d\n" -msgstr "" - -#: ports/analog/peripherals/max32690/max32_spi.c -#, c-format -msgid "" -"ERR: Unable to find an SPI matching pins... \n" -"MOSI: port %d mask %d\n" -"MISO: port %d mask %d\n" -msgstr "" - #: ports/analog/common-hal/busio/I2C.c msgid "ERROR during I2C Transaction\n" msgstr "" @@ -1095,19 +1051,6 @@ msgstr "" msgid "Failed to enable continuous" msgstr "" -#: ports/analog/common-hal/busio/I2C.c -#, c-format -msgid "Failed to init I2C. ERR: %d\n" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to init SPI.\n" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "Failed to initialize UART.\n" -msgstr "" - #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" msgstr "" @@ -1121,11 +1064,6 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" -#: ports/analog/common-hal/busio/I2C.c -#, c-format -msgid "Failed to set I2C frequency. ERR: %d\n" -msgstr "" - #: ports/analog/common-hal/busio/SPI.c msgid "Failed to set SPI Clock Mode\n" msgstr "" @@ -1178,10 +1116,6 @@ msgstr "" msgid "Firmware is too big" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Flow Ctrl needs both CTS & RTS" -msgstr "" - #: shared-bindings/bitmaptools/__init__.c msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" @@ -1241,10 +1175,6 @@ msgstr "" msgid "I2C init error" msgstr "" -#: ports/analog/common-hal/busio/I2C.c -msgid "I2C needs SDA & SCL" -msgstr "" - #: ports/raspberrypi/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c msgid "I2C peripheral in use" @@ -1348,6 +1278,10 @@ msgstr "" msgid "Interrupted by output function" msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c @@ -1862,10 +1796,6 @@ msgstr "" msgid "Parameter error" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Parity must be ODD, EVEN, or NONE\n" -msgstr "" - #: ports/espressif/common-hal/audiobusio/__init__.c msgid "Peripheral in use" msgstr "" @@ -2290,6 +2220,14 @@ msgstr "" msgid "UART re-init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + #: ports/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -2326,6 +2264,10 @@ msgstr "" msgid "UUID value is not str, int or byte buffer" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Uart transaction timed out." +msgstr "" + #: ports/raspberrypi/common-hal/memorymap/AddressRange.c msgid "Unable to access unaligned IO register" msgstr "" From ed92610e506d4f63bcf28152fa10c0d8eedbc010 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Thu, 10 Jul 2025 21:57:47 -0700 Subject: [PATCH 74/78] Reuse more existing error messages in ports/analog BUSIO - Reuse more messages in locales/circuitpython.pot in BUSIO - Remove UART write timeout - Refine some error handling for SPI initialization Signed-off-by: Brandon-Hurst --- locale/circuitpython.pot | 26 ++++----------------- ports/analog/common-hal/busio/I2C.c | 2 +- ports/analog/common-hal/busio/SPI.c | 15 +++++------- ports/analog/common-hal/busio/UART.c | 34 +++++++--------------------- 4 files changed, 19 insertions(+), 58 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index a0477d71abc19..1e167c30353dd 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -242,6 +242,7 @@ msgstr "" msgid "%q out of bounds" msgstr "" +#: ports/analog/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/nordic/common-hal/pulseio/PulseIn.c @@ -950,14 +951,6 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "ERR: Could not init ringbuffer\n" -msgstr "" - -#: ports/analog/common-hal/busio/I2C.c -msgid "ERROR during I2C Transaction\n" -msgstr "" - #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c msgid "ESP-IDF memory allocation failed" @@ -1006,7 +999,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1065,15 +1058,7 @@ msgid "Failed to release mutex, err 0x%04x" msgstr "" #: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode\n" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Frame Size\n" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Frequency\n" +msgid "Failed to set SPI Clock Mode" msgstr "" #: ports/zephyr-cp/common-hal/wifi/Radio.c @@ -1374,6 +1359,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" +#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" @@ -2264,10 +2250,6 @@ msgstr "" msgid "UUID value is not str, int or byte buffer" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Uart transaction timed out." -msgstr "" - #: ports/raspberrypi/common-hal/memorymap/AddressRange.c msgid "Unable to access unaligned IO register" msgstr "" diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 19c71034eea4c..2c8f2e328eb1f 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -191,7 +191,7 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, }; ret = MXC_I2C_MasterTransaction(&wr_req); if (ret) { - mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + return MP_EIO; } return 0; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 95ad1851a59ed..516ae26a8cf69 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -177,17 +177,19 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, ret = MXC_SPI_SetFrequency(self->spi_regs, baudrate); if (ret) { - mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Frequency\n")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_baudrate); return false; } ret = MXC_SPI_SetDataSize(self->spi_regs, bits); - if (ret) { - mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Frame Size\n")); + if (ret == E_BAD_PARAM) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_bits); return false; + } else if (ret == E_BAD_STATE) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid state")); } ret = MXC_SPI_SetMode(self->spi_regs, clk_mode); if (ret) { - mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Clock Mode\n")); + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Clock Mode")); return false; } return true; @@ -246,11 +248,6 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t write_value) { int ret = 0; - // uint8_t tx_buffer[len] = {0x0}; - - // for (int i = 0; i < len; i++) { - // tx_buffer[i] = write_value; - // } mxc_spi_req_t rd_req = { .spi = self->spi_regs, diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 633ecb1684005..be7851f52a21c 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -24,11 +24,6 @@ * THE SOFTWARE. */ -/** TODO: - * - Fix readline issue - * -*/ - #if CIRCUITPY_BUSIO_UART #include "mpconfigport.h" @@ -242,19 +237,19 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->ringbuf = m_malloc_without_collect(receiver_buffer_size); if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { m_malloc_fail(receiver_buffer_size); - mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to allocate %q buffer"), + MP_QSTR_UART); } } else { if (!(ringbuf_init(self->ringbuf, receiver_buffer, receiver_buffer_size))) { - mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to allocate %q buffer"), + MP_QSTR_UART); } - ; } context = self; // Setup UART interrupt - NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); @@ -351,7 +346,7 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { - // todo: indicate error? + mp_raise_RuntimeError(MP_ERROR_TEXT("UART read error")); MXC_UART_AbortAsync(self->uart_regs); } @@ -368,7 +363,6 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { int err; - uint32_t start_time = 0; static size_t bytes_remaining; // Setup globals & status tracking @@ -390,7 +384,6 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, uart_wr_req.callback = (void *)uartCallback; // Start the transaction - start_time = supervisor_ticks_ms64(); err = MXC_UART_TransactionAsync(&uart_wr_req); if (err != E_NO_ERROR) { *errcode = err; @@ -399,27 +392,16 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("All UART peripherals are in use")); } - // Wait for transaction completion or timeout - while ((uart_status[self->uart_id] != UART_FREE) && - (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { - + // Wait for transaction completion + while (uart_status[self->uart_id] != UART_FREE) { // Call the handler and abort if errors uart_err = MXC_UART_AsyncHandler(self->uart_regs); if (uart_err != E_NO_ERROR) { - // todo: indicate error? MXC_UART_AbortAsync(self->uart_regs); } } - - // If the timeout gets hit, abort and error out - if (uart_status[self->uart_id] != UART_FREE) { - MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError(MP_ERROR_TEXT("Uart transaction timed out.")); - } // Check for errors from the callback - else if (uart_err != E_NO_ERROR) { - // todo: indicate error? + if (uart_err != E_NO_ERROR) { MXC_UART_AbortAsync(self->uart_regs); } From 183a517ba1e4ab818904254e2c4bd932caf4f52a Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Mon, 22 Sep 2025 20:30:39 -0700 Subject: [PATCH 75/78] Fix I2C bug in ports/analog/busio - Add clear flags + Shutdown/Init to I2C constructor - Explicitly set frequency - Add failsafe in probe function if MST mode disabled (can happen in some error conditions) - Fix Makefile bug with missing "\" for source files Signed-off-by: Brandon-Hurst --- ports/analog/Makefile | 2 +- ports/analog/common-hal/busio/I2C.c | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ports/analog/Makefile b/ports/analog/Makefile index 4a758eff9c46d..0ae276985f7f4 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -125,7 +125,7 @@ SRC_MAX32 += \ $(PERIPH_SRC)/UART/uart_$(DIE_TYPE).c \ $(PERIPH_SRC)/UART/uart_revb.c \ $(PERIPH_SRC)/TRNG/trng_revb.c \ - $(PERIPH_SRC)/TRNG/trng_$(DIE_TYPE).c + $(PERIPH_SRC)/TRNG/trng_$(DIE_TYPE).c \ $(PERIPH_SRC)/I2C/i2c_$(DIE_TYPE).c \ $(PERIPH_SRC)/I2C/i2c_reva.c \ $(PERIPH_SRC)/SPI/spi_$(DIE_TYPE).c \ diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 2c8f2e328eb1f..b3aeac76ce2d3 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -76,6 +76,16 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, common_hal_mcu_pin_claim(self->sda); common_hal_mcu_pin_claim(self->scl); + // Clear all flags + MXC_I2C_ClearFlags(self->i2c_regs, 0xFFFFFF, 0xFFFFFF); + + // Init as master, no slave address + MXC_I2C_Shutdown(self->i2c_regs); + MXC_I2C_Init(self->i2c_regs, 1, 0); + + // Set frequency arg (CircuitPython shared-bindings validate) + MXC_I2C_SetFrequency(self->i2c_regs, frequency); + // Indicate to this module that the I2C is active i2c_active |= (1 << self->i2c_id); @@ -116,6 +126,11 @@ bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { uint32_t int_fl0; bool ret = 0; + // If not in Master mode, error out (can happen in some error conditions) + if (!(self->i2c_regs->ctrl & MXC_F_I2C_CTRL_MST_MODE)) { + return false; + } + // Clear FIFOs & all interrupt flags MXC_I2C_ClearRXFIFO(self->i2c_regs); MXC_I2C_ClearTXFIFO(self->i2c_regs); @@ -175,7 +190,6 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address -// todo test uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { @@ -221,7 +235,7 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, return 0; } -// Write the bytes from out_data to the device selected by address, +// Write the bytes from out_data to the device selected by address uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { From 29914f88b80954cfb59a6bbb6152af78e8e1a098 Mon Sep 17 00:00:00 2001 From: gychang Date: Tue, 23 Sep 2025 15:03:40 -0700 Subject: [PATCH 76/78] Remove neopixel_write workaround Turns out it was a workaround for a bad LED on one particular board. --- .../boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk | 4 ---- ports/espressif/common-hal/neopixel_write/__init__.c | 10 ---------- 2 files changed, 14 deletions(-) diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk index a233eb526fdbd..4b23a76ba6a15 100644 --- a/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk @@ -8,7 +8,3 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 - -ESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD = 1 - -CFLAGS += -DESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD=$(ESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD) diff --git a/ports/espressif/common-hal/neopixel_write/__init__.c b/ports/espressif/common-hal/neopixel_write/__init__.c index 945b309372ac7..d0d46a3179787 100644 --- a/ports/espressif/common-hal/neopixel_write/__init__.c +++ b/ports/espressif/common-hal/neopixel_write/__init__.c @@ -126,11 +126,6 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, // Update the next start to +2 ticks. It ensures that we've gone 300+ us. next_start_raw_ticks = port_get_raw_ticks(NULL) + 2; - #if defined(ESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD) - // Hold the pin, deleting the channel seems to glitch pixels into turning off. - gpio_hold_en(digitalinout->pin->number); - #endif - // Free channel again rmt_del_encoder(encoder); rmt_disable(channel); @@ -138,9 +133,4 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, CHECK_ESP_RESULT(result); // Swap pin back to GPIO mode gpio_set_direction(digitalinout->pin->number, GPIO_MODE_OUTPUT); - - #if defined(ESPRESSIF_ESP32C3_LYRA_STATUS_LED_HOLD) - // Release hold - gpio_hold_dis(digitalinout->pin->number); - #endif } From bb27b4010c27e47912741be88481e77d6d7c580b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 24 Sep 2025 12:35:08 -0400 Subject: [PATCH 77/78] Use more explicit names for i2c_id and spi_id --- ports/analog/common-hal/busio/I2C.c | 11 ++++------- ports/analog/common-hal/busio/SPI.c | 10 +++++----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index b3aeac76ce2d3..336c04fe039f9 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -46,9 +46,6 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - - int temp = 0; - // Check for NULL Pointers && valid I2C settings assert(self); @@ -58,12 +55,12 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, */ // Assign I2C ID based on pins - temp = pinsToI2c(sda, scl); - if (temp == -1) { + int i2c_id = pinsToI2c(sda, scl); + if (i2c_id == -1) { return; } else { - self->i2c_id = temp; - self->i2c_regs = MXC_I2C_GET_I2C(temp); + self->i2c_id = i2c_id; + self->i2c_regs = MXC_I2C_GET_I2C(i2c_id); } // Check for valid I2C controller diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 516ae26a8cf69..b4a519c37a72d 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -56,18 +56,18 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { - int temp, err = 0; + int err = 0; // Check for NULL Pointer assert(self); // Assign SPI ID based on pins - temp = pinsToSpi(mosi, miso, sck); - if (temp == -1) { + int spi_id = pinsToSpi(mosi, miso, sck); + if (spi_id == -1) { return; } else { - self->spi_id = temp; - self->spi_regs = MXC_SPI_GET_SPI(temp); + self->spi_id = spi_id; + self->spi_regs = MXC_SPI_GET_SPI(spi_id); } // Other pins default to true From caf65d3ac9ef9db9619eb4c1ed781339686df778 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 24 Sep 2025 20:11:32 +0200 Subject: [PATCH 78/78] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 42 ++++++++++++++++++++++++++++++++++++++++-- locale/el.po | 45 ++++++++++++++++++++++++++++++++++++++++----- locale/hi.po | 42 ++++++++++++++++++++++++++++++++++++++++-- locale/ko.po | 47 +++++++++++++++++++++++++++++++++++++++++------ locale/ru.po | 45 ++++++++++++++++++++++++++++++++++++++++----- locale/tr.po | 42 ++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 241 insertions(+), 22 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index eab928c2aaaf6..fa1cb2d40b738 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -141,6 +141,7 @@ msgstr "Index %q je mimo rozsah" msgid "%q indices must be integers, not %s" msgstr "Indexy %q musí být celá čísla, nikoli %s" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-module/bitbangio/SPI.c msgid "%q init failed" msgstr "Inicializace %q selhala" @@ -169,6 +170,10 @@ msgstr "Délka %q musí být <= %d" msgid "%q length must be >= %d" msgstr "Délka %q musí být >= %d" +#: py/runtime.c +msgid "%q moved from %q to %q" +msgstr "" + #: py/argcheck.c msgid "%q must be %d" msgstr "%q musí být %d" @@ -248,6 +253,7 @@ msgstr "%q musí být mocnina 2" msgid "%q out of bounds" msgstr "%q je mimo hranice" +#: ports/analog/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/nordic/common-hal/pulseio/PulseIn.c @@ -509,7 +515,8 @@ msgstr "Všechny RX FIFO jsou používány" msgid "All SPI peripherals are in use" msgstr "Všechny SPI periferie jsou používány" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c msgid "All UART peripherals are in use" msgstr "Všechny UART periferie jsou používány" @@ -662,6 +669,7 @@ msgstr "Velikost bitmapy a počet bitů na hodnotu se musí shodovat" msgid "Boot device must be first (interface #0)." msgstr "Bootovací zařízení musí být první (rozhraní #0)." +#: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "RX a TX jsou vyžadovány pro kontrolu toku" @@ -1009,7 +1017,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "Chyba alokace %q bufferu" @@ -1067,6 +1075,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "Nepodařilo se uvolnit mutex, err 0x%04x" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1271,6 +1283,10 @@ msgstr "Chyba přerušení." msgid "Interrupted by output function" msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c @@ -1363,6 +1379,7 @@ msgstr "Chybná velikost" msgid "Invalid socket for TLS" msgstr "Chybný soket pro TLS" +#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" @@ -1925,6 +1942,7 @@ msgstr "" msgid "ROS topic failed to initialize" msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2017,6 +2035,10 @@ msgstr "Konfigurace SPI selhala" msgid "SPI init error" msgstr "Chyba inicializace SPI" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "SPI periferie je používána" @@ -2148,6 +2170,10 @@ msgstr "Čas je v minulosti." msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "Časový limit je příliš dlouhý: maximální limit je %d vteřin" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "V samplu je příliš mnoho kanálů" @@ -2192,6 +2218,10 @@ msgstr "De-inicializace UART" msgid "UART init" msgstr "Inicializace UART" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "UART periférie je používána" @@ -2200,6 +2230,14 @@ msgstr "UART periférie je používána" msgid "UART re-init" msgstr "Opětovná inicializace UART" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + #: ports/stm/common-hal/busio/UART.c msgid "UART write" msgstr "Zápis na UART" diff --git a/locale/el.po b/locale/el.po index 871ce82f6725c..91624ceb08672 100644 --- a/locale/el.po +++ b/locale/el.po @@ -145,6 +145,7 @@ msgstr "%q δείκτης εκτός εμβέλειας" msgid "%q indices must be integers, not %s" msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι %s" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-module/bitbangio/SPI.c msgid "%q init failed" msgstr "%q εκκίνηση απέτυχε" @@ -173,6 +174,10 @@ msgstr "%q μήκος πρέπει να είναι <= %d" msgid "%q length must be >= %d" msgstr "%q μήκος πρέπει να είναι >= %d" +#: py/runtime.c +msgid "%q moved from %q to %q" +msgstr "%q μετακινήθηκε από το %q στο %q" + #: py/argcheck.c msgid "%q must be %d" msgstr "%q πρέπει να είναι %d" @@ -252,6 +257,7 @@ msgstr "%q πρέπει να είναι δύναμη του 2" msgid "%q out of bounds" msgstr "%q εκτός ορίων" +#: ports/analog/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/nordic/common-hal/pulseio/PulseIn.c @@ -513,7 +519,8 @@ msgstr "Όλα τα RX FIFOs είναι σε χρήση" msgid "All SPI peripherals are in use" msgstr "Όλα τα SPI περιφεριακά είναι σε χρήση" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c msgid "All UART peripherals are in use" msgstr "Όλα τα UART περιφεριακά ειναι σε χρήση" @@ -666,6 +673,7 @@ msgstr "Το μέγεθος του bitmap και τα bits ανα τιμή πρ msgid "Boot device must be first (interface #0)." msgstr "Η συσκευή εκκίνησης πρέπει να επιλεχθεί πρώτα (διεπαφή #0)." +#: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "Και RX και TX απαιτούνται για έλεγχο flow" @@ -1017,7 +1025,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1075,6 +1083,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1277,6 +1289,10 @@ msgstr "" msgid "Interrupted by output function" msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c @@ -1369,6 +1385,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" +#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" @@ -1930,6 +1947,7 @@ msgstr "" msgid "ROS topic failed to initialize" msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2022,6 +2040,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2153,6 +2175,10 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" @@ -2196,6 +2222,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2204,6 +2234,14 @@ msgstr "" msgid "UART re-init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + #: ports/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -4545,9 +4583,6 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" -#~ msgid "%q moved from %q to %q" -#~ msgstr "%q μετακινήθηκε από το %q στο %q" - #, c-format #~ msgid "%%c requires int or char" #~ msgstr "%%c απαιτεί ακέραιο ή χαρακτήρα" diff --git a/locale/hi.po b/locale/hi.po index f8408f6c119a5..1ab48338ebaba 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -132,6 +132,7 @@ msgstr "" msgid "%q indices must be integers, not %s" msgstr "" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-module/bitbangio/SPI.c msgid "%q init failed" msgstr "" @@ -160,6 +161,10 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" +#: py/runtime.c +msgid "%q moved from %q to %q" +msgstr "" + #: py/argcheck.c msgid "%q must be %d" msgstr "" @@ -239,6 +244,7 @@ msgstr "" msgid "%q out of bounds" msgstr "" +#: ports/analog/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/nordic/common-hal/pulseio/PulseIn.c @@ -500,7 +506,8 @@ msgstr "" msgid "All SPI peripherals are in use" msgstr "" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c msgid "All UART peripherals are in use" msgstr "" @@ -651,6 +658,7 @@ msgstr "" msgid "Boot device must be first (interface #0)." msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "" @@ -993,7 +1001,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1051,6 +1059,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1253,6 +1265,10 @@ msgstr "" msgid "Interrupted by output function" msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c @@ -1345,6 +1361,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" +#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" @@ -1904,6 +1921,7 @@ msgstr "" msgid "ROS topic failed to initialize" msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -1996,6 +2014,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2127,6 +2149,10 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" @@ -2170,6 +2196,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2178,6 +2208,14 @@ msgstr "" msgid "UART re-init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + #: ports/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 4a74ec9003488..35bfed4de08e9 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -143,6 +143,7 @@ msgstr "%q 인덱스 범위를 벗어났습니다" msgid "%q indices must be integers, not %s" msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-module/bitbangio/SPI.c msgid "%q init failed" msgstr "%q 초기화 실패" @@ -171,6 +172,11 @@ msgstr "%q 길이는 <= %d>여야 합니다" msgid "%q length must be >= %d" msgstr "%q 길이는 >= %d이어야 합니다" +#: py/runtime.c +#, fuzzy +msgid "%q moved from %q to %q" +msgstr "%q가 %q에서 %q로 이동했습니다" + #: py/argcheck.c msgid "%q must be %d" msgstr "%q는 %d이어야 합니다" @@ -256,6 +262,7 @@ msgstr "%q는 2의 거듭제곱이어야 합니다" msgid "%q out of bounds" msgstr "%q가 경계를 벗어남" +#: ports/analog/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/nordic/common-hal/pulseio/PulseIn.c @@ -531,7 +538,8 @@ msgstr "모든 RX FIFOs가 사용 중입니다" msgid "All SPI peripherals are in use" msgstr "사용중인 모든 SPI주변 기기" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c msgid "All UART peripherals are in use" msgstr "사용중인 모든 UART주변 기기" @@ -692,6 +700,7 @@ msgstr "비트맵 크기와 값 당 비트가 일치해야 합니다" msgid "Boot device must be first (interface #0)." msgstr "부팅 장치는 첫 번째(인터페이스 #0)여야 합니다." +#: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "플로우 제어에 RX와 TX가 모두 필요합니다" @@ -1041,7 +1050,7 @@ msgstr "" "서비스 TXT 레코드를 추가하는 것에 실패했습니다; txt_records에서 비문자열 또" "는 바이트가 발견되었습니다" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "%q 버퍼 할당에 실패했습니다" @@ -1099,6 +1108,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "뮤텍스 해제에 실패했습니다, 오류 0x%04x" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1304,6 +1317,10 @@ msgstr "인터럽트 오류." msgid "Interrupted by output function" msgstr "출력 함수로 인해 종료되었다" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c @@ -1396,6 +1413,7 @@ msgstr "잘못된 크기" msgid "Invalid socket for TLS" msgstr "TLS에 대한 잘못된 소켓" +#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" @@ -1978,6 +1996,7 @@ msgstr "" msgid "ROS topic failed to initialize" msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2070,6 +2089,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2201,6 +2224,10 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" @@ -2244,6 +2271,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2252,6 +2283,14 @@ msgstr "" msgid "UART re-init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + #: ports/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -4594,10 +4633,6 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" -#, fuzzy -#~ msgid "%q moved from %q to %q" -#~ msgstr "%q가 %q에서 %q로 이동했습니다" - #, c-format #~ msgid "%%c requires int or char" #~ msgstr "%%c 전수(int)또는 캐릭터(char)필요합니다" diff --git a/locale/ru.po b/locale/ru.po index 24b880972cb42..af7c8bca194d2 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -145,6 +145,7 @@ msgstr "Индекс %q вне диапазона" msgid "%q indices must be integers, not %s" msgstr "Индексы %q должны быть целыми числами, а не %s" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-module/bitbangio/SPI.c msgid "%q init failed" msgstr "Инициализация %q не удалась" @@ -173,6 +174,10 @@ msgstr "Длинна %q должна быть <= %d" msgid "%q length must be >= %d" msgstr "Длинна %q должна быть >= %d" +#: py/runtime.c +msgid "%q moved from %q to %q" +msgstr "%q переместился из %q в %q" + #: py/argcheck.c msgid "%q must be %d" msgstr "%q должно быть %d" @@ -252,6 +257,7 @@ msgstr "%q должен быть во 2-й степени" msgid "%q out of bounds" msgstr "%q за пределом" +#: ports/analog/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/nordic/common-hal/pulseio/PulseIn.c @@ -513,7 +519,8 @@ msgstr "Все RX FIFO уже используются" msgid "All SPI peripherals are in use" msgstr "Все периферийные устройства SPI уже используются" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c msgid "All UART peripherals are in use" msgstr "Все периферийные устройства UART уже используются" @@ -667,6 +674,7 @@ msgstr "" msgid "Boot device must be first (interface #0)." msgstr "Загрузочное устройство должно быть первым (интерфейс #0)." +#: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "Для управления потоком требуется как RX так и TX" @@ -1022,7 +1030,7 @@ msgstr "" "Не удалось добавить служебную TXT-запись; в txt_records обнаружена нестрока " "или байт" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "Не удалось выделить буфер %q" @@ -1080,6 +1088,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "Не удалось освободить mutex, ошибка 0x%04x" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1292,6 +1304,10 @@ msgstr "Прерванная ошибка." msgid "Interrupted by output function" msgstr "Прерывается функцией выхода" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c @@ -1384,6 +1400,7 @@ msgstr "Неверный размер" msgid "Invalid socket for TLS" msgstr "Неверный сокет для TLS" +#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" @@ -1955,6 +1972,7 @@ msgstr "" msgid "ROS topic failed to initialize" msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2047,6 +2065,10 @@ msgstr "Сбой конфигурации SPI" msgid "SPI init error" msgstr "Ошибка инициализации SPI" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "Используемое периферийное устройство SPI" @@ -2183,6 +2205,10 @@ msgstr "Время в прошлом." msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "Таймаут слишком длинный: максимальная длина таймаута %d секунд" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "Слишком много каналов в выборке" @@ -2226,6 +2252,10 @@ msgstr "Деинициализация UART" msgid "UART init" msgstr "Инициализация UART" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "Используемое периферийное устройство UART" @@ -2234,6 +2264,14 @@ msgstr "Используемое периферийное устройство U msgid "UART re-init" msgstr "Повторная инициализация UART" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + #: ports/stm/common-hal/busio/UART.c msgid "UART write" msgstr "Запись UART" @@ -4612,9 +4650,6 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" -#~ msgid "%q moved from %q to %q" -#~ msgstr "%q переместился из %q в %q" - #~ msgid "start/end indices" #~ msgstr "Начальные/конечные индексы" diff --git a/locale/tr.po b/locale/tr.po index f51ad3e8c12ee..758137eae21f8 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -143,6 +143,7 @@ msgstr "%q indeksi aralık dışında" msgid "%q indices must be integers, not %s" msgstr "%q indeksleri integer olmalı, %s değil" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-module/bitbangio/SPI.c msgid "%q init failed" msgstr "%q init başarısız oldu" @@ -171,6 +172,10 @@ msgstr "%q boyutu <= %d olmalıdır" msgid "%q length must be >= %d" msgstr "%q boyutu >= %d olmalıdır" +#: py/runtime.c +msgid "%q moved from %q to %q" +msgstr "" + #: py/argcheck.c msgid "%q must be %d" msgstr "%q, %d olmalıdır" @@ -250,6 +255,7 @@ msgstr "%q, 2'nin kuvveti olmalıdır" msgid "%q out of bounds" msgstr "%q sınırların dışında" +#: ports/analog/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/nordic/common-hal/pulseio/PulseIn.c @@ -511,7 +517,8 @@ msgstr "Tüm RX FIFO'ları kullanımda" msgid "All SPI peripherals are in use" msgstr "Tüm SPI çevre birimleri kullanımda" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c msgid "All UART peripherals are in use" msgstr "Tüm UART çevre birimleri kullanımda" @@ -664,6 +671,7 @@ msgstr "Bitmap boyutu ve bit başına değer uyuşmalı" msgid "Boot device must be first (interface #0)." msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "Hem RX hem de TX akış kontrolü için gerekli" @@ -1007,7 +1015,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1065,6 +1073,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "Muteks serbest bırakılamadı, err 0x%04x" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1271,6 +1283,10 @@ msgstr "" msgid "Interrupted by output function" msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c @@ -1364,6 +1380,7 @@ msgstr "Geçersiz boyut" msgid "Invalid socket for TLS" msgstr "TLS için geçersiz soket" +#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" @@ -1926,6 +1943,7 @@ msgstr "" msgid "ROS topic failed to initialize" msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2018,6 +2036,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2149,6 +2171,10 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" @@ -2192,6 +2218,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2200,6 +2230,14 @@ msgstr "" msgid "UART re-init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + #: ports/stm/common-hal/busio/UART.c msgid "UART write" msgstr ""