diff options
| author | James Munns <[email protected]> | 2025-12-04 18:37:01 +0100 |
|---|---|---|
| committer | James Munns <[email protected]> | 2025-12-04 18:43:11 +0100 |
| commit | dc6bf5d44675f6f2013ddfab6b14df25a996a965 (patch) | |
| tree | ab593af8f4b2be502a809833f80e4f3b741b8fad /embassy-mcxa | |
| parent | 22bae2d80153003af4637c4b0cc26d52858f5228 (diff) | |
Move to subfolder
Diffstat (limited to 'embassy-mcxa')
67 files changed, 14560 insertions, 0 deletions
diff --git a/embassy-mcxa/.cargo/config.toml b/embassy-mcxa/.cargo/config.toml new file mode 100644 index 000000000..55dd5ea5f --- /dev/null +++ b/embassy-mcxa/.cargo/config.toml | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | [build] | ||
| 2 | target = "thumbv8m.main-none-eabihf" # Cortex-M33 | ||
diff --git a/embassy-mcxa/.github/DOCS.md b/embassy-mcxa/.github/DOCS.md new file mode 100644 index 000000000..e932784c7 --- /dev/null +++ b/embassy-mcxa/.github/DOCS.md | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | # Github config and workflows | ||
| 2 | |||
| 3 | In this folder there is configuration for codecoverage, dependabot, and ci | ||
| 4 | workflows that check the library more deeply than the default configurations. | ||
| 5 | |||
| 6 | This folder can be or was merged using a --allow-unrelated-histories merge | ||
| 7 | strategy from <https://github.com/jonhoo/rust-ci-conf/> which provides a | ||
| 8 | reasonably sensible base for writing your own ci on. By using this strategy | ||
| 9 | the history of the CI repo is included in your repo, and future updates to | ||
| 10 | the CI can be merged later. | ||
| 11 | |||
| 12 | To perform this merge run: | ||
| 13 | |||
| 14 | ```shell | ||
| 15 | git remote add ci https://github.com/jonhoo/rust-ci-conf.git | ||
| 16 | git fetch ci | ||
| 17 | git merge --allow-unrelated-histories ci/main | ||
| 18 | ``` | ||
| 19 | |||
| 20 | An overview of the files in this project is available at: | ||
| 21 | <https://www.youtube.com/watch?v=xUH-4y92jPg&t=491s>, which contains some | ||
| 22 | rationale for decisions and runs through an example of solving minimal version | ||
| 23 | and OpenSSL issues. | ||
diff --git a/embassy-mcxa/.github/codecov.yml b/embassy-mcxa/.github/codecov.yml new file mode 100644 index 000000000..cd5ce8fc1 --- /dev/null +++ b/embassy-mcxa/.github/codecov.yml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | # ref: https://docs.codecov.com/docs/codecovyml-reference | ||
| 2 | coverage: | ||
| 3 | # Hold ourselves to a high bar | ||
| 4 | range: 85..100 | ||
| 5 | round: down | ||
| 6 | precision: 1 | ||
| 7 | status: | ||
| 8 | # ref: https://docs.codecov.com/docs/commit-status | ||
| 9 | project: | ||
| 10 | default: | ||
| 11 | # Avoid false negatives | ||
| 12 | threshold: 1% | ||
| 13 | |||
| 14 | # Test files aren't important for coverage | ||
| 15 | ignore: | ||
| 16 | - "tests" | ||
| 17 | |||
| 18 | # Make comments less noisy | ||
| 19 | comment: | ||
| 20 | layout: "files" | ||
| 21 | require_changes: true | ||
diff --git a/embassy-mcxa/.github/dependabot.yml b/embassy-mcxa/.github/dependabot.yml new file mode 100644 index 000000000..d0f091e7b --- /dev/null +++ b/embassy-mcxa/.github/dependabot.yml | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | version: 2 | ||
| 2 | updates: | ||
| 3 | - package-ecosystem: github-actions | ||
| 4 | directory: / | ||
| 5 | schedule: | ||
| 6 | interval: daily | ||
| 7 | - package-ecosystem: cargo | ||
| 8 | directory: / | ||
| 9 | schedule: | ||
| 10 | interval: daily | ||
| 11 | ignore: | ||
| 12 | - dependency-name: "*" | ||
| 13 | # patch and minor updates don't matter for libraries as consumers of this library build | ||
| 14 | # with their own lockfile, rather than the version specified in this library's lockfile | ||
| 15 | # remove this ignore rule if your package has binaries to ensure that the binaries are | ||
| 16 | # built with the exact set of dependencies and those are up to date. | ||
| 17 | update-types: | ||
| 18 | - "version-update:semver-patch" | ||
| 19 | - "version-update:semver-minor" | ||
diff --git a/embassy-mcxa/.github/workflows/cargo-vet-pr-comment.yml b/embassy-mcxa/.github/workflows/cargo-vet-pr-comment.yml new file mode 100644 index 000000000..66f27ceab --- /dev/null +++ b/embassy-mcxa/.github/workflows/cargo-vet-pr-comment.yml | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | # This workflow triggers after cargo-vet workflow has run. | ||
| 2 | # It adds a comment to the PR with the results of the cargo vet run. | ||
| 3 | # It first adds a comment if the cargo vet run fails, | ||
| 4 | # and updates the comment if the cargo vet run succeeds after having failed at least once. | ||
| 5 | |||
| 6 | name: Cargo vet PR comment | ||
| 7 | |||
| 8 | on: | ||
| 9 | workflow_run: | ||
| 10 | workflows: [cargo-vet] | ||
| 11 | types: | ||
| 12 | - completed | ||
| 13 | |||
| 14 | permissions: | ||
| 15 | contents: read | ||
| 16 | pull-requests: write | ||
| 17 | |||
| 18 | concurrency: | ||
| 19 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||
| 20 | cancel-in-progress: true | ||
| 21 | |||
| 22 | jobs: | ||
| 23 | |||
| 24 | find-pr-comment: | ||
| 25 | # This job runs when the cargo-vet job fails or succeeds | ||
| 26 | # It will download the artifact from the failed job and post a comment on the PR | ||
| 27 | runs-on: ubuntu-latest | ||
| 28 | outputs: | ||
| 29 | comment-id: ${{ steps.get-comment-id.outputs.comment-id }} | ||
| 30 | pr-number: ${{ steps.get-pr-number.outputs.pr_number }} | ||
| 31 | if: github.event.workflow_run.event == 'pull_request' | ||
| 32 | steps: | ||
| 33 | - name: 'Download artifact' | ||
| 34 | uses: actions/download-artifact@v6 | ||
| 35 | with: | ||
| 36 | github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| 37 | name: pr | ||
| 38 | path: pr/ | ||
| 39 | run-id: ${{ github.event.workflow_run.id }} | ||
| 40 | |||
| 41 | - name: 'Get PR number' | ||
| 42 | id: get-pr-number | ||
| 43 | run: echo "pr_number=$(cat ./pr/NR)" >> $GITHUB_OUTPUT | ||
| 44 | |||
| 45 | - name: 'Find existing comment' | ||
| 46 | id: find-comment | ||
| 47 | uses: peter-evans/find-comment@v4 | ||
| 48 | with: | ||
| 49 | issue-number: ${{ steps.get-pr-number.outputs.pr_number }} | ||
| 50 | comment-author: 'github-actions[bot]' | ||
| 51 | body-includes: 'comment-tag: [cargo-vet]' | ||
| 52 | |||
| 53 | - name: 'Get comment ID' | ||
| 54 | id: get-comment-id | ||
| 55 | if: ${{ steps.find-comment.outputs.comment-id != '' }} | ||
| 56 | run: echo "comment-id=${{ steps.find-comment.outputs.comment-id }}" >> $GITHUB_OUTPUT | ||
| 57 | |||
| 58 | post-comment-failure: | ||
| 59 | # This job runs when the cargo-vet job fails | ||
| 60 | # It will download the artifact from the failed job and post a comment on the PR | ||
| 61 | runs-on: ubuntu-latest | ||
| 62 | needs: find-pr-comment | ||
| 63 | if: github.event.workflow_run.conclusion == 'failure' | ||
| 64 | steps: | ||
| 65 | - name: 'Comment on PR - Failure' | ||
| 66 | uses: peter-evans/create-or-update-comment@v5 | ||
| 67 | with: | ||
| 68 | comment-id: ${{ needs.find-pr-comment.outputs.comment-id }} | ||
| 69 | issue-number: ${{ needs.find-pr-comment.outputs.pr-number }} | ||
| 70 | body: | | ||
| 71 | # Cargo Vet Audit Failed | ||
| 72 | |||
| 73 | `cargo vet` has failed in this PR. Please run `cargo vet --locked` locally to check for new or updated unvetted dependencies. | ||
| 74 | Details about the vetting process can be found in [supply-chain/README.md](../blob/main/supply-chain/README.md) | ||
| 75 | |||
| 76 | ## If the unvetted dependencies are not needed | ||
| 77 | Please modify Cargo.toml file to avoid including the dependencies. | ||
| 78 | |||
| 79 | ## If the unvetted dependencies are needed | ||
| 80 | Post a new comment with the questionnaire below to the PR to help the auditors vet the dependencies. | ||
| 81 | After the auditors have vetted the dependencies, the PR will need to be rebased to pick up the new audits and pass this check. | ||
| 82 | |||
| 83 | ### Copy and paste the questionnaire as a new comment and provide your answers: | ||
| 84 | |||
| 85 | **1. What crates (with version) need to be audited?** | ||
| 86 | |||
| 87 | **2. How many of the crates are version updates vs new dependencies?** | ||
| 88 | |||
| 89 | **3. To confirm none of the already included crates serve your needs, please provide a brief description of the purpose of the new crates.** | ||
| 90 | |||
| 91 | **4. Any extra notes to the auditors to help with their audits.** | ||
| 92 | |||
| 93 | <!-- | ||
| 94 | This comment is auto-generated by the cargo-vet workflow. | ||
| 95 | Please do not edit it directly. | ||
| 96 | |||
| 97 | comment-tag: [cargo-vet] | ||
| 98 | --> | ||
| 99 | edit-mode: replace | ||
| 100 | |||
| 101 | - name: 'Label PR' | ||
| 102 | uses: actions/github-script@v8 | ||
| 103 | with: | ||
| 104 | script: | | ||
| 105 | github.rest.issues.addLabels({ | ||
| 106 | issue_number: ${{ needs.find-pr-comment.outputs.pr-number }}, | ||
| 107 | owner: context.repo.owner, | ||
| 108 | repo: context.repo.repo, | ||
| 109 | labels: ['cargo vet'] | ||
| 110 | }) | ||
| 111 | |||
| 112 | post-comment-success: | ||
| 113 | # This job runs when the cargo-vet job succeeds | ||
| 114 | # It will update the comment on the PR with a success message | ||
| 115 | runs-on: ubuntu-latest | ||
| 116 | needs: find-pr-comment | ||
| 117 | if: github.event.workflow_run.conclusion == 'success' | ||
| 118 | steps: | ||
| 119 | - name: 'Comment on PR - Success' | ||
| 120 | # Only update the comment if it exists | ||
| 121 | # This is to avoid creating a new comment if the cargo-vet job has never failed before | ||
| 122 | if: ${{ needs.find-pr-comment.outputs.comment-id }} | ||
| 123 | uses: peter-evans/create-or-update-comment@v5 | ||
| 124 | with: | ||
| 125 | comment-id: ${{ needs.find-pr-comment.outputs.comment-id }} | ||
| 126 | issue-number: ${{ needs.find-pr-comment.outputs.pr-number }} | ||
| 127 | body: | | ||
| 128 | # Cargo Vet Audit Passed | ||
| 129 | `cargo vet` has passed in this PR. No new unvetted dependencies were found. | ||
| 130 | |||
| 131 | <!-- | ||
| 132 | This comment is auto-generated by the cargo-vet workflow. | ||
| 133 | Please do not edit it directly. | ||
| 134 | |||
| 135 | comment-tag: [cargo-vet] | ||
| 136 | --> | ||
| 137 | edit-mode: replace | ||
diff --git a/embassy-mcxa/.github/workflows/cargo-vet.yml b/embassy-mcxa/.github/workflows/cargo-vet.yml new file mode 100644 index 000000000..d585d1df5 --- /dev/null +++ b/embassy-mcxa/.github/workflows/cargo-vet.yml | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | # This workflow runs whenever a PR is opened or updated. It runs cargo vet to check for unvetted dependencies in the Cargo.lock file. | ||
| 2 | permissions: | ||
| 3 | contents: read | ||
| 4 | on: | ||
| 5 | pull_request: | ||
| 6 | |||
| 7 | concurrency: | ||
| 8 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||
| 9 | cancel-in-progress: true | ||
| 10 | |||
| 11 | name: cargo-vet | ||
| 12 | jobs: | ||
| 13 | vet: | ||
| 14 | # cargo-vet checks for unvetted dependencies in the Cargo.lock file | ||
| 15 | # This is to ensure that new dependencies are vetted before they are added to the project | ||
| 16 | name: vet-dependencies | ||
| 17 | runs-on: ubuntu-latest | ||
| 18 | env: | ||
| 19 | CARGO_VET_VERSION: 0.10.1 | ||
| 20 | |||
| 21 | steps: | ||
| 22 | - uses: actions/checkout@v6 | ||
| 23 | with: | ||
| 24 | submodules: true | ||
| 25 | |||
| 26 | - uses: actions/cache@v4 | ||
| 27 | with: | ||
| 28 | path: ${{ runner.tool_cache }}/cargo-vet | ||
| 29 | key: cargo-vet-bin-${{ env.CARGO_VET_VERSION }} | ||
| 30 | |||
| 31 | - name: Add the tool cache directory to the search path | ||
| 32 | run: echo "${{ runner.tool_cache }}/cargo-vet/bin" >> $GITHUB_PATH | ||
| 33 | |||
| 34 | - name: Ensure that the tool cache is populated with the cargo-vet binary | ||
| 35 | run: cargo install --root ${{ runner.tool_cache }}/cargo-vet --version ${{ env.CARGO_VET_VERSION }} cargo-vet | ||
| 36 | |||
| 37 | - name: Invoke cargo-vet | ||
| 38 | run: cargo vet --locked | ||
| 39 | |||
| 40 | - name: Save PR number | ||
| 41 | # PR number is saved as an artifact so it can be used to determine the PR to comment on by the vet-pr-comment workflow | ||
| 42 | # vet-pr-comment workflow is triggered by the workflow_run event so it runs in the context of the base branch and not the PR branch | ||
| 43 | if: ${{ failure() }} || ${{ success() }} | ||
| 44 | run: | | ||
| 45 | mkdir -p ./pr | ||
| 46 | echo ${{ github.event.number }} > ./pr/NR | ||
| 47 | - uses: actions/upload-artifact@v5 | ||
| 48 | # Need to upload the artifact in both success and failure cases so comment can be updated in either case | ||
| 49 | if: ${{ failure() }} || ${{ success() }} | ||
| 50 | with: | ||
| 51 | name: pr | ||
| 52 | path: pr/ | ||
| 53 | overwrite: true \ No newline at end of file | ||
diff --git a/embassy-mcxa/.github/workflows/check.yml b/embassy-mcxa/.github/workflows/check.yml new file mode 100644 index 000000000..ad9f44428 --- /dev/null +++ b/embassy-mcxa/.github/workflows/check.yml | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | # This workflow runs whenever a PR is opened or updated, or a commit is pushed to main. It runs | ||
| 2 | # several checks: | ||
| 3 | # - fmt: checks that the code is formatted according to rustfmt | ||
| 4 | # - clippy: checks that the code does not contain any clippy warnings | ||
| 5 | # - doc: checks that the code can be documented without errors | ||
| 6 | # - hack: check combinations of feature flags | ||
| 7 | # - msrv: check that the msrv specified in the crate is correct | ||
| 8 | permissions: | ||
| 9 | contents: read | ||
| 10 | |||
| 11 | # This configuration allows maintainers of this repo to create a branch and pull request based on | ||
| 12 | # the new branch. Restricting the push trigger to the main branch ensures that the PR only gets | ||
| 13 | # built once. | ||
| 14 | on: | ||
| 15 | |||
| 16 | push: | ||
| 17 | branches: [main, main-nextgen] | ||
| 18 | pull_request: | ||
| 19 | |||
| 20 | # If new code is pushed to a PR branch, then cancel in progress workflows for that PR. Ensures that | ||
| 21 | # we don't waste CI time, and returns results quicker https://github.com/jonhoo/rust-ci-conf/pull/5 | ||
| 22 | concurrency: | ||
| 23 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||
| 24 | cancel-in-progress: true | ||
| 25 | |||
| 26 | name: check | ||
| 27 | |||
| 28 | jobs: | ||
| 29 | |||
| 30 | fmt: | ||
| 31 | runs-on: ubuntu-latest | ||
| 32 | name: nightly / fmt | ||
| 33 | |||
| 34 | strategy: | ||
| 35 | fail-fast: false | ||
| 36 | matrix: | ||
| 37 | workdir: [ ".", "examples",] | ||
| 38 | |||
| 39 | steps: | ||
| 40 | - uses: actions/checkout@v6 | ||
| 41 | with: | ||
| 42 | submodules: true | ||
| 43 | |||
| 44 | - name: Install nightly | ||
| 45 | uses: dtolnay/rust-toolchain@nightly | ||
| 46 | with: | ||
| 47 | components: rustfmt | ||
| 48 | targets: thumbv8m.main-none-eabihf | ||
| 49 | |||
| 50 | - name: cargo fmt --check | ||
| 51 | run: cargo fmt --check | ||
| 52 | working-directory: ${{ matrix.workdir }} | ||
| 53 | |||
| 54 | clippy-examples: | ||
| 55 | runs-on: ubuntu-latest | ||
| 56 | name: ${{ matrix.toolchain }} / clippy | ||
| 57 | |||
| 58 | permissions: | ||
| 59 | contents: read | ||
| 60 | checks: write | ||
| 61 | |||
| 62 | strategy: | ||
| 63 | fail-fast: false | ||
| 64 | matrix: | ||
| 65 | # Get early warning of new lints which are regularly introduced in beta channels. | ||
| 66 | toolchain: [stable] | ||
| 67 | workdir: ["examples"] | ||
| 68 | |||
| 69 | steps: | ||
| 70 | - uses: actions/checkout@v6 | ||
| 71 | with: | ||
| 72 | submodules: true | ||
| 73 | |||
| 74 | - name: Install ${{ matrix.toolchain }} | ||
| 75 | uses: dtolnay/rust-toolchain@master | ||
| 76 | with: | ||
| 77 | toolchain: ${{ matrix.toolchain }} | ||
| 78 | components: clippy | ||
| 79 | targets: thumbv8m.main-none-eabihf | ||
| 80 | |||
| 81 | - name: cargo clippy | ||
| 82 | working-directory: ${{ matrix.workdir }} | ||
| 83 | run: | | ||
| 84 | cargo clippy --locked -- -Dwarnings -D clippy::suspicious -D clippy::correctness -D clippy::perf -D clippy::style | ||
| 85 | |||
| 86 | # Enable once we have a released crate | ||
| 87 | # semver: | ||
| 88 | # runs-on: ubuntu-latest | ||
| 89 | # name: semver | ||
| 90 | # steps: | ||
| 91 | # - uses: actions/checkout@v6 | ||
| 92 | # with: | ||
| 93 | # submodules: true | ||
| 94 | # - name: Install stable | ||
| 95 | # uses: dtolnay/rust-toolchain@stable | ||
| 96 | # with: | ||
| 97 | # components: rustfmt | ||
| 98 | # - name: cargo-semver-checks | ||
| 99 | # uses: obi1kenobi/cargo-semver-checks-action@v2 | ||
| 100 | |||
| 101 | doc: | ||
| 102 | # run docs generation on nightly rather than stable. This enables features like | ||
| 103 | # https://doc.rust-lang.org/beta/unstable-book/language-features/doc-cfg.html which allows an | ||
| 104 | # API be documented as only available in some specific platforms. | ||
| 105 | runs-on: ubuntu-latest | ||
| 106 | name: nightly / doc | ||
| 107 | |||
| 108 | steps: | ||
| 109 | - uses: actions/checkout@v6 | ||
| 110 | with: | ||
| 111 | submodules: true | ||
| 112 | |||
| 113 | - name: Install nightly | ||
| 114 | uses: dtolnay/rust-toolchain@nightly | ||
| 115 | with: | ||
| 116 | targets: thumbv8m.main-none-eabihf | ||
| 117 | |||
| 118 | - name: cargo doc | ||
| 119 | run: | | ||
| 120 | cargo doc --no-deps --all-features --locked | ||
| 121 | env: | ||
| 122 | RUSTDOCFLAGS: --cfg docsrs | ||
| 123 | |||
| 124 | hack: | ||
| 125 | # cargo-hack checks combinations of feature flags to ensure that features are all additive | ||
| 126 | # which is required for feature unification | ||
| 127 | runs-on: ubuntu-latest | ||
| 128 | name: ubuntu / stable / features | ||
| 129 | |||
| 130 | strategy: | ||
| 131 | fail-fast: false | ||
| 132 | |||
| 133 | steps: | ||
| 134 | - uses: actions/checkout@v6 | ||
| 135 | with: | ||
| 136 | submodules: true | ||
| 137 | |||
| 138 | - name: Install stable | ||
| 139 | uses: dtolnay/rust-toolchain@stable | ||
| 140 | with: | ||
| 141 | toolchain: stable | ||
| 142 | components: clippy | ||
| 143 | targets: thumbv8m.main-none-eabihf | ||
| 144 | |||
| 145 | - name: cargo install cargo-hack | ||
| 146 | uses: taiki-e/install-action@cargo-hack | ||
| 147 | |||
| 148 | - name: cargo hack | ||
| 149 | run: cargo hack --feature-powerset check | ||
| 150 | |||
| 151 | deny: | ||
| 152 | # cargo-deny checks licenses, advisories, sources, and bans for | ||
| 153 | # our dependencies. | ||
| 154 | runs-on: ubuntu-latest | ||
| 155 | name: ubuntu / stable / deny | ||
| 156 | |||
| 157 | steps: | ||
| 158 | - uses: actions/checkout@v6 | ||
| 159 | with: | ||
| 160 | submodules: true | ||
| 161 | |||
| 162 | - name: Install stable | ||
| 163 | uses: dtolnay/rust-toolchain@stable | ||
| 164 | with: | ||
| 165 | targets: thumbv8m.main-none-eabihf | ||
| 166 | |||
| 167 | - name: cargo install cargo-deny | ||
| 168 | uses: EmbarkStudios/cargo-deny-action@v2 | ||
| 169 | with: | ||
| 170 | log-level: warn | ||
| 171 | manifest-path: ./Cargo.toml | ||
| 172 | command: check | ||
| 173 | arguments: --all-features --locked | ||
| 174 | |||
| 175 | msrv: | ||
| 176 | # check that we can build using the minimal rust version that is specified by this crate | ||
| 177 | runs-on: ubuntu-latest | ||
| 178 | # we use a matrix here just because env can't be used in job names | ||
| 179 | # https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability | ||
| 180 | strategy: | ||
| 181 | fail-fast: false | ||
| 182 | matrix: | ||
| 183 | msrv: ["1.91"] # We're relying on namespaced-features, which | ||
| 184 | # was released in 1.60 | ||
| 185 | # | ||
| 186 | # We also depend on `fixed' which requires rust | ||
| 187 | # 1.71 | ||
| 188 | # | ||
| 189 | # Additionally, we depend on embedded-hal-async | ||
| 190 | # which requires 1.75 | ||
| 191 | # | ||
| 192 | # embassy-time requires 1.79 due to | ||
| 193 | # collapse_debuginfo | ||
| 194 | # | ||
| 195 | # embassy upstream switched to rust 1.85 | ||
| 196 | # | ||
| 197 | # unsigned_is_multiple_of requires 1.90, else we get clippy warnings | ||
| 198 | # | ||
| 199 | # [email protected] requires rustc 1.91 | ||
| 200 | |||
| 201 | name: ubuntu / ${{ matrix.msrv }} | ||
| 202 | steps: | ||
| 203 | - uses: actions/checkout@v6 | ||
| 204 | with: | ||
| 205 | submodules: true | ||
| 206 | |||
| 207 | - name: Install ${{ matrix.msrv }} | ||
| 208 | uses: dtolnay/rust-toolchain@master | ||
| 209 | with: | ||
| 210 | toolchain: ${{ matrix.msrv }} | ||
| 211 | targets: thumbv8m.main-none-eabihf | ||
| 212 | |||
| 213 | - name: cargo +${{ matrix.msrv }} check | ||
| 214 | run: | | ||
| 215 | cargo check --all-features --locked | ||
diff --git a/embassy-mcxa/.github/workflows/nostd.yml b/embassy-mcxa/.github/workflows/nostd.yml new file mode 100644 index 000000000..cf6629854 --- /dev/null +++ b/embassy-mcxa/.github/workflows/nostd.yml | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | # This workflow checks whether the library is able to run without the std library (e.g., embedded). | ||
| 2 | # This entire file should be removed if this crate does not support no-std. See check.yml for | ||
| 3 | # information about how the concurrency cancellation and workflow triggering works | ||
| 4 | permissions: | ||
| 5 | contents: read | ||
| 6 | |||
| 7 | on: | ||
| 8 | push: | ||
| 9 | branches: [main, main-nextgen] | ||
| 10 | pull_request: | ||
| 11 | |||
| 12 | concurrency: | ||
| 13 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||
| 14 | cancel-in-progress: true | ||
| 15 | |||
| 16 | name: no-std | ||
| 17 | |||
| 18 | jobs: | ||
| 19 | nostd: | ||
| 20 | runs-on: ubuntu-latest | ||
| 21 | name: ${{ matrix.target }} | ||
| 22 | |||
| 23 | steps: | ||
| 24 | - uses: actions/checkout@v6 | ||
| 25 | with: | ||
| 26 | submodules: true | ||
| 27 | |||
| 28 | - name: Install stable | ||
| 29 | uses: dtolnay/rust-toolchain@stable | ||
| 30 | with: | ||
| 31 | targets: thumbv8m.main-none-eabihf | ||
| 32 | |||
| 33 | - name: Show variable | ||
| 34 | run: echo ${{ env.TOKEN }} | ||
| 35 | |||
| 36 | - name: cargo check | ||
| 37 | run: | | ||
| 38 | cargo check --target thumbv8m.main-none-eabihf --all-features --locked | ||
diff --git a/embassy-mcxa/.github/workflows/rolling.yml b/embassy-mcxa/.github/workflows/rolling.yml new file mode 100644 index 000000000..73b48484a --- /dev/null +++ b/embassy-mcxa/.github/workflows/rolling.yml | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | # This workflow runs every morning at midnight. It will run cargo hack | ||
| 2 | # and a build with msrv. If any dependency breaks our crate, we will | ||
| 3 | # know ASAP. | ||
| 4 | # | ||
| 5 | # - check: build with all features | ||
| 6 | # - msrv: check that the msrv specified in the crate is correct | ||
| 7 | permissions: | ||
| 8 | contents: read | ||
| 9 | |||
| 10 | on: | ||
| 11 | schedule: | ||
| 12 | - cron: '0 0 * * *' | ||
| 13 | |||
| 14 | name: rolling | ||
| 15 | jobs: | ||
| 16 | |||
| 17 | check: | ||
| 18 | runs-on: ubuntu-latest | ||
| 19 | name: ubuntu / stable / features | ||
| 20 | strategy: | ||
| 21 | fail-fast: false | ||
| 22 | steps: | ||
| 23 | - uses: actions/checkout@v6 | ||
| 24 | with: | ||
| 25 | submodules: true | ||
| 26 | - name: Install stable | ||
| 27 | uses: dtolnay/rust-toolchain@stable | ||
| 28 | with: | ||
| 29 | targets: thumbv8m.main-none-eabihf | ||
| 30 | |||
| 31 | - name: cargo install cargo-hack | ||
| 32 | uses: taiki-e/install-action@cargo-hack | ||
| 33 | - name: cargo check | ||
| 34 | run: | | ||
| 35 | cargo update | ||
| 36 | cargo check --all-features | ||
| 37 | |||
| 38 | msrv: | ||
| 39 | runs-on: ubuntu-latest | ||
| 40 | strategy: | ||
| 41 | fail-fast: false | ||
| 42 | matrix: | ||
| 43 | msrv: ["1.91"] | ||
| 44 | |||
| 45 | name: ubuntu / ${{ matrix.msrv }} (${{ matrix.commit }}) | ||
| 46 | steps: | ||
| 47 | - uses: actions/checkout@v6 | ||
| 48 | with: | ||
| 49 | submodules: true | ||
| 50 | - name: Install ${{ matrix.msrv }} | ||
| 51 | uses: dtolnay/rust-toolchain@master | ||
| 52 | with: | ||
| 53 | toolchain: ${{ matrix.msrv }} | ||
| 54 | targets: thumbv8m.main-none-eabihf | ||
| 55 | - name: cargo +${{ matrix.msrv }} check | ||
| 56 | run: | | ||
| 57 | cargo update | ||
| 58 | cargo check --all-features | ||
diff --git a/embassy-mcxa/.gitignore b/embassy-mcxa/.gitignore new file mode 100644 index 000000000..d128a49cb --- /dev/null +++ b/embassy-mcxa/.gitignore | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # Rust | ||
| 2 | /target/ | ||
| 3 | |||
| 4 | # IDE | ||
| 5 | .vscode/ | ||
| 6 | .idea/ | ||
| 7 | |||
| 8 | # OS | ||
| 9 | .DS_Store | ||
| 10 | Thumbs.db | ||
| 11 | |||
| 12 | # Embedded | ||
| 13 | *.bin | ||
| 14 | *.hex | ||
| 15 | *.elf | ||
| 16 | *.map | ||
| 17 | |||
| 18 | # Debug | ||
| 19 | *.log | ||
diff --git a/embassy-mcxa/CODEOWNERS b/embassy-mcxa/CODEOWNERS new file mode 100644 index 000000000..6e0f4c4c6 --- /dev/null +++ b/embassy-mcxa/CODEOWNERS | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | * @jamesmunns @felipebalbi | ||
| 2 | |||
| 3 | # Any changes in the supply-chain folder needs approval | ||
| 4 | # from auditors as it relates to cargo vet | ||
| 5 | **/supply-chain @OpenDevicePartnership/crate-auditors \ No newline at end of file | ||
diff --git a/embassy-mcxa/CODE_OF_CONDUCT.md b/embassy-mcxa/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..54a673e04 --- /dev/null +++ b/embassy-mcxa/CODE_OF_CONDUCT.md | |||
| @@ -0,0 +1,132 @@ | |||
| 1 | # Contributor Covenant Code of Conduct | ||
| 2 | |||
| 3 | ## Our Pledge | ||
| 4 | |||
| 5 | We as members, contributors, and leaders pledge to make participation in our | ||
| 6 | community a harassment-free experience for everyone, regardless of age, body | ||
| 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender | ||
| 8 | identity and expression, level of experience, education, socio-economic status, | ||
| 9 | nationality, personal appearance, race, caste, color, religion, or sexual | ||
| 10 | identity and orientation. | ||
| 11 | |||
| 12 | We pledge to act and interact in ways that contribute to an open, welcoming, | ||
| 13 | diverse, inclusive, and healthy community. | ||
| 14 | |||
| 15 | ## Our Standards | ||
| 16 | |||
| 17 | Examples of behavior that contributes to a positive environment for our | ||
| 18 | community include: | ||
| 19 | |||
| 20 | * Demonstrating empathy and kindness toward other people | ||
| 21 | * Being respectful of differing opinions, viewpoints, and experiences | ||
| 22 | * Giving and gracefully accepting constructive feedback | ||
| 23 | * Accepting responsibility and apologizing to those affected by our mistakes, | ||
| 24 | and learning from the experience | ||
| 25 | * Focusing on what is best not just for us as individuals, but for the overall | ||
| 26 | community | ||
| 27 | |||
| 28 | Examples of unacceptable behavior include: | ||
| 29 | |||
| 30 | * The use of sexualized language or imagery, and sexual attention or advances of | ||
| 31 | any kind | ||
| 32 | * Trolling, insulting or derogatory comments, and personal or political attacks | ||
| 33 | * Public or private harassment | ||
| 34 | * Publishing others' private information, such as a physical or email address, | ||
| 35 | without their explicit permission | ||
| 36 | * Other conduct which could reasonably be considered inappropriate in a | ||
| 37 | professional setting | ||
| 38 | |||
| 39 | ## Enforcement Responsibilities | ||
| 40 | |||
| 41 | Community leaders are responsible for clarifying and enforcing our standards of | ||
| 42 | acceptable behavior and will take appropriate and fair corrective action in | ||
| 43 | response to any behavior that they deem inappropriate, threatening, offensive, | ||
| 44 | or harmful. | ||
| 45 | |||
| 46 | Community leaders have the right and responsibility to remove, edit, or reject | ||
| 47 | comments, commits, code, wiki edits, issues, and other contributions that are | ||
| 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation | ||
| 49 | decisions when appropriate. | ||
| 50 | |||
| 51 | ## Scope | ||
| 52 | |||
| 53 | This Code of Conduct applies within all community spaces, and also applies when | ||
| 54 | an individual is officially representing the community in public spaces. | ||
| 55 | Examples of representing our community include using an official e-mail address, | ||
| 56 | posting via an official social media account, or acting as an appointed | ||
| 57 | representative at an online or offline event. | ||
| 58 | |||
| 59 | ## Enforcement | ||
| 60 | |||
| 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be | ||
| 62 | reported to the community leaders responsible for enforcement at | ||
| 63 | [email protected]. | ||
| 64 | All complaints will be reviewed and investigated promptly and fairly. | ||
| 65 | |||
| 66 | All community leaders are obligated to respect the privacy and security of the | ||
| 67 | reporter of any incident. | ||
| 68 | |||
| 69 | ## Enforcement Guidelines | ||
| 70 | |||
| 71 | Community leaders will follow these Community Impact Guidelines in determining | ||
| 72 | the consequences for any action they deem in violation of this Code of Conduct: | ||
| 73 | |||
| 74 | ### 1. Correction | ||
| 75 | |||
| 76 | **Community Impact**: Use of inappropriate language or other behavior deemed | ||
| 77 | unprofessional or unwelcome in the community. | ||
| 78 | |||
| 79 | **Consequence**: A private, written warning from community leaders, providing | ||
| 80 | clarity around the nature of the violation and an explanation of why the | ||
| 81 | behavior was inappropriate. A public apology may be requested. | ||
| 82 | |||
| 83 | ### 2. Warning | ||
| 84 | |||
| 85 | **Community Impact**: A violation through a single incident or series of | ||
| 86 | actions. | ||
| 87 | |||
| 88 | **Consequence**: A warning with consequences for continued behavior. No | ||
| 89 | interaction with the people involved, including unsolicited interaction with | ||
| 90 | those enforcing the Code of Conduct, for a specified period of time. This | ||
| 91 | includes avoiding interactions in community spaces as well as external channels | ||
| 92 | like social media. Violating these terms may lead to a temporary or permanent | ||
| 93 | ban. | ||
| 94 | |||
| 95 | ### 3. Temporary Ban | ||
| 96 | |||
| 97 | **Community Impact**: A serious violation of community standards, including | ||
| 98 | sustained inappropriate behavior. | ||
| 99 | |||
| 100 | **Consequence**: A temporary ban from any sort of interaction or public | ||
| 101 | communication with the community for a specified period of time. No public or | ||
| 102 | private interaction with the people involved, including unsolicited interaction | ||
| 103 | with those enforcing the Code of Conduct, is allowed during this period. | ||
| 104 | Violating these terms may lead to a permanent ban. | ||
| 105 | |||
| 106 | ### 4. Permanent Ban | ||
| 107 | |||
| 108 | **Community Impact**: Demonstrating a pattern of violation of community | ||
| 109 | standards, including sustained inappropriate behavior, harassment of an | ||
| 110 | individual, or aggression toward or disparagement of classes of individuals. | ||
| 111 | |||
| 112 | **Consequence**: A permanent ban from any sort of public interaction within the | ||
| 113 | community. | ||
| 114 | |||
| 115 | ## Attribution | ||
| 116 | |||
| 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], | ||
| 118 | version 2.1, available at | ||
| 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. | ||
| 120 | |||
| 121 | Community Impact Guidelines were inspired by | ||
| 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. | ||
| 123 | |||
| 124 | For answers to common questions about this code of conduct, see the FAQ at | ||
| 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at | ||
| 126 | [https://www.contributor-covenant.org/translations][translations]. | ||
| 127 | |||
| 128 | [homepage]: https://www.contributor-covenant.org | ||
| 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html | ||
| 130 | [Mozilla CoC]: https://github.com/mozilla/diversity | ||
| 131 | [FAQ]: https://www.contributor-covenant.org/faq | ||
| 132 | [translations]: https://www.contributor-covenant.org/translations | ||
diff --git a/embassy-mcxa/CONTRIBUTING.md b/embassy-mcxa/CONTRIBUTING.md new file mode 100644 index 000000000..f10eb5be9 --- /dev/null +++ b/embassy-mcxa/CONTRIBUTING.md | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | # Contributing to Open Device Partnership | ||
| 2 | |||
| 3 | The Open Device Partnership project welcomes your suggestions and contributions! Before opening your first issue or pull request, please review our | ||
| 4 | [Code of Conduct](CODE_OF_CONDUCT.md) to understand how our community interacts in an inclusive and respectful manner. | ||
| 5 | |||
| 6 | ## Contribution Licensing | ||
| 7 | |||
| 8 | Most of our code is distributed under the terms of the [MIT license](LICENSE), and when you contribute code that you wrote to our repositories, | ||
| 9 | you agree that you are contributing under those same terms. In addition, by submitting your contributions you are indicating that | ||
| 10 | you have the right to submit those contributions under those terms. | ||
| 11 | |||
| 12 | ## Other Contribution Information | ||
| 13 | |||
| 14 | If you wish to contribute code or documentation authored by others, or using the terms of any other license, please indicate that clearly in your | ||
| 15 | pull request so that the project team can discuss the situation with you. | ||
| 16 | |||
| 17 | ## Commit Message | ||
| 18 | |||
| 19 | * Use meaningful commit messages. See [this blogpost](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) | ||
| 20 | |||
| 21 | ## PR Etiquette | ||
| 22 | |||
| 23 | * Create a draft PR first | ||
| 24 | * Make sure that your branch has `.github` folder and all the code linting/sanity check workflows are passing in your draft PR before sending it out to code reviewers. | ||
| 25 | |||
| 26 | ## Regressions | ||
| 27 | |||
| 28 | When reporting a regression, please ensure that you use `git bisect` to find the first offending commit, as that will help us finding the culprit a lot faster. | ||
diff --git a/embassy-mcxa/Cargo.lock b/embassy-mcxa/Cargo.lock new file mode 100644 index 000000000..747a69c08 --- /dev/null +++ b/embassy-mcxa/Cargo.lock | |||
| @@ -0,0 +1,918 @@ | |||
| 1 | # This file is automatically @generated by Cargo. | ||
| 2 | # It is not intended for manual editing. | ||
| 3 | version = 4 | ||
| 4 | |||
| 5 | [[package]] | ||
| 6 | name = "aho-corasick" | ||
| 7 | version = "1.1.4" | ||
| 8 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 9 | checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" | ||
| 10 | dependencies = [ | ||
| 11 | "memchr", | ||
| 12 | ] | ||
| 13 | |||
| 14 | [[package]] | ||
| 15 | name = "autocfg" | ||
| 16 | version = "1.5.0" | ||
| 17 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 18 | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" | ||
| 19 | |||
| 20 | [[package]] | ||
| 21 | name = "bare-metal" | ||
| 22 | version = "0.2.5" | ||
| 23 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 24 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" | ||
| 25 | dependencies = [ | ||
| 26 | "rustc_version", | ||
| 27 | ] | ||
| 28 | |||
| 29 | [[package]] | ||
| 30 | name = "bitfield" | ||
| 31 | version = "0.13.2" | ||
| 32 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 33 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" | ||
| 34 | |||
| 35 | [[package]] | ||
| 36 | name = "bitflags" | ||
| 37 | version = "1.3.2" | ||
| 38 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 39 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" | ||
| 40 | |||
| 41 | [[package]] | ||
| 42 | name = "byteorder" | ||
| 43 | version = "1.5.0" | ||
| 44 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 45 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" | ||
| 46 | |||
| 47 | [[package]] | ||
| 48 | name = "cc" | ||
| 49 | version = "1.2.47" | ||
| 50 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 51 | checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" | ||
| 52 | dependencies = [ | ||
| 53 | "find-msvc-tools", | ||
| 54 | "shlex", | ||
| 55 | ] | ||
| 56 | |||
| 57 | [[package]] | ||
| 58 | name = "cfg-if" | ||
| 59 | version = "1.0.4" | ||
| 60 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 61 | checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" | ||
| 62 | |||
| 63 | [[package]] | ||
| 64 | name = "cordyceps" | ||
| 65 | version = "0.3.4" | ||
| 66 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 67 | checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" | ||
| 68 | dependencies = [ | ||
| 69 | "loom", | ||
| 70 | "tracing", | ||
| 71 | ] | ||
| 72 | |||
| 73 | [[package]] | ||
| 74 | name = "cortex-m" | ||
| 75 | version = "0.7.7" | ||
| 76 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 77 | checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" | ||
| 78 | dependencies = [ | ||
| 79 | "bare-metal", | ||
| 80 | "bitfield", | ||
| 81 | "critical-section", | ||
| 82 | "embedded-hal 0.2.7", | ||
| 83 | "volatile-register", | ||
| 84 | ] | ||
| 85 | |||
| 86 | [[package]] | ||
| 87 | name = "cortex-m-rt" | ||
| 88 | version = "0.7.5" | ||
| 89 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 90 | checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" | ||
| 91 | dependencies = [ | ||
| 92 | "cortex-m-rt-macros", | ||
| 93 | ] | ||
| 94 | |||
| 95 | [[package]] | ||
| 96 | name = "cortex-m-rt-macros" | ||
| 97 | version = "0.7.5" | ||
| 98 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 99 | checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" | ||
| 100 | dependencies = [ | ||
| 101 | "proc-macro2", | ||
| 102 | "quote", | ||
| 103 | "syn", | ||
| 104 | ] | ||
| 105 | |||
| 106 | [[package]] | ||
| 107 | name = "critical-section" | ||
| 108 | version = "1.2.0" | ||
| 109 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 110 | checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" | ||
| 111 | |||
| 112 | [[package]] | ||
| 113 | name = "defmt" | ||
| 114 | version = "1.0.1" | ||
| 115 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 116 | checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" | ||
| 117 | dependencies = [ | ||
| 118 | "bitflags", | ||
| 119 | "defmt-macros", | ||
| 120 | ] | ||
| 121 | |||
| 122 | [[package]] | ||
| 123 | name = "defmt-macros" | ||
| 124 | version = "1.0.1" | ||
| 125 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 126 | checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" | ||
| 127 | dependencies = [ | ||
| 128 | "defmt-parser", | ||
| 129 | "proc-macro-error2", | ||
| 130 | "proc-macro2", | ||
| 131 | "quote", | ||
| 132 | "syn", | ||
| 133 | ] | ||
| 134 | |||
| 135 | [[package]] | ||
| 136 | name = "defmt-parser" | ||
| 137 | version = "1.0.0" | ||
| 138 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 139 | checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" | ||
| 140 | dependencies = [ | ||
| 141 | "thiserror", | ||
| 142 | ] | ||
| 143 | |||
| 144 | [[package]] | ||
| 145 | name = "document-features" | ||
| 146 | version = "0.2.12" | ||
| 147 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 148 | checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" | ||
| 149 | dependencies = [ | ||
| 150 | "litrs", | ||
| 151 | ] | ||
| 152 | |||
| 153 | [[package]] | ||
| 154 | name = "embassy-embedded-hal" | ||
| 155 | version = "0.5.0" | ||
| 156 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 157 | checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" | ||
| 158 | dependencies = [ | ||
| 159 | "embassy-futures", | ||
| 160 | "embassy-hal-internal", | ||
| 161 | "embassy-sync", | ||
| 162 | "embedded-hal 0.2.7", | ||
| 163 | "embedded-hal 1.0.0", | ||
| 164 | "embedded-hal-async", | ||
| 165 | "embedded-storage", | ||
| 166 | "embedded-storage-async", | ||
| 167 | "nb 1.1.0", | ||
| 168 | ] | ||
| 169 | |||
| 170 | [[package]] | ||
| 171 | name = "embassy-futures" | ||
| 172 | version = "0.1.2" | ||
| 173 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 174 | checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" | ||
| 175 | |||
| 176 | [[package]] | ||
| 177 | name = "embassy-hal-internal" | ||
| 178 | version = "0.3.0" | ||
| 179 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 180 | checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" | ||
| 181 | dependencies = [ | ||
| 182 | "cortex-m", | ||
| 183 | "critical-section", | ||
| 184 | "num-traits", | ||
| 185 | ] | ||
| 186 | |||
| 187 | [[package]] | ||
| 188 | name = "embassy-mcxa" | ||
| 189 | version = "0.1.0" | ||
| 190 | dependencies = [ | ||
| 191 | "cortex-m", | ||
| 192 | "cortex-m-rt", | ||
| 193 | "critical-section", | ||
| 194 | "defmt", | ||
| 195 | "embassy-embedded-hal", | ||
| 196 | "embassy-hal-internal", | ||
| 197 | "embassy-sync", | ||
| 198 | "embassy-time", | ||
| 199 | "embassy-time-driver", | ||
| 200 | "embedded-hal 0.2.7", | ||
| 201 | "embedded-hal 1.0.0", | ||
| 202 | "embedded-hal-async", | ||
| 203 | "embedded-hal-nb", | ||
| 204 | "embedded-io", | ||
| 205 | "embedded-io-async", | ||
| 206 | "heapless", | ||
| 207 | "maitake-sync", | ||
| 208 | "mcxa-pac", | ||
| 209 | "nb 1.1.0", | ||
| 210 | "paste", | ||
| 211 | ] | ||
| 212 | |||
| 213 | [[package]] | ||
| 214 | name = "embassy-sync" | ||
| 215 | version = "0.7.2" | ||
| 216 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 217 | checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" | ||
| 218 | dependencies = [ | ||
| 219 | "cfg-if", | ||
| 220 | "critical-section", | ||
| 221 | "embedded-io-async", | ||
| 222 | "futures-core", | ||
| 223 | "futures-sink", | ||
| 224 | "heapless", | ||
| 225 | ] | ||
| 226 | |||
| 227 | [[package]] | ||
| 228 | name = "embassy-time" | ||
| 229 | version = "0.5.0" | ||
| 230 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 231 | checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" | ||
| 232 | dependencies = [ | ||
| 233 | "cfg-if", | ||
| 234 | "critical-section", | ||
| 235 | "document-features", | ||
| 236 | "embassy-time-driver", | ||
| 237 | "embedded-hal 0.2.7", | ||
| 238 | "embedded-hal 1.0.0", | ||
| 239 | "embedded-hal-async", | ||
| 240 | "futures-core", | ||
| 241 | ] | ||
| 242 | |||
| 243 | [[package]] | ||
| 244 | name = "embassy-time-driver" | ||
| 245 | version = "0.2.1" | ||
| 246 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 247 | checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" | ||
| 248 | dependencies = [ | ||
| 249 | "document-features", | ||
| 250 | ] | ||
| 251 | |||
| 252 | [[package]] | ||
| 253 | name = "embedded-hal" | ||
| 254 | version = "0.2.7" | ||
| 255 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 256 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" | ||
| 257 | dependencies = [ | ||
| 258 | "nb 0.1.3", | ||
| 259 | "void", | ||
| 260 | ] | ||
| 261 | |||
| 262 | [[package]] | ||
| 263 | name = "embedded-hal" | ||
| 264 | version = "1.0.0" | ||
| 265 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 266 | checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" | ||
| 267 | |||
| 268 | [[package]] | ||
| 269 | name = "embedded-hal-async" | ||
| 270 | version = "1.0.0" | ||
| 271 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 272 | checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" | ||
| 273 | dependencies = [ | ||
| 274 | "embedded-hal 1.0.0", | ||
| 275 | ] | ||
| 276 | |||
| 277 | [[package]] | ||
| 278 | name = "embedded-hal-nb" | ||
| 279 | version = "1.0.0" | ||
| 280 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 281 | checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" | ||
| 282 | dependencies = [ | ||
| 283 | "embedded-hal 1.0.0", | ||
| 284 | "nb 1.1.0", | ||
| 285 | ] | ||
| 286 | |||
| 287 | [[package]] | ||
| 288 | name = "embedded-io" | ||
| 289 | version = "0.6.1" | ||
| 290 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 291 | checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" | ||
| 292 | |||
| 293 | [[package]] | ||
| 294 | name = "embedded-io-async" | ||
| 295 | version = "0.6.1" | ||
| 296 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 297 | checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" | ||
| 298 | dependencies = [ | ||
| 299 | "embedded-io", | ||
| 300 | ] | ||
| 301 | |||
| 302 | [[package]] | ||
| 303 | name = "embedded-storage" | ||
| 304 | version = "0.3.1" | ||
| 305 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 306 | checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" | ||
| 307 | |||
| 308 | [[package]] | ||
| 309 | name = "embedded-storage-async" | ||
| 310 | version = "0.4.1" | ||
| 311 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 312 | checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" | ||
| 313 | dependencies = [ | ||
| 314 | "embedded-storage", | ||
| 315 | ] | ||
| 316 | |||
| 317 | [[package]] | ||
| 318 | name = "find-msvc-tools" | ||
| 319 | version = "0.1.5" | ||
| 320 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 321 | checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" | ||
| 322 | |||
| 323 | [[package]] | ||
| 324 | name = "futures-core" | ||
| 325 | version = "0.3.31" | ||
| 326 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 327 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" | ||
| 328 | |||
| 329 | [[package]] | ||
| 330 | name = "futures-sink" | ||
| 331 | version = "0.3.31" | ||
| 332 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 333 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" | ||
| 334 | |||
| 335 | [[package]] | ||
| 336 | name = "generator" | ||
| 337 | version = "0.8.7" | ||
| 338 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 339 | checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" | ||
| 340 | dependencies = [ | ||
| 341 | "cc", | ||
| 342 | "cfg-if", | ||
| 343 | "libc", | ||
| 344 | "log", | ||
| 345 | "rustversion", | ||
| 346 | "windows", | ||
| 347 | ] | ||
| 348 | |||
| 349 | [[package]] | ||
| 350 | name = "hash32" | ||
| 351 | version = "0.3.1" | ||
| 352 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 353 | checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" | ||
| 354 | dependencies = [ | ||
| 355 | "byteorder", | ||
| 356 | ] | ||
| 357 | |||
| 358 | [[package]] | ||
| 359 | name = "heapless" | ||
| 360 | version = "0.8.0" | ||
| 361 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 362 | checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" | ||
| 363 | dependencies = [ | ||
| 364 | "hash32", | ||
| 365 | "stable_deref_trait", | ||
| 366 | ] | ||
| 367 | |||
| 368 | [[package]] | ||
| 369 | name = "lazy_static" | ||
| 370 | version = "1.5.0" | ||
| 371 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 372 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" | ||
| 373 | |||
| 374 | [[package]] | ||
| 375 | name = "libc" | ||
| 376 | version = "0.2.177" | ||
| 377 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 378 | checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" | ||
| 379 | |||
| 380 | [[package]] | ||
| 381 | name = "litrs" | ||
| 382 | version = "1.0.0" | ||
| 383 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 384 | checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" | ||
| 385 | |||
| 386 | [[package]] | ||
| 387 | name = "log" | ||
| 388 | version = "0.4.28" | ||
| 389 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 390 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" | ||
| 391 | |||
| 392 | [[package]] | ||
| 393 | name = "loom" | ||
| 394 | version = "0.7.2" | ||
| 395 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 396 | checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" | ||
| 397 | dependencies = [ | ||
| 398 | "cfg-if", | ||
| 399 | "generator", | ||
| 400 | "scoped-tls", | ||
| 401 | "tracing", | ||
| 402 | "tracing-subscriber", | ||
| 403 | ] | ||
| 404 | |||
| 405 | [[package]] | ||
| 406 | name = "maitake-sync" | ||
| 407 | version = "0.2.2" | ||
| 408 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 409 | checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" | ||
| 410 | dependencies = [ | ||
| 411 | "cordyceps", | ||
| 412 | "critical-section", | ||
| 413 | "loom", | ||
| 414 | "mutex-traits", | ||
| 415 | "mycelium-bitfield", | ||
| 416 | "pin-project", | ||
| 417 | "portable-atomic", | ||
| 418 | "tracing", | ||
| 419 | ] | ||
| 420 | |||
| 421 | [[package]] | ||
| 422 | name = "matchers" | ||
| 423 | version = "0.2.0" | ||
| 424 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 425 | checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" | ||
| 426 | dependencies = [ | ||
| 427 | "regex-automata", | ||
| 428 | ] | ||
| 429 | |||
| 430 | [[package]] | ||
| 431 | name = "mcxa-pac" | ||
| 432 | version = "0.1.0" | ||
| 433 | source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca" | ||
| 434 | dependencies = [ | ||
| 435 | "cortex-m", | ||
| 436 | "cortex-m-rt", | ||
| 437 | "critical-section", | ||
| 438 | "defmt", | ||
| 439 | "vcell", | ||
| 440 | ] | ||
| 441 | |||
| 442 | [[package]] | ||
| 443 | name = "memchr" | ||
| 444 | version = "2.7.6" | ||
| 445 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 446 | checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" | ||
| 447 | |||
| 448 | [[package]] | ||
| 449 | name = "mutex-traits" | ||
| 450 | version = "1.0.1" | ||
| 451 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 452 | checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" | ||
| 453 | |||
| 454 | [[package]] | ||
| 455 | name = "mycelium-bitfield" | ||
| 456 | version = "0.1.5" | ||
| 457 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 458 | checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc" | ||
| 459 | |||
| 460 | [[package]] | ||
| 461 | name = "nb" | ||
| 462 | version = "0.1.3" | ||
| 463 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 464 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" | ||
| 465 | dependencies = [ | ||
| 466 | "nb 1.1.0", | ||
| 467 | ] | ||
| 468 | |||
| 469 | [[package]] | ||
| 470 | name = "nb" | ||
| 471 | version = "1.1.0" | ||
| 472 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 473 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" | ||
| 474 | |||
| 475 | [[package]] | ||
| 476 | name = "nu-ansi-term" | ||
| 477 | version = "0.50.3" | ||
| 478 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 479 | checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" | ||
| 480 | dependencies = [ | ||
| 481 | "windows-sys", | ||
| 482 | ] | ||
| 483 | |||
| 484 | [[package]] | ||
| 485 | name = "num-traits" | ||
| 486 | version = "0.2.19" | ||
| 487 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 488 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" | ||
| 489 | dependencies = [ | ||
| 490 | "autocfg", | ||
| 491 | ] | ||
| 492 | |||
| 493 | [[package]] | ||
| 494 | name = "once_cell" | ||
| 495 | version = "1.21.3" | ||
| 496 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 497 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" | ||
| 498 | |||
| 499 | [[package]] | ||
| 500 | name = "paste" | ||
| 501 | version = "1.0.15" | ||
| 502 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 503 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" | ||
| 504 | |||
| 505 | [[package]] | ||
| 506 | name = "pin-project" | ||
| 507 | version = "1.1.10" | ||
| 508 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 509 | checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" | ||
| 510 | dependencies = [ | ||
| 511 | "pin-project-internal", | ||
| 512 | ] | ||
| 513 | |||
| 514 | [[package]] | ||
| 515 | name = "pin-project-internal" | ||
| 516 | version = "1.1.10" | ||
| 517 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 518 | checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" | ||
| 519 | dependencies = [ | ||
| 520 | "proc-macro2", | ||
| 521 | "quote", | ||
| 522 | "syn", | ||
| 523 | ] | ||
| 524 | |||
| 525 | [[package]] | ||
| 526 | name = "pin-project-lite" | ||
| 527 | version = "0.2.16" | ||
| 528 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 529 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" | ||
| 530 | |||
| 531 | [[package]] | ||
| 532 | name = "portable-atomic" | ||
| 533 | version = "1.11.1" | ||
| 534 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 535 | checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" | ||
| 536 | dependencies = [ | ||
| 537 | "critical-section", | ||
| 538 | ] | ||
| 539 | |||
| 540 | [[package]] | ||
| 541 | name = "proc-macro-error-attr2" | ||
| 542 | version = "2.0.0" | ||
| 543 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 544 | checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" | ||
| 545 | dependencies = [ | ||
| 546 | "proc-macro2", | ||
| 547 | "quote", | ||
| 548 | ] | ||
| 549 | |||
| 550 | [[package]] | ||
| 551 | name = "proc-macro-error2" | ||
| 552 | version = "2.0.1" | ||
| 553 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 554 | checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" | ||
| 555 | dependencies = [ | ||
| 556 | "proc-macro-error-attr2", | ||
| 557 | "proc-macro2", | ||
| 558 | "quote", | ||
| 559 | "syn", | ||
| 560 | ] | ||
| 561 | |||
| 562 | [[package]] | ||
| 563 | name = "proc-macro2" | ||
| 564 | version = "1.0.103" | ||
| 565 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 566 | checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" | ||
| 567 | dependencies = [ | ||
| 568 | "unicode-ident", | ||
| 569 | ] | ||
| 570 | |||
| 571 | [[package]] | ||
| 572 | name = "quote" | ||
| 573 | version = "1.0.42" | ||
| 574 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 575 | checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" | ||
| 576 | dependencies = [ | ||
| 577 | "proc-macro2", | ||
| 578 | ] | ||
| 579 | |||
| 580 | [[package]] | ||
| 581 | name = "regex-automata" | ||
| 582 | version = "0.4.13" | ||
| 583 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 584 | checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" | ||
| 585 | dependencies = [ | ||
| 586 | "aho-corasick", | ||
| 587 | "memchr", | ||
| 588 | "regex-syntax", | ||
| 589 | ] | ||
| 590 | |||
| 591 | [[package]] | ||
| 592 | name = "regex-syntax" | ||
| 593 | version = "0.8.8" | ||
| 594 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 595 | checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" | ||
| 596 | |||
| 597 | [[package]] | ||
| 598 | name = "rustc_version" | ||
| 599 | version = "0.2.3" | ||
| 600 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 601 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" | ||
| 602 | dependencies = [ | ||
| 603 | "semver", | ||
| 604 | ] | ||
| 605 | |||
| 606 | [[package]] | ||
| 607 | name = "rustversion" | ||
| 608 | version = "1.0.22" | ||
| 609 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 610 | checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" | ||
| 611 | |||
| 612 | [[package]] | ||
| 613 | name = "scoped-tls" | ||
| 614 | version = "1.0.1" | ||
| 615 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 616 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" | ||
| 617 | |||
| 618 | [[package]] | ||
| 619 | name = "semver" | ||
| 620 | version = "0.9.0" | ||
| 621 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 622 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" | ||
| 623 | dependencies = [ | ||
| 624 | "semver-parser", | ||
| 625 | ] | ||
| 626 | |||
| 627 | [[package]] | ||
| 628 | name = "semver-parser" | ||
| 629 | version = "0.7.0" | ||
| 630 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 631 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" | ||
| 632 | |||
| 633 | [[package]] | ||
| 634 | name = "sharded-slab" | ||
| 635 | version = "0.1.7" | ||
| 636 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 637 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" | ||
| 638 | dependencies = [ | ||
| 639 | "lazy_static", | ||
| 640 | ] | ||
| 641 | |||
| 642 | [[package]] | ||
| 643 | name = "shlex" | ||
| 644 | version = "1.3.0" | ||
| 645 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 646 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" | ||
| 647 | |||
| 648 | [[package]] | ||
| 649 | name = "smallvec" | ||
| 650 | version = "1.15.1" | ||
| 651 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 652 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" | ||
| 653 | |||
| 654 | [[package]] | ||
| 655 | name = "stable_deref_trait" | ||
| 656 | version = "1.2.1" | ||
| 657 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 658 | checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" | ||
| 659 | |||
| 660 | [[package]] | ||
| 661 | name = "syn" | ||
| 662 | version = "2.0.110" | ||
| 663 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 664 | checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" | ||
| 665 | dependencies = [ | ||
| 666 | "proc-macro2", | ||
| 667 | "quote", | ||
| 668 | "unicode-ident", | ||
| 669 | ] | ||
| 670 | |||
| 671 | [[package]] | ||
| 672 | name = "thiserror" | ||
| 673 | version = "2.0.17" | ||
| 674 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 675 | checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" | ||
| 676 | dependencies = [ | ||
| 677 | "thiserror-impl", | ||
| 678 | ] | ||
| 679 | |||
| 680 | [[package]] | ||
| 681 | name = "thiserror-impl" | ||
| 682 | version = "2.0.17" | ||
| 683 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 684 | checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" | ||
| 685 | dependencies = [ | ||
| 686 | "proc-macro2", | ||
| 687 | "quote", | ||
| 688 | "syn", | ||
| 689 | ] | ||
| 690 | |||
| 691 | [[package]] | ||
| 692 | name = "thread_local" | ||
| 693 | version = "1.1.9" | ||
| 694 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 695 | checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" | ||
| 696 | dependencies = [ | ||
| 697 | "cfg-if", | ||
| 698 | ] | ||
| 699 | |||
| 700 | [[package]] | ||
| 701 | name = "tracing" | ||
| 702 | version = "0.1.41" | ||
| 703 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 704 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" | ||
| 705 | dependencies = [ | ||
| 706 | "pin-project-lite", | ||
| 707 | "tracing-attributes", | ||
| 708 | "tracing-core", | ||
| 709 | ] | ||
| 710 | |||
| 711 | [[package]] | ||
| 712 | name = "tracing-attributes" | ||
| 713 | version = "0.1.30" | ||
| 714 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 715 | checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" | ||
| 716 | dependencies = [ | ||
| 717 | "proc-macro2", | ||
| 718 | "quote", | ||
| 719 | "syn", | ||
| 720 | ] | ||
| 721 | |||
| 722 | [[package]] | ||
| 723 | name = "tracing-core" | ||
| 724 | version = "0.1.34" | ||
| 725 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 726 | checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" | ||
| 727 | dependencies = [ | ||
| 728 | "once_cell", | ||
| 729 | "valuable", | ||
| 730 | ] | ||
| 731 | |||
| 732 | [[package]] | ||
| 733 | name = "tracing-log" | ||
| 734 | version = "0.2.0" | ||
| 735 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 736 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" | ||
| 737 | dependencies = [ | ||
| 738 | "log", | ||
| 739 | "once_cell", | ||
| 740 | "tracing-core", | ||
| 741 | ] | ||
| 742 | |||
| 743 | [[package]] | ||
| 744 | name = "tracing-subscriber" | ||
| 745 | version = "0.3.20" | ||
| 746 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 747 | checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" | ||
| 748 | dependencies = [ | ||
| 749 | "matchers", | ||
| 750 | "nu-ansi-term", | ||
| 751 | "once_cell", | ||
| 752 | "regex-automata", | ||
| 753 | "sharded-slab", | ||
| 754 | "smallvec", | ||
| 755 | "thread_local", | ||
| 756 | "tracing", | ||
| 757 | "tracing-core", | ||
| 758 | "tracing-log", | ||
| 759 | ] | ||
| 760 | |||
| 761 | [[package]] | ||
| 762 | name = "unicode-ident" | ||
| 763 | version = "1.0.22" | ||
| 764 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 765 | checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" | ||
| 766 | |||
| 767 | [[package]] | ||
| 768 | name = "valuable" | ||
| 769 | version = "0.1.1" | ||
| 770 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 771 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" | ||
| 772 | |||
| 773 | [[package]] | ||
| 774 | name = "vcell" | ||
| 775 | version = "0.1.3" | ||
| 776 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 777 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" | ||
| 778 | |||
| 779 | [[package]] | ||
| 780 | name = "void" | ||
| 781 | version = "1.0.2" | ||
| 782 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 783 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" | ||
| 784 | |||
| 785 | [[package]] | ||
| 786 | name = "volatile-register" | ||
| 787 | version = "0.2.2" | ||
| 788 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 789 | checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" | ||
| 790 | dependencies = [ | ||
| 791 | "vcell", | ||
| 792 | ] | ||
| 793 | |||
| 794 | [[package]] | ||
| 795 | name = "windows" | ||
| 796 | version = "0.61.3" | ||
| 797 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 798 | checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" | ||
| 799 | dependencies = [ | ||
| 800 | "windows-collections", | ||
| 801 | "windows-core", | ||
| 802 | "windows-future", | ||
| 803 | "windows-link 0.1.3", | ||
| 804 | "windows-numerics", | ||
| 805 | ] | ||
| 806 | |||
| 807 | [[package]] | ||
| 808 | name = "windows-collections" | ||
| 809 | version = "0.2.0" | ||
| 810 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 811 | checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" | ||
| 812 | dependencies = [ | ||
| 813 | "windows-core", | ||
| 814 | ] | ||
| 815 | |||
| 816 | [[package]] | ||
| 817 | name = "windows-core" | ||
| 818 | version = "0.61.2" | ||
| 819 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 820 | checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" | ||
| 821 | dependencies = [ | ||
| 822 | "windows-implement", | ||
| 823 | "windows-interface", | ||
| 824 | "windows-link 0.1.3", | ||
| 825 | "windows-result", | ||
| 826 | "windows-strings", | ||
| 827 | ] | ||
| 828 | |||
| 829 | [[package]] | ||
| 830 | name = "windows-future" | ||
| 831 | version = "0.2.1" | ||
| 832 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 833 | checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" | ||
| 834 | dependencies = [ | ||
| 835 | "windows-core", | ||
| 836 | "windows-link 0.1.3", | ||
| 837 | "windows-threading", | ||
| 838 | ] | ||
| 839 | |||
| 840 | [[package]] | ||
| 841 | name = "windows-implement" | ||
| 842 | version = "0.60.2" | ||
| 843 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 844 | checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" | ||
| 845 | dependencies = [ | ||
| 846 | "proc-macro2", | ||
| 847 | "quote", | ||
| 848 | "syn", | ||
| 849 | ] | ||
| 850 | |||
| 851 | [[package]] | ||
| 852 | name = "windows-interface" | ||
| 853 | version = "0.59.3" | ||
| 854 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 855 | checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" | ||
| 856 | dependencies = [ | ||
| 857 | "proc-macro2", | ||
| 858 | "quote", | ||
| 859 | "syn", | ||
| 860 | ] | ||
| 861 | |||
| 862 | [[package]] | ||
| 863 | name = "windows-link" | ||
| 864 | version = "0.1.3" | ||
| 865 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 866 | checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" | ||
| 867 | |||
| 868 | [[package]] | ||
| 869 | name = "windows-link" | ||
| 870 | version = "0.2.1" | ||
| 871 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 872 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" | ||
| 873 | |||
| 874 | [[package]] | ||
| 875 | name = "windows-numerics" | ||
| 876 | version = "0.2.0" | ||
| 877 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 878 | checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" | ||
| 879 | dependencies = [ | ||
| 880 | "windows-core", | ||
| 881 | "windows-link 0.1.3", | ||
| 882 | ] | ||
| 883 | |||
| 884 | [[package]] | ||
| 885 | name = "windows-result" | ||
| 886 | version = "0.3.4" | ||
| 887 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 888 | checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" | ||
| 889 | dependencies = [ | ||
| 890 | "windows-link 0.1.3", | ||
| 891 | ] | ||
| 892 | |||
| 893 | [[package]] | ||
| 894 | name = "windows-strings" | ||
| 895 | version = "0.4.2" | ||
| 896 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 897 | checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" | ||
| 898 | dependencies = [ | ||
| 899 | "windows-link 0.1.3", | ||
| 900 | ] | ||
| 901 | |||
| 902 | [[package]] | ||
| 903 | name = "windows-sys" | ||
| 904 | version = "0.61.2" | ||
| 905 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 906 | checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" | ||
| 907 | dependencies = [ | ||
| 908 | "windows-link 0.2.1", | ||
| 909 | ] | ||
| 910 | |||
| 911 | [[package]] | ||
| 912 | name = "windows-threading" | ||
| 913 | version = "0.1.0" | ||
| 914 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 915 | checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" | ||
| 916 | dependencies = [ | ||
| 917 | "windows-link 0.1.3", | ||
| 918 | ] | ||
diff --git a/embassy-mcxa/Cargo.toml b/embassy-mcxa/Cargo.toml new file mode 100644 index 000000000..22660bee9 --- /dev/null +++ b/embassy-mcxa/Cargo.toml | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-mcxa" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | description = "Embassy Hardware Abstraction Layer (HAL) for NXP MCXA series of MCUs" | ||
| 7 | keywords = ["embedded", "hal", "nxp", "mcxa", "embassy"] | ||
| 8 | categories = ["embedded", "hardware-support", "no-std"] | ||
| 9 | |||
| 10 | [dependencies] | ||
| 11 | cortex-m = { version = "0.7", features = ["critical-section-single-core"] } | ||
| 12 | # If you would like "device" to be an optional feature, please open an issue. | ||
| 13 | cortex-m-rt = { version = "0.7", features = ["device"] } | ||
| 14 | critical-section = "1.2.0" | ||
| 15 | defmt = { version = "1.0", optional = true } | ||
| 16 | embassy-embedded-hal = "0.5.0" | ||
| 17 | embassy-hal-internal = { version = "0.3.0", features = ["cortex-m", "prio-bits-3"] } | ||
| 18 | embassy-sync = "0.7.2" | ||
| 19 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||
| 20 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | ||
| 21 | embedded-hal-async = { version = "1.0" } | ||
| 22 | embedded-hal-nb = { version = "1.0" } | ||
| 23 | embedded-io = "0.6" | ||
| 24 | embedded-io-async = { version = "0.6.1" } | ||
| 25 | heapless = "0.8" | ||
| 26 | mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0" } | ||
| 27 | nb = "1.1.0" | ||
| 28 | paste = "1.0.15" | ||
| 29 | maitake-sync = { version = "0.2.2", default-features = false, features = ["critical-section", "no-cache-pad"] } | ||
| 30 | |||
| 31 | # `time` dependencies | ||
| 32 | embassy-time = { version = "0.5.0", optional = true } | ||
| 33 | embassy-time-driver = { version = "0.2.1", optional = true } | ||
| 34 | |||
| 35 | [features] | ||
| 36 | default = ["rt"] | ||
| 37 | |||
| 38 | # Base defmt feature enables core + panic handler | ||
| 39 | # Use with one logger feature: defmt-rtt (preferred) or defmt-uart (fallback) | ||
| 40 | defmt = ["dep:defmt", "mcxa-pac/defmt"] | ||
| 41 | |||
| 42 | unstable-pac = [] | ||
| 43 | |||
| 44 | # dummy feature to silence embassy-hal-internal lint | ||
| 45 | # | ||
| 46 | # This feature makes no change to embassy-mcxa's operation. | ||
| 47 | rt = [] | ||
| 48 | |||
| 49 | # Embassy time | ||
| 50 | time = [ | ||
| 51 | "dep:embassy-time", | ||
| 52 | "dep:embassy-time-driver", | ||
| 53 | ] | ||
diff --git a/embassy-mcxa/Embed.toml b/embassy-mcxa/Embed.toml new file mode 100644 index 000000000..40218c8bf --- /dev/null +++ b/embassy-mcxa/Embed.toml | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | [default.probe] | ||
| 2 | # Use the first available probe | ||
| 3 | protocol = "Swd" | ||
| 4 | speed = 1000 | ||
| 5 | |||
| 6 | [default.flashing] | ||
| 7 | # Attach-only: don't flash (we already loaded to RAM) | ||
| 8 | enabled = false | ||
| 9 | |||
| 10 | [default.reset] | ||
| 11 | # Don't reset; keep running app started by run_jlink_noblock.sh | ||
| 12 | enabled = false | ||
| 13 | |||
| 14 | [default.general] | ||
| 15 | # The chip name of the target | ||
| 16 | chip = "MCXA276" | ||
| 17 | |||
| 18 | [default.gdb] | ||
| 19 | # Whether or not a GDB server should be opened after loading | ||
| 20 | enabled = false | ||
| 21 | |||
| 22 | [default.rtt] | ||
| 23 | # Enable RTT for debugging output | ||
| 24 | enabled = true | ||
| 25 | |||
| 26 | # Increase timeout for RTT CB discovery | ||
| 27 | up_channels = [ { channel = 0, mode = "BlockIfFull" } ] | ||
| 28 | timeout = 5000 | ||
diff --git a/embassy-mcxa/LICENSE b/embassy-mcxa/LICENSE new file mode 100644 index 000000000..609bd42da --- /dev/null +++ b/embassy-mcxa/LICENSE | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | MIT License | ||
| 2 | |||
| 3 | Copyright (c) 2025 Open Device Partnership | ||
| 4 | |||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | of this software and associated documentation files (the "Software"), to deal | ||
| 7 | in the Software without restriction, including without limitation the rights | ||
| 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | copies of the Software, and to permit persons to whom the Software is | ||
| 10 | furnished to do so, subject to the following conditions: | ||
| 11 | |||
| 12 | The above copyright notice and this permission notice shall be included in all | ||
| 13 | copies or substantial portions of the Software. | ||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | SOFTWARE. | ||
diff --git a/embassy-mcxa/README.md b/embassy-mcxa/README.md new file mode 100644 index 000000000..6e7d61c0e --- /dev/null +++ b/embassy-mcxa/README.md | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | # Embassy MCXA256 HAL | ||
| 2 | |||
| 3 | [](https://github.com/OpenDevicePartnership/embassy-mcxa/actions/workflows/check.yml) | ||
| 4 | [](https://github.com/OpenDevicePartnership/embassy-mcxa/actions/workflows/nostd.yml) | ||
| 5 | [](https://github.com/OpenDevicePartnership/embassy-mcxa/actions/workflows/rolling.yml) | ||
| 6 | |||
| 7 | A Hardware Abstraction Layer (HAL) for the NXP MCXA256 microcontroller | ||
| 8 | using the Embassy async framework. This HAL provides safe, idiomatic | ||
| 9 | Rust interfaces for GPIO, UART, and OSTIMER peripherals. | ||
| 10 | |||
| 11 | ## License | ||
| 12 | |||
| 13 | This project is licensed under MIT OR Apache-2.0. | ||
diff --git a/embassy-mcxa/SECURITY.md b/embassy-mcxa/SECURITY.md new file mode 100644 index 000000000..5357b8824 --- /dev/null +++ b/embassy-mcxa/SECURITY.md | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | # Vulnerability Disclosure and Embargo Policy | ||
| 2 | |||
| 3 | The Open Device Partnership project welcomes the responsible disclosure of vulnerabilities. | ||
| 4 | |||
| 5 | ## Initial Contact | ||
| 6 | |||
| 7 | All security bugs in Open Device Partnership should be reported to the security team. | ||
| 8 | To do so, please reach out in the form of a | ||
| 9 | [Github Security Advisory](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities). | ||
| 10 | |||
| 11 | You will be invited to join this private area to discuss specifics. Doing so | ||
| 12 | allows us to start with a high level of confidentiality and relax it if the | ||
| 13 | issue is less critical, moving to work on the fix in the open. | ||
| 14 | |||
| 15 | Your initial contact will be acknowledged within 48 hours, and you’ll receive | ||
| 16 | a more detailed response within 96 hours indicating the next steps in handling | ||
| 17 | your report. | ||
| 18 | |||
| 19 | After the initial reply to your report, the security team will endeavor to | ||
| 20 | keep you informed of the progress being made towards a fix and full | ||
| 21 | announcement. As recommended by | ||
| 22 | [RFPolicy](https://dl.packetstormsecurity.net/papers/general/rfpolicy-2.0.txt), | ||
| 23 | these updates will be sent at least every five working days. | ||
| 24 | |||
| 25 | ## Disclosure Policy | ||
| 26 | |||
| 27 | The Open Device Partnership project has a 5 step disclosure process. | ||
| 28 | |||
| 29 | 1. Contact is established, a private channel created, and the security report | ||
| 30 | is received and is assigned a primary handler. This person will coordinate | ||
| 31 | the fix and release process. | ||
| 32 | 2. The problem is confirmed and a list of all affected versions is determined. | ||
| 33 | If an embargo is needed (see below), details of the embargo are decided. | ||
| 34 | 3. Code is audited to find any potential similar problems. | ||
| 35 | 4. Fixes are prepared for all releases which are still under maintenance. In | ||
| 36 | case of embargo, these fixes are not committed to the public repository but | ||
| 37 | rather held in a private fork pending the announcement. | ||
| 38 | 5. The changes are pushed to the public repository and new builds are deployed. | ||
| 39 | |||
| 40 | This process can take some time, especially when coordination is required | ||
| 41 | with maintainers of other projects. Every effort will be made to handle the bug | ||
| 42 | in as timely a manner as possible, however it is important that we follow the | ||
| 43 | release process above to ensure that the disclosure is handled in a consistent | ||
| 44 | manner. | ||
| 45 | |||
| 46 | ## Embargoes | ||
| 47 | |||
| 48 | While the Open Device Partnership project aims to follow the highest standards of | ||
| 49 | transparency and openness, handling some security issues may pose such an | ||
| 50 | immediate threat to various stakeholders and require coordination between | ||
| 51 | various actors that it cannot be made immediately public. | ||
| 52 | |||
| 53 | In this case, security issues will fall under an embargo. | ||
| 54 | |||
| 55 | An embargo can be called for in various cases: | ||
| 56 | |||
| 57 | - when disclosing the issue without simultaneously providing a mitigation | ||
| 58 | would seriously endanger users, | ||
| 59 | - when producing a fix requires coordinating between multiple actors (such as | ||
| 60 | upstream or downstream/dependency projects), or simply | ||
| 61 | - when proper analysis of the issue and its ramifications demands time. | ||
| 62 | |||
| 63 | If we determine that an issue you report requires an embargo, we will discuss | ||
| 64 | this with you and try to find a reasonable expiry date (aka “embargo | ||
| 65 | completion date”), as well as who should be included in the list of | ||
| 66 | need-to-know people. | ||
diff --git a/embassy-mcxa/SW-Content-Register.txt b/embassy-mcxa/SW-Content-Register.txt new file mode 100644 index 000000000..09f879c2f --- /dev/null +++ b/embassy-mcxa/SW-Content-Register.txt | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | Release Name: Embassy MCXA276 HAL | ||
| 2 | Release Version: 0.1.0 | ||
| 3 | Package License: MIT (see ./License.txt) | ||
| 4 | Note: The crate is dual-licensed “MIT OR Apache-2.0” per Cargo.toml; choosing MIT satisfies the dual-license terms. | ||
| 5 | |||
| 6 | Scope of this Register | ||
| 7 | This file documents software content that is part of this repository and, for transparency, lists major non-vendored Rust dependencies that are resolved from crates.io during builds. Components that are not present in the repository (e.g., external crates) are listed under “Non‑vendored Rust dependencies”. | ||
| 8 | |||
| 9 | Repository Components (included in this release) | ||
| 10 | |||
| 11 | embassy_mcxa276_hal Name: Embassy MCXA276 HAL (library + examples) | ||
| 12 | Version: 0.1.0 | ||
| 13 | Outgoing License: MIT | ||
| 14 | License File: ./License.txt | ||
| 15 | Format: Rust source code, examples, scripts, linker scripts | ||
| 16 | Description: Hardware Abstraction Layer for NXP MCXA276 using the Embassy async framework. Implements drivers and helpers for: | ||
| 17 | - LPUART2 (UART), OSTIMER0, RTC0, ADC1, GPIO | ||
| 18 | - Embassy integration (executors, time) | ||
| 19 | Location: ./src, ./examples, ./build.rs, ./memory.x, ./ram.ld, ./defmt.x, ./.cargo/config.toml, ./run.sh, ./tools/ | ||
| 20 | Origin: OEMWCSE (MIT) | ||
| 21 | URL: https://bitbucket.sw.nxp.com/scm/oemwcse/mcxa_rust.git | ||
| 22 | |||
| 23 | mcxa276_pac Name: MCXA276 Peripheral Access Crate (PAC) | ||
| 24 | Version: 0.1.0 | ||
| 25 | Outgoing License: MIT OR Apache-2.0 | ||
| 26 | License File: (see crate metadata) | ||
| 27 | Format: Rust source code (auto-generated PAC) | ||
| 28 | Description: Auto-generated register mappings for MCXA276 peripherals (svd2rust). Includes device.x and interrupt vectors. | ||
| 29 | Location: External (git): https://github.com/bogdan-petru/mcxa-pac (pinned rev a9dd3301) | ||
| 30 | Origin: Generated by svdtools + svd2rust from NXP SVD 25.06.00 | ||
| 31 | URL: N/A (generated from NXP SVD) | ||
| 32 | |||
| 33 | examples Name: Example applications | ||
| 34 | Version: N/A | ||
| 35 | Outgoing License: MIT | ||
| 36 | License File: ./License.txt | ||
| 37 | Format: Rust source code (examples) | ||
| 38 | Description: Demonstrations for HAL peripherals and features: | ||
| 39 | - hello, blink | ||
| 40 | - lpuart_polling, lpuart_buffered, uart_interrupt | ||
| 41 | - rtc_alarm | ||
| 42 | - adc_polling, adc_interrupt | ||
| 43 | - ostimer_alarm, ostimer_async, ostimer_counter, ostimer_race_test | ||
| 44 | Location: ./examples | ||
| 45 | Origin: OEMWCSE (MIT) | ||
| 46 | |||
| 47 | Non‑vendored Rust dependencies (resolved from crates.io at build time) | ||
| 48 | The following crates are not vendored in this repository. They are fetched during builds via Cargo. See Cargo.lock for exact versions. License summaries below are for convenience; consult each crate for authoritative terms. | ||
| 49 | |||
| 50 | cortex-m License: MIT OR Apache-2.0 Purpose: Cortex-M core support | ||
| 51 | cortex-m-rt License: MIT OR Apache-2.0 Purpose: Cortex-M runtime (vectors, reset) | ||
| 52 | embassy-executor License: MIT OR Apache-2.0 Purpose: Async executor for Cortex-M | ||
| 53 | embassy-time (+ driver) License: MIT OR Apache-2.0 Purpose: Time abstraction and drivers | ||
| 54 | embassy-sync License: MIT OR Apache-2.0 Purpose: No-std synchronization primitives | ||
| 55 | embassy-embedded-hal License: MIT OR Apache-2.0 Purpose: Traits/adapters for embedded-hal | ||
| 56 | embassy-hal-internal License: MIT OR Apache-2.0 Purpose: HAL building blocks (peripherals!) | ||
| 57 | embedded-hal (1.0) License: MIT OR Apache-2.0 Purpose: Core embedded hardware traits | ||
| 58 | embedded-hal (0.2.6) License: MIT OR Apache-2.0 Purpose: Legacy HAL traits ("unproven") | ||
| 59 | embedded-hal-async License: MIT OR Apache-2.0 Purpose: Async HAL traits | ||
| 60 | embedded-hal-nb License: MIT OR Apache-2.0 Purpose: Non-blocking HAL traits | ||
| 61 | embedded-io / embedded-io-async License: MIT OR Apache-2.0 Purpose: IO traits | ||
| 62 | critical-section License: MIT OR Apache-2.0 Purpose: Critical-section abstraction | ||
| 63 | heapless License: MIT OR Apache-2.0 Purpose: Fixed-capacity data structures | ||
| 64 | paste License: MIT OR Apache-2.0 Purpose: Macro hygiene utility | ||
| 65 | nb License: MIT OR Apache-2.0 Purpose: Non-blocking result type | ||
| 66 | vcell License: MIT OR Apache-2.0 Purpose: Volatile cell (PAC dependency) | ||
| 67 | |||
| 68 | defmt, defmt-rtt, rtt-target, panic-probe License: MIT OR Apache-2.0 Purpose: Optional (feature-gated) logging/panic crates | ||
| 69 | |||
| 70 | Attribution notes | ||
| 71 | - MCXA276 PAC is sourced as an external dependency (see Cargo.toml). SVD 25.06.00 already includes OS_EVENT and WAKETIMER0 interrupts (no local fixes). | ||
| 72 | - Examples run from RAM using custom linker setup; see README.txt for platform-specific instructions. | ||
| 73 | |||
| 74 | Compliance | ||
| 75 | - This repository’s distributed source is covered by MIT (see License.txt). Where crates are pulled from crates.io, those crates retain their own licenses; the dual-license compatibility (MIT OR Apache-2.0) is standard in the Rust embedded ecosystem and is compatible with this project’s selected MIT distribution. | ||
| 76 | |||
| 77 | |||
| 78 | |||
diff --git a/embassy-mcxa/defmt.x b/embassy-mcxa/defmt.x new file mode 100644 index 000000000..dbd6d0850 --- /dev/null +++ b/embassy-mcxa/defmt.x | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | /* | ||
| 2 | Dummy defmt.x to satisfy -Tdefmt.x when building without the `defmt` feature. | ||
| 3 | When `defmt` is enabled, the real defmt.x provided by the defmt crate is used via the linker search path. | ||
| 4 | This file intentionally contains no SECTIONS so it won't override ram.ld. | ||
| 5 | */ | ||
| 6 | |||
diff --git a/embassy-mcxa/deny.toml b/embassy-mcxa/deny.toml new file mode 100644 index 000000000..7097f2f55 --- /dev/null +++ b/embassy-mcxa/deny.toml | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | # This template contains all of the possible sections and their default values | ||
| 2 | |||
| 3 | # Note that all fields that take a lint level have these possible values: | ||
| 4 | # * deny - An error will be produced and the check will fail | ||
| 5 | # * warn - A warning will be produced, but the check will not fail | ||
| 6 | # * allow - No warning or error will be produced, though in some cases a note | ||
| 7 | # will be | ||
| 8 | |||
| 9 | # The values provided in this template are the default values that will be used | ||
| 10 | # when any section or field is not specified in your own configuration | ||
| 11 | |||
| 12 | # Root options | ||
| 13 | |||
| 14 | # The graph table configures how the dependency graph is constructed and thus | ||
| 15 | # which crates the checks are performed against | ||
| 16 | [graph] | ||
| 17 | # If 1 or more target triples (and optionally, target_features) are specified, | ||
| 18 | # only the specified targets will be checked when running `cargo deny check`. | ||
| 19 | # This means, if a particular package is only ever used as a target specific | ||
| 20 | # dependency, such as, for example, the `nix` crate only being used via the | ||
| 21 | # `target_family = "unix"` configuration, that only having windows targets in | ||
| 22 | # this list would mean the nix crate, as well as any of its exclusive | ||
| 23 | # dependencies not shared by any other crates, would be ignored, as the target | ||
| 24 | # list here is effectively saying which targets you are building for. | ||
| 25 | targets = [ | ||
| 26 | # The triple can be any string, but only the target triples built in to | ||
| 27 | # rustc (as of 1.40) can be checked against actual config expressions | ||
| 28 | #"x86_64-unknown-linux-musl", | ||
| 29 | # You can also specify which target_features you promise are enabled for a | ||
| 30 | # particular target. target_features are currently not validated against | ||
| 31 | # the actual valid features supported by the target architecture. | ||
| 32 | #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, | ||
| 33 | ] | ||
| 34 | # When creating the dependency graph used as the source of truth when checks are | ||
| 35 | # executed, this field can be used to prune crates from the graph, removing them | ||
| 36 | # from the view of cargo-deny. This is an extremely heavy hammer, as if a crate | ||
| 37 | # is pruned from the graph, all of its dependencies will also be pruned unless | ||
| 38 | # they are connected to another crate in the graph that hasn't been pruned, | ||
| 39 | # so it should be used with care. The identifiers are [Package ID Specifications] | ||
| 40 | # (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) | ||
| 41 | #exclude = [] | ||
| 42 | # If true, metadata will be collected with `--all-features`. Note that this can't | ||
| 43 | # be toggled off if true, if you want to conditionally enable `--all-features` it | ||
| 44 | # is recommended to pass `--all-features` on the cmd line instead | ||
| 45 | all-features = false | ||
| 46 | # If true, metadata will be collected with `--no-default-features`. The same | ||
| 47 | # caveat with `all-features` applies | ||
| 48 | no-default-features = false | ||
| 49 | # If set, these feature will be enabled when collecting metadata. If `--features` | ||
| 50 | # is specified on the cmd line they will take precedence over this option. | ||
| 51 | #features = [] | ||
| 52 | |||
| 53 | # The output table provides options for how/if diagnostics are outputted | ||
| 54 | [output] | ||
| 55 | # When outputting inclusion graphs in diagnostics that include features, this | ||
| 56 | # option can be used to specify the depth at which feature edges will be added. | ||
| 57 | # This option is included since the graphs can be quite large and the addition | ||
| 58 | # of features from the crate(s) to all of the graph roots can be far too verbose. | ||
| 59 | # This option can be overridden via `--feature-depth` on the cmd line | ||
| 60 | feature-depth = 1 | ||
| 61 | |||
| 62 | # This section is considered when running `cargo deny check advisories` | ||
| 63 | # More documentation for the advisories section can be found here: | ||
| 64 | # https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html | ||
| 65 | [advisories] | ||
| 66 | # The path where the advisory databases are cloned/fetched into | ||
| 67 | #db-path = "$CARGO_HOME/advisory-dbs" | ||
| 68 | # The url(s) of the advisory databases to use | ||
| 69 | #db-urls = ["https://github.com/rustsec/advisory-db"] | ||
| 70 | # A list of advisory IDs to ignore. Note that ignored advisories will still | ||
| 71 | # output a note when they are encountered. | ||
| 72 | ignore = [ | ||
| 73 | #"RUSTSEC-0000-0000", | ||
| 74 | #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, | ||
| 75 | #"[email protected]", # you can also ignore yanked crate versions if you wish | ||
| 76 | #{ crate = "[email protected]", reason = "you can specify why you are ignoring the yanked crate" }, | ||
| 77 | # { id = "RUSTSEC-2024-0370", reason = "proc-macro-error is unmaintained, no safe upgrade available, need upstream dependencies to migrate away from it." }, | ||
| 78 | { id = "RUSTSEC-2024-0436", reason = "there are no suitable replacements for paste right now; paste has been archived as read-only. It only affects compile time concatenation in macros. We will allow it for now" }, | ||
| 79 | # { id = "RUSTSEC-2023-0089", reason = "this is a deprecation warning for a dependency of a dependency. https://github.com/jamesmunns/postcard/issues/223 tracks fixing the dependency; until that's resolved, we can accept the deprecated code as it has no known vulnerabilities."} | ||
| 80 | ] | ||
| 81 | # If this is true, then cargo deny will use the git executable to fetch advisory database. | ||
| 82 | # If this is false, then it uses a built-in git library. | ||
| 83 | # Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. | ||
| 84 | # See Git Authentication for more information about setting up git authentication. | ||
| 85 | #git-fetch-with-cli = true | ||
| 86 | |||
| 87 | # This section is considered when running `cargo deny check licenses` | ||
| 88 | # More documentation for the licenses section can be found here: | ||
| 89 | # https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html | ||
| 90 | [licenses] | ||
| 91 | # List of explicitly allowed licenses | ||
| 92 | # See https://spdx.org/licenses/ for list of possible licenses | ||
| 93 | # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. | ||
| 94 | allow = [ | ||
| 95 | "MIT", | ||
| 96 | "Apache-2.0", | ||
| 97 | |||
| 98 | # unicode-ident 1.0.14 switched from Unicode-DFS-2016 to Unicode-3.0 license. | ||
| 99 | "Unicode-3.0", | ||
| 100 | #"Apache-2.0 WITH LLVM-exception", | ||
| 101 | ] | ||
| 102 | # The confidence threshold for detecting a license from license text. | ||
| 103 | # The higher the value, the more closely the license text must be to the | ||
| 104 | # canonical license text of a valid SPDX license file. | ||
| 105 | # [possible values: any between 0.0 and 1.0]. | ||
| 106 | confidence-threshold = 0.8 | ||
| 107 | # Allow 1 or more licenses on a per-crate basis, so that particular licenses | ||
| 108 | # aren't accepted for every possible crate as with the normal allow list | ||
| 109 | exceptions = [ | ||
| 110 | # Each entry is the crate and version constraint, and its specific allow | ||
| 111 | # list | ||
| 112 | #{ allow = ["Zlib"], crate = "adler32" }, | ||
| 113 | ] | ||
| 114 | |||
| 115 | # Some crates don't have (easily) machine readable licensing information, | ||
| 116 | # adding a clarification entry for it allows you to manually specify the | ||
| 117 | # licensing information | ||
| 118 | #[[licenses.clarify]] | ||
| 119 | # The package spec the clarification applies to | ||
| 120 | #crate = "ring" | ||
| 121 | # The SPDX expression for the license requirements of the crate | ||
| 122 | #expression = "MIT AND ISC AND OpenSSL" | ||
| 123 | # One or more files in the crate's source used as the "source of truth" for | ||
| 124 | # the license expression. If the contents match, the clarification will be used | ||
| 125 | # when running the license check, otherwise the clarification will be ignored | ||
| 126 | # and the crate will be checked normally, which may produce warnings or errors | ||
| 127 | # depending on the rest of your configuration | ||
| 128 | #license-files = [ | ||
| 129 | # Each entry is a crate relative path, and the (opaque) hash of its contents | ||
| 130 | #{ path = "LICENSE", hash = 0xbd0eed23 } | ||
| 131 | #] | ||
| 132 | |||
| 133 | [licenses.private] | ||
| 134 | # If true, ignores workspace crates that aren't published, or are only | ||
| 135 | # published to private registries. | ||
| 136 | # To see how to mark a crate as unpublished (to the official registry), | ||
| 137 | # visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. | ||
| 138 | ignore = false | ||
| 139 | # One or more private registries that you might publish crates to, if a crate | ||
| 140 | # is only published to private registries, and ignore is true, the crate will | ||
| 141 | # not have its license(s) checked | ||
| 142 | registries = [ | ||
| 143 | #"https://sekretz.com/registry | ||
| 144 | ] | ||
| 145 | |||
| 146 | # This section is considered when running `cargo deny check bans`. | ||
| 147 | # More documentation about the 'bans' section can be found here: | ||
| 148 | # https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html | ||
| 149 | [bans] | ||
| 150 | # Lint level for when multiple versions of the same crate are detected | ||
| 151 | multiple-versions = "warn" | ||
| 152 | # Lint level for when a crate version requirement is `*` | ||
| 153 | wildcards = "allow" | ||
| 154 | # The graph highlighting used when creating dotgraphs for crates | ||
| 155 | # with multiple versions | ||
| 156 | # * lowest-version - The path to the lowest versioned duplicate is highlighted | ||
| 157 | # * simplest-path - The path to the version with the fewest edges is highlighted | ||
| 158 | # * all - Both lowest-version and simplest-path are used | ||
| 159 | highlight = "all" | ||
| 160 | # The default lint level for `default` features for crates that are members of | ||
| 161 | # the workspace that is being checked. This can be overridden by allowing/denying | ||
| 162 | # `default` on a crate-by-crate basis if desired. | ||
| 163 | workspace-default-features = "allow" | ||
| 164 | # The default lint level for `default` features for external crates that are not | ||
| 165 | # members of the workspace. This can be overridden by allowing/denying `default` | ||
| 166 | # on a crate-by-crate basis if desired. | ||
| 167 | external-default-features = "allow" | ||
| 168 | # List of crates that are allowed. Use with care! | ||
| 169 | allow = [ | ||
| 170 | #"[email protected]", | ||
| 171 | #{ crate = "[email protected]", reason = "you can specify a reason it is allowed" }, | ||
| 172 | ] | ||
| 173 | # List of crates to deny | ||
| 174 | deny = [ | ||
| 175 | #"[email protected]", | ||
| 176 | #{ crate = "[email protected]", reason = "you can specify a reason it is banned" }, | ||
| 177 | # Wrapper crates can optionally be specified to allow the crate when it | ||
| 178 | # is a direct dependency of the otherwise banned crate | ||
| 179 | #{ crate = "[email protected]", wrappers = ["this-crate-directly-depends-on-ansi_term"] }, | ||
| 180 | ] | ||
| 181 | |||
| 182 | # List of features to allow/deny | ||
| 183 | # Each entry the name of a crate and a version range. If version is | ||
| 184 | # not specified, all versions will be matched. | ||
| 185 | #[[bans.features]] | ||
| 186 | #crate = "reqwest" | ||
| 187 | # Features to not allow | ||
| 188 | #deny = ["json"] | ||
| 189 | # Features to allow | ||
| 190 | #allow = [ | ||
| 191 | # "rustls", | ||
| 192 | # "__rustls", | ||
| 193 | # "__tls", | ||
| 194 | # "hyper-rustls", | ||
| 195 | # "rustls", | ||
| 196 | # "rustls-pemfile", | ||
| 197 | # "rustls-tls-webpki-roots", | ||
| 198 | # "tokio-rustls", | ||
| 199 | # "webpki-roots", | ||
| 200 | #] | ||
| 201 | # If true, the allowed features must exactly match the enabled feature set. If | ||
| 202 | # this is set there is no point setting `deny` | ||
| 203 | #exact = true | ||
| 204 | |||
| 205 | # Certain crates/versions that will be skipped when doing duplicate detection. | ||
| 206 | skip = [ | ||
| 207 | #"[email protected]", | ||
| 208 | #{ crate = "[email protected]", reason = "you can specify a reason why it can't be updated/removed" }, | ||
| 209 | ] | ||
| 210 | # Similarly to `skip` allows you to skip certain crates during duplicate | ||
| 211 | # detection. Unlike skip, it also includes the entire tree of transitive | ||
| 212 | # dependencies starting at the specified crate, up to a certain depth, which is | ||
| 213 | # by default infinite. | ||
| 214 | skip-tree = [ | ||
| 215 | #"[email protected]", # will be skipped along with _all_ of its direct and transitive dependencies | ||
| 216 | #{ crate = "[email protected]", depth = 20 }, | ||
| 217 | ] | ||
| 218 | |||
| 219 | # This section is considered when running `cargo deny check sources`. | ||
| 220 | # More documentation about the 'sources' section can be found here: | ||
| 221 | # https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html | ||
| 222 | [sources] | ||
| 223 | # Lint level for what to happen when a crate from a crate registry that is not | ||
| 224 | # in the allow list is encountered | ||
| 225 | unknown-registry = "warn" | ||
| 226 | # Lint level for what to happen when a crate from a git repository that is not | ||
| 227 | # in the allow list is encountered | ||
| 228 | unknown-git = "warn" | ||
| 229 | # List of URLs for allowed crate registries. Defaults to the crates.io index | ||
| 230 | # if not specified. If it is specified but empty, no registries are allowed. | ||
| 231 | allow-registry = ["https://github.com/rust-lang/crates.io-index"] | ||
| 232 | # List of URLs for allowed Git repositories | ||
| 233 | allow-git = [] | ||
| 234 | |||
| 235 | [sources.allow-org] | ||
| 236 | # github.com organizations to allow git sources for | ||
| 237 | github = ["OpenDevicePartnership"] | ||
| 238 | # gitlab.com organizations to allow git sources for | ||
| 239 | gitlab = [] | ||
| 240 | # bitbucket.org organizations to allow git sources for | ||
| 241 | bitbucket = [] | ||
diff --git a/embassy-mcxa/examples/.cargo/config.toml b/embassy-mcxa/examples/.cargo/config.toml new file mode 100644 index 000000000..aedc55b06 --- /dev/null +++ b/embassy-mcxa/examples/.cargo/config.toml | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | [target.thumbv8m.main-none-eabihf] | ||
| 2 | runner = 'probe-rs run --chip MCXA276 --preverify --verify --protocol swd --speed 12000' | ||
| 3 | |||
| 4 | rustflags = [ | ||
| 5 | "-C", "linker=flip-link", | ||
| 6 | "-C", "link-arg=-Tlink.x", | ||
| 7 | "-C", "link-arg=-Tdefmt.x", | ||
| 8 | # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x | ||
| 9 | # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 | ||
| 10 | "-C", "link-arg=--nmagic", | ||
| 11 | ] | ||
| 12 | |||
| 13 | [build] | ||
| 14 | target = "thumbv8m.main-none-eabihf" # Cortex-M33 | ||
| 15 | |||
| 16 | [env] | ||
| 17 | DEFMT_LOG = "trace" | ||
diff --git a/embassy-mcxa/examples/.gitignore b/embassy-mcxa/examples/.gitignore new file mode 100644 index 000000000..2f7896d1d --- /dev/null +++ b/embassy-mcxa/examples/.gitignore | |||
| @@ -0,0 +1 @@ | |||
| target/ | |||
diff --git a/embassy-mcxa/examples/Cargo.lock b/embassy-mcxa/examples/Cargo.lock new file mode 100644 index 000000000..c6e864df2 --- /dev/null +++ b/embassy-mcxa/examples/Cargo.lock | |||
| @@ -0,0 +1,1555 @@ | |||
| 1 | # This file is automatically @generated by Cargo. | ||
| 2 | # It is not intended for manual editing. | ||
| 3 | version = 4 | ||
| 4 | |||
| 5 | [[package]] | ||
| 6 | name = "aho-corasick" | ||
| 7 | version = "1.1.4" | ||
| 8 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 9 | checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" | ||
| 10 | dependencies = [ | ||
| 11 | "memchr", | ||
| 12 | ] | ||
| 13 | |||
| 14 | [[package]] | ||
| 15 | name = "anyhow" | ||
| 16 | version = "1.0.100" | ||
| 17 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 18 | checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" | ||
| 19 | |||
| 20 | [[package]] | ||
| 21 | name = "askama" | ||
| 22 | version = "0.14.0" | ||
| 23 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 24 | checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" | ||
| 25 | dependencies = [ | ||
| 26 | "askama_derive", | ||
| 27 | "itoa", | ||
| 28 | "percent-encoding", | ||
| 29 | "serde", | ||
| 30 | "serde_json", | ||
| 31 | ] | ||
| 32 | |||
| 33 | [[package]] | ||
| 34 | name = "askama_derive" | ||
| 35 | version = "0.14.0" | ||
| 36 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 37 | checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" | ||
| 38 | dependencies = [ | ||
| 39 | "askama_parser", | ||
| 40 | "memchr", | ||
| 41 | "proc-macro2", | ||
| 42 | "quote", | ||
| 43 | "rustc-hash", | ||
| 44 | "syn 2.0.110", | ||
| 45 | ] | ||
| 46 | |||
| 47 | [[package]] | ||
| 48 | name = "askama_parser" | ||
| 49 | version = "0.14.0" | ||
| 50 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 51 | checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" | ||
| 52 | dependencies = [ | ||
| 53 | "memchr", | ||
| 54 | "winnow 0.7.13", | ||
| 55 | ] | ||
| 56 | |||
| 57 | [[package]] | ||
| 58 | name = "autocfg" | ||
| 59 | version = "1.5.0" | ||
| 60 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 61 | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" | ||
| 62 | |||
| 63 | [[package]] | ||
| 64 | name = "bare-metal" | ||
| 65 | version = "0.2.5" | ||
| 66 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 67 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" | ||
| 68 | dependencies = [ | ||
| 69 | "rustc_version", | ||
| 70 | ] | ||
| 71 | |||
| 72 | [[package]] | ||
| 73 | name = "bitfield" | ||
| 74 | version = "0.13.2" | ||
| 75 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 76 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" | ||
| 77 | |||
| 78 | [[package]] | ||
| 79 | name = "bitflags" | ||
| 80 | version = "1.3.2" | ||
| 81 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 82 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" | ||
| 83 | |||
| 84 | [[package]] | ||
| 85 | name = "bitflags" | ||
| 86 | version = "2.10.0" | ||
| 87 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 88 | checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" | ||
| 89 | |||
| 90 | [[package]] | ||
| 91 | name = "bitvec" | ||
| 92 | version = "1.0.1" | ||
| 93 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 94 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" | ||
| 95 | dependencies = [ | ||
| 96 | "funty", | ||
| 97 | "radium", | ||
| 98 | "tap", | ||
| 99 | "wyz", | ||
| 100 | ] | ||
| 101 | |||
| 102 | [[package]] | ||
| 103 | name = "byteorder" | ||
| 104 | version = "1.5.0" | ||
| 105 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 106 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" | ||
| 107 | |||
| 108 | [[package]] | ||
| 109 | name = "cc" | ||
| 110 | version = "1.2.47" | ||
| 111 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 112 | checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" | ||
| 113 | dependencies = [ | ||
| 114 | "find-msvc-tools", | ||
| 115 | "shlex", | ||
| 116 | ] | ||
| 117 | |||
| 118 | [[package]] | ||
| 119 | name = "cfg-if" | ||
| 120 | version = "1.0.4" | ||
| 121 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 122 | checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" | ||
| 123 | |||
| 124 | [[package]] | ||
| 125 | name = "convert_case" | ||
| 126 | version = "0.6.0" | ||
| 127 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 128 | checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" | ||
| 129 | dependencies = [ | ||
| 130 | "unicode-segmentation", | ||
| 131 | ] | ||
| 132 | |||
| 133 | [[package]] | ||
| 134 | name = "cordyceps" | ||
| 135 | version = "0.3.4" | ||
| 136 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 137 | checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" | ||
| 138 | dependencies = [ | ||
| 139 | "loom", | ||
| 140 | "tracing", | ||
| 141 | ] | ||
| 142 | |||
| 143 | [[package]] | ||
| 144 | name = "cortex-m" | ||
| 145 | version = "0.7.7" | ||
| 146 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 147 | checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" | ||
| 148 | dependencies = [ | ||
| 149 | "bare-metal", | ||
| 150 | "bitfield", | ||
| 151 | "critical-section", | ||
| 152 | "embedded-hal 0.2.7", | ||
| 153 | "volatile-register", | ||
| 154 | ] | ||
| 155 | |||
| 156 | [[package]] | ||
| 157 | name = "cortex-m-rt" | ||
| 158 | version = "0.7.5" | ||
| 159 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 160 | checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" | ||
| 161 | dependencies = [ | ||
| 162 | "cortex-m-rt-macros", | ||
| 163 | ] | ||
| 164 | |||
| 165 | [[package]] | ||
| 166 | name = "cortex-m-rt-macros" | ||
| 167 | version = "0.7.5" | ||
| 168 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 169 | checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" | ||
| 170 | dependencies = [ | ||
| 171 | "proc-macro2", | ||
| 172 | "quote", | ||
| 173 | "syn 2.0.110", | ||
| 174 | ] | ||
| 175 | |||
| 176 | [[package]] | ||
| 177 | name = "critical-section" | ||
| 178 | version = "1.2.0" | ||
| 179 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 180 | checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" | ||
| 181 | |||
| 182 | [[package]] | ||
| 183 | name = "darling" | ||
| 184 | version = "0.20.11" | ||
| 185 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 186 | checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" | ||
| 187 | dependencies = [ | ||
| 188 | "darling_core", | ||
| 189 | "darling_macro", | ||
| 190 | ] | ||
| 191 | |||
| 192 | [[package]] | ||
| 193 | name = "darling_core" | ||
| 194 | version = "0.20.11" | ||
| 195 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 196 | checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" | ||
| 197 | dependencies = [ | ||
| 198 | "fnv", | ||
| 199 | "ident_case", | ||
| 200 | "proc-macro2", | ||
| 201 | "quote", | ||
| 202 | "strsim", | ||
| 203 | "syn 2.0.110", | ||
| 204 | ] | ||
| 205 | |||
| 206 | [[package]] | ||
| 207 | name = "darling_macro" | ||
| 208 | version = "0.20.11" | ||
| 209 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 210 | checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" | ||
| 211 | dependencies = [ | ||
| 212 | "darling_core", | ||
| 213 | "quote", | ||
| 214 | "syn 2.0.110", | ||
| 215 | ] | ||
| 216 | |||
| 217 | [[package]] | ||
| 218 | name = "dd-manifest-tree" | ||
| 219 | version = "1.0.0" | ||
| 220 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 221 | checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" | ||
| 222 | dependencies = [ | ||
| 223 | "toml", | ||
| 224 | ] | ||
| 225 | |||
| 226 | [[package]] | ||
| 227 | name = "defmt" | ||
| 228 | version = "1.0.1" | ||
| 229 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 230 | checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" | ||
| 231 | dependencies = [ | ||
| 232 | "bitflags 1.3.2", | ||
| 233 | "defmt-macros", | ||
| 234 | ] | ||
| 235 | |||
| 236 | [[package]] | ||
| 237 | name = "defmt-macros" | ||
| 238 | version = "1.0.1" | ||
| 239 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 240 | checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" | ||
| 241 | dependencies = [ | ||
| 242 | "defmt-parser", | ||
| 243 | "proc-macro-error2", | ||
| 244 | "proc-macro2", | ||
| 245 | "quote", | ||
| 246 | "syn 2.0.110", | ||
| 247 | ] | ||
| 248 | |||
| 249 | [[package]] | ||
| 250 | name = "defmt-parser" | ||
| 251 | version = "1.0.0" | ||
| 252 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 253 | checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" | ||
| 254 | dependencies = [ | ||
| 255 | "thiserror", | ||
| 256 | ] | ||
| 257 | |||
| 258 | [[package]] | ||
| 259 | name = "defmt-rtt" | ||
| 260 | version = "1.1.0" | ||
| 261 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 262 | checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e" | ||
| 263 | dependencies = [ | ||
| 264 | "critical-section", | ||
| 265 | "defmt", | ||
| 266 | ] | ||
| 267 | |||
| 268 | [[package]] | ||
| 269 | name = "device-driver" | ||
| 270 | version = "1.0.7" | ||
| 271 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 272 | checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" | ||
| 273 | dependencies = [ | ||
| 274 | "device-driver-macros", | ||
| 275 | "embedded-io", | ||
| 276 | "embedded-io-async", | ||
| 277 | ] | ||
| 278 | |||
| 279 | [[package]] | ||
| 280 | name = "device-driver-generation" | ||
| 281 | version = "1.0.7" | ||
| 282 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 283 | checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" | ||
| 284 | dependencies = [ | ||
| 285 | "anyhow", | ||
| 286 | "askama", | ||
| 287 | "bitvec", | ||
| 288 | "convert_case", | ||
| 289 | "dd-manifest-tree", | ||
| 290 | "itertools", | ||
| 291 | "kdl", | ||
| 292 | "proc-macro2", | ||
| 293 | "quote", | ||
| 294 | "syn 2.0.110", | ||
| 295 | ] | ||
| 296 | |||
| 297 | [[package]] | ||
| 298 | name = "device-driver-macros" | ||
| 299 | version = "1.0.7" | ||
| 300 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 301 | checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" | ||
| 302 | dependencies = [ | ||
| 303 | "device-driver-generation", | ||
| 304 | "proc-macro2", | ||
| 305 | "syn 2.0.110", | ||
| 306 | ] | ||
| 307 | |||
| 308 | [[package]] | ||
| 309 | name = "document-features" | ||
| 310 | version = "0.2.12" | ||
| 311 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 312 | checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" | ||
| 313 | dependencies = [ | ||
| 314 | "litrs", | ||
| 315 | ] | ||
| 316 | |||
| 317 | [[package]] | ||
| 318 | name = "either" | ||
| 319 | version = "1.15.0" | ||
| 320 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 321 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" | ||
| 322 | |||
| 323 | [[package]] | ||
| 324 | name = "embassy-embedded-hal" | ||
| 325 | version = "0.5.0" | ||
| 326 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 327 | checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" | ||
| 328 | dependencies = [ | ||
| 329 | "embassy-futures", | ||
| 330 | "embassy-hal-internal", | ||
| 331 | "embassy-sync", | ||
| 332 | "embedded-hal 0.2.7", | ||
| 333 | "embedded-hal 1.0.0", | ||
| 334 | "embedded-hal-async", | ||
| 335 | "embedded-storage", | ||
| 336 | "embedded-storage-async", | ||
| 337 | "nb 1.1.0", | ||
| 338 | ] | ||
| 339 | |||
| 340 | [[package]] | ||
| 341 | name = "embassy-executor" | ||
| 342 | version = "0.9.1" | ||
| 343 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 344 | checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" | ||
| 345 | dependencies = [ | ||
| 346 | "cortex-m", | ||
| 347 | "critical-section", | ||
| 348 | "document-features", | ||
| 349 | "embassy-executor-macros", | ||
| 350 | "embassy-executor-timer-queue", | ||
| 351 | ] | ||
| 352 | |||
| 353 | [[package]] | ||
| 354 | name = "embassy-executor-macros" | ||
| 355 | version = "0.7.0" | ||
| 356 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 357 | checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" | ||
| 358 | dependencies = [ | ||
| 359 | "darling", | ||
| 360 | "proc-macro2", | ||
| 361 | "quote", | ||
| 362 | "syn 2.0.110", | ||
| 363 | ] | ||
| 364 | |||
| 365 | [[package]] | ||
| 366 | name = "embassy-executor-timer-queue" | ||
| 367 | version = "0.1.0" | ||
| 368 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 369 | checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" | ||
| 370 | |||
| 371 | [[package]] | ||
| 372 | name = "embassy-futures" | ||
| 373 | version = "0.1.2" | ||
| 374 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 375 | checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" | ||
| 376 | |||
| 377 | [[package]] | ||
| 378 | name = "embassy-hal-internal" | ||
| 379 | version = "0.3.0" | ||
| 380 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 381 | checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" | ||
| 382 | dependencies = [ | ||
| 383 | "cortex-m", | ||
| 384 | "critical-section", | ||
| 385 | "num-traits", | ||
| 386 | ] | ||
| 387 | |||
| 388 | [[package]] | ||
| 389 | name = "embassy-mcxa" | ||
| 390 | version = "0.1.0" | ||
| 391 | dependencies = [ | ||
| 392 | "cortex-m", | ||
| 393 | "cortex-m-rt", | ||
| 394 | "critical-section", | ||
| 395 | "defmt", | ||
| 396 | "embassy-embedded-hal", | ||
| 397 | "embassy-hal-internal", | ||
| 398 | "embassy-sync", | ||
| 399 | "embassy-time", | ||
| 400 | "embassy-time-driver", | ||
| 401 | "embedded-hal 0.2.7", | ||
| 402 | "embedded-hal 1.0.0", | ||
| 403 | "embedded-hal-async", | ||
| 404 | "embedded-hal-nb", | ||
| 405 | "embedded-io", | ||
| 406 | "embedded-io-async", | ||
| 407 | "heapless 0.8.0", | ||
| 408 | "maitake-sync", | ||
| 409 | "mcxa-pac", | ||
| 410 | "nb 1.1.0", | ||
| 411 | "paste", | ||
| 412 | ] | ||
| 413 | |||
| 414 | [[package]] | ||
| 415 | name = "embassy-mcxa-examples" | ||
| 416 | version = "0.1.0" | ||
| 417 | dependencies = [ | ||
| 418 | "cortex-m", | ||
| 419 | "cortex-m-rt", | ||
| 420 | "critical-section", | ||
| 421 | "defmt", | ||
| 422 | "defmt-rtt", | ||
| 423 | "embassy-embedded-hal", | ||
| 424 | "embassy-executor", | ||
| 425 | "embassy-mcxa", | ||
| 426 | "embassy-sync", | ||
| 427 | "embassy-time", | ||
| 428 | "embassy-time-driver", | ||
| 429 | "embedded-io-async", | ||
| 430 | "heapless 0.9.2", | ||
| 431 | "panic-probe", | ||
| 432 | "tmp108", | ||
| 433 | ] | ||
| 434 | |||
| 435 | [[package]] | ||
| 436 | name = "embassy-sync" | ||
| 437 | version = "0.7.2" | ||
| 438 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 439 | checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" | ||
| 440 | dependencies = [ | ||
| 441 | "cfg-if", | ||
| 442 | "critical-section", | ||
| 443 | "embedded-io-async", | ||
| 444 | "futures-core", | ||
| 445 | "futures-sink", | ||
| 446 | "heapless 0.8.0", | ||
| 447 | ] | ||
| 448 | |||
| 449 | [[package]] | ||
| 450 | name = "embassy-time" | ||
| 451 | version = "0.5.0" | ||
| 452 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 453 | checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" | ||
| 454 | dependencies = [ | ||
| 455 | "cfg-if", | ||
| 456 | "critical-section", | ||
| 457 | "document-features", | ||
| 458 | "embassy-time-driver", | ||
| 459 | "embedded-hal 0.2.7", | ||
| 460 | "embedded-hal 1.0.0", | ||
| 461 | "embedded-hal-async", | ||
| 462 | "futures-core", | ||
| 463 | ] | ||
| 464 | |||
| 465 | [[package]] | ||
| 466 | name = "embassy-time-driver" | ||
| 467 | version = "0.2.1" | ||
| 468 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 469 | checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" | ||
| 470 | dependencies = [ | ||
| 471 | "document-features", | ||
| 472 | ] | ||
| 473 | |||
| 474 | [[package]] | ||
| 475 | name = "embedded-hal" | ||
| 476 | version = "0.2.7" | ||
| 477 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 478 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" | ||
| 479 | dependencies = [ | ||
| 480 | "nb 0.1.3", | ||
| 481 | "void", | ||
| 482 | ] | ||
| 483 | |||
| 484 | [[package]] | ||
| 485 | name = "embedded-hal" | ||
| 486 | version = "1.0.0" | ||
| 487 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 488 | checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" | ||
| 489 | |||
| 490 | [[package]] | ||
| 491 | name = "embedded-hal-async" | ||
| 492 | version = "1.0.0" | ||
| 493 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 494 | checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" | ||
| 495 | dependencies = [ | ||
| 496 | "embedded-hal 1.0.0", | ||
| 497 | ] | ||
| 498 | |||
| 499 | [[package]] | ||
| 500 | name = "embedded-hal-nb" | ||
| 501 | version = "1.0.0" | ||
| 502 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 503 | checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" | ||
| 504 | dependencies = [ | ||
| 505 | "embedded-hal 1.0.0", | ||
| 506 | "nb 1.1.0", | ||
| 507 | ] | ||
| 508 | |||
| 509 | [[package]] | ||
| 510 | name = "embedded-io" | ||
| 511 | version = "0.6.1" | ||
| 512 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 513 | checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" | ||
| 514 | |||
| 515 | [[package]] | ||
| 516 | name = "embedded-io-async" | ||
| 517 | version = "0.6.1" | ||
| 518 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 519 | checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" | ||
| 520 | dependencies = [ | ||
| 521 | "embedded-io", | ||
| 522 | ] | ||
| 523 | |||
| 524 | [[package]] | ||
| 525 | name = "embedded-storage" | ||
| 526 | version = "0.3.1" | ||
| 527 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 528 | checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" | ||
| 529 | |||
| 530 | [[package]] | ||
| 531 | name = "embedded-storage-async" | ||
| 532 | version = "0.4.1" | ||
| 533 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 534 | checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" | ||
| 535 | dependencies = [ | ||
| 536 | "embedded-storage", | ||
| 537 | ] | ||
| 538 | |||
| 539 | [[package]] | ||
| 540 | name = "equivalent" | ||
| 541 | version = "1.0.2" | ||
| 542 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 543 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" | ||
| 544 | |||
| 545 | [[package]] | ||
| 546 | name = "find-msvc-tools" | ||
| 547 | version = "0.1.5" | ||
| 548 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 549 | checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" | ||
| 550 | |||
| 551 | [[package]] | ||
| 552 | name = "fnv" | ||
| 553 | version = "1.0.7" | ||
| 554 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 555 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" | ||
| 556 | |||
| 557 | [[package]] | ||
| 558 | name = "funty" | ||
| 559 | version = "2.0.0" | ||
| 560 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 561 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" | ||
| 562 | |||
| 563 | [[package]] | ||
| 564 | name = "futures-core" | ||
| 565 | version = "0.3.31" | ||
| 566 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 567 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" | ||
| 568 | |||
| 569 | [[package]] | ||
| 570 | name = "futures-sink" | ||
| 571 | version = "0.3.31" | ||
| 572 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 573 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" | ||
| 574 | |||
| 575 | [[package]] | ||
| 576 | name = "generator" | ||
| 577 | version = "0.8.7" | ||
| 578 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 579 | checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" | ||
| 580 | dependencies = [ | ||
| 581 | "cc", | ||
| 582 | "cfg-if", | ||
| 583 | "libc", | ||
| 584 | "log", | ||
| 585 | "rustversion", | ||
| 586 | "windows", | ||
| 587 | ] | ||
| 588 | |||
| 589 | [[package]] | ||
| 590 | name = "hash32" | ||
| 591 | version = "0.3.1" | ||
| 592 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 593 | checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" | ||
| 594 | dependencies = [ | ||
| 595 | "byteorder", | ||
| 596 | ] | ||
| 597 | |||
| 598 | [[package]] | ||
| 599 | name = "hashbrown" | ||
| 600 | version = "0.16.0" | ||
| 601 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 602 | checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" | ||
| 603 | |||
| 604 | [[package]] | ||
| 605 | name = "heapless" | ||
| 606 | version = "0.8.0" | ||
| 607 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 608 | checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" | ||
| 609 | dependencies = [ | ||
| 610 | "hash32", | ||
| 611 | "stable_deref_trait", | ||
| 612 | ] | ||
| 613 | |||
| 614 | [[package]] | ||
| 615 | name = "heapless" | ||
| 616 | version = "0.9.2" | ||
| 617 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 618 | checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" | ||
| 619 | dependencies = [ | ||
| 620 | "hash32", | ||
| 621 | "stable_deref_trait", | ||
| 622 | ] | ||
| 623 | |||
| 624 | [[package]] | ||
| 625 | name = "ident_case" | ||
| 626 | version = "1.0.1" | ||
| 627 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 628 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" | ||
| 629 | |||
| 630 | [[package]] | ||
| 631 | name = "indexmap" | ||
| 632 | version = "2.12.0" | ||
| 633 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 634 | checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" | ||
| 635 | dependencies = [ | ||
| 636 | "equivalent", | ||
| 637 | "hashbrown", | ||
| 638 | ] | ||
| 639 | |||
| 640 | [[package]] | ||
| 641 | name = "itertools" | ||
| 642 | version = "0.14.0" | ||
| 643 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 644 | checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" | ||
| 645 | dependencies = [ | ||
| 646 | "either", | ||
| 647 | ] | ||
| 648 | |||
| 649 | [[package]] | ||
| 650 | name = "itoa" | ||
| 651 | version = "1.0.15" | ||
| 652 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 653 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" | ||
| 654 | |||
| 655 | [[package]] | ||
| 656 | name = "kdl" | ||
| 657 | version = "6.5.0" | ||
| 658 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 659 | checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e" | ||
| 660 | dependencies = [ | ||
| 661 | "miette", | ||
| 662 | "num", | ||
| 663 | "winnow 0.6.24", | ||
| 664 | ] | ||
| 665 | |||
| 666 | [[package]] | ||
| 667 | name = "lazy_static" | ||
| 668 | version = "1.5.0" | ||
| 669 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 670 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" | ||
| 671 | |||
| 672 | [[package]] | ||
| 673 | name = "libc" | ||
| 674 | version = "0.2.177" | ||
| 675 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 676 | checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" | ||
| 677 | |||
| 678 | [[package]] | ||
| 679 | name = "litrs" | ||
| 680 | version = "1.0.0" | ||
| 681 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 682 | checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" | ||
| 683 | |||
| 684 | [[package]] | ||
| 685 | name = "log" | ||
| 686 | version = "0.4.28" | ||
| 687 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 688 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" | ||
| 689 | |||
| 690 | [[package]] | ||
| 691 | name = "loom" | ||
| 692 | version = "0.7.2" | ||
| 693 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 694 | checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" | ||
| 695 | dependencies = [ | ||
| 696 | "cfg-if", | ||
| 697 | "generator", | ||
| 698 | "scoped-tls", | ||
| 699 | "tracing", | ||
| 700 | "tracing-subscriber", | ||
| 701 | ] | ||
| 702 | |||
| 703 | [[package]] | ||
| 704 | name = "maitake-sync" | ||
| 705 | version = "0.2.2" | ||
| 706 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 707 | checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" | ||
| 708 | dependencies = [ | ||
| 709 | "cordyceps", | ||
| 710 | "critical-section", | ||
| 711 | "loom", | ||
| 712 | "mutex-traits", | ||
| 713 | "mycelium-bitfield", | ||
| 714 | "pin-project", | ||
| 715 | "portable-atomic", | ||
| 716 | "tracing", | ||
| 717 | ] | ||
| 718 | |||
| 719 | [[package]] | ||
| 720 | name = "manyhow" | ||
| 721 | version = "0.11.4" | ||
| 722 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 723 | checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" | ||
| 724 | dependencies = [ | ||
| 725 | "manyhow-macros", | ||
| 726 | "proc-macro2", | ||
| 727 | "quote", | ||
| 728 | "syn 1.0.109", | ||
| 729 | "syn 2.0.110", | ||
| 730 | ] | ||
| 731 | |||
| 732 | [[package]] | ||
| 733 | name = "manyhow-macros" | ||
| 734 | version = "0.11.4" | ||
| 735 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 736 | checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" | ||
| 737 | dependencies = [ | ||
| 738 | "proc-macro-utils", | ||
| 739 | "proc-macro2", | ||
| 740 | "quote", | ||
| 741 | ] | ||
| 742 | |||
| 743 | [[package]] | ||
| 744 | name = "matchers" | ||
| 745 | version = "0.2.0" | ||
| 746 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 747 | checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" | ||
| 748 | dependencies = [ | ||
| 749 | "regex-automata", | ||
| 750 | ] | ||
| 751 | |||
| 752 | [[package]] | ||
| 753 | name = "maybe-async-cfg" | ||
| 754 | version = "0.2.5" | ||
| 755 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 756 | checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627" | ||
| 757 | dependencies = [ | ||
| 758 | "manyhow", | ||
| 759 | "proc-macro2", | ||
| 760 | "pulldown-cmark", | ||
| 761 | "quote", | ||
| 762 | "syn 1.0.109", | ||
| 763 | ] | ||
| 764 | |||
| 765 | [[package]] | ||
| 766 | name = "mcxa-pac" | ||
| 767 | version = "0.1.0" | ||
| 768 | source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca" | ||
| 769 | dependencies = [ | ||
| 770 | "cortex-m", | ||
| 771 | "cortex-m-rt", | ||
| 772 | "critical-section", | ||
| 773 | "defmt", | ||
| 774 | "vcell", | ||
| 775 | ] | ||
| 776 | |||
| 777 | [[package]] | ||
| 778 | name = "memchr" | ||
| 779 | version = "2.7.6" | ||
| 780 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 781 | checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" | ||
| 782 | |||
| 783 | [[package]] | ||
| 784 | name = "miette" | ||
| 785 | version = "7.6.0" | ||
| 786 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 787 | checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" | ||
| 788 | dependencies = [ | ||
| 789 | "cfg-if", | ||
| 790 | "unicode-width", | ||
| 791 | ] | ||
| 792 | |||
| 793 | [[package]] | ||
| 794 | name = "mutex-traits" | ||
| 795 | version = "1.0.1" | ||
| 796 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 797 | checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" | ||
| 798 | |||
| 799 | [[package]] | ||
| 800 | name = "mycelium-bitfield" | ||
| 801 | version = "0.1.5" | ||
| 802 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 803 | checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc" | ||
| 804 | |||
| 805 | [[package]] | ||
| 806 | name = "nb" | ||
| 807 | version = "0.1.3" | ||
| 808 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 809 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" | ||
| 810 | dependencies = [ | ||
| 811 | "nb 1.1.0", | ||
| 812 | ] | ||
| 813 | |||
| 814 | [[package]] | ||
| 815 | name = "nb" | ||
| 816 | version = "1.1.0" | ||
| 817 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 818 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" | ||
| 819 | |||
| 820 | [[package]] | ||
| 821 | name = "nu-ansi-term" | ||
| 822 | version = "0.50.3" | ||
| 823 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 824 | checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" | ||
| 825 | dependencies = [ | ||
| 826 | "windows-sys", | ||
| 827 | ] | ||
| 828 | |||
| 829 | [[package]] | ||
| 830 | name = "num" | ||
| 831 | version = "0.4.3" | ||
| 832 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 833 | checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" | ||
| 834 | dependencies = [ | ||
| 835 | "num-bigint", | ||
| 836 | "num-complex", | ||
| 837 | "num-integer", | ||
| 838 | "num-iter", | ||
| 839 | "num-rational", | ||
| 840 | "num-traits", | ||
| 841 | ] | ||
| 842 | |||
| 843 | [[package]] | ||
| 844 | name = "num-bigint" | ||
| 845 | version = "0.4.6" | ||
| 846 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 847 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" | ||
| 848 | dependencies = [ | ||
| 849 | "num-integer", | ||
| 850 | "num-traits", | ||
| 851 | ] | ||
| 852 | |||
| 853 | [[package]] | ||
| 854 | name = "num-complex" | ||
| 855 | version = "0.4.6" | ||
| 856 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 857 | checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" | ||
| 858 | dependencies = [ | ||
| 859 | "num-traits", | ||
| 860 | ] | ||
| 861 | |||
| 862 | [[package]] | ||
| 863 | name = "num-integer" | ||
| 864 | version = "0.1.46" | ||
| 865 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 866 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" | ||
| 867 | dependencies = [ | ||
| 868 | "num-traits", | ||
| 869 | ] | ||
| 870 | |||
| 871 | [[package]] | ||
| 872 | name = "num-iter" | ||
| 873 | version = "0.1.45" | ||
| 874 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 875 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" | ||
| 876 | dependencies = [ | ||
| 877 | "autocfg", | ||
| 878 | "num-integer", | ||
| 879 | "num-traits", | ||
| 880 | ] | ||
| 881 | |||
| 882 | [[package]] | ||
| 883 | name = "num-rational" | ||
| 884 | version = "0.4.2" | ||
| 885 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 886 | checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" | ||
| 887 | dependencies = [ | ||
| 888 | "num-bigint", | ||
| 889 | "num-integer", | ||
| 890 | "num-traits", | ||
| 891 | ] | ||
| 892 | |||
| 893 | [[package]] | ||
| 894 | name = "num-traits" | ||
| 895 | version = "0.2.19" | ||
| 896 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 897 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" | ||
| 898 | dependencies = [ | ||
| 899 | "autocfg", | ||
| 900 | ] | ||
| 901 | |||
| 902 | [[package]] | ||
| 903 | name = "once_cell" | ||
| 904 | version = "1.21.3" | ||
| 905 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 906 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" | ||
| 907 | |||
| 908 | [[package]] | ||
| 909 | name = "panic-probe" | ||
| 910 | version = "1.0.0" | ||
| 911 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 912 | checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a" | ||
| 913 | dependencies = [ | ||
| 914 | "cortex-m", | ||
| 915 | "defmt", | ||
| 916 | ] | ||
| 917 | |||
| 918 | [[package]] | ||
| 919 | name = "paste" | ||
| 920 | version = "1.0.15" | ||
| 921 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 922 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" | ||
| 923 | |||
| 924 | [[package]] | ||
| 925 | name = "percent-encoding" | ||
| 926 | version = "2.3.2" | ||
| 927 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 928 | checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" | ||
| 929 | |||
| 930 | [[package]] | ||
| 931 | name = "pin-project" | ||
| 932 | version = "1.1.10" | ||
| 933 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 934 | checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" | ||
| 935 | dependencies = [ | ||
| 936 | "pin-project-internal", | ||
| 937 | ] | ||
| 938 | |||
| 939 | [[package]] | ||
| 940 | name = "pin-project-internal" | ||
| 941 | version = "1.1.10" | ||
| 942 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 943 | checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" | ||
| 944 | dependencies = [ | ||
| 945 | "proc-macro2", | ||
| 946 | "quote", | ||
| 947 | "syn 2.0.110", | ||
| 948 | ] | ||
| 949 | |||
| 950 | [[package]] | ||
| 951 | name = "pin-project-lite" | ||
| 952 | version = "0.2.16" | ||
| 953 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 954 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" | ||
| 955 | |||
| 956 | [[package]] | ||
| 957 | name = "portable-atomic" | ||
| 958 | version = "1.11.1" | ||
| 959 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 960 | checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" | ||
| 961 | dependencies = [ | ||
| 962 | "critical-section", | ||
| 963 | ] | ||
| 964 | |||
| 965 | [[package]] | ||
| 966 | name = "proc-macro-error-attr2" | ||
| 967 | version = "2.0.0" | ||
| 968 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 969 | checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" | ||
| 970 | dependencies = [ | ||
| 971 | "proc-macro2", | ||
| 972 | "quote", | ||
| 973 | ] | ||
| 974 | |||
| 975 | [[package]] | ||
| 976 | name = "proc-macro-error2" | ||
| 977 | version = "2.0.1" | ||
| 978 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 979 | checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" | ||
| 980 | dependencies = [ | ||
| 981 | "proc-macro-error-attr2", | ||
| 982 | "proc-macro2", | ||
| 983 | "quote", | ||
| 984 | "syn 2.0.110", | ||
| 985 | ] | ||
| 986 | |||
| 987 | [[package]] | ||
| 988 | name = "proc-macro-utils" | ||
| 989 | version = "0.10.0" | ||
| 990 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 991 | checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" | ||
| 992 | dependencies = [ | ||
| 993 | "proc-macro2", | ||
| 994 | "quote", | ||
| 995 | "smallvec", | ||
| 996 | ] | ||
| 997 | |||
| 998 | [[package]] | ||
| 999 | name = "proc-macro2" | ||
| 1000 | version = "1.0.103" | ||
| 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1002 | checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" | ||
| 1003 | dependencies = [ | ||
| 1004 | "unicode-ident", | ||
| 1005 | ] | ||
| 1006 | |||
| 1007 | [[package]] | ||
| 1008 | name = "pulldown-cmark" | ||
| 1009 | version = "0.11.3" | ||
| 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1011 | checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" | ||
| 1012 | dependencies = [ | ||
| 1013 | "bitflags 2.10.0", | ||
| 1014 | "memchr", | ||
| 1015 | "unicase", | ||
| 1016 | ] | ||
| 1017 | |||
| 1018 | [[package]] | ||
| 1019 | name = "quote" | ||
| 1020 | version = "1.0.42" | ||
| 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1022 | checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" | ||
| 1023 | dependencies = [ | ||
| 1024 | "proc-macro2", | ||
| 1025 | ] | ||
| 1026 | |||
| 1027 | [[package]] | ||
| 1028 | name = "radium" | ||
| 1029 | version = "0.7.0" | ||
| 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1031 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" | ||
| 1032 | |||
| 1033 | [[package]] | ||
| 1034 | name = "regex-automata" | ||
| 1035 | version = "0.4.13" | ||
| 1036 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1037 | checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" | ||
| 1038 | dependencies = [ | ||
| 1039 | "aho-corasick", | ||
| 1040 | "memchr", | ||
| 1041 | "regex-syntax", | ||
| 1042 | ] | ||
| 1043 | |||
| 1044 | [[package]] | ||
| 1045 | name = "regex-syntax" | ||
| 1046 | version = "0.8.8" | ||
| 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1048 | checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" | ||
| 1049 | |||
| 1050 | [[package]] | ||
| 1051 | name = "rustc-hash" | ||
| 1052 | version = "2.1.1" | ||
| 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1054 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" | ||
| 1055 | |||
| 1056 | [[package]] | ||
| 1057 | name = "rustc_version" | ||
| 1058 | version = "0.2.3" | ||
| 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1060 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" | ||
| 1061 | dependencies = [ | ||
| 1062 | "semver", | ||
| 1063 | ] | ||
| 1064 | |||
| 1065 | [[package]] | ||
| 1066 | name = "rustversion" | ||
| 1067 | version = "1.0.22" | ||
| 1068 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1069 | checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" | ||
| 1070 | |||
| 1071 | [[package]] | ||
| 1072 | name = "ryu" | ||
| 1073 | version = "1.0.20" | ||
| 1074 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1075 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" | ||
| 1076 | |||
| 1077 | [[package]] | ||
| 1078 | name = "scoped-tls" | ||
| 1079 | version = "1.0.1" | ||
| 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1081 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" | ||
| 1082 | |||
| 1083 | [[package]] | ||
| 1084 | name = "semver" | ||
| 1085 | version = "0.9.0" | ||
| 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1087 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" | ||
| 1088 | dependencies = [ | ||
| 1089 | "semver-parser", | ||
| 1090 | ] | ||
| 1091 | |||
| 1092 | [[package]] | ||
| 1093 | name = "semver-parser" | ||
| 1094 | version = "0.7.0" | ||
| 1095 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1096 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" | ||
| 1097 | |||
| 1098 | [[package]] | ||
| 1099 | name = "serde" | ||
| 1100 | version = "1.0.228" | ||
| 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1102 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" | ||
| 1103 | dependencies = [ | ||
| 1104 | "serde_core", | ||
| 1105 | ] | ||
| 1106 | |||
| 1107 | [[package]] | ||
| 1108 | name = "serde_core" | ||
| 1109 | version = "1.0.228" | ||
| 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1111 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" | ||
| 1112 | dependencies = [ | ||
| 1113 | "serde_derive", | ||
| 1114 | ] | ||
| 1115 | |||
| 1116 | [[package]] | ||
| 1117 | name = "serde_derive" | ||
| 1118 | version = "1.0.228" | ||
| 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1120 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" | ||
| 1121 | dependencies = [ | ||
| 1122 | "proc-macro2", | ||
| 1123 | "quote", | ||
| 1124 | "syn 2.0.110", | ||
| 1125 | ] | ||
| 1126 | |||
| 1127 | [[package]] | ||
| 1128 | name = "serde_json" | ||
| 1129 | version = "1.0.145" | ||
| 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1131 | checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" | ||
| 1132 | dependencies = [ | ||
| 1133 | "itoa", | ||
| 1134 | "memchr", | ||
| 1135 | "ryu", | ||
| 1136 | "serde", | ||
| 1137 | "serde_core", | ||
| 1138 | ] | ||
| 1139 | |||
| 1140 | [[package]] | ||
| 1141 | name = "serde_spanned" | ||
| 1142 | version = "0.6.9" | ||
| 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1144 | checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" | ||
| 1145 | dependencies = [ | ||
| 1146 | "serde", | ||
| 1147 | ] | ||
| 1148 | |||
| 1149 | [[package]] | ||
| 1150 | name = "sharded-slab" | ||
| 1151 | version = "0.1.7" | ||
| 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1153 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" | ||
| 1154 | dependencies = [ | ||
| 1155 | "lazy_static", | ||
| 1156 | ] | ||
| 1157 | |||
| 1158 | [[package]] | ||
| 1159 | name = "shlex" | ||
| 1160 | version = "1.3.0" | ||
| 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1162 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" | ||
| 1163 | |||
| 1164 | [[package]] | ||
| 1165 | name = "smallvec" | ||
| 1166 | version = "1.15.1" | ||
| 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1168 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" | ||
| 1169 | |||
| 1170 | [[package]] | ||
| 1171 | name = "stable_deref_trait" | ||
| 1172 | version = "1.2.1" | ||
| 1173 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1174 | checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" | ||
| 1175 | |||
| 1176 | [[package]] | ||
| 1177 | name = "strsim" | ||
| 1178 | version = "0.11.1" | ||
| 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1180 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" | ||
| 1181 | |||
| 1182 | [[package]] | ||
| 1183 | name = "syn" | ||
| 1184 | version = "1.0.109" | ||
| 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1186 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" | ||
| 1187 | dependencies = [ | ||
| 1188 | "proc-macro2", | ||
| 1189 | "quote", | ||
| 1190 | "unicode-ident", | ||
| 1191 | ] | ||
| 1192 | |||
| 1193 | [[package]] | ||
| 1194 | name = "syn" | ||
| 1195 | version = "2.0.110" | ||
| 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1197 | checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" | ||
| 1198 | dependencies = [ | ||
| 1199 | "proc-macro2", | ||
| 1200 | "quote", | ||
| 1201 | "unicode-ident", | ||
| 1202 | ] | ||
| 1203 | |||
| 1204 | [[package]] | ||
| 1205 | name = "tap" | ||
| 1206 | version = "1.0.1" | ||
| 1207 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1208 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" | ||
| 1209 | |||
| 1210 | [[package]] | ||
| 1211 | name = "thiserror" | ||
| 1212 | version = "2.0.17" | ||
| 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1214 | checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" | ||
| 1215 | dependencies = [ | ||
| 1216 | "thiserror-impl", | ||
| 1217 | ] | ||
| 1218 | |||
| 1219 | [[package]] | ||
| 1220 | name = "thiserror-impl" | ||
| 1221 | version = "2.0.17" | ||
| 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1223 | checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" | ||
| 1224 | dependencies = [ | ||
| 1225 | "proc-macro2", | ||
| 1226 | "quote", | ||
| 1227 | "syn 2.0.110", | ||
| 1228 | ] | ||
| 1229 | |||
| 1230 | [[package]] | ||
| 1231 | name = "thread_local" | ||
| 1232 | version = "1.1.9" | ||
| 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1234 | checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" | ||
| 1235 | dependencies = [ | ||
| 1236 | "cfg-if", | ||
| 1237 | ] | ||
| 1238 | |||
| 1239 | [[package]] | ||
| 1240 | name = "tmp108" | ||
| 1241 | version = "0.4.0" | ||
| 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1243 | checksum = "e0d644cc97d3cee96793f454b834881f78b5d4e89c90ecf26b3690f42004d111" | ||
| 1244 | dependencies = [ | ||
| 1245 | "device-driver", | ||
| 1246 | "embedded-hal 1.0.0", | ||
| 1247 | "maybe-async-cfg", | ||
| 1248 | ] | ||
| 1249 | |||
| 1250 | [[package]] | ||
| 1251 | name = "toml" | ||
| 1252 | version = "0.8.23" | ||
| 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1254 | checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" | ||
| 1255 | dependencies = [ | ||
| 1256 | "indexmap", | ||
| 1257 | "serde", | ||
| 1258 | "serde_spanned", | ||
| 1259 | "toml_datetime", | ||
| 1260 | "toml_edit", | ||
| 1261 | ] | ||
| 1262 | |||
| 1263 | [[package]] | ||
| 1264 | name = "toml_datetime" | ||
| 1265 | version = "0.6.11" | ||
| 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1267 | checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" | ||
| 1268 | dependencies = [ | ||
| 1269 | "serde", | ||
| 1270 | ] | ||
| 1271 | |||
| 1272 | [[package]] | ||
| 1273 | name = "toml_edit" | ||
| 1274 | version = "0.22.27" | ||
| 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1276 | checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" | ||
| 1277 | dependencies = [ | ||
| 1278 | "indexmap", | ||
| 1279 | "serde", | ||
| 1280 | "serde_spanned", | ||
| 1281 | "toml_datetime", | ||
| 1282 | "toml_write", | ||
| 1283 | "winnow 0.7.13", | ||
| 1284 | ] | ||
| 1285 | |||
| 1286 | [[package]] | ||
| 1287 | name = "toml_write" | ||
| 1288 | version = "0.1.2" | ||
| 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1290 | checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" | ||
| 1291 | |||
| 1292 | [[package]] | ||
| 1293 | name = "tracing" | ||
| 1294 | version = "0.1.42" | ||
| 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1296 | checksum = "8eb41cbdb933e23b7929f47bb577710643157d7602ef3a2ebd3902b13ac5eda6" | ||
| 1297 | dependencies = [ | ||
| 1298 | "pin-project-lite", | ||
| 1299 | "tracing-attributes", | ||
| 1300 | "tracing-core", | ||
| 1301 | ] | ||
| 1302 | |||
| 1303 | [[package]] | ||
| 1304 | name = "tracing-attributes" | ||
| 1305 | version = "0.1.31" | ||
| 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1307 | checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" | ||
| 1308 | dependencies = [ | ||
| 1309 | "proc-macro2", | ||
| 1310 | "quote", | ||
| 1311 | "syn 2.0.110", | ||
| 1312 | ] | ||
| 1313 | |||
| 1314 | [[package]] | ||
| 1315 | name = "tracing-core" | ||
| 1316 | version = "0.1.35" | ||
| 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1318 | checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" | ||
| 1319 | dependencies = [ | ||
| 1320 | "once_cell", | ||
| 1321 | "valuable", | ||
| 1322 | ] | ||
| 1323 | |||
| 1324 | [[package]] | ||
| 1325 | name = "tracing-log" | ||
| 1326 | version = "0.2.0" | ||
| 1327 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1328 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" | ||
| 1329 | dependencies = [ | ||
| 1330 | "log", | ||
| 1331 | "once_cell", | ||
| 1332 | "tracing-core", | ||
| 1333 | ] | ||
| 1334 | |||
| 1335 | [[package]] | ||
| 1336 | name = "tracing-subscriber" | ||
| 1337 | version = "0.3.20" | ||
| 1338 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1339 | checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" | ||
| 1340 | dependencies = [ | ||
| 1341 | "matchers", | ||
| 1342 | "nu-ansi-term", | ||
| 1343 | "once_cell", | ||
| 1344 | "regex-automata", | ||
| 1345 | "sharded-slab", | ||
| 1346 | "smallvec", | ||
| 1347 | "thread_local", | ||
| 1348 | "tracing", | ||
| 1349 | "tracing-core", | ||
| 1350 | "tracing-log", | ||
| 1351 | ] | ||
| 1352 | |||
| 1353 | [[package]] | ||
| 1354 | name = "unicase" | ||
| 1355 | version = "2.8.1" | ||
| 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1357 | checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" | ||
| 1358 | |||
| 1359 | [[package]] | ||
| 1360 | name = "unicode-ident" | ||
| 1361 | version = "1.0.22" | ||
| 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1363 | checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" | ||
| 1364 | |||
| 1365 | [[package]] | ||
| 1366 | name = "unicode-segmentation" | ||
| 1367 | version = "1.12.0" | ||
| 1368 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1369 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" | ||
| 1370 | |||
| 1371 | [[package]] | ||
| 1372 | name = "unicode-width" | ||
| 1373 | version = "0.1.14" | ||
| 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1375 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" | ||
| 1376 | |||
| 1377 | [[package]] | ||
| 1378 | name = "valuable" | ||
| 1379 | version = "0.1.1" | ||
| 1380 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1381 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" | ||
| 1382 | |||
| 1383 | [[package]] | ||
| 1384 | name = "vcell" | ||
| 1385 | version = "0.1.3" | ||
| 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1387 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" | ||
| 1388 | |||
| 1389 | [[package]] | ||
| 1390 | name = "void" | ||
| 1391 | version = "1.0.2" | ||
| 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1393 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" | ||
| 1394 | |||
| 1395 | [[package]] | ||
| 1396 | name = "volatile-register" | ||
| 1397 | version = "0.2.2" | ||
| 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1399 | checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" | ||
| 1400 | dependencies = [ | ||
| 1401 | "vcell", | ||
| 1402 | ] | ||
| 1403 | |||
| 1404 | [[package]] | ||
| 1405 | name = "windows" | ||
| 1406 | version = "0.61.3" | ||
| 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1408 | checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" | ||
| 1409 | dependencies = [ | ||
| 1410 | "windows-collections", | ||
| 1411 | "windows-core", | ||
| 1412 | "windows-future", | ||
| 1413 | "windows-link 0.1.3", | ||
| 1414 | "windows-numerics", | ||
| 1415 | ] | ||
| 1416 | |||
| 1417 | [[package]] | ||
| 1418 | name = "windows-collections" | ||
| 1419 | version = "0.2.0" | ||
| 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1421 | checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" | ||
| 1422 | dependencies = [ | ||
| 1423 | "windows-core", | ||
| 1424 | ] | ||
| 1425 | |||
| 1426 | [[package]] | ||
| 1427 | name = "windows-core" | ||
| 1428 | version = "0.61.2" | ||
| 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1430 | checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" | ||
| 1431 | dependencies = [ | ||
| 1432 | "windows-implement", | ||
| 1433 | "windows-interface", | ||
| 1434 | "windows-link 0.1.3", | ||
| 1435 | "windows-result", | ||
| 1436 | "windows-strings", | ||
| 1437 | ] | ||
| 1438 | |||
| 1439 | [[package]] | ||
| 1440 | name = "windows-future" | ||
| 1441 | version = "0.2.1" | ||
| 1442 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1443 | checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" | ||
| 1444 | dependencies = [ | ||
| 1445 | "windows-core", | ||
| 1446 | "windows-link 0.1.3", | ||
| 1447 | "windows-threading", | ||
| 1448 | ] | ||
| 1449 | |||
| 1450 | [[package]] | ||
| 1451 | name = "windows-implement" | ||
| 1452 | version = "0.60.2" | ||
| 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1454 | checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" | ||
| 1455 | dependencies = [ | ||
| 1456 | "proc-macro2", | ||
| 1457 | "quote", | ||
| 1458 | "syn 2.0.110", | ||
| 1459 | ] | ||
| 1460 | |||
| 1461 | [[package]] | ||
| 1462 | name = "windows-interface" | ||
| 1463 | version = "0.59.3" | ||
| 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1465 | checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" | ||
| 1466 | dependencies = [ | ||
| 1467 | "proc-macro2", | ||
| 1468 | "quote", | ||
| 1469 | "syn 2.0.110", | ||
| 1470 | ] | ||
| 1471 | |||
| 1472 | [[package]] | ||
| 1473 | name = "windows-link" | ||
| 1474 | version = "0.1.3" | ||
| 1475 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1476 | checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" | ||
| 1477 | |||
| 1478 | [[package]] | ||
| 1479 | name = "windows-link" | ||
| 1480 | version = "0.2.1" | ||
| 1481 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1482 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" | ||
| 1483 | |||
| 1484 | [[package]] | ||
| 1485 | name = "windows-numerics" | ||
| 1486 | version = "0.2.0" | ||
| 1487 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1488 | checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" | ||
| 1489 | dependencies = [ | ||
| 1490 | "windows-core", | ||
| 1491 | "windows-link 0.1.3", | ||
| 1492 | ] | ||
| 1493 | |||
| 1494 | [[package]] | ||
| 1495 | name = "windows-result" | ||
| 1496 | version = "0.3.4" | ||
| 1497 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1498 | checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" | ||
| 1499 | dependencies = [ | ||
| 1500 | "windows-link 0.1.3", | ||
| 1501 | ] | ||
| 1502 | |||
| 1503 | [[package]] | ||
| 1504 | name = "windows-strings" | ||
| 1505 | version = "0.4.2" | ||
| 1506 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1507 | checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" | ||
| 1508 | dependencies = [ | ||
| 1509 | "windows-link 0.1.3", | ||
| 1510 | ] | ||
| 1511 | |||
| 1512 | [[package]] | ||
| 1513 | name = "windows-sys" | ||
| 1514 | version = "0.61.2" | ||
| 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1516 | checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" | ||
| 1517 | dependencies = [ | ||
| 1518 | "windows-link 0.2.1", | ||
| 1519 | ] | ||
| 1520 | |||
| 1521 | [[package]] | ||
| 1522 | name = "windows-threading" | ||
| 1523 | version = "0.1.0" | ||
| 1524 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1525 | checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" | ||
| 1526 | dependencies = [ | ||
| 1527 | "windows-link 0.1.3", | ||
| 1528 | ] | ||
| 1529 | |||
| 1530 | [[package]] | ||
| 1531 | name = "winnow" | ||
| 1532 | version = "0.6.24" | ||
| 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1534 | checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" | ||
| 1535 | dependencies = [ | ||
| 1536 | "memchr", | ||
| 1537 | ] | ||
| 1538 | |||
| 1539 | [[package]] | ||
| 1540 | name = "winnow" | ||
| 1541 | version = "0.7.13" | ||
| 1542 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1543 | checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" | ||
| 1544 | dependencies = [ | ||
| 1545 | "memchr", | ||
| 1546 | ] | ||
| 1547 | |||
| 1548 | [[package]] | ||
| 1549 | name = "wyz" | ||
| 1550 | version = "0.5.1" | ||
| 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1552 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" | ||
| 1553 | dependencies = [ | ||
| 1554 | "tap", | ||
| 1555 | ] | ||
diff --git a/embassy-mcxa/examples/Cargo.toml b/embassy-mcxa/examples/Cargo.toml new file mode 100644 index 000000000..a1092c416 --- /dev/null +++ b/embassy-mcxa/examples/Cargo.toml | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-mcxa-examples" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | cortex-m = { version = "0.7", features = ["critical-section-single-core"] } | ||
| 9 | cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] } | ||
| 10 | critical-section = "1.2.0" | ||
| 11 | defmt = "1.0" | ||
| 12 | defmt-rtt = "1.0" | ||
| 13 | embassy-embedded-hal = "0.5.0" | ||
| 14 | embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } | ||
| 15 | embassy-mcxa = { path = "../", features = ["defmt", "unstable-pac", "time"] } | ||
| 16 | embassy-sync = "0.7.2" | ||
| 17 | embassy-time = "0.5.0" | ||
| 18 | embassy-time-driver = "0.2.1" | ||
| 19 | embedded-io-async = "0.6.1" | ||
| 20 | heapless = "0.9.2" | ||
| 21 | panic-probe = { version = "1.0", features = ["print-defmt"] } | ||
| 22 | tmp108 = "0.4.0" | ||
| 23 | |||
| 24 | [profile.release] | ||
| 25 | lto = true # better optimizations | ||
| 26 | debug = 2 # enough information for defmt/rtt locations | ||
diff --git a/embassy-mcxa/examples/build.rs b/embassy-mcxa/examples/build.rs new file mode 100644 index 000000000..f076bba9f --- /dev/null +++ b/embassy-mcxa/examples/build.rs | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | use std::env; | ||
| 2 | use std::fs::File; | ||
| 3 | use std::io::Write; | ||
| 4 | use std::path::PathBuf; | ||
| 5 | |||
| 6 | fn main() { | ||
| 7 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 8 | |||
| 9 | // Generate memory.x - put "FLASH" at start of RAM, RAM after "FLASH" | ||
| 10 | // cortex-m-rt expects FLASH for code, RAM for data/bss/stack | ||
| 11 | // Both are in RAM, but separated to satisfy cortex-m-rt's expectations | ||
| 12 | // MCXA256 has 128KB RAM total | ||
| 13 | File::create(out.join("memory.x")) | ||
| 14 | .unwrap() | ||
| 15 | .write_all(include_bytes!("memory.x")) | ||
| 16 | .unwrap(); | ||
| 17 | |||
| 18 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 19 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 20 | } | ||
diff --git a/embassy-mcxa/examples/memory.x b/embassy-mcxa/examples/memory.x new file mode 100644 index 000000000..315ced58a --- /dev/null +++ b/embassy-mcxa/examples/memory.x | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 1M | ||
| 4 | RAM : ORIGIN = 0x20000000, LENGTH = 128K | ||
| 5 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/adc_interrupt.rs b/embassy-mcxa/examples/src/bin/adc_interrupt.rs new file mode 100644 index 000000000..83d8046b3 --- /dev/null +++ b/embassy-mcxa/examples/src/bin/adc_interrupt.rs | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_mcxa_examples::init_adc_pins; | ||
| 6 | use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; | ||
| 7 | use hal::clocks::periph_helpers::{AdcClockSel, Div4}; | ||
| 8 | use hal::clocks::PoweredClock; | ||
| 9 | use hal::pac::adc1::cfg::{Pwrsel, Refsel}; | ||
| 10 | use hal::pac::adc1::cmdl1::{Adch, Mode}; | ||
| 11 | use hal::pac::adc1::ctrl::CalAvgs; | ||
| 12 | use hal::pac::adc1::tctrl::Tcmd; | ||
| 13 | use hal::{bind_interrupts, InterruptExt}; | ||
| 14 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 15 | |||
| 16 | bind_interrupts!(struct Irqs { | ||
| 17 | ADC1 => hal::adc::AdcHandler; | ||
| 18 | }); | ||
| 19 | |||
| 20 | #[used] | ||
| 21 | #[no_mangle] | ||
| 22 | static KEEP_ADC: unsafe extern "C" fn() = ADC1; | ||
| 23 | |||
| 24 | #[embassy_executor::main] | ||
| 25 | async fn main(_spawner: Spawner) { | ||
| 26 | let p = hal::init(hal::config::Config::default()); | ||
| 27 | |||
| 28 | defmt::info!("ADC interrupt Example"); | ||
| 29 | |||
| 30 | unsafe { | ||
| 31 | init_adc_pins(); | ||
| 32 | } | ||
| 33 | |||
| 34 | let adc_config = LpadcConfig { | ||
| 35 | enable_in_doze_mode: true, | ||
| 36 | conversion_average_mode: CalAvgs::Average128, | ||
| 37 | enable_analog_preliminary: true, | ||
| 38 | power_up_delay: 0x80, | ||
| 39 | reference_voltage_source: Refsel::Option3, | ||
| 40 | power_level_mode: Pwrsel::Lowest, | ||
| 41 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, | ||
| 42 | enable_conv_pause: false, | ||
| 43 | conv_pause_delay: 0, | ||
| 44 | fifo_watermark: 0, | ||
| 45 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 46 | source: AdcClockSel::FroLfDiv, | ||
| 47 | div: Div4::no_div(), | ||
| 48 | }; | ||
| 49 | let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); | ||
| 50 | |||
| 51 | adc.do_offset_calibration(); | ||
| 52 | adc.do_auto_calibration(); | ||
| 53 | |||
| 54 | let mut conv_command_config = adc.get_default_conv_command_config(); | ||
| 55 | conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; | ||
| 56 | conv_command_config.conversion_resolution_mode = Mode::Data16Bits; | ||
| 57 | adc.set_conv_command_config(1, &conv_command_config); | ||
| 58 | |||
| 59 | let mut conv_trigger_config = adc.get_default_conv_trigger_config(); | ||
| 60 | conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; | ||
| 61 | conv_trigger_config.enable_hardware_trigger = false; | ||
| 62 | adc.set_conv_trigger_config(0, &conv_trigger_config); | ||
| 63 | |||
| 64 | defmt::info!("ADC configuration done..."); | ||
| 65 | |||
| 66 | adc.enable_interrupt(0x1); | ||
| 67 | |||
| 68 | unsafe { | ||
| 69 | hal::interrupt::ADC1.enable(); | ||
| 70 | } | ||
| 71 | |||
| 72 | unsafe { | ||
| 73 | cortex_m::interrupt::enable(); | ||
| 74 | } | ||
| 75 | |||
| 76 | loop { | ||
| 77 | adc.do_software_trigger(1); | ||
| 78 | while !adc.is_interrupt_triggered() { | ||
| 79 | // Wait until the interrupt is triggered | ||
| 80 | } | ||
| 81 | defmt::info!("*** ADC interrupt TRIGGERED! ***"); | ||
| 82 | //TBD need to print the value | ||
| 83 | } | ||
| 84 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/adc_polling.rs b/embassy-mcxa/examples/src/bin/adc_polling.rs new file mode 100644 index 000000000..ddf3f586b --- /dev/null +++ b/embassy-mcxa/examples/src/bin/adc_polling.rs | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_mcxa_examples::init_adc_pins; | ||
| 6 | use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; | ||
| 7 | use hal::clocks::periph_helpers::{AdcClockSel, Div4}; | ||
| 8 | use hal::clocks::PoweredClock; | ||
| 9 | use hal::pac::adc1::cfg::{Pwrsel, Refsel}; | ||
| 10 | use hal::pac::adc1::cmdl1::{Adch, Mode}; | ||
| 11 | use hal::pac::adc1::ctrl::CalAvgs; | ||
| 12 | use hal::pac::adc1::tctrl::Tcmd; | ||
| 13 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 14 | |||
| 15 | const G_LPADC_RESULT_SHIFT: u32 = 0; | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async fn main(_spawner: Spawner) { | ||
| 19 | let p = hal::init(hal::config::Config::default()); | ||
| 20 | |||
| 21 | unsafe { | ||
| 22 | init_adc_pins(); | ||
| 23 | } | ||
| 24 | |||
| 25 | defmt::info!("=== ADC polling Example ==="); | ||
| 26 | |||
| 27 | let adc_config = LpadcConfig { | ||
| 28 | enable_in_doze_mode: true, | ||
| 29 | conversion_average_mode: CalAvgs::Average128, | ||
| 30 | enable_analog_preliminary: true, | ||
| 31 | power_up_delay: 0x80, | ||
| 32 | reference_voltage_source: Refsel::Option3, | ||
| 33 | power_level_mode: Pwrsel::Lowest, | ||
| 34 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, | ||
| 35 | enable_conv_pause: false, | ||
| 36 | conv_pause_delay: 0, | ||
| 37 | fifo_watermark: 0, | ||
| 38 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 39 | source: AdcClockSel::FroLfDiv, | ||
| 40 | div: Div4::no_div(), | ||
| 41 | }; | ||
| 42 | let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); | ||
| 43 | |||
| 44 | adc.do_offset_calibration(); | ||
| 45 | adc.do_auto_calibration(); | ||
| 46 | |||
| 47 | let mut conv_command_config = adc.get_default_conv_command_config(); | ||
| 48 | conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; | ||
| 49 | conv_command_config.conversion_resolution_mode = Mode::Data16Bits; | ||
| 50 | adc.set_conv_command_config(1, &conv_command_config); | ||
| 51 | |||
| 52 | let mut conv_trigger_config = adc.get_default_conv_trigger_config(); | ||
| 53 | conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; | ||
| 54 | conv_trigger_config.enable_hardware_trigger = false; | ||
| 55 | adc.set_conv_trigger_config(0, &conv_trigger_config); | ||
| 56 | |||
| 57 | defmt::info!("=== ADC configuration done... ==="); | ||
| 58 | |||
| 59 | loop { | ||
| 60 | adc.do_software_trigger(1); | ||
| 61 | let mut result: Option<ConvResult> = None; | ||
| 62 | while result.is_none() { | ||
| 63 | result = hal::adc::get_conv_result(); | ||
| 64 | } | ||
| 65 | let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; | ||
| 66 | defmt::info!("value: {=u16}", value); | ||
| 67 | } | ||
| 68 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/blinky.rs b/embassy-mcxa/examples/src/bin/blinky.rs new file mode 100644 index 000000000..dd08ec0d9 --- /dev/null +++ b/embassy-mcxa/examples/src/bin/blinky.rs | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_time::Timer; | ||
| 6 | use hal::gpio::{DriveStrength, Level, Output, SlewRate}; | ||
| 7 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let p = hal::init(hal::config::Config::default()); | ||
| 12 | |||
| 13 | defmt::info!("Blink example"); | ||
| 14 | |||
| 15 | let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast); | ||
| 16 | let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast); | ||
| 17 | let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast); | ||
| 18 | |||
| 19 | loop { | ||
| 20 | defmt::info!("Toggle LEDs"); | ||
| 21 | |||
| 22 | red.toggle(); | ||
| 23 | Timer::after_millis(250).await; | ||
| 24 | |||
| 25 | red.toggle(); | ||
| 26 | green.toggle(); | ||
| 27 | Timer::after_millis(250).await; | ||
| 28 | |||
| 29 | green.toggle(); | ||
| 30 | blue.toggle(); | ||
| 31 | Timer::after_millis(250).await; | ||
| 32 | blue.toggle(); | ||
| 33 | |||
| 34 | Timer::after_millis(250).await; | ||
| 35 | } | ||
| 36 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/button.rs b/embassy-mcxa/examples/src/bin/button.rs new file mode 100644 index 000000000..943edbb15 --- /dev/null +++ b/embassy-mcxa/examples/src/bin/button.rs | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_time::Timer; | ||
| 6 | use hal::gpio::{Input, Pull}; | ||
| 7 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let p = hal::init(hal::config::Config::default()); | ||
| 12 | |||
| 13 | defmt::info!("Button example"); | ||
| 14 | |||
| 15 | // This button is labeled "WAKEUP" on the FRDM-MCXA276 | ||
| 16 | // The board already has a 10K pullup | ||
| 17 | let monitor = Input::new(p.P1_7, Pull::Disabled); | ||
| 18 | |||
| 19 | loop { | ||
| 20 | defmt::info!("Pin level is {:?}", monitor.get_level()); | ||
| 21 | Timer::after_millis(1000).await; | ||
| 22 | } | ||
| 23 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/button_async.rs b/embassy-mcxa/examples/src/bin/button_async.rs new file mode 100644 index 000000000..6cc7b62cd --- /dev/null +++ b/embassy-mcxa/examples/src/bin/button_async.rs | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_time::Timer; | ||
| 6 | use hal::gpio::{Input, Pull}; | ||
| 7 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let p = hal::init(hal::config::Config::default()); | ||
| 12 | |||
| 13 | defmt::info!("GPIO interrupt example"); | ||
| 14 | |||
| 15 | // This button is labeled "WAKEUP" on the FRDM-MCXA276 | ||
| 16 | // The board already has a 10K pullup | ||
| 17 | let mut pin = Input::new(p.P1_7, Pull::Disabled); | ||
| 18 | |||
| 19 | let mut press_count = 0u32; | ||
| 20 | |||
| 21 | loop { | ||
| 22 | pin.wait_for_falling_edge().await; | ||
| 23 | |||
| 24 | press_count += 1; | ||
| 25 | |||
| 26 | defmt::info!("Button pressed! Count: {}", press_count); | ||
| 27 | Timer::after_millis(50).await; | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/clkout.rs b/embassy-mcxa/examples/src/bin/clkout.rs new file mode 100644 index 000000000..bfd963540 --- /dev/null +++ b/embassy-mcxa/examples/src/bin/clkout.rs | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4}; | ||
| 6 | use embassy_mcxa::clocks::PoweredClock; | ||
| 7 | use embassy_mcxa::gpio::{DriveStrength, SlewRate}; | ||
| 8 | use embassy_mcxa::{Level, Output}; | ||
| 9 | use embassy_time::Timer; | ||
| 10 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 11 | |||
| 12 | /// Demonstrate CLKOUT, using Pin P4.2 | ||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let p = hal::init(hal::config::Config::default()); | ||
| 16 | let mut pin = p.P4_2; | ||
| 17 | let mut clkout = p.CLKOUT; | ||
| 18 | |||
| 19 | loop { | ||
| 20 | defmt::info!("Set Low..."); | ||
| 21 | let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); | ||
| 22 | Timer::after_millis(500).await; | ||
| 23 | |||
| 24 | defmt::info!("Set High..."); | ||
| 25 | output.set_high(); | ||
| 26 | Timer::after_millis(400).await; | ||
| 27 | |||
| 28 | defmt::info!("Set Low..."); | ||
| 29 | output.set_low(); | ||
| 30 | Timer::after_millis(500).await; | ||
| 31 | |||
| 32 | defmt::info!("16k..."); | ||
| 33 | // Run Clock Out with the 16K clock | ||
| 34 | let _clock_out = ClockOut::new( | ||
| 35 | clkout.reborrow(), | ||
| 36 | pin.reborrow(), | ||
| 37 | Config { | ||
| 38 | sel: ClockOutSel::Clk16K, | ||
| 39 | div: Div4::no_div(), | ||
| 40 | level: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 41 | }, | ||
| 42 | ) | ||
| 43 | .unwrap(); | ||
| 44 | |||
| 45 | Timer::after_millis(3000).await; | ||
| 46 | |||
| 47 | defmt::info!("Set Low..."); | ||
| 48 | drop(_clock_out); | ||
| 49 | |||
| 50 | let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); | ||
| 51 | Timer::after_millis(500).await; | ||
| 52 | |||
| 53 | // Run Clock Out with the 12M clock, divided by 3 | ||
| 54 | defmt::info!("4M..."); | ||
| 55 | let _clock_out = ClockOut::new( | ||
| 56 | clkout.reborrow(), | ||
| 57 | pin.reborrow(), | ||
| 58 | Config { | ||
| 59 | sel: ClockOutSel::Fro12M, | ||
| 60 | div: const { Div4::from_divisor(3).unwrap() }, | ||
| 61 | level: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 62 | }, | ||
| 63 | ) | ||
| 64 | .unwrap(); | ||
| 65 | |||
| 66 | // Let it run for 3 seconds... | ||
| 67 | Timer::after_millis(3000).await; | ||
| 68 | } | ||
| 69 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/hello.rs b/embassy-mcxa/examples/src/bin/hello.rs new file mode 100644 index 000000000..e371d9413 --- /dev/null +++ b/embassy-mcxa/examples/src/bin/hello.rs | |||
| @@ -0,0 +1,119 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_mcxa::clocks::config::Div8; | ||
| 6 | use hal::lpuart::{Blocking, Config, Lpuart}; | ||
| 7 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 8 | |||
| 9 | /// Simple helper to write a byte as hex to UART | ||
| 10 | fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) { | ||
| 11 | const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; | ||
| 12 | let _ = uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); | ||
| 13 | let _ = uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); | ||
| 14 | } | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut cfg = hal::config::Config::default(); | ||
| 19 | cfg.clock_cfg.sirc.fro_12m_enabled = true; | ||
| 20 | cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div()); | ||
| 21 | let p = hal::init(cfg); | ||
| 22 | |||
| 23 | defmt::info!("boot"); | ||
| 24 | |||
| 25 | // Create UART configuration | ||
| 26 | let config = Config { | ||
| 27 | baudrate_bps: 115_200, | ||
| 28 | ..Default::default() | ||
| 29 | }; | ||
| 30 | |||
| 31 | // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX | ||
| 32 | let mut uart = Lpuart::new_blocking( | ||
| 33 | p.LPUART2, // Peripheral | ||
| 34 | p.P2_2, // TX pin | ||
| 35 | p.P2_3, // RX pin | ||
| 36 | config, | ||
| 37 | ) | ||
| 38 | .unwrap(); | ||
| 39 | |||
| 40 | // Print welcome message before any async delays to guarantee early console output | ||
| 41 | uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); | ||
| 42 | uart.write_str_blocking("Available commands:\r\n"); | ||
| 43 | uart.write_str_blocking(" help - Show this help\r\n"); | ||
| 44 | uart.write_str_blocking(" echo <text> - Echo back the text\r\n"); | ||
| 45 | uart.write_str_blocking(" hex <byte> - Display byte in hex (0-255)\r\n"); | ||
| 46 | uart.write_str_blocking("Type a command: "); | ||
| 47 | |||
| 48 | let mut buffer = [0u8; 64]; | ||
| 49 | let mut buf_idx = 0; | ||
| 50 | |||
| 51 | loop { | ||
| 52 | // Read a byte from UART | ||
| 53 | let byte = uart.read_byte_blocking(); | ||
| 54 | |||
| 55 | // Echo the character back | ||
| 56 | if byte == b'\r' || byte == b'\n' { | ||
| 57 | // Enter pressed - process command | ||
| 58 | uart.write_str_blocking("\r\n"); | ||
| 59 | |||
| 60 | if buf_idx > 0 { | ||
| 61 | let command = &buffer[0..buf_idx]; | ||
| 62 | |||
| 63 | if command == b"help" { | ||
| 64 | uart.write_str_blocking("Available commands:\r\n"); | ||
| 65 | uart.write_str_blocking(" help - Show this help\r\n"); | ||
| 66 | uart.write_str_blocking(" echo <text> - Echo back the text\r\n"); | ||
| 67 | uart.write_str_blocking(" hex <byte> - Display byte in hex (0-255)\r\n"); | ||
| 68 | } else if command.starts_with(b"echo ") && command.len() > 5 { | ||
| 69 | uart.write_str_blocking("Echo: "); | ||
| 70 | uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or("")); | ||
| 71 | uart.write_str_blocking("\r\n"); | ||
| 72 | } else if command.starts_with(b"hex ") && command.len() > 4 { | ||
| 73 | // Parse the byte value | ||
| 74 | let num_str = &command[4..]; | ||
| 75 | if let Ok(num) = parse_u8(num_str) { | ||
| 76 | uart.write_str_blocking("Hex: 0x"); | ||
| 77 | write_hex_byte(&mut uart, num); | ||
| 78 | uart.write_str_blocking("\r\n"); | ||
| 79 | } else { | ||
| 80 | uart.write_str_blocking("Invalid number for hex command\r\n"); | ||
| 81 | } | ||
| 82 | } else if !command.is_empty() { | ||
| 83 | uart.write_str_blocking("Unknown command: "); | ||
| 84 | uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); | ||
| 85 | uart.write_str_blocking("\r\n"); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | // Reset buffer and prompt | ||
| 90 | buf_idx = 0; | ||
| 91 | uart.write_str_blocking("Type a command: "); | ||
| 92 | } else if byte == 8 || byte == 127 { | ||
| 93 | // Backspace | ||
| 94 | if buf_idx > 0 { | ||
| 95 | buf_idx -= 1; | ||
| 96 | uart.write_str_blocking("\x08 \x08"); // Erase character | ||
| 97 | } | ||
| 98 | } else if buf_idx < buffer.len() - 1 { | ||
| 99 | // Regular character | ||
| 100 | buffer[buf_idx] = byte; | ||
| 101 | buf_idx += 1; | ||
| 102 | let _ = uart.write_byte(byte); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | /// Simple parser for u8 from ASCII bytes | ||
| 108 | fn parse_u8(bytes: &[u8]) -> Result<u8, ()> { | ||
| 109 | let mut result = 0u8; | ||
| 110 | for &b in bytes { | ||
| 111 | if b.is_ascii_digit() { | ||
| 112 | result = result.checked_mul(10).ok_or(())?; | ||
| 113 | result = result.checked_add(b - b'0').ok_or(())?; | ||
| 114 | } else { | ||
| 115 | return Err(()); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | Ok(result) | ||
| 119 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/i2c-async.rs b/embassy-mcxa/examples/src/bin/i2c-async.rs new file mode 100644 index 000000000..47b5f3cbe --- /dev/null +++ b/embassy-mcxa/examples/src/bin/i2c-async.rs | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_time::Timer; | ||
| 6 | use hal::bind_interrupts; | ||
| 7 | use hal::clocks::config::Div8; | ||
| 8 | use hal::config::Config; | ||
| 9 | use hal::i2c::controller::{self, I2c, Speed}; | ||
| 10 | use hal::i2c::InterruptHandler; | ||
| 11 | use hal::peripherals::LPI2C3; | ||
| 12 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!( | ||
| 15 | struct Irqs { | ||
| 16 | LPI2C3 => InterruptHandler<LPI2C3>; | ||
| 17 | } | ||
| 18 | ); | ||
| 19 | |||
| 20 | #[embassy_executor::main] | ||
| 21 | async fn main(_spawner: Spawner) { | ||
| 22 | let mut config = Config::default(); | ||
| 23 | config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); | ||
| 24 | |||
| 25 | let p = hal::init(config); | ||
| 26 | |||
| 27 | defmt::info!("I2C example"); | ||
| 28 | |||
| 29 | let mut config = controller::Config::default(); | ||
| 30 | config.speed = Speed::Standard; | ||
| 31 | let mut i2c = I2c::new_async(p.LPI2C3, p.P3_27, p.P3_28, Irqs, config).unwrap(); | ||
| 32 | let mut buf = [0u8; 2]; | ||
| 33 | |||
| 34 | loop { | ||
| 35 | i2c.async_write_read(0x48, &[0x00], &mut buf).await.unwrap(); | ||
| 36 | defmt::info!("Buffer: {:02x}", buf); | ||
| 37 | Timer::after_secs(1).await; | ||
| 38 | } | ||
| 39 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/i2c-blocking.rs b/embassy-mcxa/examples/src/bin/i2c-blocking.rs new file mode 100644 index 000000000..0f6c8cbae --- /dev/null +++ b/embassy-mcxa/examples/src/bin/i2c-blocking.rs | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_time::Timer; | ||
| 6 | use hal::clocks::config::Div8; | ||
| 7 | use hal::config::Config; | ||
| 8 | use hal::i2c::controller::{self, I2c, Speed}; | ||
| 9 | use tmp108::Tmp108; | ||
| 10 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let mut config = Config::default(); | ||
| 15 | config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); | ||
| 16 | |||
| 17 | let p = hal::init(config); | ||
| 18 | |||
| 19 | defmt::info!("I2C example"); | ||
| 20 | |||
| 21 | let mut config = controller::Config::default(); | ||
| 22 | config.speed = Speed::Standard; | ||
| 23 | let i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap(); | ||
| 24 | let mut tmp = Tmp108::new_with_a0_gnd(i2c); | ||
| 25 | |||
| 26 | loop { | ||
| 27 | let temperature = tmp.temperature().unwrap(); | ||
| 28 | defmt::info!("Temperature: {}C", temperature); | ||
| 29 | Timer::after_secs(1).await; | ||
| 30 | } | ||
| 31 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/i2c-scan-blocking.rs b/embassy-mcxa/examples/src/bin/i2c-scan-blocking.rs new file mode 100644 index 000000000..4e203597b --- /dev/null +++ b/embassy-mcxa/examples/src/bin/i2c-scan-blocking.rs | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_mcxa::gpio::Pull; | ||
| 6 | use embassy_mcxa::Input; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use hal::clocks::config::Div8; | ||
| 9 | use hal::config::Config; | ||
| 10 | use hal::i2c::controller::{self, I2c, Speed}; | ||
| 11 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let mut config = Config::default(); | ||
| 16 | config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); | ||
| 17 | |||
| 18 | let p = hal::init(config); | ||
| 19 | |||
| 20 | defmt::info!("I2C example"); | ||
| 21 | |||
| 22 | let mut config = controller::Config::default(); | ||
| 23 | config.speed = Speed::Standard; | ||
| 24 | |||
| 25 | // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and | ||
| 26 | // defaults to SWO on the debug peripheral. Explicitly make it a high-z | ||
| 27 | // input. | ||
| 28 | let _pin = Input::new(p.P0_2, Pull::Disabled); | ||
| 29 | let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap(); | ||
| 30 | |||
| 31 | for addr in 0x01..=0x7f { | ||
| 32 | let result = i2c.blocking_write(addr, &[]); | ||
| 33 | if result.is_ok() { | ||
| 34 | defmt::info!("Device found at addr {:02x}", addr); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | loop { | ||
| 39 | Timer::after_secs(10).await; | ||
| 40 | } | ||
| 41 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/lpuart_buffered.rs b/embassy-mcxa/examples/src/bin/lpuart_buffered.rs new file mode 100644 index 000000000..420589d00 --- /dev/null +++ b/embassy-mcxa/examples/src/bin/lpuart_buffered.rs | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_mcxa::clocks::config::Div8; | ||
| 6 | use embassy_mcxa::lpuart::buffered::BufferedLpuart; | ||
| 7 | use embassy_mcxa::lpuart::Config; | ||
| 8 | use embassy_mcxa::{bind_interrupts, lpuart}; | ||
| 9 | use embedded_io_async::Write; | ||
| 10 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 11 | |||
| 12 | // Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver | ||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | LPUART2 => lpuart::buffered::BufferedInterruptHandler::<hal::peripherals::LPUART2>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async fn main(_spawner: Spawner) { | ||
| 19 | let mut cfg = hal::config::Config::default(); | ||
| 20 | cfg.clock_cfg.sirc.fro_12m_enabled = true; | ||
| 21 | cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div()); | ||
| 22 | let p = hal::init(cfg); | ||
| 23 | |||
| 24 | // Configure NVIC for LPUART2 | ||
| 25 | hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); | ||
| 26 | |||
| 27 | // UART configuration (enable both TX and RX) | ||
| 28 | let config = Config { | ||
| 29 | baudrate_bps: 115_200, | ||
| 30 | rx_fifo_watermark: 0, | ||
| 31 | tx_fifo_watermark: 0, | ||
| 32 | ..Default::default() | ||
| 33 | }; | ||
| 34 | |||
| 35 | let mut tx_buf = [0u8; 256]; | ||
| 36 | let mut rx_buf = [0u8; 256]; | ||
| 37 | |||
| 38 | // Create a buffered LPUART2 instance with both TX and RX | ||
| 39 | let mut uart = BufferedLpuart::new( | ||
| 40 | p.LPUART2, | ||
| 41 | p.P2_2, // TX pin | ||
| 42 | p.P2_3, // RX pin | ||
| 43 | Irqs, | ||
| 44 | &mut tx_buf, | ||
| 45 | &mut rx_buf, | ||
| 46 | config, | ||
| 47 | ) | ||
| 48 | .unwrap(); | ||
| 49 | |||
| 50 | // Split into TX and RX parts | ||
| 51 | let (tx, rx) = uart.split_ref(); | ||
| 52 | |||
| 53 | tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); | ||
| 54 | tx.write(b"Type characters to echo them back.\r\n").await.unwrap(); | ||
| 55 | |||
| 56 | // Echo loop | ||
| 57 | let mut buf = [0u8; 4]; | ||
| 58 | loop { | ||
| 59 | let used = rx.read(&mut buf).await.unwrap(); | ||
| 60 | tx.write_all(&buf[..used]).await.unwrap(); | ||
| 61 | } | ||
| 62 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/lpuart_polling.rs b/embassy-mcxa/examples/src/bin/lpuart_polling.rs new file mode 100644 index 000000000..b80668834 --- /dev/null +++ b/embassy-mcxa/examples/src/bin/lpuart_polling.rs | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_mcxa::clocks::config::Div8; | ||
| 6 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 7 | |||
| 8 | use crate::hal::lpuart::{Config, Lpuart}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let mut cfg = hal::config::Config::default(); | ||
| 13 | cfg.clock_cfg.sirc.fro_12m_enabled = true; | ||
| 14 | cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div()); | ||
| 15 | let p = hal::init(cfg); | ||
| 16 | |||
| 17 | defmt::info!("boot"); | ||
| 18 | |||
| 19 | // Create UART configuration | ||
| 20 | let config = Config { | ||
| 21 | baudrate_bps: 115_200, | ||
| 22 | ..Default::default() | ||
| 23 | }; | ||
| 24 | |||
| 25 | // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX | ||
| 26 | let lpuart = Lpuart::new_blocking( | ||
| 27 | p.LPUART2, // Peripheral | ||
| 28 | p.P2_2, // TX pin | ||
| 29 | p.P2_3, // RX pin | ||
| 30 | config, | ||
| 31 | ) | ||
| 32 | .unwrap(); | ||
| 33 | |||
| 34 | // Split into separate TX and RX parts | ||
| 35 | let (mut tx, mut rx) = lpuart.split(); | ||
| 36 | |||
| 37 | // Write hello messages | ||
| 38 | tx.blocking_write(b"Hello world.\r\n").unwrap(); | ||
| 39 | tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap(); | ||
| 40 | |||
| 41 | // Echo loop | ||
| 42 | loop { | ||
| 43 | let mut buf = [0u8; 1]; | ||
| 44 | rx.blocking_read(&mut buf).unwrap(); | ||
| 45 | tx.blocking_write(&buf).unwrap(); | ||
| 46 | } | ||
| 47 | } | ||
diff --git a/embassy-mcxa/examples/src/bin/rtc_alarm.rs b/embassy-mcxa/examples/src/bin/rtc_alarm.rs new file mode 100644 index 000000000..fe355888b --- /dev/null +++ b/embassy-mcxa/examples/src/bin/rtc_alarm.rs | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_mcxa::bind_interrupts; | ||
| 6 | use hal::rtc::{InterruptHandler, Rtc, RtcDateTime}; | ||
| 7 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 8 | |||
| 9 | bind_interrupts!(struct Irqs { | ||
| 10 | RTC => InterruptHandler<hal::rtc::Rtc0>; | ||
| 11 | }); | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let p = hal::init(hal::config::Config::default()); | ||
| 16 | |||
| 17 | defmt::info!("=== RTC Alarm Example ==="); | ||
| 18 | |||
| 19 | let rtc_config = hal::rtc::get_default_config(); | ||
| 20 | |||
| 21 | let mut rtc = Rtc::new(p.RTC0, Irqs, rtc_config); | ||
| 22 | |||
| 23 | let now = RtcDateTime { | ||
| 24 | year: 2025, | ||
| 25 | month: 10, | ||
| 26 | day: 15, | ||
| 27 | hour: 14, | ||
| 28 | minute: 30, | ||
| 29 | second: 0, | ||
| 30 | }; | ||
| 31 | |||
| 32 | rtc.stop(); | ||
| 33 | |||
| 34 | defmt::info!("Time set to: 2025-10-15 14:30:00"); | ||
| 35 | rtc.set_datetime(now); | ||
| 36 | |||
| 37 | let mut alarm = now; | ||
| 38 | alarm.second += 10; | ||
| 39 | |||
| 40 | defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)"); | ||
| 41 | defmt::info!("RTC started, waiting for alarm..."); | ||
| 42 | |||
| 43 | rtc.wait_for_alarm(alarm).await; | ||
| 44 | defmt::info!("*** ALARM TRIGGERED! ***"); | ||
| 45 | |||
| 46 | defmt::info!("Example complete - Test PASSED!"); | ||
| 47 | } | ||
diff --git a/embassy-mcxa/examples/src/lib.rs b/embassy-mcxa/examples/src/lib.rs new file mode 100644 index 000000000..2573a6adc --- /dev/null +++ b/embassy-mcxa/examples/src/lib.rs | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![allow(clippy::missing_safety_doc)] | ||
| 3 | |||
| 4 | //! Shared board-specific helpers for the FRDM-MCXA276 examples. | ||
| 5 | //! These live with the examples so the HAL stays generic. | ||
| 6 | |||
| 7 | use hal::{clocks, pins}; | ||
| 8 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 9 | |||
| 10 | /// Initialize clocks and pin muxing for ADC. | ||
| 11 | pub unsafe fn init_adc_pins() { | ||
| 12 | // NOTE: Lpuart has been updated to properly enable + reset its own clocks. | ||
| 13 | // GPIO has not. | ||
| 14 | _ = clocks::enable_and_reset::<hal::peripherals::PORT1>(&clocks::periph_helpers::NoConfig); | ||
| 15 | pins::configure_adc_pins(); | ||
| 16 | } | ||
diff --git a/embassy-mcxa/ram.ld b/embassy-mcxa/ram.ld new file mode 100644 index 000000000..816ab6819 --- /dev/null +++ b/embassy-mcxa/ram.ld | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | /* Simple RAM execution linker script for MCXA276 */ | ||
| 2 | MEMORY | ||
| 3 | { | ||
| 4 | RAM : ORIGIN = 0x20000000, LENGTH = 128K | ||
| 5 | } | ||
| 6 | |||
| 7 | /* Pull in device default interrupt symbol aliases (e.g., CMC = DefaultHandler) */ | ||
| 8 | INCLUDE device.x | ||
| 9 | |||
| 10 | |||
| 11 | /* Provide core exception weak aliases if not supplied by cortex-m-rt's link.x */ | ||
| 12 | PROVIDE(NonMaskableInt = DefaultHandler); | ||
| 13 | PROVIDE(HardFault = DefaultHandler); | ||
| 14 | PROVIDE(MemoryManagement = DefaultHandler); | ||
| 15 | PROVIDE(BusFault = DefaultHandler); | ||
| 16 | PROVIDE(UsageFault = DefaultHandler); | ||
| 17 | PROVIDE(SecureFault = DefaultHandler); | ||
| 18 | PROVIDE(SVCall = DefaultHandler); | ||
| 19 | PROVIDE(DebugMonitor = DefaultHandler); | ||
| 20 | PROVIDE(PendSV = DefaultHandler); | ||
| 21 | PROVIDE(SysTick = DefaultHandler); | ||
| 22 | |||
| 23 | /* In RAM-run we have no FLASH sidata; copy from sdata */ | ||
| 24 | __sidata = __sdata; | ||
| 25 | |||
| 26 | /* Ensure the PAC interrupt table is kept */ | ||
| 27 | EXTERN(__INTERRUPTS); | ||
| 28 | |||
| 29 | |||
| 30 | /* Pull in defmt's linker script to generate the defmt table that host decoders expect */ | ||
| 31 | INCLUDE defmt.x | ||
| 32 | |||
| 33 | ENTRY(Reset) | ||
| 34 | EXTERN(VECTOR_TABLE) | ||
| 35 | EXTERN(Reset) | ||
| 36 | EXTERN(main) | ||
| 37 | |||
| 38 | /* Define _stack_start at end of RAM BEFORE it's used in vector table */ | ||
| 39 | _stack_start = ORIGIN(RAM) + LENGTH(RAM); | ||
| 40 | |||
| 41 | SECTIONS | ||
| 42 | { | ||
| 43 | .vector_table ORIGIN(RAM) : | ||
| 44 | { | ||
| 45 | /* Slot 0: Initial stack pointer - use our explicitly set _stack_start */ | ||
| 46 | LONG(_stack_start); | ||
| 47 | /* Slot 1: Reset vector - address of Reset function with Thumb bit set */ | ||
| 48 | LONG(Reset | 1); | ||
| 49 | /* Cortex-M33 core exceptions (slots 2-14) */ | ||
| 50 | KEEP(*(.vector_table.exceptions)); | ||
| 51 | /* Peripheral interrupt vectors provided by PAC (slots 16+) */ | ||
| 52 | KEEP(*(.vector_table.interrupts)); | ||
| 53 | } > RAM | ||
| 54 | |||
| 55 | .text : | ||
| 56 | { | ||
| 57 | KEEP(*(.text.Reset)); | ||
| 58 | KEEP(*(.text.main)); | ||
| 59 | *(.text .text.*); | ||
| 60 | } > RAM | ||
| 61 | |||
| 62 | /* Keep defmt table and fragments so host decoders can find metadata */ | ||
| 63 | .defmt : | ||
| 64 | { | ||
| 65 | KEEP(*(.defmt)); | ||
| 66 | KEEP(*(.defmt.*)); | ||
| 67 | } > RAM | ||
| 68 | |||
| 69 | .rodata : | ||
| 70 | { | ||
| 71 | *(.rodata .rodata.*); | ||
| 72 | } > RAM | ||
| 73 | |||
| 74 | .data : | ||
| 75 | { | ||
| 76 | . = ALIGN(4); | ||
| 77 | __sdata = .; | ||
| 78 | *(.data .data.*); | ||
| 79 | . = ALIGN(4); | ||
| 80 | __edata = .; | ||
| 81 | } > RAM | ||
| 82 | |||
| 83 | /* Ensure RTT control block with "SEGGER RTT" signature is loaded to RAM */ | ||
| 84 | .rtt : | ||
| 85 | { | ||
| 86 | KEEP(*(.rtt)); | ||
| 87 | } > RAM | ||
| 88 | |||
| 89 | /* Place uninitialized buffers (like defmt-rtt) in RAM; load is fine for RAM-run */ | ||
| 90 | .uninit : | ||
| 91 | { | ||
| 92 | *(.uninit .uninit.*); | ||
| 93 | } > RAM | ||
| 94 | |||
| 95 | .bss : | ||
| 96 | { | ||
| 97 | . = ALIGN(4); | ||
| 98 | __sbss = .; | ||
| 99 | *(.bss .bss.*); | ||
| 100 | . = ALIGN(4); | ||
| 101 | __ebss = .; | ||
| 102 | } > RAM | ||
| 103 | |||
| 104 | /* Discard exception unwinding info */ | ||
| 105 | /DISCARD/ : | ||
| 106 | { | ||
| 107 | *(.ARM.exidx .ARM.exidx.*); | ||
| 108 | } | ||
| 109 | } | ||
diff --git a/embassy-mcxa/run.sh b/embassy-mcxa/run.sh new file mode 100644 index 000000000..418dc8a24 --- /dev/null +++ b/embassy-mcxa/run.sh | |||
| @@ -0,0 +1,93 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | set -euo pipefail | ||
| 3 | |||
| 4 | ELF="${1:-}" | ||
| 5 | if [[ -z "${ELF}" ]]; then | ||
| 6 | echo "Usage: $0 <elf_file>" | ||
| 7 | exit 1 | ||
| 8 | fi | ||
| 9 | if [[ ! -f "${ELF}" ]]; then | ||
| 10 | echo "ELF not found: ${ELF}" | ||
| 11 | exit 1 | ||
| 12 | fi | ||
| 13 | |||
| 14 | # Configurable via env | ||
| 15 | CHIP="${CHIP:-MCXA276}" | ||
| 16 | SPEED="${PROBE_SPEED:-1000}" # kHz | ||
| 17 | # Default to J-Link if PROBE not provided | ||
| 18 | PROBE_OPT=(--probe "${PROBE:-1366:0101:000600110607}") | ||
| 19 | PORT="${PROBE_RS_GDB_PORT:-1337}" | ||
| 20 | |||
| 21 | cleanup() { | ||
| 22 | if [[ -n "${GDB_SERVER_PID:-}" ]]; then kill "${GDB_SERVER_PID}" 2>/dev/null || true; fi | ||
| 23 | [[ -n "${GDB_SCRIPT:-}" ]] && rm -f "${GDB_SCRIPT}" || true | ||
| 24 | [[ -n "${SERVER_LOG:-}" ]] && rm -f "${SERVER_LOG}" || true | ||
| 25 | } | ||
| 26 | trap cleanup EXIT | ||
| 27 | |||
| 28 | if ! command -v probe-rs >/dev/null 2>&1; then | ||
| 29 | echo "probe-rs not found (cargo install probe-rs --features cli)" | ||
| 30 | exit 1 | ||
| 31 | fi | ||
| 32 | if ! command -v gdb-multiarch >/dev/null 2>&1; then | ||
| 33 | echo "gdb-multiarch not found; install it (e.g., sudo apt install gdb-multiarch)." | ||
| 34 | exit 1 | ||
| 35 | fi | ||
| 36 | |||
| 37 | # Start probe-rs GDB server and capture its output to a log (do not hide errors) | ||
| 38 | SERVER_LOG=$(mktemp) | ||
| 39 | set +e | ||
| 40 | probe-rs gdb --chip "${CHIP}" --protocol swd --speed "${SPEED}" --non-interactive "${ELF}" "${PROBE_OPT[@]}" \ | ||
| 41 | >"${SERVER_LOG}" 2>&1 & | ||
| 42 | GDB_SERVER_PID=$! | ||
| 43 | set -e | ||
| 44 | |||
| 45 | # Wait for server readiness without touching the TCP port to avoid corrupting the GDB protocol | ||
| 46 | ready="" | ||
| 47 | for _ in {1..50}; do | ||
| 48 | if grep -q "Firing up GDB stub" "${SERVER_LOG}"; then ready=1; break; fi | ||
| 49 | if grep -q "Connecting to the chip was unsuccessful" "${SERVER_LOG}"; then | ||
| 50 | echo "probe-rs gdb server failed to connect to target. Log:" >&2 | ||
| 51 | echo "----- probe-rs gdb log -----" >&2 | ||
| 52 | sed -e 's/^/ /' "${SERVER_LOG}" >&2 || true | ||
| 53 | exit 1 | ||
| 54 | fi | ||
| 55 | sleep 0.1 | ||
| 56 | done | ||
| 57 | if [[ -z "${ready}" ]]; then | ||
| 58 | echo "probe-rs gdb server did not report readiness. Log:" >&2 | ||
| 59 | echo "----- probe-rs gdb log -----" >&2 | ||
| 60 | sed -e 's/^/ /' "${SERVER_LOG}" >&2 || true | ||
| 61 | exit 1 | ||
| 62 | fi | ||
| 63 | |||
| 64 | # GDB script: load to RAM and run, no reset | ||
| 65 | GDB_SCRIPT=$(mktemp) | ||
| 66 | cat >"${GDB_SCRIPT}" <<EOF | ||
| 67 | set pagination off | ||
| 68 | set confirm off | ||
| 69 | set mem inaccessible-by-default off | ||
| 70 | |||
| 71 | # Connect and load without reset | ||
| 72 | target remote :${PORT} | ||
| 73 | monitor halt | ||
| 74 | load | ||
| 75 | # Set VTOR to point to our RAM vector table at 0x20000000 | ||
| 76 | # This ensures the CPU uses the correct initial SP and Reset vector | ||
| 77 | set *0xE000ED08 = 0x20000000 | ||
| 78 | # Now read SP and PC from our vector table and set them | ||
| 79 | set \$sp = *(unsigned int*)0x20000000 | ||
| 80 | set \$pc = *(unsigned int*)0x20000004 | ||
| 81 | # Run target (blocks here until you Ctrl+C, like before) | ||
| 82 | continue | ||
| 83 | EOF | ||
| 84 | |||
| 85 | # Run gdb against the server | ||
| 86 | if ! gdb-multiarch -q -batch -x "${GDB_SCRIPT}" "${ELF}"; then | ||
| 87 | echo "GDB failed to load/run. probe-rs gdb server log:" >&2 | ||
| 88 | echo "----- probe-rs gdb log -----" >&2 | ||
| 89 | sed -e 's/^/ /' "${SERVER_LOG}" >&2 || true | ||
| 90 | exit 1 | ||
| 91 | fi | ||
| 92 | |||
| 93 | echo "Program loaded and started (no reset)" | ||
diff --git a/embassy-mcxa/rustfmt.toml b/embassy-mcxa/rustfmt.toml new file mode 100644 index 000000000..9eb3c3b4f --- /dev/null +++ b/embassy-mcxa/rustfmt.toml | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | group_imports = "StdExternalCrate" | ||
| 2 | imports_granularity = "Module" | ||
| 3 | max_width = 120 | ||
diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs new file mode 100644 index 000000000..b5ec5983f --- /dev/null +++ b/embassy-mcxa/src/adc.rs | |||
| @@ -0,0 +1,409 @@ | |||
| 1 | //! ADC driver | ||
| 2 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 3 | |||
| 4 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 5 | |||
| 6 | use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; | ||
| 7 | use crate::clocks::{enable_and_reset, Gate, PoweredClock}; | ||
| 8 | use crate::pac; | ||
| 9 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; | ||
| 10 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; | ||
| 11 | use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; | ||
| 12 | use crate::pac::adc1::ctrl::CalAvgs; | ||
| 13 | use crate::pac::adc1::tctrl::{Tcmd, Tpri}; | ||
| 14 | |||
| 15 | type Regs = pac::adc1::RegisterBlock; | ||
| 16 | |||
| 17 | static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false); | ||
| 18 | // Token-based instance pattern like embassy-imxrt | ||
| 19 | pub trait Instance: Gate<MrccPeriphConfig = AdcConfig> + PeripheralType { | ||
| 20 | fn ptr() -> *const Regs; | ||
| 21 | } | ||
| 22 | |||
| 23 | /// Token for ADC1 | ||
| 24 | pub type Adc1 = crate::peripherals::ADC1; | ||
| 25 | impl Instance for crate::peripherals::ADC1 { | ||
| 26 | #[inline(always)] | ||
| 27 | fn ptr() -> *const Regs { | ||
| 28 | pac::Adc1::ptr() | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | // Also implement Instance for the Peri wrapper type | ||
| 33 | // impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> { | ||
| 34 | // #[inline(always)] | ||
| 35 | // fn ptr() -> *const Regs { | ||
| 36 | // pac::Adc1::ptr() | ||
| 37 | // } | ||
| 38 | // } | ||
| 39 | |||
| 40 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 41 | #[repr(u8)] | ||
| 42 | pub enum TriggerPriorityPolicy { | ||
| 43 | ConvPreemptImmediatelyNotAutoResumed = 0, | ||
| 44 | ConvPreemptSoftlyNotAutoResumed = 1, | ||
| 45 | ConvPreemptImmediatelyAutoRestarted = 4, | ||
| 46 | ConvPreemptSoftlyAutoRestarted = 5, | ||
| 47 | ConvPreemptImmediatelyAutoResumed = 12, | ||
| 48 | ConvPreemptSoftlyAutoResumed = 13, | ||
| 49 | ConvPreemptSubsequentlyNotAutoResumed = 2, | ||
| 50 | ConvPreemptSubsequentlyAutoRestarted = 6, | ||
| 51 | ConvPreemptSubsequentlyAutoResumed = 14, | ||
| 52 | TriggerPriorityExceptionDisabled = 16, | ||
| 53 | } | ||
| 54 | |||
| 55 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 56 | pub struct LpadcConfig { | ||
| 57 | pub enable_in_doze_mode: bool, | ||
| 58 | pub conversion_average_mode: CalAvgs, | ||
| 59 | pub enable_analog_preliminary: bool, | ||
| 60 | pub power_up_delay: u8, | ||
| 61 | pub reference_voltage_source: Refsel, | ||
| 62 | pub power_level_mode: Pwrsel, | ||
| 63 | pub trigger_priority_policy: TriggerPriorityPolicy, | ||
| 64 | pub enable_conv_pause: bool, | ||
| 65 | pub conv_pause_delay: u16, | ||
| 66 | pub fifo_watermark: u8, | ||
| 67 | pub power: PoweredClock, | ||
| 68 | pub source: AdcClockSel, | ||
| 69 | pub div: Div4, | ||
| 70 | } | ||
| 71 | |||
| 72 | impl Default for LpadcConfig { | ||
| 73 | fn default() -> Self { | ||
| 74 | LpadcConfig { | ||
| 75 | enable_in_doze_mode: true, | ||
| 76 | conversion_average_mode: CalAvgs::NoAverage, | ||
| 77 | enable_analog_preliminary: false, | ||
| 78 | power_up_delay: 0x80, | ||
| 79 | reference_voltage_source: Refsel::Option1, | ||
| 80 | power_level_mode: Pwrsel::Lowest, | ||
| 81 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, | ||
| 82 | enable_conv_pause: false, | ||
| 83 | conv_pause_delay: 0, | ||
| 84 | fifo_watermark: 0, | ||
| 85 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 86 | source: AdcClockSel::FroLfDiv, | ||
| 87 | div: Div4::no_div(), | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 93 | pub struct ConvCommandConfig { | ||
| 94 | pub sample_channel_mode: Ctype, | ||
| 95 | pub channel_number: Adch, | ||
| 96 | pub chained_next_command_number: Next, | ||
| 97 | pub enable_auto_channel_increment: bool, | ||
| 98 | pub loop_count: u8, | ||
| 99 | pub hardware_average_mode: Avgs, | ||
| 100 | pub sample_time_mode: Sts, | ||
| 101 | pub hardware_compare_mode: Cmpen, | ||
| 102 | pub hardware_compare_value_high: u32, | ||
| 103 | pub hardware_compare_value_low: u32, | ||
| 104 | pub conversion_resolution_mode: Mode, | ||
| 105 | pub enable_wait_trigger: bool, | ||
| 106 | } | ||
| 107 | |||
| 108 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 109 | pub struct ConvTriggerConfig { | ||
| 110 | pub target_command_id: Tcmd, | ||
| 111 | pub delay_power: u8, | ||
| 112 | pub priority: Tpri, | ||
| 113 | pub enable_hardware_trigger: bool, | ||
| 114 | } | ||
| 115 | |||
| 116 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 117 | pub struct ConvResult { | ||
| 118 | pub command_id_source: u32, | ||
| 119 | pub loop_count_index: u32, | ||
| 120 | pub trigger_id_source: u32, | ||
| 121 | pub conv_value: u16, | ||
| 122 | } | ||
| 123 | |||
| 124 | pub struct Adc<'a, I: Instance> { | ||
| 125 | _inst: core::marker::PhantomData<&'a mut I>, | ||
| 126 | } | ||
| 127 | |||
| 128 | impl<'a, I: Instance> Adc<'a, I> { | ||
| 129 | /// initialize ADC | ||
| 130 | pub fn new(_inst: Peri<'a, I>, config: LpadcConfig) -> Self { | ||
| 131 | let adc = unsafe { &*I::ptr() }; | ||
| 132 | |||
| 133 | let _clock_freq = unsafe { | ||
| 134 | enable_and_reset::<I>(&AdcConfig { | ||
| 135 | power: config.power, | ||
| 136 | source: config.source, | ||
| 137 | div: config.div, | ||
| 138 | }) | ||
| 139 | .expect("Adc Init should not fail") | ||
| 140 | }; | ||
| 141 | |||
| 142 | /* Reset the module. */ | ||
| 143 | adc.ctrl().modify(|_, w| w.rst().held_in_reset()); | ||
| 144 | adc.ctrl().modify(|_, w| w.rst().released_from_reset()); | ||
| 145 | |||
| 146 | adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | ||
| 147 | |||
| 148 | /* Disable the module before setting configuration. */ | ||
| 149 | adc.ctrl().modify(|_, w| w.adcen().disabled()); | ||
| 150 | |||
| 151 | /* Configure the module generally. */ | ||
| 152 | if config.enable_in_doze_mode { | ||
| 153 | adc.ctrl().modify(|_, w| w.dozen().enabled()); | ||
| 154 | } else { | ||
| 155 | adc.ctrl().modify(|_, w| w.dozen().disabled()); | ||
| 156 | } | ||
| 157 | |||
| 158 | /* Set calibration average mode. */ | ||
| 159 | adc.ctrl() | ||
| 160 | .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode)); | ||
| 161 | |||
| 162 | adc.cfg().write(|w| unsafe { | ||
| 163 | let w = if config.enable_analog_preliminary { | ||
| 164 | w.pwren().pre_enabled() | ||
| 165 | } else { | ||
| 166 | w | ||
| 167 | }; | ||
| 168 | |||
| 169 | w.pudly() | ||
| 170 | .bits(config.power_up_delay) | ||
| 171 | .refsel() | ||
| 172 | .variant(config.reference_voltage_source) | ||
| 173 | .pwrsel() | ||
| 174 | .variant(config.power_level_mode) | ||
| 175 | .tprictrl() | ||
| 176 | .variant(match config.trigger_priority_policy { | ||
| 177 | TriggerPriorityPolicy::ConvPreemptSoftlyNotAutoResumed | ||
| 178 | | TriggerPriorityPolicy::ConvPreemptSoftlyAutoRestarted | ||
| 179 | | TriggerPriorityPolicy::ConvPreemptSoftlyAutoResumed => Tprictrl::FinishCurrentOnPriority, | ||
| 180 | TriggerPriorityPolicy::ConvPreemptSubsequentlyNotAutoResumed | ||
| 181 | | TriggerPriorityPolicy::ConvPreemptSubsequentlyAutoRestarted | ||
| 182 | | TriggerPriorityPolicy::ConvPreemptSubsequentlyAutoResumed => Tprictrl::FinishSequenceOnPriority, | ||
| 183 | _ => Tprictrl::AbortCurrentOnPriority, | ||
| 184 | }) | ||
| 185 | .tres() | ||
| 186 | .variant(match config.trigger_priority_policy { | ||
| 187 | TriggerPriorityPolicy::ConvPreemptImmediatelyAutoRestarted | ||
| 188 | | TriggerPriorityPolicy::ConvPreemptSoftlyAutoRestarted | ||
| 189 | | TriggerPriorityPolicy::ConvPreemptImmediatelyAutoResumed | ||
| 190 | | TriggerPriorityPolicy::ConvPreemptSoftlyAutoResumed | ||
| 191 | | TriggerPriorityPolicy::ConvPreemptSubsequentlyAutoRestarted | ||
| 192 | | TriggerPriorityPolicy::ConvPreemptSubsequentlyAutoResumed => Tres::Enabled, | ||
| 193 | _ => Tres::Disabled, | ||
| 194 | }) | ||
| 195 | .tcmdres() | ||
| 196 | .variant(match config.trigger_priority_policy { | ||
| 197 | TriggerPriorityPolicy::ConvPreemptImmediatelyAutoResumed | ||
| 198 | | TriggerPriorityPolicy::ConvPreemptSoftlyAutoResumed | ||
| 199 | | TriggerPriorityPolicy::ConvPreemptSubsequentlyAutoResumed | ||
| 200 | | TriggerPriorityPolicy::TriggerPriorityExceptionDisabled => Tcmdres::Enabled, | ||
| 201 | _ => Tcmdres::Disabled, | ||
| 202 | }) | ||
| 203 | .hpt_exdi() | ||
| 204 | .variant(match config.trigger_priority_policy { | ||
| 205 | TriggerPriorityPolicy::TriggerPriorityExceptionDisabled => HptExdi::Disabled, | ||
| 206 | _ => HptExdi::Enabled, | ||
| 207 | }) | ||
| 208 | }); | ||
| 209 | |||
| 210 | if config.enable_conv_pause { | ||
| 211 | adc.pause() | ||
| 212 | .modify(|_, w| unsafe { w.pauseen().enabled().pausedly().bits(config.conv_pause_delay) }); | ||
| 213 | } else { | ||
| 214 | adc.pause().write(|w| unsafe { w.bits(0) }); | ||
| 215 | } | ||
| 216 | |||
| 217 | adc.fctrl0() | ||
| 218 | .write(|w| unsafe { w.fwmark().bits(config.fifo_watermark) }); | ||
| 219 | |||
| 220 | // Enable ADC | ||
| 221 | adc.ctrl().modify(|_, w| w.adcen().enabled()); | ||
| 222 | |||
| 223 | Self { | ||
| 224 | _inst: core::marker::PhantomData, | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | pub fn deinit(&self) { | ||
| 229 | let adc = unsafe { &*I::ptr() }; | ||
| 230 | adc.ctrl().modify(|_, w| w.adcen().disabled()); | ||
| 231 | } | ||
| 232 | |||
| 233 | pub fn do_offset_calibration(&self) { | ||
| 234 | let adc = unsafe { &*I::ptr() }; | ||
| 235 | // Enable calibration mode | ||
| 236 | adc.ctrl() | ||
| 237 | .modify(|_, w| w.calofs().offset_calibration_request_pending()); | ||
| 238 | |||
| 239 | // Wait for calibration to complete (polling status register) | ||
| 240 | while adc.stat().read().cal_rdy().is_not_set() {} | ||
| 241 | } | ||
| 242 | |||
| 243 | pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 { | ||
| 244 | let mut gcra_array = [0u32; 17]; | ||
| 245 | let mut gcalr: u32 = 0; | ||
| 246 | |||
| 247 | for i in (1..=17).rev() { | ||
| 248 | let shift = 16 - (i - 1); | ||
| 249 | let step = 1.0 / (1u32 << shift) as f32; | ||
| 250 | let tmp = (gain_adjustment / step) as u32; | ||
| 251 | gcra_array[i - 1] = tmp; | ||
| 252 | gain_adjustment -= tmp as f32 * step; | ||
| 253 | } | ||
| 254 | |||
| 255 | for i in (1..=17).rev() { | ||
| 256 | gcalr += gcra_array[i - 1] << (i - 1); | ||
| 257 | } | ||
| 258 | gcalr | ||
| 259 | } | ||
| 260 | |||
| 261 | pub fn do_auto_calibration(&self) { | ||
| 262 | let adc = unsafe { &*I::ptr() }; | ||
| 263 | adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); | ||
| 264 | |||
| 265 | while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} | ||
| 266 | |||
| 267 | let mut gcca = adc.gcc0().read().gain_cal().bits() as u32; | ||
| 268 | if gcca & ((0xFFFF + 1) >> 1) != 0 { | ||
| 269 | gcca |= !0xFFFF; | ||
| 270 | } | ||
| 271 | |||
| 272 | let gcra = 131072.0 / (131072.0 - gcca as f32); | ||
| 273 | |||
| 274 | // Write to GCR0 | ||
| 275 | adc.gcr0().write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); | ||
| 276 | |||
| 277 | adc.gcr0().modify(|_, w| w.rdy().set_bit()); | ||
| 278 | |||
| 279 | // Wait for calibration to complete (polling status register) | ||
| 280 | while adc.stat().read().cal_rdy().is_not_set() {} | ||
| 281 | } | ||
| 282 | |||
| 283 | pub fn do_software_trigger(&self, trigger_id_mask: u32) { | ||
| 284 | let adc = unsafe { &*I::ptr() }; | ||
| 285 | adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); | ||
| 286 | } | ||
| 287 | |||
| 288 | pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { | ||
| 289 | ConvCommandConfig { | ||
| 290 | sample_channel_mode: Ctype::SingleEndedASideChannel, | ||
| 291 | channel_number: Adch::SelectCh0, | ||
| 292 | chained_next_command_number: Next::NoNextCmdTerminateOnFinish, | ||
| 293 | enable_auto_channel_increment: false, | ||
| 294 | loop_count: 0, | ||
| 295 | hardware_average_mode: Avgs::NoAverage, | ||
| 296 | sample_time_mode: Sts::Sample3p5, | ||
| 297 | hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, | ||
| 298 | hardware_compare_value_high: 0, | ||
| 299 | hardware_compare_value_low: 0, | ||
| 300 | conversion_resolution_mode: Mode::Data12Bits, | ||
| 301 | enable_wait_trigger: false, | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | //TBD Need to add cmdlx and cmdhx with x {2..7} | ||
| 306 | pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { | ||
| 307 | let adc = unsafe { &*I::ptr() }; | ||
| 308 | |||
| 309 | match index { | ||
| 310 | 1 => { | ||
| 311 | adc.cmdl1().write(|w| { | ||
| 312 | w.adch() | ||
| 313 | .variant(config.channel_number) | ||
| 314 | .mode() | ||
| 315 | .variant(config.conversion_resolution_mode) | ||
| 316 | }); | ||
| 317 | adc.cmdh1().write(|w| unsafe { | ||
| 318 | w.next() | ||
| 319 | .variant(config.chained_next_command_number) | ||
| 320 | .loop_() | ||
| 321 | .bits(config.loop_count) | ||
| 322 | .avgs() | ||
| 323 | .variant(config.hardware_average_mode) | ||
| 324 | .sts() | ||
| 325 | .variant(config.sample_time_mode) | ||
| 326 | .cmpen() | ||
| 327 | .variant(config.hardware_compare_mode); | ||
| 328 | if config.enable_wait_trigger { | ||
| 329 | w.wait_trig().enabled(); | ||
| 330 | } | ||
| 331 | if config.enable_auto_channel_increment { | ||
| 332 | w.lwi().enabled(); | ||
| 333 | } | ||
| 334 | w | ||
| 335 | }); | ||
| 336 | } | ||
| 337 | _ => panic!("Invalid command index: must be between 1 and 7"), | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig { | ||
| 342 | ConvTriggerConfig { | ||
| 343 | target_command_id: Tcmd::NotValid, | ||
| 344 | delay_power: 0, | ||
| 345 | priority: Tpri::HighestPriority, | ||
| 346 | enable_hardware_trigger: false, | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { | ||
| 351 | let adc = unsafe { &*I::ptr() }; | ||
| 352 | let tctrl = &adc.tctrl(trigger_id); | ||
| 353 | |||
| 354 | tctrl.write(|w| unsafe { | ||
| 355 | let w = w.tcmd().variant(config.target_command_id); | ||
| 356 | let w = w.tdly().bits(config.delay_power); | ||
| 357 | w.tpri().variant(config.priority); | ||
| 358 | if config.enable_hardware_trigger { | ||
| 359 | w.hten().enabled() | ||
| 360 | } else { | ||
| 361 | w | ||
| 362 | } | ||
| 363 | }); | ||
| 364 | } | ||
| 365 | |||
| 366 | pub fn do_reset_fifo(&self) { | ||
| 367 | let adc = unsafe { &*I::ptr() }; | ||
| 368 | adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | ||
| 369 | } | ||
| 370 | |||
| 371 | pub fn enable_interrupt(&self, mask: u32) { | ||
| 372 | let adc = unsafe { &*I::ptr() }; | ||
| 373 | adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); | ||
| 374 | INTERRUPT_TRIGGERED.store(false, Ordering::SeqCst); | ||
| 375 | } | ||
| 376 | |||
| 377 | pub fn is_interrupt_triggered(&self) -> bool { | ||
| 378 | INTERRUPT_TRIGGERED.load(Ordering::Relaxed) | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | pub fn get_conv_result() -> Option<ConvResult> { | ||
| 383 | let adc = unsafe { &*pac::Adc1::ptr() }; | ||
| 384 | let fifo = adc.resfifo0().read().bits(); | ||
| 385 | const VALID_MASK: u32 = 1 << 31; | ||
| 386 | if fifo & VALID_MASK == 0 { | ||
| 387 | return None; | ||
| 388 | } | ||
| 389 | |||
| 390 | Some(ConvResult { | ||
| 391 | command_id_source: (fifo >> 24) & 0x0F, | ||
| 392 | loop_count_index: (fifo >> 20) & 0x0F, | ||
| 393 | trigger_id_source: (fifo >> 16) & 0x0F, | ||
| 394 | conv_value: (fifo & 0xFFFF) as u16, | ||
| 395 | }) | ||
| 396 | } | ||
| 397 | |||
| 398 | pub fn on_interrupt() { | ||
| 399 | if get_conv_result().is_some() { | ||
| 400 | INTERRUPT_TRIGGERED.store(true, Ordering::SeqCst); | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | pub struct AdcHandler; | ||
| 405 | impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::ADC1> for AdcHandler { | ||
| 406 | unsafe fn on_interrupt() { | ||
| 407 | on_interrupt(); | ||
| 408 | } | ||
| 409 | } | ||
diff --git a/embassy-mcxa/src/clkout.rs b/embassy-mcxa/src/clkout.rs new file mode 100644 index 000000000..88c731df1 --- /dev/null +++ b/embassy-mcxa/src/clkout.rs | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | //! CLKOUT pseudo-peripheral | ||
| 2 | //! | ||
| 3 | //! CLKOUT is a part of the clock generation subsystem, and can be used | ||
| 4 | //! either to generate arbitrary waveforms, or to debug the state of | ||
| 5 | //! internal oscillators. | ||
| 6 | |||
| 7 | use core::marker::PhantomData; | ||
| 8 | |||
| 9 | use embassy_hal_internal::Peri; | ||
| 10 | |||
| 11 | pub use crate::clocks::periph_helpers::Div4; | ||
| 12 | use crate::clocks::{with_clocks, ClockError, PoweredClock}; | ||
| 13 | use crate::pac::mrcc0::mrcc_clkout_clksel::Mux; | ||
| 14 | use crate::peripherals::CLKOUT; | ||
| 15 | |||
| 16 | /// A peripheral representing the CLKOUT pseudo-peripheral | ||
| 17 | pub struct ClockOut<'a> { | ||
| 18 | _p: PhantomData<&'a mut CLKOUT>, | ||
| 19 | freq: u32, | ||
| 20 | } | ||
| 21 | |||
| 22 | /// Selected clock source to output | ||
| 23 | pub enum ClockOutSel { | ||
| 24 | /// 12MHz Internal Oscillator | ||
| 25 | Fro12M, | ||
| 26 | /// FRO180M Internal Oscillator, via divisor | ||
| 27 | FroHfDiv, | ||
| 28 | /// External Oscillator | ||
| 29 | ClkIn, | ||
| 30 | /// 16KHz oscillator | ||
| 31 | Clk16K, | ||
| 32 | /// Output of PLL1 | ||
| 33 | Pll1Clk, | ||
| 34 | /// Main System CPU clock, divided by 6 | ||
| 35 | SlowClk, | ||
| 36 | } | ||
| 37 | |||
| 38 | /// Configuration for the ClockOut | ||
| 39 | pub struct Config { | ||
| 40 | /// Selected Source Clock | ||
| 41 | pub sel: ClockOutSel, | ||
| 42 | /// Selected division level | ||
| 43 | pub div: Div4, | ||
| 44 | /// Selected power level | ||
| 45 | pub level: PoweredClock, | ||
| 46 | } | ||
| 47 | |||
| 48 | impl<'a> ClockOut<'a> { | ||
| 49 | /// Create a new ClockOut pin. On success, the clock signal will begin immediately | ||
| 50 | /// on the given pin. | ||
| 51 | pub fn new( | ||
| 52 | _peri: Peri<'a, CLKOUT>, | ||
| 53 | pin: Peri<'a, impl sealed::ClockOutPin>, | ||
| 54 | cfg: Config, | ||
| 55 | ) -> Result<Self, ClockError> { | ||
| 56 | // There's no MRCC enable bit, so we check the validity of the clocks here | ||
| 57 | // | ||
| 58 | // TODO: Should we check that the frequency is suitably low? | ||
| 59 | let (freq, mux) = check_sel(cfg.sel, cfg.level)?; | ||
| 60 | |||
| 61 | // All good! Apply requested config, starting with the pin. | ||
| 62 | pin.mux(); | ||
| 63 | |||
| 64 | setup_clkout(mux, cfg.div); | ||
| 65 | |||
| 66 | Ok(Self { | ||
| 67 | _p: PhantomData, | ||
| 68 | freq: freq / cfg.div.into_divisor(), | ||
| 69 | }) | ||
| 70 | } | ||
| 71 | |||
| 72 | /// Frequency of the clkout pin | ||
| 73 | #[inline] | ||
| 74 | pub fn frequency(&self) -> u32 { | ||
| 75 | self.freq | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | impl Drop for ClockOut<'_> { | ||
| 80 | fn drop(&mut self) { | ||
| 81 | disable_clkout(); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | /// Check whether the given clock selection is valid | ||
| 86 | fn check_sel(sel: ClockOutSel, level: PoweredClock) -> Result<(u32, Mux), ClockError> { | ||
| 87 | let res = with_clocks(|c| { | ||
| 88 | Ok(match sel { | ||
| 89 | ClockOutSel::Fro12M => (c.ensure_fro_hf_active(&level)?, Mux::Clkroot12m), | ||
| 90 | ClockOutSel::FroHfDiv => (c.ensure_fro_hf_div_active(&level)?, Mux::ClkrootFircDiv), | ||
| 91 | ClockOutSel::ClkIn => (c.ensure_clk_in_active(&level)?, Mux::ClkrootSosc), | ||
| 92 | ClockOutSel::Clk16K => (c.ensure_clk_16k_vdd_core_active(&level)?, Mux::Clkroot16k), | ||
| 93 | ClockOutSel::Pll1Clk => (c.ensure_pll1_clk_active(&level)?, Mux::ClkrootSpll), | ||
| 94 | ClockOutSel::SlowClk => (c.ensure_slow_clk_active(&level)?, Mux::ClkrootSlow), | ||
| 95 | }) | ||
| 96 | }); | ||
| 97 | let Some(res) = res else { | ||
| 98 | return Err(ClockError::NeverInitialized); | ||
| 99 | }; | ||
| 100 | res | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Set up the clkout pin using the given mux and div settings | ||
| 104 | fn setup_clkout(mux: Mux, div: Div4) { | ||
| 105 | let mrcc = unsafe { crate::pac::Mrcc0::steal() }; | ||
| 106 | |||
| 107 | mrcc.mrcc_clkout_clksel().write(|w| w.mux().variant(mux)); | ||
| 108 | |||
| 109 | // Set up clkdiv | ||
| 110 | mrcc.mrcc_clkout_clkdiv().write(|w| { | ||
| 111 | w.halt().set_bit(); | ||
| 112 | w.reset().set_bit(); | ||
| 113 | unsafe { w.div().bits(div.into_bits()) }; | ||
| 114 | w | ||
| 115 | }); | ||
| 116 | mrcc.mrcc_clkout_clkdiv().write(|w| { | ||
| 117 | w.halt().clear_bit(); | ||
| 118 | w.reset().clear_bit(); | ||
| 119 | unsafe { w.div().bits(div.into_bits()) }; | ||
| 120 | w | ||
| 121 | }); | ||
| 122 | |||
| 123 | while mrcc.mrcc_clkout_clkdiv().read().unstab().bit_is_set() {} | ||
| 124 | } | ||
| 125 | |||
| 126 | /// Stop the clkout | ||
| 127 | fn disable_clkout() { | ||
| 128 | // Stop the output by selecting the "none" clock | ||
| 129 | // | ||
| 130 | // TODO: restore the pin to hi-z or something? | ||
| 131 | let mrcc = unsafe { crate::pac::Mrcc0::steal() }; | ||
| 132 | mrcc.mrcc_clkout_clkdiv().write(|w| { | ||
| 133 | w.reset().set_bit(); | ||
| 134 | w.halt().set_bit(); | ||
| 135 | unsafe { | ||
| 136 | w.div().bits(0); | ||
| 137 | } | ||
| 138 | w | ||
| 139 | }); | ||
| 140 | mrcc.mrcc_clkout_clksel().write(|w| unsafe { w.bits(0b111) }); | ||
| 141 | } | ||
| 142 | |||
| 143 | mod sealed { | ||
| 144 | use embassy_hal_internal::PeripheralType; | ||
| 145 | |||
| 146 | use crate::gpio::{Pull, SealedPin}; | ||
| 147 | |||
| 148 | /// Sealed marker trait for clockout pins | ||
| 149 | pub trait ClockOutPin: PeripheralType { | ||
| 150 | /// Set the given pin to the correct muxing state | ||
| 151 | fn mux(&self); | ||
| 152 | } | ||
| 153 | |||
| 154 | macro_rules! impl_pin { | ||
| 155 | ($pin:ident, $func:ident) => { | ||
| 156 | impl ClockOutPin for crate::peripherals::$pin { | ||
| 157 | fn mux(&self) { | ||
| 158 | self.set_function(crate::pac::port0::pcr0::Mux::$func); | ||
| 159 | self.set_pull(Pull::Disabled); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | }; | ||
| 163 | } | ||
| 164 | |||
| 165 | impl_pin!(P0_6, Mux12); | ||
| 166 | impl_pin!(P3_6, Mux1); | ||
| 167 | impl_pin!(P3_8, Mux12); | ||
| 168 | impl_pin!(P4_2, Mux1); | ||
| 169 | } | ||
diff --git a/embassy-mcxa/src/clocks/config.rs b/embassy-mcxa/src/clocks/config.rs new file mode 100644 index 000000000..0563b8917 --- /dev/null +++ b/embassy-mcxa/src/clocks/config.rs | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | //! Clock Configuration | ||
| 2 | //! | ||
| 3 | //! This module holds configuration types used for the system clocks. For | ||
| 4 | //! configuration of individual peripherals, see [`super::periph_helpers`]. | ||
| 5 | |||
| 6 | use super::PoweredClock; | ||
| 7 | |||
| 8 | /// This type represents a divider in the range 1..=256. | ||
| 9 | /// | ||
| 10 | /// At a hardware level, this is an 8-bit register from 0..=255, | ||
| 11 | /// which adds one. | ||
| 12 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 13 | pub struct Div8(pub(super) u8); | ||
| 14 | |||
| 15 | impl Div8 { | ||
| 16 | /// Store a "raw" divisor value that will divide the source by | ||
| 17 | /// `(n + 1)`, e.g. `Div8::from_raw(0)` will divide the source | ||
| 18 | /// by 1, and `Div8::from_raw(255)` will divide the source by | ||
| 19 | /// 256. | ||
| 20 | pub const fn from_raw(n: u8) -> Self { | ||
| 21 | Self(n) | ||
| 22 | } | ||
| 23 | |||
| 24 | /// Divide by one, or no division | ||
| 25 | pub const fn no_div() -> Self { | ||
| 26 | Self(0) | ||
| 27 | } | ||
| 28 | |||
| 29 | /// Store a specific divisor value that will divide the source | ||
| 30 | /// by `n`. e.g. `Div8::from_divisor(1)` will divide the source | ||
| 31 | /// by 1, and `Div8::from_divisor(256)` will divide the source | ||
| 32 | /// by 256. | ||
| 33 | /// | ||
| 34 | /// Will return `None` if `n` is not in the range `1..=256`. | ||
| 35 | /// Consider [`Self::from_raw`] for an infallible version. | ||
| 36 | pub const fn from_divisor(n: u16) -> Option<Self> { | ||
| 37 | let Some(n) = n.checked_sub(1) else { | ||
| 38 | return None; | ||
| 39 | }; | ||
| 40 | if n > (u8::MAX as u16) { | ||
| 41 | return None; | ||
| 42 | } | ||
| 43 | Some(Self(n as u8)) | ||
| 44 | } | ||
| 45 | |||
| 46 | /// Convert into "raw" bits form | ||
| 47 | #[inline(always)] | ||
| 48 | pub const fn into_bits(self) -> u8 { | ||
| 49 | self.0 | ||
| 50 | } | ||
| 51 | |||
| 52 | /// Convert into "divisor" form, as a u32 for convenient frequency math | ||
| 53 | #[inline(always)] | ||
| 54 | pub const fn into_divisor(self) -> u32 { | ||
| 55 | self.0 as u32 + 1 | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | /// ```text | ||
| 60 | /// ┌─────────────────────────────────────────────────────────┐ | ||
| 61 | /// │ │ | ||
| 62 | /// │ ┌───────────┐ clk_out ┌─────────┐ │ | ||
| 63 | /// XTAL ──────┼──▷│ System │───────────▷│ │ clk_in │ | ||
| 64 | /// │ │ OSC │ clkout_byp │ MUX │──────────────────┼──────▷ | ||
| 65 | /// EXTAL ──────┼──▷│ │───────────▷│ │ │ | ||
| 66 | /// │ └───────────┘ └─────────┘ │ | ||
| 67 | /// │ │ | ||
| 68 | /// │ ┌───────────┐ fro_hf_root ┌────┐ fro_hf │ | ||
| 69 | /// │ │ FRO180 ├───────┬─────▷│ CG │─────────────────────┼──────▷ | ||
| 70 | /// │ │ │ │ ├────┤ clk_45m │ | ||
| 71 | /// │ │ │ └─────▷│ CG │─────────────────────┼──────▷ | ||
| 72 | /// │ └───────────┘ └────┘ │ | ||
| 73 | /// │ ┌───────────┐ fro_12m_root ┌────┐ fro_12m │ | ||
| 74 | /// │ │ FRO12M │────────┬─────▷│ CG │────────────────────┼──────▷ | ||
| 75 | /// │ │ │ │ ├────┤ clk_1m │ | ||
| 76 | /// │ │ │ └─────▷│1/12│────────────────────┼──────▷ | ||
| 77 | /// │ └───────────┘ └────┘ │ | ||
| 78 | /// │ │ | ||
| 79 | /// │ ┌──────────┐ │ | ||
| 80 | /// │ │000 │ │ | ||
| 81 | /// │ clk_in │ │ │ | ||
| 82 | /// │ ───────────────▷│001 │ │ | ||
| 83 | /// │ fro_12m │ │ │ | ||
| 84 | /// │ ───────────────▷│010 │ │ | ||
| 85 | /// │ fro_hf_root │ │ │ | ||
| 86 | /// │ ───────────────▷│011 │ main_clk │ | ||
| 87 | /// │ │ │───────────────────────────┼──────▷ | ||
| 88 | /// clk_16k ──────┼─────────────────▷│100 │ │ | ||
| 89 | /// │ none │ │ │ | ||
| 90 | /// │ ───────────────▷│101 │ │ | ||
| 91 | /// │ pll1_clk │ │ │ | ||
| 92 | /// │ ───────────────▷│110 │ │ | ||
| 93 | /// │ none │ │ │ | ||
| 94 | /// │ ───────────────▷│111 │ │ | ||
| 95 | /// │ └──────────┘ │ | ||
| 96 | /// │ ▲ │ | ||
| 97 | /// │ │ │ | ||
| 98 | /// │ SCG SCS │ | ||
| 99 | /// │ SCG-Lite │ | ||
| 100 | /// └─────────────────────────────────────────────────────────┘ | ||
| 101 | /// | ||
| 102 | /// | ||
| 103 | /// clk_in ┌─────┐ | ||
| 104 | /// ───────────────▷│00 │ | ||
| 105 | /// clk_45m │ │ | ||
| 106 | /// ───────────────▷│01 │ ┌───────────┐ pll1_clk | ||
| 107 | /// none │ │─────▷│ SPLL │───────────────▷ | ||
| 108 | /// ───────────────▷│10 │ └───────────┘ | ||
| 109 | /// fro_12m │ │ | ||
| 110 | /// ───────────────▷│11 │ | ||
| 111 | /// └─────┘ | ||
| 112 | /// ``` | ||
| 113 | #[non_exhaustive] | ||
| 114 | pub struct ClocksConfig { | ||
| 115 | /// FIRC, FRO180, 45/60/90/180M clock source | ||
| 116 | pub firc: Option<FircConfig>, | ||
| 117 | /// SIRC, FRO12M, clk_12m clock source | ||
| 118 | // NOTE: I don't think we *can* disable the SIRC? | ||
| 119 | pub sirc: SircConfig, | ||
| 120 | /// FRO16K clock source | ||
| 121 | pub fro16k: Option<Fro16KConfig>, | ||
| 122 | } | ||
| 123 | |||
| 124 | // FIRC/FRO180M | ||
| 125 | |||
| 126 | /// ```text | ||
| 127 | /// ┌───────────┐ fro_hf_root ┌────┐ fro_hf | ||
| 128 | /// │ FRO180M ├───────┬─────▷│GATE│──────────▷ | ||
| 129 | /// │ │ │ ├────┤ clk_45m | ||
| 130 | /// │ │ └─────▷│GATE│──────────▷ | ||
| 131 | /// └───────────┘ └────┘ | ||
| 132 | /// ``` | ||
| 133 | #[non_exhaustive] | ||
| 134 | pub struct FircConfig { | ||
| 135 | /// Selected clock frequency | ||
| 136 | pub frequency: FircFreqSel, | ||
| 137 | /// Selected power state of the clock | ||
| 138 | pub power: PoweredClock, | ||
| 139 | /// Is the "fro_hf" gated clock enabled? | ||
| 140 | pub fro_hf_enabled: bool, | ||
| 141 | /// Is the "clk_45m" gated clock enabled? | ||
| 142 | pub clk_45m_enabled: bool, | ||
| 143 | /// Is the "fro_hf_div" clock enabled? Requires `fro_hf`! | ||
| 144 | pub fro_hf_div: Option<Div8>, | ||
| 145 | } | ||
| 146 | |||
| 147 | /// Selected FIRC frequency | ||
| 148 | pub enum FircFreqSel { | ||
| 149 | /// 45MHz Output | ||
| 150 | Mhz45, | ||
| 151 | /// 60MHz Output | ||
| 152 | Mhz60, | ||
| 153 | /// 90MHz Output | ||
| 154 | Mhz90, | ||
| 155 | /// 180MHz Output | ||
| 156 | Mhz180, | ||
| 157 | } | ||
| 158 | |||
| 159 | // SIRC/FRO12M | ||
| 160 | |||
| 161 | /// ```text | ||
| 162 | /// ┌───────────┐ fro_12m_root ┌────┐ fro_12m | ||
| 163 | /// │ FRO12M │────────┬─────▷│ CG │──────────▷ | ||
| 164 | /// │ │ │ ├────┤ clk_1m | ||
| 165 | /// │ │ └─────▷│1/12│──────────▷ | ||
| 166 | /// └───────────┘ └────┘ | ||
| 167 | /// ``` | ||
| 168 | #[non_exhaustive] | ||
| 169 | pub struct SircConfig { | ||
| 170 | pub power: PoweredClock, | ||
| 171 | // peripheral output, aka sirc_12mhz | ||
| 172 | pub fro_12m_enabled: bool, | ||
| 173 | /// Is the "fro_lf_div" clock enabled? Requires `fro_12m`! | ||
| 174 | pub fro_lf_div: Option<Div8>, | ||
| 175 | } | ||
| 176 | |||
| 177 | #[non_exhaustive] | ||
| 178 | pub struct Fro16KConfig { | ||
| 179 | pub vsys_domain_active: bool, | ||
| 180 | pub vdd_core_domain_active: bool, | ||
| 181 | } | ||
| 182 | |||
| 183 | impl Default for ClocksConfig { | ||
| 184 | fn default() -> Self { | ||
| 185 | Self { | ||
| 186 | firc: Some(FircConfig { | ||
| 187 | frequency: FircFreqSel::Mhz45, | ||
| 188 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 189 | fro_hf_enabled: true, | ||
| 190 | clk_45m_enabled: true, | ||
| 191 | fro_hf_div: None, | ||
| 192 | }), | ||
| 193 | sirc: SircConfig { | ||
| 194 | power: PoweredClock::AlwaysEnabled, | ||
| 195 | fro_12m_enabled: true, | ||
| 196 | fro_lf_div: None, | ||
| 197 | }, | ||
| 198 | fro16k: Some(Fro16KConfig { | ||
| 199 | vsys_domain_active: true, | ||
| 200 | vdd_core_domain_active: true, | ||
| 201 | }), | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs new file mode 100644 index 000000000..9c9e6ef3d --- /dev/null +++ b/embassy-mcxa/src/clocks/mod.rs | |||
| @@ -0,0 +1,943 @@ | |||
| 1 | //! # Clock Module | ||
| 2 | //! | ||
| 3 | //! For the MCX-A, we separate clock and peripheral control into two main stages: | ||
| 4 | //! | ||
| 5 | //! 1. At startup, e.g. when `embassy_mcxa::init()` is called, we configure the | ||
| 6 | //! core system clocks, including external and internal oscillators. This | ||
| 7 | //! configuration is then largely static for the duration of the program. | ||
| 8 | //! 2. When HAL drivers are created, e.g. `Lpuart::new()` is called, the driver | ||
| 9 | //! is responsible for two main things: | ||
| 10 | //! * Ensuring that any required "upstream" core system clocks necessary for | ||
| 11 | //! clocking the peripheral is active and configured to a reasonable value | ||
| 12 | //! * Enabling the clock gates for that peripheral, and resetting the peripheral | ||
| 13 | //! | ||
| 14 | //! From a user perspective, only step 1 is visible. Step 2 is automatically handled | ||
| 15 | //! by HAL drivers, using interfaces defined in this module. | ||
| 16 | //! | ||
| 17 | //! It is also possible to *view* the state of the clock configuration after [`init()`] | ||
| 18 | //! has been called, using the [`with_clocks()`] function, which provides a view of the | ||
| 19 | //! [`Clocks`] structure. | ||
| 20 | //! | ||
| 21 | //! ## For HAL driver implementors | ||
| 22 | //! | ||
| 23 | //! The majority of peripherals in the MCXA chip are fed from either a "hard-coded" or | ||
| 24 | //! configurable clock source, e.g. selecting the FROM12M or `clk_1m` as a source. This | ||
| 25 | //! selection, as well as often any pre-scaler division from that source clock, is made | ||
| 26 | //! through MRCC registers. | ||
| 27 | //! | ||
| 28 | //! Any peripheral that is controlled through the MRCC register can automatically implement | ||
| 29 | //! the necessary APIs using the `impl_cc_gate!` macro in this module. You will also need | ||
| 30 | //! to define the configuration surface and steps necessary to fully configure that peripheral | ||
| 31 | //! from a clocks perspective by: | ||
| 32 | //! | ||
| 33 | //! 1. Defining a configuration type in the [`periph_helpers`] module that contains any selects | ||
| 34 | //! or divisions available to the HAL driver | ||
| 35 | //! 2. Implementing the [`periph_helpers::SPConfHelper`] trait, which should check that the | ||
| 36 | //! necessary input clocks are reasonable | ||
| 37 | |||
| 38 | use core::cell::RefCell; | ||
| 39 | |||
| 40 | use config::{ClocksConfig, FircConfig, FircFreqSel, Fro16KConfig, SircConfig}; | ||
| 41 | use mcxa_pac::scg0::firccsr::{FircFclkPeriphEn, FircSclkPeriphEn, Fircsten}; | ||
| 42 | use mcxa_pac::scg0::sirccsr::{SircClkPeriphEn, Sircsten}; | ||
| 43 | use periph_helpers::SPConfHelper; | ||
| 44 | |||
| 45 | use crate::pac; | ||
| 46 | pub mod config; | ||
| 47 | pub mod periph_helpers; | ||
| 48 | |||
| 49 | // | ||
| 50 | // Statics/Consts | ||
| 51 | // | ||
| 52 | |||
| 53 | /// The state of system core clocks. | ||
| 54 | /// | ||
| 55 | /// Initialized by [`init()`], and then unchanged for the remainder of the program. | ||
| 56 | static CLOCKS: critical_section::Mutex<RefCell<Option<Clocks>>> = critical_section::Mutex::new(RefCell::new(None)); | ||
| 57 | |||
| 58 | // | ||
| 59 | // Free functions | ||
| 60 | // | ||
| 61 | |||
| 62 | /// Initialize the core system clocks with the given [`ClocksConfig`]. | ||
| 63 | /// | ||
| 64 | /// This function should be called EXACTLY once at start-up, usually via a | ||
| 65 | /// call to [`embassy_mcxa::init()`](crate::init()). Subsequent calls will | ||
| 66 | /// return an error. | ||
| 67 | pub fn init(settings: ClocksConfig) -> Result<(), ClockError> { | ||
| 68 | critical_section::with(|cs| { | ||
| 69 | if CLOCKS.borrow_ref(cs).is_some() { | ||
| 70 | Err(ClockError::AlreadyInitialized) | ||
| 71 | } else { | ||
| 72 | Ok(()) | ||
| 73 | } | ||
| 74 | })?; | ||
| 75 | |||
| 76 | let mut clocks = Clocks::default(); | ||
| 77 | let mut operator = ClockOperator { | ||
| 78 | clocks: &mut clocks, | ||
| 79 | config: &settings, | ||
| 80 | |||
| 81 | _mrcc0: unsafe { pac::Mrcc0::steal() }, | ||
| 82 | scg0: unsafe { pac::Scg0::steal() }, | ||
| 83 | syscon: unsafe { pac::Syscon::steal() }, | ||
| 84 | vbat0: unsafe { pac::Vbat0::steal() }, | ||
| 85 | }; | ||
| 86 | |||
| 87 | operator.configure_firc_clocks()?; | ||
| 88 | operator.configure_sirc_clocks()?; | ||
| 89 | operator.configure_fro16k_clocks()?; | ||
| 90 | |||
| 91 | // For now, just use FIRC as the main/cpu clock, which should already be | ||
| 92 | // the case on reset | ||
| 93 | assert!(operator.scg0.rccr().read().scs().is_firc()); | ||
| 94 | let input = operator.clocks.fro_hf_root.clone().unwrap(); | ||
| 95 | operator.clocks.main_clk = Some(input.clone()); | ||
| 96 | // We can also assume cpu/system clk == fro_hf because div is /1. | ||
| 97 | assert_eq!(operator.syscon.ahbclkdiv().read().div().bits(), 0); | ||
| 98 | operator.clocks.cpu_system_clk = Some(input); | ||
| 99 | |||
| 100 | critical_section::with(|cs| { | ||
| 101 | let mut clks = CLOCKS.borrow_ref_mut(cs); | ||
| 102 | assert!(clks.is_none(), "Clock setup race!"); | ||
| 103 | *clks = Some(clocks); | ||
| 104 | }); | ||
| 105 | |||
| 106 | Ok(()) | ||
| 107 | } | ||
| 108 | |||
| 109 | /// Obtain the full clocks structure, calling the given closure in a critical section. | ||
| 110 | /// | ||
| 111 | /// The given closure will be called with read-only access to the state of the system | ||
| 112 | /// clocks. This can be used to query and return the state of a given clock. | ||
| 113 | /// | ||
| 114 | /// As the caller's closure will be called in a critical section, care must be taken | ||
| 115 | /// not to block or cause any other undue delays while accessing. | ||
| 116 | /// | ||
| 117 | /// Calls to this function will not succeed until after a successful call to `init()`, | ||
| 118 | /// and will always return None. | ||
| 119 | pub fn with_clocks<R: 'static, F: FnOnce(&Clocks) -> R>(f: F) -> Option<R> { | ||
| 120 | critical_section::with(|cs| { | ||
| 121 | let c = CLOCKS.borrow_ref(cs); | ||
| 122 | let c = c.as_ref()?; | ||
| 123 | Some(f(c)) | ||
| 124 | }) | ||
| 125 | } | ||
| 126 | |||
| 127 | // | ||
| 128 | // Structs/Enums | ||
| 129 | // | ||
| 130 | |||
| 131 | /// The `Clocks` structure contains the initialized state of the core system clocks | ||
| 132 | /// | ||
| 133 | /// These values are configured by providing [`config::ClocksConfig`] to the [`init()`] function | ||
| 134 | /// at boot time. | ||
| 135 | #[derive(Default, Debug, Clone)] | ||
| 136 | #[non_exhaustive] | ||
| 137 | pub struct Clocks { | ||
| 138 | /// The `clk_in` is a clock provided by an external oscillator | ||
| 139 | pub clk_in: Option<Clock>, | ||
| 140 | |||
| 141 | // FRO180M stuff | ||
| 142 | // | ||
| 143 | /// `fro_hf_root` is the direct output of the `FRO180M` internal oscillator | ||
| 144 | /// | ||
| 145 | /// It is used to feed downstream clocks, such as `fro_hf`, `clk_45m`, | ||
| 146 | /// and `fro_hf_div`. | ||
| 147 | pub fro_hf_root: Option<Clock>, | ||
| 148 | |||
| 149 | /// `fro_hf` is the same frequency as `fro_hf_root`, but behind a gate. | ||
| 150 | pub fro_hf: Option<Clock>, | ||
| 151 | |||
| 152 | /// `clk_45` is a 45MHz clock, sourced from `fro_hf`. | ||
| 153 | pub clk_45m: Option<Clock>, | ||
| 154 | |||
| 155 | /// `fro_hf_div` is a configurable frequency clock, sourced from `fro_hf`. | ||
| 156 | pub fro_hf_div: Option<Clock>, | ||
| 157 | |||
| 158 | // | ||
| 159 | // End FRO180M | ||
| 160 | |||
| 161 | // FRO12M stuff | ||
| 162 | // | ||
| 163 | /// `fro_12m_root` is the direct output of the `FRO12M` internal oscillator | ||
| 164 | /// | ||
| 165 | /// It is used to feed downstream clocks, such as `fro_12m`, `clk_1m`, | ||
| 166 | /// `and `fro_lf_div`. | ||
| 167 | pub fro_12m_root: Option<Clock>, | ||
| 168 | |||
| 169 | /// `fro_12m` is the same frequency as `fro_12m_root`, but behind a gate. | ||
| 170 | pub fro_12m: Option<Clock>, | ||
| 171 | |||
| 172 | /// `clk_1m` is a 1MHz clock, sourced from `fro_12m` | ||
| 173 | pub clk_1m: Option<Clock>, | ||
| 174 | |||
| 175 | /// `fro_lf_div` is a configurable frequency clock, sourced from `fro_12m` | ||
| 176 | pub fro_lf_div: Option<Clock>, | ||
| 177 | // | ||
| 178 | // End FRO12M stuff | ||
| 179 | /// `clk_16k_vsys` is one of two outputs of the `FRO16K` internal oscillator. | ||
| 180 | /// | ||
| 181 | /// Also referred to as `clk_16k[0]` in the datasheet, it feeds peripherals in | ||
| 182 | /// the system domain, such as the CMP and RTC. | ||
| 183 | pub clk_16k_vsys: Option<Clock>, | ||
| 184 | |||
| 185 | /// `clk_16k_vdd_core` is one of two outputs of the `FRO16K` internal oscillator. | ||
| 186 | /// | ||
| 187 | /// Also referred to as `clk_16k[1]` in the datasheet, it feeds peripherals in | ||
| 188 | /// the VDD Core domain, such as the OSTimer or LPUarts. | ||
| 189 | pub clk_16k_vdd_core: Option<Clock>, | ||
| 190 | |||
| 191 | /// `main_clk` is the main clock used by the CPU, AHB, APB, IPS bus, and some | ||
| 192 | /// peripherals. | ||
| 193 | pub main_clk: Option<Clock>, | ||
| 194 | |||
| 195 | /// `CPU_CLK` or `SYSTEM_CLK` is the output of `main_clk`, run through the `AHBCLKDIV` | ||
| 196 | pub cpu_system_clk: Option<Clock>, | ||
| 197 | |||
| 198 | /// `pll1_clk` is the output of the main system PLL, `pll1`. | ||
| 199 | pub pll1_clk: Option<Clock>, | ||
| 200 | } | ||
| 201 | |||
| 202 | /// `ClockError` is the main error returned when configuring or checking clock state | ||
| 203 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 204 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 205 | #[non_exhaustive] | ||
| 206 | pub enum ClockError { | ||
| 207 | /// The system clocks were never initialized by calling [`init()`] | ||
| 208 | NeverInitialized, | ||
| 209 | /// The [`init()`] function was called more than once | ||
| 210 | AlreadyInitialized, | ||
| 211 | /// The requested configuration was not possible to fulfill, as the system clocks | ||
| 212 | /// were not configured in a compatible way | ||
| 213 | BadConfig { clock: &'static str, reason: &'static str }, | ||
| 214 | /// The requested configuration was not possible to fulfill, as the required system | ||
| 215 | /// clocks have not yet been implemented. | ||
| 216 | NotImplemented { clock: &'static str }, | ||
| 217 | /// The requested peripheral could not be configured, as the steps necessary to | ||
| 218 | /// enable it have not yet been implemented. | ||
| 219 | UnimplementedConfig, | ||
| 220 | } | ||
| 221 | |||
| 222 | /// Information regarding a system clock | ||
| 223 | #[derive(Debug, Clone)] | ||
| 224 | pub struct Clock { | ||
| 225 | /// The frequency, in Hz, of the given clock | ||
| 226 | pub frequency: u32, | ||
| 227 | /// The power state of the clock, e.g. whether it is active in deep sleep mode | ||
| 228 | /// or not. | ||
| 229 | pub power: PoweredClock, | ||
| 230 | } | ||
| 231 | |||
| 232 | /// The power state of a given clock. | ||
| 233 | /// | ||
| 234 | /// On the MCX-A, when Deep-Sleep is entered, any clock not configured for Deep Sleep | ||
| 235 | /// mode will be stopped. This means that any downstream usage, e.g. by peripherals, | ||
| 236 | /// will also stop. | ||
| 237 | /// | ||
| 238 | /// In the future, we will provide an API for entering Deep Sleep, and if there are | ||
| 239 | /// any peripherals that are NOT using an `AlwaysEnabled` clock active, entry into | ||
| 240 | /// Deep Sleep will be prevented, in order to avoid misbehaving peripherals. | ||
| 241 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 242 | pub enum PoweredClock { | ||
| 243 | /// The given clock will NOT continue running in Deep Sleep mode | ||
| 244 | NormalEnabledDeepSleepDisabled, | ||
| 245 | /// The given clock WILL continue running in Deep Sleep mode | ||
| 246 | AlwaysEnabled, | ||
| 247 | } | ||
| 248 | |||
| 249 | /// The ClockOperator is a private helper type that contains the methods used | ||
| 250 | /// during system clock initialization. | ||
| 251 | /// | ||
| 252 | /// # SAFETY | ||
| 253 | /// | ||
| 254 | /// Concurrent access to clock-relevant peripheral registers, such as `MRCC`, `SCG`, | ||
| 255 | /// `SYSCON`, and `VBAT` should not be allowed for the duration of the [`init()`] function. | ||
| 256 | struct ClockOperator<'a> { | ||
| 257 | /// A mutable reference to the current state of system clocks | ||
| 258 | clocks: &'a mut Clocks, | ||
| 259 | /// A reference to the requested configuration provided by the caller of [`init()`] | ||
| 260 | config: &'a ClocksConfig, | ||
| 261 | |||
| 262 | // We hold on to stolen peripherals | ||
| 263 | _mrcc0: pac::Mrcc0, | ||
| 264 | scg0: pac::Scg0, | ||
| 265 | syscon: pac::Syscon, | ||
| 266 | vbat0: pac::Vbat0, | ||
| 267 | } | ||
| 268 | |||
| 269 | /// Trait describing an AHB clock gate that can be toggled through MRCC. | ||
| 270 | pub trait Gate { | ||
| 271 | type MrccPeriphConfig: SPConfHelper; | ||
| 272 | |||
| 273 | /// Enable the clock gate. | ||
| 274 | /// | ||
| 275 | /// # SAFETY | ||
| 276 | /// | ||
| 277 | /// The current peripheral must be disabled prior to calling this method | ||
| 278 | unsafe fn enable_clock(); | ||
| 279 | |||
| 280 | /// Disable the clock gate. | ||
| 281 | /// | ||
| 282 | /// # SAFETY | ||
| 283 | /// | ||
| 284 | /// There must be no active user of this peripheral when calling this method | ||
| 285 | unsafe fn disable_clock(); | ||
| 286 | |||
| 287 | /// Drive the peripheral into reset. | ||
| 288 | /// | ||
| 289 | /// # SAFETY | ||
| 290 | /// | ||
| 291 | /// There must be no active user of this peripheral when calling this method | ||
| 292 | unsafe fn assert_reset(); | ||
| 293 | |||
| 294 | /// Drive the peripheral out of reset. | ||
| 295 | /// | ||
| 296 | /// # SAFETY | ||
| 297 | /// | ||
| 298 | /// There must be no active user of this peripheral when calling this method | ||
| 299 | unsafe fn release_reset(); | ||
| 300 | |||
| 301 | /// Return whether the clock gate for this peripheral is currently enabled. | ||
| 302 | fn is_clock_enabled() -> bool; | ||
| 303 | |||
| 304 | /// Return whether the peripheral is currently held in reset. | ||
| 305 | fn is_reset_released() -> bool; | ||
| 306 | } | ||
| 307 | |||
| 308 | /// This is the primary helper method HAL drivers are expected to call when creating | ||
| 309 | /// an instance of the peripheral. | ||
| 310 | /// | ||
| 311 | /// This method: | ||
| 312 | /// | ||
| 313 | /// 1. Enables the MRCC clock gate for this peripheral | ||
| 314 | /// 2. Calls the `G::MrccPeriphConfig::post_enable_config()` method, returning an error | ||
| 315 | /// and re-disabling the peripheral if this fails. | ||
| 316 | /// 3. Pulses the MRCC reset line, to reset the peripheral to the default state | ||
| 317 | /// 4. Returns the frequency, in Hz that is fed into the peripheral, taking into account | ||
| 318 | /// the selected upstream clock, as well as any division specified by `cfg`. | ||
| 319 | /// | ||
| 320 | /// NOTE: if a clock is disabled, sourced from an "ambient" clock source, this method | ||
| 321 | /// may return `Ok(0)`. In the future, this might be updated to return the correct | ||
| 322 | /// "ambient" clock, e.g. the AHB/APB frequency. | ||
| 323 | /// | ||
| 324 | /// # SAFETY | ||
| 325 | /// | ||
| 326 | /// This peripheral must not yet be in use prior to calling `enable_and_reset`. | ||
| 327 | #[inline] | ||
| 328 | pub unsafe fn enable_and_reset<G: Gate>(cfg: &G::MrccPeriphConfig) -> Result<u32, ClockError> { | ||
| 329 | let freq = enable::<G>(cfg).inspect_err(|_| disable::<G>())?; | ||
| 330 | pulse_reset::<G>(); | ||
| 331 | Ok(freq) | ||
| 332 | } | ||
| 333 | |||
| 334 | /// Enable the clock gate for the given peripheral. | ||
| 335 | /// | ||
| 336 | /// Prefer [`enable_and_reset`] unless you are specifically avoiding a pulse of the reset, or need | ||
| 337 | /// to control the duration of the pulse more directly. | ||
| 338 | /// | ||
| 339 | /// # SAFETY | ||
| 340 | /// | ||
| 341 | /// This peripheral must not yet be in use prior to calling `enable`. | ||
| 342 | #[inline] | ||
| 343 | pub unsafe fn enable<G: Gate>(cfg: &G::MrccPeriphConfig) -> Result<u32, ClockError> { | ||
| 344 | G::enable_clock(); | ||
| 345 | while !G::is_clock_enabled() {} | ||
| 346 | core::arch::asm!("dsb sy; isb sy", options(nomem, nostack, preserves_flags)); | ||
| 347 | |||
| 348 | let freq = critical_section::with(|cs| { | ||
| 349 | let clocks = CLOCKS.borrow_ref(cs); | ||
| 350 | let clocks = clocks.as_ref().ok_or(ClockError::NeverInitialized)?; | ||
| 351 | cfg.post_enable_config(clocks) | ||
| 352 | }); | ||
| 353 | |||
| 354 | freq.inspect_err(|_e| { | ||
| 355 | G::disable_clock(); | ||
| 356 | }) | ||
| 357 | } | ||
| 358 | |||
| 359 | /// Disable the clock gate for the given peripheral. | ||
| 360 | /// | ||
| 361 | /// # SAFETY | ||
| 362 | /// | ||
| 363 | /// This peripheral must no longer be in use prior to calling `enable`. | ||
| 364 | #[allow(dead_code)] | ||
| 365 | #[inline] | ||
| 366 | pub unsafe fn disable<G: Gate>() { | ||
| 367 | G::disable_clock(); | ||
| 368 | } | ||
| 369 | |||
| 370 | /// Check whether a gate is currently enabled. | ||
| 371 | #[allow(dead_code)] | ||
| 372 | #[inline] | ||
| 373 | pub fn is_clock_enabled<G: Gate>() -> bool { | ||
| 374 | G::is_clock_enabled() | ||
| 375 | } | ||
| 376 | |||
| 377 | /// Release a reset line for the given peripheral set. | ||
| 378 | /// | ||
| 379 | /// Prefer [`enable_and_reset`]. | ||
| 380 | /// | ||
| 381 | /// # SAFETY | ||
| 382 | /// | ||
| 383 | /// This peripheral must not yet be in use prior to calling `release_reset`. | ||
| 384 | #[inline] | ||
| 385 | pub unsafe fn release_reset<G: Gate>() { | ||
| 386 | G::release_reset(); | ||
| 387 | } | ||
| 388 | |||
| 389 | /// Assert a reset line for the given peripheral set. | ||
| 390 | /// | ||
| 391 | /// Prefer [`enable_and_reset`]. | ||
| 392 | /// | ||
| 393 | /// # SAFETY | ||
| 394 | /// | ||
| 395 | /// This peripheral must not yet be in use prior to calling `assert_reset`. | ||
| 396 | #[inline] | ||
| 397 | pub unsafe fn assert_reset<G: Gate>() { | ||
| 398 | G::assert_reset(); | ||
| 399 | } | ||
| 400 | |||
| 401 | /// Check whether the peripheral is held in reset. | ||
| 402 | #[inline] | ||
| 403 | pub unsafe fn is_reset_released<G: Gate>() -> bool { | ||
| 404 | G::is_reset_released() | ||
| 405 | } | ||
| 406 | |||
| 407 | /// Pulse a reset line (assert then release) with a short delay. | ||
| 408 | /// | ||
| 409 | /// Prefer [`enable_and_reset`]. | ||
| 410 | /// | ||
| 411 | /// # SAFETY | ||
| 412 | /// | ||
| 413 | /// This peripheral must not yet be in use prior to calling `release_reset`. | ||
| 414 | #[inline] | ||
| 415 | pub unsafe fn pulse_reset<G: Gate>() { | ||
| 416 | G::assert_reset(); | ||
| 417 | cortex_m::asm::nop(); | ||
| 418 | cortex_m::asm::nop(); | ||
| 419 | G::release_reset(); | ||
| 420 | } | ||
| 421 | |||
| 422 | // | ||
| 423 | // `impl`s for structs/enums | ||
| 424 | // | ||
| 425 | |||
| 426 | /// The [`Clocks`] type's methods generally take the form of "ensure X clock is active". | ||
| 427 | /// | ||
| 428 | /// These methods are intended to be used by HAL peripheral implementors to ensure that their | ||
| 429 | /// selected clocks are active at a suitable level at time of construction. These methods | ||
| 430 | /// return the frequency of the requested clock, in Hertz, or a [`ClockError`]. | ||
| 431 | impl Clocks { | ||
| 432 | /// Ensure the `fro_lf_div` clock is active and valid at the given power state. | ||
| 433 | pub fn ensure_fro_lf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 434 | let Some(clk) = self.fro_lf_div.as_ref() else { | ||
| 435 | return Err(ClockError::BadConfig { | ||
| 436 | clock: "fro_lf_div", | ||
| 437 | reason: "required but not active", | ||
| 438 | }); | ||
| 439 | }; | ||
| 440 | if !clk.power.meets_requirement_of(at_level) { | ||
| 441 | return Err(ClockError::BadConfig { | ||
| 442 | clock: "fro_lf_div", | ||
| 443 | reason: "not low power active", | ||
| 444 | }); | ||
| 445 | } | ||
| 446 | Ok(clk.frequency) | ||
| 447 | } | ||
| 448 | |||
| 449 | /// Ensure the `fro_hf` clock is active and valid at the given power state. | ||
| 450 | pub fn ensure_fro_hf_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 451 | let Some(clk) = self.fro_hf.as_ref() else { | ||
| 452 | return Err(ClockError::BadConfig { | ||
| 453 | clock: "fro_hf", | ||
| 454 | reason: "required but not active", | ||
| 455 | }); | ||
| 456 | }; | ||
| 457 | if !clk.power.meets_requirement_of(at_level) { | ||
| 458 | return Err(ClockError::BadConfig { | ||
| 459 | clock: "fro_hf", | ||
| 460 | reason: "not low power active", | ||
| 461 | }); | ||
| 462 | } | ||
| 463 | Ok(clk.frequency) | ||
| 464 | } | ||
| 465 | |||
| 466 | /// Ensure the `fro_hf_div` clock is active and valid at the given power state. | ||
| 467 | pub fn ensure_fro_hf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 468 | let Some(clk) = self.fro_hf_div.as_ref() else { | ||
| 469 | return Err(ClockError::BadConfig { | ||
| 470 | clock: "fro_hf_div", | ||
| 471 | reason: "required but not active", | ||
| 472 | }); | ||
| 473 | }; | ||
| 474 | if !clk.power.meets_requirement_of(at_level) { | ||
| 475 | return Err(ClockError::BadConfig { | ||
| 476 | clock: "fro_hf_div", | ||
| 477 | reason: "not low power active", | ||
| 478 | }); | ||
| 479 | } | ||
| 480 | Ok(clk.frequency) | ||
| 481 | } | ||
| 482 | |||
| 483 | /// Ensure the `clk_in` clock is active and valid at the given power state. | ||
| 484 | pub fn ensure_clk_in_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 485 | Err(ClockError::NotImplemented { clock: "clk_in" }) | ||
| 486 | } | ||
| 487 | |||
| 488 | /// Ensure the `clk_16k_vsys` clock is active and valid at the given power state. | ||
| 489 | pub fn ensure_clk_16k_vsys_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 490 | // NOTE: clk_16k is always active in low power mode | ||
| 491 | Ok(self | ||
| 492 | .clk_16k_vsys | ||
| 493 | .as_ref() | ||
| 494 | .ok_or(ClockError::BadConfig { | ||
| 495 | clock: "clk_16k_vsys", | ||
| 496 | reason: "required but not active", | ||
| 497 | })? | ||
| 498 | .frequency) | ||
| 499 | } | ||
| 500 | |||
| 501 | /// Ensure the `clk_16k_vdd_core` clock is active and valid at the given power state. | ||
| 502 | pub fn ensure_clk_16k_vdd_core_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 503 | // NOTE: clk_16k is always active in low power mode | ||
| 504 | Ok(self | ||
| 505 | .clk_16k_vdd_core | ||
| 506 | .as_ref() | ||
| 507 | .ok_or(ClockError::BadConfig { | ||
| 508 | clock: "clk_16k_vdd_core", | ||
| 509 | reason: "required but not active", | ||
| 510 | })? | ||
| 511 | .frequency) | ||
| 512 | } | ||
| 513 | |||
| 514 | /// Ensure the `clk_1m` clock is active and valid at the given power state. | ||
| 515 | pub fn ensure_clk_1m_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 516 | let Some(clk) = self.clk_1m.as_ref() else { | ||
| 517 | return Err(ClockError::BadConfig { | ||
| 518 | clock: "clk_1m", | ||
| 519 | reason: "required but not active", | ||
| 520 | }); | ||
| 521 | }; | ||
| 522 | if !clk.power.meets_requirement_of(at_level) { | ||
| 523 | return Err(ClockError::BadConfig { | ||
| 524 | clock: "clk_1m", | ||
| 525 | reason: "not low power active", | ||
| 526 | }); | ||
| 527 | } | ||
| 528 | Ok(clk.frequency) | ||
| 529 | } | ||
| 530 | |||
| 531 | /// Ensure the `pll1_clk` clock is active and valid at the given power state. | ||
| 532 | pub fn ensure_pll1_clk_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 533 | Err(ClockError::NotImplemented { clock: "pll1_clk" }) | ||
| 534 | } | ||
| 535 | |||
| 536 | /// Ensure the `pll1_clk_div` clock is active and valid at the given power state. | ||
| 537 | pub fn ensure_pll1_clk_div_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 538 | Err(ClockError::NotImplemented { clock: "pll1_clk_div" }) | ||
| 539 | } | ||
| 540 | |||
| 541 | /// Ensure the `CPU_CLK` or `SYSTEM_CLK` is active | ||
| 542 | pub fn ensure_cpu_system_clk_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 543 | let Some(clk) = self.cpu_system_clk.as_ref() else { | ||
| 544 | return Err(ClockError::BadConfig { | ||
| 545 | clock: "cpu_system_clk", | ||
| 546 | reason: "required but not active", | ||
| 547 | }); | ||
| 548 | }; | ||
| 549 | // Can the main_clk ever be active in deep sleep? I think it is gated? | ||
| 550 | match at_level { | ||
| 551 | PoweredClock::NormalEnabledDeepSleepDisabled => {} | ||
| 552 | PoweredClock::AlwaysEnabled => { | ||
| 553 | return Err(ClockError::BadConfig { | ||
| 554 | clock: "main_clk", | ||
| 555 | reason: "not low power active", | ||
| 556 | }); | ||
| 557 | } | ||
| 558 | } | ||
| 559 | |||
| 560 | Ok(clk.frequency) | ||
| 561 | } | ||
| 562 | |||
| 563 | pub fn ensure_slow_clk_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { | ||
| 564 | let freq = self.ensure_cpu_system_clk_active(at_level)?; | ||
| 565 | |||
| 566 | Ok(freq / 6) | ||
| 567 | } | ||
| 568 | } | ||
| 569 | |||
| 570 | impl PoweredClock { | ||
| 571 | /// Does THIS clock meet the power requirements of the OTHER clock? | ||
| 572 | pub fn meets_requirement_of(&self, other: &Self) -> bool { | ||
| 573 | match (self, other) { | ||
| 574 | (PoweredClock::NormalEnabledDeepSleepDisabled, PoweredClock::AlwaysEnabled) => false, | ||
| 575 | (PoweredClock::NormalEnabledDeepSleepDisabled, PoweredClock::NormalEnabledDeepSleepDisabled) => true, | ||
| 576 | (PoweredClock::AlwaysEnabled, PoweredClock::NormalEnabledDeepSleepDisabled) => true, | ||
| 577 | (PoweredClock::AlwaysEnabled, PoweredClock::AlwaysEnabled) => true, | ||
| 578 | } | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | impl ClockOperator<'_> { | ||
| 583 | /// Configure the FIRC/FRO180M clock family | ||
| 584 | /// | ||
| 585 | /// NOTE: Currently we require this to be a fairly hardcoded value, as this clock is used | ||
| 586 | /// as the main clock used for the CPU, AHB, APB, etc. | ||
| 587 | fn configure_firc_clocks(&mut self) -> Result<(), ClockError> { | ||
| 588 | const HARDCODED_ERR: Result<(), ClockError> = Err(ClockError::BadConfig { | ||
| 589 | clock: "firc", | ||
| 590 | reason: "For now, FIRC must be enabled and in default state!", | ||
| 591 | }); | ||
| 592 | |||
| 593 | // Did the user give us a FIRC config? | ||
| 594 | let Some(firc) = self.config.firc.as_ref() else { | ||
| 595 | return HARDCODED_ERR; | ||
| 596 | }; | ||
| 597 | // Is the FIRC set to 45MHz (should be reset default) | ||
| 598 | if !matches!(firc.frequency, FircFreqSel::Mhz45) { | ||
| 599 | return HARDCODED_ERR; | ||
| 600 | } | ||
| 601 | let base_freq = 45_000_000; | ||
| 602 | |||
| 603 | // Now, check if the FIRC as expected for our hardcoded value | ||
| 604 | let mut firc_ok = true; | ||
| 605 | |||
| 606 | // Is the hardware currently set to the default 45MHz? | ||
| 607 | // | ||
| 608 | // NOTE: the SVD currently has the wrong(?) values for these: | ||
| 609 | // 45 -> 48 | ||
| 610 | // 60 -> 64 | ||
| 611 | // 90 -> 96 | ||
| 612 | // 180 -> 192 | ||
| 613 | // Probably correct-ish, but for a different trim value? | ||
| 614 | firc_ok &= self.scg0.firccfg().read().freq_sel().is_firc_48mhz_192s(); | ||
| 615 | |||
| 616 | // Check some values in the CSR | ||
| 617 | let csr = self.scg0.firccsr().read(); | ||
| 618 | // Is it enabled? | ||
| 619 | firc_ok &= csr.fircen().is_enabled(); | ||
| 620 | // Is it accurate? | ||
| 621 | firc_ok &= csr.fircacc().is_enabled_and_valid(); | ||
| 622 | // Is there no error? | ||
| 623 | firc_ok &= csr.fircerr().is_error_not_detected(); | ||
| 624 | // Is the FIRC the system clock? | ||
| 625 | firc_ok &= csr.fircsel().is_firc(); | ||
| 626 | // Is it valid? | ||
| 627 | firc_ok &= csr.fircvld().is_enabled_and_valid(); | ||
| 628 | |||
| 629 | // Are we happy with the current (hardcoded) state? | ||
| 630 | if !firc_ok { | ||
| 631 | return HARDCODED_ERR; | ||
| 632 | } | ||
| 633 | |||
| 634 | // Note that the fro_hf_root is active | ||
| 635 | self.clocks.fro_hf_root = Some(Clock { | ||
| 636 | frequency: base_freq, | ||
| 637 | power: firc.power, | ||
| 638 | }); | ||
| 639 | |||
| 640 | // Okay! Now we're past that, let's enable all the downstream clocks. | ||
| 641 | let FircConfig { | ||
| 642 | frequency: _, | ||
| 643 | power, | ||
| 644 | fro_hf_enabled, | ||
| 645 | clk_45m_enabled, | ||
| 646 | fro_hf_div, | ||
| 647 | } = firc; | ||
| 648 | |||
| 649 | // When is the FRO enabled? | ||
| 650 | let pow_set = match power { | ||
| 651 | PoweredClock::NormalEnabledDeepSleepDisabled => Fircsten::DisabledInStopModes, | ||
| 652 | PoweredClock::AlwaysEnabled => Fircsten::EnabledInStopModes, | ||
| 653 | }; | ||
| 654 | |||
| 655 | // Do we enable the `fro_hf` output? | ||
| 656 | let fro_hf_set = if *fro_hf_enabled { | ||
| 657 | self.clocks.fro_hf = Some(Clock { | ||
| 658 | frequency: base_freq, | ||
| 659 | power: *power, | ||
| 660 | }); | ||
| 661 | FircFclkPeriphEn::Enabled | ||
| 662 | } else { | ||
| 663 | FircFclkPeriphEn::Disabled | ||
| 664 | }; | ||
| 665 | |||
| 666 | // Do we enable the `clk_45m` output? | ||
| 667 | let clk_45m_set = if *clk_45m_enabled { | ||
| 668 | self.clocks.clk_45m = Some(Clock { | ||
| 669 | frequency: 45_000_000, | ||
| 670 | power: *power, | ||
| 671 | }); | ||
| 672 | FircSclkPeriphEn::Enabled | ||
| 673 | } else { | ||
| 674 | FircSclkPeriphEn::Disabled | ||
| 675 | }; | ||
| 676 | |||
| 677 | self.scg0.firccsr().modify(|_r, w| { | ||
| 678 | w.fircsten().variant(pow_set); | ||
| 679 | w.firc_fclk_periph_en().variant(fro_hf_set); | ||
| 680 | w.firc_sclk_periph_en().variant(clk_45m_set); | ||
| 681 | w | ||
| 682 | }); | ||
| 683 | |||
| 684 | // Do we enable the `fro_hf_div` output? | ||
| 685 | if let Some(d) = fro_hf_div.as_ref() { | ||
| 686 | // We need `fro_hf` to be enabled | ||
| 687 | if !*fro_hf_enabled { | ||
| 688 | return Err(ClockError::BadConfig { | ||
| 689 | clock: "fro_hf_div", | ||
| 690 | reason: "fro_hf not enabled", | ||
| 691 | }); | ||
| 692 | } | ||
| 693 | |||
| 694 | // Halt and reset the div; then set our desired div. | ||
| 695 | self.syscon.frohfdiv().write(|w| { | ||
| 696 | w.halt().halt(); | ||
| 697 | w.reset().asserted(); | ||
| 698 | unsafe { w.div().bits(d.into_bits()) }; | ||
| 699 | w | ||
| 700 | }); | ||
| 701 | // Then unhalt it, and reset it | ||
| 702 | self.syscon.frohfdiv().write(|w| { | ||
| 703 | w.halt().run(); | ||
| 704 | w.reset().released(); | ||
| 705 | w | ||
| 706 | }); | ||
| 707 | |||
| 708 | // Wait for clock to stabilize | ||
| 709 | while self.syscon.frohfdiv().read().unstab().is_ongoing() {} | ||
| 710 | |||
| 711 | // Store off the clock info | ||
| 712 | self.clocks.fro_hf_div = Some(Clock { | ||
| 713 | frequency: base_freq / d.into_divisor(), | ||
| 714 | power: *power, | ||
| 715 | }); | ||
| 716 | } | ||
| 717 | |||
| 718 | Ok(()) | ||
| 719 | } | ||
| 720 | |||
| 721 | /// Configure the SIRC/FRO12M clock family | ||
| 722 | fn configure_sirc_clocks(&mut self) -> Result<(), ClockError> { | ||
| 723 | let SircConfig { | ||
| 724 | power, | ||
| 725 | fro_12m_enabled, | ||
| 726 | fro_lf_div, | ||
| 727 | } = &self.config.sirc; | ||
| 728 | let base_freq = 12_000_000; | ||
| 729 | |||
| 730 | // Allow writes | ||
| 731 | self.scg0.sirccsr().modify(|_r, w| w.lk().write_enabled()); | ||
| 732 | self.clocks.fro_12m_root = Some(Clock { | ||
| 733 | frequency: base_freq, | ||
| 734 | power: *power, | ||
| 735 | }); | ||
| 736 | |||
| 737 | let deep = match power { | ||
| 738 | PoweredClock::NormalEnabledDeepSleepDisabled => Sircsten::Disabled, | ||
| 739 | PoweredClock::AlwaysEnabled => Sircsten::Enabled, | ||
| 740 | }; | ||
| 741 | let pclk = if *fro_12m_enabled { | ||
| 742 | self.clocks.fro_12m = Some(Clock { | ||
| 743 | frequency: base_freq, | ||
| 744 | power: *power, | ||
| 745 | }); | ||
| 746 | self.clocks.clk_1m = Some(Clock { | ||
| 747 | frequency: base_freq / 12, | ||
| 748 | power: *power, | ||
| 749 | }); | ||
| 750 | SircClkPeriphEn::Enabled | ||
| 751 | } else { | ||
| 752 | SircClkPeriphEn::Disabled | ||
| 753 | }; | ||
| 754 | |||
| 755 | // Set sleep/peripheral usage | ||
| 756 | self.scg0.sirccsr().modify(|_r, w| { | ||
| 757 | w.sircsten().variant(deep); | ||
| 758 | w.sirc_clk_periph_en().variant(pclk); | ||
| 759 | w | ||
| 760 | }); | ||
| 761 | |||
| 762 | while self.scg0.sirccsr().read().sircvld().is_disabled_or_not_valid() {} | ||
| 763 | if self.scg0.sirccsr().read().sircerr().is_error_detected() { | ||
| 764 | return Err(ClockError::BadConfig { | ||
| 765 | clock: "sirc", | ||
| 766 | reason: "error set", | ||
| 767 | }); | ||
| 768 | } | ||
| 769 | |||
| 770 | // reset lock | ||
| 771 | self.scg0.sirccsr().modify(|_r, w| w.lk().write_disabled()); | ||
| 772 | |||
| 773 | // Do we enable the `fro_lf_div` output? | ||
| 774 | if let Some(d) = fro_lf_div.as_ref() { | ||
| 775 | // We need `fro_lf` to be enabled | ||
| 776 | if !*fro_12m_enabled { | ||
| 777 | return Err(ClockError::BadConfig { | ||
| 778 | clock: "fro_lf_div", | ||
| 779 | reason: "fro_12m not enabled", | ||
| 780 | }); | ||
| 781 | } | ||
| 782 | |||
| 783 | // Halt and reset the div; then set our desired div. | ||
| 784 | self.syscon.frolfdiv().write(|w| { | ||
| 785 | w.halt().halt(); | ||
| 786 | w.reset().asserted(); | ||
| 787 | unsafe { w.div().bits(d.into_bits()) }; | ||
| 788 | w | ||
| 789 | }); | ||
| 790 | // Then unhalt it, and reset it | ||
| 791 | self.syscon.frolfdiv().modify(|_r, w| { | ||
| 792 | w.halt().run(); | ||
| 793 | w.reset().released(); | ||
| 794 | w | ||
| 795 | }); | ||
| 796 | |||
| 797 | // Wait for clock to stabilize | ||
| 798 | while self.syscon.frolfdiv().read().unstab().is_ongoing() {} | ||
| 799 | |||
| 800 | // Store off the clock info | ||
| 801 | self.clocks.fro_lf_div = Some(Clock { | ||
| 802 | frequency: base_freq / d.into_divisor(), | ||
| 803 | power: *power, | ||
| 804 | }); | ||
| 805 | } | ||
| 806 | |||
| 807 | Ok(()) | ||
| 808 | } | ||
| 809 | |||
| 810 | /// Configure the FRO16K/clk_16k clock family | ||
| 811 | fn configure_fro16k_clocks(&mut self) -> Result<(), ClockError> { | ||
| 812 | let Some(fro16k) = self.config.fro16k.as_ref() else { | ||
| 813 | return Ok(()); | ||
| 814 | }; | ||
| 815 | // Enable FRO16K oscillator | ||
| 816 | self.vbat0.froctla().modify(|_, w| w.fro_en().set_bit()); | ||
| 817 | |||
| 818 | // Lock the control register | ||
| 819 | self.vbat0.frolcka().modify(|_, w| w.lock().set_bit()); | ||
| 820 | |||
| 821 | let Fro16KConfig { | ||
| 822 | vsys_domain_active, | ||
| 823 | vdd_core_domain_active, | ||
| 824 | } = fro16k; | ||
| 825 | |||
| 826 | // Enable clock outputs to both VSYS and VDD_CORE domains | ||
| 827 | // Bit 0: clk_16k0 to VSYS domain | ||
| 828 | // Bit 1: clk_16k1 to VDD_CORE domain | ||
| 829 | // | ||
| 830 | // TODO: Define sub-fields for this register with a PAC patch? | ||
| 831 | let mut bits = 0; | ||
| 832 | if *vsys_domain_active { | ||
| 833 | bits |= 0b01; | ||
| 834 | self.clocks.clk_16k_vsys = Some(Clock { | ||
| 835 | frequency: 16_384, | ||
| 836 | power: PoweredClock::AlwaysEnabled, | ||
| 837 | }); | ||
| 838 | } | ||
| 839 | if *vdd_core_domain_active { | ||
| 840 | bits |= 0b10; | ||
| 841 | self.clocks.clk_16k_vdd_core = Some(Clock { | ||
| 842 | frequency: 16_384, | ||
| 843 | power: PoweredClock::AlwaysEnabled, | ||
| 844 | }); | ||
| 845 | } | ||
| 846 | self.vbat0.froclke().modify(|_r, w| unsafe { w.clke().bits(bits) }); | ||
| 847 | |||
| 848 | Ok(()) | ||
| 849 | } | ||
| 850 | } | ||
| 851 | |||
| 852 | // | ||
| 853 | // Macros/macro impls | ||
| 854 | // | ||
| 855 | |||
| 856 | /// This macro is used to implement the [`Gate`] trait for a given peripheral | ||
| 857 | /// that is controlled by the MRCC peripheral. | ||
| 858 | macro_rules! impl_cc_gate { | ||
| 859 | ($name:ident, $clk_reg:ident, $rst_reg:ident, $field:ident, $config:ty) => { | ||
| 860 | impl Gate for crate::peripherals::$name { | ||
| 861 | type MrccPeriphConfig = $config; | ||
| 862 | |||
| 863 | #[inline] | ||
| 864 | unsafe fn enable_clock() { | ||
| 865 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 866 | mrcc.$clk_reg().modify(|_, w| w.$field().enabled()); | ||
| 867 | } | ||
| 868 | |||
| 869 | #[inline] | ||
| 870 | unsafe fn disable_clock() { | ||
| 871 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 872 | mrcc.$clk_reg().modify(|_r, w| w.$field().disabled()); | ||
| 873 | } | ||
| 874 | |||
| 875 | #[inline] | ||
| 876 | fn is_clock_enabled() -> bool { | ||
| 877 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 878 | mrcc.$clk_reg().read().$field().is_enabled() | ||
| 879 | } | ||
| 880 | |||
| 881 | #[inline] | ||
| 882 | unsafe fn release_reset() { | ||
| 883 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 884 | mrcc.$rst_reg().modify(|_, w| w.$field().enabled()); | ||
| 885 | } | ||
| 886 | |||
| 887 | #[inline] | ||
| 888 | unsafe fn assert_reset() { | ||
| 889 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 890 | mrcc.$rst_reg().modify(|_, w| w.$field().disabled()); | ||
| 891 | } | ||
| 892 | |||
| 893 | #[inline] | ||
| 894 | fn is_reset_released() -> bool { | ||
| 895 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 896 | mrcc.$rst_reg().read().$field().is_enabled() | ||
| 897 | } | ||
| 898 | } | ||
| 899 | }; | ||
| 900 | } | ||
| 901 | |||
| 902 | /// This module contains implementations of MRCC APIs, specifically of the [`Gate`] trait, | ||
| 903 | /// for various low level peripherals. | ||
| 904 | pub(crate) mod gate { | ||
| 905 | #[cfg(not(feature = "time"))] | ||
| 906 | use super::periph_helpers::OsTimerConfig; | ||
| 907 | use super::periph_helpers::{AdcConfig, Lpi2cConfig, LpuartConfig, NoConfig}; | ||
| 908 | use super::*; | ||
| 909 | |||
| 910 | // These peripherals have no additional upstream clocks or configuration required | ||
| 911 | // other than enabling through the MRCC gate. Currently, these peripherals will | ||
| 912 | // ALWAYS return `Ok(0)` when calling [`enable_and_reset()`] and/or | ||
| 913 | // [`SPConfHelper::post_enable_config()`]. | ||
| 914 | impl_cc_gate!(PORT0, mrcc_glb_cc1, mrcc_glb_rst1, port0, NoConfig); | ||
| 915 | impl_cc_gate!(PORT1, mrcc_glb_cc1, mrcc_glb_rst1, port1, NoConfig); | ||
| 916 | impl_cc_gate!(PORT2, mrcc_glb_cc1, mrcc_glb_rst1, port2, NoConfig); | ||
| 917 | impl_cc_gate!(PORT3, mrcc_glb_cc1, mrcc_glb_rst1, port3, NoConfig); | ||
| 918 | impl_cc_gate!(PORT4, mrcc_glb_cc1, mrcc_glb_rst1, port4, NoConfig); | ||
| 919 | |||
| 920 | impl_cc_gate!(GPIO0, mrcc_glb_cc2, mrcc_glb_rst2, gpio0, NoConfig); | ||
| 921 | impl_cc_gate!(GPIO1, mrcc_glb_cc2, mrcc_glb_rst2, gpio1, NoConfig); | ||
| 922 | impl_cc_gate!(GPIO2, mrcc_glb_cc2, mrcc_glb_rst2, gpio2, NoConfig); | ||
| 923 | impl_cc_gate!(GPIO3, mrcc_glb_cc2, mrcc_glb_rst2, gpio3, NoConfig); | ||
| 924 | impl_cc_gate!(GPIO4, mrcc_glb_cc2, mrcc_glb_rst2, gpio4, NoConfig); | ||
| 925 | |||
| 926 | // These peripherals DO have meaningful configuration, and could fail if the system | ||
| 927 | // clocks do not match their needs. | ||
| 928 | #[cfg(not(feature = "time"))] | ||
| 929 | impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig); | ||
| 930 | |||
| 931 | impl_cc_gate!(LPI2C0, mrcc_glb_cc0, mrcc_glb_rst0, lpi2c0, Lpi2cConfig); | ||
| 932 | impl_cc_gate!(LPI2C1, mrcc_glb_cc0, mrcc_glb_rst0, lpi2c1, Lpi2cConfig); | ||
| 933 | impl_cc_gate!(LPI2C2, mrcc_glb_cc1, mrcc_glb_rst1, lpi2c2, Lpi2cConfig); | ||
| 934 | impl_cc_gate!(LPI2C3, mrcc_glb_cc1, mrcc_glb_rst1, lpi2c3, Lpi2cConfig); | ||
| 935 | |||
| 936 | impl_cc_gate!(LPUART0, mrcc_glb_cc0, mrcc_glb_rst0, lpuart0, LpuartConfig); | ||
| 937 | impl_cc_gate!(LPUART1, mrcc_glb_cc0, mrcc_glb_rst0, lpuart1, LpuartConfig); | ||
| 938 | impl_cc_gate!(LPUART2, mrcc_glb_cc0, mrcc_glb_rst0, lpuart2, LpuartConfig); | ||
| 939 | impl_cc_gate!(LPUART3, mrcc_glb_cc0, mrcc_glb_rst0, lpuart3, LpuartConfig); | ||
| 940 | impl_cc_gate!(LPUART4, mrcc_glb_cc0, mrcc_glb_rst0, lpuart4, LpuartConfig); | ||
| 941 | impl_cc_gate!(LPUART5, mrcc_glb_cc1, mrcc_glb_rst1, lpuart5, LpuartConfig); | ||
| 942 | impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); | ||
| 943 | } | ||
diff --git a/embassy-mcxa/src/clocks/periph_helpers.rs b/embassy-mcxa/src/clocks/periph_helpers.rs new file mode 100644 index 000000000..1ea7a99ed --- /dev/null +++ b/embassy-mcxa/src/clocks/periph_helpers.rs | |||
| @@ -0,0 +1,502 @@ | |||
| 1 | //! Peripheral Helpers | ||
| 2 | //! | ||
| 3 | //! The purpose of this module is to define the per-peripheral special handling | ||
| 4 | //! required from a clocking perspective. Different peripherals have different | ||
| 5 | //! selectable source clocks, and some peripherals have additional pre-dividers | ||
| 6 | //! that can be used. | ||
| 7 | //! | ||
| 8 | //! See the docs of [`SPConfHelper`] for more details. | ||
| 9 | |||
| 10 | use super::{ClockError, Clocks, PoweredClock}; | ||
| 11 | use crate::pac; | ||
| 12 | |||
| 13 | /// Sealed Peripheral Configuration Helper | ||
| 14 | /// | ||
| 15 | /// NOTE: the name "sealed" doesn't *totally* make sense because its not sealed yet in the | ||
| 16 | /// embassy-mcxa project, but it derives from embassy-imxrt where it is. We should | ||
| 17 | /// fix the name, or actually do the sealing of peripherals. | ||
| 18 | /// | ||
| 19 | /// This trait serves to act as a per-peripheral customization for clocking behavior. | ||
| 20 | /// | ||
| 21 | /// This trait should be implemented on a configuration type for a given peripheral, and | ||
| 22 | /// provide the methods that will be called by the higher level operations like | ||
| 23 | /// `embassy_mcxa::clocks::enable_and_reset()`. | ||
| 24 | pub trait SPConfHelper { | ||
| 25 | /// This method is called AFTER a given MRCC peripheral has been enabled (e.g. un-gated), | ||
| 26 | /// but BEFORE the peripheral reset line is reset. | ||
| 27 | /// | ||
| 28 | /// This function should check that any relevant upstream clocks are enabled, are in a | ||
| 29 | /// reasonable power state, and that the requested configuration can be made. If any of | ||
| 30 | /// these checks fail, an `Err(ClockError)` should be returned, likely `ClockError::BadConfig`. | ||
| 31 | /// | ||
| 32 | /// This function SHOULD NOT make any changes to the system clock configuration, even | ||
| 33 | /// unsafely, as this should remain static for the duration of the program. | ||
| 34 | /// | ||
| 35 | /// This function WILL be called in a critical section, care should be taken not to delay | ||
| 36 | /// for an unreasonable amount of time. | ||
| 37 | /// | ||
| 38 | /// On success, this function MUST return an `Ok(freq)`, where `freq` is the frequency | ||
| 39 | /// fed into the peripheral, taking into account the selected source clock, as well as | ||
| 40 | /// any pre-divisors. | ||
| 41 | fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError>; | ||
| 42 | } | ||
| 43 | |||
| 44 | /// Copy and paste macro that: | ||
| 45 | /// | ||
| 46 | /// * Sets the clocksel mux to `$selvar` | ||
| 47 | /// * Resets and halts the div, and applies the calculated div4 bits | ||
| 48 | /// * Releases reset + halt | ||
| 49 | /// * Waits for the div to stabilize | ||
| 50 | /// * Returns `Ok($freq / $conf.div.into_divisor())` | ||
| 51 | /// | ||
| 52 | /// Assumes: | ||
| 53 | /// | ||
| 54 | /// * self is a configuration struct that has a field called `div`, which | ||
| 55 | /// is a `Div4` | ||
| 56 | /// | ||
| 57 | /// usage: | ||
| 58 | /// | ||
| 59 | /// ```rust | ||
| 60 | /// apply_div4!(self, clksel, clkdiv, variant, freq) | ||
| 61 | /// ``` | ||
| 62 | /// | ||
| 63 | /// In the future if we make all the clksel+clkdiv pairs into commonly derivedFrom | ||
| 64 | /// registers, or if we put some kind of simple trait around those regs, we could | ||
| 65 | /// do this with something other than a macro, but for now, this is harm-reduction | ||
| 66 | /// to avoid incorrect copy + paste | ||
| 67 | macro_rules! apply_div4 { | ||
| 68 | ($conf:ident, $selreg:ident, $divreg:ident, $selvar:ident, $freq:ident) => {{ | ||
| 69 | // set clksel | ||
| 70 | $selreg.modify(|_r, w| w.mux().variant($selvar)); | ||
| 71 | |||
| 72 | // Set up clkdiv | ||
| 73 | $divreg.modify(|_r, w| { | ||
| 74 | unsafe { w.div().bits($conf.div.into_bits()) } | ||
| 75 | .halt() | ||
| 76 | .asserted() | ||
| 77 | .reset() | ||
| 78 | .asserted() | ||
| 79 | }); | ||
| 80 | $divreg.modify(|_r, w| w.halt().deasserted().reset().deasserted()); | ||
| 81 | |||
| 82 | while $divreg.read().unstab().is_unstable() {} | ||
| 83 | |||
| 84 | Ok($freq / $conf.div.into_divisor()) | ||
| 85 | }}; | ||
| 86 | } | ||
| 87 | |||
| 88 | // config types | ||
| 89 | |||
| 90 | /// This type represents a divider in the range 1..=16. | ||
| 91 | /// | ||
| 92 | /// At a hardware level, this is an 8-bit register from 0..=15, | ||
| 93 | /// which adds one. | ||
| 94 | /// | ||
| 95 | /// While the *clock* domain seems to use 8-bit dividers, the *peripheral* domain | ||
| 96 | /// seems to use 4 bit dividers! | ||
| 97 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 98 | pub struct Div4(pub(super) u8); | ||
| 99 | |||
| 100 | impl Div4 { | ||
| 101 | /// Divide by one, or no division | ||
| 102 | pub const fn no_div() -> Self { | ||
| 103 | Self(0) | ||
| 104 | } | ||
| 105 | |||
| 106 | /// Store a "raw" divisor value that will divide the source by | ||
| 107 | /// `(n + 1)`, e.g. `Div4::from_raw(0)` will divide the source | ||
| 108 | /// by 1, and `Div4::from_raw(15)` will divide the source by | ||
| 109 | /// 16. | ||
| 110 | pub const fn from_raw(n: u8) -> Option<Self> { | ||
| 111 | if n > 0b1111 { | ||
| 112 | None | ||
| 113 | } else { | ||
| 114 | Some(Self(n)) | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Store a specific divisor value that will divide the source | ||
| 119 | /// by `n`. e.g. `Div4::from_divisor(1)` will divide the source | ||
| 120 | /// by 1, and `Div4::from_divisor(16)` will divide the source | ||
| 121 | /// by 16. | ||
| 122 | /// | ||
| 123 | /// Will return `None` if `n` is not in the range `1..=16`. | ||
| 124 | /// Consider [`Self::from_raw`] for an infallible version. | ||
| 125 | pub const fn from_divisor(n: u8) -> Option<Self> { | ||
| 126 | let Some(n) = n.checked_sub(1) else { | ||
| 127 | return None; | ||
| 128 | }; | ||
| 129 | if n > 0b1111 { | ||
| 130 | return None; | ||
| 131 | } | ||
| 132 | Some(Self(n)) | ||
| 133 | } | ||
| 134 | |||
| 135 | /// Convert into "raw" bits form | ||
| 136 | #[inline(always)] | ||
| 137 | pub const fn into_bits(self) -> u8 { | ||
| 138 | self.0 | ||
| 139 | } | ||
| 140 | |||
| 141 | /// Convert into "divisor" form, as a u32 for convenient frequency math | ||
| 142 | #[inline(always)] | ||
| 143 | pub const fn into_divisor(self) -> u32 { | ||
| 144 | self.0 as u32 + 1 | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | /// A basic type that always returns an error when `post_enable_config` is called. | ||
| 149 | /// | ||
| 150 | /// Should only be used as a placeholder. | ||
| 151 | pub struct UnimplementedConfig; | ||
| 152 | |||
| 153 | impl SPConfHelper for UnimplementedConfig { | ||
| 154 | fn post_enable_config(&self, _clocks: &Clocks) -> Result<u32, ClockError> { | ||
| 155 | Err(ClockError::UnimplementedConfig) | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | /// A basic type that always returns `Ok(0)` when `post_enable_config` is called. | ||
| 160 | /// | ||
| 161 | /// This should only be used for peripherals that are "ambiently" clocked, like `PORTn` | ||
| 162 | /// peripherals, which have no selectable/configurable source clock. | ||
| 163 | pub struct NoConfig; | ||
| 164 | impl SPConfHelper for NoConfig { | ||
| 165 | fn post_enable_config(&self, _clocks: &Clocks) -> Result<u32, ClockError> { | ||
| 166 | Ok(0) | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | // | ||
| 171 | // LPI2c | ||
| 172 | // | ||
| 173 | |||
| 174 | /// Selectable clocks for `Lpi2c` peripherals | ||
| 175 | #[derive(Debug, Clone, Copy)] | ||
| 176 | pub enum Lpi2cClockSel { | ||
| 177 | /// FRO12M/FRO_LF/SIRC clock source, passed through divider | ||
| 178 | /// "fro_lf_div" | ||
| 179 | FroLfDiv, | ||
| 180 | /// FRO180M/FRO_HF/FIRC clock source, passed through divider | ||
| 181 | /// "fro_hf_div" | ||
| 182 | FroHfDiv, | ||
| 183 | /// SOSC/XTAL/EXTAL clock source | ||
| 184 | ClkIn, | ||
| 185 | /// clk_1m/FRO_LF divided by 12 | ||
| 186 | Clk1M, | ||
| 187 | /// Output of PLL1, passed through clock divider, | ||
| 188 | /// "pll1_clk_div", maybe "pll1_lf_div"? | ||
| 189 | Pll1ClkDiv, | ||
| 190 | /// Disabled | ||
| 191 | None, | ||
| 192 | } | ||
| 193 | |||
| 194 | /// Which instance of the `Lpi2c` is this? | ||
| 195 | /// | ||
| 196 | /// Should not be directly selectable by end-users. | ||
| 197 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 198 | pub enum Lpi2cInstance { | ||
| 199 | /// Instance 0 | ||
| 200 | Lpi2c0, | ||
| 201 | /// Instance 1 | ||
| 202 | Lpi2c1, | ||
| 203 | /// Instance 2 | ||
| 204 | Lpi2c2, | ||
| 205 | /// Instance 3 | ||
| 206 | Lpi2c3, | ||
| 207 | } | ||
| 208 | |||
| 209 | /// Top level configuration for `Lpi2c` instances. | ||
| 210 | pub struct Lpi2cConfig { | ||
| 211 | /// Power state required for this peripheral | ||
| 212 | pub power: PoweredClock, | ||
| 213 | /// Clock source | ||
| 214 | pub source: Lpi2cClockSel, | ||
| 215 | /// Clock divisor | ||
| 216 | pub div: Div4, | ||
| 217 | /// Which instance is this? | ||
| 218 | // NOTE: should not be user settable | ||
| 219 | pub(crate) instance: Lpi2cInstance, | ||
| 220 | } | ||
| 221 | |||
| 222 | impl SPConfHelper for Lpi2cConfig { | ||
| 223 | fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> { | ||
| 224 | // check that source is suitable | ||
| 225 | let mrcc0 = unsafe { pac::Mrcc0::steal() }; | ||
| 226 | use mcxa_pac::mrcc0::mrcc_lpi2c0_clksel::Mux; | ||
| 227 | |||
| 228 | let (clkdiv, clksel) = match self.instance { | ||
| 229 | Lpi2cInstance::Lpi2c0 => (mrcc0.mrcc_lpi2c0_clkdiv(), mrcc0.mrcc_lpi2c0_clksel()), | ||
| 230 | Lpi2cInstance::Lpi2c1 => (mrcc0.mrcc_lpi2c1_clkdiv(), mrcc0.mrcc_lpi2c1_clksel()), | ||
| 231 | Lpi2cInstance::Lpi2c2 => (mrcc0.mrcc_lpi2c2_clkdiv(), mrcc0.mrcc_lpi2c2_clksel()), | ||
| 232 | Lpi2cInstance::Lpi2c3 => (mrcc0.mrcc_lpi2c3_clkdiv(), mrcc0.mrcc_lpi2c3_clksel()), | ||
| 233 | }; | ||
| 234 | |||
| 235 | let (freq, variant) = match self.source { | ||
| 236 | Lpi2cClockSel::FroLfDiv => { | ||
| 237 | let freq = clocks.ensure_fro_lf_div_active(&self.power)?; | ||
| 238 | (freq, Mux::ClkrootFunc0) | ||
| 239 | } | ||
| 240 | Lpi2cClockSel::FroHfDiv => { | ||
| 241 | let freq = clocks.ensure_fro_hf_div_active(&self.power)?; | ||
| 242 | (freq, Mux::ClkrootFunc2) | ||
| 243 | } | ||
| 244 | Lpi2cClockSel::ClkIn => { | ||
| 245 | let freq = clocks.ensure_clk_in_active(&self.power)?; | ||
| 246 | (freq, Mux::ClkrootFunc3) | ||
| 247 | } | ||
| 248 | Lpi2cClockSel::Clk1M => { | ||
| 249 | let freq = clocks.ensure_clk_1m_active(&self.power)?; | ||
| 250 | (freq, Mux::ClkrootFunc5) | ||
| 251 | } | ||
| 252 | Lpi2cClockSel::Pll1ClkDiv => { | ||
| 253 | let freq = clocks.ensure_pll1_clk_div_active(&self.power)?; | ||
| 254 | (freq, Mux::ClkrootFunc6) | ||
| 255 | } | ||
| 256 | Lpi2cClockSel::None => unsafe { | ||
| 257 | // no ClkrootFunc7, just write manually for now | ||
| 258 | clksel.write(|w| w.bits(0b111)); | ||
| 259 | clkdiv.modify(|_r, w| w.reset().asserted().halt().asserted()); | ||
| 260 | return Ok(0); | ||
| 261 | }, | ||
| 262 | }; | ||
| 263 | |||
| 264 | apply_div4!(self, clksel, clkdiv, variant, freq) | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | // | ||
| 269 | // LPUart | ||
| 270 | // | ||
| 271 | |||
| 272 | /// Selectable clocks for Lpuart peripherals | ||
| 273 | #[derive(Debug, Clone, Copy)] | ||
| 274 | pub enum LpuartClockSel { | ||
| 275 | /// FRO12M/FRO_LF/SIRC clock source, passed through divider | ||
| 276 | /// "fro_lf_div" | ||
| 277 | FroLfDiv, | ||
| 278 | /// FRO180M/FRO_HF/FIRC clock source, passed through divider | ||
| 279 | /// "fro_hf_div" | ||
| 280 | FroHfDiv, | ||
| 281 | /// SOSC/XTAL/EXTAL clock source | ||
| 282 | ClkIn, | ||
| 283 | /// FRO16K/clk_16k source | ||
| 284 | Clk16K, | ||
| 285 | /// clk_1m/FRO_LF divided by 12 | ||
| 286 | Clk1M, | ||
| 287 | /// Output of PLL1, passed through clock divider, | ||
| 288 | /// "pll1_clk_div", maybe "pll1_lf_div"? | ||
| 289 | Pll1ClkDiv, | ||
| 290 | /// Disabled | ||
| 291 | None, | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Which instance of the Lpuart is this? | ||
| 295 | /// | ||
| 296 | /// Should not be directly selectable by end-users. | ||
| 297 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 298 | pub enum LpuartInstance { | ||
| 299 | /// Instance 0 | ||
| 300 | Lpuart0, | ||
| 301 | /// Instance 1 | ||
| 302 | Lpuart1, | ||
| 303 | /// Instance 2 | ||
| 304 | Lpuart2, | ||
| 305 | /// Instance 3 | ||
| 306 | Lpuart3, | ||
| 307 | /// Instance 4 | ||
| 308 | Lpuart4, | ||
| 309 | /// Instance 5 | ||
| 310 | Lpuart5, | ||
| 311 | } | ||
| 312 | |||
| 313 | /// Top level configuration for `Lpuart` instances. | ||
| 314 | pub struct LpuartConfig { | ||
| 315 | /// Power state required for this peripheral | ||
| 316 | pub power: PoweredClock, | ||
| 317 | /// Clock source | ||
| 318 | pub source: LpuartClockSel, | ||
| 319 | /// Clock divisor | ||
| 320 | pub div: Div4, | ||
| 321 | /// Which instance is this? | ||
| 322 | // NOTE: should not be user settable | ||
| 323 | pub(crate) instance: LpuartInstance, | ||
| 324 | } | ||
| 325 | |||
| 326 | impl SPConfHelper for LpuartConfig { | ||
| 327 | fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> { | ||
| 328 | // check that source is suitable | ||
| 329 | let mrcc0 = unsafe { pac::Mrcc0::steal() }; | ||
| 330 | use mcxa_pac::mrcc0::mrcc_lpuart0_clksel::Mux; | ||
| 331 | |||
| 332 | let (clkdiv, clksel) = match self.instance { | ||
| 333 | LpuartInstance::Lpuart0 => (mrcc0.mrcc_lpuart0_clkdiv(), mrcc0.mrcc_lpuart0_clksel()), | ||
| 334 | LpuartInstance::Lpuart1 => (mrcc0.mrcc_lpuart1_clkdiv(), mrcc0.mrcc_lpuart1_clksel()), | ||
| 335 | LpuartInstance::Lpuart2 => (mrcc0.mrcc_lpuart2_clkdiv(), mrcc0.mrcc_lpuart2_clksel()), | ||
| 336 | LpuartInstance::Lpuart3 => (mrcc0.mrcc_lpuart3_clkdiv(), mrcc0.mrcc_lpuart3_clksel()), | ||
| 337 | LpuartInstance::Lpuart4 => (mrcc0.mrcc_lpuart4_clkdiv(), mrcc0.mrcc_lpuart4_clksel()), | ||
| 338 | LpuartInstance::Lpuart5 => (mrcc0.mrcc_lpuart5_clkdiv(), mrcc0.mrcc_lpuart5_clksel()), | ||
| 339 | }; | ||
| 340 | |||
| 341 | let (freq, variant) = match self.source { | ||
| 342 | LpuartClockSel::FroLfDiv => { | ||
| 343 | let freq = clocks.ensure_fro_lf_div_active(&self.power)?; | ||
| 344 | (freq, Mux::ClkrootFunc0) | ||
| 345 | } | ||
| 346 | LpuartClockSel::FroHfDiv => { | ||
| 347 | let freq = clocks.ensure_fro_hf_div_active(&self.power)?; | ||
| 348 | (freq, Mux::ClkrootFunc2) | ||
| 349 | } | ||
| 350 | LpuartClockSel::ClkIn => { | ||
| 351 | let freq = clocks.ensure_clk_in_active(&self.power)?; | ||
| 352 | (freq, Mux::ClkrootFunc3) | ||
| 353 | } | ||
| 354 | LpuartClockSel::Clk16K => { | ||
| 355 | let freq = clocks.ensure_clk_16k_vdd_core_active(&self.power)?; | ||
| 356 | (freq, Mux::ClkrootFunc4) | ||
| 357 | } | ||
| 358 | LpuartClockSel::Clk1M => { | ||
| 359 | let freq = clocks.ensure_clk_1m_active(&self.power)?; | ||
| 360 | (freq, Mux::ClkrootFunc5) | ||
| 361 | } | ||
| 362 | LpuartClockSel::Pll1ClkDiv => { | ||
| 363 | let freq = clocks.ensure_pll1_clk_div_active(&self.power)?; | ||
| 364 | (freq, Mux::ClkrootFunc6) | ||
| 365 | } | ||
| 366 | LpuartClockSel::None => unsafe { | ||
| 367 | // no ClkrootFunc7, just write manually for now | ||
| 368 | clksel.write(|w| w.bits(0b111)); | ||
| 369 | clkdiv.modify(|_r, w| { | ||
| 370 | w.reset().asserted(); | ||
| 371 | w.halt().asserted(); | ||
| 372 | w | ||
| 373 | }); | ||
| 374 | return Ok(0); | ||
| 375 | }, | ||
| 376 | }; | ||
| 377 | |||
| 378 | // set clksel | ||
| 379 | apply_div4!(self, clksel, clkdiv, variant, freq) | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | // | ||
| 384 | // OSTimer | ||
| 385 | // | ||
| 386 | |||
| 387 | /// Selectable clocks for the OSTimer peripheral | ||
| 388 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 389 | pub enum OstimerClockSel { | ||
| 390 | /// 16k clock, sourced from FRO16K (Vdd Core) | ||
| 391 | Clk16kVddCore, | ||
| 392 | /// 1 MHz Clock sourced from FRO12M | ||
| 393 | Clk1M, | ||
| 394 | /// Disabled | ||
| 395 | None, | ||
| 396 | } | ||
| 397 | |||
| 398 | /// Top level configuration for the `OSTimer` peripheral | ||
| 399 | pub struct OsTimerConfig { | ||
| 400 | /// Power state required for this peripheral | ||
| 401 | pub power: PoweredClock, | ||
| 402 | /// Selected clock source for this peripheral | ||
| 403 | pub source: OstimerClockSel, | ||
| 404 | } | ||
| 405 | |||
| 406 | impl SPConfHelper for OsTimerConfig { | ||
| 407 | fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> { | ||
| 408 | let mrcc0 = unsafe { pac::Mrcc0::steal() }; | ||
| 409 | Ok(match self.source { | ||
| 410 | OstimerClockSel::Clk16kVddCore => { | ||
| 411 | let freq = clocks.ensure_clk_16k_vdd_core_active(&self.power)?; | ||
| 412 | mrcc0.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_16k()); | ||
| 413 | freq | ||
| 414 | } | ||
| 415 | OstimerClockSel::Clk1M => { | ||
| 416 | let freq = clocks.ensure_clk_1m_active(&self.power)?; | ||
| 417 | mrcc0.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_1m()); | ||
| 418 | freq | ||
| 419 | } | ||
| 420 | OstimerClockSel::None => { | ||
| 421 | mrcc0.mrcc_ostimer0_clksel().write(|w| unsafe { w.mux().bits(0b11) }); | ||
| 422 | 0 | ||
| 423 | } | ||
| 424 | }) | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | // | ||
| 429 | // Adc | ||
| 430 | // | ||
| 431 | |||
| 432 | /// Selectable clocks for the ADC peripheral | ||
| 433 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 434 | pub enum AdcClockSel { | ||
| 435 | /// Divided `fro_lf`/`clk_12m`/FRO12M source | ||
| 436 | FroLfDiv, | ||
| 437 | /// Gated `fro_hf`/`FRO180M` source | ||
| 438 | FroHf, | ||
| 439 | /// External Clock Source | ||
| 440 | ClkIn, | ||
| 441 | /// 1MHz clock sourced by a divided `fro_lf`/`clk_12m` | ||
| 442 | Clk1M, | ||
| 443 | /// Internal PLL output, with configurable divisor | ||
| 444 | Pll1ClkDiv, | ||
| 445 | /// No clock/disabled | ||
| 446 | None, | ||
| 447 | } | ||
| 448 | |||
| 449 | /// Top level configuration for the ADC peripheral | ||
| 450 | pub struct AdcConfig { | ||
| 451 | /// Power state required for this peripheral | ||
| 452 | pub power: PoweredClock, | ||
| 453 | /// Selected clock-source for this peripheral | ||
| 454 | pub source: AdcClockSel, | ||
| 455 | /// Pre-divisor, applied to the upstream clock output | ||
| 456 | pub div: Div4, | ||
| 457 | } | ||
| 458 | |||
| 459 | impl SPConfHelper for AdcConfig { | ||
| 460 | fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> { | ||
| 461 | use mcxa_pac::mrcc0::mrcc_adc_clksel::Mux; | ||
| 462 | let mrcc0 = unsafe { pac::Mrcc0::steal() }; | ||
| 463 | let (freq, variant) = match self.source { | ||
| 464 | AdcClockSel::FroLfDiv => { | ||
| 465 | let freq = clocks.ensure_fro_lf_div_active(&self.power)?; | ||
| 466 | (freq, Mux::ClkrootFunc0) | ||
| 467 | } | ||
| 468 | AdcClockSel::FroHf => { | ||
| 469 | let freq = clocks.ensure_fro_hf_active(&self.power)?; | ||
| 470 | (freq, Mux::ClkrootFunc1) | ||
| 471 | } | ||
| 472 | AdcClockSel::ClkIn => { | ||
| 473 | let freq = clocks.ensure_clk_in_active(&self.power)?; | ||
| 474 | (freq, Mux::ClkrootFunc3) | ||
| 475 | } | ||
| 476 | AdcClockSel::Clk1M => { | ||
| 477 | let freq = clocks.ensure_clk_1m_active(&self.power)?; | ||
| 478 | (freq, Mux::ClkrootFunc5) | ||
| 479 | } | ||
| 480 | AdcClockSel::Pll1ClkDiv => { | ||
| 481 | let freq = clocks.ensure_pll1_clk_div_active(&self.power)?; | ||
| 482 | (freq, Mux::ClkrootFunc6) | ||
| 483 | } | ||
| 484 | AdcClockSel::None => { | ||
| 485 | mrcc0.mrcc_adc_clksel().write(|w| unsafe { | ||
| 486 | // no ClkrootFunc7, just write manually for now | ||
| 487 | w.mux().bits(0b111) | ||
| 488 | }); | ||
| 489 | mrcc0.mrcc_adc_clkdiv().modify(|_r, w| { | ||
| 490 | w.reset().asserted(); | ||
| 491 | w.halt().asserted(); | ||
| 492 | w | ||
| 493 | }); | ||
| 494 | return Ok(0); | ||
| 495 | } | ||
| 496 | }; | ||
| 497 | let clksel = mrcc0.mrcc_adc_clksel(); | ||
| 498 | let clkdiv = mrcc0.mrcc_adc_clkdiv(); | ||
| 499 | |||
| 500 | apply_div4!(self, clksel, clkdiv, variant, freq) | ||
| 501 | } | ||
| 502 | } | ||
diff --git a/embassy-mcxa/src/config.rs b/embassy-mcxa/src/config.rs new file mode 100644 index 000000000..8d52a1d44 --- /dev/null +++ b/embassy-mcxa/src/config.rs | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // HAL configuration (minimal), mirroring embassy-imxrt style | ||
| 2 | |||
| 3 | use crate::clocks::config::ClocksConfig; | ||
| 4 | use crate::interrupt::Priority; | ||
| 5 | |||
| 6 | #[non_exhaustive] | ||
| 7 | pub struct Config { | ||
| 8 | #[cfg(feature = "time")] | ||
| 9 | pub time_interrupt_priority: Priority, | ||
| 10 | pub rtc_interrupt_priority: Priority, | ||
| 11 | pub adc_interrupt_priority: Priority, | ||
| 12 | pub gpio_interrupt_priority: Priority, | ||
| 13 | pub clock_cfg: ClocksConfig, | ||
| 14 | } | ||
| 15 | |||
| 16 | impl Default for Config { | ||
| 17 | fn default() -> Self { | ||
| 18 | Self { | ||
| 19 | #[cfg(feature = "time")] | ||
| 20 | time_interrupt_priority: Priority::from(0), | ||
| 21 | rtc_interrupt_priority: Priority::from(0), | ||
| 22 | adc_interrupt_priority: Priority::from(0), | ||
| 23 | gpio_interrupt_priority: Priority::from(0), | ||
| 24 | clock_cfg: ClocksConfig::default(), | ||
| 25 | } | ||
| 26 | } | ||
| 27 | } | ||
diff --git a/embassy-mcxa/src/gpio.rs b/embassy-mcxa/src/gpio.rs new file mode 100644 index 000000000..65f8df985 --- /dev/null +++ b/embassy-mcxa/src/gpio.rs | |||
| @@ -0,0 +1,1062 @@ | |||
| 1 | //! GPIO driver built around a type-erased `Flex` pin, similar to other Embassy HALs. | ||
| 2 | //! The exported `Output`/`Input` drivers own a `Flex` so they no longer depend on the | ||
| 3 | //! concrete pin type. | ||
| 4 | |||
| 5 | use core::convert::Infallible; | ||
| 6 | use core::future::Future; | ||
| 7 | use core::marker::PhantomData; | ||
| 8 | use core::pin::pin; | ||
| 9 | |||
| 10 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 11 | use maitake_sync::WaitMap; | ||
| 12 | use paste::paste; | ||
| 13 | |||
| 14 | use crate::pac::interrupt; | ||
| 15 | use crate::pac::port0::pcr0::{Dse, Inv, Mux, Pe, Ps, Sre}; | ||
| 16 | |||
| 17 | struct BitIter(u32); | ||
| 18 | |||
| 19 | impl Iterator for BitIter { | ||
| 20 | type Item = usize; | ||
| 21 | |||
| 22 | fn next(&mut self) -> Option<Self::Item> { | ||
| 23 | match self.0.trailing_zeros() { | ||
| 24 | 32 => None, | ||
| 25 | b => { | ||
| 26 | self.0 &= !(1 << b); | ||
| 27 | Some(b as usize) | ||
| 28 | } | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | const PORT_COUNT: usize = 5; | ||
| 34 | |||
| 35 | static PORT_WAIT_MAPS: [WaitMap<usize, ()>; PORT_COUNT] = [ | ||
| 36 | WaitMap::new(), | ||
| 37 | WaitMap::new(), | ||
| 38 | WaitMap::new(), | ||
| 39 | WaitMap::new(), | ||
| 40 | WaitMap::new(), | ||
| 41 | ]; | ||
| 42 | |||
| 43 | fn irq_handler(port_index: usize, gpio_base: *const crate::pac::gpio0::RegisterBlock) { | ||
| 44 | let gpio = unsafe { &*gpio_base }; | ||
| 45 | let isfr = gpio.isfr0().read().bits(); | ||
| 46 | |||
| 47 | for pin in BitIter(isfr) { | ||
| 48 | // Clear all pending interrupts | ||
| 49 | gpio.isfr0().write(|w| unsafe { w.bits(1 << pin) }); | ||
| 50 | gpio.icr(pin).modify(|_, w| w.irqc().irqc0()); // Disable interrupt | ||
| 51 | |||
| 52 | // Wake the corresponding port waker | ||
| 53 | if let Some(w) = PORT_WAIT_MAPS.get(port_index) { | ||
| 54 | w.wake(&pin, ()); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | #[interrupt] | ||
| 60 | fn GPIO0() { | ||
| 61 | irq_handler(0, crate::pac::Gpio0::ptr()); | ||
| 62 | } | ||
| 63 | |||
| 64 | #[interrupt] | ||
| 65 | fn GPIO1() { | ||
| 66 | irq_handler(1, crate::pac::Gpio1::ptr()); | ||
| 67 | } | ||
| 68 | |||
| 69 | #[interrupt] | ||
| 70 | fn GPIO2() { | ||
| 71 | irq_handler(2, crate::pac::Gpio2::ptr()); | ||
| 72 | } | ||
| 73 | |||
| 74 | #[interrupt] | ||
| 75 | fn GPIO3() { | ||
| 76 | irq_handler(3, crate::pac::Gpio3::ptr()); | ||
| 77 | } | ||
| 78 | |||
| 79 | #[interrupt] | ||
| 80 | fn GPIO4() { | ||
| 81 | irq_handler(4, crate::pac::Gpio4::ptr()); | ||
| 82 | } | ||
| 83 | |||
| 84 | pub(crate) unsafe fn init() { | ||
| 85 | use embassy_hal_internal::interrupt::InterruptExt; | ||
| 86 | |||
| 87 | crate::pac::interrupt::GPIO0.enable(); | ||
| 88 | crate::pac::interrupt::GPIO1.enable(); | ||
| 89 | crate::pac::interrupt::GPIO2.enable(); | ||
| 90 | crate::pac::interrupt::GPIO3.enable(); | ||
| 91 | crate::pac::interrupt::GPIO4.enable(); | ||
| 92 | |||
| 93 | cortex_m::interrupt::enable(); | ||
| 94 | } | ||
| 95 | |||
| 96 | /// Logical level for GPIO pins. | ||
| 97 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 98 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 99 | pub enum Level { | ||
| 100 | Low, | ||
| 101 | High, | ||
| 102 | } | ||
| 103 | |||
| 104 | impl From<bool> for Level { | ||
| 105 | fn from(val: bool) -> Self { | ||
| 106 | match val { | ||
| 107 | true => Self::High, | ||
| 108 | false => Self::Low, | ||
| 109 | } | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 114 | pub enum Pull { | ||
| 115 | Disabled, | ||
| 116 | Up, | ||
| 117 | Down, | ||
| 118 | } | ||
| 119 | |||
| 120 | impl From<Pull> for (Pe, Ps) { | ||
| 121 | fn from(pull: Pull) -> Self { | ||
| 122 | match pull { | ||
| 123 | Pull::Disabled => (Pe::Pe0, Ps::Ps0), | ||
| 124 | Pull::Up => (Pe::Pe1, Ps::Ps1), | ||
| 125 | Pull::Down => (Pe::Pe1, Ps::Ps0), | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 131 | pub enum SlewRate { | ||
| 132 | Fast, | ||
| 133 | Slow, | ||
| 134 | } | ||
| 135 | |||
| 136 | impl From<SlewRate> for Sre { | ||
| 137 | fn from(slew_rate: SlewRate) -> Self { | ||
| 138 | match slew_rate { | ||
| 139 | SlewRate::Fast => Sre::Sre0, | ||
| 140 | SlewRate::Slow => Sre::Sre1, | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 146 | pub enum DriveStrength { | ||
| 147 | Normal, | ||
| 148 | Double, | ||
| 149 | } | ||
| 150 | |||
| 151 | impl From<DriveStrength> for Dse { | ||
| 152 | fn from(strength: DriveStrength) -> Self { | ||
| 153 | match strength { | ||
| 154 | DriveStrength::Normal => Dse::Dse0, | ||
| 155 | DriveStrength::Double => Dse::Dse1, | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 161 | pub enum Inverter { | ||
| 162 | Disabled, | ||
| 163 | Enabled, | ||
| 164 | } | ||
| 165 | |||
| 166 | impl From<Inverter> for Inv { | ||
| 167 | fn from(strength: Inverter) -> Self { | ||
| 168 | match strength { | ||
| 169 | Inverter::Disabled => Inv::Inv0, | ||
| 170 | Inverter::Enabled => Inv::Inv1, | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | pub type Gpio = crate::peripherals::GPIO0; | ||
| 176 | |||
| 177 | /// Type-erased representation of a GPIO pin. | ||
| 178 | pub struct AnyPin { | ||
| 179 | port: usize, | ||
| 180 | pin: usize, | ||
| 181 | gpio: &'static crate::pac::gpio0::RegisterBlock, | ||
| 182 | port_reg: &'static crate::pac::port0::RegisterBlock, | ||
| 183 | pcr_reg: &'static crate::pac::port0::Pcr0, | ||
| 184 | } | ||
| 185 | |||
| 186 | impl AnyPin { | ||
| 187 | /// Create an `AnyPin` from raw components. | ||
| 188 | fn new( | ||
| 189 | port: usize, | ||
| 190 | pin: usize, | ||
| 191 | gpio: &'static crate::pac::gpio0::RegisterBlock, | ||
| 192 | port_reg: &'static crate::pac::port0::RegisterBlock, | ||
| 193 | pcr_reg: &'static crate::pac::port0::Pcr0, | ||
| 194 | ) -> Self { | ||
| 195 | Self { | ||
| 196 | port, | ||
| 197 | pin, | ||
| 198 | gpio, | ||
| 199 | port_reg, | ||
| 200 | pcr_reg, | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | #[inline(always)] | ||
| 205 | fn mask(&self) -> u32 { | ||
| 206 | 1 << self.pin | ||
| 207 | } | ||
| 208 | |||
| 209 | #[inline(always)] | ||
| 210 | fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { | ||
| 211 | self.gpio | ||
| 212 | } | ||
| 213 | |||
| 214 | #[inline(always)] | ||
| 215 | pub fn port_index(&self) -> usize { | ||
| 216 | self.port | ||
| 217 | } | ||
| 218 | |||
| 219 | #[inline(always)] | ||
| 220 | pub fn pin_index(&self) -> usize { | ||
| 221 | self.pin | ||
| 222 | } | ||
| 223 | |||
| 224 | #[inline(always)] | ||
| 225 | fn port_reg(&self) -> &'static crate::pac::port0::RegisterBlock { | ||
| 226 | self.port_reg | ||
| 227 | } | ||
| 228 | |||
| 229 | #[inline(always)] | ||
| 230 | fn pcr_reg(&self) -> &'static crate::pac::port0::Pcr0 { | ||
| 231 | self.pcr_reg | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | embassy_hal_internal::impl_peripheral!(AnyPin); | ||
| 236 | |||
| 237 | pub(crate) trait SealedPin { | ||
| 238 | fn pin_port(&self) -> usize; | ||
| 239 | |||
| 240 | fn port(&self) -> usize { | ||
| 241 | self.pin_port() / 32 | ||
| 242 | } | ||
| 243 | |||
| 244 | fn pin(&self) -> usize { | ||
| 245 | self.pin_port() % 32 | ||
| 246 | } | ||
| 247 | |||
| 248 | fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock; | ||
| 249 | |||
| 250 | fn port_reg(&self) -> &'static crate::pac::port0::RegisterBlock; | ||
| 251 | |||
| 252 | fn pcr_reg(&self) -> &'static crate::pac::port0::Pcr0; | ||
| 253 | |||
| 254 | fn set_function(&self, function: Mux); | ||
| 255 | |||
| 256 | fn set_pull(&self, pull: Pull); | ||
| 257 | |||
| 258 | fn set_drive_strength(&self, strength: Dse); | ||
| 259 | |||
| 260 | fn set_slew_rate(&self, slew_rate: Sre); | ||
| 261 | |||
| 262 | fn set_enable_input_buffer(&self); | ||
| 263 | } | ||
| 264 | |||
| 265 | /// GPIO pin trait. | ||
| 266 | #[allow(private_bounds)] | ||
| 267 | pub trait GpioPin: SealedPin + Sized + PeripheralType + Into<AnyPin> + 'static { | ||
| 268 | /// Type-erase the pin. | ||
| 269 | fn degrade(self) -> AnyPin { | ||
| 270 | // SAFETY: This is only called within the GpioPin trait, which is only | ||
| 271 | // implemented within this module on valid pin peripherals and thus | ||
| 272 | // has been verified to be correct. | ||
| 273 | AnyPin::new(self.port(), self.pin(), self.gpio(), self.port_reg(), self.pcr_reg()) | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | impl SealedPin for AnyPin { | ||
| 278 | fn pin_port(&self) -> usize { | ||
| 279 | self.port * 32 + self.pin | ||
| 280 | } | ||
| 281 | |||
| 282 | fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { | ||
| 283 | self.gpio() | ||
| 284 | } | ||
| 285 | |||
| 286 | fn port_reg(&self) -> &'static crate::pac::port0::RegisterBlock { | ||
| 287 | self.port_reg() | ||
| 288 | } | ||
| 289 | |||
| 290 | fn pcr_reg(&self) -> &'static crate::pac::port0::Pcr0 { | ||
| 291 | self.pcr_reg() | ||
| 292 | } | ||
| 293 | |||
| 294 | fn set_function(&self, function: Mux) { | ||
| 295 | self.pcr_reg().modify(|_, w| w.mux().variant(function)); | ||
| 296 | } | ||
| 297 | |||
| 298 | fn set_pull(&self, pull: Pull) { | ||
| 299 | let (pull_enable, pull_select) = pull.into(); | ||
| 300 | self.pcr_reg().modify(|_, w| { | ||
| 301 | w.pe().variant(pull_enable); | ||
| 302 | w.ps().variant(pull_select) | ||
| 303 | }); | ||
| 304 | } | ||
| 305 | |||
| 306 | fn set_drive_strength(&self, strength: Dse) { | ||
| 307 | self.pcr_reg().modify(|_, w| w.dse().variant(strength)); | ||
| 308 | } | ||
| 309 | |||
| 310 | fn set_slew_rate(&self, slew_rate: Sre) { | ||
| 311 | self.pcr_reg().modify(|_, w| w.sre().variant(slew_rate)); | ||
| 312 | } | ||
| 313 | |||
| 314 | fn set_enable_input_buffer(&self) { | ||
| 315 | self.pcr_reg().modify(|_, w| w.ibe().ibe1()); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | impl GpioPin for AnyPin {} | ||
| 320 | |||
| 321 | macro_rules! impl_pin { | ||
| 322 | ($peri:ident, $port:expr, $pin:expr, $block:ident) => { | ||
| 323 | paste! { | ||
| 324 | impl SealedPin for crate::peripherals::$peri { | ||
| 325 | fn pin_port(&self) -> usize { | ||
| 326 | $port * 32 + $pin | ||
| 327 | } | ||
| 328 | |||
| 329 | fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { | ||
| 330 | unsafe { &*crate::pac::$block::ptr() } | ||
| 331 | } | ||
| 332 | |||
| 333 | fn port_reg(&self) -> &'static crate::pac::port0::RegisterBlock { | ||
| 334 | unsafe { &*crate::pac::[<Port $port>]::ptr() } | ||
| 335 | } | ||
| 336 | |||
| 337 | fn pcr_reg(&self) -> &'static crate::pac::port0::Pcr0 { | ||
| 338 | self.port_reg().[<pcr $pin>]() | ||
| 339 | } | ||
| 340 | |||
| 341 | fn set_function(&self, function: Mux) { | ||
| 342 | unsafe { | ||
| 343 | let port_reg = &*crate::pac::[<Port $port>]::ptr(); | ||
| 344 | port_reg.[<pcr $pin>]().modify(|_, w| { | ||
| 345 | w.mux().variant(function) | ||
| 346 | }); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | fn set_pull(&self, pull: Pull) { | ||
| 351 | let port_reg = unsafe {&*crate::pac::[<Port $port>]::ptr()}; | ||
| 352 | let (pull_enable, pull_select) = pull.into(); | ||
| 353 | port_reg.[<pcr $pin>]().modify(|_, w| { | ||
| 354 | w.pe().variant(pull_enable); | ||
| 355 | w.ps().variant(pull_select) | ||
| 356 | }); | ||
| 357 | } | ||
| 358 | |||
| 359 | fn set_drive_strength(&self, strength: Dse) { | ||
| 360 | let port_reg = unsafe {&*crate::pac::[<Port $port>]::ptr()}; | ||
| 361 | port_reg.[<pcr $pin>]().modify(|_, w| w.dse().variant(strength)); | ||
| 362 | } | ||
| 363 | |||
| 364 | fn set_slew_rate(&self, slew_rate: Sre) { | ||
| 365 | let port_reg = unsafe {&*crate::pac::[<Port $port>]::ptr()}; | ||
| 366 | port_reg.[<pcr $pin>]().modify(|_, w| w.sre().variant(slew_rate)); | ||
| 367 | } | ||
| 368 | |||
| 369 | fn set_enable_input_buffer(&self) { | ||
| 370 | let port_reg = unsafe {&*crate::pac::[<Port $port>]::ptr()}; | ||
| 371 | port_reg.[<pcr $pin>]().modify(|_, w| w.ibe().ibe1()); | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | impl GpioPin for crate::peripherals::$peri {} | ||
| 376 | |||
| 377 | impl From<crate::peripherals::$peri> for AnyPin { | ||
| 378 | fn from(value: crate::peripherals::$peri) -> Self { | ||
| 379 | value.degrade() | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | impl crate::peripherals::$peri { | ||
| 384 | /// Convenience helper to obtain a type-erased handle to this pin. | ||
| 385 | pub fn degrade(&self) -> AnyPin { | ||
| 386 | AnyPin::new(self.port(), self.pin(), self.gpio(), self.port_reg(), self.pcr_reg()) | ||
| 387 | } | ||
| 388 | } | ||
| 389 | } | ||
| 390 | }; | ||
| 391 | } | ||
| 392 | |||
| 393 | impl_pin!(P0_0, 0, 0, Gpio0); | ||
| 394 | impl_pin!(P0_1, 0, 1, Gpio0); | ||
| 395 | impl_pin!(P0_2, 0, 2, Gpio0); | ||
| 396 | impl_pin!(P0_3, 0, 3, Gpio0); | ||
| 397 | impl_pin!(P0_4, 0, 4, Gpio0); | ||
| 398 | impl_pin!(P0_5, 0, 5, Gpio0); | ||
| 399 | impl_pin!(P0_6, 0, 6, Gpio0); | ||
| 400 | impl_pin!(P0_7, 0, 7, Gpio0); | ||
| 401 | impl_pin!(P0_8, 0, 8, Gpio0); | ||
| 402 | impl_pin!(P0_9, 0, 9, Gpio0); | ||
| 403 | impl_pin!(P0_10, 0, 10, Gpio0); | ||
| 404 | impl_pin!(P0_11, 0, 11, Gpio0); | ||
| 405 | impl_pin!(P0_12, 0, 12, Gpio0); | ||
| 406 | impl_pin!(P0_13, 0, 13, Gpio0); | ||
| 407 | impl_pin!(P0_14, 0, 14, Gpio0); | ||
| 408 | impl_pin!(P0_15, 0, 15, Gpio0); | ||
| 409 | impl_pin!(P0_16, 0, 16, Gpio0); | ||
| 410 | impl_pin!(P0_17, 0, 17, Gpio0); | ||
| 411 | impl_pin!(P0_18, 0, 18, Gpio0); | ||
| 412 | impl_pin!(P0_19, 0, 19, Gpio0); | ||
| 413 | impl_pin!(P0_20, 0, 20, Gpio0); | ||
| 414 | impl_pin!(P0_21, 0, 21, Gpio0); | ||
| 415 | impl_pin!(P0_22, 0, 22, Gpio0); | ||
| 416 | impl_pin!(P0_23, 0, 23, Gpio0); | ||
| 417 | impl_pin!(P0_24, 0, 24, Gpio0); | ||
| 418 | impl_pin!(P0_25, 0, 25, Gpio0); | ||
| 419 | impl_pin!(P0_26, 0, 26, Gpio0); | ||
| 420 | impl_pin!(P0_27, 0, 27, Gpio0); | ||
| 421 | impl_pin!(P0_28, 0, 28, Gpio0); | ||
| 422 | impl_pin!(P0_29, 0, 29, Gpio0); | ||
| 423 | impl_pin!(P0_30, 0, 30, Gpio0); | ||
| 424 | impl_pin!(P0_31, 0, 31, Gpio0); | ||
| 425 | |||
| 426 | impl_pin!(P1_0, 1, 0, Gpio1); | ||
| 427 | impl_pin!(P1_1, 1, 1, Gpio1); | ||
| 428 | impl_pin!(P1_2, 1, 2, Gpio1); | ||
| 429 | impl_pin!(P1_3, 1, 3, Gpio1); | ||
| 430 | impl_pin!(P1_4, 1, 4, Gpio1); | ||
| 431 | impl_pin!(P1_5, 1, 5, Gpio1); | ||
| 432 | impl_pin!(P1_6, 1, 6, Gpio1); | ||
| 433 | impl_pin!(P1_7, 1, 7, Gpio1); | ||
| 434 | impl_pin!(P1_8, 1, 8, Gpio1); | ||
| 435 | impl_pin!(P1_9, 1, 9, Gpio1); | ||
| 436 | impl_pin!(P1_10, 1, 10, Gpio1); | ||
| 437 | impl_pin!(P1_11, 1, 11, Gpio1); | ||
| 438 | impl_pin!(P1_12, 1, 12, Gpio1); | ||
| 439 | impl_pin!(P1_13, 1, 13, Gpio1); | ||
| 440 | impl_pin!(P1_14, 1, 14, Gpio1); | ||
| 441 | impl_pin!(P1_15, 1, 15, Gpio1); | ||
| 442 | impl_pin!(P1_16, 1, 16, Gpio1); | ||
| 443 | impl_pin!(P1_17, 1, 17, Gpio1); | ||
| 444 | impl_pin!(P1_18, 1, 18, Gpio1); | ||
| 445 | impl_pin!(P1_19, 1, 19, Gpio1); | ||
| 446 | impl_pin!(P1_20, 1, 20, Gpio1); | ||
| 447 | impl_pin!(P1_21, 1, 21, Gpio1); | ||
| 448 | impl_pin!(P1_22, 1, 22, Gpio1); | ||
| 449 | impl_pin!(P1_23, 1, 23, Gpio1); | ||
| 450 | impl_pin!(P1_24, 1, 24, Gpio1); | ||
| 451 | impl_pin!(P1_25, 1, 25, Gpio1); | ||
| 452 | impl_pin!(P1_26, 1, 26, Gpio1); | ||
| 453 | impl_pin!(P1_27, 1, 27, Gpio1); | ||
| 454 | impl_pin!(P1_28, 1, 28, Gpio1); | ||
| 455 | impl_pin!(P1_29, 1, 29, Gpio1); | ||
| 456 | impl_pin!(P1_30, 1, 30, Gpio1); | ||
| 457 | impl_pin!(P1_31, 1, 31, Gpio1); | ||
| 458 | |||
| 459 | impl_pin!(P2_0, 2, 0, Gpio2); | ||
| 460 | impl_pin!(P2_1, 2, 1, Gpio2); | ||
| 461 | impl_pin!(P2_2, 2, 2, Gpio2); | ||
| 462 | impl_pin!(P2_3, 2, 3, Gpio2); | ||
| 463 | impl_pin!(P2_4, 2, 4, Gpio2); | ||
| 464 | impl_pin!(P2_5, 2, 5, Gpio2); | ||
| 465 | impl_pin!(P2_6, 2, 6, Gpio2); | ||
| 466 | impl_pin!(P2_7, 2, 7, Gpio2); | ||
| 467 | impl_pin!(P2_8, 2, 8, Gpio2); | ||
| 468 | impl_pin!(P2_9, 2, 9, Gpio2); | ||
| 469 | impl_pin!(P2_10, 2, 10, Gpio2); | ||
| 470 | impl_pin!(P2_11, 2, 11, Gpio2); | ||
| 471 | impl_pin!(P2_12, 2, 12, Gpio2); | ||
| 472 | impl_pin!(P2_13, 2, 13, Gpio2); | ||
| 473 | impl_pin!(P2_14, 2, 14, Gpio2); | ||
| 474 | impl_pin!(P2_15, 2, 15, Gpio2); | ||
| 475 | impl_pin!(P2_16, 2, 16, Gpio2); | ||
| 476 | impl_pin!(P2_17, 2, 17, Gpio2); | ||
| 477 | impl_pin!(P2_18, 2, 18, Gpio2); | ||
| 478 | impl_pin!(P2_19, 2, 19, Gpio2); | ||
| 479 | impl_pin!(P2_20, 2, 20, Gpio2); | ||
| 480 | impl_pin!(P2_21, 2, 21, Gpio2); | ||
| 481 | impl_pin!(P2_22, 2, 22, Gpio2); | ||
| 482 | impl_pin!(P2_23, 2, 23, Gpio2); | ||
| 483 | impl_pin!(P2_24, 2, 24, Gpio2); | ||
| 484 | impl_pin!(P2_25, 2, 25, Gpio2); | ||
| 485 | impl_pin!(P2_26, 2, 26, Gpio2); | ||
| 486 | impl_pin!(P2_27, 2, 27, Gpio2); | ||
| 487 | impl_pin!(P2_28, 2, 28, Gpio2); | ||
| 488 | impl_pin!(P2_29, 2, 29, Gpio2); | ||
| 489 | impl_pin!(P2_30, 2, 30, Gpio2); | ||
| 490 | impl_pin!(P2_31, 2, 31, Gpio2); | ||
| 491 | |||
| 492 | impl_pin!(P3_0, 3, 0, Gpio3); | ||
| 493 | impl_pin!(P3_1, 3, 1, Gpio3); | ||
| 494 | impl_pin!(P3_2, 3, 2, Gpio3); | ||
| 495 | impl_pin!(P3_3, 3, 3, Gpio3); | ||
| 496 | impl_pin!(P3_4, 3, 4, Gpio3); | ||
| 497 | impl_pin!(P3_5, 3, 5, Gpio3); | ||
| 498 | impl_pin!(P3_6, 3, 6, Gpio3); | ||
| 499 | impl_pin!(P3_7, 3, 7, Gpio3); | ||
| 500 | impl_pin!(P3_8, 3, 8, Gpio3); | ||
| 501 | impl_pin!(P3_9, 3, 9, Gpio3); | ||
| 502 | impl_pin!(P3_10, 3, 10, Gpio3); | ||
| 503 | impl_pin!(P3_11, 3, 11, Gpio3); | ||
| 504 | impl_pin!(P3_12, 3, 12, Gpio3); | ||
| 505 | impl_pin!(P3_13, 3, 13, Gpio3); | ||
| 506 | impl_pin!(P3_14, 3, 14, Gpio3); | ||
| 507 | impl_pin!(P3_15, 3, 15, Gpio3); | ||
| 508 | impl_pin!(P3_16, 3, 16, Gpio3); | ||
| 509 | impl_pin!(P3_17, 3, 17, Gpio3); | ||
| 510 | impl_pin!(P3_18, 3, 18, Gpio3); | ||
| 511 | impl_pin!(P3_19, 3, 19, Gpio3); | ||
| 512 | impl_pin!(P3_20, 3, 20, Gpio3); | ||
| 513 | impl_pin!(P3_21, 3, 21, Gpio3); | ||
| 514 | impl_pin!(P3_22, 3, 22, Gpio3); | ||
| 515 | impl_pin!(P3_23, 3, 23, Gpio3); | ||
| 516 | impl_pin!(P3_24, 3, 24, Gpio3); | ||
| 517 | impl_pin!(P3_25, 3, 25, Gpio3); | ||
| 518 | impl_pin!(P3_26, 3, 26, Gpio3); | ||
| 519 | impl_pin!(P3_27, 3, 27, Gpio3); | ||
| 520 | impl_pin!(P3_28, 3, 28, Gpio3); | ||
| 521 | impl_pin!(P3_29, 3, 29, Gpio3); | ||
| 522 | impl_pin!(P3_30, 3, 30, Gpio3); | ||
| 523 | impl_pin!(P3_31, 3, 31, Gpio3); | ||
| 524 | |||
| 525 | impl_pin!(P4_0, 4, 0, Gpio4); | ||
| 526 | impl_pin!(P4_1, 4, 1, Gpio4); | ||
| 527 | impl_pin!(P4_2, 4, 2, Gpio4); | ||
| 528 | impl_pin!(P4_3, 4, 3, Gpio4); | ||
| 529 | impl_pin!(P4_4, 4, 4, Gpio4); | ||
| 530 | impl_pin!(P4_5, 4, 5, Gpio4); | ||
| 531 | impl_pin!(P4_6, 4, 6, Gpio4); | ||
| 532 | impl_pin!(P4_7, 4, 7, Gpio4); | ||
| 533 | impl_pin!(P4_8, 4, 8, Gpio4); | ||
| 534 | impl_pin!(P4_9, 4, 9, Gpio4); | ||
| 535 | impl_pin!(P4_10, 4, 10, Gpio4); | ||
| 536 | impl_pin!(P4_11, 4, 11, Gpio4); | ||
| 537 | impl_pin!(P4_12, 4, 12, Gpio4); | ||
| 538 | impl_pin!(P4_13, 4, 13, Gpio4); | ||
| 539 | impl_pin!(P4_14, 4, 14, Gpio4); | ||
| 540 | impl_pin!(P4_15, 4, 15, Gpio4); | ||
| 541 | impl_pin!(P4_16, 4, 16, Gpio4); | ||
| 542 | impl_pin!(P4_17, 4, 17, Gpio4); | ||
| 543 | impl_pin!(P4_18, 4, 18, Gpio4); | ||
| 544 | impl_pin!(P4_19, 4, 19, Gpio4); | ||
| 545 | impl_pin!(P4_20, 4, 20, Gpio4); | ||
| 546 | impl_pin!(P4_21, 4, 21, Gpio4); | ||
| 547 | impl_pin!(P4_22, 4, 22, Gpio4); | ||
| 548 | impl_pin!(P4_23, 4, 23, Gpio4); | ||
| 549 | impl_pin!(P4_24, 4, 24, Gpio4); | ||
| 550 | impl_pin!(P4_25, 4, 25, Gpio4); | ||
| 551 | impl_pin!(P4_26, 4, 26, Gpio4); | ||
| 552 | impl_pin!(P4_27, 4, 27, Gpio4); | ||
| 553 | impl_pin!(P4_28, 4, 28, Gpio4); | ||
| 554 | impl_pin!(P4_29, 4, 29, Gpio4); | ||
| 555 | impl_pin!(P4_30, 4, 30, Gpio4); | ||
| 556 | impl_pin!(P4_31, 4, 31, Gpio4); | ||
| 557 | |||
| 558 | /// A flexible pin that can be configured as input or output. | ||
| 559 | pub struct Flex<'d> { | ||
| 560 | pin: Peri<'d, AnyPin>, | ||
| 561 | _marker: PhantomData<&'d mut ()>, | ||
| 562 | } | ||
| 563 | |||
| 564 | impl<'d> Flex<'d> { | ||
| 565 | /// Wrap the pin in a `Flex`. | ||
| 566 | /// | ||
| 567 | /// The pin remains unmodified. The initial output level is unspecified, but | ||
| 568 | /// can be changed before the pin is put into output mode. | ||
| 569 | pub fn new(pin: Peri<'d, impl GpioPin>) -> Self { | ||
| 570 | pin.set_function(Mux::Mux0); | ||
| 571 | Self { | ||
| 572 | pin: pin.into(), | ||
| 573 | _marker: PhantomData, | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | #[inline] | ||
| 578 | fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { | ||
| 579 | self.pin.gpio() | ||
| 580 | } | ||
| 581 | |||
| 582 | #[inline] | ||
| 583 | fn mask(&self) -> u32 { | ||
| 584 | self.pin.mask() | ||
| 585 | } | ||
| 586 | |||
| 587 | /// Put the pin into input mode. | ||
| 588 | pub fn set_as_input(&mut self) { | ||
| 589 | let mask = self.mask(); | ||
| 590 | let gpio = self.gpio(); | ||
| 591 | |||
| 592 | self.set_enable_input_buffer(); | ||
| 593 | |||
| 594 | gpio.pddr().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); | ||
| 595 | } | ||
| 596 | |||
| 597 | /// Put the pin into output mode. | ||
| 598 | pub fn set_as_output(&mut self) { | ||
| 599 | let mask = self.mask(); | ||
| 600 | let gpio = self.gpio(); | ||
| 601 | |||
| 602 | self.set_pull(Pull::Disabled); | ||
| 603 | |||
| 604 | gpio.pddr().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); | ||
| 605 | } | ||
| 606 | |||
| 607 | /// Set output level to High. | ||
| 608 | #[inline] | ||
| 609 | pub fn set_high(&mut self) { | ||
| 610 | self.gpio().psor().write(|w| unsafe { w.bits(self.mask()) }); | ||
| 611 | } | ||
| 612 | |||
| 613 | /// Set output level to Low. | ||
| 614 | #[inline] | ||
| 615 | pub fn set_low(&mut self) { | ||
| 616 | self.gpio().pcor().write(|w| unsafe { w.bits(self.mask()) }); | ||
| 617 | } | ||
| 618 | |||
| 619 | /// Set output level to the given `Level`. | ||
| 620 | #[inline] | ||
| 621 | pub fn set_level(&mut self, level: Level) { | ||
| 622 | match level { | ||
| 623 | Level::High => self.set_high(), | ||
| 624 | Level::Low => self.set_low(), | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 628 | /// Toggle output level. | ||
| 629 | #[inline] | ||
| 630 | pub fn toggle(&mut self) { | ||
| 631 | self.gpio().ptor().write(|w| unsafe { w.bits(self.mask()) }); | ||
| 632 | } | ||
| 633 | |||
| 634 | /// Get whether the pin input level is high. | ||
| 635 | #[inline] | ||
| 636 | pub fn is_high(&self) -> bool { | ||
| 637 | (self.gpio().pdir().read().bits() & self.mask()) != 0 | ||
| 638 | } | ||
| 639 | |||
| 640 | /// Get whether the pin input level is low. | ||
| 641 | #[inline] | ||
| 642 | pub fn is_low(&self) -> bool { | ||
| 643 | !self.is_high() | ||
| 644 | } | ||
| 645 | |||
| 646 | /// Is the output pin set as high? | ||
| 647 | #[inline] | ||
| 648 | pub fn is_set_high(&self) -> bool { | ||
| 649 | self.is_high() | ||
| 650 | } | ||
| 651 | |||
| 652 | /// Is the output pin set as low? | ||
| 653 | #[inline] | ||
| 654 | pub fn is_set_low(&self) -> bool { | ||
| 655 | !self.is_set_high() | ||
| 656 | } | ||
| 657 | |||
| 658 | /// Configure the pin pull up/down level. | ||
| 659 | pub fn set_pull(&mut self, pull_select: Pull) { | ||
| 660 | self.pin.set_pull(pull_select); | ||
| 661 | } | ||
| 662 | |||
| 663 | /// Configure the pin drive strength. | ||
| 664 | pub fn set_drive_strength(&mut self, strength: DriveStrength) { | ||
| 665 | self.pin.set_drive_strength(strength.into()); | ||
| 666 | } | ||
| 667 | |||
| 668 | /// Configure the pin slew rate. | ||
| 669 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | ||
| 670 | self.pin.set_slew_rate(slew_rate.into()); | ||
| 671 | } | ||
| 672 | |||
| 673 | /// Enable input buffer for the pin. | ||
| 674 | pub fn set_enable_input_buffer(&mut self) { | ||
| 675 | self.pin.set_enable_input_buffer(); | ||
| 676 | } | ||
| 677 | |||
| 678 | /// Get pin level. | ||
| 679 | pub fn get_level(&self) -> Level { | ||
| 680 | self.is_high().into() | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 684 | /// Async methods | ||
| 685 | impl<'d> Flex<'d> { | ||
| 686 | /// Helper function that waits for a given interrupt trigger | ||
| 687 | async fn wait_for_inner(&mut self, level: crate::pac::gpio0::icr::Irqc) { | ||
| 688 | // First, ensure that we have a waker that is ready for this port+pin | ||
| 689 | let w = PORT_WAIT_MAPS[self.pin.port].wait(self.pin.pin); | ||
| 690 | let mut w = pin!(w); | ||
| 691 | // Wait for the subscription to occur, which requires polling at least once | ||
| 692 | // | ||
| 693 | // This function returns a result, but can only be an Err if: | ||
| 694 | // | ||
| 695 | // * We call `.close()` on a WaitMap, which we never do | ||
| 696 | // * We have a duplicate key, which can't happen because `wait_for_*` methods | ||
| 697 | // take an &mut ref of their unique port+pin combo | ||
| 698 | // | ||
| 699 | // So we wait for it to complete, but ignore the result. | ||
| 700 | _ = w.as_mut().subscribe().await; | ||
| 701 | |||
| 702 | // Now that our waker is in the map, we can enable the appropriate interrupt | ||
| 703 | // | ||
| 704 | // Clear any existing pending interrupt on this pin | ||
| 705 | self.pin | ||
| 706 | .gpio() | ||
| 707 | .isfr0() | ||
| 708 | .write(|w| unsafe { w.bits(1 << self.pin.pin()) }); | ||
| 709 | self.pin.gpio().icr(self.pin.pin()).write(|w| w.isf().isf1()); | ||
| 710 | |||
| 711 | // Pin interrupt configuration | ||
| 712 | self.pin | ||
| 713 | .gpio() | ||
| 714 | .icr(self.pin.pin()) | ||
| 715 | .modify(|_, w| w.irqc().variant(level)); | ||
| 716 | |||
| 717 | // Finally, we can await the matching call to `.wake()` from the interrupt. | ||
| 718 | // | ||
| 719 | // Again, technically, this could return a result, but for the same reasons | ||
| 720 | // as above, this can't be an error in our case, so just wait for it to complete | ||
| 721 | _ = w.await; | ||
| 722 | } | ||
| 723 | |||
| 724 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 725 | #[inline] | ||
| 726 | pub fn wait_for_high(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 727 | self.wait_for_inner(crate::pac::gpio0::icr::Irqc::Irqc12) | ||
| 728 | } | ||
| 729 | |||
| 730 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 731 | #[inline] | ||
| 732 | pub fn wait_for_low(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 733 | self.wait_for_inner(crate::pac::gpio0::icr::Irqc::Irqc8) | ||
| 734 | } | ||
| 735 | |||
| 736 | /// Wait for the pin to undergo a transition from low to high. | ||
| 737 | #[inline] | ||
| 738 | pub fn wait_for_rising_edge(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 739 | self.wait_for_inner(crate::pac::gpio0::icr::Irqc::Irqc9) | ||
| 740 | } | ||
| 741 | |||
| 742 | /// Wait for the pin to undergo a transition from high to low. | ||
| 743 | #[inline] | ||
| 744 | pub fn wait_for_falling_edge(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 745 | self.wait_for_inner(crate::pac::gpio0::icr::Irqc::Irqc10) | ||
| 746 | } | ||
| 747 | |||
| 748 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 749 | #[inline] | ||
| 750 | pub fn wait_for_any_edge(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 751 | self.wait_for_inner(crate::pac::gpio0::icr::Irqc::Irqc11) | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | /// GPIO output driver that owns a `Flex` pin. | ||
| 756 | pub struct Output<'d> { | ||
| 757 | flex: Flex<'d>, | ||
| 758 | } | ||
| 759 | |||
| 760 | impl<'d> Output<'d> { | ||
| 761 | /// Create a GPIO output driver for a [GpioPin] with the provided [Level]. | ||
| 762 | pub fn new(pin: Peri<'d, impl GpioPin>, initial: Level, strength: DriveStrength, slew_rate: SlewRate) -> Self { | ||
| 763 | let mut flex = Flex::new(pin); | ||
| 764 | flex.set_level(initial); | ||
| 765 | flex.set_as_output(); | ||
| 766 | flex.set_drive_strength(strength); | ||
| 767 | flex.set_slew_rate(slew_rate); | ||
| 768 | Self { flex } | ||
| 769 | } | ||
| 770 | |||
| 771 | /// Set the output as high. | ||
| 772 | #[inline] | ||
| 773 | pub fn set_high(&mut self) { | ||
| 774 | self.flex.set_high(); | ||
| 775 | } | ||
| 776 | |||
| 777 | /// Set the output as low. | ||
| 778 | #[inline] | ||
| 779 | pub fn set_low(&mut self) { | ||
| 780 | self.flex.set_low(); | ||
| 781 | } | ||
| 782 | |||
| 783 | /// Set the output level. | ||
| 784 | #[inline] | ||
| 785 | pub fn set_level(&mut self, level: Level) { | ||
| 786 | self.flex.set_level(level); | ||
| 787 | } | ||
| 788 | |||
| 789 | /// Toggle the output level. | ||
| 790 | #[inline] | ||
| 791 | pub fn toggle(&mut self) { | ||
| 792 | self.flex.toggle(); | ||
| 793 | } | ||
| 794 | |||
| 795 | /// Is the output pin set as high? | ||
| 796 | #[inline] | ||
| 797 | pub fn is_set_high(&self) -> bool { | ||
| 798 | self.flex.is_high() | ||
| 799 | } | ||
| 800 | |||
| 801 | /// Is the output pin set as low? | ||
| 802 | #[inline] | ||
| 803 | pub fn is_set_low(&self) -> bool { | ||
| 804 | !self.is_set_high() | ||
| 805 | } | ||
| 806 | |||
| 807 | /// Expose the inner `Flex` if callers need to reconfigure the pin. | ||
| 808 | #[inline] | ||
| 809 | pub fn into_flex(self) -> Flex<'d> { | ||
| 810 | self.flex | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | /// GPIO input driver that owns a `Flex` pin. | ||
| 815 | pub struct Input<'d> { | ||
| 816 | flex: Flex<'d>, | ||
| 817 | } | ||
| 818 | |||
| 819 | impl<'d> Input<'d> { | ||
| 820 | /// Create a GPIO input driver for a [GpioPin]. | ||
| 821 | /// | ||
| 822 | pub fn new(pin: Peri<'d, impl GpioPin>, pull_select: Pull) -> Self { | ||
| 823 | let mut flex = Flex::new(pin); | ||
| 824 | flex.set_as_input(); | ||
| 825 | flex.set_pull(pull_select); | ||
| 826 | Self { flex } | ||
| 827 | } | ||
| 828 | |||
| 829 | /// Get whether the pin input level is high. | ||
| 830 | #[inline] | ||
| 831 | pub fn is_high(&self) -> bool { | ||
| 832 | self.flex.is_high() | ||
| 833 | } | ||
| 834 | |||
| 835 | /// Get whether the pin input level is low. | ||
| 836 | #[inline] | ||
| 837 | pub fn is_low(&self) -> bool { | ||
| 838 | self.flex.is_low() | ||
| 839 | } | ||
| 840 | |||
| 841 | /// Expose the inner `Flex` if callers need to reconfigure the pin. | ||
| 842 | /// | ||
| 843 | /// Since Drive Strength and Slew Rate are not set when creating the Input | ||
| 844 | /// pin, they need to be set when converting | ||
| 845 | #[inline] | ||
| 846 | pub fn into_flex(mut self, strength: DriveStrength, slew_rate: SlewRate) -> Flex<'d> { | ||
| 847 | self.flex.set_drive_strength(strength); | ||
| 848 | self.flex.set_slew_rate(slew_rate); | ||
| 849 | self.flex | ||
| 850 | } | ||
| 851 | |||
| 852 | /// Get the pin level. | ||
| 853 | pub fn get_level(&self) -> Level { | ||
| 854 | self.flex.get_level() | ||
| 855 | } | ||
| 856 | } | ||
| 857 | |||
| 858 | /// Async methods | ||
| 859 | impl<'d> Input<'d> { | ||
| 860 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 861 | #[inline] | ||
| 862 | pub fn wait_for_high(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 863 | self.flex.wait_for_high() | ||
| 864 | } | ||
| 865 | |||
| 866 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 867 | #[inline] | ||
| 868 | pub fn wait_for_low(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 869 | self.flex.wait_for_low() | ||
| 870 | } | ||
| 871 | |||
| 872 | /// Wait for the pin to undergo a transition from low to high. | ||
| 873 | #[inline] | ||
| 874 | pub fn wait_for_rising_edge(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 875 | self.flex.wait_for_rising_edge() | ||
| 876 | } | ||
| 877 | |||
| 878 | /// Wait for the pin to undergo a transition from high to low. | ||
| 879 | #[inline] | ||
| 880 | pub fn wait_for_falling_edge(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 881 | self.flex.wait_for_falling_edge() | ||
| 882 | } | ||
| 883 | |||
| 884 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 885 | #[inline] | ||
| 886 | pub fn wait_for_any_edge(&mut self) -> impl Future<Output = ()> + use<'_, 'd> { | ||
| 887 | self.flex.wait_for_any_edge() | ||
| 888 | } | ||
| 889 | } | ||
| 890 | |||
| 891 | impl embedded_hal_async::digital::Wait for Input<'_> { | ||
| 892 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { | ||
| 893 | self.wait_for_high().await; | ||
| 894 | Ok(()) | ||
| 895 | } | ||
| 896 | |||
| 897 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { | ||
| 898 | self.wait_for_low().await; | ||
| 899 | Ok(()) | ||
| 900 | } | ||
| 901 | |||
| 902 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { | ||
| 903 | self.wait_for_rising_edge().await; | ||
| 904 | Ok(()) | ||
| 905 | } | ||
| 906 | |||
| 907 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { | ||
| 908 | self.wait_for_falling_edge().await; | ||
| 909 | Ok(()) | ||
| 910 | } | ||
| 911 | |||
| 912 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { | ||
| 913 | self.wait_for_any_edge().await; | ||
| 914 | Ok(()) | ||
| 915 | } | ||
| 916 | } | ||
| 917 | |||
| 918 | impl embedded_hal_async::digital::Wait for Flex<'_> { | ||
| 919 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { | ||
| 920 | self.wait_for_high().await; | ||
| 921 | Ok(()) | ||
| 922 | } | ||
| 923 | |||
| 924 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { | ||
| 925 | self.wait_for_low().await; | ||
| 926 | Ok(()) | ||
| 927 | } | ||
| 928 | |||
| 929 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { | ||
| 930 | self.wait_for_rising_edge().await; | ||
| 931 | Ok(()) | ||
| 932 | } | ||
| 933 | |||
| 934 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { | ||
| 935 | self.wait_for_falling_edge().await; | ||
| 936 | Ok(()) | ||
| 937 | } | ||
| 938 | |||
| 939 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { | ||
| 940 | self.wait_for_any_edge().await; | ||
| 941 | Ok(()) | ||
| 942 | } | ||
| 943 | } | ||
| 944 | |||
| 945 | // Both embedded_hal 0.2 and 1.0 must be supported by embassy HALs. | ||
| 946 | impl embedded_hal_02::digital::v2::InputPin for Flex<'_> { | ||
| 947 | // GPIO operations on this block cannot fail, therefor we set the error type | ||
| 948 | // to Infallible to guarantee that we can only produce Ok variants. | ||
| 949 | type Error = Infallible; | ||
| 950 | |||
| 951 | #[inline] | ||
| 952 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 953 | Ok(self.is_high()) | ||
| 954 | } | ||
| 955 | |||
| 956 | #[inline] | ||
| 957 | fn is_low(&self) -> Result<bool, Self::Error> { | ||
| 958 | Ok(self.is_low()) | ||
| 959 | } | ||
| 960 | } | ||
| 961 | |||
| 962 | impl embedded_hal_02::digital::v2::InputPin for Input<'_> { | ||
| 963 | type Error = Infallible; | ||
| 964 | |||
| 965 | #[inline] | ||
| 966 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 967 | Ok(self.is_high()) | ||
| 968 | } | ||
| 969 | |||
| 970 | #[inline] | ||
| 971 | fn is_low(&self) -> Result<bool, Self::Error> { | ||
| 972 | Ok(self.is_low()) | ||
| 973 | } | ||
| 974 | } | ||
| 975 | |||
| 976 | impl embedded_hal_02::digital::v2::OutputPin for Flex<'_> { | ||
| 977 | type Error = Infallible; | ||
| 978 | |||
| 979 | #[inline] | ||
| 980 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 981 | self.set_high(); | ||
| 982 | Ok(()) | ||
| 983 | } | ||
| 984 | |||
| 985 | #[inline] | ||
| 986 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 987 | self.set_low(); | ||
| 988 | Ok(()) | ||
| 989 | } | ||
| 990 | } | ||
| 991 | |||
| 992 | impl embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'_> { | ||
| 993 | #[inline] | ||
| 994 | fn is_set_high(&self) -> Result<bool, Self::Error> { | ||
| 995 | Ok(self.is_set_high()) | ||
| 996 | } | ||
| 997 | |||
| 998 | #[inline] | ||
| 999 | fn is_set_low(&self) -> Result<bool, Self::Error> { | ||
| 1000 | Ok(self.is_set_low()) | ||
| 1001 | } | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | impl embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'_> { | ||
| 1005 | type Error = Infallible; | ||
| 1006 | |||
| 1007 | #[inline] | ||
| 1008 | fn toggle(&mut self) -> Result<(), Self::Error> { | ||
| 1009 | self.toggle(); | ||
| 1010 | Ok(()) | ||
| 1011 | } | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | impl embedded_hal_1::digital::ErrorType for Flex<'_> { | ||
| 1015 | type Error = Infallible; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | impl embedded_hal_1::digital::ErrorType for Input<'_> { | ||
| 1019 | type Error = Infallible; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | impl embedded_hal_1::digital::ErrorType for Output<'_> { | ||
| 1023 | type Error = Infallible; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | impl embedded_hal_1::digital::InputPin for Input<'_> { | ||
| 1027 | #[inline] | ||
| 1028 | fn is_high(&mut self) -> Result<bool, Self::Error> { | ||
| 1029 | Ok((*self).is_high()) | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | #[inline] | ||
| 1033 | fn is_low(&mut self) -> Result<bool, Self::Error> { | ||
| 1034 | Ok((*self).is_low()) | ||
| 1035 | } | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | impl embedded_hal_1::digital::OutputPin for Flex<'_> { | ||
| 1039 | #[inline] | ||
| 1040 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 1041 | self.set_high(); | ||
| 1042 | Ok(()) | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | #[inline] | ||
| 1046 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 1047 | self.set_low(); | ||
| 1048 | Ok(()) | ||
| 1049 | } | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | impl embedded_hal_1::digital::StatefulOutputPin for Flex<'_> { | ||
| 1053 | #[inline] | ||
| 1054 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { | ||
| 1055 | Ok((*self).is_set_high()) | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | #[inline] | ||
| 1059 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { | ||
| 1060 | Ok((*self).is_set_low()) | ||
| 1061 | } | ||
| 1062 | } | ||
diff --git a/embassy-mcxa/src/i2c/controller.rs b/embassy-mcxa/src/i2c/controller.rs new file mode 100644 index 000000000..182a53aea --- /dev/null +++ b/embassy-mcxa/src/i2c/controller.rs | |||
| @@ -0,0 +1,742 @@ | |||
| 1 | //! LPI2C controller driver | ||
| 2 | |||
| 3 | use core::future::Future; | ||
| 4 | use core::marker::PhantomData; | ||
| 5 | |||
| 6 | use embassy_hal_internal::drop::OnDrop; | ||
| 7 | use embassy_hal_internal::Peri; | ||
| 8 | use mcxa_pac::lpi2c0::mtdr::Cmd; | ||
| 9 | |||
| 10 | use super::{Async, Blocking, Error, Instance, InterruptHandler, Mode, Result, SclPin, SdaPin}; | ||
| 11 | use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig}; | ||
| 12 | use crate::clocks::{enable_and_reset, PoweredClock}; | ||
| 13 | use crate::interrupt::typelevel::Interrupt; | ||
| 14 | use crate::AnyPin; | ||
| 15 | |||
| 16 | /// Bus speed (nominal SCL, no clock stretching) | ||
| 17 | #[derive(Clone, Copy, Default, PartialEq)] | ||
| 18 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 19 | pub enum Speed { | ||
| 20 | #[default] | ||
| 21 | /// 100 kbit/sec | ||
| 22 | Standard, | ||
| 23 | /// 400 kbit/sec | ||
| 24 | Fast, | ||
| 25 | /// 1 Mbit/sec | ||
| 26 | FastPlus, | ||
| 27 | /// 3.4 Mbit/sec | ||
| 28 | UltraFast, | ||
| 29 | } | ||
| 30 | |||
| 31 | impl From<Speed> for (u8, u8, u8, u8) { | ||
| 32 | fn from(value: Speed) -> (u8, u8, u8, u8) { | ||
| 33 | match value { | ||
| 34 | Speed::Standard => (0x3d, 0x37, 0x3b, 0x1d), | ||
| 35 | Speed::Fast => (0x0e, 0x0c, 0x0d, 0x06), | ||
| 36 | Speed::FastPlus => (0x04, 0x03, 0x03, 0x02), | ||
| 37 | |||
| 38 | // UltraFast is "special". Leaving it unimplemented until | ||
| 39 | // the driver and the clock API is further stabilized. | ||
| 40 | Speed::UltraFast => todo!(), | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 46 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 47 | enum SendStop { | ||
| 48 | No, | ||
| 49 | Yes, | ||
| 50 | } | ||
| 51 | |||
| 52 | /// I2C controller configuration | ||
| 53 | #[derive(Clone, Copy, Default)] | ||
| 54 | #[non_exhaustive] | ||
| 55 | pub struct Config { | ||
| 56 | /// Bus speed | ||
| 57 | pub speed: Speed, | ||
| 58 | } | ||
| 59 | |||
| 60 | /// I2C Controller Driver. | ||
| 61 | pub struct I2c<'d, T: Instance, M: Mode> { | ||
| 62 | _peri: Peri<'d, T>, | ||
| 63 | _scl: Peri<'d, AnyPin>, | ||
| 64 | _sda: Peri<'d, AnyPin>, | ||
| 65 | _phantom: PhantomData<M>, | ||
| 66 | is_hs: bool, | ||
| 67 | } | ||
| 68 | |||
| 69 | impl<'d, T: Instance> I2c<'d, T, Blocking> { | ||
| 70 | /// Create a new blocking instance of the I2C Controller bus driver. | ||
| 71 | pub fn new_blocking( | ||
| 72 | peri: Peri<'d, T>, | ||
| 73 | scl: Peri<'d, impl SclPin<T>>, | ||
| 74 | sda: Peri<'d, impl SdaPin<T>>, | ||
| 75 | config: Config, | ||
| 76 | ) -> Result<Self> { | ||
| 77 | Self::new_inner(peri, scl, sda, config) | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | ||
| 82 | fn new_inner( | ||
| 83 | _peri: Peri<'d, T>, | ||
| 84 | scl: Peri<'d, impl SclPin<T>>, | ||
| 85 | sda: Peri<'d, impl SdaPin<T>>, | ||
| 86 | config: Config, | ||
| 87 | ) -> Result<Self> { | ||
| 88 | let (power, source, div) = Self::clock_config(config.speed); | ||
| 89 | |||
| 90 | // Enable clocks | ||
| 91 | let conf = Lpi2cConfig { | ||
| 92 | power, | ||
| 93 | source, | ||
| 94 | div, | ||
| 95 | instance: T::CLOCK_INSTANCE, | ||
| 96 | }; | ||
| 97 | |||
| 98 | _ = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? }; | ||
| 99 | |||
| 100 | scl.mux(); | ||
| 101 | sda.mux(); | ||
| 102 | |||
| 103 | let _scl = scl.into(); | ||
| 104 | let _sda = sda.into(); | ||
| 105 | |||
| 106 | Self::set_config(&config)?; | ||
| 107 | |||
| 108 | Ok(Self { | ||
| 109 | _peri, | ||
| 110 | _scl, | ||
| 111 | _sda, | ||
| 112 | _phantom: PhantomData, | ||
| 113 | is_hs: config.speed == Speed::UltraFast, | ||
| 114 | }) | ||
| 115 | } | ||
| 116 | |||
| 117 | fn set_config(config: &Config) -> Result<()> { | ||
| 118 | // Disable the controller. | ||
| 119 | critical_section::with(|_| T::regs().mcr().modify(|_, w| w.men().disabled())); | ||
| 120 | |||
| 121 | // Soft-reset the controller, read and write FIFOs. | ||
| 122 | Self::reset_fifos(); | ||
| 123 | critical_section::with(|_| { | ||
| 124 | T::regs().mcr().modify(|_, w| w.rst().reset()); | ||
| 125 | // According to Reference Manual section 40.7.1.4, "There | ||
| 126 | // is no minimum delay required before clearing the | ||
| 127 | // software reset", therefore we clear it immediately. | ||
| 128 | T::regs().mcr().modify(|_, w| w.rst().not_reset()); | ||
| 129 | |||
| 130 | T::regs().mcr().modify(|_, w| w.dozen().clear_bit().dbgen().clear_bit()); | ||
| 131 | }); | ||
| 132 | |||
| 133 | let (clklo, clkhi, sethold, datavd) = config.speed.into(); | ||
| 134 | |||
| 135 | critical_section::with(|_| { | ||
| 136 | T::regs().mccr0().modify(|_, w| unsafe { | ||
| 137 | w.clklo() | ||
| 138 | .bits(clklo) | ||
| 139 | .clkhi() | ||
| 140 | .bits(clkhi) | ||
| 141 | .sethold() | ||
| 142 | .bits(sethold) | ||
| 143 | .datavd() | ||
| 144 | .bits(datavd) | ||
| 145 | }) | ||
| 146 | }); | ||
| 147 | |||
| 148 | // Enable the controller. | ||
| 149 | critical_section::with(|_| T::regs().mcr().modify(|_, w| w.men().enabled())); | ||
| 150 | |||
| 151 | // Clear all flags | ||
| 152 | T::regs().msr().write(|w| { | ||
| 153 | w.epf() | ||
| 154 | .clear_bit_by_one() | ||
| 155 | .sdf() | ||
| 156 | .clear_bit_by_one() | ||
| 157 | .ndf() | ||
| 158 | .clear_bit_by_one() | ||
| 159 | .alf() | ||
| 160 | .clear_bit_by_one() | ||
| 161 | .fef() | ||
| 162 | .clear_bit_by_one() | ||
| 163 | .pltf() | ||
| 164 | .clear_bit_by_one() | ||
| 165 | .dmf() | ||
| 166 | .clear_bit_by_one() | ||
| 167 | .stf() | ||
| 168 | .clear_bit_by_one() | ||
| 169 | }); | ||
| 170 | |||
| 171 | Ok(()) | ||
| 172 | } | ||
| 173 | |||
| 174 | // REVISIT: turn this into a function of the speed parameter | ||
| 175 | fn clock_config(speed: Speed) -> (PoweredClock, Lpi2cClockSel, Div4) { | ||
| 176 | match speed { | ||
| 177 | Speed::Standard | Speed::Fast | Speed::FastPlus => ( | ||
| 178 | PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 179 | Lpi2cClockSel::FroLfDiv, | ||
| 180 | const { Div4::no_div() }, | ||
| 181 | ), | ||
| 182 | Speed::UltraFast => ( | ||
| 183 | PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 184 | Lpi2cClockSel::FroHfDiv, | ||
| 185 | const { Div4::no_div() }, | ||
| 186 | ), | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | /// Resets both TX and RX FIFOs dropping their contents. | ||
| 191 | fn reset_fifos() { | ||
| 192 | critical_section::with(|_| { | ||
| 193 | T::regs().mcr().modify(|_, w| w.rtf().reset().rrf().reset()); | ||
| 194 | }); | ||
| 195 | } | ||
| 196 | |||
| 197 | /// Checks whether the TX FIFO is full | ||
| 198 | fn is_tx_fifo_full() -> bool { | ||
| 199 | let txfifo_size = 1 << T::regs().param().read().mtxfifo().bits(); | ||
| 200 | T::regs().mfsr().read().txcount().bits() == txfifo_size | ||
| 201 | } | ||
| 202 | |||
| 203 | /// Checks whether the TX FIFO is empty | ||
| 204 | fn is_tx_fifo_empty() -> bool { | ||
| 205 | T::regs().mfsr().read().txcount() == 0 | ||
| 206 | } | ||
| 207 | |||
| 208 | /// Checks whether the RX FIFO is empty. | ||
| 209 | fn is_rx_fifo_empty() -> bool { | ||
| 210 | T::regs().mfsr().read().rxcount() == 0 | ||
| 211 | } | ||
| 212 | |||
| 213 | /// Reads and parses the controller status producing an | ||
| 214 | /// appropriate `Result<(), Error>` variant. | ||
| 215 | fn status() -> Result<()> { | ||
| 216 | let msr = T::regs().msr().read(); | ||
| 217 | T::regs().msr().write(|w| { | ||
| 218 | w.epf() | ||
| 219 | .clear_bit_by_one() | ||
| 220 | .sdf() | ||
| 221 | .clear_bit_by_one() | ||
| 222 | .ndf() | ||
| 223 | .clear_bit_by_one() | ||
| 224 | .alf() | ||
| 225 | .clear_bit_by_one() | ||
| 226 | .fef() | ||
| 227 | .clear_bit_by_one() | ||
| 228 | .fef() | ||
| 229 | .clear_bit_by_one() | ||
| 230 | .pltf() | ||
| 231 | .clear_bit_by_one() | ||
| 232 | .dmf() | ||
| 233 | .clear_bit_by_one() | ||
| 234 | .stf() | ||
| 235 | .clear_bit_by_one() | ||
| 236 | }); | ||
| 237 | |||
| 238 | if msr.ndf().bit_is_set() { | ||
| 239 | Err(Error::AddressNack) | ||
| 240 | } else if msr.alf().bit_is_set() { | ||
| 241 | Err(Error::ArbitrationLoss) | ||
| 242 | } else if msr.fef().bit_is_set() { | ||
| 243 | Err(Error::FifoError) | ||
| 244 | } else { | ||
| 245 | Ok(()) | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | /// Inserts the given command into the outgoing FIFO. | ||
| 250 | /// | ||
| 251 | /// Caller must ensure there is space in the FIFO for the new | ||
| 252 | /// command. | ||
| 253 | fn send_cmd(cmd: Cmd, data: u8) { | ||
| 254 | #[cfg(feature = "defmt")] | ||
| 255 | defmt::trace!( | ||
| 256 | "Sending cmd '{}' ({}) with data '{:08x}' MSR: {:08x}", | ||
| 257 | cmd, | ||
| 258 | cmd as u8, | ||
| 259 | data, | ||
| 260 | T::regs().msr().read().bits() | ||
| 261 | ); | ||
| 262 | |||
| 263 | T::regs() | ||
| 264 | .mtdr() | ||
| 265 | .write(|w| unsafe { w.data().bits(data) }.cmd().variant(cmd)); | ||
| 266 | } | ||
| 267 | |||
| 268 | /// Prepares an appropriate Start condition on bus by issuing a | ||
| 269 | /// `Start` command together with the device address and R/w bit. | ||
| 270 | /// | ||
| 271 | /// Blocks waiting for space in the FIFO to become available, then | ||
| 272 | /// sends the command and blocks waiting for the FIFO to become | ||
| 273 | /// empty ensuring the command was sent. | ||
| 274 | fn start(&mut self, address: u8, read: bool) -> Result<()> { | ||
| 275 | if address >= 0x80 { | ||
| 276 | return Err(Error::AddressOutOfRange(address)); | ||
| 277 | } | ||
| 278 | |||
| 279 | // Wait until we have space in the TxFIFO | ||
| 280 | while Self::is_tx_fifo_full() {} | ||
| 281 | |||
| 282 | let addr_rw = address << 1 | if read { 1 } else { 0 }; | ||
| 283 | Self::send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw); | ||
| 284 | |||
| 285 | // Wait for TxFIFO to be drained | ||
| 286 | while !Self::is_tx_fifo_empty() {} | ||
| 287 | |||
| 288 | // Check controller status | ||
| 289 | Self::status() | ||
| 290 | } | ||
| 291 | |||
| 292 | /// Prepares a Stop condition on the bus. | ||
| 293 | /// | ||
| 294 | /// Analogous to `start`, this blocks waiting for space in the | ||
| 295 | /// FIFO to become available, then sends the command and blocks | ||
| 296 | /// waiting for the FIFO to become empty ensuring the command was | ||
| 297 | /// sent. | ||
| 298 | fn stop() -> Result<()> { | ||
| 299 | // Wait until we have space in the TxFIFO | ||
| 300 | while Self::is_tx_fifo_full() {} | ||
| 301 | |||
| 302 | Self::send_cmd(Cmd::Stop, 0); | ||
| 303 | |||
| 304 | // Wait for TxFIFO to be drained | ||
| 305 | while !Self::is_tx_fifo_empty() {} | ||
| 306 | |||
| 307 | Self::status() | ||
| 308 | } | ||
| 309 | |||
| 310 | fn blocking_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> { | ||
| 311 | if read.is_empty() { | ||
| 312 | return Err(Error::InvalidReadBufferLength); | ||
| 313 | } | ||
| 314 | |||
| 315 | for chunk in read.chunks_mut(256) { | ||
| 316 | self.start(address, true)?; | ||
| 317 | |||
| 318 | // Wait until we have space in the TxFIFO | ||
| 319 | while Self::is_tx_fifo_full() {} | ||
| 320 | |||
| 321 | Self::send_cmd(Cmd::Receive, (chunk.len() - 1) as u8); | ||
| 322 | |||
| 323 | for byte in chunk.iter_mut() { | ||
| 324 | // Wait until there's data in the RxFIFO | ||
| 325 | while Self::is_rx_fifo_empty() {} | ||
| 326 | |||
| 327 | *byte = T::regs().mrdr().read().data().bits(); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | if send_stop == SendStop::Yes { | ||
| 332 | Self::stop()?; | ||
| 333 | } | ||
| 334 | |||
| 335 | Ok(()) | ||
| 336 | } | ||
| 337 | |||
| 338 | fn blocking_write_internal(&mut self, address: u8, write: &[u8], send_stop: SendStop) -> Result<()> { | ||
| 339 | self.start(address, false)?; | ||
| 340 | |||
| 341 | // Usually, embassy HALs error out with an empty write, | ||
| 342 | // however empty writes are useful for writing I2C scanning | ||
| 343 | // logic through write probing. That is, we send a start with | ||
| 344 | // R/w bit cleared, but instead of writing any data, just send | ||
| 345 | // the stop onto the bus. This has the effect of checking if | ||
| 346 | // the resulting address got an ACK but causing no | ||
| 347 | // side-effects to the device on the other end. | ||
| 348 | // | ||
| 349 | // Because of this, we are not going to error out in case of | ||
| 350 | // empty writes. | ||
| 351 | #[cfg(feature = "defmt")] | ||
| 352 | if write.is_empty() { | ||
| 353 | defmt::trace!("Empty write, write probing?"); | ||
| 354 | } | ||
| 355 | |||
| 356 | for byte in write { | ||
| 357 | // Wait until we have space in the TxFIFO | ||
| 358 | while Self::is_tx_fifo_full() {} | ||
| 359 | |||
| 360 | Self::send_cmd(Cmd::Transmit, *byte); | ||
| 361 | } | ||
| 362 | |||
| 363 | if send_stop == SendStop::Yes { | ||
| 364 | Self::stop()?; | ||
| 365 | } | ||
| 366 | |||
| 367 | Ok(()) | ||
| 368 | } | ||
| 369 | |||
| 370 | // Public API: Blocking | ||
| 371 | |||
| 372 | /// Read from address into buffer blocking caller until done. | ||
| 373 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<()> { | ||
| 374 | self.blocking_read_internal(address, read, SendStop::Yes) | ||
| 375 | } | ||
| 376 | |||
| 377 | /// Write to address from buffer blocking caller until done. | ||
| 378 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<()> { | ||
| 379 | self.blocking_write_internal(address, write, SendStop::Yes) | ||
| 380 | } | ||
| 381 | |||
| 382 | /// Write to address from bytes and read from address into buffer blocking caller until done. | ||
| 383 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<()> { | ||
| 384 | self.blocking_write_internal(address, write, SendStop::No)?; | ||
| 385 | self.blocking_read_internal(address, read, SendStop::Yes) | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | impl<'d, T: Instance> I2c<'d, T, Async> { | ||
| 390 | /// Create a new async instance of the I2C Controller bus driver. | ||
| 391 | pub fn new_async( | ||
| 392 | peri: Peri<'d, T>, | ||
| 393 | scl: Peri<'d, impl SclPin<T>>, | ||
| 394 | sda: Peri<'d, impl SdaPin<T>>, | ||
| 395 | _irq: impl crate::interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 396 | config: Config, | ||
| 397 | ) -> Result<Self> { | ||
| 398 | T::Interrupt::unpend(); | ||
| 399 | |||
| 400 | // Safety: `_irq` ensures an Interrupt Handler exists. | ||
| 401 | unsafe { T::Interrupt::enable() }; | ||
| 402 | |||
| 403 | Self::new_inner(peri, scl, sda, config) | ||
| 404 | } | ||
| 405 | |||
| 406 | fn remediation() { | ||
| 407 | #[cfg(feature = "defmt")] | ||
| 408 | defmt::trace!("Future dropped, issuing stop",); | ||
| 409 | |||
| 410 | // if the FIFO is not empty, drop its contents. | ||
| 411 | if !Self::is_tx_fifo_empty() { | ||
| 412 | Self::reset_fifos(); | ||
| 413 | } | ||
| 414 | |||
| 415 | // send a stop command | ||
| 416 | let _ = Self::stop(); | ||
| 417 | } | ||
| 418 | |||
| 419 | fn enable_rx_ints(&mut self) { | ||
| 420 | T::regs().mier().write(|w| { | ||
| 421 | w.rdie() | ||
| 422 | .enabled() | ||
| 423 | .ndie() | ||
| 424 | .enabled() | ||
| 425 | .alie() | ||
| 426 | .enabled() | ||
| 427 | .feie() | ||
| 428 | .enabled() | ||
| 429 | .pltie() | ||
| 430 | .enabled() | ||
| 431 | }); | ||
| 432 | } | ||
| 433 | |||
| 434 | fn enable_tx_ints(&mut self) { | ||
| 435 | T::regs().mier().write(|w| { | ||
| 436 | w.tdie() | ||
| 437 | .enabled() | ||
| 438 | .ndie() | ||
| 439 | .enabled() | ||
| 440 | .alie() | ||
| 441 | .enabled() | ||
| 442 | .feie() | ||
| 443 | .enabled() | ||
| 444 | .pltie() | ||
| 445 | .enabled() | ||
| 446 | }); | ||
| 447 | } | ||
| 448 | |||
| 449 | async fn async_start(&mut self, address: u8, read: bool) -> Result<()> { | ||
| 450 | if address >= 0x80 { | ||
| 451 | return Err(Error::AddressOutOfRange(address)); | ||
| 452 | } | ||
| 453 | |||
| 454 | // send the start command | ||
| 455 | let addr_rw = address << 1 | if read { 1 } else { 0 }; | ||
| 456 | Self::send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw); | ||
| 457 | |||
| 458 | T::wait_cell() | ||
| 459 | .wait_for(|| { | ||
| 460 | // enable interrupts | ||
| 461 | self.enable_tx_ints(); | ||
| 462 | // if the command FIFO is empty, we're done sending start | ||
| 463 | Self::is_tx_fifo_empty() | ||
| 464 | }) | ||
| 465 | .await | ||
| 466 | .map_err(|_| Error::Other)?; | ||
| 467 | |||
| 468 | Self::status() | ||
| 469 | } | ||
| 470 | |||
| 471 | async fn async_stop(&mut self) -> Result<()> { | ||
| 472 | // send the stop command | ||
| 473 | Self::send_cmd(Cmd::Stop, 0); | ||
| 474 | |||
| 475 | T::wait_cell() | ||
| 476 | .wait_for(|| { | ||
| 477 | // enable interrupts | ||
| 478 | self.enable_tx_ints(); | ||
| 479 | // if the command FIFO is empty, we're done sending stop | ||
| 480 | Self::is_tx_fifo_empty() | ||
| 481 | }) | ||
| 482 | .await | ||
| 483 | .map_err(|_| Error::Other)?; | ||
| 484 | |||
| 485 | Self::status() | ||
| 486 | } | ||
| 487 | |||
| 488 | async fn async_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> { | ||
| 489 | if read.is_empty() { | ||
| 490 | return Err(Error::InvalidReadBufferLength); | ||
| 491 | } | ||
| 492 | |||
| 493 | // perform corrective action if the future is dropped | ||
| 494 | let on_drop = OnDrop::new(|| Self::remediation()); | ||
| 495 | |||
| 496 | for chunk in read.chunks_mut(256) { | ||
| 497 | self.async_start(address, true).await?; | ||
| 498 | |||
| 499 | // send receive command | ||
| 500 | Self::send_cmd(Cmd::Receive, (chunk.len() - 1) as u8); | ||
| 501 | |||
| 502 | T::wait_cell() | ||
| 503 | .wait_for(|| { | ||
| 504 | // enable interrupts | ||
| 505 | self.enable_tx_ints(); | ||
| 506 | // if the command FIFO is empty, we're done sending start | ||
| 507 | Self::is_tx_fifo_empty() | ||
| 508 | }) | ||
| 509 | .await | ||
| 510 | .map_err(|_| Error::Other)?; | ||
| 511 | |||
| 512 | for byte in chunk.iter_mut() { | ||
| 513 | T::wait_cell() | ||
| 514 | .wait_for(|| { | ||
| 515 | // enable interrupts | ||
| 516 | self.enable_rx_ints(); | ||
| 517 | // if the rx FIFO is not empty, we need to read a byte | ||
| 518 | !Self::is_rx_fifo_empty() | ||
| 519 | }) | ||
| 520 | .await | ||
| 521 | .map_err(|_| Error::ReadFail)?; | ||
| 522 | |||
| 523 | *byte = T::regs().mrdr().read().data().bits(); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | if send_stop == SendStop::Yes { | ||
| 528 | self.async_stop().await?; | ||
| 529 | } | ||
| 530 | |||
| 531 | // defuse it if the future is not dropped | ||
| 532 | on_drop.defuse(); | ||
| 533 | |||
| 534 | Ok(()) | ||
| 535 | } | ||
| 536 | |||
| 537 | async fn async_write_internal(&mut self, address: u8, write: &[u8], send_stop: SendStop) -> Result<()> { | ||
| 538 | self.async_start(address, false).await?; | ||
| 539 | |||
| 540 | // perform corrective action if the future is dropped | ||
| 541 | let on_drop = OnDrop::new(|| Self::remediation()); | ||
| 542 | |||
| 543 | // Usually, embassy HALs error out with an empty write, | ||
| 544 | // however empty writes are useful for writing I2C scanning | ||
| 545 | // logic through write probing. That is, we send a start with | ||
| 546 | // R/w bit cleared, but instead of writing any data, just send | ||
| 547 | // the stop onto the bus. This has the effect of checking if | ||
| 548 | // the resulting address got an ACK but causing no | ||
| 549 | // side-effects to the device on the other end. | ||
| 550 | // | ||
| 551 | // Because of this, we are not going to error out in case of | ||
| 552 | // empty writes. | ||
| 553 | #[cfg(feature = "defmt")] | ||
| 554 | if write.is_empty() { | ||
| 555 | defmt::trace!("Empty write, write probing?"); | ||
| 556 | } | ||
| 557 | |||
| 558 | for byte in write { | ||
| 559 | T::wait_cell() | ||
| 560 | .wait_for(|| { | ||
| 561 | // enable interrupts | ||
| 562 | self.enable_tx_ints(); | ||
| 563 | // initiate transmit | ||
| 564 | Self::send_cmd(Cmd::Transmit, *byte); | ||
| 565 | // if the tx FIFO is empty, we're done transmiting | ||
| 566 | Self::is_tx_fifo_empty() | ||
| 567 | }) | ||
| 568 | .await | ||
| 569 | .map_err(|_| Error::WriteFail)?; | ||
| 570 | } | ||
| 571 | |||
| 572 | if send_stop == SendStop::Yes { | ||
| 573 | self.async_stop().await?; | ||
| 574 | } | ||
| 575 | |||
| 576 | // defuse it if the future is not dropped | ||
| 577 | on_drop.defuse(); | ||
| 578 | |||
| 579 | Ok(()) | ||
| 580 | } | ||
| 581 | |||
| 582 | // Public API: Async | ||
| 583 | |||
| 584 | /// Read from address into buffer asynchronously. | ||
| 585 | pub fn async_read<'a>( | ||
| 586 | &mut self, | ||
| 587 | address: u8, | ||
| 588 | read: &'a mut [u8], | ||
| 589 | ) -> impl Future<Output = Result<()>> + use<'_, 'a, 'd, T> { | ||
| 590 | self.async_read_internal(address, read, SendStop::Yes) | ||
| 591 | } | ||
| 592 | |||
| 593 | /// Write to address from buffer asynchronously. | ||
| 594 | pub fn async_write<'a>( | ||
| 595 | &mut self, | ||
| 596 | address: u8, | ||
| 597 | write: &'a [u8], | ||
| 598 | ) -> impl Future<Output = Result<()>> + use<'_, 'a, 'd, T> { | ||
| 599 | self.async_write_internal(address, write, SendStop::Yes) | ||
| 600 | } | ||
| 601 | |||
| 602 | /// Write to address from bytes and read from address into buffer asynchronously. | ||
| 603 | pub async fn async_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<()> { | ||
| 604 | self.async_write_internal(address, write, SendStop::No).await?; | ||
| 605 | self.async_read_internal(address, read, SendStop::Yes).await | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { | ||
| 610 | type Error = Error; | ||
| 611 | |||
| 612 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<()> { | ||
| 613 | self.blocking_read(address, buffer) | ||
| 614 | } | ||
| 615 | } | ||
| 616 | |||
| 617 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> { | ||
| 618 | type Error = Error; | ||
| 619 | |||
| 620 | fn write(&mut self, address: u8, bytes: &[u8]) -> Result<()> { | ||
| 621 | self.blocking_write(address, bytes) | ||
| 622 | } | ||
| 623 | } | ||
| 624 | |||
| 625 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> { | ||
| 626 | type Error = Error; | ||
| 627 | |||
| 628 | fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<()> { | ||
| 629 | self.blocking_write_read(address, bytes, buffer) | ||
| 630 | } | ||
| 631 | } | ||
| 632 | |||
| 633 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Transactional for I2c<'d, T, M> { | ||
| 634 | type Error = Error; | ||
| 635 | |||
| 636 | fn exec(&mut self, address: u8, operations: &mut [embedded_hal_02::blocking::i2c::Operation<'_>]) -> Result<()> { | ||
| 637 | if let Some((last, rest)) = operations.split_last_mut() { | ||
| 638 | for op in rest { | ||
| 639 | match op { | ||
| 640 | embedded_hal_02::blocking::i2c::Operation::Read(buf) => { | ||
| 641 | self.blocking_read_internal(address, buf, SendStop::No)? | ||
| 642 | } | ||
| 643 | embedded_hal_02::blocking::i2c::Operation::Write(buf) => { | ||
| 644 | self.blocking_write_internal(address, buf, SendStop::No)? | ||
| 645 | } | ||
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 649 | match last { | ||
| 650 | embedded_hal_02::blocking::i2c::Operation::Read(buf) => { | ||
| 651 | self.blocking_read_internal(address, buf, SendStop::Yes) | ||
| 652 | } | ||
| 653 | embedded_hal_02::blocking::i2c::Operation::Write(buf) => { | ||
| 654 | self.blocking_write_internal(address, buf, SendStop::Yes) | ||
| 655 | } | ||
| 656 | } | ||
| 657 | } else { | ||
| 658 | Ok(()) | ||
| 659 | } | ||
| 660 | } | ||
| 661 | } | ||
| 662 | |||
| 663 | impl embedded_hal_1::i2c::Error for Error { | ||
| 664 | fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { | ||
| 665 | match *self { | ||
| 666 | Self::ArbitrationLoss => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, | ||
| 667 | Self::AddressNack => { | ||
| 668 | embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) | ||
| 669 | } | ||
| 670 | _ => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 671 | } | ||
| 672 | } | ||
| 673 | } | ||
| 674 | |||
| 675 | impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> { | ||
| 676 | type Error = Error; | ||
| 677 | } | ||
| 678 | |||
| 679 | impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> { | ||
| 680 | fn transaction(&mut self, address: u8, operations: &mut [embedded_hal_1::i2c::Operation<'_>]) -> Result<()> { | ||
| 681 | if let Some((last, rest)) = operations.split_last_mut() { | ||
| 682 | for op in rest { | ||
| 683 | match op { | ||
| 684 | embedded_hal_1::i2c::Operation::Read(buf) => { | ||
| 685 | self.blocking_read_internal(address, buf, SendStop::No)? | ||
| 686 | } | ||
| 687 | embedded_hal_1::i2c::Operation::Write(buf) => { | ||
| 688 | self.blocking_write_internal(address, buf, SendStop::No)? | ||
| 689 | } | ||
| 690 | } | ||
| 691 | } | ||
| 692 | |||
| 693 | match last { | ||
| 694 | embedded_hal_1::i2c::Operation::Read(buf) => self.blocking_read_internal(address, buf, SendStop::Yes), | ||
| 695 | embedded_hal_1::i2c::Operation::Write(buf) => self.blocking_write_internal(address, buf, SendStop::Yes), | ||
| 696 | } | ||
| 697 | } else { | ||
| 698 | Ok(()) | ||
| 699 | } | ||
| 700 | } | ||
| 701 | } | ||
| 702 | |||
| 703 | impl<'d, T: Instance> embedded_hal_async::i2c::I2c for I2c<'d, T, Async> { | ||
| 704 | async fn transaction( | ||
| 705 | &mut self, | ||
| 706 | address: u8, | ||
| 707 | operations: &mut [embedded_hal_async::i2c::Operation<'_>], | ||
| 708 | ) -> Result<()> { | ||
| 709 | if let Some((last, rest)) = operations.split_last_mut() { | ||
| 710 | for op in rest { | ||
| 711 | match op { | ||
| 712 | embedded_hal_async::i2c::Operation::Read(buf) => { | ||
| 713 | self.async_read_internal(address, buf, SendStop::No).await? | ||
| 714 | } | ||
| 715 | embedded_hal_async::i2c::Operation::Write(buf) => { | ||
| 716 | self.async_write_internal(address, buf, SendStop::No).await? | ||
| 717 | } | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | match last { | ||
| 722 | embedded_hal_async::i2c::Operation::Read(buf) => { | ||
| 723 | self.async_read_internal(address, buf, SendStop::Yes).await | ||
| 724 | } | ||
| 725 | embedded_hal_async::i2c::Operation::Write(buf) => { | ||
| 726 | self.async_write_internal(address, buf, SendStop::Yes).await | ||
| 727 | } | ||
| 728 | } | ||
| 729 | } else { | ||
| 730 | Ok(()) | ||
| 731 | } | ||
| 732 | } | ||
| 733 | } | ||
| 734 | |||
| 735 | impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> { | ||
| 736 | type Config = Config; | ||
| 737 | type ConfigError = Error; | ||
| 738 | |||
| 739 | fn set_config(&mut self, config: &Self::Config) -> Result<()> { | ||
| 740 | Self::set_config(config) | ||
| 741 | } | ||
| 742 | } | ||
diff --git a/embassy-mcxa/src/i2c/mod.rs b/embassy-mcxa/src/i2c/mod.rs new file mode 100644 index 000000000..9a014224a --- /dev/null +++ b/embassy-mcxa/src/i2c/mod.rs | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | //! I2C Support | ||
| 2 | |||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 5 | use embassy_hal_internal::PeripheralType; | ||
| 6 | use maitake_sync::WaitCell; | ||
| 7 | use paste::paste; | ||
| 8 | |||
| 9 | use crate::clocks::periph_helpers::Lpi2cConfig; | ||
| 10 | use crate::clocks::{ClockError, Gate}; | ||
| 11 | use crate::gpio::{GpioPin, SealedPin}; | ||
| 12 | use crate::{interrupt, pac}; | ||
| 13 | |||
| 14 | /// Shorthand for `Result<T>`. | ||
| 15 | pub type Result<T> = core::result::Result<T, Error>; | ||
| 16 | |||
| 17 | pub mod controller; | ||
| 18 | |||
| 19 | /// Error information type | ||
| 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 22 | pub enum Error { | ||
| 23 | /// Clock configuration error. | ||
| 24 | ClockSetup(ClockError), | ||
| 25 | /// FIFO Error | ||
| 26 | FifoError, | ||
| 27 | /// Reading for I2C failed. | ||
| 28 | ReadFail, | ||
| 29 | /// Writing to I2C failed. | ||
| 30 | WriteFail, | ||
| 31 | /// I2C address NAK condition. | ||
| 32 | AddressNack, | ||
| 33 | /// Bus level arbitration loss. | ||
| 34 | ArbitrationLoss, | ||
| 35 | /// Address out of range. | ||
| 36 | AddressOutOfRange(u8), | ||
| 37 | /// Invalid write buffer length. | ||
| 38 | InvalidWriteBufferLength, | ||
| 39 | /// Invalid read buffer length. | ||
| 40 | InvalidReadBufferLength, | ||
| 41 | /// Other internal errors or unexpected state. | ||
| 42 | Other, | ||
| 43 | } | ||
| 44 | |||
| 45 | /// I2C interrupt handler. | ||
| 46 | pub struct InterruptHandler<T: Instance> { | ||
| 47 | _phantom: PhantomData<T>, | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 51 | unsafe fn on_interrupt() { | ||
| 52 | if T::regs().mier().read().bits() != 0 { | ||
| 53 | T::regs().mier().write(|w| { | ||
| 54 | w.tdie() | ||
| 55 | .disabled() | ||
| 56 | .rdie() | ||
| 57 | .disabled() | ||
| 58 | .epie() | ||
| 59 | .disabled() | ||
| 60 | .sdie() | ||
| 61 | .disabled() | ||
| 62 | .ndie() | ||
| 63 | .disabled() | ||
| 64 | .alie() | ||
| 65 | .disabled() | ||
| 66 | .feie() | ||
| 67 | .disabled() | ||
| 68 | .pltie() | ||
| 69 | .disabled() | ||
| 70 | .dmie() | ||
| 71 | .disabled() | ||
| 72 | .stie() | ||
| 73 | .disabled() | ||
| 74 | }); | ||
| 75 | |||
| 76 | T::wait_cell().wake(); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | mod sealed { | ||
| 82 | /// Seal a trait | ||
| 83 | pub trait Sealed {} | ||
| 84 | } | ||
| 85 | |||
| 86 | impl<T: GpioPin> sealed::Sealed for T {} | ||
| 87 | |||
| 88 | trait SealedInstance { | ||
| 89 | fn regs() -> &'static pac::lpi2c0::RegisterBlock; | ||
| 90 | fn wait_cell() -> &'static WaitCell; | ||
| 91 | } | ||
| 92 | |||
| 93 | /// I2C Instance | ||
| 94 | #[allow(private_bounds)] | ||
| 95 | pub trait Instance: SealedInstance + PeripheralType + 'static + Send + Gate<MrccPeriphConfig = Lpi2cConfig> { | ||
| 96 | /// Interrupt for this I2C instance. | ||
| 97 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 98 | /// Clock instance | ||
| 99 | const CLOCK_INSTANCE: crate::clocks::periph_helpers::Lpi2cInstance; | ||
| 100 | } | ||
| 101 | |||
| 102 | macro_rules! impl_instance { | ||
| 103 | ($($n:expr),*) => { | ||
| 104 | $( | ||
| 105 | paste!{ | ||
| 106 | impl SealedInstance for crate::peripherals::[<LPI2C $n>] { | ||
| 107 | fn regs() -> &'static pac::lpi2c0::RegisterBlock { | ||
| 108 | unsafe { &*pac::[<Lpi2c $n>]::ptr() } | ||
| 109 | } | ||
| 110 | |||
| 111 | fn wait_cell() -> &'static WaitCell { | ||
| 112 | static WAIT_CELL: WaitCell = WaitCell::new(); | ||
| 113 | &WAIT_CELL | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | impl Instance for crate::peripherals::[<LPI2C $n>] { | ||
| 118 | type Interrupt = crate::interrupt::typelevel::[<LPI2C $n>]; | ||
| 119 | const CLOCK_INSTANCE: crate::clocks::periph_helpers::Lpi2cInstance | ||
| 120 | = crate::clocks::periph_helpers::Lpi2cInstance::[<Lpi2c $n>]; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | )* | ||
| 124 | }; | ||
| 125 | } | ||
| 126 | |||
| 127 | impl_instance!(0, 1, 2, 3); | ||
| 128 | |||
| 129 | /// SCL pin trait. | ||
| 130 | pub trait SclPin<Instance>: GpioPin + sealed::Sealed + PeripheralType { | ||
| 131 | fn mux(&self); | ||
| 132 | } | ||
| 133 | |||
| 134 | /// SDA pin trait. | ||
| 135 | pub trait SdaPin<Instance>: GpioPin + sealed::Sealed + PeripheralType { | ||
| 136 | fn mux(&self); | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Driver mode. | ||
| 140 | #[allow(private_bounds)] | ||
| 141 | pub trait Mode: sealed::Sealed {} | ||
| 142 | |||
| 143 | /// Blocking mode. | ||
| 144 | pub struct Blocking; | ||
| 145 | impl sealed::Sealed for Blocking {} | ||
| 146 | impl Mode for Blocking {} | ||
| 147 | |||
| 148 | /// Async mode. | ||
| 149 | pub struct Async; | ||
| 150 | impl sealed::Sealed for Async {} | ||
| 151 | impl Mode for Async {} | ||
| 152 | |||
| 153 | macro_rules! impl_pin { | ||
| 154 | ($pin:ident, $peri:ident, $fn:ident, $trait:ident) => { | ||
| 155 | impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin { | ||
| 156 | fn mux(&self) { | ||
| 157 | self.set_pull(crate::gpio::Pull::Disabled); | ||
| 158 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | ||
| 159 | self.set_drive_strength(crate::gpio::DriveStrength::Double.into()); | ||
| 160 | self.set_function(crate::pac::port0::pcr0::Mux::$fn); | ||
| 161 | self.set_enable_input_buffer(); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | }; | ||
| 165 | } | ||
| 166 | |||
| 167 | impl_pin!(P0_16, LPI2C0, Mux2, SdaPin); | ||
| 168 | impl_pin!(P0_17, LPI2C0, Mux2, SclPin); | ||
| 169 | impl_pin!(P0_18, LPI2C0, Mux2, SclPin); | ||
| 170 | impl_pin!(P0_19, LPI2C0, Mux2, SdaPin); | ||
| 171 | impl_pin!(P1_0, LPI2C1, Mux3, SdaPin); | ||
| 172 | impl_pin!(P1_1, LPI2C1, Mux3, SclPin); | ||
| 173 | impl_pin!(P1_2, LPI2C1, Mux3, SdaPin); | ||
| 174 | impl_pin!(P1_3, LPI2C1, Mux3, SclPin); | ||
| 175 | impl_pin!(P1_8, LPI2C2, Mux3, SdaPin); | ||
| 176 | impl_pin!(P1_9, LPI2C2, Mux3, SclPin); | ||
| 177 | impl_pin!(P1_10, LPI2C2, Mux3, SdaPin); | ||
| 178 | impl_pin!(P1_11, LPI2C2, Mux3, SclPin); | ||
| 179 | impl_pin!(P1_12, LPI2C1, Mux2, SdaPin); | ||
| 180 | impl_pin!(P1_13, LPI2C1, Mux2, SclPin); | ||
| 181 | impl_pin!(P1_14, LPI2C1, Mux2, SclPin); | ||
| 182 | impl_pin!(P1_15, LPI2C1, Mux2, SdaPin); | ||
| 183 | impl_pin!(P1_30, LPI2C0, Mux3, SdaPin); | ||
| 184 | impl_pin!(P1_31, LPI2C0, Mux3, SclPin); | ||
| 185 | impl_pin!(P3_27, LPI2C3, Mux2, SclPin); | ||
| 186 | impl_pin!(P3_28, LPI2C3, Mux2, SdaPin); | ||
| 187 | // impl_pin!(P3_29, LPI2C3, Mux2, HreqPin); What is this HREQ pin? | ||
| 188 | impl_pin!(P3_30, LPI2C3, Mux2, SclPin); | ||
| 189 | impl_pin!(P3_31, LPI2C3, Mux2, SdaPin); | ||
| 190 | impl_pin!(P4_2, LPI2C2, Mux2, SdaPin); | ||
| 191 | impl_pin!(P4_3, LPI2C0, Mux2, SclPin); | ||
| 192 | impl_pin!(P4_4, LPI2C2, Mux2, SdaPin); | ||
| 193 | impl_pin!(P4_5, LPI2C0, Mux2, SclPin); | ||
| 194 | // impl_pin!(P4_6, LPI2C0, Mux2, HreqPin); What is this HREQ pin? | ||
diff --git a/embassy-mcxa/src/interrupt.rs b/embassy-mcxa/src/interrupt.rs new file mode 100644 index 000000000..1d10e3b2d --- /dev/null +++ b/embassy-mcxa/src/interrupt.rs | |||
| @@ -0,0 +1,563 @@ | |||
| 1 | //! Minimal interrupt helpers mirroring embassy-imxrt style for OS_EVENT and LPUART2. | ||
| 2 | //! Type-level interrupt traits and bindings are provided by the | ||
| 3 | //! `embassy_hal_internal::interrupt_mod!` macro via the generated module below. | ||
| 4 | |||
| 5 | // TODO(AJM): As of 2025-11-13, we need to do a pass to ensure safety docs | ||
| 6 | // are complete prior to release. | ||
| 7 | #![allow(clippy::missing_safety_doc)] | ||
| 8 | |||
| 9 | mod generated { | ||
| 10 | #[rustfmt::skip] | ||
| 11 | embassy_hal_internal::interrupt_mod!( | ||
| 12 | ADC1, | ||
| 13 | GPIO0, | ||
| 14 | GPIO1, | ||
| 15 | GPIO2, | ||
| 16 | GPIO3, | ||
| 17 | GPIO4, | ||
| 18 | LPI2C0, | ||
| 19 | LPI2C1, | ||
| 20 | LPI2C2, | ||
| 21 | LPI2C3, | ||
| 22 | LPUART0, | ||
| 23 | LPUART1, | ||
| 24 | LPUART2, | ||
| 25 | LPUART3, | ||
| 26 | LPUART4, | ||
| 27 | LPUART5, | ||
| 28 | OS_EVENT, | ||
| 29 | RTC, | ||
| 30 | ); | ||
| 31 | } | ||
| 32 | |||
| 33 | use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; | ||
| 34 | |||
| 35 | pub use generated::interrupt::{typelevel, Priority}; | ||
| 36 | |||
| 37 | use crate::pac::Interrupt; | ||
| 38 | |||
| 39 | /// Trait for configuring and controlling interrupts. | ||
| 40 | /// | ||
| 41 | /// This trait provides a consistent interface for interrupt management across | ||
| 42 | /// different interrupt sources, similar to embassy-imxrt's InterruptExt. | ||
| 43 | pub trait InterruptExt { | ||
| 44 | /// Clear any pending interrupt in NVIC. | ||
| 45 | fn unpend(&self); | ||
| 46 | |||
| 47 | /// Set NVIC priority for this interrupt. | ||
| 48 | fn set_priority(&self, priority: Priority); | ||
| 49 | |||
| 50 | /// Enable this interrupt in NVIC. | ||
| 51 | /// | ||
| 52 | /// # Safety | ||
| 53 | /// This function is unsafe because it can enable interrupts that may not be | ||
| 54 | /// properly configured, potentially leading to undefined behavior. | ||
| 55 | unsafe fn enable(&self); | ||
| 56 | |||
| 57 | /// Disable this interrupt in NVIC. | ||
| 58 | /// | ||
| 59 | /// # Safety | ||
| 60 | /// This function is unsafe because disabling interrupts may leave the system | ||
| 61 | /// in an inconsistent state if the interrupt was expected to fire. | ||
| 62 | unsafe fn disable(&self); | ||
| 63 | |||
| 64 | /// Check if the interrupt is pending in NVIC. | ||
| 65 | fn is_pending(&self) -> bool; | ||
| 66 | } | ||
| 67 | |||
| 68 | #[derive(Clone, Copy, Debug, Default)] | ||
| 69 | pub struct DefaultHandlerSnapshot { | ||
| 70 | pub vector: u16, | ||
| 71 | pub count: u32, | ||
| 72 | pub cfsr: u32, | ||
| 73 | pub hfsr: u32, | ||
| 74 | pub stacked_pc: u32, | ||
| 75 | pub stacked_lr: u32, | ||
| 76 | pub stacked_sp: u32, | ||
| 77 | } | ||
| 78 | |||
| 79 | static LAST_DEFAULT_VECTOR: AtomicU16 = AtomicU16::new(0); | ||
| 80 | static LAST_DEFAULT_COUNT: AtomicU32 = AtomicU32::new(0); | ||
| 81 | static LAST_DEFAULT_CFSR: AtomicU32 = AtomicU32::new(0); | ||
| 82 | static LAST_DEFAULT_HFSR: AtomicU32 = AtomicU32::new(0); | ||
| 83 | static LAST_DEFAULT_PC: AtomicU32 = AtomicU32::new(0); | ||
| 84 | static LAST_DEFAULT_LR: AtomicU32 = AtomicU32::new(0); | ||
| 85 | static LAST_DEFAULT_SP: AtomicU32 = AtomicU32::new(0); | ||
| 86 | |||
| 87 | #[inline] | ||
| 88 | pub fn default_handler_snapshot() -> DefaultHandlerSnapshot { | ||
| 89 | DefaultHandlerSnapshot { | ||
| 90 | vector: LAST_DEFAULT_VECTOR.load(Ordering::Relaxed), | ||
| 91 | count: LAST_DEFAULT_COUNT.load(Ordering::Relaxed), | ||
| 92 | cfsr: LAST_DEFAULT_CFSR.load(Ordering::Relaxed), | ||
| 93 | hfsr: LAST_DEFAULT_HFSR.load(Ordering::Relaxed), | ||
| 94 | stacked_pc: LAST_DEFAULT_PC.load(Ordering::Relaxed), | ||
| 95 | stacked_lr: LAST_DEFAULT_LR.load(Ordering::Relaxed), | ||
| 96 | stacked_sp: LAST_DEFAULT_SP.load(Ordering::Relaxed), | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | #[inline] | ||
| 101 | pub fn clear_default_handler_snapshot() { | ||
| 102 | LAST_DEFAULT_VECTOR.store(0, Ordering::Relaxed); | ||
| 103 | LAST_DEFAULT_COUNT.store(0, Ordering::Relaxed); | ||
| 104 | LAST_DEFAULT_CFSR.store(0, Ordering::Relaxed); | ||
| 105 | LAST_DEFAULT_HFSR.store(0, Ordering::Relaxed); | ||
| 106 | LAST_DEFAULT_PC.store(0, Ordering::Relaxed); | ||
| 107 | LAST_DEFAULT_LR.store(0, Ordering::Relaxed); | ||
| 108 | LAST_DEFAULT_SP.store(0, Ordering::Relaxed); | ||
| 109 | } | ||
| 110 | |||
| 111 | /// OS_EVENT interrupt helper with methods similar to embassy-imxrt's InterruptExt. | ||
| 112 | pub struct OsEvent; | ||
| 113 | pub const OS_EVENT: OsEvent = OsEvent; | ||
| 114 | |||
| 115 | impl InterruptExt for OsEvent { | ||
| 116 | /// Clear any pending OS_EVENT in NVIC. | ||
| 117 | #[inline] | ||
| 118 | fn unpend(&self) { | ||
| 119 | cortex_m::peripheral::NVIC::unpend(Interrupt::OS_EVENT); | ||
| 120 | } | ||
| 121 | |||
| 122 | /// Set NVIC priority for OS_EVENT. | ||
| 123 | #[inline] | ||
| 124 | fn set_priority(&self, priority: Priority) { | ||
| 125 | unsafe { | ||
| 126 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 127 | nvic.set_priority(Interrupt::OS_EVENT, u8::from(priority)); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | /// Enable OS_EVENT in NVIC. | ||
| 132 | #[inline] | ||
| 133 | unsafe fn enable(&self) { | ||
| 134 | cortex_m::peripheral::NVIC::unmask(Interrupt::OS_EVENT); | ||
| 135 | } | ||
| 136 | |||
| 137 | /// Disable OS_EVENT in NVIC. | ||
| 138 | #[inline] | ||
| 139 | unsafe fn disable(&self) { | ||
| 140 | cortex_m::peripheral::NVIC::mask(Interrupt::OS_EVENT); | ||
| 141 | } | ||
| 142 | |||
| 143 | /// Check if OS_EVENT is pending in NVIC. | ||
| 144 | #[inline] | ||
| 145 | fn is_pending(&self) -> bool { | ||
| 146 | cortex_m::peripheral::NVIC::is_pending(Interrupt::OS_EVENT) | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | impl OsEvent { | ||
| 151 | /// Configure OS_EVENT interrupt for timer operation. | ||
| 152 | /// This sets up the NVIC priority, enables the interrupt, and ensures global interrupts are enabled. | ||
| 153 | /// Also performs a software event to wake any pending WFE. | ||
| 154 | pub fn configure_for_timer(&self, priority: Priority) { | ||
| 155 | // Configure NVIC | ||
| 156 | self.unpend(); | ||
| 157 | self.set_priority(priority); | ||
| 158 | unsafe { | ||
| 159 | self.enable(); | ||
| 160 | } | ||
| 161 | |||
| 162 | // Ensure global interrupts are enabled in no-reset scenarios (e.g., cargo run) | ||
| 163 | // Debuggers typically perform a reset which leaves PRIMASK=0; cargo run may not. | ||
| 164 | unsafe { | ||
| 165 | cortex_m::interrupt::enable(); | ||
| 166 | } | ||
| 167 | |||
| 168 | // Wake any executor WFE that might be sleeping when we armed the first deadline | ||
| 169 | cortex_m::asm::sev(); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | /// LPUART2 interrupt helper with methods similar to embassy-imxrt's InterruptExt. | ||
| 174 | pub struct Lpuart2; | ||
| 175 | pub const LPUART2: Lpuart2 = Lpuart2; | ||
| 176 | |||
| 177 | impl InterruptExt for Lpuart2 { | ||
| 178 | /// Clear any pending LPUART2 in NVIC. | ||
| 179 | #[inline] | ||
| 180 | fn unpend(&self) { | ||
| 181 | cortex_m::peripheral::NVIC::unpend(Interrupt::LPUART2); | ||
| 182 | } | ||
| 183 | |||
| 184 | /// Set NVIC priority for LPUART2. | ||
| 185 | #[inline] | ||
| 186 | fn set_priority(&self, priority: Priority) { | ||
| 187 | unsafe { | ||
| 188 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 189 | nvic.set_priority(Interrupt::LPUART2, u8::from(priority)); | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Enable LPUART2 in NVIC. | ||
| 194 | #[inline] | ||
| 195 | unsafe fn enable(&self) { | ||
| 196 | cortex_m::peripheral::NVIC::unmask(Interrupt::LPUART2); | ||
| 197 | } | ||
| 198 | |||
| 199 | /// Disable LPUART2 in NVIC. | ||
| 200 | #[inline] | ||
| 201 | unsafe fn disable(&self) { | ||
| 202 | cortex_m::peripheral::NVIC::mask(Interrupt::LPUART2); | ||
| 203 | } | ||
| 204 | |||
| 205 | /// Check if LPUART2 is pending in NVIC. | ||
| 206 | #[inline] | ||
| 207 | fn is_pending(&self) -> bool { | ||
| 208 | cortex_m::peripheral::NVIC::is_pending(Interrupt::LPUART2) | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | impl Lpuart2 { | ||
| 213 | /// Configure LPUART2 interrupt for UART operation. | ||
| 214 | /// This sets up the NVIC priority, enables the interrupt, and ensures global interrupts are enabled. | ||
| 215 | pub fn configure_for_uart(&self, priority: Priority) { | ||
| 216 | // Configure NVIC | ||
| 217 | self.unpend(); | ||
| 218 | self.set_priority(priority); | ||
| 219 | unsafe { | ||
| 220 | self.enable(); | ||
| 221 | } | ||
| 222 | |||
| 223 | // Ensure global interrupts are enabled in no-reset scenarios (e.g., cargo run) | ||
| 224 | // Debuggers typically perform a reset which leaves PRIMASK=0; cargo run may not. | ||
| 225 | unsafe { | ||
| 226 | cortex_m::interrupt::enable(); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | /// Install LPUART2 handler into the RAM vector table. | ||
| 231 | /// Safety: See `install_irq_handler`. | ||
| 232 | pub unsafe fn install_handler(&self, handler: unsafe extern "C" fn()) { | ||
| 233 | install_irq_handler(Interrupt::LPUART2, handler); | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | pub struct Rtc; | ||
| 238 | pub const RTC: Rtc = Rtc; | ||
| 239 | |||
| 240 | impl InterruptExt for Rtc { | ||
| 241 | /// Clear any pending RTC in NVIC. | ||
| 242 | #[inline] | ||
| 243 | fn unpend(&self) { | ||
| 244 | cortex_m::peripheral::NVIC::unpend(Interrupt::RTC); | ||
| 245 | } | ||
| 246 | |||
| 247 | /// Set NVIC priority for RTC. | ||
| 248 | #[inline] | ||
| 249 | fn set_priority(&self, priority: Priority) { | ||
| 250 | unsafe { | ||
| 251 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 252 | nvic.set_priority(Interrupt::RTC, u8::from(priority)); | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | /// Enable RTC in NVIC. | ||
| 257 | #[inline] | ||
| 258 | unsafe fn enable(&self) { | ||
| 259 | cortex_m::peripheral::NVIC::unmask(Interrupt::RTC); | ||
| 260 | } | ||
| 261 | |||
| 262 | /// Disable RTC in NVIC. | ||
| 263 | #[inline] | ||
| 264 | unsafe fn disable(&self) { | ||
| 265 | cortex_m::peripheral::NVIC::mask(Interrupt::RTC); | ||
| 266 | } | ||
| 267 | |||
| 268 | /// Check if RTC is pending in NVIC. | ||
| 269 | #[inline] | ||
| 270 | fn is_pending(&self) -> bool { | ||
| 271 | cortex_m::peripheral::NVIC::is_pending(Interrupt::RTC) | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | pub struct Adc; | ||
| 276 | pub const ADC1: Adc = Adc; | ||
| 277 | |||
| 278 | impl InterruptExt for Adc { | ||
| 279 | /// Clear any pending ADC1 in NVIC. | ||
| 280 | #[inline] | ||
| 281 | fn unpend(&self) { | ||
| 282 | cortex_m::peripheral::NVIC::unpend(Interrupt::ADC1); | ||
| 283 | } | ||
| 284 | |||
| 285 | /// Set NVIC priority for ADC1. | ||
| 286 | #[inline] | ||
| 287 | fn set_priority(&self, priority: Priority) { | ||
| 288 | unsafe { | ||
| 289 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 290 | nvic.set_priority(Interrupt::ADC1, u8::from(priority)); | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Enable ADC1 in NVIC. | ||
| 295 | #[inline] | ||
| 296 | unsafe fn enable(&self) { | ||
| 297 | cortex_m::peripheral::NVIC::unmask(Interrupt::ADC1); | ||
| 298 | } | ||
| 299 | |||
| 300 | /// Disable ADC1 in NVIC. | ||
| 301 | #[inline] | ||
| 302 | unsafe fn disable(&self) { | ||
| 303 | cortex_m::peripheral::NVIC::mask(Interrupt::ADC1); | ||
| 304 | } | ||
| 305 | |||
| 306 | /// Check if ADC1 is pending in NVIC. | ||
| 307 | #[inline] | ||
| 308 | fn is_pending(&self) -> bool { | ||
| 309 | cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC1) | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | pub struct Gpio0; | ||
| 314 | pub const GPIO0: Gpio0 = Gpio0; | ||
| 315 | |||
| 316 | impl InterruptExt for Gpio0 { | ||
| 317 | /// Clear any pending GPIO0 in NVIC. | ||
| 318 | #[inline] | ||
| 319 | fn unpend(&self) { | ||
| 320 | cortex_m::peripheral::NVIC::unpend(Interrupt::GPIO0); | ||
| 321 | } | ||
| 322 | |||
| 323 | /// Set NVIC priority for GPIO0. | ||
| 324 | #[inline] | ||
| 325 | fn set_priority(&self, priority: Priority) { | ||
| 326 | unsafe { | ||
| 327 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 328 | nvic.set_priority(Interrupt::GPIO0, u8::from(priority)); | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | /// Enable GPIO0 in NVIC. | ||
| 333 | #[inline] | ||
| 334 | unsafe fn enable(&self) { | ||
| 335 | cortex_m::peripheral::NVIC::unmask(Interrupt::GPIO0); | ||
| 336 | } | ||
| 337 | |||
| 338 | /// Disable GPIO0 in NVIC. | ||
| 339 | #[inline] | ||
| 340 | unsafe fn disable(&self) { | ||
| 341 | cortex_m::peripheral::NVIC::mask(Interrupt::GPIO0); | ||
| 342 | } | ||
| 343 | |||
| 344 | /// Check if GPIO0 is pending in NVIC. | ||
| 345 | #[inline] | ||
| 346 | fn is_pending(&self) -> bool { | ||
| 347 | cortex_m::peripheral::NVIC::is_pending(Interrupt::GPIO0) | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | pub struct Gpio1; | ||
| 352 | pub const GPIO1: Gpio1 = Gpio1; | ||
| 353 | |||
| 354 | impl InterruptExt for Gpio1 { | ||
| 355 | /// Clear any pending GPIO1 in NVIC. | ||
| 356 | #[inline] | ||
| 357 | fn unpend(&self) { | ||
| 358 | cortex_m::peripheral::NVIC::unpend(Interrupt::GPIO1); | ||
| 359 | } | ||
| 360 | |||
| 361 | /// Set NVIC priority for GPIO1. | ||
| 362 | #[inline] | ||
| 363 | fn set_priority(&self, priority: Priority) { | ||
| 364 | unsafe { | ||
| 365 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 366 | nvic.set_priority(Interrupt::GPIO1, u8::from(priority)); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | /// Enable GPIO1 in NVIC. | ||
| 371 | #[inline] | ||
| 372 | unsafe fn enable(&self) { | ||
| 373 | cortex_m::peripheral::NVIC::unmask(Interrupt::GPIO1); | ||
| 374 | } | ||
| 375 | |||
| 376 | /// Disable GPIO1 in NVIC. | ||
| 377 | #[inline] | ||
| 378 | unsafe fn disable(&self) { | ||
| 379 | cortex_m::peripheral::NVIC::mask(Interrupt::GPIO1); | ||
| 380 | } | ||
| 381 | |||
| 382 | /// Check if GPIO1 is pending in NVIC. | ||
| 383 | #[inline] | ||
| 384 | fn is_pending(&self) -> bool { | ||
| 385 | cortex_m::peripheral::NVIC::is_pending(Interrupt::GPIO1) | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | pub struct Gpio2; | ||
| 390 | pub const GPIO2: Gpio2 = Gpio2; | ||
| 391 | |||
| 392 | impl InterruptExt for Gpio2 { | ||
| 393 | /// Clear any pending GPIO2 in NVIC. | ||
| 394 | #[inline] | ||
| 395 | fn unpend(&self) { | ||
| 396 | cortex_m::peripheral::NVIC::unpend(Interrupt::GPIO2); | ||
| 397 | } | ||
| 398 | |||
| 399 | /// Set NVIC priority for GPIO2. | ||
| 400 | #[inline] | ||
| 401 | fn set_priority(&self, priority: Priority) { | ||
| 402 | unsafe { | ||
| 403 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 404 | nvic.set_priority(Interrupt::GPIO2, u8::from(priority)); | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 408 | /// Enable GPIO2 in NVIC. | ||
| 409 | #[inline] | ||
| 410 | unsafe fn enable(&self) { | ||
| 411 | cortex_m::peripheral::NVIC::unmask(Interrupt::GPIO2); | ||
| 412 | } | ||
| 413 | |||
| 414 | /// Disable GPIO2 in NVIC. | ||
| 415 | #[inline] | ||
| 416 | unsafe fn disable(&self) { | ||
| 417 | cortex_m::peripheral::NVIC::mask(Interrupt::GPIO2); | ||
| 418 | } | ||
| 419 | |||
| 420 | /// Check if GPIO2 is pending in NVIC. | ||
| 421 | #[inline] | ||
| 422 | fn is_pending(&self) -> bool { | ||
| 423 | cortex_m::peripheral::NVIC::is_pending(Interrupt::GPIO2) | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | pub struct Gpio3; | ||
| 428 | pub const GPIO3: Gpio3 = Gpio3; | ||
| 429 | |||
| 430 | impl InterruptExt for Gpio3 { | ||
| 431 | /// Clear any pending GPIO3 in NVIC. | ||
| 432 | #[inline] | ||
| 433 | fn unpend(&self) { | ||
| 434 | cortex_m::peripheral::NVIC::unpend(Interrupt::GPIO3); | ||
| 435 | } | ||
| 436 | |||
| 437 | /// Set NVIC priority for GPIO3. | ||
| 438 | #[inline] | ||
| 439 | fn set_priority(&self, priority: Priority) { | ||
| 440 | unsafe { | ||
| 441 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 442 | nvic.set_priority(Interrupt::GPIO3, u8::from(priority)); | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | /// Enable GPIO3 in NVIC. | ||
| 447 | #[inline] | ||
| 448 | unsafe fn enable(&self) { | ||
| 449 | cortex_m::peripheral::NVIC::unmask(Interrupt::GPIO3); | ||
| 450 | } | ||
| 451 | |||
| 452 | /// Disable GPIO3 in NVIC. | ||
| 453 | #[inline] | ||
| 454 | unsafe fn disable(&self) { | ||
| 455 | cortex_m::peripheral::NVIC::mask(Interrupt::GPIO3); | ||
| 456 | } | ||
| 457 | |||
| 458 | /// Check if GPIO3 is pending in NVIC. | ||
| 459 | #[inline] | ||
| 460 | fn is_pending(&self) -> bool { | ||
| 461 | cortex_m::peripheral::NVIC::is_pending(Interrupt::GPIO3) | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | pub struct Gpio4; | ||
| 466 | pub const GPIO4: Gpio4 = Gpio4; | ||
| 467 | |||
| 468 | impl InterruptExt for Gpio4 { | ||
| 469 | /// Clear any pending GPIO4 in NVIC. | ||
| 470 | #[inline] | ||
| 471 | fn unpend(&self) { | ||
| 472 | cortex_m::peripheral::NVIC::unpend(Interrupt::GPIO4); | ||
| 473 | } | ||
| 474 | |||
| 475 | /// Set NVIC priority for GPIO4. | ||
| 476 | #[inline] | ||
| 477 | fn set_priority(&self, priority: Priority) { | ||
| 478 | unsafe { | ||
| 479 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 480 | nvic.set_priority(Interrupt::GPIO4, u8::from(priority)); | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | /// Enable GPIO4 in NVIC. | ||
| 485 | #[inline] | ||
| 486 | unsafe fn enable(&self) { | ||
| 487 | cortex_m::peripheral::NVIC::unmask(Interrupt::GPIO4); | ||
| 488 | } | ||
| 489 | |||
| 490 | /// Disable GPIO4 in NVIC. | ||
| 491 | #[inline] | ||
| 492 | unsafe fn disable(&self) { | ||
| 493 | cortex_m::peripheral::NVIC::mask(Interrupt::GPIO4); | ||
| 494 | } | ||
| 495 | |||
| 496 | /// Check if GPIO4 is pending in NVIC. | ||
| 497 | #[inline] | ||
| 498 | fn is_pending(&self) -> bool { | ||
| 499 | cortex_m::peripheral::NVIC::is_pending(Interrupt::GPIO4) | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | /// Set VTOR (Vector Table Offset) to a RAM-based vector table. | ||
| 504 | /// Pass a pointer to the first word in the RAM table (stack pointer slot 0). | ||
| 505 | /// Safety: Caller must ensure the RAM table is valid and aligned as required by the core. | ||
| 506 | pub unsafe fn vtor_set_ram_vector_base(base: *const u32) { | ||
| 507 | core::ptr::write_volatile(0xE000_ED08 as *mut u32, base as u32); | ||
| 508 | } | ||
| 509 | |||
| 510 | /// Install an interrupt handler into the current VTOR-based vector table. | ||
| 511 | /// This writes the function pointer at index 16 + irq number. | ||
| 512 | /// Safety: Caller must ensure VTOR points at a writable RAM table and that `handler` | ||
| 513 | /// has the correct ABI and lifetime. | ||
| 514 | pub unsafe fn install_irq_handler(irq: Interrupt, handler: unsafe extern "C" fn()) { | ||
| 515 | let vtor_base = core::ptr::read_volatile(0xE000_ED08 as *const u32) as *mut u32; | ||
| 516 | let idx = 16 + (irq as isize as usize); | ||
| 517 | core::ptr::write_volatile(vtor_base.add(idx), handler as usize as u32); | ||
| 518 | } | ||
| 519 | |||
| 520 | impl OsEvent { | ||
| 521 | /// Convenience to install the OS_EVENT handler into the RAM vector table. | ||
| 522 | /// Safety: See `install_irq_handler`. | ||
| 523 | pub unsafe fn install_handler(&self, handler: extern "C" fn()) { | ||
| 524 | install_irq_handler(Interrupt::OS_EVENT, handler); | ||
| 525 | } | ||
| 526 | } | ||
| 527 | |||
| 528 | /// Install OS_EVENT handler by raw address. Useful to avoid fn pointer type mismatches. | ||
| 529 | /// Safety: Caller must ensure the address is a valid `extern "C" fn()` handler. | ||
| 530 | pub unsafe fn os_event_install_handler_raw(handler_addr: usize) { | ||
| 531 | let vtor_base = core::ptr::read_volatile(0xE000_ED08 as *const u32) as *mut u32; | ||
| 532 | let idx = 16 + (Interrupt::OS_EVENT as isize as usize); | ||
| 533 | core::ptr::write_volatile(vtor_base.add(idx), handler_addr as u32); | ||
| 534 | } | ||
| 535 | |||
| 536 | /// Provide a conservative default IRQ handler that avoids wedging the system. | ||
| 537 | /// It clears all NVIC pending bits and returns, so spurious or reserved IRQs | ||
| 538 | /// don’t trap the core in an infinite WFI loop during bring-up. | ||
| 539 | #[no_mangle] | ||
| 540 | pub unsafe extern "C" fn DefaultHandler() { | ||
| 541 | let active = core::ptr::read_volatile(0xE000_ED04 as *const u32) & 0x1FF; | ||
| 542 | let cfsr = core::ptr::read_volatile(0xE000_ED28 as *const u32); | ||
| 543 | let hfsr = core::ptr::read_volatile(0xE000_ED2C as *const u32); | ||
| 544 | |||
| 545 | let sp = cortex_m::register::msp::read(); | ||
| 546 | let stacked = sp as *const u32; | ||
| 547 | // Stacked registers follow ARMv8-M procedure call standard order | ||
| 548 | let stacked_pc = unsafe { stacked.add(6).read() }; | ||
| 549 | let stacked_lr = unsafe { stacked.add(5).read() }; | ||
| 550 | |||
| 551 | LAST_DEFAULT_VECTOR.store(active as u16, Ordering::Relaxed); | ||
| 552 | LAST_DEFAULT_CFSR.store(cfsr, Ordering::Relaxed); | ||
| 553 | LAST_DEFAULT_HFSR.store(hfsr, Ordering::Relaxed); | ||
| 554 | LAST_DEFAULT_COUNT.fetch_add(1, Ordering::Relaxed); | ||
| 555 | LAST_DEFAULT_PC.store(stacked_pc, Ordering::Relaxed); | ||
| 556 | LAST_DEFAULT_LR.store(stacked_lr, Ordering::Relaxed); | ||
| 557 | LAST_DEFAULT_SP.store(sp, Ordering::Relaxed); | ||
| 558 | |||
| 559 | // Do nothing here: on some MCUs/TrustZone setups, writing NVIC from a spurious | ||
| 560 | // handler can fault if targeting the Secure bank. Just return. | ||
| 561 | cortex_m::asm::dsb(); | ||
| 562 | cortex_m::asm::isb(); | ||
| 563 | } | ||
diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs new file mode 100644 index 000000000..c6d8adc8f --- /dev/null +++ b/embassy-mcxa/src/lib.rs | |||
| @@ -0,0 +1,471 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![allow(async_fn_in_trait)] | ||
| 3 | #![doc = include_str!("../README.md")] | ||
| 4 | |||
| 5 | // //! ## Feature flags | ||
| 6 | // #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] | ||
| 7 | |||
| 8 | pub mod clocks; // still provide clock helpers | ||
| 9 | pub mod gpio; | ||
| 10 | pub mod pins; // pin mux helpers | ||
| 11 | |||
| 12 | pub mod adc; | ||
| 13 | pub mod clkout; | ||
| 14 | pub mod config; | ||
| 15 | pub mod i2c; | ||
| 16 | pub mod interrupt; | ||
| 17 | pub mod lpuart; | ||
| 18 | pub mod ostimer; | ||
| 19 | pub mod rtc; | ||
| 20 | |||
| 21 | pub use crate::pac::NVIC_PRIO_BITS; | ||
| 22 | |||
| 23 | #[rustfmt::skip] | ||
| 24 | embassy_hal_internal::peripherals!( | ||
| 25 | ADC0, | ||
| 26 | ADC1, | ||
| 27 | |||
| 28 | AOI0, | ||
| 29 | AOI1, | ||
| 30 | |||
| 31 | CAN0, | ||
| 32 | CAN1, | ||
| 33 | |||
| 34 | CDOG0, | ||
| 35 | CDOG1, | ||
| 36 | |||
| 37 | // CLKOUT is not specifically a peripheral (it's part of SYSCON), | ||
| 38 | // but we still want it to be a singleton. | ||
| 39 | CLKOUT, | ||
| 40 | |||
| 41 | CMC, | ||
| 42 | CMP0, | ||
| 43 | CMP1, | ||
| 44 | CRC0, | ||
| 45 | |||
| 46 | CTIMER0, | ||
| 47 | CTIMER1, | ||
| 48 | CTIMER2, | ||
| 49 | CTIMER3, | ||
| 50 | CTIMER4, | ||
| 51 | |||
| 52 | DBGMAILBOX, | ||
| 53 | DMA0, | ||
| 54 | EDMA0_TCD0, | ||
| 55 | EIM0, | ||
| 56 | EQDC0, | ||
| 57 | EQDC1, | ||
| 58 | ERM0, | ||
| 59 | FLEXIO0, | ||
| 60 | FLEXPWM0, | ||
| 61 | FLEXPWM1, | ||
| 62 | FMC0, | ||
| 63 | FMU0, | ||
| 64 | FREQME0, | ||
| 65 | GLIKEY0, | ||
| 66 | |||
| 67 | GPIO0, | ||
| 68 | GPIO1, | ||
| 69 | GPIO2, | ||
| 70 | GPIO3, | ||
| 71 | GPIO4, | ||
| 72 | |||
| 73 | I3C0, | ||
| 74 | INPUTMUX0, | ||
| 75 | |||
| 76 | LPI2C0, | ||
| 77 | LPI2C1, | ||
| 78 | LPI2C2, | ||
| 79 | LPI2C3, | ||
| 80 | |||
| 81 | LPSPI0, | ||
| 82 | LPSPI1, | ||
| 83 | |||
| 84 | LPTMR0, | ||
| 85 | |||
| 86 | LPUART0, | ||
| 87 | LPUART1, | ||
| 88 | LPUART2, | ||
| 89 | LPUART3, | ||
| 90 | LPUART4, | ||
| 91 | LPUART5, | ||
| 92 | |||
| 93 | MAU0, | ||
| 94 | MBC0, | ||
| 95 | MRCC0, | ||
| 96 | OPAMP0, | ||
| 97 | |||
| 98 | #[cfg(not(feature = "time"))] | ||
| 99 | OSTIMER0, | ||
| 100 | |||
| 101 | P0_0, | ||
| 102 | P0_1, | ||
| 103 | P0_2, | ||
| 104 | P0_3, | ||
| 105 | P0_4, | ||
| 106 | P0_5, | ||
| 107 | P0_6, | ||
| 108 | P0_7, | ||
| 109 | P0_8, | ||
| 110 | P0_9, | ||
| 111 | P0_10, | ||
| 112 | P0_11, | ||
| 113 | P0_12, | ||
| 114 | P0_13, | ||
| 115 | P0_14, | ||
| 116 | P0_15, | ||
| 117 | P0_16, | ||
| 118 | P0_17, | ||
| 119 | P0_18, | ||
| 120 | P0_19, | ||
| 121 | P0_20, | ||
| 122 | P0_21, | ||
| 123 | P0_22, | ||
| 124 | P0_23, | ||
| 125 | P0_24, | ||
| 126 | P0_25, | ||
| 127 | P0_26, | ||
| 128 | P0_27, | ||
| 129 | P0_28, | ||
| 130 | P0_29, | ||
| 131 | P0_30, | ||
| 132 | P0_31, | ||
| 133 | |||
| 134 | P1_0, | ||
| 135 | P1_1, | ||
| 136 | P1_2, | ||
| 137 | P1_3, | ||
| 138 | P1_4, | ||
| 139 | P1_5, | ||
| 140 | P1_6, | ||
| 141 | P1_7, | ||
| 142 | P1_8, | ||
| 143 | P1_9, | ||
| 144 | P1_10, | ||
| 145 | P1_11, | ||
| 146 | P1_12, | ||
| 147 | P1_13, | ||
| 148 | P1_14, | ||
| 149 | P1_15, | ||
| 150 | P1_16, | ||
| 151 | P1_17, | ||
| 152 | P1_18, | ||
| 153 | P1_19, | ||
| 154 | P1_20, | ||
| 155 | P1_21, | ||
| 156 | P1_22, | ||
| 157 | P1_23, | ||
| 158 | P1_24, | ||
| 159 | P1_25, | ||
| 160 | P1_26, | ||
| 161 | P1_27, | ||
| 162 | P1_28, | ||
| 163 | P1_29, | ||
| 164 | P1_30, | ||
| 165 | P1_31, | ||
| 166 | |||
| 167 | P2_0, | ||
| 168 | P2_1, | ||
| 169 | P2_2, | ||
| 170 | P2_3, | ||
| 171 | P2_4, | ||
| 172 | P2_5, | ||
| 173 | P2_6, | ||
| 174 | P2_7, | ||
| 175 | P2_8, | ||
| 176 | P2_9, | ||
| 177 | P2_10, | ||
| 178 | P2_11, | ||
| 179 | P2_12, | ||
| 180 | P2_13, | ||
| 181 | P2_14, | ||
| 182 | P2_15, | ||
| 183 | P2_16, | ||
| 184 | P2_17, | ||
| 185 | P2_18, | ||
| 186 | P2_19, | ||
| 187 | P2_20, | ||
| 188 | P2_21, | ||
| 189 | P2_22, | ||
| 190 | P2_23, | ||
| 191 | P2_24, | ||
| 192 | P2_25, | ||
| 193 | P2_26, | ||
| 194 | P2_27, | ||
| 195 | P2_28, | ||
| 196 | P2_29, | ||
| 197 | P2_30, | ||
| 198 | P2_31, | ||
| 199 | |||
| 200 | P3_0, | ||
| 201 | P3_1, | ||
| 202 | P3_2, | ||
| 203 | P3_3, | ||
| 204 | P3_4, | ||
| 205 | P3_5, | ||
| 206 | P3_6, | ||
| 207 | P3_7, | ||
| 208 | P3_8, | ||
| 209 | P3_9, | ||
| 210 | P3_10, | ||
| 211 | P3_11, | ||
| 212 | P3_12, | ||
| 213 | P3_13, | ||
| 214 | P3_14, | ||
| 215 | P3_15, | ||
| 216 | P3_16, | ||
| 217 | P3_17, | ||
| 218 | P3_18, | ||
| 219 | P3_19, | ||
| 220 | P3_20, | ||
| 221 | P3_21, | ||
| 222 | P3_22, | ||
| 223 | P3_23, | ||
| 224 | P3_24, | ||
| 225 | P3_25, | ||
| 226 | P3_26, | ||
| 227 | P3_27, | ||
| 228 | P3_28, | ||
| 229 | P3_29, | ||
| 230 | P3_30, | ||
| 231 | P3_31, | ||
| 232 | |||
| 233 | P4_0, | ||
| 234 | P4_1, | ||
| 235 | P4_2, | ||
| 236 | P4_3, | ||
| 237 | P4_4, | ||
| 238 | P4_5, | ||
| 239 | P4_6, | ||
| 240 | P4_7, | ||
| 241 | P4_8, | ||
| 242 | P4_9, | ||
| 243 | P4_10, | ||
| 244 | P4_11, | ||
| 245 | P4_12, | ||
| 246 | P4_13, | ||
| 247 | P4_14, | ||
| 248 | P4_15, | ||
| 249 | P4_16, | ||
| 250 | P4_17, | ||
| 251 | P4_18, | ||
| 252 | P4_19, | ||
| 253 | P4_20, | ||
| 254 | P4_21, | ||
| 255 | P4_22, | ||
| 256 | P4_23, | ||
| 257 | P4_24, | ||
| 258 | P4_25, | ||
| 259 | P4_26, | ||
| 260 | P4_27, | ||
| 261 | P4_28, | ||
| 262 | P4_29, | ||
| 263 | P4_30, | ||
| 264 | P4_31, | ||
| 265 | |||
| 266 | P5_0, | ||
| 267 | P5_1, | ||
| 268 | P5_2, | ||
| 269 | P5_3, | ||
| 270 | P5_4, | ||
| 271 | P5_5, | ||
| 272 | P5_6, | ||
| 273 | P5_7, | ||
| 274 | P5_8, | ||
| 275 | P5_9, | ||
| 276 | P5_10, | ||
| 277 | P5_11, | ||
| 278 | P5_12, | ||
| 279 | P5_13, | ||
| 280 | P5_14, | ||
| 281 | P5_15, | ||
| 282 | P5_16, | ||
| 283 | P5_17, | ||
| 284 | P5_18, | ||
| 285 | P5_19, | ||
| 286 | P5_20, | ||
| 287 | P5_21, | ||
| 288 | P5_22, | ||
| 289 | P5_23, | ||
| 290 | P5_24, | ||
| 291 | P5_25, | ||
| 292 | P5_26, | ||
| 293 | P5_27, | ||
| 294 | P5_28, | ||
| 295 | P5_29, | ||
| 296 | P5_30, | ||
| 297 | P5_31, | ||
| 298 | |||
| 299 | PKC0, | ||
| 300 | |||
| 301 | PORT0, | ||
| 302 | PORT1, | ||
| 303 | PORT2, | ||
| 304 | PORT3, | ||
| 305 | PORT4, | ||
| 306 | |||
| 307 | RTC0, | ||
| 308 | SAU, | ||
| 309 | SCG0, | ||
| 310 | SCN_SCB, | ||
| 311 | SGI0, | ||
| 312 | SMARTDMA0, | ||
| 313 | SPC0, | ||
| 314 | SYSCON, | ||
| 315 | TDET0, | ||
| 316 | TRNG0, | ||
| 317 | UDF0, | ||
| 318 | USB0, | ||
| 319 | UTICK0, | ||
| 320 | VBAT0, | ||
| 321 | WAKETIMER0, | ||
| 322 | WUU0, | ||
| 323 | WWDT0, | ||
| 324 | ); | ||
| 325 | |||
| 326 | // Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. | ||
| 327 | |||
| 328 | // Re-export interrupt traits and types | ||
| 329 | pub use adc::Adc1 as Adc1Token; | ||
| 330 | pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output}; | ||
| 331 | pub use interrupt::InterruptExt; | ||
| 332 | #[cfg(feature = "unstable-pac")] | ||
| 333 | pub use mcxa_pac as pac; | ||
| 334 | #[cfg(not(feature = "unstable-pac"))] | ||
| 335 | pub(crate) use mcxa_pac as pac; | ||
| 336 | |||
| 337 | /// Initialize HAL with configuration (mirrors embassy-imxrt style). Minimal: just take peripherals. | ||
| 338 | /// Also applies configurable NVIC priority for the OSTIMER OS_EVENT interrupt (no enabling). | ||
| 339 | pub fn init(cfg: crate::config::Config) -> Peripherals { | ||
| 340 | let peripherals = Peripherals::take(); | ||
| 341 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 342 | #[cfg(feature = "time")] | ||
| 343 | crate::interrupt::OS_EVENT.set_priority(cfg.time_interrupt_priority); | ||
| 344 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 345 | crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); | ||
| 346 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 347 | crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority); | ||
| 348 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 349 | crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); | ||
| 350 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 351 | crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); | ||
| 352 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 353 | crate::interrupt::GPIO2.set_priority(cfg.gpio_interrupt_priority); | ||
| 354 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 355 | crate::interrupt::GPIO3.set_priority(cfg.gpio_interrupt_priority); | ||
| 356 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 357 | crate::interrupt::GPIO4.set_priority(cfg.gpio_interrupt_priority); | ||
| 358 | |||
| 359 | // Configure clocks | ||
| 360 | crate::clocks::init(cfg.clock_cfg).unwrap(); | ||
| 361 | |||
| 362 | unsafe { | ||
| 363 | crate::gpio::init(); | ||
| 364 | } | ||
| 365 | |||
| 366 | // Initialize embassy-time global driver backed by OSTIMER0 | ||
| 367 | #[cfg(feature = "time")] | ||
| 368 | crate::ostimer::time_driver::init(crate::config::Config::default().time_interrupt_priority, 1_000_000); | ||
| 369 | |||
| 370 | // Enable GPIO clocks | ||
| 371 | unsafe { | ||
| 372 | _ = crate::clocks::enable_and_reset::<crate::peripherals::PORT0>(&crate::clocks::periph_helpers::NoConfig); | ||
| 373 | _ = crate::clocks::enable_and_reset::<crate::peripherals::GPIO0>(&crate::clocks::periph_helpers::NoConfig); | ||
| 374 | |||
| 375 | _ = crate::clocks::enable_and_reset::<crate::peripherals::PORT1>(&crate::clocks::periph_helpers::NoConfig); | ||
| 376 | _ = crate::clocks::enable_and_reset::<crate::peripherals::GPIO1>(&crate::clocks::periph_helpers::NoConfig); | ||
| 377 | |||
| 378 | _ = crate::clocks::enable_and_reset::<crate::peripherals::PORT2>(&crate::clocks::periph_helpers::NoConfig); | ||
| 379 | _ = crate::clocks::enable_and_reset::<crate::peripherals::GPIO2>(&crate::clocks::periph_helpers::NoConfig); | ||
| 380 | |||
| 381 | _ = crate::clocks::enable_and_reset::<crate::peripherals::PORT3>(&crate::clocks::periph_helpers::NoConfig); | ||
| 382 | _ = crate::clocks::enable_and_reset::<crate::peripherals::GPIO3>(&crate::clocks::periph_helpers::NoConfig); | ||
| 383 | |||
| 384 | _ = crate::clocks::enable_and_reset::<crate::peripherals::PORT4>(&crate::clocks::periph_helpers::NoConfig); | ||
| 385 | _ = crate::clocks::enable_and_reset::<crate::peripherals::GPIO4>(&crate::clocks::periph_helpers::NoConfig); | ||
| 386 | } | ||
| 387 | |||
| 388 | peripherals | ||
| 389 | } | ||
| 390 | |||
| 391 | // /// Optional hook called by cortex-m-rt before RAM init. | ||
| 392 | // /// We proactively mask and clear all NVIC IRQs to avoid wedges from stale state | ||
| 393 | // /// left by soft resets/debug sessions. | ||
| 394 | // /// | ||
| 395 | // /// NOTE: Manual VTOR setup is required for RAM execution. The cortex-m-rt 'set-vtor' | ||
| 396 | // /// feature is incompatible with our setup because it expects __vector_table to be | ||
| 397 | // /// defined differently than how our RAM-based linker script arranges it. | ||
| 398 | // #[no_mangle] | ||
| 399 | // pub unsafe extern "C" fn __pre_init() { | ||
| 400 | // // Set the VTOR to point to the interrupt vector table in RAM | ||
| 401 | // // This is required since code runs from RAM on this MCU | ||
| 402 | // crate::interrupt::vtor_set_ram_vector_base(0x2000_0000 as *const u32); | ||
| 403 | |||
| 404 | // // Mask and clear pending for all NVIC lines (0..127) to avoid stale state across runs. | ||
| 405 | // let nvic = &*cortex_m::peripheral::NVIC::PTR; | ||
| 406 | // for i in 0..4 { | ||
| 407 | // // 4 words x 32 = 128 IRQs | ||
| 408 | // nvic.icer[i].write(0xFFFF_FFFF); | ||
| 409 | // nvic.icpr[i].write(0xFFFF_FFFF); | ||
| 410 | // } | ||
| 411 | // // Do NOT touch peripheral registers here: clocks may be off and accesses can fault. | ||
| 412 | // crate::interrupt::clear_default_handler_snapshot(); | ||
| 413 | // } | ||
| 414 | |||
| 415 | /// Internal helper to dispatch a type-level interrupt handler. | ||
| 416 | #[inline(always)] | ||
| 417 | #[doc(hidden)] | ||
| 418 | pub unsafe fn __handle_interrupt<T, H>() | ||
| 419 | where | ||
| 420 | T: crate::interrupt::typelevel::Interrupt, | ||
| 421 | H: crate::interrupt::typelevel::Handler<T>, | ||
| 422 | { | ||
| 423 | H::on_interrupt(); | ||
| 424 | } | ||
| 425 | |||
| 426 | /// Macro to bind interrupts to handlers, similar to embassy-imxrt. | ||
| 427 | /// | ||
| 428 | /// Example: | ||
| 429 | /// - Bind OS_EVENT to the OSTIMER time-driver handler | ||
| 430 | /// bind_interrupts!(struct Irqs { OS_EVENT => crate::ostimer::time_driver::OsEventHandler; }); | ||
| 431 | #[macro_export] | ||
| 432 | macro_rules! bind_interrupts { | ||
| 433 | ($(#[$attr:meta])* $vis:vis struct $name:ident { | ||
| 434 | $( | ||
| 435 | $(#[cfg($cond_irq:meta)])? | ||
| 436 | $irq:ident => $( | ||
| 437 | $(#[cfg($cond_handler:meta)])? | ||
| 438 | $handler:ty | ||
| 439 | ),*; | ||
| 440 | )* | ||
| 441 | }) => { | ||
| 442 | #[derive(Copy, Clone)] | ||
| 443 | $(#[$attr])* | ||
| 444 | $vis struct $name; | ||
| 445 | |||
| 446 | $( | ||
| 447 | #[allow(non_snake_case)] | ||
| 448 | #[no_mangle] | ||
| 449 | $(#[cfg($cond_irq)])? | ||
| 450 | unsafe extern "C" fn $irq() { | ||
| 451 | unsafe { | ||
| 452 | $( | ||
| 453 | $(#[cfg($cond_handler)])? | ||
| 454 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); | ||
| 455 | )* | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | $(#[cfg($cond_irq)])? | ||
| 460 | $crate::bind_interrupts!(@inner | ||
| 461 | $( | ||
| 462 | $(#[cfg($cond_handler)])? | ||
| 463 | unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} | ||
| 464 | )* | ||
| 465 | ); | ||
| 466 | )* | ||
| 467 | }; | ||
| 468 | (@inner $($t:tt)*) => { | ||
| 469 | $($t)* | ||
| 470 | } | ||
| 471 | } | ||
diff --git a/embassy-mcxa/src/lpuart/buffered.rs b/embassy-mcxa/src/lpuart/buffered.rs new file mode 100644 index 000000000..8eb443ca7 --- /dev/null +++ b/embassy-mcxa/src/lpuart/buffered.rs | |||
| @@ -0,0 +1,780 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; | ||
| 7 | use embassy_hal_internal::Peri; | ||
| 8 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | |||
| 10 | use super::*; | ||
| 11 | use crate::interrupt; | ||
| 12 | |||
| 13 | // ============================================================================ | ||
| 14 | // STATIC STATE MANAGEMENT | ||
| 15 | // ============================================================================ | ||
| 16 | |||
| 17 | /// State for buffered LPUART operations | ||
| 18 | pub struct State { | ||
| 19 | tx_waker: AtomicWaker, | ||
| 20 | tx_buf: RingBuffer, | ||
| 21 | tx_done: AtomicBool, | ||
| 22 | rx_waker: AtomicWaker, | ||
| 23 | rx_buf: RingBuffer, | ||
| 24 | initialized: AtomicBool, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl Default for State { | ||
| 28 | fn default() -> Self { | ||
| 29 | Self::new() | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | impl State { | ||
| 34 | /// Create a new state instance | ||
| 35 | pub const fn new() -> Self { | ||
| 36 | Self { | ||
| 37 | tx_waker: AtomicWaker::new(), | ||
| 38 | tx_buf: RingBuffer::new(), | ||
| 39 | tx_done: AtomicBool::new(true), | ||
| 40 | rx_waker: AtomicWaker::new(), | ||
| 41 | rx_buf: RingBuffer::new(), | ||
| 42 | initialized: AtomicBool::new(false), | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | // ============================================================================ | ||
| 47 | // BUFFERED DRIVER STRUCTURES | ||
| 48 | // ============================================================================ | ||
| 49 | |||
| 50 | /// Buffered LPUART driver | ||
| 51 | pub struct BufferedLpuart<'a> { | ||
| 52 | tx: BufferedLpuartTx<'a>, | ||
| 53 | rx: BufferedLpuartRx<'a>, | ||
| 54 | } | ||
| 55 | |||
| 56 | /// Buffered LPUART TX driver | ||
| 57 | pub struct BufferedLpuartTx<'a> { | ||
| 58 | info: Info, | ||
| 59 | state: &'static State, | ||
| 60 | _tx_pin: Peri<'a, AnyPin>, | ||
| 61 | _cts_pin: Option<Peri<'a, AnyPin>>, | ||
| 62 | } | ||
| 63 | |||
| 64 | /// Buffered LPUART RX driver | ||
| 65 | pub struct BufferedLpuartRx<'a> { | ||
| 66 | info: Info, | ||
| 67 | state: &'static State, | ||
| 68 | _rx_pin: Peri<'a, AnyPin>, | ||
| 69 | _rts_pin: Option<Peri<'a, AnyPin>>, | ||
| 70 | } | ||
| 71 | |||
| 72 | // ============================================================================ | ||
| 73 | // BUFFERED LPUART IMPLEMENTATION | ||
| 74 | // ============================================================================ | ||
| 75 | |||
| 76 | impl<'a> BufferedLpuart<'a> { | ||
| 77 | /// Common initialization logic | ||
| 78 | fn init_common<T: Instance>( | ||
| 79 | _inner: &Peri<'a, T>, | ||
| 80 | tx_buffer: Option<&'a mut [u8]>, | ||
| 81 | rx_buffer: Option<&'a mut [u8]>, | ||
| 82 | config: &Config, | ||
| 83 | enable_tx: bool, | ||
| 84 | enable_rx: bool, | ||
| 85 | enable_rts: bool, | ||
| 86 | enable_cts: bool, | ||
| 87 | ) -> Result<&'static State> { | ||
| 88 | let state = T::buffered_state(); | ||
| 89 | |||
| 90 | if state.initialized.load(Ordering::Relaxed) { | ||
| 91 | return Err(Error::InvalidArgument); | ||
| 92 | } | ||
| 93 | |||
| 94 | // Initialize buffers | ||
| 95 | if let Some(tx_buffer) = tx_buffer { | ||
| 96 | if tx_buffer.is_empty() { | ||
| 97 | return Err(Error::InvalidArgument); | ||
| 98 | } | ||
| 99 | unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), tx_buffer.len()) }; | ||
| 100 | } | ||
| 101 | |||
| 102 | if let Some(rx_buffer) = rx_buffer { | ||
| 103 | if rx_buffer.is_empty() { | ||
| 104 | return Err(Error::InvalidArgument); | ||
| 105 | } | ||
| 106 | unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_buffer.len()) }; | ||
| 107 | } | ||
| 108 | |||
| 109 | state.initialized.store(true, Ordering::Relaxed); | ||
| 110 | |||
| 111 | // Enable clocks and initialize hardware | ||
| 112 | let conf = LpuartConfig { | ||
| 113 | power: config.power, | ||
| 114 | source: config.source, | ||
| 115 | div: config.div, | ||
| 116 | instance: T::CLOCK_INSTANCE, | ||
| 117 | }; | ||
| 118 | let clock_freq = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? }; | ||
| 119 | |||
| 120 | Self::init_hardware( | ||
| 121 | T::info().regs, | ||
| 122 | *config, | ||
| 123 | clock_freq, | ||
| 124 | enable_tx, | ||
| 125 | enable_rx, | ||
| 126 | enable_rts, | ||
| 127 | enable_cts, | ||
| 128 | )?; | ||
| 129 | |||
| 130 | Ok(state) | ||
| 131 | } | ||
| 132 | |||
| 133 | /// Helper for full-duplex initialization | ||
| 134 | fn new_inner<T: Instance>( | ||
| 135 | inner: Peri<'a, T>, | ||
| 136 | tx_pin: Peri<'a, AnyPin>, | ||
| 137 | rx_pin: Peri<'a, AnyPin>, | ||
| 138 | rts_pin: Option<Peri<'a, AnyPin>>, | ||
| 139 | cts_pin: Option<Peri<'a, AnyPin>>, | ||
| 140 | tx_buffer: &'a mut [u8], | ||
| 141 | rx_buffer: &'a mut [u8], | ||
| 142 | config: Config, | ||
| 143 | ) -> Result<(BufferedLpuartTx<'a>, BufferedLpuartRx<'a>)> { | ||
| 144 | let state = Self::init_common::<T>( | ||
| 145 | &inner, | ||
| 146 | Some(tx_buffer), | ||
| 147 | Some(rx_buffer), | ||
| 148 | &config, | ||
| 149 | true, | ||
| 150 | true, | ||
| 151 | rts_pin.is_some(), | ||
| 152 | cts_pin.is_some(), | ||
| 153 | )?; | ||
| 154 | |||
| 155 | let tx = BufferedLpuartTx { | ||
| 156 | info: T::info(), | ||
| 157 | state, | ||
| 158 | _tx_pin: tx_pin, | ||
| 159 | _cts_pin: cts_pin, | ||
| 160 | }; | ||
| 161 | |||
| 162 | let rx = BufferedLpuartRx { | ||
| 163 | info: T::info(), | ||
| 164 | state, | ||
| 165 | _rx_pin: rx_pin, | ||
| 166 | _rts_pin: rts_pin, | ||
| 167 | }; | ||
| 168 | |||
| 169 | Ok((tx, rx)) | ||
| 170 | } | ||
| 171 | |||
| 172 | /// Common hardware initialization logic | ||
| 173 | fn init_hardware( | ||
| 174 | regs: &'static mcxa_pac::lpuart0::RegisterBlock, | ||
| 175 | config: Config, | ||
| 176 | clock_freq: u32, | ||
| 177 | enable_tx: bool, | ||
| 178 | enable_rx: bool, | ||
| 179 | enable_rts: bool, | ||
| 180 | enable_cts: bool, | ||
| 181 | ) -> Result<()> { | ||
| 182 | // Perform standard initialization | ||
| 183 | perform_software_reset(regs); | ||
| 184 | disable_transceiver(regs); | ||
| 185 | configure_baudrate(regs, config.baudrate_bps, clock_freq)?; | ||
| 186 | configure_frame_format(regs, &config); | ||
| 187 | configure_control_settings(regs, &config); | ||
| 188 | configure_fifo(regs, &config); | ||
| 189 | clear_all_status_flags(regs); | ||
| 190 | configure_flow_control(regs, enable_rts, enable_cts, &config); | ||
| 191 | configure_bit_order(regs, config.msb_first); | ||
| 192 | |||
| 193 | // Enable interrupts for buffered operation | ||
| 194 | cortex_m::interrupt::free(|_| { | ||
| 195 | regs.ctrl().modify(|_, w| { | ||
| 196 | w.rie() | ||
| 197 | .enabled() // RX interrupt | ||
| 198 | .orie() | ||
| 199 | .enabled() // Overrun interrupt | ||
| 200 | .peie() | ||
| 201 | .enabled() // Parity error interrupt | ||
| 202 | .feie() | ||
| 203 | .enabled() // Framing error interrupt | ||
| 204 | .neie() | ||
| 205 | .enabled() // Noise error interrupt | ||
| 206 | }); | ||
| 207 | }); | ||
| 208 | |||
| 209 | // Enable the transceiver | ||
| 210 | enable_transceiver(regs, enable_rx, enable_tx); | ||
| 211 | |||
| 212 | Ok(()) | ||
| 213 | } | ||
| 214 | |||
| 215 | /// Create a new full duplex buffered LPUART | ||
| 216 | pub fn new<T: Instance>( | ||
| 217 | inner: Peri<'a, T>, | ||
| 218 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 219 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 220 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, BufferedInterruptHandler<T>> + 'a, | ||
| 221 | tx_buffer: &'a mut [u8], | ||
| 222 | rx_buffer: &'a mut [u8], | ||
| 223 | config: Config, | ||
| 224 | ) -> Result<Self> { | ||
| 225 | tx_pin.as_tx(); | ||
| 226 | rx_pin.as_rx(); | ||
| 227 | |||
| 228 | let (tx, rx) = Self::new_inner::<T>( | ||
| 229 | inner, | ||
| 230 | tx_pin.into(), | ||
| 231 | rx_pin.into(), | ||
| 232 | None, | ||
| 233 | None, | ||
| 234 | tx_buffer, | ||
| 235 | rx_buffer, | ||
| 236 | config, | ||
| 237 | )?; | ||
| 238 | |||
| 239 | Ok(Self { tx, rx }) | ||
| 240 | } | ||
| 241 | |||
| 242 | /// Create a new buffered LPUART instance with RTS/CTS flow control | ||
| 243 | pub fn new_with_rtscts<T: Instance>( | ||
| 244 | inner: Peri<'a, T>, | ||
| 245 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 246 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 247 | rts_pin: Peri<'a, impl RtsPin<T>>, | ||
| 248 | cts_pin: Peri<'a, impl CtsPin<T>>, | ||
| 249 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, BufferedInterruptHandler<T>> + 'a, | ||
| 250 | tx_buffer: &'a mut [u8], | ||
| 251 | rx_buffer: &'a mut [u8], | ||
| 252 | config: Config, | ||
| 253 | ) -> Result<Self> { | ||
| 254 | tx_pin.as_tx(); | ||
| 255 | rx_pin.as_rx(); | ||
| 256 | rts_pin.as_rts(); | ||
| 257 | cts_pin.as_cts(); | ||
| 258 | |||
| 259 | let (tx, rx) = Self::new_inner::<T>( | ||
| 260 | inner, | ||
| 261 | tx_pin.into(), | ||
| 262 | rx_pin.into(), | ||
| 263 | Some(rts_pin.into()), | ||
| 264 | Some(cts_pin.into()), | ||
| 265 | tx_buffer, | ||
| 266 | rx_buffer, | ||
| 267 | config, | ||
| 268 | )?; | ||
| 269 | |||
| 270 | Ok(Self { tx, rx }) | ||
| 271 | } | ||
| 272 | |||
| 273 | /// Create a new buffered LPUART with only RTS flow control (RX flow control) | ||
| 274 | pub fn new_with_rts<T: Instance>( | ||
| 275 | inner: Peri<'a, T>, | ||
| 276 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 277 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 278 | rts_pin: Peri<'a, impl RtsPin<T>>, | ||
| 279 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, BufferedInterruptHandler<T>> + 'a, | ||
| 280 | tx_buffer: &'a mut [u8], | ||
| 281 | rx_buffer: &'a mut [u8], | ||
| 282 | config: Config, | ||
| 283 | ) -> Result<Self> { | ||
| 284 | tx_pin.as_tx(); | ||
| 285 | rx_pin.as_rx(); | ||
| 286 | rts_pin.as_rts(); | ||
| 287 | |||
| 288 | let (tx, rx) = Self::new_inner::<T>( | ||
| 289 | inner, | ||
| 290 | tx_pin.into(), | ||
| 291 | rx_pin.into(), | ||
| 292 | Some(rts_pin.into()), | ||
| 293 | None, | ||
| 294 | tx_buffer, | ||
| 295 | rx_buffer, | ||
| 296 | config, | ||
| 297 | )?; | ||
| 298 | |||
| 299 | Ok(Self { tx, rx }) | ||
| 300 | } | ||
| 301 | |||
| 302 | /// Create a new buffered LPUART with only CTS flow control (TX flow control) | ||
| 303 | pub fn new_with_cts<T: Instance>( | ||
| 304 | inner: Peri<'a, T>, | ||
| 305 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 306 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 307 | cts_pin: Peri<'a, impl CtsPin<T>>, | ||
| 308 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, BufferedInterruptHandler<T>> + 'a, | ||
| 309 | tx_buffer: &'a mut [u8], | ||
| 310 | rx_buffer: &'a mut [u8], | ||
| 311 | config: Config, | ||
| 312 | ) -> Result<Self> { | ||
| 313 | tx_pin.as_tx(); | ||
| 314 | rx_pin.as_rx(); | ||
| 315 | cts_pin.as_cts(); | ||
| 316 | |||
| 317 | let (tx, rx) = Self::new_inner::<T>( | ||
| 318 | inner, | ||
| 319 | tx_pin.into(), | ||
| 320 | rx_pin.into(), | ||
| 321 | None, | ||
| 322 | Some(cts_pin.into()), | ||
| 323 | tx_buffer, | ||
| 324 | rx_buffer, | ||
| 325 | config, | ||
| 326 | )?; | ||
| 327 | |||
| 328 | Ok(Self { tx, rx }) | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Split the buffered LPUART into separate TX and RX parts | ||
| 332 | pub fn split(self) -> (BufferedLpuartTx<'a>, BufferedLpuartRx<'a>) { | ||
| 333 | (self.tx, self.rx) | ||
| 334 | } | ||
| 335 | |||
| 336 | /// Get mutable references to TX and RX parts | ||
| 337 | pub fn split_ref(&mut self) -> (&mut BufferedLpuartTx<'a>, &mut BufferedLpuartRx<'a>) { | ||
| 338 | (&mut self.tx, &mut self.rx) | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | // ============================================================================ | ||
| 343 | // BUFFERED TX IMPLEMENTATION | ||
| 344 | // ============================================================================ | ||
| 345 | |||
| 346 | impl<'a> BufferedLpuartTx<'a> { | ||
| 347 | /// Helper for TX-only initialization | ||
| 348 | fn new_inner<T: Instance>( | ||
| 349 | inner: Peri<'a, T>, | ||
| 350 | tx_pin: Peri<'a, AnyPin>, | ||
| 351 | cts_pin: Option<Peri<'a, AnyPin>>, | ||
| 352 | tx_buffer: &'a mut [u8], | ||
| 353 | config: Config, | ||
| 354 | ) -> Result<BufferedLpuartTx<'a>> { | ||
| 355 | let state = BufferedLpuart::init_common::<T>( | ||
| 356 | &inner, | ||
| 357 | Some(tx_buffer), | ||
| 358 | None, | ||
| 359 | &config, | ||
| 360 | true, | ||
| 361 | false, | ||
| 362 | false, | ||
| 363 | cts_pin.is_some(), | ||
| 364 | )?; | ||
| 365 | |||
| 366 | Ok(BufferedLpuartTx { | ||
| 367 | info: T::info(), | ||
| 368 | state, | ||
| 369 | _tx_pin: tx_pin, | ||
| 370 | _cts_pin: cts_pin, | ||
| 371 | }) | ||
| 372 | } | ||
| 373 | |||
| 374 | pub fn new<T: Instance>( | ||
| 375 | inner: Peri<'a, T>, | ||
| 376 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 377 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, BufferedInterruptHandler<T>> + 'a, | ||
| 378 | tx_buffer: &'a mut [u8], | ||
| 379 | config: Config, | ||
| 380 | ) -> Result<Self> { | ||
| 381 | tx_pin.as_tx(); | ||
| 382 | |||
| 383 | Self::new_inner::<T>(inner, tx_pin.into(), None, tx_buffer, config) | ||
| 384 | } | ||
| 385 | |||
| 386 | /// Create a new TX-only buffered LPUART with CTS flow control | ||
| 387 | pub fn new_with_cts<T: Instance>( | ||
| 388 | inner: Peri<'a, T>, | ||
| 389 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 390 | cts_pin: Peri<'a, impl CtsPin<T>>, | ||
| 391 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, BufferedInterruptHandler<T>> + 'a, | ||
| 392 | tx_buffer: &'a mut [u8], | ||
| 393 | config: Config, | ||
| 394 | ) -> Result<Self> { | ||
| 395 | tx_pin.as_tx(); | ||
| 396 | cts_pin.as_cts(); | ||
| 397 | |||
| 398 | Self::new_inner::<T>(inner, tx_pin.into(), Some(cts_pin.into()), tx_buffer, config) | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | impl<'a> BufferedLpuartTx<'a> { | ||
| 403 | /// Write data asynchronously | ||
| 404 | pub async fn write(&mut self, buf: &[u8]) -> Result<usize> { | ||
| 405 | let mut written = 0; | ||
| 406 | |||
| 407 | for &byte in buf { | ||
| 408 | // Wait for space in the buffer | ||
| 409 | poll_fn(|cx| { | ||
| 410 | self.state.tx_waker.register(cx.waker()); | ||
| 411 | |||
| 412 | let mut writer = unsafe { self.state.tx_buf.writer() }; | ||
| 413 | if writer.push_one(byte) { | ||
| 414 | // Enable TX interrupt to start transmission | ||
| 415 | cortex_m::interrupt::free(|_| { | ||
| 416 | self.info.regs.ctrl().modify(|_, w| w.tie().enabled()); | ||
| 417 | }); | ||
| 418 | Poll::Ready(Ok(())) | ||
| 419 | } else { | ||
| 420 | Poll::Pending | ||
| 421 | } | ||
| 422 | }) | ||
| 423 | .await?; | ||
| 424 | |||
| 425 | written += 1; | ||
| 426 | } | ||
| 427 | |||
| 428 | Ok(written) | ||
| 429 | } | ||
| 430 | |||
| 431 | /// Flush the TX buffer and wait for transmission to complete | ||
| 432 | pub async fn flush(&mut self) -> Result<()> { | ||
| 433 | // Wait for TX buffer to empty and transmission to complete | ||
| 434 | poll_fn(|cx| { | ||
| 435 | self.state.tx_waker.register(cx.waker()); | ||
| 436 | |||
| 437 | let tx_empty = self.state.tx_buf.is_empty(); | ||
| 438 | let fifo_empty = self.info.regs.water().read().txcount().bits() == 0; | ||
| 439 | let tc_complete = self.info.regs.stat().read().tc().is_complete(); | ||
| 440 | |||
| 441 | if tx_empty && fifo_empty && tc_complete { | ||
| 442 | Poll::Ready(Ok(())) | ||
| 443 | } else { | ||
| 444 | // Enable appropriate interrupt | ||
| 445 | cortex_m::interrupt::free(|_| { | ||
| 446 | if !tx_empty { | ||
| 447 | self.info.regs.ctrl().modify(|_, w| w.tie().enabled()); | ||
| 448 | } else { | ||
| 449 | self.info.regs.ctrl().modify(|_, w| w.tcie().enabled()); | ||
| 450 | } | ||
| 451 | }); | ||
| 452 | Poll::Pending | ||
| 453 | } | ||
| 454 | }) | ||
| 455 | .await | ||
| 456 | } | ||
| 457 | |||
| 458 | /// Try to write without blocking | ||
| 459 | pub fn try_write(&mut self, buf: &[u8]) -> Result<usize> { | ||
| 460 | let mut writer = unsafe { self.state.tx_buf.writer() }; | ||
| 461 | let mut written = 0; | ||
| 462 | |||
| 463 | for &byte in buf { | ||
| 464 | if writer.push_one(byte) { | ||
| 465 | written += 1; | ||
| 466 | } else { | ||
| 467 | break; | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 471 | if written > 0 { | ||
| 472 | // Enable TX interrupt to start transmission | ||
| 473 | cortex_m::interrupt::free(|_| { | ||
| 474 | self.info.regs.ctrl().modify(|_, w| w.tie().enabled()); | ||
| 475 | }); | ||
| 476 | } | ||
| 477 | |||
| 478 | Ok(written) | ||
| 479 | } | ||
| 480 | } | ||
| 481 | |||
| 482 | // ============================================================================ | ||
| 483 | // BUFFERED RX IMPLEMENTATION | ||
| 484 | // ============================================================================ | ||
| 485 | |||
| 486 | impl<'a> BufferedLpuartRx<'a> { | ||
| 487 | /// Helper for RX-only initialization | ||
| 488 | fn new_inner<T: Instance>( | ||
| 489 | inner: Peri<'a, T>, | ||
| 490 | rx_pin: Peri<'a, AnyPin>, | ||
| 491 | rts_pin: Option<Peri<'a, AnyPin>>, | ||
| 492 | rx_buffer: &'a mut [u8], | ||
| 493 | config: Config, | ||
| 494 | ) -> Result<BufferedLpuartRx<'a>> { | ||
| 495 | let state = BufferedLpuart::init_common::<T>( | ||
| 496 | &inner, | ||
| 497 | None, | ||
| 498 | Some(rx_buffer), | ||
| 499 | &config, | ||
| 500 | false, | ||
| 501 | true, | ||
| 502 | rts_pin.is_some(), | ||
| 503 | false, | ||
| 504 | )?; | ||
| 505 | |||
| 506 | Ok(BufferedLpuartRx { | ||
| 507 | info: T::info(), | ||
| 508 | state, | ||
| 509 | _rx_pin: rx_pin, | ||
| 510 | _rts_pin: rts_pin, | ||
| 511 | }) | ||
| 512 | } | ||
| 513 | |||
| 514 | /// Create a new RX-only buffered LPUART | ||
| 515 | pub fn new<T: Instance>( | ||
| 516 | inner: Peri<'a, T>, | ||
| 517 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 518 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, BufferedInterruptHandler<T>> + 'a, | ||
| 519 | rx_buffer: &'a mut [u8], | ||
| 520 | config: Config, | ||
| 521 | ) -> Result<Self> { | ||
| 522 | rx_pin.as_rx(); | ||
| 523 | |||
| 524 | Self::new_inner::<T>(inner, rx_pin.into(), None, rx_buffer, config) | ||
| 525 | } | ||
| 526 | |||
| 527 | /// Create a new RX-only buffered LPUART with RTS flow control | ||
| 528 | pub fn new_with_rts<T: Instance>( | ||
| 529 | inner: Peri<'a, T>, | ||
| 530 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 531 | rts_pin: Peri<'a, impl RtsPin<T>>, | ||
| 532 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, BufferedInterruptHandler<T>> + 'a, | ||
| 533 | rx_buffer: &'a mut [u8], | ||
| 534 | config: Config, | ||
| 535 | ) -> Result<Self> { | ||
| 536 | rx_pin.as_rx(); | ||
| 537 | rts_pin.as_rts(); | ||
| 538 | |||
| 539 | Self::new_inner::<T>(inner, rx_pin.into(), Some(rts_pin.into()), rx_buffer, config) | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | impl<'a> BufferedLpuartRx<'a> { | ||
| 544 | /// Read data asynchronously | ||
| 545 | pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize> { | ||
| 546 | if buf.is_empty() { | ||
| 547 | return Ok(0); | ||
| 548 | } | ||
| 549 | |||
| 550 | let mut read = 0; | ||
| 551 | |||
| 552 | // Try to read available data | ||
| 553 | poll_fn(|cx| { | ||
| 554 | self.state.rx_waker.register(cx.waker()); | ||
| 555 | |||
| 556 | // Disable RX interrupt while reading from buffer | ||
| 557 | cortex_m::interrupt::free(|_| { | ||
| 558 | self.info.regs.ctrl().modify(|_, w| w.rie().disabled()); | ||
| 559 | }); | ||
| 560 | |||
| 561 | let mut reader = unsafe { self.state.rx_buf.reader() }; | ||
| 562 | let available = reader.pop(|data| { | ||
| 563 | let to_copy = core::cmp::min(data.len(), buf.len() - read); | ||
| 564 | if to_copy > 0 { | ||
| 565 | buf[read..read + to_copy].copy_from_slice(&data[..to_copy]); | ||
| 566 | read += to_copy; | ||
| 567 | } | ||
| 568 | to_copy | ||
| 569 | }); | ||
| 570 | |||
| 571 | // Re-enable RX interrupt | ||
| 572 | cortex_m::interrupt::free(|_| { | ||
| 573 | self.info.regs.ctrl().modify(|_, w| w.rie().enabled()); | ||
| 574 | }); | ||
| 575 | |||
| 576 | if read > 0 { | ||
| 577 | Poll::Ready(Ok(read)) | ||
| 578 | } else if available == 0 { | ||
| 579 | Poll::Pending | ||
| 580 | } else { | ||
| 581 | Poll::Ready(Ok(0)) | ||
| 582 | } | ||
| 583 | }) | ||
| 584 | .await | ||
| 585 | } | ||
| 586 | |||
| 587 | /// Try to read without blocking | ||
| 588 | pub fn try_read(&mut self, buf: &mut [u8]) -> Result<usize> { | ||
| 589 | if buf.is_empty() { | ||
| 590 | return Ok(0); | ||
| 591 | } | ||
| 592 | |||
| 593 | // Disable RX interrupt while reading from buffer | ||
| 594 | cortex_m::interrupt::free(|_| { | ||
| 595 | self.info.regs.ctrl().modify(|_, w| w.rie().disabled()); | ||
| 596 | }); | ||
| 597 | |||
| 598 | let mut reader = unsafe { self.state.rx_buf.reader() }; | ||
| 599 | let read = reader.pop(|data| { | ||
| 600 | let to_copy = core::cmp::min(data.len(), buf.len()); | ||
| 601 | if to_copy > 0 { | ||
| 602 | buf[..to_copy].copy_from_slice(&data[..to_copy]); | ||
| 603 | } | ||
| 604 | to_copy | ||
| 605 | }); | ||
| 606 | |||
| 607 | // Re-enable RX interrupt | ||
| 608 | cortex_m::interrupt::free(|_| { | ||
| 609 | self.info.regs.ctrl().modify(|_, w| w.rie().enabled()); | ||
| 610 | }); | ||
| 611 | |||
| 612 | Ok(read) | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | // ============================================================================ | ||
| 617 | // INTERRUPT HANDLER | ||
| 618 | // ============================================================================ | ||
| 619 | |||
| 620 | /// Buffered UART interrupt handler | ||
| 621 | pub struct BufferedInterruptHandler<T: Instance> { | ||
| 622 | _phantom: PhantomData<T>, | ||
| 623 | } | ||
| 624 | |||
| 625 | impl<T: Instance> crate::interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> { | ||
| 626 | unsafe fn on_interrupt() { | ||
| 627 | let regs = T::info().regs; | ||
| 628 | let state = T::buffered_state(); | ||
| 629 | |||
| 630 | // Check if this instance is initialized | ||
| 631 | if !state.initialized.load(Ordering::Relaxed) { | ||
| 632 | return; | ||
| 633 | } | ||
| 634 | |||
| 635 | let ctrl = regs.ctrl().read(); | ||
| 636 | let stat = regs.stat().read(); | ||
| 637 | let has_fifo = regs.param().read().rxfifo().bits() > 0; | ||
| 638 | |||
| 639 | // Handle overrun error | ||
| 640 | if stat.or().is_overrun() { | ||
| 641 | regs.stat().write(|w| w.or().clear_bit_by_one()); | ||
| 642 | state.rx_waker.wake(); | ||
| 643 | return; | ||
| 644 | } | ||
| 645 | |||
| 646 | // Clear other error flags | ||
| 647 | if stat.pf().is_parity() { | ||
| 648 | regs.stat().write(|w| w.pf().clear_bit_by_one()); | ||
| 649 | } | ||
| 650 | if stat.fe().is_error() { | ||
| 651 | regs.stat().write(|w| w.fe().clear_bit_by_one()); | ||
| 652 | } | ||
| 653 | if stat.nf().is_noise() { | ||
| 654 | regs.stat().write(|w| w.nf().clear_bit_by_one()); | ||
| 655 | } | ||
| 656 | |||
| 657 | // Handle RX data | ||
| 658 | if ctrl.rie().is_enabled() && (has_data(regs) || stat.idle().is_idle()) { | ||
| 659 | let mut pushed_any = false; | ||
| 660 | let mut writer = state.rx_buf.writer(); | ||
| 661 | |||
| 662 | if has_fifo { | ||
| 663 | // Read from FIFO | ||
| 664 | while regs.water().read().rxcount().bits() > 0 { | ||
| 665 | let byte = (regs.data().read().bits() & 0xFF) as u8; | ||
| 666 | if writer.push_one(byte) { | ||
| 667 | pushed_any = true; | ||
| 668 | } else { | ||
| 669 | // Buffer full, stop reading | ||
| 670 | break; | ||
| 671 | } | ||
| 672 | } | ||
| 673 | } else { | ||
| 674 | // Read single byte | ||
| 675 | if regs.stat().read().rdrf().is_rxdata() { | ||
| 676 | let byte = (regs.data().read().bits() & 0xFF) as u8; | ||
| 677 | if writer.push_one(byte) { | ||
| 678 | pushed_any = true; | ||
| 679 | } | ||
| 680 | } | ||
| 681 | } | ||
| 682 | |||
| 683 | if pushed_any { | ||
| 684 | state.rx_waker.wake(); | ||
| 685 | } | ||
| 686 | |||
| 687 | // Clear idle flag if set | ||
| 688 | if stat.idle().is_idle() { | ||
| 689 | regs.stat().write(|w| w.idle().clear_bit_by_one()); | ||
| 690 | } | ||
| 691 | } | ||
| 692 | |||
| 693 | // Handle TX data | ||
| 694 | if ctrl.tie().is_enabled() { | ||
| 695 | let mut sent_any = false; | ||
| 696 | let mut reader = state.tx_buf.reader(); | ||
| 697 | |||
| 698 | // Send data while TX buffer is ready and we have data | ||
| 699 | while regs.stat().read().tdre().is_no_txdata() { | ||
| 700 | if let Some(byte) = reader.pop_one() { | ||
| 701 | regs.data().write(|w| w.bits(u32::from(byte))); | ||
| 702 | sent_any = true; | ||
| 703 | } else { | ||
| 704 | // No more data to send | ||
| 705 | break; | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | if sent_any { | ||
| 710 | state.tx_waker.wake(); | ||
| 711 | } | ||
| 712 | |||
| 713 | // If buffer is empty, switch to TC interrupt or disable | ||
| 714 | if state.tx_buf.is_empty() { | ||
| 715 | cortex_m::interrupt::free(|_| { | ||
| 716 | regs.ctrl().modify(|_, w| w.tie().disabled().tcie().enabled()); | ||
| 717 | }); | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | // Handle transmission complete | ||
| 722 | if ctrl.tcie().is_enabled() && regs.stat().read().tc().is_complete() { | ||
| 723 | state.tx_done.store(true, Ordering::Release); | ||
| 724 | state.tx_waker.wake(); | ||
| 725 | |||
| 726 | // Disable TC interrupt | ||
| 727 | cortex_m::interrupt::free(|_| { | ||
| 728 | regs.ctrl().modify(|_, w| w.tcie().disabled()); | ||
| 729 | }); | ||
| 730 | } | ||
| 731 | } | ||
| 732 | } | ||
| 733 | |||
| 734 | // ============================================================================ | ||
| 735 | // EMBEDDED-IO ASYNC TRAIT IMPLEMENTATIONS | ||
| 736 | // ============================================================================ | ||
| 737 | |||
| 738 | impl embedded_io_async::ErrorType for BufferedLpuartTx<'_> { | ||
| 739 | type Error = Error; | ||
| 740 | } | ||
| 741 | |||
| 742 | impl embedded_io_async::ErrorType for BufferedLpuartRx<'_> { | ||
| 743 | type Error = Error; | ||
| 744 | } | ||
| 745 | |||
| 746 | impl embedded_io_async::ErrorType for BufferedLpuart<'_> { | ||
| 747 | type Error = Error; | ||
| 748 | } | ||
| 749 | |||
| 750 | impl embedded_io_async::Write for BufferedLpuartTx<'_> { | ||
| 751 | async fn write(&mut self, buf: &[u8]) -> core::result::Result<usize, Self::Error> { | ||
| 752 | self.write(buf).await | ||
| 753 | } | ||
| 754 | |||
| 755 | async fn flush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 756 | self.flush().await | ||
| 757 | } | ||
| 758 | } | ||
| 759 | |||
| 760 | impl embedded_io_async::Read for BufferedLpuartRx<'_> { | ||
| 761 | async fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> { | ||
| 762 | self.read(buf).await | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | impl embedded_io_async::Write for BufferedLpuart<'_> { | ||
| 767 | async fn write(&mut self, buf: &[u8]) -> core::result::Result<usize, Self::Error> { | ||
| 768 | self.tx.write(buf).await | ||
| 769 | } | ||
| 770 | |||
| 771 | async fn flush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 772 | self.tx.flush().await | ||
| 773 | } | ||
| 774 | } | ||
| 775 | |||
| 776 | impl embedded_io_async::Read for BufferedLpuart<'_> { | ||
| 777 | async fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> { | ||
| 778 | self.rx.read(buf).await | ||
| 779 | } | ||
| 780 | } | ||
diff --git a/embassy-mcxa/src/lpuart/mod.rs b/embassy-mcxa/src/lpuart/mod.rs new file mode 100644 index 000000000..2d8308ec8 --- /dev/null +++ b/embassy-mcxa/src/lpuart/mod.rs | |||
| @@ -0,0 +1,1292 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 4 | use paste::paste; | ||
| 5 | |||
| 6 | use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig}; | ||
| 7 | use crate::clocks::{enable_and_reset, ClockError, Gate, PoweredClock}; | ||
| 8 | use crate::gpio::SealedPin; | ||
| 9 | use crate::pac::lpuart0::baud::Sbns as StopBits; | ||
| 10 | use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits}; | ||
| 11 | use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; | ||
| 12 | use crate::pac::lpuart0::stat::Msbf as MsbFirst; | ||
| 13 | use crate::{interrupt, pac, AnyPin}; | ||
| 14 | |||
| 15 | pub mod buffered; | ||
| 16 | |||
| 17 | // ============================================================================ | ||
| 18 | // STUB IMPLEMENTATION | ||
| 19 | // ============================================================================ | ||
| 20 | |||
| 21 | // Stub implementation for LIB (Peripherals), GPIO, DMA and CLOCK until stable API | ||
| 22 | // Pin and Clock initialization is currently done at the examples level. | ||
| 23 | |||
| 24 | // --- START DMA --- | ||
| 25 | mod dma { | ||
| 26 | pub struct Channel<'d> { | ||
| 27 | pub(super) _lifetime: core::marker::PhantomData<&'d ()>, | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | use dma::Channel; | ||
| 32 | |||
| 33 | // --- END DMA --- | ||
| 34 | |||
| 35 | // ============================================================================ | ||
| 36 | // MISC | ||
| 37 | // ============================================================================ | ||
| 38 | |||
| 39 | mod sealed { | ||
| 40 | /// Simply seal a trait to prevent external implementations | ||
| 41 | pub trait Sealed {} | ||
| 42 | } | ||
| 43 | |||
| 44 | // ============================================================================ | ||
| 45 | // INSTANCE TRAIT | ||
| 46 | // ============================================================================ | ||
| 47 | |||
| 48 | pub type Regs = &'static crate::pac::lpuart0::RegisterBlock; | ||
| 49 | |||
| 50 | pub trait SealedInstance { | ||
| 51 | fn info() -> Info; | ||
| 52 | fn index() -> usize; | ||
| 53 | fn buffered_state() -> &'static buffered::State; | ||
| 54 | } | ||
| 55 | |||
| 56 | pub struct Info { | ||
| 57 | pub regs: Regs, | ||
| 58 | } | ||
| 59 | |||
| 60 | /// Trait for LPUART peripheral instances | ||
| 61 | #[allow(private_bounds)] | ||
| 62 | pub trait Instance: SealedInstance + PeripheralType + 'static + Send + Gate<MrccPeriphConfig = LpuartConfig> { | ||
| 63 | const CLOCK_INSTANCE: crate::clocks::periph_helpers::LpuartInstance; | ||
| 64 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 65 | } | ||
| 66 | |||
| 67 | macro_rules! impl_instance { | ||
| 68 | ($($n:expr),*) => { | ||
| 69 | $( | ||
| 70 | paste!{ | ||
| 71 | impl SealedInstance for crate::peripherals::[<LPUART $n>] { | ||
| 72 | fn info() -> Info { | ||
| 73 | Info { | ||
| 74 | regs: unsafe { &*pac::[<Lpuart $n>]::ptr() }, | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | #[inline] | ||
| 79 | fn index() -> usize { | ||
| 80 | $n | ||
| 81 | } | ||
| 82 | |||
| 83 | fn buffered_state() -> &'static buffered::State { | ||
| 84 | static BUFFERED_STATE: buffered::State = buffered::State::new(); | ||
| 85 | &BUFFERED_STATE | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | impl Instance for crate::peripherals::[<LPUART $n>] { | ||
| 90 | const CLOCK_INSTANCE: crate::clocks::periph_helpers::LpuartInstance | ||
| 91 | = crate::clocks::periph_helpers::LpuartInstance::[<Lpuart $n>]; | ||
| 92 | type Interrupt = crate::interrupt::typelevel::[<LPUART $n>]; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | )* | ||
| 96 | }; | ||
| 97 | } | ||
| 98 | |||
| 99 | impl_instance!(0, 1, 2, 3, 4, 5); | ||
| 100 | |||
| 101 | // ============================================================================ | ||
| 102 | // INSTANCE HELPER FUNCTIONS | ||
| 103 | // ============================================================================ | ||
| 104 | |||
| 105 | /// Perform software reset on the LPUART peripheral | ||
| 106 | pub fn perform_software_reset(regs: Regs) { | ||
| 107 | // Software reset - set and clear RST bit (Global register) | ||
| 108 | regs.global().write(|w| w.rst().reset()); | ||
| 109 | regs.global().write(|w| w.rst().no_effect()); | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Disable both transmitter and receiver | ||
| 113 | pub fn disable_transceiver(regs: Regs) { | ||
| 114 | regs.ctrl().modify(|_, w| w.te().disabled().re().disabled()); | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Calculate and configure baudrate settings | ||
| 118 | pub fn configure_baudrate(regs: Regs, baudrate_bps: u32, clock_freq: u32) -> Result<()> { | ||
| 119 | let (osr, sbr) = calculate_baudrate(baudrate_bps, clock_freq)?; | ||
| 120 | |||
| 121 | // Configure BAUD register | ||
| 122 | regs.baud().modify(|_, w| unsafe { | ||
| 123 | // Clear and set OSR | ||
| 124 | w.osr().bits(osr - 1); | ||
| 125 | // Clear and set SBR | ||
| 126 | w.sbr().bits(sbr); | ||
| 127 | // Set BOTHEDGE if OSR is between 4 and 7 | ||
| 128 | if osr > 3 && osr < 8 { | ||
| 129 | w.bothedge().enabled() | ||
| 130 | } else { | ||
| 131 | w.bothedge().disabled() | ||
| 132 | } | ||
| 133 | }); | ||
| 134 | |||
| 135 | Ok(()) | ||
| 136 | } | ||
| 137 | |||
| 138 | /// Configure frame format (stop bits, data bits) | ||
| 139 | pub fn configure_frame_format(regs: Regs, config: &Config) { | ||
| 140 | // Configure stop bits | ||
| 141 | regs.baud().modify(|_, w| w.sbns().variant(config.stop_bits_count)); | ||
| 142 | |||
| 143 | // Clear M10 for now (10-bit mode) | ||
| 144 | regs.baud().modify(|_, w| w.m10().disabled()); | ||
| 145 | } | ||
| 146 | |||
| 147 | /// Configure control settings (parity, data bits, idle config, pin swap) | ||
| 148 | pub fn configure_control_settings(regs: Regs, config: &Config) { | ||
| 149 | regs.ctrl().modify(|_, w| { | ||
| 150 | // Parity configuration | ||
| 151 | let mut w = if let Some(parity) = config.parity_mode { | ||
| 152 | w.pe().enabled().pt().variant(parity) | ||
| 153 | } else { | ||
| 154 | w.pe().disabled() | ||
| 155 | }; | ||
| 156 | |||
| 157 | // Data bits configuration | ||
| 158 | w = match config.data_bits_count { | ||
| 159 | DataBits::Data8 => { | ||
| 160 | if config.parity_mode.is_some() { | ||
| 161 | w.m().data9() // 8 data + 1 parity = 9 bits | ||
| 162 | } else { | ||
| 163 | w.m().data8() // 8 data bits only | ||
| 164 | } | ||
| 165 | } | ||
| 166 | DataBits::Data9 => w.m().data9(), | ||
| 167 | }; | ||
| 168 | |||
| 169 | // Idle configuration | ||
| 170 | w = w.idlecfg().variant(config.rx_idle_config); | ||
| 171 | w = w.ilt().variant(config.rx_idle_type); | ||
| 172 | |||
| 173 | // Swap TXD/RXD if configured | ||
| 174 | if config.swap_txd_rxd { | ||
| 175 | w.swap().swap() | ||
| 176 | } else { | ||
| 177 | w.swap().standard() | ||
| 178 | } | ||
| 179 | }); | ||
| 180 | } | ||
| 181 | |||
| 182 | /// Configure FIFO settings and watermarks | ||
| 183 | pub fn configure_fifo(regs: Regs, config: &Config) { | ||
| 184 | // Configure WATER register for FIFO watermarks | ||
| 185 | regs.water().write(|w| unsafe { | ||
| 186 | w.rxwater() | ||
| 187 | .bits(config.rx_fifo_watermark) | ||
| 188 | .txwater() | ||
| 189 | .bits(config.tx_fifo_watermark) | ||
| 190 | }); | ||
| 191 | |||
| 192 | // Enable TX/RX FIFOs | ||
| 193 | regs.fifo().modify(|_, w| w.txfe().enabled().rxfe().enabled()); | ||
| 194 | |||
| 195 | // Flush FIFOs | ||
| 196 | regs.fifo() | ||
| 197 | .modify(|_, w| w.txflush().txfifo_rst().rxflush().rxfifo_rst()); | ||
| 198 | } | ||
| 199 | |||
| 200 | /// Clear all status flags | ||
| 201 | pub fn clear_all_status_flags(regs: Regs) { | ||
| 202 | regs.stat().reset(); | ||
| 203 | } | ||
| 204 | |||
| 205 | /// Configure hardware flow control if enabled | ||
| 206 | pub fn configure_flow_control(regs: Regs, enable_tx_cts: bool, enable_rx_rts: bool, config: &Config) { | ||
| 207 | if enable_rx_rts || enable_tx_cts { | ||
| 208 | regs.modir().modify(|_, w| { | ||
| 209 | let mut w = w; | ||
| 210 | |||
| 211 | // Configure TX CTS | ||
| 212 | w = w.txctsc().variant(config.tx_cts_config); | ||
| 213 | w = w.txctssrc().variant(config.tx_cts_source); | ||
| 214 | |||
| 215 | if enable_rx_rts { | ||
| 216 | w = w.rxrtse().enabled(); | ||
| 217 | } else { | ||
| 218 | w = w.rxrtse().disabled(); | ||
| 219 | } | ||
| 220 | |||
| 221 | if enable_tx_cts { | ||
| 222 | w = w.txctse().enabled(); | ||
| 223 | } else { | ||
| 224 | w = w.txctse().disabled(); | ||
| 225 | } | ||
| 226 | |||
| 227 | w | ||
| 228 | }); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | /// Configure bit order (MSB first or LSB first) | ||
| 233 | pub fn configure_bit_order(regs: Regs, msb_first: MsbFirst) { | ||
| 234 | regs.stat().modify(|_, w| w.msbf().variant(msb_first)); | ||
| 235 | } | ||
| 236 | |||
| 237 | /// Enable transmitter and/or receiver based on configuration | ||
| 238 | pub fn enable_transceiver(regs: Regs, enable_tx: bool, enable_rx: bool) { | ||
| 239 | regs.ctrl().modify(|_, w| { | ||
| 240 | let mut w = w; | ||
| 241 | if enable_tx { | ||
| 242 | w = w.te().enabled(); | ||
| 243 | } | ||
| 244 | if enable_rx { | ||
| 245 | w = w.re().enabled(); | ||
| 246 | } | ||
| 247 | w | ||
| 248 | }); | ||
| 249 | } | ||
| 250 | |||
| 251 | pub fn calculate_baudrate(baudrate: u32, src_clock_hz: u32) -> Result<(u8, u16)> { | ||
| 252 | let mut baud_diff = baudrate; | ||
| 253 | let mut osr = 0u8; | ||
| 254 | let mut sbr = 0u16; | ||
| 255 | |||
| 256 | // Try OSR values from 4 to 32 | ||
| 257 | for osr_temp in 4u8..=32u8 { | ||
| 258 | // Calculate SBR: (srcClock_Hz * 2 / (baudRate * osr) + 1) / 2 | ||
| 259 | let sbr_calc = ((src_clock_hz * 2) / (baudrate * osr_temp as u32)).div_ceil(2); | ||
| 260 | |||
| 261 | let sbr_temp = if sbr_calc == 0 { | ||
| 262 | 1 | ||
| 263 | } else if sbr_calc > 0x1FFF { | ||
| 264 | 0x1FFF | ||
| 265 | } else { | ||
| 266 | sbr_calc as u16 | ||
| 267 | }; | ||
| 268 | |||
| 269 | // Calculate actual baud rate | ||
| 270 | let calculated_baud = src_clock_hz / (osr_temp as u32 * sbr_temp as u32); | ||
| 271 | |||
| 272 | let temp_diff = calculated_baud.abs_diff(baudrate); | ||
| 273 | |||
| 274 | if temp_diff <= baud_diff { | ||
| 275 | baud_diff = temp_diff; | ||
| 276 | osr = osr_temp; | ||
| 277 | sbr = sbr_temp; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | // Check if baud rate difference is within 3% | ||
| 282 | if baud_diff > (baudrate / 100) * 3 { | ||
| 283 | return Err(Error::UnsupportedBaudrate); | ||
| 284 | } | ||
| 285 | |||
| 286 | Ok((osr, sbr)) | ||
| 287 | } | ||
| 288 | |||
| 289 | /// Wait for all transmit operations to complete | ||
| 290 | pub fn wait_for_tx_complete(regs: Regs) { | ||
| 291 | // Wait for TX FIFO to empty | ||
| 292 | while regs.water().read().txcount().bits() != 0 { | ||
| 293 | // Wait for TX FIFO to drain | ||
| 294 | } | ||
| 295 | |||
| 296 | // Wait for last character to shift out (TC = Transmission Complete) | ||
| 297 | while regs.stat().read().tc().is_active() { | ||
| 298 | // Wait for transmission to complete | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | pub fn check_and_clear_rx_errors(regs: Regs) -> Result<()> { | ||
| 303 | let stat = regs.stat().read(); | ||
| 304 | let mut status = Ok(()); | ||
| 305 | |||
| 306 | // Check for overrun first - other error flags are prevented when OR is set | ||
| 307 | if stat.or().is_overrun() { | ||
| 308 | regs.stat().write(|w| w.or().clear_bit_by_one()); | ||
| 309 | |||
| 310 | return Err(Error::Overrun); | ||
| 311 | } | ||
| 312 | |||
| 313 | if stat.pf().is_parity() { | ||
| 314 | regs.stat().write(|w| w.pf().clear_bit_by_one()); | ||
| 315 | status = Err(Error::Parity); | ||
| 316 | } | ||
| 317 | |||
| 318 | if stat.fe().is_error() { | ||
| 319 | regs.stat().write(|w| w.fe().clear_bit_by_one()); | ||
| 320 | status = Err(Error::Framing); | ||
| 321 | } | ||
| 322 | |||
| 323 | if stat.nf().is_noise() { | ||
| 324 | regs.stat().write(|w| w.nf().clear_bit_by_one()); | ||
| 325 | status = Err(Error::Noise); | ||
| 326 | } | ||
| 327 | |||
| 328 | status | ||
| 329 | } | ||
| 330 | |||
| 331 | pub fn has_data(regs: Regs) -> bool { | ||
| 332 | if regs.param().read().rxfifo().bits() > 0 { | ||
| 333 | // FIFO is available - check RXCOUNT in WATER register | ||
| 334 | regs.water().read().rxcount().bits() > 0 | ||
| 335 | } else { | ||
| 336 | // No FIFO - check RDRF flag in STAT register | ||
| 337 | regs.stat().read().rdrf().is_rxdata() | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | // ============================================================================ | ||
| 342 | // PIN TRAITS FOR LPUART FUNCTIONALITY | ||
| 343 | // ============================================================================ | ||
| 344 | |||
| 345 | impl<T: SealedPin> sealed::Sealed for T {} | ||
| 346 | |||
| 347 | /// io configuration trait for Lpuart Tx configuration | ||
| 348 | pub trait TxPin<T: Instance>: Into<AnyPin> + sealed::Sealed + PeripheralType { | ||
| 349 | /// convert the pin to appropriate function for Lpuart Tx usage | ||
| 350 | fn as_tx(&self); | ||
| 351 | } | ||
| 352 | |||
| 353 | /// io configuration trait for Lpuart Rx configuration | ||
| 354 | pub trait RxPin<T: Instance>: Into<AnyPin> + sealed::Sealed + PeripheralType { | ||
| 355 | /// convert the pin to appropriate function for Lpuart Rx usage | ||
| 356 | fn as_rx(&self); | ||
| 357 | } | ||
| 358 | |||
| 359 | /// io configuration trait for Lpuart Cts | ||
| 360 | pub trait CtsPin<T: Instance>: Into<AnyPin> + sealed::Sealed + PeripheralType { | ||
| 361 | /// convert the pin to appropriate function for Lpuart Cts usage | ||
| 362 | fn as_cts(&self); | ||
| 363 | } | ||
| 364 | |||
| 365 | /// io configuration trait for Lpuart Rts | ||
| 366 | pub trait RtsPin<T: Instance>: Into<AnyPin> + sealed::Sealed + PeripheralType { | ||
| 367 | /// convert the pin to appropriate function for Lpuart Rts usage | ||
| 368 | fn as_rts(&self); | ||
| 369 | } | ||
| 370 | |||
| 371 | macro_rules! impl_tx_pin { | ||
| 372 | ($inst:ident, $pin:ident, $alt:ident) => { | ||
| 373 | impl TxPin<crate::peripherals::$inst> for crate::peripherals::$pin { | ||
| 374 | fn as_tx(&self) { | ||
| 375 | // TODO: Check these are right | ||
| 376 | self.set_pull(crate::gpio::Pull::Up); | ||
| 377 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | ||
| 378 | self.set_drive_strength(crate::gpio::DriveStrength::Double.into()); | ||
| 379 | self.set_function(crate::pac::port0::pcr0::Mux::$alt); | ||
| 380 | self.set_enable_input_buffer(); | ||
| 381 | } | ||
| 382 | } | ||
| 383 | }; | ||
| 384 | } | ||
| 385 | |||
| 386 | macro_rules! impl_rx_pin { | ||
| 387 | ($inst:ident, $pin:ident, $alt:ident) => { | ||
| 388 | impl RxPin<crate::peripherals::$inst> for crate::peripherals::$pin { | ||
| 389 | fn as_rx(&self) { | ||
| 390 | // TODO: Check these are right | ||
| 391 | self.set_pull(crate::gpio::Pull::Up); | ||
| 392 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | ||
| 393 | self.set_drive_strength(crate::gpio::DriveStrength::Double.into()); | ||
| 394 | self.set_function(crate::pac::port0::pcr0::Mux::$alt); | ||
| 395 | self.set_enable_input_buffer(); | ||
| 396 | } | ||
| 397 | } | ||
| 398 | }; | ||
| 399 | } | ||
| 400 | |||
| 401 | // TODO: Macro and impls for CTS/RTS pins | ||
| 402 | macro_rules! impl_cts_pin { | ||
| 403 | ($inst:ident, $pin:ident, $alt:ident) => { | ||
| 404 | impl CtsPin<crate::peripherals::$inst> for crate::peripherals::$pin { | ||
| 405 | fn as_cts(&self) { | ||
| 406 | todo!() | ||
| 407 | } | ||
| 408 | } | ||
| 409 | }; | ||
| 410 | } | ||
| 411 | |||
| 412 | macro_rules! impl_rts_pin { | ||
| 413 | ($inst:ident, $pin:ident, $alt:ident) => { | ||
| 414 | impl RtsPin<crate::peripherals::$inst> for crate::peripherals::$pin { | ||
| 415 | fn as_rts(&self) { | ||
| 416 | todo!() | ||
| 417 | } | ||
| 418 | } | ||
| 419 | }; | ||
| 420 | } | ||
| 421 | |||
| 422 | // LPUART 0 | ||
| 423 | impl_tx_pin!(LPUART0, P0_3, Mux2); | ||
| 424 | impl_tx_pin!(LPUART0, P0_21, Mux3); | ||
| 425 | impl_tx_pin!(LPUART0, P2_1, Mux2); | ||
| 426 | |||
| 427 | impl_rx_pin!(LPUART0, P0_2, Mux2); | ||
| 428 | impl_rx_pin!(LPUART0, P0_20, Mux3); | ||
| 429 | impl_rx_pin!(LPUART0, P2_0, Mux2); | ||
| 430 | |||
| 431 | impl_cts_pin!(LPUART0, P0_1, Mux2); | ||
| 432 | impl_cts_pin!(LPUART0, P0_23, Mux3); | ||
| 433 | impl_cts_pin!(LPUART0, P2_3, Mux2); | ||
| 434 | |||
| 435 | impl_rts_pin!(LPUART0, P0_0, Mux2); | ||
| 436 | impl_rts_pin!(LPUART0, P0_22, Mux3); | ||
| 437 | impl_rts_pin!(LPUART0, P2_2, Mux2); | ||
| 438 | |||
| 439 | // LPUART 1 | ||
| 440 | impl_tx_pin!(LPUART1, P1_9, Mux2); | ||
| 441 | impl_tx_pin!(LPUART1, P2_13, Mux3); | ||
| 442 | impl_tx_pin!(LPUART1, P3_9, Mux3); | ||
| 443 | impl_tx_pin!(LPUART1, P3_21, Mux3); | ||
| 444 | |||
| 445 | impl_rx_pin!(LPUART1, P1_8, Mux2); | ||
| 446 | impl_rx_pin!(LPUART1, P2_12, Mux3); | ||
| 447 | impl_rx_pin!(LPUART1, P3_8, Mux3); | ||
| 448 | impl_rx_pin!(LPUART1, P3_20, Mux3); | ||
| 449 | |||
| 450 | impl_cts_pin!(LPUART1, P1_11, Mux2); | ||
| 451 | impl_cts_pin!(LPUART1, P2_17, Mux3); | ||
| 452 | impl_cts_pin!(LPUART1, P3_11, Mux3); | ||
| 453 | impl_cts_pin!(LPUART1, P3_23, Mux3); | ||
| 454 | |||
| 455 | impl_rts_pin!(LPUART1, P1_10, Mux2); | ||
| 456 | impl_rts_pin!(LPUART1, P2_15, Mux3); | ||
| 457 | impl_rts_pin!(LPUART1, P2_16, Mux3); | ||
| 458 | impl_rts_pin!(LPUART1, P3_10, Mux3); | ||
| 459 | |||
| 460 | // LPUART 2 | ||
| 461 | impl_tx_pin!(LPUART2, P1_5, Mux3); | ||
| 462 | impl_tx_pin!(LPUART2, P1_13, Mux3); | ||
| 463 | impl_tx_pin!(LPUART2, P2_2, Mux3); | ||
| 464 | impl_tx_pin!(LPUART2, P2_10, Mux3); | ||
| 465 | impl_tx_pin!(LPUART2, P3_15, Mux2); | ||
| 466 | |||
| 467 | impl_rx_pin!(LPUART2, P1_4, Mux3); | ||
| 468 | impl_rx_pin!(LPUART2, P1_12, Mux3); | ||
| 469 | impl_rx_pin!(LPUART2, P2_3, Mux3); | ||
| 470 | impl_rx_pin!(LPUART2, P2_11, Mux3); | ||
| 471 | impl_rx_pin!(LPUART2, P3_14, Mux2); | ||
| 472 | |||
| 473 | impl_cts_pin!(LPUART2, P1_7, Mux3); | ||
| 474 | impl_cts_pin!(LPUART2, P1_15, Mux3); | ||
| 475 | impl_cts_pin!(LPUART2, P2_4, Mux3); | ||
| 476 | impl_cts_pin!(LPUART2, P3_13, Mux2); | ||
| 477 | |||
| 478 | impl_rts_pin!(LPUART2, P1_6, Mux3); | ||
| 479 | impl_rts_pin!(LPUART2, P1_14, Mux3); | ||
| 480 | impl_rts_pin!(LPUART2, P2_5, Mux3); | ||
| 481 | impl_rts_pin!(LPUART2, P3_12, Mux2); | ||
| 482 | |||
| 483 | // LPUART 3 | ||
| 484 | impl_tx_pin!(LPUART3, P3_1, Mux3); | ||
| 485 | impl_tx_pin!(LPUART3, P3_12, Mux3); | ||
| 486 | impl_tx_pin!(LPUART3, P4_5, Mux3); | ||
| 487 | |||
| 488 | impl_rx_pin!(LPUART3, P3_0, Mux3); | ||
| 489 | impl_rx_pin!(LPUART3, P3_13, Mux3); | ||
| 490 | impl_rx_pin!(LPUART3, P4_2, Mux3); | ||
| 491 | |||
| 492 | impl_cts_pin!(LPUART3, P3_7, Mux3); | ||
| 493 | impl_cts_pin!(LPUART3, P3_14, Mux3); | ||
| 494 | impl_cts_pin!(LPUART3, P4_6, Mux3); | ||
| 495 | |||
| 496 | impl_rts_pin!(LPUART3, P3_6, Mux3); | ||
| 497 | impl_rts_pin!(LPUART3, P3_15, Mux3); | ||
| 498 | impl_rts_pin!(LPUART3, P4_7, Mux3); | ||
| 499 | |||
| 500 | // LPUART 4 | ||
| 501 | impl_tx_pin!(LPUART4, P2_7, Mux3); | ||
| 502 | impl_tx_pin!(LPUART4, P3_19, Mux2); | ||
| 503 | impl_tx_pin!(LPUART4, P3_27, Mux3); | ||
| 504 | impl_tx_pin!(LPUART4, P4_3, Mux3); | ||
| 505 | |||
| 506 | impl_rx_pin!(LPUART4, P2_6, Mux3); | ||
| 507 | impl_rx_pin!(LPUART4, P3_18, Mux2); | ||
| 508 | impl_rx_pin!(LPUART4, P3_28, Mux3); | ||
| 509 | impl_rx_pin!(LPUART4, P4_4, Mux3); | ||
| 510 | |||
| 511 | impl_cts_pin!(LPUART4, P2_0, Mux3); | ||
| 512 | impl_cts_pin!(LPUART4, P3_17, Mux2); | ||
| 513 | impl_cts_pin!(LPUART4, P3_31, Mux3); | ||
| 514 | |||
| 515 | impl_rts_pin!(LPUART4, P2_1, Mux3); | ||
| 516 | impl_rts_pin!(LPUART4, P3_16, Mux2); | ||
| 517 | impl_rts_pin!(LPUART4, P3_30, Mux3); | ||
| 518 | |||
| 519 | // LPUART 5 | ||
| 520 | impl_tx_pin!(LPUART5, P1_10, Mux8); | ||
| 521 | impl_tx_pin!(LPUART5, P1_17, Mux8); | ||
| 522 | |||
| 523 | impl_rx_pin!(LPUART5, P1_11, Mux8); | ||
| 524 | impl_rx_pin!(LPUART5, P1_16, Mux8); | ||
| 525 | |||
| 526 | impl_cts_pin!(LPUART5, P1_12, Mux8); | ||
| 527 | impl_cts_pin!(LPUART5, P1_19, Mux8); | ||
| 528 | |||
| 529 | impl_rts_pin!(LPUART5, P1_13, Mux8); | ||
| 530 | impl_rts_pin!(LPUART5, P1_18, Mux8); | ||
| 531 | |||
| 532 | // ============================================================================ | ||
| 533 | // ERROR TYPES AND RESULTS | ||
| 534 | // ============================================================================ | ||
| 535 | |||
| 536 | /// LPUART error types | ||
| 537 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 538 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 539 | pub enum Error { | ||
| 540 | /// Read error | ||
| 541 | Read, | ||
| 542 | /// Buffer overflow | ||
| 543 | Overrun, | ||
| 544 | /// Noise error | ||
| 545 | Noise, | ||
| 546 | /// Framing error | ||
| 547 | Framing, | ||
| 548 | /// Parity error | ||
| 549 | Parity, | ||
| 550 | /// Failure | ||
| 551 | Fail, | ||
| 552 | /// Invalid argument | ||
| 553 | InvalidArgument, | ||
| 554 | /// Lpuart baud rate cannot be supported with the given clock | ||
| 555 | UnsupportedBaudrate, | ||
| 556 | /// RX FIFO Empty | ||
| 557 | RxFifoEmpty, | ||
| 558 | /// TX FIFO Full | ||
| 559 | TxFifoFull, | ||
| 560 | /// TX Busy | ||
| 561 | TxBusy, | ||
| 562 | /// Clock Error | ||
| 563 | ClockSetup(ClockError), | ||
| 564 | } | ||
| 565 | |||
| 566 | /// A specialized Result type for LPUART operations | ||
| 567 | pub type Result<T> = core::result::Result<T, Error>; | ||
| 568 | |||
| 569 | // ============================================================================ | ||
| 570 | // CONFIGURATION STRUCTURES | ||
| 571 | // ============================================================================ | ||
| 572 | |||
| 573 | /// Lpuart config | ||
| 574 | #[derive(Debug, Clone, Copy)] | ||
| 575 | pub struct Config { | ||
| 576 | /// Power state required for this peripheral | ||
| 577 | pub power: PoweredClock, | ||
| 578 | /// Clock source | ||
| 579 | pub source: LpuartClockSel, | ||
| 580 | /// Clock divisor | ||
| 581 | pub div: Div4, | ||
| 582 | /// Baud rate in bits per second | ||
| 583 | pub baudrate_bps: u32, | ||
| 584 | /// Parity configuration | ||
| 585 | pub parity_mode: Option<Parity>, | ||
| 586 | /// Number of data bits | ||
| 587 | pub data_bits_count: DataBits, | ||
| 588 | /// MSB First or LSB First configuration | ||
| 589 | pub msb_first: MsbFirst, | ||
| 590 | /// Number of stop bits | ||
| 591 | pub stop_bits_count: StopBits, | ||
| 592 | /// TX FIFO watermark | ||
| 593 | pub tx_fifo_watermark: u8, | ||
| 594 | /// RX FIFO watermark | ||
| 595 | pub rx_fifo_watermark: u8, | ||
| 596 | /// TX CTS source | ||
| 597 | pub tx_cts_source: TxCtsSource, | ||
| 598 | /// TX CTS configure | ||
| 599 | pub tx_cts_config: TxCtsConfig, | ||
| 600 | /// RX IDLE type | ||
| 601 | pub rx_idle_type: IdleType, | ||
| 602 | /// RX IDLE configuration | ||
| 603 | pub rx_idle_config: IdleConfig, | ||
| 604 | /// Swap TXD and RXD pins | ||
| 605 | pub swap_txd_rxd: bool, | ||
| 606 | } | ||
| 607 | |||
| 608 | impl Default for Config { | ||
| 609 | fn default() -> Self { | ||
| 610 | Self { | ||
| 611 | baudrate_bps: 115_200u32, | ||
| 612 | parity_mode: None, | ||
| 613 | data_bits_count: DataBits::Data8, | ||
| 614 | msb_first: MsbFirst::LsbFirst, | ||
| 615 | stop_bits_count: StopBits::One, | ||
| 616 | tx_fifo_watermark: 0, | ||
| 617 | rx_fifo_watermark: 1, | ||
| 618 | tx_cts_source: TxCtsSource::Cts, | ||
| 619 | tx_cts_config: TxCtsConfig::Start, | ||
| 620 | rx_idle_type: IdleType::FromStart, | ||
| 621 | rx_idle_config: IdleConfig::Idle1, | ||
| 622 | swap_txd_rxd: false, | ||
| 623 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 624 | source: LpuartClockSel::FroLfDiv, | ||
| 625 | div: Div4::no_div(), | ||
| 626 | } | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | /// LPUART status flags | ||
| 631 | #[derive(Debug, Clone, Copy)] | ||
| 632 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 633 | pub struct Status { | ||
| 634 | /// Transmit data register empty | ||
| 635 | pub tx_empty: bool, | ||
| 636 | /// Transmission complete | ||
| 637 | pub tx_complete: bool, | ||
| 638 | /// Receive data register full | ||
| 639 | pub rx_full: bool, | ||
| 640 | /// Idle line detected | ||
| 641 | pub idle: bool, | ||
| 642 | /// Receiver overrun | ||
| 643 | pub overrun: bool, | ||
| 644 | /// Noise error | ||
| 645 | pub noise: bool, | ||
| 646 | /// Framing error | ||
| 647 | pub framing: bool, | ||
| 648 | /// Parity error | ||
| 649 | pub parity: bool, | ||
| 650 | } | ||
| 651 | |||
| 652 | // ============================================================================ | ||
| 653 | // MODE TRAITS (BLOCKING/ASYNC) | ||
| 654 | // ============================================================================ | ||
| 655 | |||
| 656 | /// Driver move trait. | ||
| 657 | #[allow(private_bounds)] | ||
| 658 | pub trait Mode: sealed::Sealed {} | ||
| 659 | |||
| 660 | /// Blocking mode. | ||
| 661 | pub struct Blocking; | ||
| 662 | impl sealed::Sealed for Blocking {} | ||
| 663 | impl Mode for Blocking {} | ||
| 664 | |||
| 665 | /// Async mode. | ||
| 666 | pub struct Async; | ||
| 667 | impl sealed::Sealed for Async {} | ||
| 668 | impl Mode for Async {} | ||
| 669 | |||
| 670 | // ============================================================================ | ||
| 671 | // CORE DRIVER STRUCTURES | ||
| 672 | // ============================================================================ | ||
| 673 | |||
| 674 | /// Lpuart driver. | ||
| 675 | pub struct Lpuart<'a, M: Mode> { | ||
| 676 | info: Info, | ||
| 677 | tx: LpuartTx<'a, M>, | ||
| 678 | rx: LpuartRx<'a, M>, | ||
| 679 | } | ||
| 680 | |||
| 681 | /// Lpuart TX driver. | ||
| 682 | pub struct LpuartTx<'a, M: Mode> { | ||
| 683 | info: Info, | ||
| 684 | _tx_pin: Peri<'a, AnyPin>, | ||
| 685 | _cts_pin: Option<Peri<'a, AnyPin>>, | ||
| 686 | _tx_dma: Option<Channel<'a>>, | ||
| 687 | mode: PhantomData<(&'a (), M)>, | ||
| 688 | } | ||
| 689 | |||
| 690 | /// Lpuart Rx driver. | ||
| 691 | pub struct LpuartRx<'a, M: Mode> { | ||
| 692 | info: Info, | ||
| 693 | _rx_pin: Peri<'a, AnyPin>, | ||
| 694 | _rts_pin: Option<Peri<'a, AnyPin>>, | ||
| 695 | _rx_dma: Option<Channel<'a>>, | ||
| 696 | mode: PhantomData<(&'a (), M)>, | ||
| 697 | } | ||
| 698 | |||
| 699 | // ============================================================================ | ||
| 700 | // LPUART CORE IMPLEMENTATION | ||
| 701 | // ============================================================================ | ||
| 702 | |||
| 703 | impl<'a, M: Mode> Lpuart<'a, M> { | ||
| 704 | fn init<T: Instance>( | ||
| 705 | enable_tx: bool, | ||
| 706 | enable_rx: bool, | ||
| 707 | enable_tx_cts: bool, | ||
| 708 | enable_rx_rts: bool, | ||
| 709 | config: Config, | ||
| 710 | ) -> Result<()> { | ||
| 711 | let regs = T::info().regs; | ||
| 712 | |||
| 713 | // Enable clocks | ||
| 714 | let conf = LpuartConfig { | ||
| 715 | power: config.power, | ||
| 716 | source: config.source, | ||
| 717 | div: config.div, | ||
| 718 | instance: T::CLOCK_INSTANCE, | ||
| 719 | }; | ||
| 720 | let clock_freq = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? }; | ||
| 721 | |||
| 722 | // Perform initialization sequence | ||
| 723 | perform_software_reset(regs); | ||
| 724 | disable_transceiver(regs); | ||
| 725 | configure_baudrate(regs, config.baudrate_bps, clock_freq)?; | ||
| 726 | configure_frame_format(regs, &config); | ||
| 727 | configure_control_settings(regs, &config); | ||
| 728 | configure_fifo(regs, &config); | ||
| 729 | clear_all_status_flags(regs); | ||
| 730 | configure_flow_control(regs, enable_tx_cts, enable_rx_rts, &config); | ||
| 731 | configure_bit_order(regs, config.msb_first); | ||
| 732 | enable_transceiver(regs, enable_rx, enable_tx); | ||
| 733 | |||
| 734 | Ok(()) | ||
| 735 | } | ||
| 736 | |||
| 737 | /// Deinitialize the LPUART peripheral | ||
| 738 | pub fn deinit(&self) -> Result<()> { | ||
| 739 | let regs = self.info.regs; | ||
| 740 | |||
| 741 | // Wait for TX operations to complete | ||
| 742 | wait_for_tx_complete(regs); | ||
| 743 | |||
| 744 | // Clear all status flags | ||
| 745 | clear_all_status_flags(regs); | ||
| 746 | |||
| 747 | // Disable the module - clear all CTRL register bits | ||
| 748 | regs.ctrl().reset(); | ||
| 749 | |||
| 750 | Ok(()) | ||
| 751 | } | ||
| 752 | |||
| 753 | /// Split the Lpuart into a transmitter and receiver | ||
| 754 | pub fn split(self) -> (LpuartTx<'a, M>, LpuartRx<'a, M>) { | ||
| 755 | (self.tx, self.rx) | ||
| 756 | } | ||
| 757 | |||
| 758 | /// Split the Lpuart into a transmitter and receiver by mutable reference | ||
| 759 | pub fn split_ref(&mut self) -> (&mut LpuartTx<'a, M>, &mut LpuartRx<'a, M>) { | ||
| 760 | (&mut self.tx, &mut self.rx) | ||
| 761 | } | ||
| 762 | } | ||
| 763 | |||
| 764 | // ============================================================================ | ||
| 765 | // BLOCKING MODE IMPLEMENTATIONS | ||
| 766 | // ============================================================================ | ||
| 767 | |||
| 768 | impl<'a> Lpuart<'a, Blocking> { | ||
| 769 | /// Create a new blocking LPUART instance with RX/TX pins. | ||
| 770 | pub fn new_blocking<T: Instance>( | ||
| 771 | _inner: Peri<'a, T>, | ||
| 772 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 773 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 774 | config: Config, | ||
| 775 | ) -> Result<Self> { | ||
| 776 | // Configure the pins for LPUART usage | ||
| 777 | tx_pin.as_tx(); | ||
| 778 | rx_pin.as_rx(); | ||
| 779 | |||
| 780 | // Initialize the peripheral | ||
| 781 | Self::init::<T>(true, true, false, false, config)?; | ||
| 782 | |||
| 783 | Ok(Self { | ||
| 784 | info: T::info(), | ||
| 785 | tx: LpuartTx::new_inner(T::info(), tx_pin.into(), None, None), | ||
| 786 | rx: LpuartRx::new_inner(T::info(), rx_pin.into(), None, None), | ||
| 787 | }) | ||
| 788 | } | ||
| 789 | |||
| 790 | /// Create a new blocking LPUART instance with RX, TX and RTS/CTS flow control pins | ||
| 791 | pub fn new_blocking_with_rtscts<T: Instance>( | ||
| 792 | _inner: Peri<'a, T>, | ||
| 793 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 794 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 795 | cts_pin: Peri<'a, impl CtsPin<T>>, | ||
| 796 | rts_pin: Peri<'a, impl RtsPin<T>>, | ||
| 797 | config: Config, | ||
| 798 | ) -> Result<Self> { | ||
| 799 | // Configure the pins for LPUART usage | ||
| 800 | rx_pin.as_rx(); | ||
| 801 | tx_pin.as_tx(); | ||
| 802 | rts_pin.as_rts(); | ||
| 803 | cts_pin.as_cts(); | ||
| 804 | |||
| 805 | // Initialize the peripheral with flow control | ||
| 806 | Self::init::<T>(true, true, true, true, config)?; | ||
| 807 | |||
| 808 | Ok(Self { | ||
| 809 | info: T::info(), | ||
| 810 | rx: LpuartRx::new_inner(T::info(), rx_pin.into(), Some(rts_pin.into()), None), | ||
| 811 | tx: LpuartTx::new_inner(T::info(), tx_pin.into(), Some(cts_pin.into()), None), | ||
| 812 | }) | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | // ---------------------------------------------------------------------------- | ||
| 817 | // Blocking TX Implementation | ||
| 818 | // ---------------------------------------------------------------------------- | ||
| 819 | |||
| 820 | impl<'a, M: Mode> LpuartTx<'a, M> { | ||
| 821 | fn new_inner( | ||
| 822 | info: Info, | ||
| 823 | tx_pin: Peri<'a, AnyPin>, | ||
| 824 | cts_pin: Option<Peri<'a, AnyPin>>, | ||
| 825 | tx_dma: Option<Channel<'a>>, | ||
| 826 | ) -> Self { | ||
| 827 | Self { | ||
| 828 | info, | ||
| 829 | _tx_pin: tx_pin, | ||
| 830 | _cts_pin: cts_pin, | ||
| 831 | _tx_dma: tx_dma, | ||
| 832 | mode: PhantomData, | ||
| 833 | } | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | impl<'a> LpuartTx<'a, Blocking> { | ||
| 838 | /// Create a new blocking LPUART transmitter instance | ||
| 839 | pub fn new_blocking<T: Instance>( | ||
| 840 | _inner: Peri<'a, T>, | ||
| 841 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 842 | config: Config, | ||
| 843 | ) -> Result<Self> { | ||
| 844 | // Configure the pins for LPUART usage | ||
| 845 | tx_pin.as_tx(); | ||
| 846 | |||
| 847 | // Initialize the peripheral | ||
| 848 | Lpuart::<Blocking>::init::<T>(true, false, false, false, config)?; | ||
| 849 | |||
| 850 | Ok(Self::new_inner(T::info(), tx_pin.into(), None, None)) | ||
| 851 | } | ||
| 852 | |||
| 853 | /// Create a new blocking LPUART transmitter instance with CTS flow control | ||
| 854 | pub fn new_blocking_with_cts<T: Instance>( | ||
| 855 | _inner: Peri<'a, T>, | ||
| 856 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 857 | cts_pin: Peri<'a, impl CtsPin<T>>, | ||
| 858 | config: Config, | ||
| 859 | ) -> Result<Self> { | ||
| 860 | tx_pin.as_tx(); | ||
| 861 | cts_pin.as_cts(); | ||
| 862 | |||
| 863 | Lpuart::<Blocking>::init::<T>(true, false, true, false, config)?; | ||
| 864 | |||
| 865 | Ok(Self::new_inner(T::info(), tx_pin.into(), Some(cts_pin.into()), None)) | ||
| 866 | } | ||
| 867 | |||
| 868 | fn write_byte_internal(&mut self, byte: u8) -> Result<()> { | ||
| 869 | self.info.regs.data().modify(|_, w| unsafe { w.bits(u32::from(byte)) }); | ||
| 870 | |||
| 871 | Ok(()) | ||
| 872 | } | ||
| 873 | |||
| 874 | fn blocking_write_byte(&mut self, byte: u8) -> Result<()> { | ||
| 875 | while self.info.regs.stat().read().tdre().is_txdata() {} | ||
| 876 | self.write_byte_internal(byte) | ||
| 877 | } | ||
| 878 | |||
| 879 | fn write_byte(&mut self, byte: u8) -> Result<()> { | ||
| 880 | if self.info.regs.stat().read().tdre().is_txdata() { | ||
| 881 | Err(Error::TxFifoFull) | ||
| 882 | } else { | ||
| 883 | self.write_byte_internal(byte) | ||
| 884 | } | ||
| 885 | } | ||
| 886 | |||
| 887 | /// Write data to LPUART TX blocking execution until all data is sent. | ||
| 888 | pub fn blocking_write(&mut self, buf: &[u8]) -> Result<()> { | ||
| 889 | for x in buf { | ||
| 890 | self.blocking_write_byte(*x)?; | ||
| 891 | } | ||
| 892 | |||
| 893 | Ok(()) | ||
| 894 | } | ||
| 895 | |||
| 896 | pub fn write_str_blocking(&mut self, buf: &str) { | ||
| 897 | let _ = self.blocking_write(buf.as_bytes()); | ||
| 898 | } | ||
| 899 | |||
| 900 | /// Write data to LPUART TX without blocking. | ||
| 901 | pub fn write(&mut self, buf: &[u8]) -> Result<()> { | ||
| 902 | for x in buf { | ||
| 903 | self.write_byte(*x)?; | ||
| 904 | } | ||
| 905 | |||
| 906 | Ok(()) | ||
| 907 | } | ||
| 908 | |||
| 909 | /// Flush LPUART TX blocking execution until all data has been transmitted. | ||
| 910 | pub fn blocking_flush(&mut self) -> Result<()> { | ||
| 911 | while self.info.regs.water().read().txcount().bits() != 0 { | ||
| 912 | // Wait for TX FIFO to drain | ||
| 913 | } | ||
| 914 | |||
| 915 | // Wait for last character to shift out | ||
| 916 | while self.info.regs.stat().read().tc().is_active() { | ||
| 917 | // Wait for transmission to complete | ||
| 918 | } | ||
| 919 | |||
| 920 | Ok(()) | ||
| 921 | } | ||
| 922 | |||
| 923 | /// Flush LPUART TX. | ||
| 924 | pub fn flush(&mut self) -> Result<()> { | ||
| 925 | // Check if TX FIFO is empty | ||
| 926 | if self.info.regs.water().read().txcount().bits() != 0 { | ||
| 927 | return Err(Error::TxBusy); | ||
| 928 | } | ||
| 929 | |||
| 930 | // Check if transmission is complete | ||
| 931 | if self.info.regs.stat().read().tc().is_active() { | ||
| 932 | return Err(Error::TxBusy); | ||
| 933 | } | ||
| 934 | |||
| 935 | Ok(()) | ||
| 936 | } | ||
| 937 | } | ||
| 938 | |||
| 939 | // ---------------------------------------------------------------------------- | ||
| 940 | // Blocking RX Implementation | ||
| 941 | // ---------------------------------------------------------------------------- | ||
| 942 | |||
| 943 | impl<'a, M: Mode> LpuartRx<'a, M> { | ||
| 944 | fn new_inner( | ||
| 945 | info: Info, | ||
| 946 | rx_pin: Peri<'a, AnyPin>, | ||
| 947 | rts_pin: Option<Peri<'a, AnyPin>>, | ||
| 948 | rx_dma: Option<Channel<'a>>, | ||
| 949 | ) -> Self { | ||
| 950 | Self { | ||
| 951 | info, | ||
| 952 | _rx_pin: rx_pin, | ||
| 953 | _rts_pin: rts_pin, | ||
| 954 | _rx_dma: rx_dma, | ||
| 955 | mode: PhantomData, | ||
| 956 | } | ||
| 957 | } | ||
| 958 | } | ||
| 959 | |||
| 960 | impl<'a> LpuartRx<'a, Blocking> { | ||
| 961 | /// Create a new blocking LPUART Receiver instance | ||
| 962 | pub fn new_blocking<T: Instance>( | ||
| 963 | _inner: Peri<'a, T>, | ||
| 964 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 965 | config: Config, | ||
| 966 | ) -> Result<Self> { | ||
| 967 | rx_pin.as_rx(); | ||
| 968 | |||
| 969 | Lpuart::<Blocking>::init::<T>(false, true, false, false, config)?; | ||
| 970 | |||
| 971 | Ok(Self::new_inner(T::info(), rx_pin.into(), None, None)) | ||
| 972 | } | ||
| 973 | |||
| 974 | /// Create a new blocking LPUART Receiver instance with RTS flow control | ||
| 975 | pub fn new_blocking_with_rts<T: Instance>( | ||
| 976 | _inner: Peri<'a, T>, | ||
| 977 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 978 | rts_pin: Peri<'a, impl RtsPin<T>>, | ||
| 979 | config: Config, | ||
| 980 | ) -> Result<Self> { | ||
| 981 | rx_pin.as_rx(); | ||
| 982 | rts_pin.as_rts(); | ||
| 983 | |||
| 984 | Lpuart::<Blocking>::init::<T>(false, true, false, true, config)?; | ||
| 985 | |||
| 986 | Ok(Self::new_inner(T::info(), rx_pin.into(), Some(rts_pin.into()), None)) | ||
| 987 | } | ||
| 988 | |||
| 989 | fn read_byte_internal(&mut self) -> Result<u8> { | ||
| 990 | let data = self.info.regs.data().read(); | ||
| 991 | |||
| 992 | Ok((data.bits() & 0xFF) as u8) | ||
| 993 | } | ||
| 994 | |||
| 995 | fn read_byte(&mut self) -> Result<u8> { | ||
| 996 | check_and_clear_rx_errors(self.info.regs)?; | ||
| 997 | |||
| 998 | if !has_data(self.info.regs) { | ||
| 999 | return Err(Error::RxFifoEmpty); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | self.read_byte_internal() | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | fn blocking_read_byte(&mut self) -> Result<u8> { | ||
| 1006 | loop { | ||
| 1007 | if has_data(self.info.regs) { | ||
| 1008 | return self.read_byte_internal(); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | check_and_clear_rx_errors(self.info.regs)?; | ||
| 1012 | } | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | /// Read data from LPUART RX without blocking. | ||
| 1016 | pub fn read(&mut self, buf: &mut [u8]) -> Result<()> { | ||
| 1017 | for byte in buf.iter_mut() { | ||
| 1018 | *byte = self.read_byte()?; | ||
| 1019 | } | ||
| 1020 | Ok(()) | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | /// Read data from LPUART RX blocking execution until the buffer is filled. | ||
| 1024 | pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<()> { | ||
| 1025 | for byte in buf.iter_mut() { | ||
| 1026 | *byte = self.blocking_read_byte()?; | ||
| 1027 | } | ||
| 1028 | Ok(()) | ||
| 1029 | } | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | impl<'a> Lpuart<'a, Blocking> { | ||
| 1033 | /// Read data from LPUART RX blocking execution until the buffer is filled | ||
| 1034 | pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<()> { | ||
| 1035 | self.rx.blocking_read(buf) | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | /// Read data from LPUART RX without blocking | ||
| 1039 | pub fn read(&mut self, buf: &mut [u8]) -> Result<()> { | ||
| 1040 | self.rx.read(buf) | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | /// Write data to LPUART TX blocking execution until all data is sent | ||
| 1044 | pub fn blocking_write(&mut self, buf: &[u8]) -> Result<()> { | ||
| 1045 | self.tx.blocking_write(buf) | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | pub fn write_byte(&mut self, byte: u8) -> Result<()> { | ||
| 1049 | self.tx.write_byte(byte) | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | pub fn read_byte_blocking(&mut self) -> u8 { | ||
| 1053 | loop { | ||
| 1054 | if let Ok(b) = self.rx.read_byte() { | ||
| 1055 | return b; | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | pub fn write_str_blocking(&mut self, buf: &str) { | ||
| 1061 | self.tx.write_str_blocking(buf); | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | /// Write data to LPUART TX without blocking | ||
| 1065 | pub fn write(&mut self, buf: &[u8]) -> Result<()> { | ||
| 1066 | self.tx.write(buf) | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | /// Flush LPUART TX blocking execution until all data has been transmitted | ||
| 1070 | pub fn blocking_flush(&mut self) -> Result<()> { | ||
| 1071 | self.tx.blocking_flush() | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | /// Flush LPUART TX without blocking | ||
| 1075 | pub fn flush(&mut self) -> Result<()> { | ||
| 1076 | self.tx.flush() | ||
| 1077 | } | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | // ============================================================================ | ||
| 1081 | // ASYNC MODE IMPLEMENTATIONS | ||
| 1082 | // ============================================================================ | ||
| 1083 | |||
| 1084 | // TODO: Implement async mode for LPUART | ||
| 1085 | |||
| 1086 | // ============================================================================ | ||
| 1087 | // EMBEDDED-HAL 0.2 TRAIT IMPLEMENTATIONS | ||
| 1088 | // ============================================================================ | ||
| 1089 | |||
| 1090 | impl embedded_hal_02::serial::Read<u8> for LpuartRx<'_, Blocking> { | ||
| 1091 | type Error = Error; | ||
| 1092 | |||
| 1093 | fn read(&mut self) -> core::result::Result<u8, nb::Error<Self::Error>> { | ||
| 1094 | let mut buf = [0; 1]; | ||
| 1095 | match self.read(&mut buf) { | ||
| 1096 | Ok(_) => Ok(buf[0]), | ||
| 1097 | Err(Error::RxFifoEmpty) => Err(nb::Error::WouldBlock), | ||
| 1098 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1099 | } | ||
| 1100 | } | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | impl embedded_hal_02::serial::Write<u8> for LpuartTx<'_, Blocking> { | ||
| 1104 | type Error = Error; | ||
| 1105 | |||
| 1106 | fn write(&mut self, word: u8) -> core::result::Result<(), nb::Error<Self::Error>> { | ||
| 1107 | match self.write(&[word]) { | ||
| 1108 | Ok(_) => Ok(()), | ||
| 1109 | Err(Error::TxFifoFull) => Err(nb::Error::WouldBlock), | ||
| 1110 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1111 | } | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | fn flush(&mut self) -> core::result::Result<(), nb::Error<Self::Error>> { | ||
| 1115 | match self.flush() { | ||
| 1116 | Ok(_) => Ok(()), | ||
| 1117 | Err(Error::TxBusy) => Err(nb::Error::WouldBlock), | ||
| 1118 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1119 | } | ||
| 1120 | } | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | impl embedded_hal_02::blocking::serial::Write<u8> for LpuartTx<'_, Blocking> { | ||
| 1124 | type Error = Error; | ||
| 1125 | |||
| 1126 | fn bwrite_all(&mut self, buffer: &[u8]) -> core::result::Result<(), Self::Error> { | ||
| 1127 | self.blocking_write(buffer) | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | fn bflush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 1131 | self.blocking_flush() | ||
| 1132 | } | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | impl embedded_hal_02::serial::Read<u8> for Lpuart<'_, Blocking> { | ||
| 1136 | type Error = Error; | ||
| 1137 | |||
| 1138 | fn read(&mut self) -> core::result::Result<u8, nb::Error<Self::Error>> { | ||
| 1139 | embedded_hal_02::serial::Read::read(&mut self.rx) | ||
| 1140 | } | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | impl embedded_hal_02::serial::Write<u8> for Lpuart<'_, Blocking> { | ||
| 1144 | type Error = Error; | ||
| 1145 | |||
| 1146 | fn write(&mut self, word: u8) -> core::result::Result<(), nb::Error<Self::Error>> { | ||
| 1147 | embedded_hal_02::serial::Write::write(&mut self.tx, word) | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | fn flush(&mut self) -> core::result::Result<(), nb::Error<Self::Error>> { | ||
| 1151 | embedded_hal_02::serial::Write::flush(&mut self.tx) | ||
| 1152 | } | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | impl embedded_hal_02::blocking::serial::Write<u8> for Lpuart<'_, Blocking> { | ||
| 1156 | type Error = Error; | ||
| 1157 | |||
| 1158 | fn bwrite_all(&mut self, buffer: &[u8]) -> core::result::Result<(), Self::Error> { | ||
| 1159 | self.blocking_write(buffer) | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | fn bflush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 1163 | self.blocking_flush() | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | // ============================================================================ | ||
| 1168 | // EMBEDDED-HAL-NB TRAIT IMPLEMENTATIONS | ||
| 1169 | // ============================================================================ | ||
| 1170 | |||
| 1171 | impl embedded_hal_nb::serial::Error for Error { | ||
| 1172 | fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { | ||
| 1173 | match *self { | ||
| 1174 | Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, | ||
| 1175 | Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, | ||
| 1176 | Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, | ||
| 1177 | Self::Noise => embedded_hal_nb::serial::ErrorKind::Noise, | ||
| 1178 | _ => embedded_hal_nb::serial::ErrorKind::Other, | ||
| 1179 | } | ||
| 1180 | } | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | impl embedded_hal_nb::serial::ErrorType for LpuartRx<'_, Blocking> { | ||
| 1184 | type Error = Error; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | impl embedded_hal_nb::serial::ErrorType for LpuartTx<'_, Blocking> { | ||
| 1188 | type Error = Error; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | impl embedded_hal_nb::serial::ErrorType for Lpuart<'_, Blocking> { | ||
| 1192 | type Error = Error; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | impl embedded_hal_nb::serial::Read for LpuartRx<'_, Blocking> { | ||
| 1196 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | ||
| 1197 | let mut buf = [0; 1]; | ||
| 1198 | match self.read(&mut buf) { | ||
| 1199 | Ok(_) => Ok(buf[0]), | ||
| 1200 | Err(Error::RxFifoEmpty) => Err(nb::Error::WouldBlock), | ||
| 1201 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1202 | } | ||
| 1203 | } | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | impl embedded_hal_nb::serial::Write for LpuartTx<'_, Blocking> { | ||
| 1207 | fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { | ||
| 1208 | match self.write(&[word]) { | ||
| 1209 | Ok(_) => Ok(()), | ||
| 1210 | Err(Error::TxFifoFull) => Err(nb::Error::WouldBlock), | ||
| 1211 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 1216 | match self.flush() { | ||
| 1217 | Ok(_) => Ok(()), | ||
| 1218 | Err(Error::TxBusy) => Err(nb::Error::WouldBlock), | ||
| 1219 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1220 | } | ||
| 1221 | } | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | impl embedded_hal_nb::serial::Read for Lpuart<'_, Blocking> { | ||
| 1225 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | ||
| 1226 | embedded_hal_nb::serial::Read::read(&mut self.rx) | ||
| 1227 | } | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | impl embedded_hal_nb::serial::Write for Lpuart<'_, Blocking> { | ||
| 1231 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | ||
| 1232 | embedded_hal_nb::serial::Write::write(&mut self.tx, char) | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 1236 | embedded_hal_nb::serial::Write::flush(&mut self.tx) | ||
| 1237 | } | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | // ============================================================================ | ||
| 1241 | // EMBEDDED-IO TRAIT IMPLEMENTATIONS | ||
| 1242 | // ============================================================================ | ||
| 1243 | |||
| 1244 | impl embedded_io::Error for Error { | ||
| 1245 | fn kind(&self) -> embedded_io::ErrorKind { | ||
| 1246 | embedded_io::ErrorKind::Other | ||
| 1247 | } | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | impl embedded_io::ErrorType for LpuartRx<'_, Blocking> { | ||
| 1251 | type Error = Error; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | impl embedded_io::ErrorType for LpuartTx<'_, Blocking> { | ||
| 1255 | type Error = Error; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | impl embedded_io::ErrorType for Lpuart<'_, Blocking> { | ||
| 1259 | type Error = Error; | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | impl embedded_io::Read for LpuartRx<'_, Blocking> { | ||
| 1263 | fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> { | ||
| 1264 | self.blocking_read(buf).map(|_| buf.len()) | ||
| 1265 | } | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | impl embedded_io::Write for LpuartTx<'_, Blocking> { | ||
| 1269 | fn write(&mut self, buf: &[u8]) -> core::result::Result<usize, Self::Error> { | ||
| 1270 | self.blocking_write(buf).map(|_| buf.len()) | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | fn flush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 1274 | self.blocking_flush() | ||
| 1275 | } | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | impl embedded_io::Read for Lpuart<'_, Blocking> { | ||
| 1279 | fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> { | ||
| 1280 | embedded_io::Read::read(&mut self.rx, buf) | ||
| 1281 | } | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | impl embedded_io::Write for Lpuart<'_, Blocking> { | ||
| 1285 | fn write(&mut self, buf: &[u8]) -> core::result::Result<usize, Self::Error> { | ||
| 1286 | embedded_io::Write::write(&mut self.tx, buf) | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | fn flush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 1290 | embedded_io::Write::flush(&mut self.tx) | ||
| 1291 | } | ||
| 1292 | } | ||
diff --git a/embassy-mcxa/src/ostimer.rs b/embassy-mcxa/src/ostimer.rs new file mode 100644 index 000000000..c51812e3d --- /dev/null +++ b/embassy-mcxa/src/ostimer.rs | |||
| @@ -0,0 +1,745 @@ | |||
| 1 | //! # OSTIMER Driver with Robustness Features | ||
| 2 | //! | ||
| 3 | //! This module provides an async timer driver for the NXP MCXA276 OSTIMER peripheral | ||
| 4 | //! with protection against race conditions and timer rollover issues. | ||
| 5 | //! | ||
| 6 | //! ## Features | ||
| 7 | //! | ||
| 8 | //! - Async timing with embassy-time integration | ||
| 9 | //! - Gray code counter handling (42-bit counter) | ||
| 10 | //! - Interrupt-driven wakeups | ||
| 11 | //! - Configurable interrupt priority | ||
| 12 | //! - **Race condition protection**: Critical sections and atomic operations | ||
| 13 | //! - **Timer rollover handling**: Bounds checking and rollover prevention | ||
| 14 | //! | ||
| 15 | //! ## Clock Frequency Configuration | ||
| 16 | //! | ||
| 17 | //! The OSTIMER frequency depends on your system's clock configuration. You must provide | ||
| 18 | //! the actual frequency when calling `time_driver::init()`. | ||
| 19 | //! | ||
| 20 | //! ## Race Condition Protection | ||
| 21 | //! - Critical sections in interrupt handlers prevent concurrent access | ||
| 22 | //! - Atomic register operations with memory barriers | ||
| 23 | //! - Proper interrupt flag clearing and validation | ||
| 24 | //! | ||
| 25 | //! ## Timer Rollover Handling | ||
| 26 | //! - Bounds checking prevents scheduling beyond timer capacity | ||
| 27 | //! - Immediate wake for timestamps that would cause rollover issues | ||
| 28 | #![allow(dead_code)] | ||
| 29 | |||
| 30 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 31 | |||
| 32 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 33 | |||
| 34 | use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel}; | ||
| 35 | use crate::clocks::{assert_reset, enable_and_reset, is_reset_released, release_reset, Gate, PoweredClock}; | ||
| 36 | use crate::interrupt::InterruptExt; | ||
| 37 | use crate::pac; | ||
| 38 | |||
| 39 | // PAC defines the shared RegisterBlock under `ostimer0`. | ||
| 40 | type Regs = pac::ostimer0::RegisterBlock; | ||
| 41 | |||
| 42 | // OSTIMER EVTIMER register layout constants | ||
| 43 | /// Total width of the EVTIMER counter in bits (42 bits total) | ||
| 44 | const EVTIMER_TOTAL_BITS: u32 = 42; | ||
| 45 | /// Width of the low part of EVTIMER (bits 31:0) | ||
| 46 | const EVTIMER_LO_BITS: u32 = 32; | ||
| 47 | /// Width of the high part of EVTIMER (bits 41:32) | ||
| 48 | const EVTIMER_HI_BITS: u32 = 10; | ||
| 49 | /// Bit position where high part starts in the combined 64-bit value | ||
| 50 | const EVTIMER_HI_SHIFT: u32 = 32; | ||
| 51 | |||
| 52 | /// Bit mask for the high part of EVTIMER | ||
| 53 | const EVTIMER_HI_MASK: u16 = (1 << EVTIMER_HI_BITS) - 1; | ||
| 54 | |||
| 55 | /// Maximum value for MATCH_L register (32-bit) | ||
| 56 | const MATCH_L_MAX: u32 = u32::MAX; | ||
| 57 | /// Maximum value for MATCH_H register (10-bit) | ||
| 58 | const MATCH_H_MAX: u16 = EVTIMER_HI_MASK; | ||
| 59 | |||
| 60 | /// Bit mask for extracting the low 32 bits from a 64-bit value | ||
| 61 | const LOW_32_BIT_MASK: u64 = u32::MAX as u64; | ||
| 62 | |||
| 63 | /// Gray code conversion bit shifts (most significant to least) | ||
| 64 | const GRAY_CONVERSION_SHIFTS: [u32; 6] = [32, 16, 8, 4, 2, 1]; | ||
| 65 | |||
| 66 | /// Maximum timer value before rollover (2^42 - 1 ticks) | ||
| 67 | /// Actual rollover time depends on the configured clock frequency | ||
| 68 | const TIMER_MAX_VALUE: u64 = (1u64 << EVTIMER_TOTAL_BITS) - 1; | ||
| 69 | |||
| 70 | /// Threshold for detecting timer rollover in comparisons (1 second at 1MHz) | ||
| 71 | const TIMER_ROLLOVER_THRESHOLD: u64 = 1_000_000; | ||
| 72 | |||
| 73 | /// Common default interrupt priority for OSTIMER | ||
| 74 | const DEFAULT_INTERRUPT_PRIORITY: u8 = 3; | ||
| 75 | |||
| 76 | // Global alarm state for interrupt handling | ||
| 77 | static ALARM_ACTIVE: AtomicBool = AtomicBool::new(false); | ||
| 78 | static mut ALARM_CALLBACK: Option<fn()> = None; | ||
| 79 | static mut ALARM_FLAG: Option<*const AtomicBool> = None; | ||
| 80 | static mut ALARM_TARGET_TIME: u64 = 0; | ||
| 81 | |||
| 82 | /// Number of tight spin iterations between elapsed time checks while waiting for MATCH writes to return to the idle (0) state. | ||
| 83 | const MATCH_WRITE_READY_SPINS: usize = 512; | ||
| 84 | /// Maximum time (in OSTIMER ticks) to wait for MATCH registers to become writable (~5 ms at 1 MHz). | ||
| 85 | const MATCH_WRITE_READY_TIMEOUT_TICKS: u64 = 5_000; | ||
| 86 | /// Short stabilization delay executed after toggling the MRCC reset line to let the OSTIMER bus interface settle. | ||
| 87 | const RESET_STABILIZE_SPINS: usize = 512; | ||
| 88 | |||
| 89 | pub(super) fn wait_for_match_write_ready(r: &Regs) -> bool { | ||
| 90 | let start = now_ticks_read(); | ||
| 91 | let mut spin_budget = 0usize; | ||
| 92 | |||
| 93 | loop { | ||
| 94 | if r.osevent_ctrl().read().match_wr_rdy().bit_is_clear() { | ||
| 95 | return true; | ||
| 96 | } | ||
| 97 | |||
| 98 | cortex_m::asm::nop(); | ||
| 99 | spin_budget += 1; | ||
| 100 | |||
| 101 | if spin_budget >= MATCH_WRITE_READY_SPINS { | ||
| 102 | spin_budget = 0; | ||
| 103 | |||
| 104 | let elapsed = now_ticks_read().wrapping_sub(start); | ||
| 105 | if elapsed >= MATCH_WRITE_READY_TIMEOUT_TICKS { | ||
| 106 | return false; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | pub(super) fn wait_for_match_write_complete(r: &Regs) -> bool { | ||
| 113 | let start = now_ticks_read(); | ||
| 114 | let mut spin_budget = 0usize; | ||
| 115 | |||
| 116 | loop { | ||
| 117 | if r.osevent_ctrl().read().match_wr_rdy().bit_is_clear() { | ||
| 118 | return true; | ||
| 119 | } | ||
| 120 | |||
| 121 | cortex_m::asm::nop(); | ||
| 122 | spin_budget += 1; | ||
| 123 | |||
| 124 | if spin_budget >= MATCH_WRITE_READY_SPINS { | ||
| 125 | spin_budget = 0; | ||
| 126 | |||
| 127 | let elapsed = now_ticks_read().wrapping_sub(start); | ||
| 128 | if elapsed >= MATCH_WRITE_READY_TIMEOUT_TICKS { | ||
| 129 | return false; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | fn prime_match_registers(r: &Regs) { | ||
| 136 | // Disable the interrupt, clear any pending flag, then wait until the MATCH registers are writable. | ||
| 137 | r.osevent_ctrl() | ||
| 138 | .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); | ||
| 139 | |||
| 140 | if wait_for_match_write_ready(r) { | ||
| 141 | r.match_l().write(|w| unsafe { w.match_value().bits(MATCH_L_MAX) }); | ||
| 142 | r.match_h().write(|w| unsafe { w.match_value().bits(MATCH_H_MAX) }); | ||
| 143 | let _ = wait_for_match_write_complete(r); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | /// Single-shot alarm functionality for OSTIMER | ||
| 148 | pub struct Alarm<'d> { | ||
| 149 | /// Whether the alarm is currently active | ||
| 150 | active: AtomicBool, | ||
| 151 | /// Callback to execute when alarm expires (optional) | ||
| 152 | callback: Option<fn()>, | ||
| 153 | /// Flag that gets set when alarm expires (optional) | ||
| 154 | flag: Option<&'d AtomicBool>, | ||
| 155 | _phantom: core::marker::PhantomData<&'d mut ()>, | ||
| 156 | } | ||
| 157 | |||
| 158 | impl<'d> Default for Alarm<'d> { | ||
| 159 | fn default() -> Self { | ||
| 160 | Self::new() | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | impl<'d> Alarm<'d> { | ||
| 165 | /// Create a new alarm instance | ||
| 166 | pub fn new() -> Self { | ||
| 167 | Self { | ||
| 168 | active: AtomicBool::new(false), | ||
| 169 | callback: None, | ||
| 170 | flag: None, | ||
| 171 | _phantom: core::marker::PhantomData, | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | /// Set a callback that will be executed when the alarm expires | ||
| 176 | /// Note: Due to interrupt handler constraints, callbacks must be static function pointers | ||
| 177 | pub fn with_callback(mut self, callback: fn()) -> Self { | ||
| 178 | self.callback = Some(callback); | ||
| 179 | self | ||
| 180 | } | ||
| 181 | |||
| 182 | /// Set a flag that will be set to true when the alarm expires | ||
| 183 | pub fn with_flag(mut self, flag: &'d AtomicBool) -> Self { | ||
| 184 | self.flag = Some(flag); | ||
| 185 | self | ||
| 186 | } | ||
| 187 | |||
| 188 | /// Check if the alarm is currently active | ||
| 189 | pub fn is_active(&self) -> bool { | ||
| 190 | self.active.load(Ordering::Acquire) | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Cancel the alarm if it's active | ||
| 194 | pub fn cancel(&self) { | ||
| 195 | self.active.store(false, Ordering::Release); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | /// Configuration for Ostimer::new() | ||
| 200 | #[derive(Copy, Clone)] | ||
| 201 | pub struct Config { | ||
| 202 | /// Initialize MATCH registers to their max values and mask/clear the interrupt flag. | ||
| 203 | pub init_match_max: bool, | ||
| 204 | pub power: PoweredClock, | ||
| 205 | pub source: OstimerClockSel, | ||
| 206 | } | ||
| 207 | |||
| 208 | impl Default for Config { | ||
| 209 | fn default() -> Self { | ||
| 210 | Self { | ||
| 211 | init_match_max: true, | ||
| 212 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 213 | source: OstimerClockSel::Clk1M, | ||
| 214 | } | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | /// OSTIMER peripheral instance | ||
| 219 | pub struct Ostimer<'d, I: Instance> { | ||
| 220 | _inst: core::marker::PhantomData<I>, | ||
| 221 | clock_frequency_hz: u64, | ||
| 222 | _phantom: core::marker::PhantomData<&'d mut ()>, | ||
| 223 | } | ||
| 224 | |||
| 225 | impl<'d, I: Instance> Ostimer<'d, I> { | ||
| 226 | /// Construct OSTIMER handle. | ||
| 227 | /// Requires clocks for the instance to be enabled by the board before calling. | ||
| 228 | /// Does not enable NVIC or INTENA; use time_driver::init() for async operation. | ||
| 229 | pub fn new(_inst: Peri<'d, I>, cfg: Config) -> Self { | ||
| 230 | let clock_freq = unsafe { | ||
| 231 | enable_and_reset::<I>(&OsTimerConfig { | ||
| 232 | power: cfg.power, | ||
| 233 | source: cfg.source, | ||
| 234 | }) | ||
| 235 | .expect("Enabling OsTimer clock should not fail") | ||
| 236 | }; | ||
| 237 | |||
| 238 | assert!(clock_freq > 0, "OSTIMER frequency must be greater than 0"); | ||
| 239 | |||
| 240 | if cfg.init_match_max { | ||
| 241 | let r: &Regs = unsafe { &*I::ptr() }; | ||
| 242 | // Mask INTENA, clear pending flag, and set MATCH to max so no spurious IRQ fires. | ||
| 243 | prime_match_registers(r); | ||
| 244 | } | ||
| 245 | |||
| 246 | Self { | ||
| 247 | _inst: core::marker::PhantomData, | ||
| 248 | clock_frequency_hz: clock_freq as u64, | ||
| 249 | _phantom: core::marker::PhantomData, | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | /// Get the configured clock frequency in Hz | ||
| 254 | pub fn clock_frequency_hz(&self) -> u64 { | ||
| 255 | self.clock_frequency_hz | ||
| 256 | } | ||
| 257 | |||
| 258 | /// Read the current timer counter value in timer ticks | ||
| 259 | /// | ||
| 260 | /// # Returns | ||
| 261 | /// Current timer counter value as a 64-bit unsigned integer | ||
| 262 | pub fn now(&self) -> u64 { | ||
| 263 | now_ticks_read() | ||
| 264 | } | ||
| 265 | |||
| 266 | /// Reset the timer counter to zero | ||
| 267 | /// | ||
| 268 | /// This performs a hardware reset of the OSTIMER peripheral, which will reset | ||
| 269 | /// the counter to zero and clear any pending interrupts. Note that this will | ||
| 270 | /// affect all timer operations including embassy-time. | ||
| 271 | /// | ||
| 272 | /// # Safety | ||
| 273 | /// This operation will reset the entire OSTIMER peripheral. Any active alarms | ||
| 274 | /// or time_driver operations will be disrupted. Use with caution. | ||
| 275 | pub fn reset(&self, _peripherals: &crate::pac::Peripherals) { | ||
| 276 | critical_section::with(|_| { | ||
| 277 | let r: &Regs = unsafe { &*I::ptr() }; | ||
| 278 | |||
| 279 | // Mask the peripheral interrupt flag before we toggle the reset line so that | ||
| 280 | // no new NVIC activity races with the reset sequence. | ||
| 281 | r.osevent_ctrl() | ||
| 282 | .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); | ||
| 283 | |||
| 284 | unsafe { | ||
| 285 | assert_reset::<I>(); | ||
| 286 | |||
| 287 | for _ in 0..RESET_STABILIZE_SPINS { | ||
| 288 | cortex_m::asm::nop(); | ||
| 289 | } | ||
| 290 | |||
| 291 | release_reset::<I>(); | ||
| 292 | |||
| 293 | while !is_reset_released::<I>() { | ||
| 294 | cortex_m::asm::nop(); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | for _ in 0..RESET_STABILIZE_SPINS { | ||
| 299 | cortex_m::asm::nop(); | ||
| 300 | } | ||
| 301 | |||
| 302 | // Clear alarm bookkeeping before re-arming MATCH registers. | ||
| 303 | ALARM_ACTIVE.store(false, Ordering::Release); | ||
| 304 | unsafe { | ||
| 305 | ALARM_TARGET_TIME = 0; | ||
| 306 | ALARM_CALLBACK = None; | ||
| 307 | ALARM_FLAG = None; | ||
| 308 | } | ||
| 309 | |||
| 310 | prime_match_registers(r); | ||
| 311 | }); | ||
| 312 | |||
| 313 | // Ensure no stale OS_EVENT request remains pending after the reset sequence. | ||
| 314 | crate::interrupt::OS_EVENT.unpend(); | ||
| 315 | } | ||
| 316 | |||
| 317 | /// Schedule a single-shot alarm to expire after the specified delay in microseconds | ||
| 318 | /// | ||
| 319 | /// # Parameters | ||
| 320 | /// * `alarm` - The alarm instance to schedule | ||
| 321 | /// * `delay_us` - Delay in microseconds from now | ||
| 322 | /// | ||
| 323 | /// # Returns | ||
| 324 | /// `true` if the alarm was scheduled successfully, `false` if it would exceed timer capacity | ||
| 325 | pub fn schedule_alarm_delay(&self, alarm: &Alarm, delay_us: u64) -> bool { | ||
| 326 | let delay_ticks = (delay_us * self.clock_frequency_hz) / 1_000_000; | ||
| 327 | let target_time = now_ticks_read() + delay_ticks; | ||
| 328 | self.schedule_alarm_at(alarm, target_time) | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Schedule a single-shot alarm to expire at the specified absolute time in timer ticks | ||
| 332 | /// | ||
| 333 | /// # Parameters | ||
| 334 | /// * `alarm` - The alarm instance to schedule | ||
| 335 | /// * `target_ticks` - Absolute time in timer ticks when the alarm should expire | ||
| 336 | /// | ||
| 337 | /// # Returns | ||
| 338 | /// `true` if the alarm was scheduled successfully, `false` if it would exceed timer capacity | ||
| 339 | pub fn schedule_alarm_at(&self, alarm: &Alarm, target_ticks: u64) -> bool { | ||
| 340 | let now = now_ticks_read(); | ||
| 341 | |||
| 342 | // Check if target time is in the past | ||
| 343 | if target_ticks <= now { | ||
| 344 | // Execute callback immediately if alarm was supposed to be active | ||
| 345 | if alarm.active.load(Ordering::Acquire) { | ||
| 346 | alarm.active.store(false, Ordering::Release); | ||
| 347 | if let Some(callback) = alarm.callback { | ||
| 348 | callback(); | ||
| 349 | } | ||
| 350 | if let Some(flag) = &alarm.flag { | ||
| 351 | flag.store(true, Ordering::Release); | ||
| 352 | } | ||
| 353 | } | ||
| 354 | return true; | ||
| 355 | } | ||
| 356 | |||
| 357 | // Check for timer rollover | ||
| 358 | let max_future = now + TIMER_MAX_VALUE; | ||
| 359 | if target_ticks > max_future { | ||
| 360 | return false; // Would exceed timer capacity | ||
| 361 | } | ||
| 362 | |||
| 363 | // Program the timer | ||
| 364 | let r: &Regs = unsafe { &*I::ptr() }; | ||
| 365 | |||
| 366 | critical_section::with(|_| { | ||
| 367 | // Disable interrupt and clear flag | ||
| 368 | r.osevent_ctrl() | ||
| 369 | .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); | ||
| 370 | |||
| 371 | if !wait_for_match_write_ready(r) { | ||
| 372 | prime_match_registers(r); | ||
| 373 | |||
| 374 | if !wait_for_match_write_ready(r) { | ||
| 375 | alarm.active.store(false, Ordering::Release); | ||
| 376 | ALARM_ACTIVE.store(false, Ordering::Release); | ||
| 377 | unsafe { | ||
| 378 | ALARM_TARGET_TIME = 0; | ||
| 379 | ALARM_CALLBACK = None; | ||
| 380 | ALARM_FLAG = None; | ||
| 381 | } | ||
| 382 | return false; | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | // Mark alarm as active now that we know the MATCH registers are writable | ||
| 387 | alarm.active.store(true, Ordering::Release); | ||
| 388 | |||
| 389 | // Set global alarm state for interrupt handler | ||
| 390 | ALARM_ACTIVE.store(true, Ordering::Release); | ||
| 391 | unsafe { | ||
| 392 | ALARM_TARGET_TIME = target_ticks; | ||
| 393 | ALARM_CALLBACK = alarm.callback; | ||
| 394 | ALARM_FLAG = alarm.flag.map(|f| f as *const AtomicBool); | ||
| 395 | } | ||
| 396 | |||
| 397 | // Program MATCH registers (Gray-coded) | ||
| 398 | let gray = bin_to_gray(target_ticks); | ||
| 399 | let l = (gray & LOW_32_BIT_MASK) as u32; | ||
| 400 | let h = (((gray >> EVTIMER_HI_SHIFT) as u16) & EVTIMER_HI_MASK) as u16; | ||
| 401 | |||
| 402 | r.match_l().write(|w| unsafe { w.match_value().bits(l) }); | ||
| 403 | r.match_h().write(|w| unsafe { w.match_value().bits(h) }); | ||
| 404 | |||
| 405 | if !wait_for_match_write_complete(r) { | ||
| 406 | alarm.active.store(false, Ordering::Release); | ||
| 407 | ALARM_ACTIVE.store(false, Ordering::Release); | ||
| 408 | unsafe { | ||
| 409 | ALARM_TARGET_TIME = 0; | ||
| 410 | ALARM_CALLBACK = None; | ||
| 411 | ALARM_FLAG = None; | ||
| 412 | } | ||
| 413 | return false; | ||
| 414 | } | ||
| 415 | |||
| 416 | let now_after_program = now_ticks_read(); | ||
| 417 | let intrflag_set = r.osevent_ctrl().read().ostimer_intrflag().bit_is_set(); | ||
| 418 | if now_after_program >= target_ticks && !intrflag_set { | ||
| 419 | alarm.active.store(false, Ordering::Release); | ||
| 420 | ALARM_ACTIVE.store(false, Ordering::Release); | ||
| 421 | unsafe { | ||
| 422 | ALARM_TARGET_TIME = 0; | ||
| 423 | ALARM_CALLBACK = None; | ||
| 424 | ALARM_FLAG = None; | ||
| 425 | } | ||
| 426 | return false; | ||
| 427 | } | ||
| 428 | |||
| 429 | // Enable interrupt | ||
| 430 | r.osevent_ctrl().write(|w| w.ostimer_intena().set_bit()); | ||
| 431 | |||
| 432 | true | ||
| 433 | }) | ||
| 434 | } | ||
| 435 | |||
| 436 | /// Cancel any active alarm | ||
| 437 | pub fn cancel_alarm(&self, alarm: &Alarm) { | ||
| 438 | critical_section::with(|_| { | ||
| 439 | alarm.cancel(); | ||
| 440 | |||
| 441 | // Clear global alarm state | ||
| 442 | ALARM_ACTIVE.store(false, Ordering::Release); | ||
| 443 | unsafe { ALARM_TARGET_TIME = 0 }; | ||
| 444 | |||
| 445 | // Reset MATCH registers to maximum values to prevent spurious interrupts | ||
| 446 | let r: &Regs = unsafe { &*I::ptr() }; | ||
| 447 | prime_match_registers(r); | ||
| 448 | }); | ||
| 449 | } | ||
| 450 | |||
| 451 | /// Check if an alarm has expired (call this from your interrupt handler) | ||
| 452 | /// Returns true if the alarm was active and has now expired | ||
| 453 | pub fn check_alarm_expired(&self, alarm: &Alarm) -> bool { | ||
| 454 | if alarm.active.load(Ordering::Acquire) { | ||
| 455 | alarm.active.store(false, Ordering::Release); | ||
| 456 | |||
| 457 | // Execute callback | ||
| 458 | if let Some(callback) = alarm.callback { | ||
| 459 | callback(); | ||
| 460 | } | ||
| 461 | |||
| 462 | // Set flag | ||
| 463 | if let Some(flag) = &alarm.flag { | ||
| 464 | flag.store(true, Ordering::Release); | ||
| 465 | } | ||
| 466 | |||
| 467 | true | ||
| 468 | } else { | ||
| 469 | false | ||
| 470 | } | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | /// Read current EVTIMER (Gray-coded) and convert to binary ticks. | ||
| 475 | #[inline(always)] | ||
| 476 | fn now_ticks_read() -> u64 { | ||
| 477 | let r: &Regs = unsafe { &*pac::Ostimer0::ptr() }; | ||
| 478 | |||
| 479 | // Read high then low to minimize incoherent snapshots | ||
| 480 | let hi = (r.evtimerh().read().evtimer_count_value().bits() as u64) & (EVTIMER_HI_MASK as u64); | ||
| 481 | let lo = r.evtimerl().read().evtimer_count_value().bits() as u64; | ||
| 482 | // Combine and convert from Gray code to binary | ||
| 483 | let gray = lo | (hi << EVTIMER_HI_SHIFT); | ||
| 484 | gray_to_bin(gray) | ||
| 485 | } | ||
| 486 | |||
| 487 | // Instance trait like other drivers, providing a PAC pointer for this OSTIMER instance | ||
| 488 | pub trait Instance: Gate<MrccPeriphConfig = OsTimerConfig> + PeripheralType { | ||
| 489 | fn ptr() -> *const Regs; | ||
| 490 | } | ||
| 491 | |||
| 492 | #[cfg(not(feature = "time"))] | ||
| 493 | impl Instance for crate::peripherals::OSTIMER0 { | ||
| 494 | #[inline(always)] | ||
| 495 | fn ptr() -> *const Regs { | ||
| 496 | pac::Ostimer0::ptr() | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | #[inline(always)] | ||
| 501 | fn bin_to_gray(x: u64) -> u64 { | ||
| 502 | x ^ (x >> 1) | ||
| 503 | } | ||
| 504 | |||
| 505 | #[inline(always)] | ||
| 506 | fn gray_to_bin(gray: u64) -> u64 { | ||
| 507 | // More efficient iterative conversion using predefined shifts | ||
| 508 | let mut bin = gray; | ||
| 509 | for &shift in &GRAY_CONVERSION_SHIFTS { | ||
| 510 | bin ^= bin >> shift; | ||
| 511 | } | ||
| 512 | bin | ||
| 513 | } | ||
| 514 | |||
| 515 | #[cfg(feature = "time")] | ||
| 516 | pub mod time_driver { | ||
| 517 | use core::sync::atomic::Ordering; | ||
| 518 | use core::task::Waker; | ||
| 519 | |||
| 520 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 521 | use embassy_time_driver as etd; | ||
| 522 | |||
| 523 | use super::{ | ||
| 524 | bin_to_gray, now_ticks_read, Regs, ALARM_ACTIVE, ALARM_CALLBACK, ALARM_FLAG, ALARM_TARGET_TIME, | ||
| 525 | EVTIMER_HI_MASK, EVTIMER_HI_SHIFT, LOW_32_BIT_MASK, | ||
| 526 | }; | ||
| 527 | use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel}; | ||
| 528 | use crate::clocks::{enable_and_reset, PoweredClock}; | ||
| 529 | use crate::pac; | ||
| 530 | |||
| 531 | #[allow(non_camel_case_types)] | ||
| 532 | pub(crate) struct _OSTIMER0_TIME_DRIVER { | ||
| 533 | _x: (), | ||
| 534 | } | ||
| 535 | |||
| 536 | // #[cfg(feature = "time")] | ||
| 537 | // impl_cc_gate!(_OSTIMER0_TIME_DRIVER, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig); | ||
| 538 | |||
| 539 | impl crate::clocks::Gate for _OSTIMER0_TIME_DRIVER { | ||
| 540 | type MrccPeriphConfig = crate::clocks::periph_helpers::OsTimerConfig; | ||
| 541 | |||
| 542 | #[inline] | ||
| 543 | unsafe fn enable_clock() { | ||
| 544 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 545 | mrcc.mrcc_glb_cc1().modify(|_, w| w.ostimer0().enabled()); | ||
| 546 | } | ||
| 547 | |||
| 548 | #[inline] | ||
| 549 | unsafe fn disable_clock() { | ||
| 550 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 551 | mrcc.mrcc_glb_cc1().modify(|_r, w| w.ostimer0().disabled()); | ||
| 552 | } | ||
| 553 | |||
| 554 | #[inline] | ||
| 555 | fn is_clock_enabled() -> bool { | ||
| 556 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 557 | mrcc.mrcc_glb_cc1().read().ostimer0().is_enabled() | ||
| 558 | } | ||
| 559 | |||
| 560 | #[inline] | ||
| 561 | unsafe fn release_reset() { | ||
| 562 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 563 | mrcc.mrcc_glb_rst1().modify(|_, w| w.ostimer0().enabled()); | ||
| 564 | } | ||
| 565 | |||
| 566 | #[inline] | ||
| 567 | unsafe fn assert_reset() { | ||
| 568 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 569 | mrcc.mrcc_glb_rst1().modify(|_, w| w.ostimer0().disabled()); | ||
| 570 | } | ||
| 571 | |||
| 572 | #[inline] | ||
| 573 | fn is_reset_released() -> bool { | ||
| 574 | let mrcc = unsafe { pac::Mrcc0::steal() }; | ||
| 575 | mrcc.mrcc_glb_rst1().read().ostimer0().is_enabled() | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 579 | pub struct Driver; | ||
| 580 | static TIMER_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 581 | |||
| 582 | impl etd::Driver for Driver { | ||
| 583 | fn now(&self) -> u64 { | ||
| 584 | // Use the hardware counter (frequency configured in init) | ||
| 585 | super::now_ticks_read() | ||
| 586 | } | ||
| 587 | |||
| 588 | fn schedule_wake(&self, timestamp: u64, waker: &Waker) { | ||
| 589 | let now = self.now(); | ||
| 590 | |||
| 591 | // If timestamp is in the past or very close to now, wake immediately | ||
| 592 | if timestamp <= now { | ||
| 593 | waker.wake_by_ref(); | ||
| 594 | return; | ||
| 595 | } | ||
| 596 | |||
| 597 | // Prevent scheduling too far in the future (beyond timer rollover) | ||
| 598 | // This prevents wraparound issues | ||
| 599 | let max_future = now + super::TIMER_MAX_VALUE; | ||
| 600 | if timestamp > max_future { | ||
| 601 | // For very long timeouts, wake immediately to avoid rollover issues | ||
| 602 | waker.wake_by_ref(); | ||
| 603 | return; | ||
| 604 | } | ||
| 605 | |||
| 606 | // Register the waker first so any immediate wake below is observed by the executor. | ||
| 607 | TIMER_WAKER.register(waker); | ||
| 608 | |||
| 609 | let r: &Regs = unsafe { &*pac::Ostimer0::ptr() }; | ||
| 610 | |||
| 611 | critical_section::with(|_| { | ||
| 612 | // Mask INTENA and clear flag | ||
| 613 | r.osevent_ctrl() | ||
| 614 | .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); | ||
| 615 | |||
| 616 | // Read back to ensure W1C took effect on hardware | ||
| 617 | let _ = r.osevent_ctrl().read().ostimer_intrflag().bit(); | ||
| 618 | |||
| 619 | if !super::wait_for_match_write_ready(r) { | ||
| 620 | super::prime_match_registers(r); | ||
| 621 | |||
| 622 | if !super::wait_for_match_write_ready(r) { | ||
| 623 | // If we can't safely program MATCH, wake immediately and leave INTENA masked. | ||
| 624 | waker.wake_by_ref(); | ||
| 625 | return; | ||
| 626 | } | ||
| 627 | } | ||
| 628 | |||
| 629 | // Program MATCH (Gray-coded). Write low then high, then fence. | ||
| 630 | let gray = bin_to_gray(timestamp); | ||
| 631 | let l = (gray & LOW_32_BIT_MASK) as u32; | ||
| 632 | |||
| 633 | let h = (((gray >> EVTIMER_HI_SHIFT) as u16) & EVTIMER_HI_MASK) as u16; | ||
| 634 | |||
| 635 | r.match_l().write(|w| unsafe { w.match_value().bits(l) }); | ||
| 636 | r.match_h().write(|w| unsafe { w.match_value().bits(h) }); | ||
| 637 | |||
| 638 | if !super::wait_for_match_write_complete(r) { | ||
| 639 | waker.wake_by_ref(); | ||
| 640 | return; | ||
| 641 | } | ||
| 642 | |||
| 643 | let now_after_program = super::now_ticks_read(); | ||
| 644 | let intrflag_set = r.osevent_ctrl().read().ostimer_intrflag().bit_is_set(); | ||
| 645 | if now_after_program >= timestamp && !intrflag_set { | ||
| 646 | waker.wake_by_ref(); | ||
| 647 | return; | ||
| 648 | } | ||
| 649 | |||
| 650 | // Enable peripheral interrupt | ||
| 651 | r.osevent_ctrl().write(|w| w.ostimer_intena().set_bit()); | ||
| 652 | }); | ||
| 653 | } | ||
| 654 | } | ||
| 655 | |||
| 656 | /// Install the global embassy-time driver and configure NVIC priority for OS_EVENT. | ||
| 657 | /// | ||
| 658 | /// # Parameters | ||
| 659 | /// * `priority` - Interrupt priority for the OSTIMER interrupt | ||
| 660 | /// * `frequency_hz` - Actual OSTIMER clock frequency in Hz (stored for future use) | ||
| 661 | /// | ||
| 662 | /// Note: The frequency parameter is currently accepted for API compatibility. | ||
| 663 | /// The embassy_time_driver macro handles driver registration automatically. | ||
| 664 | pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) { | ||
| 665 | let _clock_freq = unsafe { | ||
| 666 | enable_and_reset::<_OSTIMER0_TIME_DRIVER>(&OsTimerConfig { | ||
| 667 | power: PoweredClock::AlwaysEnabled, | ||
| 668 | source: OstimerClockSel::Clk1M, | ||
| 669 | }) | ||
| 670 | .expect("Enabling OsTimer clock should not fail") | ||
| 671 | }; | ||
| 672 | |||
| 673 | // Mask/clear at peripheral and set default MATCH | ||
| 674 | let r: &Regs = unsafe { &*pac::Ostimer0::ptr() }; | ||
| 675 | super::prime_match_registers(r); | ||
| 676 | |||
| 677 | // Configure NVIC for timer operation | ||
| 678 | crate::interrupt::OS_EVENT.configure_for_timer(priority); | ||
| 679 | |||
| 680 | // Note: The embassy_time_driver macro automatically registers the driver | ||
| 681 | // The frequency parameter is accepted for future compatibility | ||
| 682 | let _ = frequency_hz; // Suppress unused parameter warning | ||
| 683 | } | ||
| 684 | |||
| 685 | // Export the global time driver expected by embassy-time | ||
| 686 | embassy_time_driver::time_driver_impl!(static DRIVER: Driver = Driver); | ||
| 687 | |||
| 688 | /// To be called from the OS_EVENT IRQ. | ||
| 689 | pub fn on_interrupt() { | ||
| 690 | let r: &Regs = unsafe { &*pac::Ostimer0::ptr() }; | ||
| 691 | |||
| 692 | // Critical section to prevent races with schedule_wake | ||
| 693 | critical_section::with(|_| { | ||
| 694 | // Check if interrupt is actually pending and handle it atomically | ||
| 695 | if r.osevent_ctrl().read().ostimer_intrflag().bit_is_set() { | ||
| 696 | // Clear flag and disable interrupt atomically | ||
| 697 | r.osevent_ctrl().write(|w| { | ||
| 698 | w.ostimer_intrflag() | ||
| 699 | .clear_bit_by_one() // Write-1-to-clear using safe helper | ||
| 700 | .ostimer_intena() | ||
| 701 | .clear_bit() | ||
| 702 | }); | ||
| 703 | |||
| 704 | // Wake the waiting task | ||
| 705 | TIMER_WAKER.wake(); | ||
| 706 | |||
| 707 | // Handle alarm callback if active and this interrupt is for the alarm | ||
| 708 | if ALARM_ACTIVE.load(Ordering::SeqCst) { | ||
| 709 | let current_time = now_ticks_read(); | ||
| 710 | let target_time = unsafe { ALARM_TARGET_TIME }; | ||
| 711 | |||
| 712 | // Check if current time is close to alarm target time (within 1000 ticks for timing variations) | ||
| 713 | if current_time >= target_time && current_time <= target_time + 1000 { | ||
| 714 | ALARM_ACTIVE.store(false, Ordering::SeqCst); | ||
| 715 | unsafe { ALARM_TARGET_TIME = 0 }; | ||
| 716 | |||
| 717 | // Execute callback if set | ||
| 718 | unsafe { | ||
| 719 | if let Some(callback) = ALARM_CALLBACK { | ||
| 720 | callback(); | ||
| 721 | } | ||
| 722 | } | ||
| 723 | |||
| 724 | // Set flag if provided | ||
| 725 | unsafe { | ||
| 726 | if let Some(flag) = ALARM_FLAG { | ||
| 727 | (*flag).store(true, Ordering::SeqCst); | ||
| 728 | } | ||
| 729 | } | ||
| 730 | } | ||
| 731 | } | ||
| 732 | } | ||
| 733 | }); | ||
| 734 | } | ||
| 735 | } | ||
| 736 | |||
| 737 | #[cfg(feature = "time")] | ||
| 738 | use crate::pac::interrupt; | ||
| 739 | |||
| 740 | #[cfg(feature = "time")] | ||
| 741 | #[allow(non_snake_case)] | ||
| 742 | #[interrupt] | ||
| 743 | fn OS_EVENT() { | ||
| 744 | time_driver::on_interrupt() | ||
| 745 | } | ||
diff --git a/embassy-mcxa/src/pins.rs b/embassy-mcxa/src/pins.rs new file mode 100644 index 000000000..fdf1b0a86 --- /dev/null +++ b/embassy-mcxa/src/pins.rs | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | //! Pin configuration helpers (separate from peripheral drivers). | ||
| 2 | use crate::pac; | ||
| 3 | |||
| 4 | pub unsafe fn configure_adc_pins() { | ||
| 5 | // P1_10 = ADC1_A8 | ||
| 6 | let port1 = &*pac::Port1::ptr(); | ||
| 7 | port1.pcr10().write(|w| { | ||
| 8 | w.ps() | ||
| 9 | .ps0() | ||
| 10 | .pe() | ||
| 11 | .pe0() | ||
| 12 | .sre() | ||
| 13 | .sre0() | ||
| 14 | .ode() | ||
| 15 | .ode0() | ||
| 16 | .dse() | ||
| 17 | .dse0() | ||
| 18 | .mux() | ||
| 19 | .mux0() | ||
| 20 | .ibe() | ||
| 21 | .ibe0() | ||
| 22 | .inv() | ||
| 23 | .inv0() | ||
| 24 | .lk() | ||
| 25 | .lk0() | ||
| 26 | }); | ||
| 27 | core::arch::asm!("dsb sy; isb sy"); | ||
| 28 | } | ||
diff --git a/embassy-mcxa/src/rtc.rs b/embassy-mcxa/src/rtc.rs new file mode 100644 index 000000000..f975d9c9f --- /dev/null +++ b/embassy-mcxa/src/rtc.rs | |||
| @@ -0,0 +1,453 @@ | |||
| 1 | //! RTC DateTime driver. | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | |||
| 4 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 5 | use maitake_sync::WaitCell; | ||
| 6 | |||
| 7 | use crate::clocks::with_clocks; | ||
| 8 | use crate::interrupt::typelevel::{Handler, Interrupt}; | ||
| 9 | use crate::pac; | ||
| 10 | use crate::pac::rtc0::cr::Um; | ||
| 11 | |||
| 12 | type Regs = pac::rtc0::RegisterBlock; | ||
| 13 | |||
| 14 | /// Global wait cell for alarm notifications | ||
| 15 | static WAKER: WaitCell = WaitCell::new(); | ||
| 16 | |||
| 17 | /// RTC interrupt handler. | ||
| 18 | pub struct InterruptHandler<I: Instance> { | ||
| 19 | _phantom: PhantomData<I>, | ||
| 20 | } | ||
| 21 | |||
| 22 | /// Trait for RTC peripheral instances | ||
| 23 | pub trait Instance: PeripheralType { | ||
| 24 | type Interrupt: Interrupt; | ||
| 25 | fn ptr() -> *const Regs; | ||
| 26 | } | ||
| 27 | |||
| 28 | /// Token for RTC0 | ||
| 29 | pub type Rtc0 = crate::peripherals::RTC0; | ||
| 30 | impl Instance for crate::peripherals::RTC0 { | ||
| 31 | type Interrupt = crate::interrupt::typelevel::RTC; | ||
| 32 | #[inline(always)] | ||
| 33 | fn ptr() -> *const Regs { | ||
| 34 | pac::Rtc0::ptr() | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | /// Number of days in a standard year | ||
| 39 | const DAYS_IN_A_YEAR: u32 = 365; | ||
| 40 | /// Number of seconds in a day | ||
| 41 | const SECONDS_IN_A_DAY: u32 = 86400; | ||
| 42 | /// Number of seconds in an hour | ||
| 43 | const SECONDS_IN_A_HOUR: u32 = 3600; | ||
| 44 | /// Number of seconds in a minute | ||
| 45 | const SECONDS_IN_A_MINUTE: u32 = 60; | ||
| 46 | /// Unix epoch start year | ||
| 47 | const YEAR_RANGE_START: u16 = 1970; | ||
| 48 | |||
| 49 | /// Date and time structure for RTC operations | ||
| 50 | #[derive(Debug, Clone, Copy)] | ||
| 51 | pub struct RtcDateTime { | ||
| 52 | pub year: u16, | ||
| 53 | pub month: u8, | ||
| 54 | pub day: u8, | ||
| 55 | pub hour: u8, | ||
| 56 | pub minute: u8, | ||
| 57 | pub second: u8, | ||
| 58 | } | ||
| 59 | #[derive(Copy, Clone)] | ||
| 60 | pub struct RtcConfig { | ||
| 61 | #[allow(dead_code)] | ||
| 62 | wakeup_select: bool, | ||
| 63 | update_mode: Um, | ||
| 64 | #[allow(dead_code)] | ||
| 65 | supervisor_access: bool, | ||
| 66 | compensation_interval: u8, | ||
| 67 | compensation_time: u8, | ||
| 68 | } | ||
| 69 | |||
| 70 | /// RTC interrupt enable flags | ||
| 71 | #[derive(Copy, Clone)] | ||
| 72 | pub struct RtcInterruptEnable; | ||
| 73 | impl RtcInterruptEnable { | ||
| 74 | pub const RTC_TIME_INVALID_INTERRUPT_ENABLE: u32 = 1 << 0; | ||
| 75 | pub const RTC_TIME_OVERFLOW_INTERRUPT_ENABLE: u32 = 1 << 1; | ||
| 76 | pub const RTC_ALARM_INTERRUPT_ENABLE: u32 = 1 << 2; | ||
| 77 | pub const RTC_SECONDS_INTERRUPT_ENABLE: u32 = 1 << 4; | ||
| 78 | } | ||
| 79 | |||
| 80 | /// Converts a DateTime structure to Unix timestamp (seconds since 1970-01-01) | ||
| 81 | /// | ||
| 82 | /// # Arguments | ||
| 83 | /// | ||
| 84 | /// * `datetime` - The date and time to convert | ||
| 85 | /// | ||
| 86 | /// # Returns | ||
| 87 | /// | ||
| 88 | /// Unix timestamp as u32 | ||
| 89 | /// | ||
| 90 | /// # Note | ||
| 91 | /// | ||
| 92 | /// This function handles leap years correctly. | ||
| 93 | pub fn convert_datetime_to_seconds(datetime: &RtcDateTime) -> u32 { | ||
| 94 | let month_days: [u16; 13] = [0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; | ||
| 95 | |||
| 96 | let mut seconds = (datetime.year as u32 - 1970) * DAYS_IN_A_YEAR; | ||
| 97 | seconds += (datetime.year as u32 / 4) - (1970 / 4); | ||
| 98 | seconds += month_days[datetime.month as usize] as u32; | ||
| 99 | seconds += datetime.day as u32 - 1; | ||
| 100 | |||
| 101 | if (datetime.year & 3 == 0) && (datetime.month <= 2) { | ||
| 102 | seconds -= 1; | ||
| 103 | } | ||
| 104 | |||
| 105 | seconds = seconds * SECONDS_IN_A_DAY | ||
| 106 | + (datetime.hour as u32 * SECONDS_IN_A_HOUR) | ||
| 107 | + (datetime.minute as u32 * SECONDS_IN_A_MINUTE) | ||
| 108 | + datetime.second as u32; | ||
| 109 | |||
| 110 | seconds | ||
| 111 | } | ||
| 112 | |||
| 113 | /// Converts Unix timestamp to DateTime structure | ||
| 114 | /// | ||
| 115 | /// # Arguments | ||
| 116 | /// | ||
| 117 | /// * `seconds` - Unix timestamp (seconds since 1970-01-01) | ||
| 118 | /// | ||
| 119 | /// # Returns | ||
| 120 | /// | ||
| 121 | /// RtcDateTime structure with the converted date and time | ||
| 122 | /// | ||
| 123 | /// # Note | ||
| 124 | /// | ||
| 125 | /// This function handles leap years correctly. | ||
| 126 | pub fn convert_seconds_to_datetime(seconds: u32) -> RtcDateTime { | ||
| 127 | let mut seconds_remaining = seconds; | ||
| 128 | let mut days = seconds_remaining / SECONDS_IN_A_DAY + 1; | ||
| 129 | seconds_remaining %= SECONDS_IN_A_DAY; | ||
| 130 | |||
| 131 | let hour = (seconds_remaining / SECONDS_IN_A_HOUR) as u8; | ||
| 132 | seconds_remaining %= SECONDS_IN_A_HOUR; | ||
| 133 | let minute = (seconds_remaining / SECONDS_IN_A_MINUTE) as u8; | ||
| 134 | let second = (seconds_remaining % SECONDS_IN_A_MINUTE) as u8; | ||
| 135 | |||
| 136 | let mut year = YEAR_RANGE_START; | ||
| 137 | let mut days_in_year = DAYS_IN_A_YEAR; | ||
| 138 | |||
| 139 | while days > days_in_year { | ||
| 140 | days -= days_in_year; | ||
| 141 | year += 1; | ||
| 142 | |||
| 143 | days_in_year = if year.is_multiple_of(4) { | ||
| 144 | DAYS_IN_A_YEAR + 1 | ||
| 145 | } else { | ||
| 146 | DAYS_IN_A_YEAR | ||
| 147 | }; | ||
| 148 | } | ||
| 149 | |||
| 150 | let days_per_month = [ | ||
| 151 | 31, | ||
| 152 | if year.is_multiple_of(4) { 29 } else { 28 }, | ||
| 153 | 31, | ||
| 154 | 30, | ||
| 155 | 31, | ||
| 156 | 30, | ||
| 157 | 31, | ||
| 158 | 31, | ||
| 159 | 30, | ||
| 160 | 31, | ||
| 161 | 30, | ||
| 162 | 31, | ||
| 163 | ]; | ||
| 164 | |||
| 165 | let mut month = 1; | ||
| 166 | for (m, month_days) in days_per_month.iter().enumerate() { | ||
| 167 | let m = m + 1; | ||
| 168 | if days <= *month_days as u32 { | ||
| 169 | month = m; | ||
| 170 | break; | ||
| 171 | } else { | ||
| 172 | days -= *month_days as u32; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | let day = days as u8; | ||
| 177 | |||
| 178 | RtcDateTime { | ||
| 179 | year, | ||
| 180 | month: month as u8, | ||
| 181 | day, | ||
| 182 | hour, | ||
| 183 | minute, | ||
| 184 | second, | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | /// Returns default RTC configuration | ||
| 189 | /// | ||
| 190 | /// # Returns | ||
| 191 | /// | ||
| 192 | /// RtcConfig with sensible default values: | ||
| 193 | /// - No wakeup selection | ||
| 194 | /// - Update mode 0 (immediate updates) | ||
| 195 | /// - No supervisor access restriction | ||
| 196 | /// - No compensation | ||
| 197 | pub fn get_default_config() -> RtcConfig { | ||
| 198 | RtcConfig { | ||
| 199 | wakeup_select: false, | ||
| 200 | update_mode: Um::Um0, | ||
| 201 | supervisor_access: false, | ||
| 202 | compensation_interval: 0, | ||
| 203 | compensation_time: 0, | ||
| 204 | } | ||
| 205 | } | ||
| 206 | /// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy) | ||
| 207 | pub struct Rtc<'a, I: Instance> { | ||
| 208 | _inst: core::marker::PhantomData<&'a mut I>, | ||
| 209 | } | ||
| 210 | |||
| 211 | impl<'a, I: Instance> Rtc<'a, I> { | ||
| 212 | /// Create a new instance of the real time clock. | ||
| 213 | pub fn new( | ||
| 214 | _inst: Peri<'a, I>, | ||
| 215 | _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, | ||
| 216 | config: RtcConfig, | ||
| 217 | ) -> Self { | ||
| 218 | let rtc = unsafe { &*I::ptr() }; | ||
| 219 | |||
| 220 | // The RTC is NOT gated by the MRCC, but we DO need to make sure the 16k clock | ||
| 221 | // on the vsys domain is active | ||
| 222 | let clocks = with_clocks(|c| c.clk_16k_vsys.clone()); | ||
| 223 | match clocks { | ||
| 224 | None => panic!("Clocks have not been initialized"), | ||
| 225 | Some(None) => panic!("Clocks initialized, but clk_16k_vsys not active"), | ||
| 226 | Some(Some(_)) => {} | ||
| 227 | } | ||
| 228 | |||
| 229 | // RTC reset | ||
| 230 | rtc.cr().modify(|_, w| w.swr().set_bit()); | ||
| 231 | rtc.cr().modify(|_, w| w.swr().clear_bit()); | ||
| 232 | rtc.tsr().write(|w| unsafe { w.bits(1) }); | ||
| 233 | |||
| 234 | rtc.cr().modify(|_, w| w.um().variant(config.update_mode)); | ||
| 235 | |||
| 236 | rtc.tcr().modify(|_, w| unsafe { | ||
| 237 | w.cir() | ||
| 238 | .bits(config.compensation_interval) | ||
| 239 | .tcr() | ||
| 240 | .bits(config.compensation_time) | ||
| 241 | }); | ||
| 242 | |||
| 243 | // Enable RTC interrupt | ||
| 244 | I::Interrupt::unpend(); | ||
| 245 | unsafe { I::Interrupt::enable() }; | ||
| 246 | |||
| 247 | Self { | ||
| 248 | _inst: core::marker::PhantomData, | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | /// Set the current date and time | ||
| 253 | /// | ||
| 254 | /// # Arguments | ||
| 255 | /// | ||
| 256 | /// * `datetime` - The date and time to set | ||
| 257 | /// | ||
| 258 | /// # Note | ||
| 259 | /// | ||
| 260 | /// The datetime is converted to Unix timestamp and written to the time seconds register. | ||
| 261 | pub fn set_datetime(&self, datetime: RtcDateTime) { | ||
| 262 | let rtc = unsafe { &*I::ptr() }; | ||
| 263 | let seconds = convert_datetime_to_seconds(&datetime); | ||
| 264 | rtc.tsr().write(|w| unsafe { w.bits(seconds) }); | ||
| 265 | } | ||
| 266 | |||
| 267 | /// Get the current date and time | ||
| 268 | /// | ||
| 269 | /// # Returns | ||
| 270 | /// | ||
| 271 | /// Current date and time as RtcDateTime | ||
| 272 | /// | ||
| 273 | /// # Note | ||
| 274 | /// | ||
| 275 | /// Reads the current Unix timestamp from the time seconds register and converts it. | ||
| 276 | pub fn get_datetime(&self) -> RtcDateTime { | ||
| 277 | let rtc = unsafe { &*I::ptr() }; | ||
| 278 | let seconds = rtc.tsr().read().bits(); | ||
| 279 | convert_seconds_to_datetime(seconds) | ||
| 280 | } | ||
| 281 | |||
| 282 | /// Set the alarm date and time | ||
| 283 | /// | ||
| 284 | /// # Arguments | ||
| 285 | /// | ||
| 286 | /// * `alarm` - The date and time when the alarm should trigger | ||
| 287 | /// | ||
| 288 | /// # Note | ||
| 289 | /// | ||
| 290 | /// This function: | ||
| 291 | /// - Clears any existing alarm by writing 0 to the alarm register | ||
| 292 | /// - Waits for the clear operation to complete | ||
| 293 | /// - Sets the new alarm time | ||
| 294 | /// - Waits for the write operation to complete | ||
| 295 | /// - Uses timeouts to prevent infinite loops | ||
| 296 | /// - Enables the alarm interrupt after setting | ||
| 297 | pub fn set_alarm(&self, alarm: RtcDateTime) { | ||
| 298 | let rtc = unsafe { &*I::ptr() }; | ||
| 299 | let seconds = convert_datetime_to_seconds(&alarm); | ||
| 300 | |||
| 301 | rtc.tar().write(|w| unsafe { w.bits(0) }); | ||
| 302 | let mut timeout = 10000; | ||
| 303 | while rtc.tar().read().bits() != 0 && timeout > 0 { | ||
| 304 | timeout -= 1; | ||
| 305 | } | ||
| 306 | |||
| 307 | rtc.tar().write(|w| unsafe { w.bits(seconds) }); | ||
| 308 | |||
| 309 | let mut timeout = 10000; | ||
| 310 | while rtc.tar().read().bits() != seconds && timeout > 0 { | ||
| 311 | timeout -= 1; | ||
| 312 | } | ||
| 313 | |||
| 314 | self.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); | ||
| 315 | } | ||
| 316 | |||
| 317 | /// Get the current alarm date and time | ||
| 318 | /// | ||
| 319 | /// # Returns | ||
| 320 | /// | ||
| 321 | /// Alarm date and time as RtcDateTime | ||
| 322 | /// | ||
| 323 | /// # Note | ||
| 324 | /// | ||
| 325 | /// Reads the alarm timestamp from the time alarm register and converts it. | ||
| 326 | pub fn get_alarm(&self) -> RtcDateTime { | ||
| 327 | let rtc = unsafe { &*I::ptr() }; | ||
| 328 | let alarm_seconds = rtc.tar().read().bits(); | ||
| 329 | convert_seconds_to_datetime(alarm_seconds) | ||
| 330 | } | ||
| 331 | |||
| 332 | /// Start the RTC time counter | ||
| 333 | /// | ||
| 334 | /// # Note | ||
| 335 | /// | ||
| 336 | /// Sets the Time Counter Enable (TCE) bit in the status register. | ||
| 337 | pub fn start(&self) { | ||
| 338 | let rtc = unsafe { &*I::ptr() }; | ||
| 339 | rtc.sr().modify(|_, w| w.tce().set_bit()); | ||
| 340 | } | ||
| 341 | |||
| 342 | /// Stop the RTC time counter | ||
| 343 | /// | ||
| 344 | /// # Note | ||
| 345 | /// | ||
| 346 | /// Clears the Time Counter Enable (TCE) bit in the status register. | ||
| 347 | pub fn stop(&self) { | ||
| 348 | let rtc = unsafe { &*I::ptr() }; | ||
| 349 | rtc.sr().modify(|_, w| w.tce().clear_bit()); | ||
| 350 | } | ||
| 351 | |||
| 352 | /// Enable specific RTC interrupts | ||
| 353 | /// | ||
| 354 | /// # Arguments | ||
| 355 | /// | ||
| 356 | /// * `mask` - Bitmask of interrupts to enable (use RtcInterruptEnable constants) | ||
| 357 | /// | ||
| 358 | /// # Note | ||
| 359 | /// | ||
| 360 | /// This function enables the specified interrupt types and resets the alarm occurred flag. | ||
| 361 | /// Available interrupts: | ||
| 362 | /// - Time Invalid Interrupt | ||
| 363 | /// - Time Overflow Interrupt | ||
| 364 | /// - Alarm Interrupt | ||
| 365 | /// - Seconds Interrupt | ||
| 366 | pub fn set_interrupt(&self, mask: u32) { | ||
| 367 | let rtc = unsafe { &*I::ptr() }; | ||
| 368 | |||
| 369 | if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 { | ||
| 370 | rtc.ier().modify(|_, w| w.tiie().tiie_1()); | ||
| 371 | } | ||
| 372 | if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 { | ||
| 373 | rtc.ier().modify(|_, w| w.toie().toie_1()); | ||
| 374 | } | ||
| 375 | if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 { | ||
| 376 | rtc.ier().modify(|_, w| w.taie().taie_1()); | ||
| 377 | } | ||
| 378 | if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 { | ||
| 379 | rtc.ier().modify(|_, w| w.tsie().tsie_1()); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | /// Disable specific RTC interrupts | ||
| 384 | /// | ||
| 385 | /// # Arguments | ||
| 386 | /// | ||
| 387 | /// * `mask` - Bitmask of interrupts to disable (use RtcInterruptEnable constants) | ||
| 388 | /// | ||
| 389 | /// # Note | ||
| 390 | /// | ||
| 391 | /// This function disables the specified interrupt types. | ||
| 392 | pub fn disable_interrupt(&self, mask: u32) { | ||
| 393 | let rtc = unsafe { &*I::ptr() }; | ||
| 394 | |||
| 395 | if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 { | ||
| 396 | rtc.ier().modify(|_, w| w.tiie().tiie_0()); | ||
| 397 | } | ||
| 398 | if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 { | ||
| 399 | rtc.ier().modify(|_, w| w.toie().toie_0()); | ||
| 400 | } | ||
| 401 | if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 { | ||
| 402 | rtc.ier().modify(|_, w| w.taie().taie_0()); | ||
| 403 | } | ||
| 404 | if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 { | ||
| 405 | rtc.ier().modify(|_, w| w.tsie().tsie_0()); | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | /// Clear the alarm interrupt flag | ||
| 410 | /// | ||
| 411 | /// # Note | ||
| 412 | /// | ||
| 413 | /// This function clears the Time Alarm Interrupt Enable bit. | ||
| 414 | pub fn clear_alarm_flag(&self) { | ||
| 415 | let rtc = unsafe { &*I::ptr() }; | ||
| 416 | rtc.ier().modify(|_, w| w.taie().clear_bit()); | ||
| 417 | } | ||
| 418 | |||
| 419 | /// Wait for an RTC alarm to trigger. | ||
| 420 | /// | ||
| 421 | /// # Arguments | ||
| 422 | /// | ||
| 423 | /// * `alarm` - The date and time when the alarm should trigger | ||
| 424 | /// This function will wait until the RTC alarm is triggered. | ||
| 425 | /// If no alarm is scheduled, it will wait indefinitely until one is scheduled and triggered. | ||
| 426 | pub async fn wait_for_alarm(&mut self, alarm: RtcDateTime) { | ||
| 427 | let wait = WAKER.subscribe().await; | ||
| 428 | |||
| 429 | self.set_alarm(alarm); | ||
| 430 | self.start(); | ||
| 431 | |||
| 432 | // REVISIT: propagate error? | ||
| 433 | let _ = wait.await; | ||
| 434 | |||
| 435 | // Clear the interrupt and disable the alarm after waking up | ||
| 436 | self.disable_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | /// RTC interrupt handler | ||
| 441 | /// | ||
| 442 | /// This struct implements the interrupt handler for RTC events. | ||
| 443 | impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 444 | unsafe fn on_interrupt() { | ||
| 445 | let rtc = &*pac::Rtc0::ptr(); | ||
| 446 | // Check if this is actually a time alarm interrupt | ||
| 447 | let sr = rtc.sr().read(); | ||
| 448 | if sr.taf().bit_is_set() { | ||
| 449 | rtc.ier().modify(|_, w| w.taie().clear_bit()); | ||
| 450 | WAKER.wake(); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | } | ||
diff --git a/embassy-mcxa/supply-chain/README.md b/embassy-mcxa/supply-chain/README.md new file mode 100644 index 000000000..12f8777b0 --- /dev/null +++ b/embassy-mcxa/supply-chain/README.md | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | # Working with cargo vet | ||
| 2 | |||
| 3 | ## Introduction | ||
| 4 | |||
| 5 | `cargo vet` is a tool to help ensure that third-party Rust dependencies have been audited by a trusted entity. | ||
| 6 | It matches all dependencies against a set of audits conducted by the authors of the project or entities they trust. | ||
| 7 | To learn more, visit [mozilla/cargo-vet](https://github.com/mozilla/cargo-vet) | ||
| 8 | |||
| 9 | --- | ||
| 10 | |||
| 11 | ## Adding a new dependency | ||
| 12 | |||
| 13 | When updating or adding a new dependency, we need to ensure it's audited before being merged into main. | ||
| 14 | For our repositories, we have designated experts who are responsible for vetting any new dependencies being added to their repository. | ||
| 15 | _It is the shared responsibility of the developer creating the PR and the auditors to conduct a successful audit._ | ||
| 16 | Follow the process below to ensure compliance: | ||
| 17 | |||
| 18 | ### For Developers | ||
| 19 | 1. **Respond to `cargo vet` failures**: | ||
| 20 | - If your PR fails the `cargo vet` step, the cargo-vet workflow will add a comment to the PR with a template questionnaire | ||
| 21 | - Copy the questionnaire, fill it out and paste it as a new comment on the PR. This greatly helps the auditors get some context of the changes requiring the new dependencies | ||
| 22 | |||
| 23 | 2. **Engage with auditors**: | ||
| 24 | - Respond to any questions that the auditors might have regarding the need of any new dependencies | ||
| 25 | |||
| 26 | 3. **Rebase and verify**: | ||
| 27 | - At their discretion, auditors will check in their audits into either [rust-crate-audits](https://github.com/OpenDevicePartnership/rust-crate-audits) or into the same repository | ||
| 28 | - Once the new audits have been merged, rebase your branch on main and verify it passes `cargo vet` | ||
| 29 | ```bash | ||
| 30 | git fetch upstream | ||
| 31 | git rebase upstream/main | ||
| 32 | cargo vet | ||
| 33 | ``` | ||
| 34 | |||
| 35 | 4. **Update PR**: | ||
| 36 | - If the audits were checked into rust-crate-audits, they will show up in _imports.lock_ on running `cargo vet`. In this case add the updated _imports.lock_ to your PR | ||
| 37 | - If the audits were checked into the same repository, they will be present in _audits.toml_ after rebase and you can simply force push to your PR after rebase | ||
| 38 | ```bash | ||
| 39 | git push -f | ||
| 40 | ``` | ||
| 41 | |||
| 42 | 5. **Check PR status**: | ||
| 43 | - The existing PR comment from the previous failure will be updated with a success message once the check passes | ||
| 44 | |||
| 45 | ### For Auditors | ||
| 46 | |||
| 47 | 1. **Review the questionnaire**: | ||
| 48 | - Check the filled questionnaire on the PR once the developer responds to the `cargo vet` failure | ||
| 49 | - Respond to the developer comment in case more information is needed | ||
| 50 | |||
| 51 | 2. **Audit new dependencies**: | ||
| 52 | - Inspect the `cargo vet` failures using your preferred method | ||
| 53 | - Use [gh pr checkout](https://cli.github.com/manual/gh_pr_checkout) to checkout the PR and run `cargo vet --locked` | ||
| 54 | - Use [Github Pull Requests for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github) to checkout the PR and run `cargo vet --locked` | ||
| 55 | - For more suggestions: [Checking out pull requests locally](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally) | ||
| 56 | |||
| 57 | 3. **Follow `cargo vet` recommendations**: | ||
| 58 | - Follow the recommendations of the `cargo vet` command output, either `cargo vet diff` for version update or `cargo vet inspect` for new dependencies | ||
| 59 | |||
| 60 | 4. **Record audits**: | ||
| 61 | - Use `cargo vet certify` to add new audits to _audits.toml_ | ||
| 62 | - Verify all dependencies pass using `cargo vet` | ||
| 63 | |||
| 64 | 5. **Decide audit location**: | ||
| 65 | - **Shared audits**: New audits should ideally be shared across ODP repositories to reduce the overhead of multiple audits for the same dependencies. To facilitate this, it's recommended to cut and paste the new audits and submit as a separate PR to the _audits.toml_ in [rust-crate-audits](https://github.com/OpenDevicePartnership/rust-crate-audits) | ||
| 66 | - If due to business reasons, the audits are not to be shared across repositories, copy the updated _audits.toml_ to a new branch off main in the same repository and submit the PR to update the audits | ||
| 67 | |||
| 68 | 6. **Communicate successful audit**: | ||
| 69 | - Communicate to the PR developer via a PR comment so they can update the PR and get `cargo vet` to pass | ||
| 70 | |||
| 71 | --- | ||
| 72 | |||
| 73 | ## Audit criteria | ||
| 74 | `cargo vet` comes pre-equipped with two built-in criteria but supports adding new criteria to suit our needs. | ||
| 75 | As defined [here](https://mozilla.github.io/cargo-vet/built-in-criteria.html), the default criteria are: | ||
| 76 | |||
| 77 | - **safe-to-run** | ||
| 78 | This crate can be compiled, run, and tested on a local workstation or in | ||
| 79 | controlled automation without surprising consequences, such as: | ||
| 80 | * Reading or writing data from sensitive or unrelated parts of the filesystem. | ||
| 81 | * Installing software or reconfiguring the device. | ||
| 82 | * Connecting to untrusted network endpoints. | ||
| 83 | * Misuse of system resources (e.g. cryptocurrency mining). | ||
| 84 | |||
| 85 | - **safe-to-deploy** | ||
| 86 | This crate will not introduce a serious security vulnerability to production | ||
| 87 | software exposed to untrusted input. | ||
| 88 | |||
| 89 | Auditors are not required to perform a full logic review of the entire crate. | ||
| 90 | Rather, they must review enough to fully reason about the behavior of all unsafe | ||
| 91 | blocks and usage of powerful imports. For any reasonable usage of the crate in | ||
| 92 | real-world software, an attacker must not be able to manipulate the runtime | ||
| 93 | behavior of these sections in an exploitable or surprising way. | ||
| 94 | |||
| 95 | Ideally, all unsafe code is fully sound, and ambient capabilities (e.g. | ||
| 96 | filesystem access) are hardened against manipulation and consistent with the | ||
| 97 | advertised behavior of the crate. However, some discretion is permitted. In such | ||
| 98 | cases, the nature of the discretion should be recorded in the `notes` field of | ||
| 99 | the audit record. | ||
| 100 | |||
| 101 | For crates which generate deployed code (e.g. build dependencies or procedural | ||
| 102 | macros), reasonable usage of the crate should output code which meets the above | ||
| 103 | criteria. | ||
| 104 | |||
| 105 | **Note: `safe-to-deploy` implies `safe-to-run`** | ||
| 106 | |||
| 107 | --- | ||
| 108 | |||
| 109 | ## Conducting an audit | ||
| 110 | |||
| 111 | When performing an audit for a new or updated dependency, auditors may consider the following criteria to ensure the safety, reliability, and suitability of the crate for use in our projects: | ||
| 112 | |||
| 113 | - **Security**: | ||
| 114 | - Review the crate for known vulnerabilities or security advisories. | ||
| 115 | - Check for unsafe code usage and ensure it is justified and well-documented. | ||
| 116 | - Evaluate the crate’s history of security issues and responsiveness to reported problems. | ||
| 117 | |||
| 118 | - **Maintenance and Activity**: | ||
| 119 | - Assess the frequency of updates and the responsiveness of maintainers to issues and pull requests. | ||
| 120 | - Prefer crates that are actively maintained and have a healthy contributor base. | ||
| 121 | |||
| 122 | - **License Compliance**: | ||
| 123 | - Verify that the crate’s license is compatible with our project’s licensing requirements. | ||
| 124 | |||
| 125 | - **Community Trust and Adoption**: | ||
| 126 | - Consider the crate’s adoption in the wider Rust ecosystem. | ||
| 127 | - Prefer crates that are widely used and trusted by the community. | ||
| 128 | |||
| 129 | - **Functionality and Suitability**: | ||
| 130 | - Confirm that the crate provides the required functionality without unnecessary features or bloat. | ||
| 131 | - Evaluate whether the crate’s API is stable and unlikely to introduce breaking changes unexpectedly. | ||
| 132 | |||
| 133 | - **Audit Trail**: | ||
| 134 | - Record the audit decision, including any concerns, mitigations, or recommendations for future updates. | ||
| 135 | - If exemptions are granted, document the justification and any follow-up actions required. | ||
| 136 | |||
| 137 | --- | ||
| 138 | |||
| 139 | ## Tips for using `cargo vet`: | ||
| 140 | |||
| 141 | - **Update _imports.lock_**: | ||
| 142 | - Import trusted third party audits to reduce the number of new audits to be performed. Running `cargo vet` without `--locked` fetches new imports and updates _imports.lock_ with any audits that are helpful for our project. | ||
| 143 | |||
| 144 | - **Add exemptions**: | ||
| 145 | - If an audit cannot be performed for some dependency due to time sensitivity or business justified reasons, use `cargo vet add-exemption <PACKAGE> <VERSION>` to add the dependency to exemptions in _config.toml_ | ||
| 146 | - To add all remaining audits to exemptions at once, use `cargo vet regenerate exemptions` | ||
| 147 | |||
| 148 | - **Prune unnecessary entries**: | ||
| 149 | - Remove unnecessary exemptions and imports using `cargo vet prune` \ No newline at end of file | ||
diff --git a/embassy-mcxa/supply-chain/audits.toml b/embassy-mcxa/supply-chain/audits.toml new file mode 100644 index 000000000..871109648 --- /dev/null +++ b/embassy-mcxa/supply-chain/audits.toml | |||
| @@ -0,0 +1,349 @@ | |||
| 1 | |||
| 2 | # cargo-vet audits file | ||
| 3 | |||
| 4 | [[audits.autocfg]] | ||
| 5 | who = "Felipe Balbi <[email protected]>" | ||
| 6 | criteria = "safe-to-deploy" | ||
| 7 | version = "1.5.0" | ||
| 8 | |||
| 9 | [[audits.cc]] | ||
| 10 | who = "Felipe Balbi <[email protected]>" | ||
| 11 | criteria = "safe-to-deploy" | ||
| 12 | version = "1.2.47" | ||
| 13 | |||
| 14 | [[audits.cfg-if]] | ||
| 15 | who = "Felipe Balbi <[email protected]>" | ||
| 16 | criteria = "safe-to-deploy" | ||
| 17 | version = "1.0.4" | ||
| 18 | |||
| 19 | [[audits.cordyceps]] | ||
| 20 | who = "Felipe Balbi <[email protected]>" | ||
| 21 | criteria = "safe-to-deploy" | ||
| 22 | version = "0.3.4" | ||
| 23 | |||
| 24 | [[audits.darling]] | ||
| 25 | who = "Felipe Balbi <[email protected]>" | ||
| 26 | criteria = "safe-to-deploy" | ||
| 27 | version = "0.20.11" | ||
| 28 | |||
| 29 | [[audits.darling_core]] | ||
| 30 | who = "Felipe Balbi <[email protected]>" | ||
| 31 | criteria = "safe-to-deploy" | ||
| 32 | version = "0.20.11" | ||
| 33 | |||
| 34 | [[audits.darling_macro]] | ||
| 35 | who = "Felipe Balbi <[email protected]>" | ||
| 36 | criteria = "safe-to-deploy" | ||
| 37 | version = "0.20.11" | ||
| 38 | |||
| 39 | [[audits.defmt-rtt]] | ||
| 40 | who = "Felipe Balbi <[email protected]>" | ||
| 41 | criteria = "safe-to-deploy" | ||
| 42 | version = "1.0.0" | ||
| 43 | notes = "defmt-rtt is used for all our logging purposes. Version 1.0.0 merely stabilizes what was already available previously." | ||
| 44 | |||
| 45 | [[audits.defmt-rtt]] | ||
| 46 | who = "Felipe Balbi <[email protected]>" | ||
| 47 | criteria = "safe-to-deploy" | ||
| 48 | delta = "1.0.0 -> 1.1.0" | ||
| 49 | |||
| 50 | [[audits.document-features]] | ||
| 51 | who = "Felipe Balbi <[email protected]>" | ||
| 52 | criteria = "safe-to-deploy" | ||
| 53 | version = "0.2.12" | ||
| 54 | |||
| 55 | [[audits.document-features]] | ||
| 56 | who = "Felipe Balbi <[email protected]>" | ||
| 57 | criteria = "safe-to-run" | ||
| 58 | version = "0.2.12" | ||
| 59 | |||
| 60 | [[audits.embassy-executor]] | ||
| 61 | who = "Felipe Balbi <[email protected]>" | ||
| 62 | criteria = "safe-to-deploy" | ||
| 63 | version = "0.9.1" | ||
| 64 | |||
| 65 | [[audits.embassy-executor-macros]] | ||
| 66 | who = "Felipe Balbi <[email protected]>" | ||
| 67 | criteria = "safe-to-deploy" | ||
| 68 | version = "0.7.0" | ||
| 69 | |||
| 70 | [[audits.embassy-executor-timer-queue]] | ||
| 71 | who = "Felipe Balbi <[email protected]>" | ||
| 72 | criteria = "safe-to-deploy" | ||
| 73 | version = "0.1.0" | ||
| 74 | |||
| 75 | [[audits.embassy-executor-timer-queue]] | ||
| 76 | who = "Felipe Balbi <[email protected]>" | ||
| 77 | criteria = "safe-to-deploy" | ||
| 78 | version = "0.1.0" | ||
| 79 | |||
| 80 | [[audits.embassy-time-queue-utils]] | ||
| 81 | who = "Felipe Balbi <[email protected]>" | ||
| 82 | criteria = "safe-to-deploy" | ||
| 83 | version = "0.3.0" | ||
| 84 | |||
| 85 | [[audits.find-msvc-tools]] | ||
| 86 | who = "Felipe Balbi <[email protected]>" | ||
| 87 | criteria = "safe-to-deploy" | ||
| 88 | version = "0.1.5" | ||
| 89 | |||
| 90 | [[audits.generator]] | ||
| 91 | who = "Felipe Balbi <[email protected]>" | ||
| 92 | criteria = "safe-to-deploy" | ||
| 93 | version = "0.8.7" | ||
| 94 | |||
| 95 | [[audits.ident_case]] | ||
| 96 | who = "Felipe Balbi <[email protected]>" | ||
| 97 | criteria = "safe-to-deploy" | ||
| 98 | version = "1.0.1" | ||
| 99 | |||
| 100 | [[audits.litrs]] | ||
| 101 | who = "Felipe Balbi <[email protected]>" | ||
| 102 | criteria = "safe-to-deploy" | ||
| 103 | version = "1.0.0" | ||
| 104 | |||
| 105 | [[audits.maitake-sync]] | ||
| 106 | who = "Felipe Balbi <[email protected]>" | ||
| 107 | criteria = "safe-to-deploy" | ||
| 108 | version = "0.2.2" | ||
| 109 | |||
| 110 | [[audits.mutex-traits]] | ||
| 111 | who = "Felipe Balbi <[email protected]>" | ||
| 112 | criteria = "safe-to-deploy" | ||
| 113 | version = "1.0.1" | ||
| 114 | |||
| 115 | [[audits.mycelium-bitfield]] | ||
| 116 | who = "Felipe Balbi <[email protected]>" | ||
| 117 | criteria = "safe-to-deploy" | ||
| 118 | version = "0.1.5" | ||
| 119 | |||
| 120 | [[audits.once_cell]] | ||
| 121 | who = "Felipe Balbi <[email protected]>" | ||
| 122 | criteria = "safe-to-deploy" | ||
| 123 | version = "1.20.1" | ||
| 124 | |||
| 125 | [[audits.panic-probe]] | ||
| 126 | who = "Felipe Balbi <[email protected]>" | ||
| 127 | criteria = "safe-to-deploy" | ||
| 128 | version = "1.0.0" | ||
| 129 | |||
| 130 | [[audits.pin-project]] | ||
| 131 | who = "Felipe Balbi <[email protected]>" | ||
| 132 | criteria = "safe-to-deploy" | ||
| 133 | version = "1.1.10" | ||
| 134 | |||
| 135 | [[audits.pin-project-internal]] | ||
| 136 | who = "Felipe Balbi <[email protected]>" | ||
| 137 | criteria = "safe-to-deploy" | ||
| 138 | version = "1.1.10" | ||
| 139 | |||
| 140 | [[audits.portable-atomic]] | ||
| 141 | who = "Felipe Balbi <[email protected]>" | ||
| 142 | criteria = "safe-to-deploy" | ||
| 143 | version = "1.11.1" | ||
| 144 | |||
| 145 | [[audits.proc-macro2]] | ||
| 146 | who = "Felipe Balbi <[email protected]>" | ||
| 147 | criteria = "safe-to-deploy" | ||
| 148 | version = "1.0.103" | ||
| 149 | |||
| 150 | [[audits.quote]] | ||
| 151 | who = "Felipe Balbi <[email protected]>" | ||
| 152 | criteria = "safe-to-deploy" | ||
| 153 | version = "1.0.42" | ||
| 154 | |||
| 155 | [[audits.stable_deref_trait]] | ||
| 156 | who = "Felipe Balbi <[email protected]>" | ||
| 157 | criteria = "safe-to-deploy" | ||
| 158 | version = "1.2.1" | ||
| 159 | |||
| 160 | [[audits.static_cell]] | ||
| 161 | who = "jerrysxie <[email protected]>" | ||
| 162 | criteria = "safe-to-run" | ||
| 163 | delta = "2.1.0 -> 2.1.1" | ||
| 164 | |||
| 165 | [[audits.syn]] | ||
| 166 | who = "Felipe Balbi <[email protected]>" | ||
| 167 | criteria = "safe-to-deploy" | ||
| 168 | version = "2.0.110" | ||
| 169 | |||
| 170 | [[audits.syn]] | ||
| 171 | who = "Felipe Balbi <[email protected]>" | ||
| 172 | criteria = "safe-to-deploy" | ||
| 173 | delta = "2.0.100 -> 2.0.109" | ||
| 174 | |||
| 175 | [[audits.thiserror]] | ||
| 176 | who = "Felipe Balbi <[email protected]>" | ||
| 177 | criteria = "safe-to-deploy" | ||
| 178 | version = "2.0.17" | ||
| 179 | |||
| 180 | [[audits.thiserror-impl]] | ||
| 181 | who = "Felipe Balbi <[email protected]>" | ||
| 182 | criteria = "safe-to-deploy" | ||
| 183 | version = "2.0.17" | ||
| 184 | |||
| 185 | [[audits.unicode-ident]] | ||
| 186 | who = "Felipe Balbi <[email protected]>" | ||
| 187 | criteria = "safe-to-deploy" | ||
| 188 | version = "1.0.22" | ||
| 189 | |||
| 190 | [[audits.valuable]] | ||
| 191 | who = "Felipe Balbi <[email protected]>" | ||
| 192 | criteria = "safe-to-deploy" | ||
| 193 | version = "0.1.1" | ||
| 194 | |||
| 195 | [[trusted.aho-corasick]] | ||
| 196 | criteria = "safe-to-deploy" | ||
| 197 | user-id = 189 # Andrew Gallant (BurntSushi) | ||
| 198 | start = "2019-03-28" | ||
| 199 | end = "2026-11-26" | ||
| 200 | |||
| 201 | [[trusted.cc]] | ||
| 202 | criteria = "safe-to-deploy" | ||
| 203 | user-id = 55123 # rust-lang-owner | ||
| 204 | start = "2022-10-29" | ||
| 205 | end = "2026-11-26" | ||
| 206 | |||
| 207 | [[trusted.find-msvc-tools]] | ||
| 208 | criteria = "safe-to-deploy" | ||
| 209 | user-id = 539 | ||
| 210 | start = "2025-08-29" | ||
| 211 | end = "2026-11-26" | ||
| 212 | |||
| 213 | [[trusted.libc]] | ||
| 214 | criteria = "safe-to-deploy" | ||
| 215 | user-id = 55123 # rust-lang-owner | ||
| 216 | start = "2024-08-15" | ||
| 217 | end = "2026-11-26" | ||
| 218 | |||
| 219 | [[trusted.loom]] | ||
| 220 | criteria = "safe-to-deploy" | ||
| 221 | user-id = 6741 # Alice Ryhl (Darksonn) | ||
| 222 | start = "2021-04-12" | ||
| 223 | end = "2026-11-26" | ||
| 224 | |||
| 225 | [[trusted.memchr]] | ||
| 226 | criteria = "safe-to-deploy" | ||
| 227 | user-id = 189 # Andrew Gallant (BurntSushi) | ||
| 228 | start = "2019-07-07" | ||
| 229 | end = "2026-11-26" | ||
| 230 | |||
| 231 | [[trusted.paste]] | ||
| 232 | criteria = "safe-to-deploy" | ||
| 233 | user-id = 3618 # David Tolnay (dtolnay) | ||
| 234 | start = "2019-03-19" | ||
| 235 | end = "2026-11-26" | ||
| 236 | |||
| 237 | [[trusted.regex-automata]] | ||
| 238 | criteria = "safe-to-deploy" | ||
| 239 | user-id = 189 # Andrew Gallant (BurntSushi) | ||
| 240 | start = "2019-02-25" | ||
| 241 | end = "2026-11-26" | ||
| 242 | |||
| 243 | [[trusted.regex-syntax]] | ||
| 244 | criteria = "safe-to-deploy" | ||
| 245 | user-id = 189 # Andrew Gallant (BurntSushi) | ||
| 246 | start = "2019-03-30" | ||
| 247 | end = "2026-11-26" | ||
| 248 | |||
| 249 | [[trusted.rustversion]] | ||
| 250 | criteria = "safe-to-deploy" | ||
| 251 | user-id = 3618 # David Tolnay (dtolnay) | ||
| 252 | start = "2019-07-08" | ||
| 253 | end = "2026-11-26" | ||
| 254 | |||
| 255 | [[trusted.scoped-tls]] | ||
| 256 | criteria = "safe-to-deploy" | ||
| 257 | user-id = 1 # Alex Crichton (alexcrichton) | ||
| 258 | start = "2019-02-26" | ||
| 259 | end = "2026-11-26" | ||
| 260 | |||
| 261 | [[trusted.thread_local]] | ||
| 262 | criteria = "safe-to-deploy" | ||
| 263 | user-id = 2915 # Amanieu d'Antras (Amanieu) | ||
| 264 | start = "2019-09-07" | ||
| 265 | end = "2026-11-26" | ||
| 266 | |||
| 267 | [[trusted.tracing-subscriber]] | ||
| 268 | criteria = "safe-to-deploy" | ||
| 269 | user-id = 10 # Carl Lerche (carllerche) | ||
| 270 | start = "2025-08-29" | ||
| 271 | end = "2026-11-26" | ||
| 272 | |||
| 273 | [[trusted.valuable]] | ||
| 274 | criteria = "safe-to-deploy" | ||
| 275 | user-id = 10 # Carl Lerche (carllerche) | ||
| 276 | start = "2022-01-03" | ||
| 277 | end = "2026-11-26" | ||
| 278 | |||
| 279 | [[trusted.windows]] | ||
| 280 | criteria = "safe-to-deploy" | ||
| 281 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 282 | start = "2021-01-15" | ||
| 283 | end = "2026-11-26" | ||
| 284 | |||
| 285 | [[trusted.windows-collections]] | ||
| 286 | criteria = "safe-to-deploy" | ||
| 287 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 288 | start = "2025-02-06" | ||
| 289 | end = "2026-11-26" | ||
| 290 | |||
| 291 | [[trusted.windows-core]] | ||
| 292 | criteria = "safe-to-deploy" | ||
| 293 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 294 | start = "2021-11-15" | ||
| 295 | end = "2026-11-26" | ||
| 296 | |||
| 297 | [[trusted.windows-future]] | ||
| 298 | criteria = "safe-to-deploy" | ||
| 299 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 300 | start = "2025-02-10" | ||
| 301 | end = "2026-11-26" | ||
| 302 | |||
| 303 | [[trusted.windows-implement]] | ||
| 304 | criteria = "safe-to-deploy" | ||
| 305 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 306 | start = "2022-01-27" | ||
| 307 | end = "2026-11-26" | ||
| 308 | |||
| 309 | [[trusted.windows-interface]] | ||
| 310 | criteria = "safe-to-deploy" | ||
| 311 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 312 | start = "2022-02-18" | ||
| 313 | end = "2026-11-26" | ||
| 314 | |||
| 315 | [[trusted.windows-link]] | ||
| 316 | criteria = "safe-to-deploy" | ||
| 317 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 318 | start = "2024-07-17" | ||
| 319 | end = "2026-11-26" | ||
| 320 | |||
| 321 | [[trusted.windows-numerics]] | ||
| 322 | criteria = "safe-to-deploy" | ||
| 323 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 324 | start = "2023-05-15" | ||
| 325 | end = "2026-11-26" | ||
| 326 | |||
| 327 | [[trusted.windows-result]] | ||
| 328 | criteria = "safe-to-deploy" | ||
| 329 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 330 | start = "2024-02-02" | ||
| 331 | end = "2026-11-26" | ||
| 332 | |||
| 333 | [[trusted.windows-strings]] | ||
| 334 | criteria = "safe-to-deploy" | ||
| 335 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 336 | start = "2024-02-02" | ||
| 337 | end = "2026-11-26" | ||
| 338 | |||
| 339 | [[trusted.windows-sys]] | ||
| 340 | criteria = "safe-to-deploy" | ||
| 341 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 342 | start = "2021-11-15" | ||
| 343 | end = "2026-11-26" | ||
| 344 | |||
| 345 | [[trusted.windows-threading]] | ||
| 346 | criteria = "safe-to-deploy" | ||
| 347 | user-id = 64539 # Kenny Kerr (kennykerr) | ||
| 348 | start = "2025-04-29" | ||
| 349 | end = "2026-11-26" | ||
diff --git a/embassy-mcxa/supply-chain/config.toml b/embassy-mcxa/supply-chain/config.toml new file mode 100644 index 000000000..5682db9ea --- /dev/null +++ b/embassy-mcxa/supply-chain/config.toml | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | |||
| 2 | # cargo-vet config file | ||
| 3 | |||
| 4 | [cargo-vet] | ||
| 5 | version = "0.10" | ||
| 6 | |||
| 7 | [imports.OpenDevicePartnership] | ||
| 8 | url = "https://raw.githubusercontent.com/OpenDevicePartnership/rust-crate-audits/main/audits.toml" | ||
| 9 | |||
| 10 | [imports.bytecode-alliance] | ||
| 11 | url = "https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/supply-chain/audits.toml" | ||
| 12 | |||
| 13 | [imports.google] | ||
| 14 | url = "https://raw.githubusercontent.com/google/rust-crate-audits/main/audits.toml" | ||
| 15 | |||
| 16 | [imports.mozilla] | ||
| 17 | url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml" | ||
| 18 | |||
| 19 | [[exemptions.bare-metal]] | ||
| 20 | version = "0.2.5" | ||
| 21 | criteria = "safe-to-deploy" | ||
| 22 | |||
| 23 | [[exemptions.bitfield]] | ||
| 24 | version = "0.13.2" | ||
| 25 | criteria = "safe-to-deploy" | ||
| 26 | |||
| 27 | [[exemptions.cortex-m]] | ||
| 28 | version = "0.7.7" | ||
| 29 | criteria = "safe-to-deploy" | ||
| 30 | |||
| 31 | [[exemptions.cortex-m-rt]] | ||
| 32 | version = "0.7.5" | ||
| 33 | criteria = "safe-to-deploy" | ||
| 34 | |||
| 35 | [[exemptions.cortex-m-rt-macros]] | ||
| 36 | version = "0.7.5" | ||
| 37 | criteria = "safe-to-deploy" | ||
| 38 | |||
| 39 | [[exemptions.critical-section]] | ||
| 40 | version = "1.2.0" | ||
| 41 | criteria = "safe-to-deploy" | ||
| 42 | |||
| 43 | [[exemptions.defmt]] | ||
| 44 | version = "1.0.1" | ||
| 45 | criteria = "safe-to-deploy" | ||
| 46 | |||
| 47 | [[exemptions.defmt-macros]] | ||
| 48 | version = "1.0.1" | ||
| 49 | criteria = "safe-to-deploy" | ||
| 50 | |||
| 51 | [[exemptions.defmt-parser]] | ||
| 52 | version = "1.0.0" | ||
| 53 | criteria = "safe-to-deploy" | ||
| 54 | |||
| 55 | [[exemptions.embassy-embedded-hal]] | ||
| 56 | version = "0.5.0" | ||
| 57 | criteria = "safe-to-deploy" | ||
| 58 | |||
| 59 | [[exemptions.embassy-futures]] | ||
| 60 | version = "0.1.2" | ||
| 61 | criteria = "safe-to-deploy" | ||
| 62 | |||
| 63 | [[exemptions.embassy-hal-internal]] | ||
| 64 | version = "0.3.0" | ||
| 65 | criteria = "safe-to-deploy" | ||
| 66 | |||
| 67 | [[exemptions.embassy-sync]] | ||
| 68 | version = "0.7.2" | ||
| 69 | criteria = "safe-to-deploy" | ||
| 70 | |||
| 71 | [[exemptions.embassy-time]] | ||
| 72 | version = "0.5.0" | ||
| 73 | criteria = "safe-to-deploy" | ||
| 74 | |||
| 75 | [[exemptions.embassy-time-driver]] | ||
| 76 | version = "0.2.1" | ||
| 77 | criteria = "safe-to-deploy" | ||
| 78 | |||
| 79 | [[exemptions.embedded-hal]] | ||
| 80 | version = "0.2.7" | ||
| 81 | criteria = "safe-to-deploy" | ||
| 82 | |||
| 83 | [[exemptions.embedded-hal]] | ||
| 84 | version = "1.0.0" | ||
| 85 | criteria = "safe-to-deploy" | ||
| 86 | |||
| 87 | [[exemptions.embedded-hal-async]] | ||
| 88 | version = "1.0.0" | ||
| 89 | criteria = "safe-to-deploy" | ||
| 90 | |||
| 91 | [[exemptions.embedded-hal-nb]] | ||
| 92 | version = "1.0.0" | ||
| 93 | criteria = "safe-to-deploy" | ||
| 94 | |||
| 95 | [[exemptions.embedded-io-async]] | ||
| 96 | version = "0.6.1" | ||
| 97 | criteria = "safe-to-deploy" | ||
| 98 | |||
| 99 | [[exemptions.embedded-storage]] | ||
| 100 | version = "0.3.1" | ||
| 101 | criteria = "safe-to-deploy" | ||
| 102 | |||
| 103 | [[exemptions.embedded-storage-async]] | ||
| 104 | version = "0.4.1" | ||
| 105 | criteria = "safe-to-deploy" | ||
| 106 | |||
| 107 | [[exemptions.hash32]] | ||
| 108 | version = "0.3.1" | ||
| 109 | criteria = "safe-to-deploy" | ||
| 110 | |||
| 111 | [[exemptions.heapless]] | ||
| 112 | version = "0.8.0" | ||
| 113 | criteria = "safe-to-deploy" | ||
| 114 | |||
| 115 | [[exemptions.proc-macro-error-attr2]] | ||
| 116 | version = "2.0.0" | ||
| 117 | criteria = "safe-to-deploy" | ||
| 118 | |||
| 119 | [[exemptions.proc-macro-error2]] | ||
| 120 | version = "2.0.1" | ||
| 121 | criteria = "safe-to-deploy" | ||
| 122 | |||
| 123 | [[exemptions.rustc_version]] | ||
| 124 | version = "0.2.3" | ||
| 125 | criteria = "safe-to-deploy" | ||
| 126 | |||
| 127 | [[exemptions.semver]] | ||
| 128 | version = "0.9.0" | ||
| 129 | criteria = "safe-to-deploy" | ||
| 130 | |||
| 131 | [[exemptions.semver-parser]] | ||
| 132 | version = "0.7.0" | ||
| 133 | criteria = "safe-to-deploy" | ||
| 134 | |||
| 135 | [[exemptions.vcell]] | ||
| 136 | version = "0.1.3" | ||
| 137 | criteria = "safe-to-deploy" | ||
| 138 | |||
| 139 | [[exemptions.volatile-register]] | ||
| 140 | version = "0.2.2" | ||
| 141 | criteria = "safe-to-deploy" | ||
diff --git a/embassy-mcxa/supply-chain/imports.lock b/embassy-mcxa/supply-chain/imports.lock new file mode 100644 index 000000000..dbd1235b0 --- /dev/null +++ b/embassy-mcxa/supply-chain/imports.lock | |||
| @@ -0,0 +1,523 @@ | |||
| 1 | |||
| 2 | # cargo-vet imports lock | ||
| 3 | |||
| 4 | [[publisher.aho-corasick]] | ||
| 5 | version = "1.1.4" | ||
| 6 | when = "2025-10-28" | ||
| 7 | user-id = 189 | ||
| 8 | user-login = "BurntSushi" | ||
| 9 | user-name = "Andrew Gallant" | ||
| 10 | |||
| 11 | [[publisher.libc]] | ||
| 12 | version = "0.2.177" | ||
| 13 | when = "2025-10-09" | ||
| 14 | user-id = 55123 | ||
| 15 | user-login = "rust-lang-owner" | ||
| 16 | |||
| 17 | [[publisher.loom]] | ||
| 18 | version = "0.7.2" | ||
| 19 | when = "2024-04-23" | ||
| 20 | user-id = 6741 | ||
| 21 | user-login = "Darksonn" | ||
| 22 | user-name = "Alice Ryhl" | ||
| 23 | |||
| 24 | [[publisher.memchr]] | ||
| 25 | version = "2.7.6" | ||
| 26 | when = "2025-09-25" | ||
| 27 | user-id = 189 | ||
| 28 | user-login = "BurntSushi" | ||
| 29 | user-name = "Andrew Gallant" | ||
| 30 | |||
| 31 | [[publisher.paste]] | ||
| 32 | version = "1.0.15" | ||
| 33 | when = "2024-05-07" | ||
| 34 | user-id = 3618 | ||
| 35 | user-login = "dtolnay" | ||
| 36 | user-name = "David Tolnay" | ||
| 37 | |||
| 38 | [[publisher.regex-automata]] | ||
| 39 | version = "0.4.13" | ||
| 40 | when = "2025-10-13" | ||
| 41 | user-id = 189 | ||
| 42 | user-login = "BurntSushi" | ||
| 43 | user-name = "Andrew Gallant" | ||
| 44 | |||
| 45 | [[publisher.regex-syntax]] | ||
| 46 | version = "0.8.8" | ||
| 47 | when = "2025-10-13" | ||
| 48 | user-id = 189 | ||
| 49 | user-login = "BurntSushi" | ||
| 50 | user-name = "Andrew Gallant" | ||
| 51 | |||
| 52 | [[publisher.rustversion]] | ||
| 53 | version = "1.0.22" | ||
| 54 | when = "2025-08-08" | ||
| 55 | user-id = 3618 | ||
| 56 | user-login = "dtolnay" | ||
| 57 | user-name = "David Tolnay" | ||
| 58 | |||
| 59 | [[publisher.scoped-tls]] | ||
| 60 | version = "1.0.1" | ||
| 61 | when = "2022-10-31" | ||
| 62 | user-id = 1 | ||
| 63 | user-login = "alexcrichton" | ||
| 64 | user-name = "Alex Crichton" | ||
| 65 | |||
| 66 | [[publisher.thread_local]] | ||
| 67 | version = "1.1.9" | ||
| 68 | when = "2025-06-12" | ||
| 69 | user-id = 2915 | ||
| 70 | user-login = "Amanieu" | ||
| 71 | user-name = "Amanieu d'Antras" | ||
| 72 | |||
| 73 | [[publisher.tracing-subscriber]] | ||
| 74 | version = "0.3.20" | ||
| 75 | when = "2025-08-29" | ||
| 76 | user-id = 10 | ||
| 77 | user-login = "carllerche" | ||
| 78 | user-name = "Carl Lerche" | ||
| 79 | |||
| 80 | [[publisher.windows]] | ||
| 81 | version = "0.61.3" | ||
| 82 | when = "2025-06-12" | ||
| 83 | user-id = 64539 | ||
| 84 | user-login = "kennykerr" | ||
| 85 | user-name = "Kenny Kerr" | ||
| 86 | |||
| 87 | [[publisher.windows-collections]] | ||
| 88 | version = "0.2.0" | ||
| 89 | when = "2025-03-18" | ||
| 90 | user-id = 64539 | ||
| 91 | user-login = "kennykerr" | ||
| 92 | user-name = "Kenny Kerr" | ||
| 93 | |||
| 94 | [[publisher.windows-core]] | ||
| 95 | version = "0.61.2" | ||
| 96 | when = "2025-05-19" | ||
| 97 | user-id = 64539 | ||
| 98 | user-login = "kennykerr" | ||
| 99 | user-name = "Kenny Kerr" | ||
| 100 | |||
| 101 | [[publisher.windows-future]] | ||
| 102 | version = "0.2.1" | ||
| 103 | when = "2025-05-15" | ||
| 104 | user-id = 64539 | ||
| 105 | user-login = "kennykerr" | ||
| 106 | user-name = "Kenny Kerr" | ||
| 107 | |||
| 108 | [[publisher.windows-implement]] | ||
| 109 | version = "0.60.2" | ||
| 110 | when = "2025-10-06" | ||
| 111 | user-id = 64539 | ||
| 112 | user-login = "kennykerr" | ||
| 113 | user-name = "Kenny Kerr" | ||
| 114 | |||
| 115 | [[publisher.windows-interface]] | ||
| 116 | version = "0.59.3" | ||
| 117 | when = "2025-10-06" | ||
| 118 | user-id = 64539 | ||
| 119 | user-login = "kennykerr" | ||
| 120 | user-name = "Kenny Kerr" | ||
| 121 | |||
| 122 | [[publisher.windows-link]] | ||
| 123 | version = "0.1.3" | ||
| 124 | when = "2025-06-12" | ||
| 125 | user-id = 64539 | ||
| 126 | user-login = "kennykerr" | ||
| 127 | user-name = "Kenny Kerr" | ||
| 128 | |||
| 129 | [[publisher.windows-link]] | ||
| 130 | version = "0.2.1" | ||
| 131 | when = "2025-10-06" | ||
| 132 | user-id = 64539 | ||
| 133 | user-login = "kennykerr" | ||
| 134 | user-name = "Kenny Kerr" | ||
| 135 | |||
| 136 | [[publisher.windows-numerics]] | ||
| 137 | version = "0.2.0" | ||
| 138 | when = "2025-03-18" | ||
| 139 | user-id = 64539 | ||
| 140 | user-login = "kennykerr" | ||
| 141 | user-name = "Kenny Kerr" | ||
| 142 | |||
| 143 | [[publisher.windows-result]] | ||
| 144 | version = "0.3.4" | ||
| 145 | when = "2025-05-19" | ||
| 146 | user-id = 64539 | ||
| 147 | user-login = "kennykerr" | ||
| 148 | user-name = "Kenny Kerr" | ||
| 149 | |||
| 150 | [[publisher.windows-strings]] | ||
| 151 | version = "0.4.2" | ||
| 152 | when = "2025-05-19" | ||
| 153 | user-id = 64539 | ||
| 154 | user-login = "kennykerr" | ||
| 155 | user-name = "Kenny Kerr" | ||
| 156 | |||
| 157 | [[publisher.windows-sys]] | ||
| 158 | version = "0.61.2" | ||
| 159 | when = "2025-10-06" | ||
| 160 | user-id = 64539 | ||
| 161 | user-login = "kennykerr" | ||
| 162 | user-name = "Kenny Kerr" | ||
| 163 | |||
| 164 | [[publisher.windows-threading]] | ||
| 165 | version = "0.1.0" | ||
| 166 | when = "2025-05-15" | ||
| 167 | user-id = 64539 | ||
| 168 | user-login = "kennykerr" | ||
| 169 | user-name = "Kenny Kerr" | ||
| 170 | |||
| 171 | [audits.OpenDevicePartnership.audits] | ||
| 172 | |||
| 173 | [[audits.bytecode-alliance.audits.embedded-io]] | ||
| 174 | who = "Alex Crichton <[email protected]>" | ||
| 175 | criteria = "safe-to-deploy" | ||
| 176 | version = "0.4.0" | ||
| 177 | notes = "No `unsafe` code and only uses `std` in ways one would expect the crate to do so." | ||
| 178 | |||
| 179 | [[audits.bytecode-alliance.audits.embedded-io]] | ||
| 180 | who = "Alex Crichton <[email protected]>" | ||
| 181 | criteria = "safe-to-deploy" | ||
| 182 | delta = "0.4.0 -> 0.6.1" | ||
| 183 | notes = "Major updates, but almost all safe code. Lots of pruning/deletions, nothing out of the ordrinary." | ||
| 184 | |||
| 185 | [[audits.bytecode-alliance.audits.futures-core]] | ||
| 186 | who = "Pat Hickey <[email protected]>" | ||
| 187 | criteria = "safe-to-deploy" | ||
| 188 | version = "0.3.27" | ||
| 189 | notes = "Unsafe used to implement a concurrency primitive AtomicWaker. Well-commented and not obviously incorrect. Like my other audits of these concurrency primitives inside the futures family, I couldn't certify that it is correct without formal methods, but that is out of scope for this vetting." | ||
| 190 | |||
| 191 | [[audits.bytecode-alliance.audits.futures-core]] | ||
| 192 | who = "Pat Hickey <[email protected]>" | ||
| 193 | criteria = "safe-to-deploy" | ||
| 194 | delta = "0.3.28 -> 0.3.31" | ||
| 195 | |||
| 196 | [[audits.bytecode-alliance.audits.futures-sink]] | ||
| 197 | who = "Pat Hickey <[email protected]>" | ||
| 198 | criteria = "safe-to-deploy" | ||
| 199 | version = "0.3.27" | ||
| 200 | |||
| 201 | [[audits.bytecode-alliance.audits.futures-sink]] | ||
| 202 | who = "Pat Hickey <[email protected]>" | ||
| 203 | criteria = "safe-to-deploy" | ||
| 204 | delta = "0.3.28 -> 0.3.31" | ||
| 205 | |||
| 206 | [[audits.bytecode-alliance.audits.log]] | ||
| 207 | who = "Alex Crichton <[email protected]>" | ||
| 208 | criteria = "safe-to-deploy" | ||
| 209 | delta = "0.4.22 -> 0.4.27" | ||
| 210 | notes = "Lots of minor updates to macros and such, nothing touching `unsafe`" | ||
| 211 | |||
| 212 | [[audits.bytecode-alliance.audits.log]] | ||
| 213 | who = "Alex Crichton <[email protected]>" | ||
| 214 | criteria = "safe-to-deploy" | ||
| 215 | delta = "0.4.27 -> 0.4.28" | ||
| 216 | notes = "Minor doc updates and lots new tests, nothing out of the ordinary." | ||
| 217 | |||
| 218 | [[audits.bytecode-alliance.audits.matchers]] | ||
| 219 | who = "Pat Hickey <[email protected]>" | ||
| 220 | criteria = "safe-to-deploy" | ||
| 221 | version = "0.1.0" | ||
| 222 | |||
| 223 | [[audits.bytecode-alliance.audits.matchers]] | ||
| 224 | who = "Alex Crichton <[email protected]>" | ||
| 225 | criteria = "safe-to-deploy" | ||
| 226 | delta = "0.1.0 -> 0.2.0" | ||
| 227 | notes = "Some unsafe code, but not more than before. Nothing awry." | ||
| 228 | |||
| 229 | [[audits.bytecode-alliance.audits.nu-ansi-term]] | ||
| 230 | who = "Pat Hickey <[email protected]>" | ||
| 231 | criteria = "safe-to-deploy" | ||
| 232 | version = "0.46.0" | ||
| 233 | notes = "one use of unsafe to call windows specific api to get console handle." | ||
| 234 | |||
| 235 | [[audits.bytecode-alliance.audits.nu-ansi-term]] | ||
| 236 | who = "Alex Crichton <[email protected]>" | ||
| 237 | criteria = "safe-to-deploy" | ||
| 238 | delta = "0.46.0 -> 0.50.1" | ||
| 239 | notes = "Lots of stylistic/rust-related chanegs, plus new features, but nothing out of the ordrinary." | ||
| 240 | |||
| 241 | [[audits.bytecode-alliance.audits.nu-ansi-term]] | ||
| 242 | who = "Alex Crichton <[email protected]>" | ||
| 243 | criteria = "safe-to-deploy" | ||
| 244 | delta = "0.50.1 -> 0.50.3" | ||
| 245 | notes = "CI changes, Rust changes, nothing out of the ordinary." | ||
| 246 | |||
| 247 | [[audits.bytecode-alliance.audits.sharded-slab]] | ||
| 248 | who = "Pat Hickey <[email protected]>" | ||
| 249 | criteria = "safe-to-deploy" | ||
| 250 | version = "0.1.4" | ||
| 251 | notes = "I always really enjoy reading eliza's code, she left perfect comments at every use of unsafe." | ||
| 252 | |||
| 253 | [[audits.bytecode-alliance.audits.shlex]] | ||
| 254 | who = "Alex Crichton <[email protected]>" | ||
| 255 | criteria = "safe-to-deploy" | ||
| 256 | version = "1.1.0" | ||
| 257 | notes = "Only minor `unsafe` code blocks which look valid and otherwise does what it says on the tin." | ||
| 258 | |||
| 259 | [[audits.bytecode-alliance.audits.tracing-attributes]] | ||
| 260 | who = "Alex Crichton <[email protected]>" | ||
| 261 | criteria = "safe-to-deploy" | ||
| 262 | delta = "0.1.28 -> 0.1.30" | ||
| 263 | notes = "Few code changes, a pretty minor update." | ||
| 264 | |||
| 265 | [[audits.bytecode-alliance.audits.tracing-core]] | ||
| 266 | who = "Alex Crichton <[email protected]>" | ||
| 267 | criteria = "safe-to-deploy" | ||
| 268 | delta = "0.1.33 -> 0.1.34" | ||
| 269 | notes = "Mostly just an update with Rust stylistic conventions changing. Nothing awry." | ||
| 270 | |||
| 271 | [[audits.bytecode-alliance.audits.tracing-log]] | ||
| 272 | who = "Alex Crichton <[email protected]>" | ||
| 273 | criteria = "safe-to-deploy" | ||
| 274 | version = "0.1.3" | ||
| 275 | notes = """ | ||
| 276 | This is a standard adapter between the `log` ecosystem and the `tracing` | ||
| 277 | ecosystem. There's one `unsafe` block in this crate and it's well-scoped. | ||
| 278 | """ | ||
| 279 | |||
| 280 | [[audits.bytecode-alliance.audits.tracing-log]] | ||
| 281 | who = "Alex Crichton <[email protected]>" | ||
| 282 | criteria = "safe-to-deploy" | ||
| 283 | delta = "0.1.3 -> 0.2.0" | ||
| 284 | notes = "Nothing out of the ordinary, a typical major version update and nothing awry." | ||
| 285 | |||
| 286 | [[audits.google.audits.bitflags]] | ||
| 287 | who = "Lukasz Anforowicz <[email protected]>" | ||
| 288 | criteria = "safe-to-deploy" | ||
| 289 | version = "1.3.2" | ||
| 290 | notes = """ | ||
| 291 | Security review of earlier versions of the crate can be found at | ||
| 292 | (Google-internal, sorry): go/image-crate-chromium-security-review | ||
| 293 | |||
| 294 | The crate exposes a function marked as `unsafe`, but doesn't use any | ||
| 295 | `unsafe` blocks (except for tests of the single `unsafe` function). I | ||
| 296 | think this justifies marking this crate as `ub-risk-1`. | ||
| 297 | |||
| 298 | Additional review comments can be found at https://crrev.com/c/4723145/31 | ||
| 299 | """ | ||
| 300 | aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" | ||
| 301 | |||
| 302 | [[audits.google.audits.byteorder]] | ||
| 303 | who = "danakj <[email protected]>" | ||
| 304 | criteria = "safe-to-deploy" | ||
| 305 | version = "1.5.0" | ||
| 306 | notes = "Unsafe review in https://crrev.com/c/5838022" | ||
| 307 | aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" | ||
| 308 | |||
| 309 | [[audits.google.audits.lazy_static]] | ||
| 310 | who = "Lukasz Anforowicz <[email protected]>" | ||
| 311 | criteria = "safe-to-deploy" | ||
| 312 | version = "1.4.0" | ||
| 313 | notes = ''' | ||
| 314 | I grepped for \"crypt\", \"cipher\", \"fs\", \"net\" - there were no hits. | ||
| 315 | |||
| 316 | There are two places where `unsafe` is used. Unsafe review notes can be found | ||
| 317 | in https://crrev.com/c/5347418. | ||
| 318 | |||
| 319 | This crate has been added to Chromium in https://crrev.com/c/3321895. | ||
| 320 | ''' | ||
| 321 | aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" | ||
| 322 | |||
| 323 | [[audits.google.audits.lazy_static]] | ||
| 324 | who = "Lukasz Anforowicz <[email protected]>" | ||
| 325 | criteria = "safe-to-deploy" | ||
| 326 | delta = "1.4.0 -> 1.5.0" | ||
| 327 | notes = "Unsafe review notes: https://crrev.com/c/5650836" | ||
| 328 | aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" | ||
| 329 | |||
| 330 | [[audits.google.audits.log]] | ||
| 331 | who = "danakj <[email protected]>" | ||
| 332 | criteria = "safe-to-deploy" | ||
| 333 | version = "0.4.22" | ||
| 334 | notes = """ | ||
| 335 | Unsafe review in https://docs.google.com/document/d/1IXQbD1GhTRqNHIGxq6yy7qHqxeO4CwN5noMFXnqyDIM/edit?usp=sharing | ||
| 336 | |||
| 337 | Unsafety is generally very well-documented, with one exception, which we | ||
| 338 | describe in the review doc. | ||
| 339 | """ | ||
| 340 | aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" | ||
| 341 | |||
| 342 | [[audits.google.audits.nb]] | ||
| 343 | who = "George Burgess IV <[email protected]>" | ||
| 344 | criteria = "safe-to-deploy" | ||
| 345 | version = "1.0.0" | ||
| 346 | aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" | ||
| 347 | |||
| 348 | [[audits.google.audits.nb]] | ||
| 349 | who = "George Burgess IV <[email protected]>" | ||
| 350 | criteria = "safe-to-deploy" | ||
| 351 | delta = "1.0.0 -> 0.1.3" | ||
| 352 | aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" | ||
| 353 | |||
| 354 | [[audits.google.audits.nb]] | ||
| 355 | who = "George Burgess IV <[email protected]>" | ||
| 356 | criteria = "safe-to-deploy" | ||
| 357 | delta = "1.0.0 -> 1.1.0" | ||
| 358 | aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" | ||
| 359 | |||
| 360 | [[audits.google.audits.num-traits]] | ||
| 361 | who = "Manish Goregaokar <[email protected]>" | ||
| 362 | criteria = "safe-to-deploy" | ||
| 363 | version = "0.2.19" | ||
| 364 | notes = "Contains a single line of float-to-int unsafe with decent safety comments" | ||
| 365 | aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" | ||
| 366 | |||
| 367 | [[audits.google.audits.pin-project-lite]] | ||
| 368 | who = "David Koloski <[email protected]>" | ||
| 369 | criteria = "safe-to-deploy" | ||
| 370 | version = "0.2.9" | ||
| 371 | notes = "Reviewed on https://fxrev.dev/824504" | ||
| 372 | aggregated-from = "https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/third_party/rust_crates/supply-chain/audits.toml?format=TEXT" | ||
| 373 | |||
| 374 | [[audits.google.audits.pin-project-lite]] | ||
| 375 | who = "David Koloski <[email protected]>" | ||
| 376 | criteria = "safe-to-deploy" | ||
| 377 | delta = "0.2.9 -> 0.2.13" | ||
| 378 | notes = "Audited at https://fxrev.dev/946396" | ||
| 379 | aggregated-from = "https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/third_party/rust_crates/supply-chain/audits.toml?format=TEXT" | ||
| 380 | |||
| 381 | [[audits.google.audits.smallvec]] | ||
| 382 | who = "Manish Goregaokar <[email protected]>" | ||
| 383 | criteria = "safe-to-deploy" | ||
| 384 | version = "1.13.2" | ||
| 385 | aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" | ||
| 386 | |||
| 387 | [[audits.google.audits.smallvec]] | ||
| 388 | who = "Jonathan Hao <[email protected]>" | ||
| 389 | criteria = "safe-to-deploy" | ||
| 390 | delta = "1.13.2 -> 1.14.0" | ||
| 391 | notes = """ | ||
| 392 | WARNING: This certification is a result of a **partial** audit. The | ||
| 393 | `malloc_size_of` feature has **not** been audited. This feature does | ||
| 394 | not explicitly document its safety requirements. | ||
| 395 | See also https://chromium-review.googlesource.com/c/chromium/src/+/6275133/comment/ea0d7a93_98051a2e/ | ||
| 396 | and https://github.com/servo/malloc_size_of/issues/8. | ||
| 397 | This feature is banned in gnrt_config.toml. | ||
| 398 | """ | ||
| 399 | aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" | ||
| 400 | |||
| 401 | [[audits.google.audits.void]] | ||
| 402 | who = "George Burgess IV <[email protected]>" | ||
| 403 | criteria = "safe-to-deploy" | ||
| 404 | version = "1.0.2" | ||
| 405 | aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" | ||
| 406 | |||
| 407 | [[audits.mozilla.audits.futures-core]] | ||
| 408 | who = "Mike Hommey <[email protected]>" | ||
| 409 | criteria = "safe-to-deploy" | ||
| 410 | delta = "0.3.27 -> 0.3.28" | ||
| 411 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 412 | |||
| 413 | [[audits.mozilla.audits.futures-sink]] | ||
| 414 | who = "Mike Hommey <[email protected]>" | ||
| 415 | criteria = "safe-to-deploy" | ||
| 416 | delta = "0.3.27 -> 0.3.28" | ||
| 417 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 418 | |||
| 419 | [[audits.mozilla.audits.once_cell]] | ||
| 420 | who = "Erich Gubler <[email protected]>" | ||
| 421 | criteria = "safe-to-deploy" | ||
| 422 | delta = "1.20.1 -> 1.20.2" | ||
| 423 | notes = "This update works around a Cargo bug that forces the addition of `portable-atomic` into a lockfile, which we have never needed to use." | ||
| 424 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 425 | |||
| 426 | [[audits.mozilla.audits.once_cell]] | ||
| 427 | who = "Erich Gubler <[email protected]>" | ||
| 428 | criteria = "safe-to-deploy" | ||
| 429 | delta = "1.20.2 -> 1.20.3" | ||
| 430 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 431 | |||
| 432 | [[audits.mozilla.audits.once_cell]] | ||
| 433 | who = "Erich Gubler <[email protected]>" | ||
| 434 | criteria = "safe-to-deploy" | ||
| 435 | delta = "1.20.3 -> 1.21.1" | ||
| 436 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 437 | |||
| 438 | [[audits.mozilla.audits.once_cell]] | ||
| 439 | who = "Erich Gubler <[email protected]>" | ||
| 440 | criteria = "safe-to-deploy" | ||
| 441 | delta = "1.21.1 -> 1.21.3" | ||
| 442 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 443 | |||
| 444 | [[audits.mozilla.audits.pin-project-lite]] | ||
| 445 | who = "Mike Hommey <[email protected]>" | ||
| 446 | criteria = "safe-to-deploy" | ||
| 447 | delta = "0.2.13 -> 0.2.14" | ||
| 448 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 449 | |||
| 450 | [[audits.mozilla.audits.pin-project-lite]] | ||
| 451 | who = "Nika Layzell <[email protected]>" | ||
| 452 | criteria = "safe-to-deploy" | ||
| 453 | delta = "0.2.14 -> 0.2.16" | ||
| 454 | notes = """ | ||
| 455 | Only functional change is to work around a bug in the negative_impls feature | ||
| 456 | (https://github.com/taiki-e/pin-project/issues/340#issuecomment-2432146009) | ||
| 457 | """ | ||
| 458 | aggregated-from = "https://raw.githubusercontent.com/mozilla/cargo-vet/main/supply-chain/audits.toml" | ||
| 459 | |||
| 460 | [[audits.mozilla.audits.sharded-slab]] | ||
| 461 | who = "Mark Hammond <[email protected]>" | ||
| 462 | criteria = "safe-to-deploy" | ||
| 463 | delta = "0.1.4 -> 0.1.7" | ||
| 464 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 465 | |||
| 466 | [[audits.mozilla.audits.shlex]] | ||
| 467 | who = "Max Inden <[email protected]>" | ||
| 468 | criteria = "safe-to-deploy" | ||
| 469 | delta = "1.1.0 -> 1.3.0" | ||
| 470 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 471 | |||
| 472 | [[audits.mozilla.audits.smallvec]] | ||
| 473 | who = "Erich Gubler <[email protected]>" | ||
| 474 | criteria = "safe-to-deploy" | ||
| 475 | delta = "1.14.0 -> 1.15.1" | ||
| 476 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 477 | |||
| 478 | [[audits.mozilla.audits.tracing]] | ||
| 479 | who = "Alex Franchuk <[email protected]>" | ||
| 480 | criteria = "safe-to-deploy" | ||
| 481 | version = "0.1.37" | ||
| 482 | notes = """ | ||
| 483 | There's only one unsafe impl, and its purpose is to ensure correct behavior by | ||
| 484 | creating a non-Send marker type (it has nothing to do with soundness). All | ||
| 485 | dependencies make sense, and no side-effectful std functions are used. | ||
| 486 | """ | ||
| 487 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 488 | |||
| 489 | [[audits.mozilla.audits.tracing]] | ||
| 490 | who = "Mark Hammond <[email protected]>" | ||
| 491 | criteria = "safe-to-deploy" | ||
| 492 | delta = "0.1.37 -> 0.1.41" | ||
| 493 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 494 | |||
| 495 | [[audits.mozilla.audits.tracing-attributes]] | ||
| 496 | who = "Alex Franchuk <[email protected]>" | ||
| 497 | criteria = "safe-to-deploy" | ||
| 498 | version = "0.1.24" | ||
| 499 | notes = "No unsafe code, macros extensively tested and produce reasonable code." | ||
| 500 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 501 | |||
| 502 | [[audits.mozilla.audits.tracing-attributes]] | ||
| 503 | who = "Mark Hammond <[email protected]>" | ||
| 504 | criteria = "safe-to-deploy" | ||
| 505 | delta = "0.1.24 -> 0.1.28" | ||
| 506 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 507 | |||
| 508 | [[audits.mozilla.audits.tracing-core]] | ||
| 509 | who = "Alex Franchuk <[email protected]>" | ||
| 510 | criteria = "safe-to-deploy" | ||
| 511 | version = "0.1.30" | ||
| 512 | notes = """ | ||
| 513 | Most unsafe code is in implementing non-std sync primitives. Unsafe impls are | ||
| 514 | logically correct and justified in comments, and unsafe code is sound and | ||
| 515 | justified in comments. | ||
| 516 | """ | ||
| 517 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
| 518 | |||
| 519 | [[audits.mozilla.audits.tracing-core]] | ||
| 520 | who = "Mark Hammond <[email protected]>" | ||
| 521 | criteria = "safe-to-deploy" | ||
| 522 | delta = "0.1.30 -> 0.1.33" | ||
| 523 | aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" | ||
diff --git a/embassy-mcxa/tools/run_and_attach_rtt.sh b/embassy-mcxa/tools/run_and_attach_rtt.sh new file mode 100644 index 000000000..13041d06b --- /dev/null +++ b/embassy-mcxa/tools/run_and_attach_rtt.sh | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | set -euo pipefail | ||
| 3 | |||
| 4 | ELF="${1:-target/thumbv8m.main-none-eabihf/debug/examples/hello}" | ||
| 5 | PROBE_ID="${2:-1fc9:0143:H3AYDQVQMTROB}" | ||
| 6 | CHIP="${3:-MCXA276}" | ||
| 7 | SPEED="${4:-1000}" | ||
| 8 | |||
| 9 | # 1) Flash & run using the existing run.sh (probe is in use only during this step) | ||
| 10 | ./run.sh "$ELF" | ||
| 11 | |||
| 12 | # 2) Give target a short moment to boot and set up RTT CB in RAM | ||
| 13 | sleep 0.5 | ||
| 14 | |||
| 15 | # 3) Attach RTT/defmt using probe-rs (no flashing) | ||
| 16 | exec probe-rs attach \ | ||
| 17 | --chip "$CHIP" \ | ||
| 18 | --probe "$PROBE_ID" \ | ||
| 19 | --protocol swd \ | ||
| 20 | --speed "$SPEED" \ | ||
| 21 | "$ELF" \ | ||
| 22 | --rtt-scan-memory \ | ||
| 23 | --log-format oneline | ||
| 24 | |||
diff --git a/embassy-mcxa/tools/run_jlink_noblock.sh b/embassy-mcxa/tools/run_jlink_noblock.sh new file mode 100644 index 000000000..3ea1f2b4b --- /dev/null +++ b/embassy-mcxa/tools/run_jlink_noblock.sh | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | set -euo pipefail | ||
| 3 | |||
| 4 | ELF="${1:-}" | ||
| 5 | PROBE_ID="${2:-1366:0101:000600110607}" # default to your J-Link | ||
| 6 | CHIP="${3:-MCXA276}" | ||
| 7 | SPEED="${4:-1000}" | ||
| 8 | PORT="${PROBE_RS_GDB_PORT:-1337}" | ||
| 9 | |||
| 10 | if [[ -z "${ELF}" || ! -f "${ELF}" ]]; then | ||
| 11 | echo "Usage: $0 <elf> [probe-id] [chip] [speed-khz]" >&2 | ||
| 12 | exit 1 | ||
| 13 | fi | ||
| 14 | |||
| 15 | if ! command -v probe-rs >/dev/null 2>&1; then | ||
| 16 | echo "probe-rs not found (cargo install probe-rs --features cli)" >&2 | ||
| 17 | exit 1 | ||
| 18 | fi | ||
| 19 | if ! command -v gdb-multiarch >/dev/null 2>&1; then | ||
| 20 | echo "gdb-multiarch not found; install it (e.g., sudo apt install gdb-multiarch)." >&2 | ||
| 21 | exit 1 | ||
| 22 | fi | ||
| 23 | |||
| 24 | # Start probe-rs GDB server | ||
| 25 | SERVER_LOG=$(mktemp) | ||
| 26 | probe-rs gdb --chip "${CHIP}" --protocol swd --speed "${SPEED}" --non-interactive "${ELF}" --probe "${PROBE_ID}" \ | ||
| 27 | >"${SERVER_LOG}" 2>&1 & | ||
| 28 | GDB_SERVER_PID=$! | ||
| 29 | |||
| 30 | # Wait for readiness | ||
| 31 | for _ in {1..50}; do | ||
| 32 | if grep -q "Firing up GDB stub" "${SERVER_LOG}"; then break; fi | ||
| 33 | if grep -q "Connecting to the chip was unsuccessful" "${SERVER_LOG}"; then | ||
| 34 | echo "probe-rs gdb server failed. Log:" >&2 | ||
| 35 | sed -e 's/^/ /' "${SERVER_LOG}" >&2 || true | ||
| 36 | kill "${GDB_SERVER_PID}" 2>/dev/null || true | ||
| 37 | exit 1 | ||
| 38 | fi | ||
| 39 | sleep 0.1 | ||
| 40 | done | ||
| 41 | |||
| 42 | # GDB script: load, resume, detach | ||
| 43 | GDB_SCRIPT=$(mktemp) | ||
| 44 | cat >"${GDB_SCRIPT}" <<EOF | ||
| 45 | set pagination off | ||
| 46 | set confirm off | ||
| 47 | set mem inaccessible-by-default off | ||
| 48 | |||
| 49 | target remote :${PORT} | ||
| 50 | monitor halt | ||
| 51 | load | ||
| 52 | set language c | ||
| 53 | # Start clean from Reset vector in RAM | ||
| 54 | set {int}0xE000ED08 = 0x20000000 | ||
| 55 | set \$xpsr = 0x01000000 | ||
| 56 | set \$sp = 0x20020000 | ||
| 57 | set \$pc = Reset | ||
| 58 | monitor resume | ||
| 59 | detach | ||
| 60 | quit | ||
| 61 | EOF | ||
| 62 | |||
| 63 | # Run GDB to program and resume target, then exit (probe released) | ||
| 64 | if ! gdb-multiarch -q -x "${GDB_SCRIPT}" "${ELF}"; then | ||
| 65 | echo "GDB failed; server log:" >&2 | ||
| 66 | sed -e 's/^/ /' "${SERVER_LOG}" >&2 || true | ||
| 67 | kill "${GDB_SERVER_PID}" 2>/dev/null || true | ||
| 68 | exit 1 | ||
| 69 | fi | ||
| 70 | |||
| 71 | # Stop server now that we've detached | ||
| 72 | kill "${GDB_SERVER_PID}" 2>/dev/null || true | ||
| 73 | rm -f "${GDB_SCRIPT}" "${SERVER_LOG}" || true | ||
| 74 | |||
| 75 | echo "Flashed, resumed, and detached (probe free)." | ||
| 76 | |||
