Monorepo for Rust support of VA416XX family of radiation hardened MCUs
This commit is contained in:
commit
5d1740efea
40
.cargo/def-config.toml
Normal file
40
.cargo/def-config.toml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
runner = "gdb-multiarch -q -x jlink/jlink.gdb"
|
||||||
|
# runner = "arm-none-eabi-gdb -q -x jlink/jlink-reva.gdb"
|
||||||
|
# runner = "gdb-multiarch -q -x jlink/jlink-reva.gdb"
|
||||||
|
|
||||||
|
# Probe-rs is currently problematic, possibly because of the
|
||||||
|
# ROM protection?
|
||||||
|
# runner = "probe-rs run --chip-description-path ./scripts/VA416xx_Series.yaml"
|
||||||
|
# runner = ["probe-rs", "run", "--chip", "$CHIP", "--log-format", "{L} {s}"]
|
||||||
|
|
||||||
|
|
||||||
|
rustflags = [
|
||||||
|
"-C",
|
||||||
|
"link-arg=-Tlink.x",
|
||||||
|
# "-C",
|
||||||
|
# "linker=flip-link",
|
||||||
|
# "-C",
|
||||||
|
# "link-arg=-Tdefmt.x",
|
||||||
|
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||||
|
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||||
|
"-C",
|
||||||
|
"link-arg=--nmagic",
|
||||||
|
# Can be useful for debugging.
|
||||||
|
# "-Clink-args=-Map=app.map"
|
||||||
|
]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
# (`thumbv6m-*` is compatible with all ARM Cortex-M chips but using the right
|
||||||
|
# target improves performance)
|
||||||
|
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||||
|
# target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
|
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||||
|
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||||
|
|
||||||
|
[alias]
|
||||||
|
rb = "run --bin"
|
||||||
|
rrb = "run --release --bin"
|
||||||
|
|
||||||
|
[env]
|
||||||
|
DEFMT_LOG = "info"
|
52
.github/workflows/ci.yml
vendored
Normal file
52
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
name: ci
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: Check build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: "thumbv7em-none-eabihf"
|
||||||
|
- run: cargo check --target thumbv7em-none-eabihf --release
|
||||||
|
- run: cargo check --target thumbv7em-none-eabihf --examples --release
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: Run Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- name: Install nextest
|
||||||
|
uses: taiki-e/install-action@nextest
|
||||||
|
- run: cargo nextest run --all-features -p va416xx-hal
|
||||||
|
# I think we can skip those on an embedded crate..
|
||||||
|
# - run: cargo test --doc -p va108xx-hal
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
name: Check formatting
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- run: cargo fmt --all -- --check
|
||||||
|
|
||||||
|
docs:
|
||||||
|
name: Check Documentation Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc --all-features
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
name: Clippy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: "thumbv7em-none-eabihf"
|
||||||
|
- run: cargo clippy --target thumbv7em-none-eabihf -- -D warnings
|
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
/.vscode
|
||||||
|
|
||||||
|
# Ignore user config
|
||||||
|
/.cargo/config.toml
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
/app.map
|
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
26
Cargo.toml
Normal file
26
Cargo.toml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
members = [
|
||||||
|
"examples/simple",
|
||||||
|
"va416xx",
|
||||||
|
"va416xx-hal",
|
||||||
|
"vorago-peb1"
|
||||||
|
]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
codegen-units = 1
|
||||||
|
debug = 2
|
||||||
|
debug-assertions = true # <-
|
||||||
|
incremental = false
|
||||||
|
opt-level = 'z' # <-
|
||||||
|
overflow-checks = true # <-
|
||||||
|
|
||||||
|
# cargo build/run --release
|
||||||
|
[profile.release]
|
||||||
|
codegen-units = 1
|
||||||
|
debug = 2
|
||||||
|
debug-assertions = false # <-
|
||||||
|
incremental = false
|
||||||
|
lto = 'fat'
|
||||||
|
opt-level = 3 # <-
|
||||||
|
overflow-checks = false # <-
|
201
LICENSE-APACHE
Normal file
201
LICENSE-APACHE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
3
NOTICE
Normal file
3
NOTICE
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Workspace to develop Rust for the VA416xx devices
|
||||||
|
|
||||||
|
This software contains code developed at the University of Stuttgart.
|
109
README.md
Normal file
109
README.md
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
[![build](https://github.com/us-irs/va416xx-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/us-irs/va416xx-rs/actions/workflows/ci.yml)
|
||||||
|
|
||||||
|
Vorago VA416xx Rust Support
|
||||||
|
=========
|
||||||
|
|
||||||
|
This crate collection provided support to write Rust applications for the VA416XX family
|
||||||
|
of devices.
|
||||||
|
|
||||||
|
## List of crates
|
||||||
|
|
||||||
|
This workspace contains the following crates:
|
||||||
|
|
||||||
|
- The [`va416xx`](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/va416xx)
|
||||||
|
PAC crate containing basic low-level register definition
|
||||||
|
- The [`va416xx-hal`](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/va416xx-hal)
|
||||||
|
HAL crate containing higher-level abstractions on top of the PAC register crate.
|
||||||
|
- The [`vorago-peb1`](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/vorago-peb1)
|
||||||
|
BSP crate containing support for the PEB1 development board.
|
||||||
|
|
||||||
|
It also contains the following helper crates:
|
||||||
|
|
||||||
|
- The `examples` crates contains various example applications for the HAL and the PAC.
|
||||||
|
|
||||||
|
## Using the `.cargo/config.toml` file
|
||||||
|
|
||||||
|
Use the following command to have a starting `config.toml` file
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp .cargo/def-config.toml .cargo/config.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
You then can adapt the `config.toml` to your needs. For example, you can configure runners
|
||||||
|
to conveniently flash with `cargo run`.
|
||||||
|
|
||||||
|
## Using the sample VS Code files
|
||||||
|
|
||||||
|
Use the following command to have a starting configuration for VS Code:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp -rT vscode .vscode
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then adapt the files in `.vscode` to your needs.
|
||||||
|
|
||||||
|
## Flashing, running and debugging the software
|
||||||
|
|
||||||
|
You can use CLI or VS Code for flashing, running and debugging. In any case, take
|
||||||
|
care of installing the pre-requisites first.
|
||||||
|
|
||||||
|
### Pre-Requisites
|
||||||
|
|
||||||
|
1. [SEGGER J-Link tools](https://www.segger.com/downloads/jlink/) installed
|
||||||
|
2. [gdb-multiarch](https://packages.debian.org/sid/gdb-multiarch) or similar
|
||||||
|
cross-architecture debugger installed. All commands here assume `gdb-multiarch`.
|
||||||
|
|
||||||
|
### Using CLI
|
||||||
|
|
||||||
|
You can build the blinky example application with the following command
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo build --example blinky
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the GDB server first. The server needs to be started with a certain configuration and with
|
||||||
|
a JLink script to disable ROM protection.
|
||||||
|
For example, on Debian based system the following command can be used to do this (this command
|
||||||
|
is also run when running the `jlink-gdb.sh` script)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
JLinkGDBServer -select USB -device Cortex-M4 -endian little -if SWD -speed 2000 \
|
||||||
|
-LocalhostOnly -vd -jlinkscriptfile ./jlink/JLinkSettings.JLinkScript
|
||||||
|
```
|
||||||
|
|
||||||
|
After this, you can flash and debug the application with the following command
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gdb-mutliarch -q -x jlink/jlink.gdb target/thumbv7em-none-eabihf/debug/examples/blinky
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that you can automate all steps except starting the GDB server by using a cargo
|
||||||
|
runner configuration, for example with the following lines in your `.cargo/config.toml` file:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
runner = "gdb-multiarch -q -x jlink/jlink.gdb"
|
||||||
|
```
|
||||||
|
|
||||||
|
After that, you can simply use `cargo run --example blinky` to flash the blinky
|
||||||
|
example.
|
||||||
|
|
||||||
|
### Using VS Code
|
||||||
|
|
||||||
|
Assuming a working debug connection to your VA108xx board, you can debug using VS Code with
|
||||||
|
the [`Cortex-Debug` plugin](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug).
|
||||||
|
|
||||||
|
Some sample configuration files for VS code were provided and can be used by running
|
||||||
|
`cp -rT vscode .vscode` like specified above. After that, you can use `Run and Debug`
|
||||||
|
to automatically rebuild and flash your application.
|
||||||
|
|
||||||
|
If you would like to use a custom GDB application, you can specify the gdb binary in the following
|
||||||
|
configuration variables in your `settings.json`:
|
||||||
|
|
||||||
|
- `"cortex-debug.gdbPath"`
|
||||||
|
- `"cortex-debug.gdbPath.linux"`
|
||||||
|
- `"cortex-debug.gdbPath.windows"`
|
||||||
|
- `"cortex-debug.gdbPath.osx"`
|
||||||
|
|
||||||
|
The provided VS Code configurations also provide an integrated RTT logger, which you can access
|
||||||
|
via the terminal at `RTT Ch:0 console`.
|
13
automation/Dockerfile
Normal file
13
automation/Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Run the following commands from root directory to build and run locally
|
||||||
|
# docker build -f automation/Dockerfile -t <NAME> .
|
||||||
|
# docker run -it <NAME>
|
||||||
|
FROM rust:latest
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get --yes upgrade
|
||||||
|
# tzdata is a dependency, won't install otherwise
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN rustup install nightly && \
|
||||||
|
rustup target add thumbv7em-none-eabihf && \
|
||||||
|
rustup +nightly target add thumbv7em-none-eabihf && \
|
||||||
|
rustup component add rustfmt clippy
|
43
automation/Jenkinsfile
vendored
Normal file
43
automation/Jenkinsfile
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
pipeline {
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
dir 'automation'
|
||||||
|
reuseNode true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Rust Toolchain Info') {
|
||||||
|
steps {
|
||||||
|
sh 'rustc --version'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Clippy') {
|
||||||
|
steps {
|
||||||
|
sh 'cargo clippy --target thumbv7em-none-eabihf'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Rustfmt') {
|
||||||
|
steps {
|
||||||
|
sh 'cargo fmt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Docs') {
|
||||||
|
steps {
|
||||||
|
sh """
|
||||||
|
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc --all-features
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Check') {
|
||||||
|
steps {
|
||||||
|
sh 'cargo check --target thumbv7em-none-eabihf'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Check Examples') {
|
||||||
|
steps {
|
||||||
|
sh 'cargo check --target thumbv7em-none-eabihf --examples'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
examples/simple/Cargo.toml
Normal file
18
examples/simple/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "simple_examples"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cortex-m-rt = "0.7"
|
||||||
|
va416xx-hal = { path = "../../va416xx-hal" }
|
||||||
|
panic-rtt-target = { version = "0.1.3" }
|
||||||
|
rtt-target = { version = "0.5" }
|
||||||
|
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||||
|
embedded-hal = "1"
|
||||||
|
embedded-hal-nb = "1"
|
||||||
|
nb = "1"
|
||||||
|
embedded-io = "0.6"
|
||||||
|
panic-halt = "0.2"
|
||||||
|
vorago-peb1 = { path = "../../vorago-peb1" }
|
||||||
|
accelerometer = "0.12"
|
33
examples/simple/examples/blinky-pac.rs
Normal file
33
examples/simple/examples/blinky-pac.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//! Simple blinky example
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use panic_halt as _;
|
||||||
|
use va416xx_hal::pac;
|
||||||
|
|
||||||
|
// Mask for the LED
|
||||||
|
const LED_PG5: u32 = 1 << 5;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let dp = pac::Peripherals::take().unwrap();
|
||||||
|
// Enable all peripheral clocks
|
||||||
|
dp.sysconfig
|
||||||
|
.peripheral_clk_enable()
|
||||||
|
.modify(|_, w| unsafe { w.bits(0xffffffff) });
|
||||||
|
dp.portg.dir().modify(|_, w| unsafe { w.bits(LED_PG5) });
|
||||||
|
dp.portg
|
||||||
|
.datamask()
|
||||||
|
.modify(|_, w| unsafe { w.bits(LED_PG5) });
|
||||||
|
for _ in 0..10 {
|
||||||
|
dp.portg.clrout().write(|w| unsafe { w.bits(LED_PG5) });
|
||||||
|
cortex_m::asm::delay(2_000_000);
|
||||||
|
dp.portg.setout().write(|w| unsafe { w.bits(LED_PG5) });
|
||||||
|
cortex_m::asm::delay(2_000_000);
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
dp.portg.togout().write(|w| unsafe { w.bits(LED_PG5) });
|
||||||
|
cortex_m::asm::delay(2_000_000);
|
||||||
|
}
|
||||||
|
}
|
24
examples/simple/examples/blinky.rs
Normal file
24
examples/simple/examples/blinky.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//! Simple blinky example using the HAL
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use embedded_hal::digital::StatefulOutputPin;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use va416xx_hal::{gpio::PinsG, pac};
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("VA416xx HAL blinky example");
|
||||||
|
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
|
||||||
|
let mut led = portg.pg5.into_readable_push_pull_output();
|
||||||
|
//let mut delay = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0);
|
||||||
|
loop {
|
||||||
|
cortex_m::asm::delay(2_000_000);
|
||||||
|
led.toggle().ok();
|
||||||
|
}
|
||||||
|
}
|
88
examples/simple/examples/peb1-accelerometer.rs
Normal file
88
examples/simple/examples/peb1-accelerometer.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
//! Example code for the PEB1 development board accelerometer.
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use accelerometer::{Accelerometer, RawAccelerometer};
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use embedded_hal::delay::DelayNs;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use simple_examples::peb1;
|
||||||
|
use va416xx_hal::{
|
||||||
|
i2c,
|
||||||
|
pac::{self},
|
||||||
|
prelude::*,
|
||||||
|
pwm::CountdownTimer,
|
||||||
|
};
|
||||||
|
use vorago_peb1::lis2dh12::{self, detect_i2c_addr, FullScale, Odr};
|
||||||
|
|
||||||
|
pub enum DisplayMode {
|
||||||
|
Raw,
|
||||||
|
Normalized,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DISPLAY_MODE: DisplayMode = DisplayMode::Normalized;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
rtt_init_print!();
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
rprintln!("-- Vorago PEB1 accelerometer example --");
|
||||||
|
// Use the external clock connected to XTAL_N.
|
||||||
|
let clocks = dp
|
||||||
|
.clkgen
|
||||||
|
.constrain()
|
||||||
|
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
|
||||||
|
.freeze(&mut dp.sysconfig)
|
||||||
|
.unwrap();
|
||||||
|
let mut i2c_master = i2c::I2cMaster::new(
|
||||||
|
dp.i2c0,
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
i2c::MasterConfig::default(),
|
||||||
|
&clocks,
|
||||||
|
i2c::I2cSpeed::Regular100khz,
|
||||||
|
)
|
||||||
|
.expect("creating I2C master failed");
|
||||||
|
let mut delay_provider = CountdownTimer::new(&mut dp.sysconfig, dp.tim1, &clocks);
|
||||||
|
// Detect the I2C address of the accelerometer by scanning all possible values.
|
||||||
|
let slave_addr = detect_i2c_addr(&mut i2c_master).expect("detecting I2C address failed");
|
||||||
|
// Create the accelerometer driver using the PEB1 BSP.
|
||||||
|
let mut accelerometer = vorago_peb1::accelerometer::new_with_i2cm(i2c_master, slave_addr)
|
||||||
|
.expect("creating accelerometer driver failed");
|
||||||
|
let device_id = accelerometer.get_device_id().unwrap();
|
||||||
|
accelerometer
|
||||||
|
.set_mode(lis2dh12::reg::Mode::Normal)
|
||||||
|
.expect("setting mode failed");
|
||||||
|
accelerometer
|
||||||
|
.set_odr(Odr::Hz100)
|
||||||
|
.expect("setting ODR failed");
|
||||||
|
accelerometer
|
||||||
|
.set_fs(FullScale::G4)
|
||||||
|
.expect("setting full scale failed");
|
||||||
|
// This function also enabled BDU.
|
||||||
|
accelerometer
|
||||||
|
.enable_temp(true)
|
||||||
|
.expect("enabling temperature sensor failed");
|
||||||
|
rprintln!("Device ID: 0x{:02X}", device_id);
|
||||||
|
// Start reading the accelerometer periodically.
|
||||||
|
loop {
|
||||||
|
let temperature = accelerometer
|
||||||
|
.get_temp_outf()
|
||||||
|
.expect("reading temperature failed");
|
||||||
|
match DISPLAY_MODE {
|
||||||
|
DisplayMode::Normalized => {
|
||||||
|
let value = accelerometer
|
||||||
|
.accel_norm()
|
||||||
|
.expect("reading normalized accelerometer data failed");
|
||||||
|
rprintln!("Accel Norm F32x3: {:.06?} | Temp {} °C", value, temperature);
|
||||||
|
}
|
||||||
|
DisplayMode::Raw => {
|
||||||
|
let value_raw = accelerometer
|
||||||
|
.accel_raw()
|
||||||
|
.expect("reading raw accelerometer data failed");
|
||||||
|
rprintln!("Accel Raw F32x3: {:?} | Temp {} °C", value_raw, temperature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay_provider.delay_ms(100);
|
||||||
|
}
|
||||||
|
}
|
81
examples/simple/examples/pwm.rs
Normal file
81
examples/simple/examples/pwm.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
//! Simple PWM example
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use embedded_hal::{delay::DelayNs, pwm::SetDutyCycle};
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use simple_examples::peb1;
|
||||||
|
use va416xx_hal::{
|
||||||
|
gpio::PinsA,
|
||||||
|
pac,
|
||||||
|
prelude::*,
|
||||||
|
pwm::{self, get_duty_from_percent, CountdownTimer, PwmA, PwmB, ReducedPwmPin},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("-- VA108xx PWM example application--");
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Use the external clock connected to XTAL_N.
|
||||||
|
let clocks = dp
|
||||||
|
.clkgen
|
||||||
|
.constrain()
|
||||||
|
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
|
||||||
|
.freeze(&mut dp.sysconfig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
|
let mut pwm = pwm::PwmPin::new(
|
||||||
|
(pinsa.pa3.into_funsel_1(), dp.tim3),
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
&clocks,
|
||||||
|
10.Hz(),
|
||||||
|
);
|
||||||
|
let mut delay_timer = CountdownTimer::new(&mut dp.sysconfig, dp.tim0, &clocks);
|
||||||
|
let mut current_duty_cycle = 0.0;
|
||||||
|
pwm.set_duty_cycle(get_duty_from_percent(current_duty_cycle))
|
||||||
|
.unwrap();
|
||||||
|
pwm.enable();
|
||||||
|
|
||||||
|
// Delete type information, increased code readibility for the rest of the code
|
||||||
|
let mut reduced_pin = ReducedPwmPin::from(pwm);
|
||||||
|
loop {
|
||||||
|
let mut counter = 0;
|
||||||
|
// Increase duty cycle continuously
|
||||||
|
while current_duty_cycle < 1.0 {
|
||||||
|
delay_timer.delay_ms(400);
|
||||||
|
current_duty_cycle += 0.02;
|
||||||
|
counter += 1;
|
||||||
|
if counter % 10 == 0 {
|
||||||
|
rprintln!("current duty cycle: {}", current_duty_cycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
reduced_pin
|
||||||
|
.set_duty_cycle(get_duty_from_percent(current_duty_cycle))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch to PWMB and decrease the window with a high signal from 100 % to 0 %
|
||||||
|
// continously
|
||||||
|
current_duty_cycle = 0.0;
|
||||||
|
let mut upper_limit = 1.0;
|
||||||
|
let mut lower_limit = 0.0;
|
||||||
|
let mut pwmb: ReducedPwmPin<PwmB> = ReducedPwmPin::from(reduced_pin);
|
||||||
|
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
|
||||||
|
pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit));
|
||||||
|
while lower_limit < 0.5 {
|
||||||
|
delay_timer.delay_ms(400);
|
||||||
|
lower_limit += 0.01;
|
||||||
|
upper_limit -= 0.01;
|
||||||
|
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
|
||||||
|
pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit));
|
||||||
|
rprintln!("Lower limit: {}", pwmb.pwmb_lower_limit());
|
||||||
|
rprintln!("Upper limit: {}", pwmb.pwmb_upper_limit());
|
||||||
|
}
|
||||||
|
reduced_pin = ReducedPwmPin::<PwmA>::from(pwmb);
|
||||||
|
}
|
||||||
|
}
|
36
examples/simple/examples/rtt-log.rs
Normal file
36
examples/simple/examples/rtt-log.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Code to test RTT logger functionality.
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use va416xx_hal::pac;
|
||||||
|
|
||||||
|
// Mask for the LED
|
||||||
|
const LED_PG5: u32 = 1 << 5;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let dp = pac::Peripherals::take().unwrap();
|
||||||
|
// Enable all peripheral clocks
|
||||||
|
dp.sysconfig
|
||||||
|
.peripheral_clk_enable()
|
||||||
|
.modify(|_, w| unsafe { w.bits(0xffffffff) });
|
||||||
|
dp.portg.dir().modify(|_, w| unsafe { w.bits(LED_PG5) });
|
||||||
|
dp.portg
|
||||||
|
.datamask()
|
||||||
|
.modify(|_, w| unsafe { w.bits(LED_PG5) });
|
||||||
|
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("VA416xx RTT Demo");
|
||||||
|
let mut counter = 0;
|
||||||
|
loop {
|
||||||
|
rprintln!("{}: Hello, world!", counter);
|
||||||
|
// Still toggle LED. If there are issues with the RTT log, the LED
|
||||||
|
// blinking ensures that the application is actually running.
|
||||||
|
dp.portg.togout().write(|w| unsafe { w.bits(LED_PG5) });
|
||||||
|
counter += 1;
|
||||||
|
cortex_m::asm::delay(10_000_000);
|
||||||
|
}
|
||||||
|
}
|
96
examples/simple/examples/spi.rs
Normal file
96
examples/simple/examples/spi.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
//! SPI example application.
|
||||||
|
//!
|
||||||
|
//! If you do not use the loopback mode, MOSI and MISO need to be tied together on the board.
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use embedded_hal::spi::{Mode, SpiBus, MODE_0};
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use simple_examples::peb1;
|
||||||
|
use va416xx_hal::spi::{Spi, TransferConfig};
|
||||||
|
use va416xx_hal::{
|
||||||
|
gpio::{PinsB, PinsC},
|
||||||
|
pac,
|
||||||
|
prelude::*,
|
||||||
|
spi::SpiConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub enum ExampleSelect {
|
||||||
|
// Enter loopback mode. It is not necessary to tie MOSI/MISO together for this
|
||||||
|
Loopback,
|
||||||
|
// Send a test buffer and print everything received. You need to tie together MOSI/MISO in this
|
||||||
|
// mode.
|
||||||
|
TestBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
const EXAMPLE_SEL: ExampleSelect = ExampleSelect::Loopback;
|
||||||
|
const SPI_SPEED_KHZ: u32 = 1000;
|
||||||
|
const SPI_MODE: Mode = MODE_0;
|
||||||
|
const BLOCKMODE: bool = true;
|
||||||
|
const FILL_WORD: u8 = 0x0f;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("-- VA108xx SPI example application--");
|
||||||
|
let cp = cortex_m::Peripherals::take().unwrap();
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
// Use the external clock connected to XTAL_N.
|
||||||
|
let clocks = dp
|
||||||
|
.clkgen
|
||||||
|
.constrain()
|
||||||
|
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
|
||||||
|
.freeze(&mut dp.sysconfig)
|
||||||
|
.unwrap();
|
||||||
|
let mut delay_sysclk = cortex_m::delay::Delay::new(cp.SYST, clocks.apb0().raw());
|
||||||
|
|
||||||
|
let pins_b = PinsB::new(&mut dp.sysconfig, dp.portb);
|
||||||
|
let pins_c = PinsC::new(&mut dp.sysconfig, dp.portc);
|
||||||
|
// Configure SPI1 pins.
|
||||||
|
let (sck, miso, mosi) = (
|
||||||
|
pins_b.pb15.into_funsel_1(),
|
||||||
|
pins_c.pc0.into_funsel_1(),
|
||||||
|
pins_c.pc1.into_funsel_1(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut spi_cfg = SpiConfig::default();
|
||||||
|
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
||||||
|
spi_cfg = spi_cfg.loopback(true)
|
||||||
|
}
|
||||||
|
let transfer_cfg =
|
||||||
|
TransferConfig::new_no_hw_cs(SPI_SPEED_KHZ.kHz(), SPI_MODE, BLOCKMODE, false);
|
||||||
|
// Create SPI peripheral.
|
||||||
|
let mut spi0 = Spi::new(
|
||||||
|
dp.spi0,
|
||||||
|
(sck, miso, mosi),
|
||||||
|
&clocks,
|
||||||
|
spi_cfg,
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
Some(&transfer_cfg.downgrade()),
|
||||||
|
);
|
||||||
|
spi0.set_fill_word(FILL_WORD);
|
||||||
|
loop {
|
||||||
|
let mut tx_buf: [u8; 3] = [1, 2, 3];
|
||||||
|
let mut rx_buf: [u8; 3] = [0; 3];
|
||||||
|
// Can't really verify correct reply here.
|
||||||
|
spi0.write(&[0x42]).expect("write failed");
|
||||||
|
// Need small delay.. otherwise we will read back the sent byte (which we don't want here).
|
||||||
|
// The write function will return as soon as all bytes were shifted out, ignoring the
|
||||||
|
// reply bytes.
|
||||||
|
delay_sysclk.delay_us(50);
|
||||||
|
// Because of the loopback mode, we should get back the fill word here.
|
||||||
|
spi0.read(&mut rx_buf[0..1]).unwrap();
|
||||||
|
assert_eq!(rx_buf[0], FILL_WORD);
|
||||||
|
|
||||||
|
spi0.transfer_in_place(&mut tx_buf)
|
||||||
|
.expect("SPI transfer_in_place failed");
|
||||||
|
assert_eq!([1, 2, 3], tx_buf);
|
||||||
|
spi0.transfer(&mut rx_buf, &tx_buf)
|
||||||
|
.expect("SPI transfer failed");
|
||||||
|
assert_eq!(rx_buf, tx_buf);
|
||||||
|
delay_sysclk.delay_ms(500);
|
||||||
|
}
|
||||||
|
}
|
68
examples/simple/examples/timer-ticks.rs
Normal file
68
examples/simple/examples/timer-ticks.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//! MS and Second counter implemented using the TIM0 and TIM1 peripheral
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use core::cell::Cell;
|
||||||
|
use cortex_m::interrupt::Mutex;
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use simple_examples::peb1;
|
||||||
|
use va416xx_hal::{
|
||||||
|
pac::{self, interrupt},
|
||||||
|
prelude::*,
|
||||||
|
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, MS_COUNTER},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum LibType {
|
||||||
|
Pac,
|
||||||
|
Hal,
|
||||||
|
}
|
||||||
|
|
||||||
|
static SEC_COUNTER: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
rtt_init_print!();
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
let mut last_ms = 0;
|
||||||
|
rprintln!("-- Vorago system ticks using timers --");
|
||||||
|
// Use the external clock connected to XTAL_N.
|
||||||
|
let clocks = dp
|
||||||
|
.clkgen
|
||||||
|
.constrain()
|
||||||
|
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
|
||||||
|
.freeze(&mut dp.sysconfig)
|
||||||
|
.unwrap();
|
||||||
|
let _ = set_up_ms_tick(&mut dp.sysconfig, dp.tim0, &clocks);
|
||||||
|
let mut second_timer = CountdownTimer::new(&mut dp.sysconfig, dp.tim1, &clocks);
|
||||||
|
second_timer.start(1.Hz());
|
||||||
|
second_timer.listen();
|
||||||
|
loop {
|
||||||
|
let current_ms = cortex_m::interrupt::free(|cs| MS_COUNTER.borrow(cs).get());
|
||||||
|
if current_ms - last_ms >= 1000 {
|
||||||
|
last_ms = current_ms;
|
||||||
|
rprintln!("MS counter: {}", current_ms);
|
||||||
|
let second = cortex_m::interrupt::free(|cs| SEC_COUNTER.borrow(cs).get());
|
||||||
|
rprintln!("Second counter: {}", second);
|
||||||
|
}
|
||||||
|
cortex_m::asm::delay(10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interrupt]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn TIM0() {
|
||||||
|
default_ms_irq_handler()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interrupt]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn TIM1() {
|
||||||
|
cortex_m::interrupt::free(|cs| {
|
||||||
|
let mut sec = SEC_COUNTER.borrow(cs).get();
|
||||||
|
sec += 1;
|
||||||
|
SEC_COUNTER.borrow(cs).set(sec);
|
||||||
|
});
|
||||||
|
}
|
57
examples/simple/examples/uart.rs
Normal file
57
examples/simple/examples/uart.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// UART example application. Sends a test string over a UART and then enters
|
||||||
|
// echo mode
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use embedded_hal_nb::serial::Read;
|
||||||
|
use embedded_io::Write;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use simple_examples::peb1;
|
||||||
|
use va416xx_hal::clock::ClkgenExt;
|
||||||
|
use va416xx_hal::time::Hertz;
|
||||||
|
use va416xx_hal::{gpio::PinsG, pac, uart};
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("-- VA416xx UART example application--");
|
||||||
|
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Use the external clock connected to XTAL_N.
|
||||||
|
let clocks = dp
|
||||||
|
.clkgen
|
||||||
|
.constrain()
|
||||||
|
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
|
||||||
|
.freeze(&mut dp.sysconfig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let gpiob = PinsG::new(&mut dp.sysconfig, dp.portg);
|
||||||
|
let tx = gpiob.pg0.into_funsel_1();
|
||||||
|
let rx = gpiob.pg1.into_funsel_1();
|
||||||
|
|
||||||
|
let uart0 = uart::Uart::new(
|
||||||
|
dp.uart0,
|
||||||
|
(tx, rx),
|
||||||
|
Hertz::from_raw(115200),
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
&clocks,
|
||||||
|
);
|
||||||
|
let (mut tx, mut rx) = uart0.split();
|
||||||
|
writeln!(tx, "Hello World\n\r").unwrap();
|
||||||
|
loop {
|
||||||
|
// Echo what is received on the serial link.
|
||||||
|
match nb::block!(rx.read()) {
|
||||||
|
Ok(recvd) => {
|
||||||
|
if let Err(e) = embedded_hal_nb::serial::Write::write(&mut tx, recvd) {
|
||||||
|
rprintln!("UART TX error: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
rprintln!("UART RX error {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
examples/simple/examples/wdt.rs
Normal file
79
examples/simple/examples/wdt.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Code to test the watchdog timer.
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use core::cell::Cell;
|
||||||
|
use cortex_m::interrupt::Mutex;
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use simple_examples::peb1;
|
||||||
|
use va416xx_hal::pac::{self, interrupt};
|
||||||
|
use va416xx_hal::prelude::*;
|
||||||
|
use va416xx_hal::wdt::WdtController;
|
||||||
|
|
||||||
|
static WDT_INTRPT_COUNT: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum TestMode {
|
||||||
|
// Watchdog is fed by main loop, which runs with high period.
|
||||||
|
FedByMain,
|
||||||
|
// Watchdog is fed by watchdog IRQ.
|
||||||
|
FedByIrq,
|
||||||
|
AllowReset,
|
||||||
|
}
|
||||||
|
const TEST_MODE: TestMode = TestMode::FedByMain;
|
||||||
|
const WDT_ROLLOVER_MS: u32 = 100;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("-- VA416xx WDT example application--");
|
||||||
|
let cp = cortex_m::Peripherals::take().unwrap();
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Use the external clock connected to XTAL_N.
|
||||||
|
let clocks = dp
|
||||||
|
.clkgen
|
||||||
|
.constrain()
|
||||||
|
.xtal_n_clk_with_src_freq(peb1::EXTCLK_FREQ)
|
||||||
|
.freeze(&mut dp.sysconfig)
|
||||||
|
.unwrap();
|
||||||
|
let mut delay_sysclk = cortex_m::delay::Delay::new(cp.SYST, clocks.apb0().raw());
|
||||||
|
|
||||||
|
let mut last_interrupt_counter = 0;
|
||||||
|
let mut wdt_ctrl =
|
||||||
|
WdtController::start(&mut dp.sysconfig, dp.watch_dog, &clocks, WDT_ROLLOVER_MS);
|
||||||
|
wdt_ctrl.enable_reset();
|
||||||
|
loop {
|
||||||
|
if TEST_MODE != TestMode::AllowReset {
|
||||||
|
wdt_ctrl.feed();
|
||||||
|
}
|
||||||
|
let interrupt_counter = cortex_m::interrupt::free(|cs| WDT_INTRPT_COUNT.borrow(cs).get());
|
||||||
|
if interrupt_counter > last_interrupt_counter {
|
||||||
|
rprintln!("interrupt counter has increased to {}", interrupt_counter);
|
||||||
|
last_interrupt_counter = interrupt_counter;
|
||||||
|
}
|
||||||
|
match TEST_MODE {
|
||||||
|
TestMode::FedByMain => delay_sysclk.delay_ms(WDT_ROLLOVER_MS / 5),
|
||||||
|
TestMode::FedByIrq => delay_sysclk.delay_ms(WDT_ROLLOVER_MS),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interrupt]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn WATCHDOG() {
|
||||||
|
cortex_m::interrupt::free(|cs| {
|
||||||
|
WDT_INTRPT_COUNT
|
||||||
|
.borrow(cs)
|
||||||
|
.set(WDT_INTRPT_COUNT.borrow(cs).get() + 1);
|
||||||
|
});
|
||||||
|
let wdt = unsafe { pac::WatchDog::steal() };
|
||||||
|
// Clear interrupt.
|
||||||
|
if TEST_MODE != TestMode::AllowReset {
|
||||||
|
wdt.wdogintclr().write(|w| unsafe { w.bits(1) });
|
||||||
|
}
|
||||||
|
}
|
11
examples/simple/src/lib.rs
Normal file
11
examples/simple/src/lib.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
/// PEB1 board specific configuration.
|
||||||
|
pub mod peb1 {
|
||||||
|
use va416xx_hal::time::Hertz;
|
||||||
|
|
||||||
|
// The clock on the PEB1 board has a 20 MHz clock which is increased to 40 MHz with a configurable
|
||||||
|
// PLL by default.
|
||||||
|
pub const EXTCLK_FREQ: Hertz = Hertz::from_raw(40_000_000);
|
||||||
|
pub const XTAL_FREQ: Hertz = Hertz::from_raw(10_000_000);
|
||||||
|
}
|
13
examples/simple/src/main.rs
Normal file
13
examples/simple/src/main.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//! Dummy app which does not do anything.
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
loop {
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
}
|
||||||
|
}
|
5
jlink-gdb.sh
Executable file
5
jlink-gdb.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Start the JLinkGDBServer while also specifying the JLinkScript file. The JLinkScript is necessary
|
||||||
|
# to disable ROM protection to allow flashing
|
||||||
|
JLinkGDBServer -select USB -device Cortex-M4 -endian little -if SWD -speed 2000 \
|
||||||
|
-LocalhostOnly -vd -jlinkscriptfile ./jlink/JLinkSettings.JLinkScript
|
62
jlink/JLinkSettings.JLinkScript
Normal file
62
jlink/JLinkSettings.JLinkScript
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* SEGGER Microcontroller GmbH *
|
||||||
|
* Solutions for real time microcontroller applications *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
|
||||||
|
* *
|
||||||
|
* www.segger.com Support: support@segger.com *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
File : JLinkSettings.JLinkScript
|
||||||
|
Purpose : J-Link target setup file for VORAGO VA416xx
|
||||||
|
---------------------------END-OF-HEADER------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* AfterResetTarget
|
||||||
|
*/
|
||||||
|
int AfterResetTarget (void) {
|
||||||
|
JLINK_SYS_Report("AfterResetTarget()");
|
||||||
|
JLINK_MEM_WriteU32(0x400210C0, 0x1ACCE551); // WDOGLOCK = 0x1ACCE551
|
||||||
|
JLINK_MEM_WriteU32(0x40021008, 0x0); // WDOGCONTROL = 0x0 (diable)
|
||||||
|
return JLINK_MEM_WriteU32(0x40010010, 0x1); // ROM_PROT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* BeforeTargetDownload
|
||||||
|
*/
|
||||||
|
int BeforeTargetDownload (void) {
|
||||||
|
JLINK_SYS_Report("BeforeTargetDownload()");
|
||||||
|
return JLINK_MEM_WriteU32(0x40010010, 0x1); // ROM_PROT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* AfterTargetDownload
|
||||||
|
*/
|
||||||
|
int AfterTargetDownload (void) {
|
||||||
|
JLINK_SYS_Report("AfterTargetDownload()");
|
||||||
|
return JLINK_MEM_WriteU32(0x40010010, 0x0); // ROM_PROT = 0x0
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* HandleBeforeFlashProg
|
||||||
|
*/
|
||||||
|
int HandleBeforeFlashProg(void) {
|
||||||
|
JLINK_SYS_Report("HandleBeforeFlashProg()");
|
||||||
|
return JLINK_MEM_WriteU32(0x40010010, 0x1); // ROM_PROT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* HandleAfterFlashProg
|
||||||
|
*/
|
||||||
|
int HandleAfterFlashProg(void) {
|
||||||
|
JLINK_SYS_Report("HandleAfterFlashProg()");
|
||||||
|
return JLINK_MEM_WriteU32(0x40010010, 0x0); // ROM_PROT = 0x0
|
||||||
|
}
|
13
jlink/jlink-reva.gdb
Normal file
13
jlink/jlink-reva.gdb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
target remote localhost:2331
|
||||||
|
|
||||||
|
# For some reason, this is problematic even if the JLinkScript disabled the remote
|
||||||
|
# write protection. Therefore, don't do it for now
|
||||||
|
# This is only problematic on board RevA
|
||||||
|
# monitor reset
|
||||||
|
|
||||||
|
# *try* to stop at the user entry point (it might be gone due to inlining)
|
||||||
|
break main
|
||||||
|
|
||||||
|
load
|
||||||
|
|
||||||
|
continue
|
10
jlink/jlink.gdb
Normal file
10
jlink/jlink.gdb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
target remote localhost:2331
|
||||||
|
|
||||||
|
monitor halt
|
||||||
|
# Reset is problematic on RevA, okay for RevB
|
||||||
|
monitor reset
|
||||||
|
|
||||||
|
# *try* to stop at the user entry point (it might be gone due to inlining)
|
||||||
|
break main
|
||||||
|
|
||||||
|
load
|
23
memory.x
Normal file
23
memory.x
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
|
||||||
|
/* RAM is a mandatory region. This RAM refers to the SRAM_0 */
|
||||||
|
RAM : ORIGIN = 0x1FFF8000, LENGTH = 32K
|
||||||
|
SRAM_1 : ORIGIN = 0x20000000, LENGTH = 32K
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is where the call stack will be allocated. */
|
||||||
|
/* The stack is of the full descending type. */
|
||||||
|
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
|
||||||
|
/* SRAM_0 can be used for all busses: Instruction, Data and System */
|
||||||
|
/* SRAM_1 only supports the system bus */
|
||||||
|
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
|
||||||
|
/* Define sections for placing symbols into the extra memory regions above. */
|
||||||
|
/* This makes them accessible from code. */
|
||||||
|
SECTIONS {
|
||||||
|
.sram1 (NOLOAD) : ALIGN(8) {
|
||||||
|
*(.sram1 .sram1.*);
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > SRAM_1
|
||||||
|
};
|
100
scripts/VA416xx_Series.yaml
Normal file
100
scripts/VA416xx_Series.yaml
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
name: VA416xx Series
|
||||||
|
generated_from_pack: true
|
||||||
|
pack_file_release: 1.0.5
|
||||||
|
variants:
|
||||||
|
- name: VA416xx
|
||||||
|
cores:
|
||||||
|
- name: main
|
||||||
|
type: armv7em
|
||||||
|
core_access_options: !Arm
|
||||||
|
ap: 0
|
||||||
|
psel: 0x0
|
||||||
|
memory_map:
|
||||||
|
- !Ram
|
||||||
|
name: IRAM1
|
||||||
|
range:
|
||||||
|
start: 0x1fff8000
|
||||||
|
end: 0x20000000
|
||||||
|
cores:
|
||||||
|
- main
|
||||||
|
- !Nvm
|
||||||
|
name: IROM1
|
||||||
|
range:
|
||||||
|
start: 0x0
|
||||||
|
end: 0x40000
|
||||||
|
is_boot_memory: true
|
||||||
|
cores:
|
||||||
|
- main
|
||||||
|
- !Generic
|
||||||
|
name: IRAM2
|
||||||
|
range:
|
||||||
|
start: 0x20000000
|
||||||
|
end: 0x20008000
|
||||||
|
cores:
|
||||||
|
- main
|
||||||
|
flash_algorithms:
|
||||||
|
- va416_spi_fram_256kb
|
||||||
|
- va416_ebiboot_fram_256kb
|
||||||
|
- va416_ebi_fram_512kb
|
||||||
|
flash_algorithms:
|
||||||
|
- name: va416_spi_fram_256kb
|
||||||
|
default: true
|
||||||
|
description: VA416_SPI_FRAM_256KB
|
||||||
|
instructions: RfYMQMTyAQABaMkHCtEBaMkHBL8BaF/qwXED0QFoyQfy0AC/AWjJBgnVAWjJBkS/AWhf6sFhAtUBaMkG8tQDIQFicEdwRwC/WCAIIcTyAQDA8qgBQWBB8ggBTvJRUsTyAgHB9swiwfi4IAAiCmABaCHwCAEBYAC/AL8CaEX2DEFC8AgCxPIBAQJgAiAAv0hgQPIHQEH4DAxA8oIgQfgIDAMgCGIIaMAHCtEIaMAHBL8IaF/qwHAD0QhowAfy0AC/CGjABgnVCGjABkS/CGhf6sBgAtUIaMAG8tQGIMjyAAADIgpiQfgEDApo0gcK0Qpo0gcEvwpoX+rCcgPRCmjSB/LQAL8KaNIGCdUKaNIGRL8KaF/qwmIC1Qpo0gby1AMiCmJB+AQMCGjABwnRCGjABwS/CGhf6sBwAtEIaMAH8tAIaMAGCdUIaMAGRL8IaF/qwGAC1QhowAby1AMgCGIBIEH4BAxP8ABAQfgEDAhowAcK0QhowAcEvwhoX+rAcAPRCGjAB/LQAL8IaMAGCdUIaMAGRL8IaF/qwGAC1QhowAby1AMiACAKYnBHAL9F9gxBxPIBAQhowAcK0QhowAcEvwhoX+rAcAPRCGjAB/LQAL8IaMAGCdUIaMAGRL8IaF/qwGAC1QhowAby1AYgyPIAAAMiCmJB+AQMCmjSBwrRCmjSBwS/Cmhf6sJyA9EKaNIH8tAAvwpo0gYJ1Qpo0gZEvwpoX+rCYgLVCmjSBvLUAyIKYgEi9zBB+AQsQfgEDAhowAcJ0QhowAcEvwhoX+rAcALRCGjAB/LQCGjABgnVCGjABkS/CGhf6sBgAtUIaMAG8tQDIgAgCmJwRwC/cLVF9gxBQPIGDAAgxPIBAcjyAAwDI0/wAg5P8ABCACQG4AC/ATS09YBvC2IA8KyAQfgEzA1o7QcK0Q1o7QcEvw1oX+rFdQPRDWjtB/LQAL8NaO0GCtUNaO0GRL8NaF/qxWUD1Q1o7Qby1AC/xPMHJQtiQfgE7EH4BFzlskH4BFwAJUH4BFwE4AU1/y1B+AQMTNAOaLYHBtQOaLYHXL8OaF/qhnY+1UH4BAwOaLYHCdQOaLYHXL8OaF/qhnYC1A5otgfy1UH4BAwOaLYHCtQOaLYHXL8OaF/qhnYD1A5otgfy1QC/QfgEDA5otgcK1A5otgdcvw5oX+qGdgPUDmi2B/LVAL9B+AQMDmi2B7zUDmi2B1y/Dmhf6oZ2tdQOaLYH8tWx5w5otgez1bznDWitBwrUDWitB1y/DWhf6oV1A9QNaK0H8tUAv0H4BCwNaO0HCtENaO0HBL8NaF/qxXUD0Q1o7Qfy0AC/DWjtBn/1Wq8NaO0GRL8NaF/qxWV/9VKvDWjtBvDUTecAIHC9ACBwR4C1grBF9gxOxPIBDgAjAZPe+AAw2wcN0d74ADDbBwS/3vgAMF/qw3ME0d74ADDbB+7QAL/e+AAw2wYM1d74ADDbBkS/3vgAMF/qw2MD1d74ADDbBu7UAyPO+CAwBiPI8gADTvgEPN74ADDbBwzR3vgAMNsHBL/e+AAwX+rDcwPR3vgAMNsH7tDe+AAw2wYM1d74ADDbBkS/3vgAMF/qw2MD1d74ADDbBu7UAyPO+CAwAiNN9vAMTvgEPMDzB0PP9v98TvgEPMDzByPAsgEpTvgEPE74BAxA8JKA3vgAAIAHAPEGgd74AACAB1y/3vgAAF/qgHAA8fyA3vgAAIAHXL/e+AAAX+qAcADx8oDe+AAAgAdcv974AABf6oBwAPHogN74AACAB1y/3vgAAF/qgHAA8d6A3vgAAIAHXL/e+AAAX+qAcADx1IDe+AAAgAdcv974AABf6oBwAPHKgN74AACAB1y/3vgAAF/qgHAA8cCA3vgAAIAHXL/e+AAAX+qAcADxtoDe+AAAgAdcv974AABf6oBwAPGsgN74AACAB1y/3vgAAF/qgHAA8aKA3vgAAIAHXL/e+AAAX+qAcADxmIDe+AAAgAdcv974AABf6oBwAPGOgBzxGQx/9H+vheAAvxL4AQsBOU74BAxe+AQMASkAkAGYAPEBAAGQP/Rur2BG3vgAMJsH69Te+AAwmwdcv974ADBf6oNz4tTe+AAwmwdcv974ADBf6oNz2dTe+AAwmwdcv974ADBf6oNz0NTe+AAwmwdcv974ADBf6oNzx9Te+AAwmwdcv974ADBf6oNzvtTe+AAwmwdcv974ADBf6oNztdTe+AAwmwdcv974ADBf6oNzrNTe+AAwmwdcv974ADBf6oNzo9Te+AAwmwdcv974ADBf6oNzmtTe+AAwmwdcv974ADBf6oNzkdTe+AAwmwdcv974ADBf6oNzP/WIr974ADCbB1y/3vgAMF/qg3M/9X6vGTB/9IuvASACsIC9EHgA8QBATvgEDN74AADABwzR3vgAAMAHBL/e+AAAX+rAcAPR3vgAAMAH7tDe+AAAwAYM1d74AADABkS/3vgAAF/qwGAD1d74AADABu7UAyDO+CAAACACsIC9AL8AIHBHsLVF9gxExPIBBCNo2wcJ0SNo2wcEvyNoX+rDcwLRI2jbB/LQI2jbBgnVI2jbBkS/I2hf6sNjAtUjaNsG8tQDIyNiRPgEPMDzB0NE+AQ8wPMHI0T4BDzDskT4BDwAI0T4BDwjaFsHCdQjaFsHXL8jaF/qQ3MC1CNoWwfy1VT4BDwAI0T4BDwjaFsHCdQjaFsHXL8jaF/qQ3MC1CNoWwfy1VT4BDwAI0T4BDwjaFsHCdQjaFsHXL8jaF/qQ3MC1CNoWwfy1VT4BDwAI0T4BDwjaFsHCdQjaFsHXL8jaF/qQ3MC1CNoWwfy1VT4BDwBs0/wAAxP8AAOAL9E+ATMI2hbBwrUI2hbB1y/I2hf6kNzA9QjaFsH8tUAv1T4BDwVeNuynUIo0Q7xAQ6ORQLxAQLj0U/wAEJE+AQsImjSBwrRImjSBwS/Imhf6sJyA9EiaNIH8tAAvyJo0gYJ1SJo0gZEvyJoX+rCYgLVImjSBvLUAyIIRCJisL1wRLC9AAAAAAAA
|
||||||
|
pc_init: 0x49
|
||||||
|
pc_uninit: 0x1ad
|
||||||
|
pc_program_page: 0x40d
|
||||||
|
pc_erase_sector: 0x409
|
||||||
|
pc_erase_all: 0x27d
|
||||||
|
data_section_offset: 0x8d8
|
||||||
|
flash_properties:
|
||||||
|
address_range:
|
||||||
|
start: 0x0
|
||||||
|
end: 0x40000
|
||||||
|
page_size: 0x100
|
||||||
|
erased_byte_value: 0x0
|
||||||
|
program_page_timeout: 3000
|
||||||
|
erase_sector_timeout: 3000
|
||||||
|
sectors:
|
||||||
|
- size: 0x2000
|
||||||
|
address: 0x0
|
||||||
|
- name: va416_ebiboot_fram_256kb
|
||||||
|
description: VA416_EBIBOOT_256KB
|
||||||
|
instructions: QfKAAsTyAQJS+CAwI/TAQ0PqQTFC+CAQcEcAv0HywALE8gECUvggMCP0wEND6kExQvggEHBHAL9B8gASxPIBAlL4IDAj9MBDQ+pBMUL4IBBwRwC/QfJAEsTyAQJS+CAwI/TAQ0PqQTFC+CAQcEcAv0HyiADE8gEAAmgBIWHzTjICYEJoYfNOMkJggmhh804ygmDCaGHzTjLCYAJpYfNOMgJhQmlh804yQmGCaWHzTjKCYcJpYfNOMsJhAmph804yAmJCamHzTjJCYoJqYfNOMoJiwmph804ywmICa2HzTjICY0JrYfNOMkJjgmth804ygmPCa2HzTjLCYwJsYfNOMgJkQmxh804yQmSCbGHzTjKCZMJsYfNOMsJkAm1h804yAmVCbWHzTjJCZYJtYfNOMoJlwm1h804ywmUCbmHzTjICZkJuYfNOMkJmgm5h804ygmbCbmHzTjLCZgJvYfNOMgJnQm9h804yQmeCb2HzTjKCZ8JvYfNOMsJn0PiAIGHzTjLA+IAg0PiEIGHzTjLA+IQg0PiIIGHzTjLA+Igg0PiMIGHzTjLA+Iwg0PiQIGHzTjLA+JAg0PiUIGHzTjLA+JQg0PiYIGHzTjLA+Jgg0PicIGHzTjLA+Jwg0PioIGHzTjLA+Kgg0PisIGHzTjLA+Kwg0PiwIGHzTjLA+LAg0Pi0IGHzTjLA+LQg0Pi4IGHzTjLA+Lgg0Pi8IGHzTjLA+LwgcEcQtVgkACDE8gEEw/Y5QGBgIGhA9IAwIGD/9xj/T/YAccDytjEAIGFhEL0AvwAgcEeAtU/wwEBP9IAhAPA7+AAggL0AvwAgcEcB8AEDGURLCCnQWR4A8cBAAykD8AMME9Mj8AMDMvgIGwQ7IPgIGzL4Bhwg+AYcMvgEHCD4BBwy+AIcIPgCHO3RvPEADwvQEYi88QEPAYAG0FGIvPECD0GAHL+RiIGAACBwRwC/ACBwRwhEcEdP8AACALUTRpRGlkYgOSK/oOgMUKDoDFCx8SABv/T3rwkHKL+g6AxQSL8MwF34BOuJACi/QPgEKwi/cEdIvyD4AisR8IBPGL8A+AErcEcAAAAAAAA=
|
||||||
|
pc_init: 0x225
|
||||||
|
pc_uninit: 0x251
|
||||||
|
pc_program_page: 0x26d
|
||||||
|
pc_erase_sector: 0x269
|
||||||
|
pc_erase_all: 0x255
|
||||||
|
data_section_offset: 0x328
|
||||||
|
flash_properties:
|
||||||
|
address_range:
|
||||||
|
start: 0x0
|
||||||
|
end: 0x40000
|
||||||
|
page_size: 0x100
|
||||||
|
erased_byte_value: 0x0
|
||||||
|
program_page_timeout: 3000
|
||||||
|
erase_sector_timeout: 3000
|
||||||
|
sectors:
|
||||||
|
- size: 0x2000
|
||||||
|
address: 0x0
|
||||||
|
- name: va416_ebi_fram_512kb
|
||||||
|
description: VA416_EBI_512KB
|
||||||
|
instructions: QfKAAsTyAQJS+CAwI/TAQ0PqQTFC+CAQcEcAv0HywALE8gECUvggMCP0wEND6kExQvggEHBHAL9B8gASxPIBAlL4IDAj9MBDQ+pBMUL4IBBwRwC/QfJAEsTyAQJS+CAwI/TAQ0PqQTFC+CAQcEcAv0HyiADE8gEAAmgBIWHzTjICYEJoYfNOMkJggmhh804ygmDCaGHzTjLCYAJpYfNOMgJhQmlh804yQmGCaWHzTjKCYcJpYfNOMsJhAmph804yAmJCamHzTjJCYoJqYfNOMoJiwmph804ywmICa2HzTjICY0JrYfNOMkJjgmth804ygmPCa2HzTjLCYwJsYfNOMgJkQmxh804yQmSCbGHzTjKCZMJsYfNOMsJkAm1h804yAmVCbWHzTjJCZYJtYfNOMoJlwm1h804ywmUCbmHzTjICZkJuYfNOMkJmgm5h804ygmbCbmHzTjLCZgJvYfNOMgJnQm9h804yQmeCb2HzTjKCZ8JvYfNOMsJn0PiAIGHzTjLA+IAg0PiEIGHzTjLA+IQg0PiIIGHzTjLA+Igg0PiMIGHzTjLA+Iwg0PiQIGHzTjLA+JAg0PiUIGHzTjLA+JQg0PiYIGHzTjLA+Jgg0PicIGHzTjLA+Jwg0PioIGHzTjLA+Kgg0PisIGHzTjLA+Kwg0PiwIGHzTjLA+LAg0Pi0IGHzTjLA+LQg0Pi4IGHzTjLA+Lgg0Pi8IGHzTjLA+LwgcEcQtVgkxPIBBCBoQPSAMCBgACDD9jlAYGD/9xj/T/YAcMDytjBgYU7yhBDO8gAAT/QAUQFgRvIAAb/zT4/E8gABGCC/82+PiGAwIgAgCmAQvQAgcEeAtU/wgFBP9AAhAPB4+AAggL0AvwAgcEcB8AEDGURLCCfQWR4DKQPwAwwT0yPwAwMy+AgbBDsg+AgbMvgGHCD4Bhwy+AQcIPgEHDL4Ahwg+AIc7dG88QAPC9ARiLzxAQ8BgAbQUYi88QIPQYAcv5GIgYAAIHBHAL8AIHBHLenwRQHwAQMZRF/qUQwr0OJGvPEBD5i/T/ABCsrxAA6q8QEIACMw+BNQMvgTYLVCItGYRRjQAutDBQDrQwZ3iGyIp0IT0Q7rAwe8HAzQtIipiIxCDdH5HAbQ8YjsiKFCCdEEM5pF3tFgRL3o8IUBMwLgAjMA4AMzT+pDDGBEvejwhU/wAAIAtRNGlEaWRiA5Ir+g6AxQoOgMULHxIAG/9PevCQcov6DoDFBIvwzAXfgE64kAKL9A+AQrCL9wR0i/IPgCKxHwgE8YvwD4AStwRwAAAAA=
|
||||||
|
pc_init: 0x225
|
||||||
|
pc_uninit: 0x275
|
||||||
|
pc_program_page: 0x291
|
||||||
|
pc_erase_sector: 0x28d
|
||||||
|
pc_erase_all: 0x279
|
||||||
|
data_section_offset: 0x3c4
|
||||||
|
flash_properties:
|
||||||
|
address_range:
|
||||||
|
start: 0x10000000
|
||||||
|
end: 0x10080000
|
||||||
|
page_size: 0x100
|
||||||
|
erased_byte_value: 0x0
|
||||||
|
program_page_timeout: 3000
|
||||||
|
erase_sector_timeout: 3000
|
||||||
|
sectors:
|
||||||
|
- size: 0x2000
|
||||||
|
address: 0x0
|
8
scripts/prep-flash.gdb
Normal file
8
scripts/prep-flash.gdb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
target remote localhost:2331
|
||||||
|
|
||||||
|
echo Disabling watchdog\n
|
||||||
|
set *0x400210C0 = 0x1ACCE551
|
||||||
|
set *0x40021008 = 0x0
|
||||||
|
|
||||||
|
echo Disabling Instruction Memory protection\n
|
||||||
|
set *0x40010010 = 0x1
|
3
scripts/prep-flash.sh
Executable file
3
scripts/prep-flash.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Alternative way to unlock the ROM protection of the VA416XX to allow flashing
|
||||||
|
gdb-multiarch -q --batch -ex 'source prep-flash.gdb'
|
38
va416xx-hal/.cargo/config.toml
Normal file
38
va416xx-hal/.cargo/config.toml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
# uncomment ONE of these three option to make `cargo run` start a GDB session
|
||||||
|
# which option to pick depends on your system
|
||||||
|
# If the RevA board is used, replace jlink.gdb with jlink-reva.gdb
|
||||||
|
# runner = "arm-none-eabi-gdb -q -x jlink.gdb"
|
||||||
|
# runner = "gdb-multiarch -q -x jlink.gdb"
|
||||||
|
# runner = "gdb -q -x openocd.gdb"
|
||||||
|
# runner = "gdb-multiarch -q -x jlink.gdb"
|
||||||
|
|
||||||
|
rustflags = [
|
||||||
|
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||||
|
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||||
|
"-C", "link-arg=--nmagic",
|
||||||
|
|
||||||
|
# LLD (shipped with the Rust toolchain) is used as the default linker
|
||||||
|
"-C", "link-arg=-Tlink.x",
|
||||||
|
|
||||||
|
# if you run into problems with LLD switch to the GNU linker by commenting out
|
||||||
|
# this line
|
||||||
|
# "-C", "linker=arm-none-eabi-ld",
|
||||||
|
|
||||||
|
# if you need to link to pre-compiled C libraries provided by a C toolchain
|
||||||
|
# use GCC as the linker by commenting out both lines above and then
|
||||||
|
# uncommenting the three lines below
|
||||||
|
# "-C", "linker=arm-none-eabi-gcc",
|
||||||
|
# "-C", "link-arg=-Wl,-Tlink.x",
|
||||||
|
# "-C", "link-arg=-nostartfiles",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
# Pick ONE of these compilation targets
|
||||||
|
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||||
|
# target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
|
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||||
|
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||||
|
# target = "thumbv8m.base-none-eabi" # Cortex-M23
|
||||||
|
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
|
||||||
|
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)
|
39
va416xx-hal/.cargo/def-config.toml
Normal file
39
va416xx-hal/.cargo/def-config.toml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
# uncomment ONE of these three option to make `cargo run` start a GDB session
|
||||||
|
# which option to pick depends on your system
|
||||||
|
# If the RevA board is used, replace jlink.gdb with jlink-reva.gdb
|
||||||
|
# runner = "arm-none-eabi-gdb -q -x jlink/jlink.gdb"
|
||||||
|
# runner = "gdb-multiarch -q -x jlink/jlink.gdb"
|
||||||
|
|
||||||
|
# runner = "arm-none-eabi-gdb -q -x jlink/jlink-reva.gdb"
|
||||||
|
# runner = "gdb-multiarch -q -x jlink/jlink-reva.gdb"
|
||||||
|
|
||||||
|
rustflags = [
|
||||||
|
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||||
|
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||||
|
"-C", "link-arg=--nmagic",
|
||||||
|
|
||||||
|
# LLD (shipped with the Rust toolchain) is used as the default linker
|
||||||
|
"-C", "link-arg=-Tlink.x",
|
||||||
|
|
||||||
|
# if you run into problems with LLD switch to the GNU linker by commenting out
|
||||||
|
# this line
|
||||||
|
# "-C", "linker=arm-none-eabi-ld",
|
||||||
|
|
||||||
|
# if you need to link to pre-compiled C libraries provided by a C toolchain
|
||||||
|
# use GCC as the linker by commenting out both lines above and then
|
||||||
|
# uncommenting the three lines below
|
||||||
|
# "-C", "linker=arm-none-eabi-gcc",
|
||||||
|
# "-C", "link-arg=-Wl,-Tlink.x",
|
||||||
|
# "-C", "link-arg=-nostartfiles",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
# Pick ONE of these compilation targets
|
||||||
|
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||||
|
# target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
|
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||||
|
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||||
|
# target = "thumbv8m.base-none-eabi" # Cortex-M23
|
||||||
|
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
|
||||||
|
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)
|
2
va416xx-hal/.gitignore
vendored
Normal file
2
va416xx-hal/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
43
va416xx-hal/Cargo.toml
Normal file
43
va416xx-hal/Cargo.toml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
[package]
|
||||||
|
name = "va416xx-hal"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||||
|
edition = "2021"
|
||||||
|
description = "HAL for the Vorago VA416xx family of MCUs"
|
||||||
|
homepage = "https://egit.irs.uni-stuttgart.de/rust/va416xx-hal"
|
||||||
|
repository = "https://egit.irs.uni-stuttgart.de/rust/va416xx-hal"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
keywords = ["no-std", "hal", "cortex-m", "vorago", "va416xx"]
|
||||||
|
categories = ["embedded", "no-std", "hardware-support"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||||
|
nb = "1"
|
||||||
|
paste = "1"
|
||||||
|
embedded-hal-nb = "1"
|
||||||
|
embedded-hal = "1"
|
||||||
|
embedded-io = "0.6"
|
||||||
|
typenum = "1"
|
||||||
|
defmt = { version = "0.3", optional = true }
|
||||||
|
fugit = "0.3"
|
||||||
|
delegate = "0.12"
|
||||||
|
|
||||||
|
[dependencies.void]
|
||||||
|
version = "1"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.va416xx]
|
||||||
|
path = "../va416xx"
|
||||||
|
default-features = false
|
||||||
|
version = "0.1.0"
|
||||||
|
features = ["critical-section"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["rt", "revb"]
|
||||||
|
rt = ["va416xx/rt"]
|
||||||
|
defmt = ["dep:defmt", "fugit/defmt"]
|
||||||
|
revb = []
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--generate-link-to-definition"]
|
201
va416xx-hal/LICENSE-APACHE
Normal file
201
va416xx-hal/LICENSE-APACHE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
3
va416xx-hal/NOTICE
Normal file
3
va416xx-hal/NOTICE
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Rust Hardware Abstraction Layer (HAL) crate for the Vorago VA416xx family of MCUs
|
||||||
|
|
||||||
|
This software contains code developed at the University of Stuttgart.
|
67
va416xx-hal/README.md
Normal file
67
va416xx-hal/README.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# HAL for the Vorago VA416xx MCU family
|
||||||
|
|
||||||
|
This repository contains the **H**ardware **A**bstraction **L**ayer (HAL), which is an additional
|
||||||
|
hardware abstraction on top of the [peripheral access API](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/va416xx).
|
||||||
|
|
||||||
|
It is the result of reading the datasheet for the device and encoding a type-safe layer over the
|
||||||
|
raw PAC. This crate also implements traits specified by the
|
||||||
|
[embedded-hal](https://github.com/rust-embedded/embedded-hal) project, making it compatible with
|
||||||
|
various drivers in the embedded rust ecosystem.
|
||||||
|
|
||||||
|
## Supported Boards
|
||||||
|
|
||||||
|
The first way to use this HAL will probably be with the
|
||||||
|
[PEB1 development board](https://www.voragotech.com/products/peb1va416x0-development-kit).
|
||||||
|
The BSP provided for this board also contains instructions how to flash the board.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Building an application requires the `thumbv7em-none-eabihf` cross-compiler toolchain.
|
||||||
|
If you have not installed it yet, you can do so with
|
||||||
|
|
||||||
|
```sh
|
||||||
|
rustup target add thumbv7em-none-eabihf
|
||||||
|
```
|
||||||
|
|
||||||
|
After that, you can use `cargo build` to build the development version of the crate.
|
||||||
|
|
||||||
|
If you have not done this yet, it is recommended to read some of the excellent resources
|
||||||
|
available to learn Rust:
|
||||||
|
|
||||||
|
- [Rust Embedded Book](https://docs.rust-embedded.org/book/)
|
||||||
|
- [Rust Discovery Book](https://docs.rust-embedded.org/discovery/)
|
||||||
|
|
||||||
|
## Setting up your own binary crate
|
||||||
|
|
||||||
|
If you have a custom board, you might be interested in setting up a new binary crate for your
|
||||||
|
project. These steps aim to provide a complete list to get a binary crate working to flash
|
||||||
|
your custom board.
|
||||||
|
|
||||||
|
The hello world of embedded development is usually to blinky a LED. This example
|
||||||
|
is contained within the
|
||||||
|
[examples folder](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/blinky.rs).
|
||||||
|
|
||||||
|
1. Set up your Rust cross-compiler if you have not done so yet. See more in the [build chapter](#Building)
|
||||||
|
2. Create a new binary crate with `cargo init`
|
||||||
|
3. To ensure that `cargo build` cross-compiles, it is recommended to create a `.cargo/config.toml`
|
||||||
|
file. A sample `.cargo/config.toml` file is provided in this repository as well
|
||||||
|
4. Copy the `memory.x` file into your project. This file contains information required by the linker.
|
||||||
|
5. Copy the `blinky.rs` file to the `src/main.rs` file in your binary crate
|
||||||
|
6. You need to add some dependencies to your `Cargo.toml` file
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
cortex-m = "<Compatible Version>"
|
||||||
|
cortex-m-rt = "<Compatible Version>"
|
||||||
|
panic-halt = "<Compatible Version>"
|
||||||
|
embedded-hal = "<Compatible Version>"
|
||||||
|
|
||||||
|
[dependencies.va416xx-hal]
|
||||||
|
version = "<Most Recent Version>"
|
||||||
|
features = ["rt"]
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Build the application with `cargo build`
|
||||||
|
|
||||||
|
7. Flashing the board might work differently for different boards and there is usually
|
||||||
|
more than one way. You can find example instructions in primary README.
|
5
va416xx-hal/jlink-gdb.sh
Executable file
5
va416xx-hal/jlink-gdb.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Start the JLinkGDBServer while also specifying the JLinkScript file. The JLinkScript is necessary
|
||||||
|
# to disable ROM protection to allow flashing
|
||||||
|
JLinkGDBServer -select USB -device Cortex-M4 -endian little -if SWD -speed 2000 \
|
||||||
|
-LocalhostOnly -vd -jlinkscriptfile ./jlink/JLinkSettings.JLinkScript
|
77
va416xx-hal/jlink/JLinkSettings.JLinkScript
Normal file
77
va416xx-hal/jlink/JLinkSettings.JLinkScript
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* SEGGER Microcontroller GmbH *
|
||||||
|
* Solutions for real time microcontroller applications *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
|
||||||
|
* *
|
||||||
|
* www.segger.com Support: support@segger.com *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
File : JLinkSettings.JLinkScript
|
||||||
|
Purpose : J-Link target setup file for VORAGO VA416xx
|
||||||
|
---------------------------END-OF-HEADER------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int DisableRomProt(void) {
|
||||||
|
JLINK_SYS_Report("VA416XX: Disabling ROM protection");
|
||||||
|
return JLINK_MEM_WriteU32(0x40010010, 0x1); // ROM_PROT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
int DisableWatchdog(void) {
|
||||||
|
JLINK_MEM_WriteU32(0x400210C0, 0x1ACCE551); // WDOGLOCK = 0x1ACCE551
|
||||||
|
JLINK_MEM_WriteU32(0x40021008, 0x0); // WDOGCONTROL = 0x0 (diable)
|
||||||
|
}
|
||||||
|
|
||||||
|
int SetupTarget (void) {
|
||||||
|
JLINK_SYS_Report("SetupTarget()");
|
||||||
|
return DisableRomProt(); // ROM_PROT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* AfterResetTarget
|
||||||
|
*/
|
||||||
|
int AfterResetTarget (void) {
|
||||||
|
JLINK_SYS_Report("AfterResetTarget()");
|
||||||
|
// disable watchdog and unlock code RAM for write
|
||||||
|
DisableWatchdog();
|
||||||
|
return DisableRomProt(); // ROM_PROT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* BeforeTargetDownload
|
||||||
|
*/
|
||||||
|
int BeforeTargetDownload (void) {
|
||||||
|
JLINK_SYS_Report("BeforeTargetDownload()");
|
||||||
|
return DisableRomProt(); // ROM_PROT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* AfterTargetDownload
|
||||||
|
*/
|
||||||
|
int AfterTargetDownload (void) {
|
||||||
|
JLINK_SYS_Report("AfterTargetDownload()");
|
||||||
|
return DisableRomProt(); // ROM_PROT = 0x0
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* HandleBeforeFlashProg
|
||||||
|
*/
|
||||||
|
int HandleBeforeFlashProg(void) {
|
||||||
|
JLINK_SYS_Report("HandleBeforeFlashProg()");
|
||||||
|
return DisableRomProt(); // ROM_PROT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* HandleAfterFlashProg
|
||||||
|
*/
|
||||||
|
int HandleAfterFlashProg(void) {
|
||||||
|
JLINK_SYS_Report("HandleAfterFlashProg()");
|
||||||
|
return DisableRomProt(); // ROM_PROT = 0x0
|
||||||
|
}
|
13
va416xx-hal/jlink/jlink-reva.gdb
Normal file
13
va416xx-hal/jlink/jlink-reva.gdb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
target remote localhost:2331
|
||||||
|
|
||||||
|
# For some reason, this is problematic even if the JLinkScript disabled the remote
|
||||||
|
# write protection. Therefore, don't do it for now
|
||||||
|
# This is only problematic on board RevA
|
||||||
|
# monitor reset
|
||||||
|
|
||||||
|
# *try* to stop at the user entry point (it might be gone due to inlining)
|
||||||
|
break main
|
||||||
|
|
||||||
|
load
|
||||||
|
|
||||||
|
continue
|
11
va416xx-hal/jlink/jlink.gdb
Normal file
11
va416xx-hal/jlink/jlink.gdb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
target remote localhost:2331
|
||||||
|
|
||||||
|
# Reset is problematic on RevA, okay for RevB
|
||||||
|
monitor reset
|
||||||
|
|
||||||
|
# *try* to stop at the user entry point (it might be gone due to inlining)
|
||||||
|
break main
|
||||||
|
|
||||||
|
load
|
||||||
|
|
||||||
|
continue
|
14
va416xx-hal/memory.x
Normal file
14
va416xx-hal/memory.x
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
|
||||||
|
/* RAM is a mandatory region. This RAM refers to the SRAM_0 */
|
||||||
|
RAM : ORIGIN = 0x1FFF8000, LENGTH = 32K
|
||||||
|
SRAM_1 : ORIGIN = 0x20000000, LENGTH = 32K
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is where the call stack will be allocated. */
|
||||||
|
/* The stack is of the full descending type. */
|
||||||
|
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
|
||||||
|
/* SRAM_0 can be used for all busses: Instruction, Data and System */
|
||||||
|
/* SRAM_1 only supports the system bus */
|
||||||
|
_stack_start = ORIGIN(RAM) + LENGTH(RAM) - 4;
|
537
va416xx-hal/src/clock.rs
Normal file
537
va416xx-hal/src/clock.rs
Normal file
@ -0,0 +1,537 @@
|
|||||||
|
//! API for using the [crate::pac::Clkgen] peripheral.
|
||||||
|
//!
|
||||||
|
//! It also includes functionality to enable the peripheral clocks.
|
||||||
|
//! Calling [ClkgenExt::constrain] on the [crate::pac::Clkgen] peripheral generates the
|
||||||
|
//! [ClkgenCfgr] structure which can be used to configure and set up the clock.
|
||||||
|
//!
|
||||||
|
//! Calling [ClkgenCfgr::freeze] returns the frozen clock configuration inside the [Clocks]
|
||||||
|
//! structure. This structure can also be used to configure other structures provided by this HAL.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! - [UART example on the PEB1 board](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/uart.rs)
|
||||||
|
use crate::pac;
|
||||||
|
|
||||||
|
use crate::time::Hertz;
|
||||||
|
|
||||||
|
pub const HBO_FREQ: Hertz = Hertz::from_raw(20_000_000);
|
||||||
|
pub const XTAL_OSC_TSTART_MS: u32 = 15;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum PeripheralSelect {
|
||||||
|
Spi0 = 0,
|
||||||
|
Spi1 = 1,
|
||||||
|
Spi2 = 2,
|
||||||
|
Spi3 = 3,
|
||||||
|
Uart0 = 4,
|
||||||
|
Uart1 = 5,
|
||||||
|
Uart2 = 6,
|
||||||
|
I2c0 = 7,
|
||||||
|
I2c1 = 8,
|
||||||
|
I2c2 = 9,
|
||||||
|
Can0 = 10,
|
||||||
|
Can1 = 11,
|
||||||
|
Rng = 12,
|
||||||
|
Adc = 13,
|
||||||
|
Dac = 14,
|
||||||
|
Dma = 15,
|
||||||
|
Ebi = 16,
|
||||||
|
Eth = 17,
|
||||||
|
Spw = 18,
|
||||||
|
Clkgen = 19,
|
||||||
|
IrqRouter = 20,
|
||||||
|
IoConfig = 21,
|
||||||
|
Utility = 22,
|
||||||
|
Watchdog = 23,
|
||||||
|
PortA = 24,
|
||||||
|
PortB = 25,
|
||||||
|
PortC = 26,
|
||||||
|
PortD = 27,
|
||||||
|
PortE = 28,
|
||||||
|
PortF = 29,
|
||||||
|
PortG = 30,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type PeripheralClocks = PeripheralSelect;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum FilterClkSel {
|
||||||
|
SysClk = 0,
|
||||||
|
Clk1 = 1,
|
||||||
|
Clk2 = 2,
|
||||||
|
Clk3 = 3,
|
||||||
|
Clk4 = 4,
|
||||||
|
Clk5 = 5,
|
||||||
|
Clk6 = 6,
|
||||||
|
Clk7 = 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn enable_peripheral_clock(syscfg: &mut pac::Sysconfig, clock: PeripheralSelect) {
|
||||||
|
syscfg
|
||||||
|
.peripheral_clk_enable()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << clock as u8)) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn disable_peripheral_clock(syscfg: &mut pac::Sysconfig, clock: PeripheralSelect) {
|
||||||
|
syscfg
|
||||||
|
.peripheral_clk_enable()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << clock as u8)) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn assert_periph_reset(syscfg: &mut pac::Sysconfig, periph: PeripheralSelect) {
|
||||||
|
syscfg
|
||||||
|
.peripheral_reset()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << periph as u8)) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn deassert_periph_reset(syscfg: &mut pac::Sysconfig, periph: PeripheralSelect) {
|
||||||
|
syscfg
|
||||||
|
.peripheral_reset()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph as u8)) });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SyscfgExt {
|
||||||
|
fn enable_peripheral_clock(&mut self, clock: PeripheralClocks);
|
||||||
|
|
||||||
|
fn disable_peripheral_clock(&mut self, clock: PeripheralClocks);
|
||||||
|
|
||||||
|
fn assert_periph_reset(&mut self, clock: PeripheralSelect);
|
||||||
|
|
||||||
|
fn deassert_periph_reset(&mut self, clock: PeripheralSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyscfgExt for pac::Sysconfig {
|
||||||
|
#[inline(always)]
|
||||||
|
fn enable_peripheral_clock(&mut self, clock: PeripheralClocks) {
|
||||||
|
enable_peripheral_clock(self, clock)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn disable_peripheral_clock(&mut self, clock: PeripheralClocks) {
|
||||||
|
disable_peripheral_clock(self, clock)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn assert_periph_reset(&mut self, clock: PeripheralSelect) {
|
||||||
|
assert_periph_reset(self, clock)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deassert_periph_reset(&mut self, clock: PeripheralSelect) {
|
||||||
|
deassert_periph_reset(self, clock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Refer to chapter 8 (p.57) of the programmers guide for detailed information.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum ClkselSys {
|
||||||
|
// Internal Heart-Beat Osciallator. Not tightly controlled (+/-20 %). Not recommended as the regular clock!
|
||||||
|
Hbo = 0b00,
|
||||||
|
// External clock signal on XTAL_N line, 1-100 MHz
|
||||||
|
XtalN = 0b01,
|
||||||
|
// Internal Phase-Locked Loop.
|
||||||
|
Pll = 0b10,
|
||||||
|
// Crystal oscillator amplified, 4-10 MHz.
|
||||||
|
XtalOsc = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This selects the input clock to the the CLKGEN peripheral in addition to the HBO clock.
|
||||||
|
///
|
||||||
|
/// This can either be a clock connected directly on the XTAL_N line or a chrystal on the XTAL_P
|
||||||
|
/// line which goes through an oscillator amplifier.
|
||||||
|
///
|
||||||
|
/// Refer to chapter 8 (p.57) of the programmers guide for detailed information.
|
||||||
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum RefClkSel {
|
||||||
|
#[default]
|
||||||
|
None = 0b00,
|
||||||
|
XtalOsc = 0b01,
|
||||||
|
XtalN = 0b10,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum ClkDivSel {
|
||||||
|
#[default]
|
||||||
|
Div1 = 0b00,
|
||||||
|
Div2 = 0b01,
|
||||||
|
Div4 = 0b10,
|
||||||
|
Div8 = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum AdcClkDivSel {
|
||||||
|
Div8 = 0b00,
|
||||||
|
Div4 = 0b01,
|
||||||
|
Div2 = 0b10,
|
||||||
|
Div1 = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct PllCfg {
|
||||||
|
/// Reference clock divider.
|
||||||
|
pub clkr: u8,
|
||||||
|
/// Clock divider on feedback path
|
||||||
|
pub clkf: u8,
|
||||||
|
// Output clock divider.
|
||||||
|
pub clkod: u8,
|
||||||
|
/// Bandwidth adjustment
|
||||||
|
pub bwadj: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clk_after_div(clk: Hertz, div_sel: ClkDivSel) -> Hertz {
|
||||||
|
match div_sel {
|
||||||
|
ClkDivSel::Div1 => clk,
|
||||||
|
ClkDivSel::Div2 => clk / 2,
|
||||||
|
ClkDivSel::Div4 => clk / 4,
|
||||||
|
ClkDivSel::Div8 => clk / 8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wait for 500 reference clock cycles like specified in the datasheet.
|
||||||
|
pub fn pll_setup_delay() {
|
||||||
|
for _ in 0..500 {
|
||||||
|
cortex_m::asm::nop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ClkgenExt {
|
||||||
|
fn constrain(self) -> ClkgenCfgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClkgenExt for pac::Clkgen {
|
||||||
|
fn constrain(self) -> ClkgenCfgr {
|
||||||
|
ClkgenCfgr {
|
||||||
|
source_clk: None,
|
||||||
|
ref_clk_sel: RefClkSel::None,
|
||||||
|
clksel_sys: ClkselSys::Hbo,
|
||||||
|
clk_div_sel: ClkDivSel::Div1,
|
||||||
|
clk_lost_detection: false,
|
||||||
|
pll_lock_lost_detection: false,
|
||||||
|
pll_cfg: None,
|
||||||
|
clkgen: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ClkgenCfgr {
|
||||||
|
ref_clk_sel: RefClkSel,
|
||||||
|
clksel_sys: ClkselSys,
|
||||||
|
clk_div_sel: ClkDivSel,
|
||||||
|
/// The source clock frequency which is either an external clock connected to XTAL_N, or a
|
||||||
|
/// crystal connected to the XTAL_OSC input.
|
||||||
|
source_clk: Option<Hertz>,
|
||||||
|
pll_cfg: Option<PllCfg>,
|
||||||
|
clk_lost_detection: bool,
|
||||||
|
/// Feature only works on revision B of the board.
|
||||||
|
#[cfg(feature = "revb")]
|
||||||
|
pll_lock_lost_detection: bool,
|
||||||
|
clkgen: pac::Clkgen,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct ClkSourceFreqNotSet;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum ClkCfgError {
|
||||||
|
ClkSourceFreqNotSet,
|
||||||
|
PllConfigNotSet,
|
||||||
|
PllInitError,
|
||||||
|
InconsistentCfg,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delays a given amount of milliseconds.
|
||||||
|
///
|
||||||
|
/// Taken from the HAL implementation. This implementation is probably not precise and it
|
||||||
|
/// also blocks!
|
||||||
|
pub fn hbo_clock_delay_ms(ms: u32) {
|
||||||
|
let wdt = unsafe { pac::WatchDog::steal() };
|
||||||
|
for _ in 0..ms {
|
||||||
|
for _ in 0..10_000 {
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
}
|
||||||
|
wdt.wdogintclr().write(|w| unsafe { w.bits(1) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClkgenCfgr {
|
||||||
|
#[inline]
|
||||||
|
pub fn source_clk(mut self, src_clk: Hertz) -> Self {
|
||||||
|
self.source_clk = Some(src_clk);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function can be used to utilize the XTAL_N clock input directly without the
|
||||||
|
/// oscillator.
|
||||||
|
///
|
||||||
|
/// It sets the internal configuration to [ClkselSys::XtalN] and [RefClkSel::XtalN].
|
||||||
|
#[inline]
|
||||||
|
pub fn xtal_n_clk(mut self) -> Self {
|
||||||
|
self.clksel_sys = ClkselSys::XtalN;
|
||||||
|
self.ref_clk_sel = RefClkSel::XtalN;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xtal_n_clk_with_src_freq(mut self, src_clk: Hertz) -> Self {
|
||||||
|
self = self.xtal_n_clk();
|
||||||
|
self.source_clk(src_clk)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clksel_sys(mut self, clksel_sys: ClkselSys) -> Self {
|
||||||
|
self.clksel_sys = clksel_sys;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ref_clk_sel(mut self, ref_clk_sel: RefClkSel) -> Self {
|
||||||
|
self.ref_clk_sel = ref_clk_sel;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configures all clocks and return a clock configuration structure containing the final
|
||||||
|
/// frozen clock.
|
||||||
|
///
|
||||||
|
/// Internal implementation details: This implementation is based on the HAL implementation
|
||||||
|
/// which performs a lot of delays. I do not know if all of those are necessary, but
|
||||||
|
/// I am going to be conservative here and assume that the vendor has tested though and
|
||||||
|
/// might have had a reason for those, so I am going to keep them. Chances are, this
|
||||||
|
/// process only has to be performed once, and it does not matter if it takes a few
|
||||||
|
/// microseconds or milliseconds longer.
|
||||||
|
pub fn freeze(self, syscfg: &mut pac::Sysconfig) -> Result<Clocks, ClkCfgError> {
|
||||||
|
// Sanitize configuration.
|
||||||
|
if self.source_clk.is_none() {
|
||||||
|
return Err(ClkCfgError::ClkSourceFreqNotSet);
|
||||||
|
}
|
||||||
|
if self.clksel_sys == ClkselSys::XtalOsc && self.ref_clk_sel != RefClkSel::XtalOsc {
|
||||||
|
return Err(ClkCfgError::InconsistentCfg);
|
||||||
|
}
|
||||||
|
if self.clksel_sys == ClkselSys::XtalN && self.ref_clk_sel != RefClkSel::XtalN {
|
||||||
|
return Err(ClkCfgError::InconsistentCfg);
|
||||||
|
}
|
||||||
|
if self.clksel_sys == ClkselSys::Pll && self.pll_cfg.is_none() {
|
||||||
|
return Err(ClkCfgError::PllConfigNotSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
syscfg.enable_peripheral_clock(PeripheralSelect::Clkgen);
|
||||||
|
let mut final_sysclk = self.source_clk.unwrap();
|
||||||
|
// The HAL forces back the HBO clock here with a delay.. Even though this is
|
||||||
|
// not stricly necessary when coming from a fresh start, it could be still become relevant
|
||||||
|
// later if the clock lost detection mechanism require a re-configuration of the clocks.
|
||||||
|
// Therefore, we do it here as well.
|
||||||
|
self.clkgen
|
||||||
|
.ctrl0()
|
||||||
|
.modify(|_, w| unsafe { w.clksel_sys().bits(ClkselSys::Hbo as u8) });
|
||||||
|
pll_setup_delay();
|
||||||
|
self.clkgen
|
||||||
|
.ctrl0()
|
||||||
|
.modify(|_, w| unsafe { w.clk_div_sel().bits(ClkDivSel::Div1 as u8) });
|
||||||
|
|
||||||
|
// Set up oscillator and PLL input clock.
|
||||||
|
self.clkgen
|
||||||
|
.ctrl0()
|
||||||
|
.modify(|_, w| unsafe { w.ref_clk_sel().bits(self.ref_clk_sel as u8) });
|
||||||
|
self.clkgen.ctrl1().modify(|_, w| {
|
||||||
|
w.xtal_en().clear_bit();
|
||||||
|
w.xtal_n_en().clear_bit();
|
||||||
|
w
|
||||||
|
});
|
||||||
|
match self.ref_clk_sel {
|
||||||
|
RefClkSel::None => pll_setup_delay(),
|
||||||
|
RefClkSel::XtalOsc => {
|
||||||
|
self.clkgen.ctrl1().modify(|_, w| w.xtal_en().set_bit());
|
||||||
|
hbo_clock_delay_ms(XTAL_OSC_TSTART_MS);
|
||||||
|
}
|
||||||
|
RefClkSel::XtalN => {
|
||||||
|
self.clkgen.ctrl1().modify(|_, w| w.xtal_n_en().set_bit());
|
||||||
|
pll_setup_delay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up PLL configuration.
|
||||||
|
match self.pll_cfg {
|
||||||
|
Some(cfg) => {
|
||||||
|
self.clkgen.ctrl0().modify(|_, w| w.pll_pwdn().clear_bit());
|
||||||
|
// Done in C HAL. I guess this gives the PLL some time to power down properly.
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
self.clkgen.ctrl0().modify(|_, w| {
|
||||||
|
unsafe {
|
||||||
|
w.pll_clkf().bits(cfg.clkf);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
w.pll_clkr().bits(cfg.clkr);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
w.pll_clkod().bits(cfg.clkod);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
w.pll_bwadj().bits(cfg.bwadj);
|
||||||
|
}
|
||||||
|
w.pll_test().clear_bit();
|
||||||
|
w.pll_bypass().clear_bit();
|
||||||
|
w.pll_intfb().set_bit()
|
||||||
|
});
|
||||||
|
// Taken from SystemCoreClockUpdate implementation from Vorago.
|
||||||
|
final_sysclk /= cfg.clkr as u32 + 1;
|
||||||
|
final_sysclk *= cfg.clkf as u32 + 1;
|
||||||
|
final_sysclk /= cfg.clkod as u32 + 1;
|
||||||
|
|
||||||
|
// Reset PLL.
|
||||||
|
self.clkgen.ctrl0().modify(|_, w| w.pll_reset().set_bit());
|
||||||
|
// The HAL does this, the datasheet specifies a delay of 5 us. I guess it does not
|
||||||
|
// really matter because the PLL lock detect is used later..
|
||||||
|
pll_setup_delay();
|
||||||
|
self.clkgen.ctrl0().modify(|_, w| w.pll_reset().clear_bit());
|
||||||
|
pll_setup_delay();
|
||||||
|
|
||||||
|
// check for lock
|
||||||
|
let stat = self.clkgen.stat().read();
|
||||||
|
if stat.fbslip().bit() || stat.rfslip().bit() {
|
||||||
|
pll_setup_delay();
|
||||||
|
if stat.fbslip().bit() || stat.rfslip().bit() {
|
||||||
|
// This is what the HAL does. We could continue, but then we would at least
|
||||||
|
// have to somehow report a partial error.. Chances are, the user does not
|
||||||
|
// want to continue with a broken PLL clock.
|
||||||
|
return Err(ClkCfgError::PllInitError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => self.clkgen.ctrl0().modify(|_, w| w.pll_pwdn().set_bit()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.clk_lost_detection {
|
||||||
|
rearm_sysclk_lost_with_periph(&self.clkgen)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "revb")]
|
||||||
|
if self.pll_lock_lost_detection {
|
||||||
|
rearm_pll_lock_lost_with_periph(&self.clkgen)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.clkgen
|
||||||
|
.ctrl0()
|
||||||
|
.modify(|_, w| unsafe { w.clk_div_sel().bits(self.clk_div_sel as u8) });
|
||||||
|
final_sysclk = clk_after_div(final_sysclk, self.clk_div_sel);
|
||||||
|
|
||||||
|
// The HAL does this. I don't know why..
|
||||||
|
pll_setup_delay();
|
||||||
|
|
||||||
|
self.clkgen
|
||||||
|
.ctrl0()
|
||||||
|
.modify(|_, w| unsafe { w.clksel_sys().bits(self.clksel_sys as u8) });
|
||||||
|
|
||||||
|
// I will just do the ADC stuff like Vorago does it.
|
||||||
|
// ADC clock (must be 2-12.5 MHz)
|
||||||
|
// NOTE: Not using divide by 1 or /2 ratio in REVA silicon because of triggering issue
|
||||||
|
// For this reason, keep SYSCLK above 8MHz to have the ADC /4 ratio in range)
|
||||||
|
if final_sysclk.raw() <= 50_000_000 {
|
||||||
|
self.clkgen
|
||||||
|
.ctrl1()
|
||||||
|
.modify(|_, w| unsafe { w.adc_clk_div_sel().bits(AdcClkDivSel::Div4 as u8) });
|
||||||
|
} else {
|
||||||
|
self.clkgen
|
||||||
|
.ctrl1()
|
||||||
|
.modify(|_, w| unsafe { w.adc_clk_div_sel().bits(AdcClkDivSel::Div8 as u8) });
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Clocks {
|
||||||
|
sysclk: final_sysclk,
|
||||||
|
apb1: final_sysclk / 2,
|
||||||
|
apb2: final_sysclk / 4,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frozen clock frequencies
|
||||||
|
///
|
||||||
|
/// The existence of this value indicates that the clock configuration can no longer be changed.
|
||||||
|
/// The [self] module documentation gives some more information on how to retrieve an instance
|
||||||
|
/// of this structure.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct Clocks {
|
||||||
|
sysclk: Hertz,
|
||||||
|
apb1: Hertz,
|
||||||
|
apb2: Hertz,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clocks {
|
||||||
|
/// Returns the frequency of the HBO clock
|
||||||
|
pub fn hbo(&self) -> Hertz {
|
||||||
|
HBO_FREQ
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the frequency of the APB0 which is equal to the system clock.
|
||||||
|
pub fn apb0(&self) -> Hertz {
|
||||||
|
self.sysclk()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns system clock divied by 2.
|
||||||
|
pub fn apb1(&self) -> Hertz {
|
||||||
|
self.apb1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns system clock divied by 4.
|
||||||
|
pub fn apb2(&self) -> Hertz {
|
||||||
|
self.apb2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the system (core) frequency
|
||||||
|
pub fn sysclk(&self) -> Hertz {
|
||||||
|
self.sysclk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rearm_sysclk_lost() {
|
||||||
|
rearm_sysclk_lost_with_periph(&unsafe { pac::Clkgen::steal() })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rearm_sysclk_lost_with_periph(clkgen: &pac::Clkgen) {
|
||||||
|
clkgen
|
||||||
|
.ctrl0()
|
||||||
|
.modify(|_, w| w.sys_clk_lost_det_en().set_bit());
|
||||||
|
clkgen
|
||||||
|
.ctrl1()
|
||||||
|
.write(|w| w.sys_clk_lost_det_rearm().set_bit());
|
||||||
|
clkgen
|
||||||
|
.ctrl1()
|
||||||
|
.write(|w| w.sys_clk_lost_det_rearm().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "revb")]
|
||||||
|
pub fn rearm_pll_lock_lost() {
|
||||||
|
rearm_pll_lock_lost_with_periph(&unsafe { pac::Clkgen::steal() })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rearm_pll_lock_lost_with_periph(clkgen: &pac::Clkgen) {
|
||||||
|
clkgen
|
||||||
|
.ctrl1()
|
||||||
|
.modify(|_, w| w.pll_lost_lock_det_en().set_bit());
|
||||||
|
clkgen.ctrl1().write(|w| w.pll_lck_det_rearm().set_bit());
|
||||||
|
clkgen.ctrl1().write(|w| w.pll_lck_det_rearm().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_basic_div() {
|
||||||
|
assert_eq!(
|
||||||
|
clk_after_div(Hertz::from_raw(10_000_000), super::ClkDivSel::Div2),
|
||||||
|
Hertz::from_raw(5_000_000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
453
va416xx-hal/src/gpio/dynpin.rs
Normal file
453
va416xx-hal/src/gpio/dynpin.rs
Normal file
@ -0,0 +1,453 @@
|
|||||||
|
use embedded_hal::digital::{ErrorKind, ErrorType, InputPin, OutputPin, StatefulOutputPin};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
reg::RegisterInterface, FilterClkSel, FilterType, InterruptEdge, InterruptLevel, Pin, PinId,
|
||||||
|
PinMode, PinState,
|
||||||
|
};
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// DynPinMode configurations
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Value-level `enum` for disabled configurations
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum DynDisabled {
|
||||||
|
Floating,
|
||||||
|
PullDown,
|
||||||
|
PullUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Value-level `enum` for input configurations
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum DynInput {
|
||||||
|
Floating,
|
||||||
|
PullDown,
|
||||||
|
PullUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Value-level `enum` for output configurations
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum DynOutput {
|
||||||
|
PushPull,
|
||||||
|
OpenDrain,
|
||||||
|
ReadablePushPull,
|
||||||
|
ReadableOpenDrain,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DynAlternate = crate::FunSel;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// DynPinMode
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Value-level `enum` representing pin modes
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum DynPinMode {
|
||||||
|
Input(DynInput),
|
||||||
|
Output(DynOutput),
|
||||||
|
Alternate(DynAlternate),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Value-level variant of [`DynPinMode`] for floating input mode
|
||||||
|
pub const DYN_FLOATING_INPUT: DynPinMode = DynPinMode::Input(DynInput::Floating);
|
||||||
|
/// Value-level variant of [`DynPinMode`] for pull-down input mode
|
||||||
|
pub const DYN_PULL_DOWN_INPUT: DynPinMode = DynPinMode::Input(DynInput::PullDown);
|
||||||
|
/// Value-level variant of [`DynPinMode`] for pull-up input mode
|
||||||
|
pub const DYN_PULL_UP_INPUT: DynPinMode = DynPinMode::Input(DynInput::PullUp);
|
||||||
|
|
||||||
|
/// Value-level variant of [`DynPinMode`] for push-pull output mode
|
||||||
|
pub const DYN_PUSH_PULL_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::PushPull);
|
||||||
|
/// Value-level variant of [`DynPinMode`] for open-drain output mode
|
||||||
|
pub const DYN_OPEN_DRAIN_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::OpenDrain);
|
||||||
|
/// Value-level variant of [`DynPinMode`] for readable push-pull output mode
|
||||||
|
pub const DYN_RD_PUSH_PULL_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::ReadablePushPull);
|
||||||
|
/// Value-level variant of [`DynPinMode`] for readable opendrain output mode
|
||||||
|
pub const DYN_RD_OPEN_DRAIN_OUTPUT: DynPinMode = DynPinMode::Output(DynOutput::ReadableOpenDrain);
|
||||||
|
|
||||||
|
/// Value-level variant of [`DynPinMode`] for function select 1
|
||||||
|
pub const DYN_ALT_FUNC_1: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel1);
|
||||||
|
/// Value-level variant of [`DynPinMode`] for function select 2
|
||||||
|
pub const DYN_ALT_FUNC_2: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel2);
|
||||||
|
/// Value-level variant of [`DynPinMode`] for function select 3
|
||||||
|
pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3);
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// DynGroup & DynPinId
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Value-level `enum` for pin groups
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum DynGroup {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
D,
|
||||||
|
E,
|
||||||
|
F,
|
||||||
|
G,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Value-level `struct` representing pin IDs
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub struct DynPinId {
|
||||||
|
pub group: DynGroup,
|
||||||
|
pub num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// DynRegisters
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/// Provide a safe register interface for [`DynPin`]s
|
||||||
|
///
|
||||||
|
/// This `struct` takes ownership of a [`DynPinId`] and provides an API to
|
||||||
|
/// access the corresponding regsiters.
|
||||||
|
struct DynRegisters {
|
||||||
|
id: DynPinId,
|
||||||
|
}
|
||||||
|
|
||||||
|
// [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
|
||||||
|
// guarantees that each pin is a singleton, so this implementation is safe.
|
||||||
|
unsafe impl RegisterInterface for DynRegisters {
|
||||||
|
#[inline]
|
||||||
|
fn id(&self) -> DynPinId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynRegisters {
|
||||||
|
/// Create a new instance of [`DynRegisters`]
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Users must never create two simultaneous instances of this `struct` with
|
||||||
|
/// the same [`DynPinId`]
|
||||||
|
#[inline]
|
||||||
|
unsafe fn new(id: DynPinId) -> Self {
|
||||||
|
DynRegisters { id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Error
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/// GPIO error type
|
||||||
|
///
|
||||||
|
/// [`DynPin`]s are not tracked and verified at compile-time, so run-time
|
||||||
|
/// operations are fallible. This `enum` represents the corresponding errors.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct InvalidPinTypeError(pub(crate) ());
|
||||||
|
|
||||||
|
impl embedded_hal::digital::Error for InvalidPinTypeError {
|
||||||
|
fn kind(&self) -> embedded_hal::digital::ErrorKind {
|
||||||
|
ErrorKind::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// DynPin
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// A value-level pin, parameterized by [`DynPinId`] and [`DynPinMode`]
|
||||||
|
///
|
||||||
|
/// This type acts as a type-erased version of [`Pin`]. Every pin is represented
|
||||||
|
/// by the same type, and pins are tracked and distinguished at run-time.
|
||||||
|
pub struct DynPin {
|
||||||
|
regs: DynRegisters,
|
||||||
|
mode: DynPinMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynPin {
|
||||||
|
/// Create a new [`DynPin`]
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Each [`DynPin`] must be a singleton. For a given [`DynPinId`], there
|
||||||
|
/// must be at most one corresponding [`DynPin`] in existence at any given
|
||||||
|
/// time. Violating this requirement is `unsafe`.
|
||||||
|
#[inline]
|
||||||
|
unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self {
|
||||||
|
DynPin {
|
||||||
|
regs: DynRegisters::new(id),
|
||||||
|
mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a copy of the pin ID
|
||||||
|
#[inline]
|
||||||
|
pub fn id(&self) -> DynPinId {
|
||||||
|
self.regs.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a copy of the pin mode
|
||||||
|
#[inline]
|
||||||
|
pub fn mode(&self) -> DynPinMode {
|
||||||
|
self.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the pin to the requested [`DynPinMode`]
|
||||||
|
#[inline]
|
||||||
|
pub fn into_mode(&mut self, mode: DynPinMode) {
|
||||||
|
// Only modify registers if we are actually changing pin mode
|
||||||
|
if mode != self.mode {
|
||||||
|
self.regs.change_mode(mode);
|
||||||
|
self.mode = mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn into_funsel_1(&mut self) {
|
||||||
|
self.into_mode(DYN_ALT_FUNC_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn into_funsel_2(&mut self) {
|
||||||
|
self.into_mode(DYN_ALT_FUNC_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn into_funsel_3(&mut self) {
|
||||||
|
self.into_mode(DYN_ALT_FUNC_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a floating input
|
||||||
|
#[inline]
|
||||||
|
pub fn into_floating_input(&mut self) {
|
||||||
|
self.into_mode(DYN_FLOATING_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a pulled down input
|
||||||
|
#[inline]
|
||||||
|
pub fn into_pull_down_input(&mut self) {
|
||||||
|
self.into_mode(DYN_PULL_DOWN_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a pulled up input
|
||||||
|
#[inline]
|
||||||
|
pub fn into_pull_up_input(&mut self) {
|
||||||
|
self.into_mode(DYN_PULL_UP_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a push-pull output
|
||||||
|
#[inline]
|
||||||
|
pub fn into_push_pull_output(&mut self) {
|
||||||
|
self.into_mode(DYN_PUSH_PULL_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a push-pull output
|
||||||
|
#[inline]
|
||||||
|
pub fn into_open_drain_output(&mut self) {
|
||||||
|
self.into_mode(DYN_OPEN_DRAIN_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a push-pull output
|
||||||
|
#[inline]
|
||||||
|
pub fn into_readable_push_pull_output(&mut self) {
|
||||||
|
self.into_mode(DYN_RD_PUSH_PULL_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a push-pull output
|
||||||
|
#[inline]
|
||||||
|
pub fn into_readable_open_drain_output(&mut self) {
|
||||||
|
self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
common_reg_if_functions!();
|
||||||
|
|
||||||
|
/// See p.53 of the programmers guide for more information.
|
||||||
|
/// Possible delays in clock cycles:
|
||||||
|
/// - Delay 1: 1
|
||||||
|
/// - Delay 2: 2
|
||||||
|
/// - Delay 1 + Delay 2: 3
|
||||||
|
#[inline]
|
||||||
|
pub fn delay(self, delay_1: bool, delay_2: bool) -> Result<Self, InvalidPinTypeError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Output(_) => {
|
||||||
|
self.regs.delay(delay_1, delay_2);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
_ => Err(InvalidPinTypeError(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See p.52 of the programmers guide for more information.
|
||||||
|
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
||||||
|
/// one clock cycle before returning to the configured default state
|
||||||
|
pub fn pulse_mode(
|
||||||
|
self,
|
||||||
|
enable: bool,
|
||||||
|
default_state: PinState,
|
||||||
|
) -> Result<Self, InvalidPinTypeError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Output(_) => {
|
||||||
|
self.regs.pulse_mode(enable, default_state);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
_ => Err(InvalidPinTypeError(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See p.37 and p.38 of the programmers guide for more information.
|
||||||
|
#[inline]
|
||||||
|
pub fn filter_type(
|
||||||
|
self,
|
||||||
|
filter: FilterType,
|
||||||
|
clksel: FilterClkSel,
|
||||||
|
) -> Result<Self, InvalidPinTypeError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Input(_) => {
|
||||||
|
self.regs.filter_type(filter, clksel);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
_ => Err(InvalidPinTypeError(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Result<Self, InvalidPinTypeError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
self.irq_enb();
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
_ => Err(InvalidPinTypeError(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_level(
|
||||||
|
mut self,
|
||||||
|
level_type: InterruptLevel,
|
||||||
|
) -> Result<Self, InvalidPinTypeError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
|
self.regs.interrupt_level(level_type);
|
||||||
|
self.irq_enb();
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
_ => Err(InvalidPinTypeError(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn _read(&self) -> Result<bool, InvalidPinTypeError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => {
|
||||||
|
Ok(self.regs.read_pin())
|
||||||
|
}
|
||||||
|
_ => Err(InvalidPinTypeError(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn _write(&mut self, bit: bool) -> Result<(), InvalidPinTypeError> {
|
||||||
|
match self.mode {
|
||||||
|
DynPinMode::Output(_) => {
|
||||||
|
self.regs.write_pin(bit);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(InvalidPinTypeError(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn _is_low(&self) -> Result<bool, InvalidPinTypeError> {
|
||||||
|
self._read().map(|v| !v)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn _is_high(&self) -> Result<bool, InvalidPinTypeError> {
|
||||||
|
self._read()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn _set_low(&mut self) -> Result<(), InvalidPinTypeError> {
|
||||||
|
self._write(false)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn _set_high(&mut self) -> Result<(), InvalidPinTypeError> {
|
||||||
|
self._write(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Convert between Pin and DynPin
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
impl<I, M> From<Pin<I, M>> for DynPin
|
||||||
|
where
|
||||||
|
I: PinId,
|
||||||
|
M: PinMode,
|
||||||
|
{
|
||||||
|
/// Erase the type-level information in a [`Pin`] and return a value-level
|
||||||
|
/// [`DynPin`]
|
||||||
|
#[inline]
|
||||||
|
fn from(_pin: Pin<I, M>) -> Self {
|
||||||
|
// The `Pin` is consumed, so it is safe to replace it with the
|
||||||
|
// corresponding `DynPin`
|
||||||
|
unsafe { DynPin::new(I::DYN, M::DYN) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, M> TryFrom<DynPin> for Pin<I, M>
|
||||||
|
where
|
||||||
|
I: PinId,
|
||||||
|
M: PinMode,
|
||||||
|
{
|
||||||
|
type Error = InvalidPinTypeError;
|
||||||
|
|
||||||
|
/// Try to recreate a type-level [`Pin`] from a value-level [`DynPin`]
|
||||||
|
///
|
||||||
|
/// There is no way for the compiler to know if the conversion will be
|
||||||
|
/// successful at compile-time. We must verify the conversion at run-time
|
||||||
|
/// or refuse to perform it.
|
||||||
|
#[inline]
|
||||||
|
fn try_from(pin: DynPin) -> Result<Self, Self::Error> {
|
||||||
|
if pin.regs.id == I::DYN && pin.mode == M::DYN {
|
||||||
|
// The `DynPin` is consumed, so it is safe to replace it with the
|
||||||
|
// corresponding `Pin`
|
||||||
|
Ok(unsafe { Self::new() })
|
||||||
|
} else {
|
||||||
|
Err(InvalidPinTypeError(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Embedded HAL v1 traits
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
impl ErrorType for DynPin {
|
||||||
|
type Error = InvalidPinTypeError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputPin for DynPin {
|
||||||
|
#[inline]
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self._set_high()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self._set_low()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputPin for DynPin {
|
||||||
|
#[inline]
|
||||||
|
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
self._is_high()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_low(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
self._is_low()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StatefulOutputPin for DynPin {
|
||||||
|
#[inline]
|
||||||
|
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
self._is_high()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
self._is_low()
|
||||||
|
}
|
||||||
|
}
|
82
va416xx-hal/src/gpio/mod.rs
Normal file
82
va416xx-hal/src/gpio/mod.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
//! # API for the GPIO peripheral
|
||||||
|
//!
|
||||||
|
//! The implementation of this GPIO module is heavily based on the
|
||||||
|
//! [ATSAMD HAL implementation](https://docs.rs/atsamd-hal/latest/atsamd_hal/gpio/index.html).
|
||||||
|
//!
|
||||||
|
//! This API provides two different submodules, [pin] and [dynpin],
|
||||||
|
//! representing two different ways to handle GPIO pins. The default, [pin],
|
||||||
|
//! is a type-level API that tracks the state of each pin at compile-time. The
|
||||||
|
//! alternative, [dynpin] is a type-erased, value-level API that tracks the
|
||||||
|
//! state of each pin at run-time.
|
||||||
|
//!
|
||||||
|
//! The type-level API is strongly preferred. By representing the state of each
|
||||||
|
//! pin within the type system, the compiler can detect logic errors at
|
||||||
|
//! compile-time. Furthermore, the type-level API has absolutely zero run-time
|
||||||
|
//! cost.
|
||||||
|
//!
|
||||||
|
//! If needed, [dynpin] can be used to erase the type-level differences
|
||||||
|
//! between pins. However, by doing so, pins must now be tracked at run-time,
|
||||||
|
//! and each pin has a non-zero memory footprint.
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/blinky.rs)
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct IsMaskedError;
|
||||||
|
|
||||||
|
macro_rules! common_reg_if_functions {
|
||||||
|
() => {
|
||||||
|
paste::paste!(
|
||||||
|
#[inline]
|
||||||
|
pub fn datamask(&self) -> bool {
|
||||||
|
self.regs.datamask()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_datamask(self) -> Self {
|
||||||
|
self.regs.clear_datamask();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_datamask(self) -> Self {
|
||||||
|
self.regs.set_datamask();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_high_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
||||||
|
self.regs.read_pin_masked()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
|
||||||
|
self.regs.read_pin_masked().map(|v| !v)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
|
||||||
|
self.regs.write_pin_masked(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
|
||||||
|
self.regs.write_pin_masked(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_enb(&mut self) {
|
||||||
|
self.regs.enable_irq();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod pin;
|
||||||
|
pub use pin::*;
|
||||||
|
|
||||||
|
pub mod dynpin;
|
||||||
|
pub use dynpin::*;
|
||||||
|
|
||||||
|
mod reg;
|
911
va416xx-hal/src/gpio/pin.rs
Normal file
911
va416xx-hal/src/gpio/pin.rs
Normal file
@ -0,0 +1,911 @@
|
|||||||
|
//! # Type-level module for GPIO pins
|
||||||
|
//!
|
||||||
|
//! This documentation is strongly based on the
|
||||||
|
//! [atsamd documentation](https://docs.rs/atsamd-hal/latest/atsamd_hal/gpio/pin/index.html).
|
||||||
|
//!
|
||||||
|
//! This module provides a type-level API for GPIO pins. It uses the type system
|
||||||
|
//! to track the state of pins at compile-time. Representing GPIO pins in this
|
||||||
|
//! manner incurs no run-time overhead. Each [`Pin`] struct is zero-sized, so
|
||||||
|
//! there is no data to copy around. Instead, real code is generated as a side
|
||||||
|
//! effect of type transformations, and the resulting assembly is nearly
|
||||||
|
//! identical to the equivalent, hand-written C.
|
||||||
|
//!
|
||||||
|
//! To track the state of pins at compile-time, this module uses traits to
|
||||||
|
//! represent [type classes] and types as instances of those type classes. For
|
||||||
|
//! example, the trait [`InputConfig`] acts as a [type-level enum] of the
|
||||||
|
//! available input configurations, and the types [`Floating`], [`PullDown`] and
|
||||||
|
//! [`PullUp`] are its type-level variants.
|
||||||
|
//!
|
||||||
|
//! Type-level [`Pin`]s are parameterized by two type-level enums, [`PinId`] and
|
||||||
|
//! [`PinMode`].
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! pub struct Pin<I, M>
|
||||||
|
//! where
|
||||||
|
//! I: PinId,
|
||||||
|
//! M: PinMode,
|
||||||
|
//! {
|
||||||
|
//! // ...
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! A `PinId` identifies a pin by it's group (A to G) and pin number. Each
|
||||||
|
//! `PinId` instance is named according to its datasheet identifier, e.g.
|
||||||
|
//! [PA2].
|
||||||
|
//!
|
||||||
|
//! A `PinMode` represents the various pin modes. The available `PinMode`
|
||||||
|
//! variants are [`Input`], [`Output`] and [`Alternate`], each with its own
|
||||||
|
//! corresponding configurations.
|
||||||
|
//!
|
||||||
|
//! It is not possible for users to create new instances of a [`Pin`]. Singleton
|
||||||
|
//! instances of each pin are made available to users through the PinsX
|
||||||
|
//! struct.
|
||||||
|
//!
|
||||||
|
//! Example for the pins of PORT A:
|
||||||
|
//!
|
||||||
|
//! To create the [PinsA] struct, users must supply the PAC
|
||||||
|
//! [Port](crate::pac::Porta) peripheral. The [PinsA] struct takes
|
||||||
|
//! ownership of the [Porta] and provides the corresponding pins. Each [`Pin`]
|
||||||
|
//! within the [PinsA] struct can be moved out and used individually.
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! let mut peripherals = Peripherals::take().unwrap();
|
||||||
|
//! let pinsa = PinsA::new(peripherals.porta);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Pins can be converted between modes using several different methods.
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! // Use one of the literal function names
|
||||||
|
//! let pa0 = pinsa.pa0.into_floating_input();
|
||||||
|
//! // Use a generic method and one of the `PinMode` variant types
|
||||||
|
//! let pa0 = pinsa.pa0.into_mode::<FloatingInput>();
|
||||||
|
//! // Specify the target type and use `From`/`Into`
|
||||||
|
//! let pa0: Pin<PA0, FloatingInput> = pinsa.pa27.into();
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Embedded HAL traits
|
||||||
|
//!
|
||||||
|
//! This module implements all of the embedded HAL GPIO traits for each [`Pin`]
|
||||||
|
//! in the corresponding [`PinMode`]s, namely: [`InputPin`], [`OutputPin`],
|
||||||
|
//! and [`StatefulOutputPin`].
|
||||||
|
use core::{convert::Infallible, marker::PhantomData, mem::transmute};
|
||||||
|
|
||||||
|
pub use crate::clock::FilterClkSel;
|
||||||
|
use crate::typelevel::Sealed;
|
||||||
|
use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
|
||||||
|
use va416xx::{Porta, Portb, Portc, Portd, Porte, Portf, Portg};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
reg::RegisterInterface, DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Errors and Definitions
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum InterruptEdge {
|
||||||
|
HighToLow,
|
||||||
|
LowToHigh,
|
||||||
|
BothEdges,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum InterruptLevel {
|
||||||
|
Low = 0,
|
||||||
|
High = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum PinState {
|
||||||
|
Low = 0,
|
||||||
|
High = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Input configuration
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Type-level enum for input configurations
|
||||||
|
///
|
||||||
|
/// The valid options are [Floating], [PullDown] and [PullUp].
|
||||||
|
pub trait InputConfig: Sealed {
|
||||||
|
/// Corresponding [DynInput]
|
||||||
|
const DYN: DynInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Floating {}
|
||||||
|
pub enum PullDown {}
|
||||||
|
pub enum PullUp {}
|
||||||
|
|
||||||
|
impl InputConfig for Floating {
|
||||||
|
const DYN: DynInput = DynInput::Floating;
|
||||||
|
}
|
||||||
|
impl InputConfig for PullDown {
|
||||||
|
const DYN: DynInput = DynInput::PullDown;
|
||||||
|
}
|
||||||
|
impl InputConfig for PullUp {
|
||||||
|
const DYN: DynInput = DynInput::PullUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sealed for Floating {}
|
||||||
|
impl Sealed for PullDown {}
|
||||||
|
impl Sealed for PullUp {}
|
||||||
|
|
||||||
|
/// Type-level variant of [PinMode] for floating input mode
|
||||||
|
pub type InputFloating = Input<Floating>;
|
||||||
|
/// Type-level variant of [PinMode] for pull-down input mode
|
||||||
|
pub type InputPullDown = Input<PullDown>;
|
||||||
|
/// Type-level variant of [PinMode] for pull-up input mode
|
||||||
|
pub type InputPullUp = Input<PullUp>;
|
||||||
|
|
||||||
|
/// Type-level variant of [PinMode] for input modes
|
||||||
|
///
|
||||||
|
/// Type `C` is one of three input configurations: [Floating], [PullDown] or
|
||||||
|
/// [PullUp]
|
||||||
|
pub struct Input<C: InputConfig> {
|
||||||
|
cfg: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: InputConfig> Sealed for Input<C> {}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum FilterType {
|
||||||
|
SystemClock = 0,
|
||||||
|
DirectInputWithSynchronization = 1,
|
||||||
|
FilterOneClockCycle = 2,
|
||||||
|
FilterTwoClockCycles = 3,
|
||||||
|
FilterThreeClockCycles = 4,
|
||||||
|
FilterFourClockCycles = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Output configuration
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub trait OutputConfig: Sealed {
|
||||||
|
const DYN: DynOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ReadableOutput: Sealed {}
|
||||||
|
|
||||||
|
/// Type-level variant of [`OutputConfig`] for a push-pull configuration
|
||||||
|
pub enum PushPull {}
|
||||||
|
/// Type-level variant of [`OutputConfig`] for an open drain configuration
|
||||||
|
pub enum OpenDrain {}
|
||||||
|
|
||||||
|
/// Type-level variant of [`OutputConfig`] for a readable push-pull configuration
|
||||||
|
pub enum ReadablePushPull {}
|
||||||
|
/// Type-level variant of [`OutputConfig`] for a readable open-drain configuration
|
||||||
|
pub enum ReadableOpenDrain {}
|
||||||
|
|
||||||
|
impl Sealed for PushPull {}
|
||||||
|
impl Sealed for OpenDrain {}
|
||||||
|
impl Sealed for ReadableOpenDrain {}
|
||||||
|
impl Sealed for ReadablePushPull {}
|
||||||
|
impl ReadableOutput for ReadableOpenDrain {}
|
||||||
|
impl ReadableOutput for ReadablePushPull {}
|
||||||
|
|
||||||
|
impl OutputConfig for PushPull {
|
||||||
|
const DYN: DynOutput = DynOutput::PushPull;
|
||||||
|
}
|
||||||
|
impl OutputConfig for OpenDrain {
|
||||||
|
const DYN: DynOutput = DynOutput::OpenDrain;
|
||||||
|
}
|
||||||
|
impl OutputConfig for ReadablePushPull {
|
||||||
|
const DYN: DynOutput = DynOutput::ReadablePushPull;
|
||||||
|
}
|
||||||
|
impl OutputConfig for ReadableOpenDrain {
|
||||||
|
const DYN: DynOutput = DynOutput::ReadableOpenDrain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type-level variant of [`PinMode`] for output modes
|
||||||
|
///
|
||||||
|
/// Type `C` is one of four output configurations: [`PushPull`], [`OpenDrain`] or
|
||||||
|
/// their respective readable versions
|
||||||
|
pub struct Output<C: OutputConfig> {
|
||||||
|
cfg: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: OutputConfig> Sealed for Output<C> {}
|
||||||
|
|
||||||
|
/// Type-level variant of [`PinMode`] for push-pull output mode
|
||||||
|
pub type PushPullOutput = Output<PushPull>;
|
||||||
|
/// Type-level variant of [`PinMode`] for open drain output mode
|
||||||
|
pub type OutputOpenDrain = Output<OpenDrain>;
|
||||||
|
|
||||||
|
pub type OutputReadablePushPull = Output<ReadablePushPull>;
|
||||||
|
pub type OutputReadableOpenDrain = Output<ReadableOpenDrain>;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Alternate configurations
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Type-level enum for alternate peripheral function configurations
|
||||||
|
pub trait AlternateConfig: Sealed {
|
||||||
|
const DYN: DynAlternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Funsel1 {}
|
||||||
|
pub enum Funsel2 {}
|
||||||
|
pub enum Funsel3 {}
|
||||||
|
|
||||||
|
impl AlternateConfig for Funsel1 {
|
||||||
|
const DYN: DynAlternate = DynAlternate::Sel1;
|
||||||
|
}
|
||||||
|
impl AlternateConfig for Funsel2 {
|
||||||
|
const DYN: DynAlternate = DynAlternate::Sel2;
|
||||||
|
}
|
||||||
|
impl AlternateConfig for Funsel3 {
|
||||||
|
const DYN: DynAlternate = DynAlternate::Sel3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sealed for Funsel1 {}
|
||||||
|
impl Sealed for Funsel2 {}
|
||||||
|
impl Sealed for Funsel3 {}
|
||||||
|
|
||||||
|
/// Type-level variant of [`PinMode`] for alternate peripheral functions
|
||||||
|
///
|
||||||
|
/// Type `C` is an [`AlternateConfig`]
|
||||||
|
pub struct Alternate<C: AlternateConfig> {
|
||||||
|
cfg: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: AlternateConfig> Sealed for Alternate<C> {}
|
||||||
|
|
||||||
|
pub type AltFunc1 = Alternate<Funsel1>;
|
||||||
|
pub type AltFunc2 = Alternate<Funsel2>;
|
||||||
|
pub type AltFunc3 = Alternate<Funsel3>;
|
||||||
|
|
||||||
|
/// Type alias for the [`PinMode`] at reset
|
||||||
|
pub type Reset = InputFloating;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Pin modes
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Type-level enum representing pin modes
|
||||||
|
///
|
||||||
|
/// The valid options are [Input], [Output] and [Alternate].
|
||||||
|
pub trait PinMode: Sealed {
|
||||||
|
/// Corresponding [DynPinMode]
|
||||||
|
const DYN: DynPinMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: InputConfig> PinMode for Input<C> {
|
||||||
|
const DYN: DynPinMode = DynPinMode::Input(C::DYN);
|
||||||
|
}
|
||||||
|
impl<C: OutputConfig> PinMode for Output<C> {
|
||||||
|
const DYN: DynPinMode = DynPinMode::Output(C::DYN);
|
||||||
|
}
|
||||||
|
impl<C: AlternateConfig> PinMode for Alternate<C> {
|
||||||
|
const DYN: DynPinMode = DynPinMode::Alternate(C::DYN);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Pin IDs
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Type-level enum for pin IDs
|
||||||
|
pub trait PinId: Sealed {
|
||||||
|
/// Corresponding [DynPinId]
|
||||||
|
const DYN: DynPinId;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pin_id {
|
||||||
|
($Group:ident, $Id:ident, $NUM:literal) => {
|
||||||
|
// Need paste macro to use ident in doc attribute
|
||||||
|
paste::paste! {
|
||||||
|
#[doc = "Pin ID representing pin " $Id]
|
||||||
|
pub enum $Id {}
|
||||||
|
impl Sealed for $Id {}
|
||||||
|
impl PinId for $Id {
|
||||||
|
const DYN: DynPinId = DynPinId {
|
||||||
|
group: DynGroup::$Group,
|
||||||
|
num: $NUM,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Pin
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// A type-level GPIO pin, parameterized by [`PinId`] and [`PinMode`] types
|
||||||
|
|
||||||
|
pub struct Pin<I: PinId, M: PinMode> {
|
||||||
|
pub(in crate::gpio) regs: Registers<I>,
|
||||||
|
mode: PhantomData<M>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: PinId, M: PinMode> Pin<I, M> {
|
||||||
|
/// Create a new [`Pin`]
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Each [`Pin`] must be a singleton. For a given [`PinId`], there must be
|
||||||
|
/// at most one corresponding [`Pin`] in existence at any given time.
|
||||||
|
/// Violating this requirement is `unsafe`.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) unsafe fn new() -> Pin<I, M> {
|
||||||
|
Pin {
|
||||||
|
regs: Registers::new(),
|
||||||
|
mode: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the pin to the requested [`PinMode`]
|
||||||
|
#[inline]
|
||||||
|
pub fn into_mode<N: PinMode>(mut self) -> Pin<I, N> {
|
||||||
|
// Only modify registers if we are actually changing pin mode
|
||||||
|
// This check should compile away
|
||||||
|
if N::DYN != M::DYN {
|
||||||
|
self.regs.change_mode::<N>();
|
||||||
|
}
|
||||||
|
// Safe because we drop the existing Pin
|
||||||
|
unsafe { Pin::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin for function select 1. See Programmer Guide p.40 for the function table
|
||||||
|
#[inline]
|
||||||
|
pub fn into_funsel_1(self) -> Pin<I, AltFunc1> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin for function select 2. See Programmer Guide p.40 for the function table
|
||||||
|
#[inline]
|
||||||
|
pub fn into_funsel_2(self) -> Pin<I, AltFunc2> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin for function select 3. See Programmer Guide p.40 for the function table
|
||||||
|
#[inline]
|
||||||
|
pub fn into_funsel_3(self) -> Pin<I, AltFunc3> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a floating input
|
||||||
|
#[inline]
|
||||||
|
pub fn into_floating_input(self) -> Pin<I, InputFloating> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a pulled down input
|
||||||
|
#[inline]
|
||||||
|
pub fn into_pull_down_input(self) -> Pin<I, InputPullDown> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a pulled up input
|
||||||
|
#[inline]
|
||||||
|
pub fn into_pull_up_input(self) -> Pin<I, InputPullUp> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a push-pull output
|
||||||
|
#[inline]
|
||||||
|
pub fn into_push_pull_output(self) -> Pin<I, PushPullOutput> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a readable push-pull output
|
||||||
|
#[inline]
|
||||||
|
pub fn into_readable_push_pull_output(self) -> Pin<I, OutputReadablePushPull> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the pin to operate as a readable open-drain output
|
||||||
|
#[inline]
|
||||||
|
pub fn into_readable_open_drain_output(self) -> Pin<I, OutputReadableOpenDrain> {
|
||||||
|
self.into_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
common_reg_if_functions!();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn _set_high(&mut self) {
|
||||||
|
self.regs.write_pin(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn _set_low(&mut self) {
|
||||||
|
self.regs.write_pin(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn _is_low(&self) -> bool {
|
||||||
|
!self.regs.read_pin()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn _is_high(&self) -> bool {
|
||||||
|
self.regs.read_pin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// AnyPin
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/// Type class for [`Pin`] types
|
||||||
|
///
|
||||||
|
/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
|
||||||
|
/// [`Pin`] types. See the `AnyKind` documentation for more details on the
|
||||||
|
/// pattern.
|
||||||
|
///
|
||||||
|
/// ## `v1` Compatibility
|
||||||
|
///
|
||||||
|
/// Normally, this trait would use `Is<Type = SpecificPin<Self>>` as a super
|
||||||
|
/// trait. But doing so would restrict implementations to only the `v2` `Pin`
|
||||||
|
/// type in this module. To aid in backwards compatibility, we want to implement
|
||||||
|
/// `AnyPin` for the `v1` `Pin` type as well. This is possible for a few
|
||||||
|
/// reasons. First, both structs are zero-sized, so there is no meaningful
|
||||||
|
/// memory layout to begin with. And even if there were, the `v1` `Pin` type is
|
||||||
|
/// a newtype wrapper around a `v2` `Pin`, and single-field structs are
|
||||||
|
/// guaranteed to have the same layout as the field, even for `repr(Rust)`.
|
||||||
|
///
|
||||||
|
/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
|
||||||
|
/// [type class]: crate::typelevel#type-classes
|
||||||
|
pub trait AnyPin
|
||||||
|
where
|
||||||
|
Self: Sealed,
|
||||||
|
Self: From<SpecificPin<Self>>,
|
||||||
|
Self: Into<SpecificPin<Self>>,
|
||||||
|
Self: AsRef<SpecificPin<Self>>,
|
||||||
|
Self: AsMut<SpecificPin<Self>>,
|
||||||
|
{
|
||||||
|
/// [`PinId`] of the corresponding [`Pin`]
|
||||||
|
type Id: PinId;
|
||||||
|
/// [`PinMode`] of the corresponding [`Pin`]
|
||||||
|
type Mode: PinMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, M> Sealed for Pin<I, M>
|
||||||
|
where
|
||||||
|
I: PinId,
|
||||||
|
M: PinMode,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, M> AnyPin for Pin<I, M>
|
||||||
|
where
|
||||||
|
I: PinId,
|
||||||
|
M: PinMode,
|
||||||
|
{
|
||||||
|
type Id = I;
|
||||||
|
type Mode = M;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type alias to recover the specific [`Pin`] type from an implementation of
|
||||||
|
/// [`AnyPin`]
|
||||||
|
///
|
||||||
|
/// See the [`AnyKind`] documentation for more details on the pattern.
|
||||||
|
///
|
||||||
|
/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
|
||||||
|
pub type SpecificPin<P> = Pin<<P as AnyPin>::Id, <P as AnyPin>::Mode>;
|
||||||
|
|
||||||
|
impl<P: AnyPin> AsRef<P> for SpecificPin<P> {
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &P {
|
||||||
|
// SAFETY: This is guaranteed to be safe, because P == SpecificPin<P>
|
||||||
|
// Transmuting between `v1` and `v2` `Pin` types is also safe, because
|
||||||
|
// both are zero-sized, and single-field, newtype structs are guaranteed
|
||||||
|
// to have the same layout as the field anyway, even for repr(Rust).
|
||||||
|
unsafe { transmute(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: AnyPin> AsMut<P> for SpecificPin<P> {
|
||||||
|
#[inline]
|
||||||
|
fn as_mut(&mut self) -> &mut P {
|
||||||
|
// SAFETY: This is guaranteed to be safe, because P == SpecificPin<P>
|
||||||
|
// Transmuting between `v1` and `v2` `Pin` types is also safe, because
|
||||||
|
// both are zero-sized, and single-field, newtype structs are guaranteed
|
||||||
|
// to have the same layout as the field anyway, even for repr(Rust).
|
||||||
|
unsafe { transmute(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Additional functionality
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
||||||
|
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Self {
|
||||||
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
self.irq_enb();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Self {
|
||||||
|
self.regs.interrupt_level(level_type);
|
||||||
|
self.irq_enb();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
||||||
|
/// See p.53 of the programmers guide for more information.
|
||||||
|
/// Possible delays in clock cycles:
|
||||||
|
/// - Delay 1: 1
|
||||||
|
/// - Delay 2: 2
|
||||||
|
/// - Delay 1 + Delay 2: 3
|
||||||
|
#[inline]
|
||||||
|
pub fn delay(self, delay_1: bool, delay_2: bool) -> Self {
|
||||||
|
self.regs.delay(delay_1, delay_2);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See p.52 of the programmers guide for more information.
|
||||||
|
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
||||||
|
/// one clock cycle before returning to the configured default state
|
||||||
|
pub fn pulse_mode(self, enable: bool, default_state: PinState) -> Self {
|
||||||
|
self.regs.pulse_mode(enable, default_state);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_edge(mut self, edge_type: InterruptEdge) -> Self {
|
||||||
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
self.irq_enb();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_level(mut self, level_type: InterruptLevel) -> Self {
|
||||||
|
self.regs.interrupt_level(level_type);
|
||||||
|
self.irq_enb();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
||||||
|
/// See p.37 and p.38 of the programmers guide for more information.
|
||||||
|
#[inline]
|
||||||
|
pub fn filter_type(self, filter: FilterType, clksel: FilterClkSel) -> Self {
|
||||||
|
self.regs.filter_type(filter, clksel);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Embedded HAL traits
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
impl<I, M> ErrorType for Pin<I, M>
|
||||||
|
where
|
||||||
|
I: PinId,
|
||||||
|
M: PinMode,
|
||||||
|
{
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: PinId, C: OutputConfig> OutputPin for Pin<I, Output<C>> {
|
||||||
|
#[inline]
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self._set_high();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self._set_low();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, C> InputPin for Pin<I, Input<C>>
|
||||||
|
where
|
||||||
|
I: PinId,
|
||||||
|
C: InputConfig,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self._is_high())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_low(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self._is_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, C> StatefulOutputPin for Pin<I, Output<C>>
|
||||||
|
where
|
||||||
|
I: PinId,
|
||||||
|
C: OutputConfig + ReadableOutput,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self._is_high())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self._is_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, C> InputPin for Pin<I, Output<C>>
|
||||||
|
where
|
||||||
|
I: PinId,
|
||||||
|
C: OutputConfig + ReadableOutput,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self._is_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_low(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self._is_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Registers
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Provide a safe register interface for [`Pin`]s
|
||||||
|
///
|
||||||
|
/// This `struct` takes ownership of a [`PinId`] and provides an API to
|
||||||
|
/// access the corresponding registers.
|
||||||
|
pub(in crate::gpio) struct Registers<I: PinId> {
|
||||||
|
id: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// [`Registers`] takes ownership of the [`PinId`], and [`Pin`] guarantees that
|
||||||
|
// each pin is a singleton, so this implementation is safe.
|
||||||
|
unsafe impl<I: PinId> RegisterInterface for Registers<I> {
|
||||||
|
#[inline]
|
||||||
|
fn id(&self) -> DynPinId {
|
||||||
|
I::DYN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: PinId> Registers<I> {
|
||||||
|
/// Create a new instance of [`Registers`]
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Users must never create two simultaneous instances of this `struct` with
|
||||||
|
/// the same [`PinId`]
|
||||||
|
#[inline]
|
||||||
|
unsafe fn new() -> Self {
|
||||||
|
Registers { id: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provide a type-level equivalent for the
|
||||||
|
/// [`RegisterInterface::change_mode`] method.
|
||||||
|
#[inline]
|
||||||
|
pub(in crate::gpio) fn change_mode<M: PinMode>(&mut self) {
|
||||||
|
RegisterInterface::change_mode(self, M::DYN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Pin definitions
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
macro_rules! pins {
|
||||||
|
(
|
||||||
|
$Port:ident, $PinsName:ident, $($Id:ident,)+,
|
||||||
|
) => {
|
||||||
|
paste::paste!(
|
||||||
|
/// Collection of all the individual [`Pin`]s for a given port (PORTA or PORTB)
|
||||||
|
pub struct $PinsName {
|
||||||
|
port: $Port,
|
||||||
|
$(
|
||||||
|
#[doc = "Pin " $Id]
|
||||||
|
pub [<$Id:lower>]: Pin<$Id, Reset>,
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $PinsName {
|
||||||
|
/// Create a new struct containing all the Pins. Passing the IOCONFIG peripheral
|
||||||
|
/// is optional because it might be required to create pin definitions for both
|
||||||
|
/// ports.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(
|
||||||
|
syscfg: &mut va416xx::Sysconfig,
|
||||||
|
port: $Port
|
||||||
|
) -> $PinsName {
|
||||||
|
syscfg.peripheral_clk_enable().modify(|_, w| {
|
||||||
|
w.[<$Port:lower>]().set_bit();
|
||||||
|
w.ioconfig().set_bit()
|
||||||
|
});
|
||||||
|
$PinsName {
|
||||||
|
port,
|
||||||
|
// Safe because we only create one `Pin` per `PinId`
|
||||||
|
$(
|
||||||
|
[<$Id:lower>]: unsafe { Pin::new() },
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the peripheral ID
|
||||||
|
/// Safety: Read-only register
|
||||||
|
pub fn get_perid() -> u32 {
|
||||||
|
let port = unsafe { &(*$Port::ptr()) };
|
||||||
|
port.perid().read().bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes the Pins struct and returns the port definitions
|
||||||
|
pub fn release(self) -> $Port {
|
||||||
|
self.port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! declare_pins {
|
||||||
|
(
|
||||||
|
$Group:ident, $PinsName:ident, $Port:ident, [$(($Id:ident, $NUM:literal),)+]
|
||||||
|
) => {
|
||||||
|
pins!($Port, $PinsName, $($Id,)+,);
|
||||||
|
$(
|
||||||
|
pin_id!($Group, $Id, $NUM);
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_pins!(
|
||||||
|
A,
|
||||||
|
PinsA,
|
||||||
|
Porta,
|
||||||
|
[
|
||||||
|
(PA0, 0),
|
||||||
|
(PA1, 1),
|
||||||
|
(PA2, 2),
|
||||||
|
(PA3, 3),
|
||||||
|
(PA4, 4),
|
||||||
|
(PA5, 5),
|
||||||
|
(PA6, 6),
|
||||||
|
(PA7, 7),
|
||||||
|
(PA8, 8),
|
||||||
|
(PA9, 9),
|
||||||
|
(PA10, 10),
|
||||||
|
(PA11, 11),
|
||||||
|
(PA12, 12),
|
||||||
|
(PA13, 13),
|
||||||
|
(PA14, 14),
|
||||||
|
(PA15, 15),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_pins!(
|
||||||
|
B,
|
||||||
|
PinsB,
|
||||||
|
Portb,
|
||||||
|
[
|
||||||
|
(PB0, 0),
|
||||||
|
(PB1, 1),
|
||||||
|
(PB2, 2),
|
||||||
|
(PB3, 3),
|
||||||
|
(PB4, 4),
|
||||||
|
(PB5, 5),
|
||||||
|
(PB6, 6),
|
||||||
|
(PB7, 7),
|
||||||
|
(PB8, 8),
|
||||||
|
(PB9, 9),
|
||||||
|
(PB10, 10),
|
||||||
|
(PB11, 11),
|
||||||
|
(PB12, 12),
|
||||||
|
(PB13, 13),
|
||||||
|
(PB14, 14),
|
||||||
|
(PB15, 15),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_pins!(
|
||||||
|
C,
|
||||||
|
PinsC,
|
||||||
|
Portc,
|
||||||
|
[
|
||||||
|
(PC0, 0),
|
||||||
|
(PC1, 1),
|
||||||
|
(PC2, 2),
|
||||||
|
(PC3, 3),
|
||||||
|
(PC4, 4),
|
||||||
|
(PC5, 5),
|
||||||
|
(PC6, 6),
|
||||||
|
(PC7, 7),
|
||||||
|
(PC8, 8),
|
||||||
|
(PC9, 9),
|
||||||
|
(PC10, 10),
|
||||||
|
(PC11, 11),
|
||||||
|
(PC12, 12),
|
||||||
|
(PC13, 13),
|
||||||
|
(PC14, 14),
|
||||||
|
(PC15, 15),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_pins!(
|
||||||
|
D,
|
||||||
|
PinsD,
|
||||||
|
Portd,
|
||||||
|
[
|
||||||
|
(PD0, 0),
|
||||||
|
(PD1, 1),
|
||||||
|
(PD2, 2),
|
||||||
|
(PD3, 3),
|
||||||
|
(PD4, 4),
|
||||||
|
(PD5, 5),
|
||||||
|
(PD6, 6),
|
||||||
|
(PD7, 7),
|
||||||
|
(PD8, 8),
|
||||||
|
(PD9, 9),
|
||||||
|
(PD10, 10),
|
||||||
|
(PD11, 11),
|
||||||
|
(PD12, 12),
|
||||||
|
(PD13, 13),
|
||||||
|
(PD14, 14),
|
||||||
|
(PD15, 15),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_pins!(
|
||||||
|
E,
|
||||||
|
PinsE,
|
||||||
|
Porte,
|
||||||
|
[
|
||||||
|
(PE0, 0),
|
||||||
|
(PE1, 1),
|
||||||
|
(PE2, 2),
|
||||||
|
(PE3, 3),
|
||||||
|
(PE4, 4),
|
||||||
|
(PE5, 5),
|
||||||
|
(PE6, 6),
|
||||||
|
(PE7, 7),
|
||||||
|
(PE8, 8),
|
||||||
|
(PE9, 9),
|
||||||
|
(PE10, 10),
|
||||||
|
(PE11, 11),
|
||||||
|
(PE12, 12),
|
||||||
|
(PE13, 13),
|
||||||
|
(PE14, 14),
|
||||||
|
(PE15, 15),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_pins!(
|
||||||
|
F,
|
||||||
|
PinsF,
|
||||||
|
Portf,
|
||||||
|
[
|
||||||
|
(PF0, 0),
|
||||||
|
(PF1, 1),
|
||||||
|
(PF2, 2),
|
||||||
|
(PF3, 3),
|
||||||
|
(PF4, 4),
|
||||||
|
(PF5, 5),
|
||||||
|
(PF6, 6),
|
||||||
|
(PF7, 7),
|
||||||
|
(PF8, 8),
|
||||||
|
(PF9, 9),
|
||||||
|
(PF10, 10),
|
||||||
|
(PF11, 11),
|
||||||
|
(PF12, 12),
|
||||||
|
(PF13, 13),
|
||||||
|
(PF14, 14),
|
||||||
|
(PF15, 15),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
declare_pins!(
|
||||||
|
G,
|
||||||
|
PinsG,
|
||||||
|
Portg,
|
||||||
|
[
|
||||||
|
(PG0, 0),
|
||||||
|
(PG1, 1),
|
||||||
|
(PG2, 2),
|
||||||
|
(PG3, 3),
|
||||||
|
(PG4, 4),
|
||||||
|
(PG5, 5),
|
||||||
|
(PG6, 6),
|
||||||
|
(PG7, 7),
|
||||||
|
]
|
||||||
|
);
|
387
va416xx-hal/src/gpio/reg.rs
Normal file
387
va416xx-hal/src/gpio/reg.rs
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
use crate::FunSel;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
dynpin::{self, DynGroup, DynPinId},
|
||||||
|
DynPinMode, FilterClkSel, FilterType, InterruptEdge, InterruptLevel, IsMaskedError, PinState,
|
||||||
|
};
|
||||||
|
use va416xx::{ioconfig, porta, Ioconfig, Porta, Portb, Portc, Portd, Porte, Portf, Portg};
|
||||||
|
|
||||||
|
/// Type definition to avoid confusion: These register blocks are identical
|
||||||
|
type PortRegisterBlock = porta::RegisterBlock;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// ModeFields
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Collect all fields needed to set the [`PinMode`](super::PinMode)
|
||||||
|
#[derive(Default)]
|
||||||
|
struct ModeFields {
|
||||||
|
dir: bool,
|
||||||
|
opendrn: bool,
|
||||||
|
pull_en: bool,
|
||||||
|
/// true for pullup, false for pulldown
|
||||||
|
pull_dir: bool,
|
||||||
|
funsel: u8,
|
||||||
|
enb_input: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DynPinMode> for ModeFields {
|
||||||
|
#[inline]
|
||||||
|
fn from(mode: DynPinMode) -> Self {
|
||||||
|
let mut fields = Self::default();
|
||||||
|
use DynPinMode::*;
|
||||||
|
match mode {
|
||||||
|
Input(config) => {
|
||||||
|
use dynpin::DynInput::*;
|
||||||
|
fields.dir = false;
|
||||||
|
fields.funsel = FunSel::Sel0 as u8;
|
||||||
|
match config {
|
||||||
|
Floating => (),
|
||||||
|
PullUp => {
|
||||||
|
fields.pull_en = true;
|
||||||
|
fields.pull_dir = true;
|
||||||
|
}
|
||||||
|
PullDown => {
|
||||||
|
fields.pull_en = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Output(config) => {
|
||||||
|
use dynpin::DynOutput::*;
|
||||||
|
fields.dir = true;
|
||||||
|
fields.funsel = FunSel::Sel0 as u8;
|
||||||
|
match config {
|
||||||
|
PushPull => (),
|
||||||
|
OpenDrain => {
|
||||||
|
fields.opendrn = true;
|
||||||
|
}
|
||||||
|
ReadableOpenDrain => {
|
||||||
|
fields.enb_input = true;
|
||||||
|
fields.opendrn = true;
|
||||||
|
}
|
||||||
|
ReadablePushPull => {
|
||||||
|
fields.enb_input = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Alternate(config) => {
|
||||||
|
fields.funsel = config as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// RegisterInterface
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
pub type PortReg = ioconfig::Porta;
|
||||||
|
|
||||||
|
/// Provide a safe register interface for pin objects
|
||||||
|
///
|
||||||
|
/// [`PORT`], like every PAC `struct`, is [`Send`] but not [`Sync`], because it
|
||||||
|
/// points to a `RegisterBlock` of `VolatileCell`s. Unfortunately, such an
|
||||||
|
/// interface is quite restrictive. Instead, it would be ideal if we could split
|
||||||
|
/// the [`PORT`] into independent pins that are both [`Send`] and [`Sync`].
|
||||||
|
///
|
||||||
|
/// [`PORT`] is a single, zero-sized marker `struct` that provides access to
|
||||||
|
/// every [`PORT`] register. Instead, we would like to create zero-sized marker
|
||||||
|
/// `struct`s for every pin, where each pin is only allowed to control its own
|
||||||
|
/// registers. Furthermore, each pin `struct` should be a singleton, so that
|
||||||
|
/// exclusive access to the `struct` also guarantees exclusive access to the
|
||||||
|
/// corresponding registers. Finally, the pin `struct`s should not have any
|
||||||
|
/// interior mutability. Together, these requirements would allow the pin
|
||||||
|
/// `struct`s to be both [`Send`] and [`Sync`].
|
||||||
|
///
|
||||||
|
/// This trait creates a safe API for accomplishing these goals. Implementers
|
||||||
|
/// supply a pin ID through the [`id`] function. The remaining functions provide
|
||||||
|
/// a safe API for accessing the registers associated with that pin ID. Any
|
||||||
|
/// modification of the registers requires `&mut self`, which destroys interior
|
||||||
|
/// mutability.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Users should only implement the [`id`] function. No default function
|
||||||
|
/// implementations should be overridden. The implementing type must also have
|
||||||
|
/// "control" over the corresponding pin ID, i.e. it must guarantee that a each
|
||||||
|
/// pin ID is a singleton.
|
||||||
|
///
|
||||||
|
/// [`id`]: Self::id
|
||||||
|
pub(super) unsafe trait RegisterInterface {
|
||||||
|
/// Provide a [`DynPinId`] identifying the set of registers controlled by
|
||||||
|
/// this type.
|
||||||
|
fn id(&self) -> DynPinId;
|
||||||
|
|
||||||
|
const PORTA: *const PortRegisterBlock = Porta::ptr();
|
||||||
|
const PORTB: *const PortRegisterBlock = Portb::ptr();
|
||||||
|
const PORTC: *const PortRegisterBlock = Portc::ptr();
|
||||||
|
const PORTD: *const PortRegisterBlock = Portd::ptr();
|
||||||
|
const PORTE: *const PortRegisterBlock = Porte::ptr();
|
||||||
|
const PORTF: *const PortRegisterBlock = Portf::ptr();
|
||||||
|
const PORTG: *const PortRegisterBlock = Portg::ptr();
|
||||||
|
|
||||||
|
/// Change the pin mode
|
||||||
|
#[inline]
|
||||||
|
fn change_mode(&mut self, mode: DynPinMode) {
|
||||||
|
let ModeFields {
|
||||||
|
dir,
|
||||||
|
funsel,
|
||||||
|
opendrn,
|
||||||
|
pull_dir,
|
||||||
|
pull_en,
|
||||||
|
enb_input,
|
||||||
|
} = mode.into();
|
||||||
|
let (portreg, iocfg) = (self.port_reg(), self.iocfg_port());
|
||||||
|
iocfg.write(|w| {
|
||||||
|
w.opendrn().bit(opendrn);
|
||||||
|
w.pen().bit(pull_en);
|
||||||
|
w.plevel().bit(pull_dir);
|
||||||
|
w.iewo().bit(enb_input);
|
||||||
|
unsafe { w.funsel().bits(funsel) }
|
||||||
|
});
|
||||||
|
let mask = self.mask_32();
|
||||||
|
unsafe {
|
||||||
|
if dir {
|
||||||
|
portreg.dir().modify(|r, w| w.bits(r.bits() | mask));
|
||||||
|
// Clear output
|
||||||
|
portreg.clrout().write(|w| w.bits(mask));
|
||||||
|
} else {
|
||||||
|
portreg.dir().modify(|r, w| w.bits(r.bits() & !mask));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn port_reg(&self) -> &PortRegisterBlock {
|
||||||
|
match self.id().group {
|
||||||
|
DynGroup::A => unsafe { &(*Self::PORTA) },
|
||||||
|
DynGroup::B => unsafe { &(*Self::PORTB) },
|
||||||
|
DynGroup::C => unsafe { &(*Self::PORTC) },
|
||||||
|
DynGroup::D => unsafe { &(*Self::PORTD) },
|
||||||
|
DynGroup::E => unsafe { &(*Self::PORTE) },
|
||||||
|
DynGroup::F => unsafe { &(*Self::PORTF) },
|
||||||
|
DynGroup::G => unsafe { &(*Self::PORTG) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iocfg_port(&self) -> &PortReg {
|
||||||
|
let ioconfig = unsafe { Ioconfig::ptr().as_ref().unwrap() };
|
||||||
|
match self.id().group {
|
||||||
|
DynGroup::A => ioconfig.porta(self.id().num as usize),
|
||||||
|
DynGroup::B => ioconfig.portb0(self.id().num as usize),
|
||||||
|
DynGroup::C => ioconfig.portc0(self.id().num as usize),
|
||||||
|
DynGroup::D => ioconfig.portd0(self.id().num as usize),
|
||||||
|
DynGroup::E => ioconfig.porte0(self.id().num as usize),
|
||||||
|
DynGroup::F => ioconfig.portf0(self.id().num as usize),
|
||||||
|
DynGroup::G => ioconfig.portg0(self.id().num as usize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mask_32(&self) -> u32 {
|
||||||
|
1 << self.id().num
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn enable_irq(&self) {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_enb()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | self.mask_32()) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Read the logic level of an output pin
|
||||||
|
fn read_pin(&self) -> bool {
|
||||||
|
let portreg = self.port_reg();
|
||||||
|
((portreg.datainraw().read().bits() >> self.id().num) & 0x01) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get DATAMASK bit for this particular pin
|
||||||
|
#[inline(always)]
|
||||||
|
fn datamask(&self) -> bool {
|
||||||
|
let portreg = self.port_reg();
|
||||||
|
(portreg.datamask().read().bits() >> self.id().num) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a pin but use the masked version but check whether the datamask for the pin is
|
||||||
|
/// cleared as well
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_pin_masked(&self) -> Result<bool, IsMaskedError> {
|
||||||
|
if !self.datamask() {
|
||||||
|
Err(IsMaskedError)
|
||||||
|
} else {
|
||||||
|
Ok(((self.port_reg().datain().read().bits() >> self.id().num) & 0x01) == 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the logic level of an output pin
|
||||||
|
#[inline(always)]
|
||||||
|
fn write_pin(&mut self, bit: bool) {
|
||||||
|
// Safety: SETOUT is a "mask" register, and we only write the bit for
|
||||||
|
// this pin ID
|
||||||
|
unsafe {
|
||||||
|
if bit {
|
||||||
|
self.port_reg().setout().write(|w| w.bits(self.mask_32()));
|
||||||
|
} else {
|
||||||
|
self.port_reg().clrout().write(|w| w.bits(self.mask_32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the logic level of an output pin but check whether the datamask for the pin is
|
||||||
|
/// cleared as well
|
||||||
|
#[inline]
|
||||||
|
fn write_pin_masked(&mut self, bit: bool) -> Result<(), IsMaskedError> {
|
||||||
|
if !self.datamask() {
|
||||||
|
Err(IsMaskedError)
|
||||||
|
} else {
|
||||||
|
// Safety: SETOUT is a "mask" register, and we only write the bit for
|
||||||
|
// this pin ID
|
||||||
|
unsafe {
|
||||||
|
if bit {
|
||||||
|
self.port_reg().setout().write(|w| w.bits(self.mask_32()));
|
||||||
|
} else {
|
||||||
|
self.port_reg().clrout().write(|w| w.bits(self.mask_32()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure
|
||||||
|
/// When using edge mode, it is possible to generate interrupts on both edges as well
|
||||||
|
#[inline]
|
||||||
|
fn interrupt_edge(&mut self, edge_type: InterruptEdge) {
|
||||||
|
unsafe {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_sen()
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
match edge_type {
|
||||||
|
InterruptEdge::HighToLow => {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_evt()
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
}
|
||||||
|
InterruptEdge::LowToHigh => {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_evt()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
}
|
||||||
|
InterruptEdge::BothEdges => {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_edge()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure which edge or level type triggers an interrupt
|
||||||
|
#[inline]
|
||||||
|
fn interrupt_level(&mut self, level: InterruptLevel) {
|
||||||
|
unsafe {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_sen()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
if level == InterruptLevel::Low {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_evt()
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
} else {
|
||||||
|
self.port_reg()
|
||||||
|
.irq_evt()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only useful for input pins
|
||||||
|
#[inline]
|
||||||
|
fn filter_type(&self, filter: FilterType, clksel: FilterClkSel) {
|
||||||
|
self.iocfg_port().modify(|_, w| {
|
||||||
|
// Safety: Only write to register for this Pin ID
|
||||||
|
unsafe {
|
||||||
|
w.flttype().bits(filter as u8);
|
||||||
|
w.fltclk().bits(clksel as u8)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set DATAMASK bit for this particular pin. 1 is the default
|
||||||
|
/// state of the bit and allows access of the corresponding bit
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_datamask(&self) {
|
||||||
|
let portreg = self.port_reg();
|
||||||
|
unsafe {
|
||||||
|
portreg
|
||||||
|
.datamask()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear DATAMASK bit for this particular pin. This prevents access
|
||||||
|
/// of the corresponding bit for output and input operations
|
||||||
|
#[inline(always)]
|
||||||
|
fn clear_datamask(&self) {
|
||||||
|
let portreg = self.port_reg();
|
||||||
|
unsafe {
|
||||||
|
portreg
|
||||||
|
.datamask()
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only useful for output pins
|
||||||
|
/// See p.52 of the programmers guide for more information.
|
||||||
|
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
||||||
|
/// one clock cycle before returning to the configured default state
|
||||||
|
fn pulse_mode(&self, enable: bool, default_state: PinState) {
|
||||||
|
let portreg = self.port_reg();
|
||||||
|
unsafe {
|
||||||
|
if enable {
|
||||||
|
portreg
|
||||||
|
.pulse()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
} else {
|
||||||
|
portreg
|
||||||
|
.pulse()
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
}
|
||||||
|
if default_state == PinState::Low {
|
||||||
|
portreg
|
||||||
|
.pulsebase()
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
} else {
|
||||||
|
portreg
|
||||||
|
.pulsebase()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only useful for output pins
|
||||||
|
fn delay(&self, delay_1: bool, delay_2: bool) {
|
||||||
|
let portreg = self.port_reg();
|
||||||
|
unsafe {
|
||||||
|
if delay_1 {
|
||||||
|
portreg
|
||||||
|
.delay1()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
} else {
|
||||||
|
portreg
|
||||||
|
.delay1()
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
}
|
||||||
|
if delay_2 {
|
||||||
|
portreg
|
||||||
|
.delay2()
|
||||||
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
|
} else {
|
||||||
|
portreg
|
||||||
|
.delay2()
|
||||||
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
904
va416xx-hal/src/i2c.rs
Normal file
904
va416xx-hal/src/i2c.rs
Normal file
@ -0,0 +1,904 @@
|
|||||||
|
//! API for the I2C peripheral
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! - [PEB1 accelerometer example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/peb1-accelerometer.rs)
|
||||||
|
use crate::{
|
||||||
|
clock::{
|
||||||
|
assert_periph_reset, deassert_periph_reset, enable_peripheral_clock, Clocks,
|
||||||
|
PeripheralSelect,
|
||||||
|
},
|
||||||
|
pac,
|
||||||
|
time::Hertz,
|
||||||
|
typelevel::Sealed,
|
||||||
|
};
|
||||||
|
use core::{marker::PhantomData, ops::Deref};
|
||||||
|
use embedded_hal::i2c::{self, Operation, SevenBitAddress, TenBitAddress};
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Defintions
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
const CLK_100K: Hertz = Hertz::from_raw(100_000);
|
||||||
|
const CLK_400K: Hertz = Hertz::from_raw(400_000);
|
||||||
|
const MIN_CLK_400K: Hertz = Hertz::from_raw(10_000_000);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum FifoEmptyMode {
|
||||||
|
Stall = 0,
|
||||||
|
EndTransaction = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct ClockTooSlowForFastI2c;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Error {
|
||||||
|
InvalidTimingParams,
|
||||||
|
ArbitrationLost,
|
||||||
|
NackAddr,
|
||||||
|
/// Data not acknowledged in write operation
|
||||||
|
NackData,
|
||||||
|
/// Not enough data received in read operation
|
||||||
|
InsufficientDataReceived,
|
||||||
|
/// Number of bytes in transfer too large (larger than 0x7fe)
|
||||||
|
DataTooLarge,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum InitError {
|
||||||
|
/// Wrong address used in constructor
|
||||||
|
WrongAddrMode,
|
||||||
|
/// APB1 clock is too slow for fast I2C mode.
|
||||||
|
ClkTooSlow(ClockTooSlowForFastI2c),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ClockTooSlowForFastI2c> for InitError {
|
||||||
|
fn from(value: ClockTooSlowForFastI2c) -> Self {
|
||||||
|
Self::ClkTooSlow(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_hal::i2c::Error for Error {
|
||||||
|
fn kind(&self) -> embedded_hal::i2c::ErrorKind {
|
||||||
|
match self {
|
||||||
|
Error::ArbitrationLost => embedded_hal::i2c::ErrorKind::ArbitrationLoss,
|
||||||
|
Error::NackAddr => {
|
||||||
|
embedded_hal::i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Address)
|
||||||
|
}
|
||||||
|
Error::NackData => {
|
||||||
|
embedded_hal::i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data)
|
||||||
|
}
|
||||||
|
Error::DataTooLarge | Error::InsufficientDataReceived | Error::InvalidTimingParams => {
|
||||||
|
embedded_hal::i2c::ErrorKind::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
enum I2cCmd {
|
||||||
|
Start = 0b00,
|
||||||
|
Stop = 0b10,
|
||||||
|
StartWithStop = 0b11,
|
||||||
|
Cancel = 0b100,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum I2cSpeed {
|
||||||
|
Regular100khz = 0,
|
||||||
|
Fast400khz = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum I2cDirection {
|
||||||
|
Send = 0,
|
||||||
|
Read = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum I2cAddress {
|
||||||
|
Regular(u8),
|
||||||
|
TenBit(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type I2cRegBlock = pac::i2c0::RegisterBlock;
|
||||||
|
|
||||||
|
/// Common trait implemented by all PAC peripheral access structures. The register block
|
||||||
|
/// format is the same for all SPI blocks.
|
||||||
|
pub trait Instance: Deref<Target = I2cRegBlock> {
|
||||||
|
const IDX: u8;
|
||||||
|
const PERIPH_SEL: PeripheralSelect;
|
||||||
|
|
||||||
|
fn ptr() -> *const I2cRegBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for pac::I2c0 {
|
||||||
|
const IDX: u8 = 0;
|
||||||
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c0;
|
||||||
|
|
||||||
|
fn ptr() -> *const I2cRegBlock {
|
||||||
|
Self::ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for pac::I2c1 {
|
||||||
|
const IDX: u8 = 1;
|
||||||
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c1;
|
||||||
|
|
||||||
|
fn ptr() -> *const I2cRegBlock {
|
||||||
|
Self::ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for pac::I2c2 {
|
||||||
|
const IDX: u8 = 2;
|
||||||
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c2;
|
||||||
|
|
||||||
|
fn ptr() -> *const I2cRegBlock {
|
||||||
|
Self::ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Config
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub struct TrTfThighTlow(u8, u8, u8, u8);
|
||||||
|
pub struct TsuStoTsuStaThdStaTBuf(u8, u8, u8, u8);
|
||||||
|
|
||||||
|
pub struct TimingCfg {
|
||||||
|
// 4 bit max width
|
||||||
|
tr: u8,
|
||||||
|
// 4 bit max width
|
||||||
|
tf: u8,
|
||||||
|
// 4 bit max width
|
||||||
|
thigh: u8,
|
||||||
|
// 4 bit max width
|
||||||
|
tlow: u8,
|
||||||
|
// 4 bit max width
|
||||||
|
tsu_sto: u8,
|
||||||
|
// 4 bit max width
|
||||||
|
tsu_sta: u8,
|
||||||
|
// 4 bit max width
|
||||||
|
thd_sta: u8,
|
||||||
|
// 4 bit max width
|
||||||
|
tbuf: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimingCfg {
|
||||||
|
pub fn new(
|
||||||
|
first_16_bits: TrTfThighTlow,
|
||||||
|
second_16_bits: TsuStoTsuStaThdStaTBuf,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
if first_16_bits.0 > 0xf
|
||||||
|
|| first_16_bits.1 > 0xf
|
||||||
|
|| first_16_bits.2 > 0xf
|
||||||
|
|| first_16_bits.3 > 0xf
|
||||||
|
|| second_16_bits.0 > 0xf
|
||||||
|
|| second_16_bits.1 > 0xf
|
||||||
|
|| second_16_bits.2 > 0xf
|
||||||
|
|| second_16_bits.3 > 0xf
|
||||||
|
{
|
||||||
|
return Err(Error::InvalidTimingParams);
|
||||||
|
}
|
||||||
|
Ok(TimingCfg {
|
||||||
|
tr: first_16_bits.0,
|
||||||
|
tf: first_16_bits.1,
|
||||||
|
thigh: first_16_bits.2,
|
||||||
|
tlow: first_16_bits.3,
|
||||||
|
tsu_sto: second_16_bits.0,
|
||||||
|
tsu_sta: second_16_bits.1,
|
||||||
|
thd_sta: second_16_bits.2,
|
||||||
|
tbuf: second_16_bits.3,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reg(&self) -> u32 {
|
||||||
|
(self.tbuf as u32) << 28
|
||||||
|
| (self.thd_sta as u32) << 24
|
||||||
|
| (self.tsu_sta as u32) << 20
|
||||||
|
| (self.tsu_sto as u32) << 16
|
||||||
|
| (self.tlow as u32) << 12
|
||||||
|
| (self.thigh as u32) << 8
|
||||||
|
| (self.tf as u32) << 4
|
||||||
|
| (self.tr as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TimingCfg {
|
||||||
|
fn default() -> Self {
|
||||||
|
TimingCfg {
|
||||||
|
tr: 0x02,
|
||||||
|
tf: 0x01,
|
||||||
|
thigh: 0x08,
|
||||||
|
tlow: 0x09,
|
||||||
|
tsu_sto: 0x8,
|
||||||
|
tsu_sta: 0x0a,
|
||||||
|
thd_sta: 0x8,
|
||||||
|
tbuf: 0xa,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MasterConfig {
|
||||||
|
pub tx_fe_mode: FifoEmptyMode,
|
||||||
|
pub rx_fe_mode: FifoEmptyMode,
|
||||||
|
/// Enable the analog delay glitch filter
|
||||||
|
pub alg_filt: bool,
|
||||||
|
/// Enable the digital glitch filter
|
||||||
|
pub dlg_filt: bool,
|
||||||
|
pub tm_cfg: Option<TimingCfg>,
|
||||||
|
// Loopback mode
|
||||||
|
// lbm: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MasterConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
MasterConfig {
|
||||||
|
tx_fe_mode: FifoEmptyMode::Stall,
|
||||||
|
rx_fe_mode: FifoEmptyMode::Stall,
|
||||||
|
alg_filt: false,
|
||||||
|
dlg_filt: false,
|
||||||
|
tm_cfg: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sealed for MasterConfig {}
|
||||||
|
|
||||||
|
pub struct SlaveConfig {
|
||||||
|
pub tx_fe_mode: FifoEmptyMode,
|
||||||
|
pub rx_fe_mode: FifoEmptyMode,
|
||||||
|
/// Maximum number of words before issuing a negative acknowledge.
|
||||||
|
/// Range should be 0 to 0x7fe. Setting the value to 0x7ff has the same effect as not setting
|
||||||
|
/// the enable bit since RXCOUNT stops counting at 0x7fe.
|
||||||
|
pub max_words: Option<usize>,
|
||||||
|
/// A received address is compared to the ADDRESS register (addr) using the address mask
|
||||||
|
/// (addr_mask). Those bits with a 1 in the address mask must match for there to be an address
|
||||||
|
/// match
|
||||||
|
pub addr: I2cAddress,
|
||||||
|
/// The default address mask will be 0x3ff to only allow full matches
|
||||||
|
pub addr_mask: Option<u16>,
|
||||||
|
/// Optionally specify a second I2C address the slave interface responds to
|
||||||
|
pub addr_b: Option<I2cAddress>,
|
||||||
|
pub addr_b_mask: Option<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SlaveConfig {
|
||||||
|
/// Build a default slave config given a specified slave address to respond to
|
||||||
|
pub fn new(addr: I2cAddress) -> Self {
|
||||||
|
SlaveConfig {
|
||||||
|
tx_fe_mode: FifoEmptyMode::Stall,
|
||||||
|
rx_fe_mode: FifoEmptyMode::Stall,
|
||||||
|
max_words: None,
|
||||||
|
addr,
|
||||||
|
addr_mask: None,
|
||||||
|
addr_b: None,
|
||||||
|
addr_b_mask: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sealed for SlaveConfig {}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// I2C Base
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub struct I2cBase<I2c> {
|
||||||
|
i2c: I2c,
|
||||||
|
clock: Hertz,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2C> I2cBase<I2C> {
|
||||||
|
#[inline]
|
||||||
|
fn unwrap_addr(addr: I2cAddress) -> (u16, u32) {
|
||||||
|
match addr {
|
||||||
|
I2cAddress::Regular(addr) => (addr as u16, 0 << 15),
|
||||||
|
I2cAddress::TenBit(addr) => (addr, 1 << 15),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2c: Instance> I2cBase<I2c> {
|
||||||
|
pub fn new(
|
||||||
|
i2c: I2c,
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
clocks: &Clocks,
|
||||||
|
speed_mode: I2cSpeed,
|
||||||
|
ms_cfg: Option<&MasterConfig>,
|
||||||
|
sl_cfg: Option<&SlaveConfig>,
|
||||||
|
) -> Result<Self, ClockTooSlowForFastI2c> {
|
||||||
|
enable_peripheral_clock(sys_cfg, I2c::PERIPH_SEL);
|
||||||
|
assert_periph_reset(sys_cfg, I2c::PERIPH_SEL);
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
deassert_periph_reset(sys_cfg, I2c::PERIPH_SEL);
|
||||||
|
|
||||||
|
let mut i2c_base = I2cBase {
|
||||||
|
i2c,
|
||||||
|
clock: clocks.apb1(),
|
||||||
|
};
|
||||||
|
if let Some(ms_cfg) = ms_cfg {
|
||||||
|
i2c_base.cfg_master(ms_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(sl_cfg) = sl_cfg {
|
||||||
|
i2c_base.cfg_slave(sl_cfg);
|
||||||
|
}
|
||||||
|
i2c_base.cfg_clk_scale(speed_mode)?;
|
||||||
|
Ok(i2c_base)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cfg_master(&mut self, ms_cfg: &MasterConfig) {
|
||||||
|
let (txfemd, rxfemd) = match (ms_cfg.tx_fe_mode, ms_cfg.rx_fe_mode) {
|
||||||
|
(FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false),
|
||||||
|
(FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true),
|
||||||
|
(FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false),
|
||||||
|
(FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true),
|
||||||
|
};
|
||||||
|
self.i2c.ctrl().modify(|_, w| {
|
||||||
|
w.txfemd().bit(txfemd);
|
||||||
|
w.rxffmd().bit(rxfemd);
|
||||||
|
w.dlgfilter().bit(ms_cfg.dlg_filt);
|
||||||
|
w.algfilter().bit(ms_cfg.alg_filt)
|
||||||
|
});
|
||||||
|
if let Some(ref tm_cfg) = ms_cfg.tm_cfg {
|
||||||
|
self.i2c
|
||||||
|
.tmconfig()
|
||||||
|
.write(|w| unsafe { w.bits(tm_cfg.reg()) });
|
||||||
|
}
|
||||||
|
self.i2c.fifo_clr().write(|w| {
|
||||||
|
w.rxfifo().set_bit();
|
||||||
|
w.txfifo().set_bit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cfg_slave(&mut self, sl_cfg: &SlaveConfig) {
|
||||||
|
let (txfemd, rxfemd) = match (sl_cfg.tx_fe_mode, sl_cfg.rx_fe_mode) {
|
||||||
|
(FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false),
|
||||||
|
(FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true),
|
||||||
|
(FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false),
|
||||||
|
(FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true),
|
||||||
|
};
|
||||||
|
self.i2c.s0_ctrl().modify(|_, w| {
|
||||||
|
w.txfemd().bit(txfemd);
|
||||||
|
w.rxffmd().bit(rxfemd)
|
||||||
|
});
|
||||||
|
self.i2c.s0_fifo_clr().write(|w| {
|
||||||
|
w.rxfifo().set_bit();
|
||||||
|
w.txfifo().set_bit()
|
||||||
|
});
|
||||||
|
let max_words = sl_cfg.max_words;
|
||||||
|
if let Some(max_words) = max_words {
|
||||||
|
self.i2c
|
||||||
|
.s0_maxwords()
|
||||||
|
.write(|w| unsafe { w.bits(1 << 31 | max_words as u32) });
|
||||||
|
}
|
||||||
|
let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr);
|
||||||
|
// The first bit is the read/write value. Normally, both read and write are matched
|
||||||
|
// using the RWMASK bit of the address mask register
|
||||||
|
self.i2c
|
||||||
|
.s0_address()
|
||||||
|
.write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) });
|
||||||
|
if let Some(addr_mask) = sl_cfg.addr_mask {
|
||||||
|
self.i2c
|
||||||
|
.s0_addressmask()
|
||||||
|
.write(|w| unsafe { w.bits((addr_mask << 1) as u32) });
|
||||||
|
}
|
||||||
|
if let Some(addr_b) = sl_cfg.addr_b {
|
||||||
|
let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b);
|
||||||
|
self.i2c
|
||||||
|
.s0_addressb()
|
||||||
|
.write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) })
|
||||||
|
}
|
||||||
|
if let Some(addr_b_mask) = sl_cfg.addr_b_mask {
|
||||||
|
self.i2c
|
||||||
|
.s0_addressmaskb()
|
||||||
|
.write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn filters(&mut self, digital_filt: bool, analog_filt: bool) {
|
||||||
|
self.i2c.ctrl().modify(|_, w| {
|
||||||
|
w.dlgfilter().bit(digital_filt);
|
||||||
|
w.algfilter().bit(analog_filt)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn fifo_empty_mode(&mut self, rx: FifoEmptyMode, tx: FifoEmptyMode) {
|
||||||
|
self.i2c.ctrl().modify(|_, w| {
|
||||||
|
w.txfemd().bit(tx as u8 != 0);
|
||||||
|
w.rxffmd().bit(rx as u8 != 0)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_clk_div(&self, speed_mode: I2cSpeed) -> Result<u8, ClockTooSlowForFastI2c> {
|
||||||
|
if speed_mode == I2cSpeed::Regular100khz {
|
||||||
|
Ok(((self.clock.raw() / CLK_100K.raw() / 20) - 1) as u8)
|
||||||
|
} else {
|
||||||
|
if self.clock.raw() < MIN_CLK_400K.raw() {
|
||||||
|
return Err(ClockTooSlowForFastI2c);
|
||||||
|
}
|
||||||
|
Ok(((self.clock.raw() / CLK_400K.raw() / 25) - 1) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configures the clock scale for a given speed mode setting
|
||||||
|
pub fn cfg_clk_scale(&mut self, speed_mode: I2cSpeed) -> Result<(), ClockTooSlowForFastI2c> {
|
||||||
|
let clk_div = self.calc_clk_div(speed_mode)?;
|
||||||
|
self.i2c
|
||||||
|
.clkscale()
|
||||||
|
.write(|w| unsafe { w.bits((speed_mode as u32) << 31 | clk_div as u32) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_address(&mut self, addr: u16) {
|
||||||
|
// Load address
|
||||||
|
self.i2c
|
||||||
|
.address()
|
||||||
|
.write(|w| unsafe { w.bits((addr << 1) as u32) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn stop_cmd(&mut self) {
|
||||||
|
self.i2c
|
||||||
|
.cmd()
|
||||||
|
.write(|w| unsafe { w.bits(I2cCmd::Stop as u32) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// I2C Master
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub struct I2cMaster<I2c, Addr = SevenBitAddress> {
|
||||||
|
i2c_base: I2cBase<I2c>,
|
||||||
|
addr: PhantomData<Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
||||||
|
pub fn new(
|
||||||
|
i2c: I2c,
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
cfg: MasterConfig,
|
||||||
|
clocks: &Clocks,
|
||||||
|
speed_mode: I2cSpeed,
|
||||||
|
) -> Result<Self, ClockTooSlowForFastI2c> {
|
||||||
|
Ok(I2cMaster {
|
||||||
|
i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, Some(&cfg), None)?,
|
||||||
|
addr: PhantomData,
|
||||||
|
}
|
||||||
|
.enable_master())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cancel_transfer(&self) {
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.cmd()
|
||||||
|
.write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_tx_fifo(&self) {
|
||||||
|
self.i2c_base.i2c.fifo_clr().write(|w| w.txfifo().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_rx_fifo(&self) {
|
||||||
|
self.i2c_base.i2c.fifo_clr().write(|w| w.rxfifo().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_master(self) -> Self {
|
||||||
|
self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().set_bit());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_master(self) -> Self {
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.ctrl()
|
||||||
|
.modify(|_, w| w.enable().clear_bit());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn load_fifo(&self, word: u8) {
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.data()
|
||||||
|
.write(|w| unsafe { w.bits(word as u32) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_fifo(&self) -> u8 {
|
||||||
|
self.i2c_base.i2c.data().read().bits() as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_handler_write(&mut self, init_cmd: &I2cCmd) {
|
||||||
|
self.clear_tx_fifo();
|
||||||
|
if *init_cmd == I2cCmd::Start {
|
||||||
|
self.i2c_base.stop_cmd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_base(
|
||||||
|
&mut self,
|
||||||
|
addr: I2cAddress,
|
||||||
|
init_cmd: I2cCmd,
|
||||||
|
bytes: impl IntoIterator<Item = u8>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut iter = bytes.into_iter();
|
||||||
|
// Load address
|
||||||
|
let (addr, addr_mode_bit) = I2cBase::<I2c>::unwrap_addr(addr);
|
||||||
|
self.i2c_base.i2c.address().write(|w| unsafe {
|
||||||
|
w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.cmd()
|
||||||
|
.write(|w| unsafe { w.bits(init_cmd as u32) });
|
||||||
|
let mut load_if_next_available = || {
|
||||||
|
if let Some(next_byte) = iter.next() {
|
||||||
|
self.load_fifo(next_byte);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
let status_reader = self.i2c_base.i2c.status().read();
|
||||||
|
if status_reader.arblost().bit_is_set() {
|
||||||
|
self.error_handler_write(&init_cmd);
|
||||||
|
return Err(Error::ArbitrationLost);
|
||||||
|
} else if status_reader.nackaddr().bit_is_set() {
|
||||||
|
self.error_handler_write(&init_cmd);
|
||||||
|
return Err(Error::NackAddr);
|
||||||
|
} else if status_reader.nackdata().bit_is_set() {
|
||||||
|
self.error_handler_write(&init_cmd);
|
||||||
|
return Err(Error::NackData);
|
||||||
|
} else if status_reader.idle().bit_is_set() {
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
while !status_reader.txnfull().bit_is_set() {
|
||||||
|
load_if_next_available();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_from_buffer(
|
||||||
|
&mut self,
|
||||||
|
init_cmd: I2cCmd,
|
||||||
|
addr: I2cAddress,
|
||||||
|
output: &[u8],
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let len = output.len();
|
||||||
|
// It should theoretically possible to transfer larger data sizes by tracking
|
||||||
|
// the number of sent words and setting it to 0x7fe as soon as only that many
|
||||||
|
// bytes are remaining. However, large transfer like this are not common. This
|
||||||
|
// feature will therefore not be supported for now.
|
||||||
|
if len > 0x7fe {
|
||||||
|
return Err(Error::DataTooLarge);
|
||||||
|
}
|
||||||
|
// Load number of words
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.words()
|
||||||
|
.write(|w| unsafe { w.bits(len as u32) });
|
||||||
|
let mut bytes = output.iter();
|
||||||
|
// FIFO has a depth of 16. We load slightly above the trigger level
|
||||||
|
// but not all of it because the transaction might fail immediately
|
||||||
|
const FILL_DEPTH: usize = 12;
|
||||||
|
|
||||||
|
// load the FIFO
|
||||||
|
for _ in 0..core::cmp::min(FILL_DEPTH, len) {
|
||||||
|
self.load_fifo(*bytes.next().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.write_base(addr, init_cmd, output.iter().cloned())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_internal(&mut self, addr: I2cAddress, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
|
let len = buffer.len();
|
||||||
|
// It should theoretically possible to transfer larger data sizes by tracking
|
||||||
|
// the number of sent words and setting it to 0x7fe as soon as only that many
|
||||||
|
// bytes are remaining. However, large transfer like this are not common. This
|
||||||
|
// feature will therefore not be supported for now.
|
||||||
|
if len > 0x7fe {
|
||||||
|
return Err(Error::DataTooLarge);
|
||||||
|
}
|
||||||
|
// Clear the receive FIFO
|
||||||
|
self.clear_rx_fifo();
|
||||||
|
|
||||||
|
// Load number of words
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.words()
|
||||||
|
.write(|w| unsafe { w.bits(len as u32) });
|
||||||
|
let (addr, addr_mode_bit) = match addr {
|
||||||
|
I2cAddress::Regular(addr) => (addr as u16, 0 << 15),
|
||||||
|
I2cAddress::TenBit(addr) => (addr, 1 << 15),
|
||||||
|
};
|
||||||
|
// Load address
|
||||||
|
self.i2c_base.i2c.address().write(|w| unsafe {
|
||||||
|
w.bits(I2cDirection::Read as u32 | (addr << 1) as u32 | addr_mode_bit)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut buf_iter = buffer.iter_mut();
|
||||||
|
let mut read_bytes = 0;
|
||||||
|
// Start receive transfer
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.cmd()
|
||||||
|
.write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) });
|
||||||
|
let mut read_if_next_available = || {
|
||||||
|
if let Some(next_byte) = buf_iter.next() {
|
||||||
|
*next_byte = self.read_fifo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
let status_reader = self.i2c_base.i2c.status().read();
|
||||||
|
if status_reader.arblost().bit_is_set() {
|
||||||
|
self.clear_rx_fifo();
|
||||||
|
return Err(Error::ArbitrationLost);
|
||||||
|
} else if status_reader.nackaddr().bit_is_set() {
|
||||||
|
self.clear_rx_fifo();
|
||||||
|
return Err(Error::NackAddr);
|
||||||
|
} else if status_reader.idle().bit_is_set() {
|
||||||
|
if read_bytes != len {
|
||||||
|
return Err(Error::InsufficientDataReceived);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
} else if status_reader.rxnempty().bit_is_set() {
|
||||||
|
read_if_next_available();
|
||||||
|
read_bytes += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//======================================================================================
|
||||||
|
// Embedded HAL I2C implementations
|
||||||
|
//======================================================================================
|
||||||
|
|
||||||
|
impl<I2c> embedded_hal::i2c::ErrorType for I2cMaster<I2c, SevenBitAddress> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2c: Instance> embedded_hal::i2c::I2c for I2cMaster<I2c, SevenBitAddress> {
|
||||||
|
fn transaction(
|
||||||
|
&mut self,
|
||||||
|
address: SevenBitAddress,
|
||||||
|
operations: &mut [Operation<'_>],
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
for operation in operations {
|
||||||
|
match operation {
|
||||||
|
Operation::Read(buf) => self.read_internal(I2cAddress::Regular(address), buf)?,
|
||||||
|
Operation::Write(buf) => self.write_from_buffer(
|
||||||
|
I2cCmd::StartWithStop,
|
||||||
|
I2cAddress::Regular(address),
|
||||||
|
buf,
|
||||||
|
)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2c> embedded_hal::i2c::ErrorType for I2cMaster<I2c, TenBitAddress> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2c: Instance> embedded_hal::i2c::I2c<TenBitAddress> for I2cMaster<I2c, TenBitAddress> {
|
||||||
|
fn transaction(
|
||||||
|
&mut self,
|
||||||
|
address: TenBitAddress,
|
||||||
|
operations: &mut [Operation<'_>],
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
for operation in operations {
|
||||||
|
match operation {
|
||||||
|
Operation::Read(buf) => self.read_internal(I2cAddress::TenBit(address), buf)?,
|
||||||
|
Operation::Write(buf) => {
|
||||||
|
self.write_from_buffer(I2cCmd::StartWithStop, I2cAddress::TenBit(address), buf)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// I2C Slave
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub struct I2cSlave<I2c, Addr = SevenBitAddress> {
|
||||||
|
i2c_base: I2cBase<I2c>,
|
||||||
|
addr: PhantomData<Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
|
||||||
|
fn new_generic(
|
||||||
|
i2c: I2c,
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
cfg: SlaveConfig,
|
||||||
|
clocks: &Clocks,
|
||||||
|
speed_mode: I2cSpeed,
|
||||||
|
) -> Result<Self, ClockTooSlowForFastI2c> {
|
||||||
|
Ok(I2cSlave {
|
||||||
|
i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, None, Some(&cfg))?,
|
||||||
|
addr: PhantomData,
|
||||||
|
}
|
||||||
|
.enable_slave())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_slave(self) -> Self {
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.s0_ctrl()
|
||||||
|
.modify(|_, w| w.enable().set_bit());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_slave(self) -> Self {
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.s0_ctrl()
|
||||||
|
.modify(|_, w| w.enable().clear_bit());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn load_fifo(&self, word: u8) {
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.s0_data()
|
||||||
|
.write(|w| unsafe { w.bits(word as u32) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_fifo(&self) -> u8 {
|
||||||
|
self.i2c_base.i2c.s0_data().read().bits() as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clear_tx_fifo(&self) {
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.s0_fifo_clr()
|
||||||
|
.write(|w| w.txfifo().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clear_rx_fifo(&self) {
|
||||||
|
self.i2c_base
|
||||||
|
.i2c
|
||||||
|
.s0_fifo_clr()
|
||||||
|
.write(|w| w.rxfifo().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the last address that was matched by the slave control and the corresponding
|
||||||
|
/// master direction
|
||||||
|
pub fn last_address(&self) -> (I2cDirection, u32) {
|
||||||
|
let bits = self.i2c_base.i2c.s0_lastaddress().read().bits();
|
||||||
|
match bits & 0x01 {
|
||||||
|
0 => (I2cDirection::Send, bits >> 1),
|
||||||
|
1 => (I2cDirection::Read, bits >> 1),
|
||||||
|
_ => (I2cDirection::Send, bits >> 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, output: &[u8]) -> Result<(), Error> {
|
||||||
|
let len = output.len();
|
||||||
|
// It should theoretically possible to transfer larger data sizes by tracking
|
||||||
|
// the number of sent words and setting it to 0x7fe as soon as only that many
|
||||||
|
// bytes are remaining. However, large transfer like this are not common. This
|
||||||
|
// feature will therefore not be supported for now.
|
||||||
|
if len > 0x7fe {
|
||||||
|
return Err(Error::DataTooLarge);
|
||||||
|
}
|
||||||
|
let mut bytes = output.iter();
|
||||||
|
// FIFO has a depth of 16. We load slightly above the trigger level
|
||||||
|
// but not all of it because the transaction might fail immediately
|
||||||
|
const FILL_DEPTH: usize = 12;
|
||||||
|
|
||||||
|
// load the FIFO
|
||||||
|
for _ in 0..core::cmp::min(FILL_DEPTH, len) {
|
||||||
|
self.load_fifo(*bytes.next().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let status_reader = self.i2c_base.i2c.s0_status().read();
|
||||||
|
let mut load_if_next_available = || {
|
||||||
|
if let Some(next_byte) = bytes.next() {
|
||||||
|
self.load_fifo(*next_byte);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
if status_reader.nackdata().bit_is_set() {
|
||||||
|
self.clear_tx_fifo();
|
||||||
|
return Err(Error::NackData);
|
||||||
|
} else if status_reader.idle().bit_is_set() {
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
while !status_reader.txnfull().bit_is_set() {
|
||||||
|
load_if_next_available();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
|
let len = buffer.len();
|
||||||
|
// It should theoretically possible to transfer larger data sizes by tracking
|
||||||
|
// the number of sent words and setting it to 0x7fe as soon as only that many
|
||||||
|
// bytes are remaining. However, large transfer like this are not common. This
|
||||||
|
// feature will therefore not be supported for now.
|
||||||
|
if len > 0x7fe {
|
||||||
|
return Err(Error::DataTooLarge);
|
||||||
|
}
|
||||||
|
// Clear the receive FIFO
|
||||||
|
self.clear_rx_fifo();
|
||||||
|
|
||||||
|
let mut buf_iter = buffer.iter_mut();
|
||||||
|
let mut read_bytes = 0;
|
||||||
|
let mut read_if_next_available = || {
|
||||||
|
if let Some(next_byte) = buf_iter.next() {
|
||||||
|
*next_byte = self.read_fifo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
let status_reader = self.i2c_base.i2c.s0_status().read();
|
||||||
|
if status_reader.idle().bit_is_set() {
|
||||||
|
if read_bytes != len {
|
||||||
|
return Err(Error::InsufficientDataReceived);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
} else if status_reader.rxnempty().bit_is_set() {
|
||||||
|
read_bytes += 1;
|
||||||
|
read_if_next_available();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2c: Instance> I2cSlave<I2c, SevenBitAddress> {
|
||||||
|
/// Create a new I2C slave for seven bit addresses
|
||||||
|
pub fn new(
|
||||||
|
i2c: I2c,
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
cfg: SlaveConfig,
|
||||||
|
clocks: &Clocks,
|
||||||
|
speed_mode: I2cSpeed,
|
||||||
|
) -> Result<Self, InitError> {
|
||||||
|
if let I2cAddress::TenBit(_) = cfg.addr {
|
||||||
|
return Err(InitError::WrongAddrMode);
|
||||||
|
}
|
||||||
|
Ok(Self::new_generic(i2c, sys_cfg, cfg, clocks, speed_mode)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2c: Instance> I2cSlave<I2c, TenBitAddress> {
|
||||||
|
pub fn new_ten_bit_addr(
|
||||||
|
i2c: I2c,
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
cfg: SlaveConfig,
|
||||||
|
clocks: &Clocks,
|
||||||
|
speed_mode: I2cSpeed,
|
||||||
|
) -> Result<Self, ClockTooSlowForFastI2c> {
|
||||||
|
Self::new_generic(i2c, sys_cfg, cfg, clocks, speed_mode)
|
||||||
|
}
|
||||||
|
}
|
46
va416xx-hal/src/lib.rs
Normal file
46
va416xx-hal/src/lib.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#[cfg(test)]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
pub use va416xx as device;
|
||||||
|
pub use va416xx as pac;
|
||||||
|
|
||||||
|
pub mod prelude;
|
||||||
|
|
||||||
|
pub mod clock;
|
||||||
|
pub mod gpio;
|
||||||
|
pub mod i2c;
|
||||||
|
pub mod pwm;
|
||||||
|
pub mod spi;
|
||||||
|
pub mod time;
|
||||||
|
pub mod timer;
|
||||||
|
pub mod typelevel;
|
||||||
|
pub mod uart;
|
||||||
|
pub mod wdt;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, Copy, Clone, PartialEq)]
|
||||||
|
pub enum FunSel {
|
||||||
|
Sel0 = 0b00,
|
||||||
|
Sel1 = 0b01,
|
||||||
|
Sel2 = 0b10,
|
||||||
|
Sel3 = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable a specific interrupt using the NVIC peripheral.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is `unsafe` because it can break mask-based critical sections.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn enable_interrupt(irq: pac::Interrupt) {
|
||||||
|
unsafe {
|
||||||
|
cortex_m::peripheral::NVIC::unmask(irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable a specific interrupt using the NVIC peripheral.
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_interrupt(irq: pac::Interrupt) {
|
||||||
|
cortex_m::peripheral::NVIC::mask(irq);
|
||||||
|
}
|
4
va416xx-hal/src/prelude.rs
Normal file
4
va416xx-hal/src/prelude.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//! Prelude
|
||||||
|
pub use crate::clock::{ClkgenExt, SyscfgExt};
|
||||||
|
pub use fugit::ExtU32 as _;
|
||||||
|
pub use fugit::RateExtU32 as _;
|
388
va416xx-hal/src/pwm.rs
Normal file
388
va416xx-hal/src/pwm.rs
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
//! API for Pulse-Width Modulation (PWM)
|
||||||
|
//!
|
||||||
|
//! The Vorago VA416xx devices use the TIM peripherals to perform PWM related tasks.
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! - [PWM example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/pwm.rs)
|
||||||
|
use core::convert::Infallible;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::pac;
|
||||||
|
use crate::{clock::Clocks, gpio::DynPinId};
|
||||||
|
pub use crate::{gpio::PinId, time::Hertz, timer::*};
|
||||||
|
|
||||||
|
const DUTY_MAX: u16 = u16::MAX;
|
||||||
|
|
||||||
|
pub struct PwmBase {
|
||||||
|
clock: Hertz,
|
||||||
|
/// For PWMB, this is the upper limit
|
||||||
|
current_duty: u16,
|
||||||
|
/// For PWMA, this value will not be used
|
||||||
|
current_lower_limit: u16,
|
||||||
|
current_period: Hertz,
|
||||||
|
current_rst_val: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StatusSelPwm {
|
||||||
|
PwmA = 3,
|
||||||
|
PwmB = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PwmA {}
|
||||||
|
pub struct PwmB {}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Common
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
macro_rules! pwm_common_func {
|
||||||
|
() => {
|
||||||
|
#[inline]
|
||||||
|
fn enable_pwm_a(&mut self) {
|
||||||
|
self.reg
|
||||||
|
.reg()
|
||||||
|
.ctrl()
|
||||||
|
.modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmA as u8) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn enable_pwm_b(&mut self) {
|
||||||
|
self.reg
|
||||||
|
.reg()
|
||||||
|
.ctrl()
|
||||||
|
.modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmB as u8) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_period(&self) -> Hertz {
|
||||||
|
self.pwm_base.current_period
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_period(&mut self, period: impl Into<Hertz>) {
|
||||||
|
self.pwm_base.current_period = period.into();
|
||||||
|
// Avoid division by 0
|
||||||
|
if self.pwm_base.current_period.raw() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.pwm_base.current_rst_val =
|
||||||
|
self.pwm_base.clock.raw() / self.pwm_base.current_period.raw();
|
||||||
|
self.reg
|
||||||
|
.reg()
|
||||||
|
.rst_value()
|
||||||
|
.write(|w| unsafe { w.bits(self.pwm_base.current_rst_val) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable(&mut self) {
|
||||||
|
self.reg.reg().ctrl().modify(|_, w| w.enable().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable(&mut self) {
|
||||||
|
self.reg.reg().ctrl().modify(|_, w| w.enable().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn period(&self) -> Hertz {
|
||||||
|
self.pwm_base.current_period
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn duty(&self) -> u16 {
|
||||||
|
self.pwm_base.current_duty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pwmb_func {
|
||||||
|
() => {
|
||||||
|
pub fn pwmb_lower_limit(&self) -> u16 {
|
||||||
|
self.pwm_base.current_lower_limit
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pwmb_upper_limit(&self) -> u16 {
|
||||||
|
self.pwm_base.current_duty
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the lower limit for PWMB
|
||||||
|
///
|
||||||
|
/// The PWM signal will be 1 as long as the current RST counter is larger than
|
||||||
|
/// the lower limit. For example, with a lower limit of 0.5 and and an upper limit
|
||||||
|
/// of 0.7, Only a fixed period between 0.5 * period and 0.7 * period will be in a high
|
||||||
|
/// state
|
||||||
|
pub fn set_pwmb_lower_limit(&mut self, duty: u16) {
|
||||||
|
self.pwm_base.current_lower_limit = duty;
|
||||||
|
let pwmb_val: u64 = (self.pwm_base.current_rst_val as u64
|
||||||
|
* self.pwm_base.current_lower_limit as u64)
|
||||||
|
/ DUTY_MAX as u64;
|
||||||
|
self.reg
|
||||||
|
.reg()
|
||||||
|
.pwmb_value()
|
||||||
|
.write(|w| unsafe { w.bits(pwmb_val as u32) });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the higher limit for PWMB
|
||||||
|
///
|
||||||
|
/// The PWM signal will be 1 as long as the current RST counter is smaller than
|
||||||
|
/// the higher limit. For example, with a lower limit of 0.5 and and an upper limit
|
||||||
|
/// of 0.7, Only a fixed period between 0.5 * period and 0.7 * period will be in a high
|
||||||
|
/// state
|
||||||
|
pub fn set_pwmb_upper_limit(&mut self, duty: u16) {
|
||||||
|
self.pwm_base.current_duty = duty;
|
||||||
|
let pwma_val: u64 = (self.pwm_base.current_rst_val as u64
|
||||||
|
* self.pwm_base.current_duty as u64)
|
||||||
|
/ DUTY_MAX as u64;
|
||||||
|
self.reg
|
||||||
|
.reg()
|
||||||
|
.pwma_value()
|
||||||
|
.write(|w| unsafe { w.bits(pwma_val as u32) });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Strongly typed PWM pin
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub struct PwmPin<Pin: TimPin, Tim: ValidTim, Mode = PwmA> {
|
||||||
|
reg: TimAndPinRegister<Pin, Tim>,
|
||||||
|
pwm_base: PwmBase,
|
||||||
|
mode: PhantomData<Mode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim, Mode> PwmPin<Pin, Tim, Mode>
|
||||||
|
where
|
||||||
|
(Pin, Tim): ValidTimAndPin<Pin, Tim>,
|
||||||
|
{
|
||||||
|
/// Create a new stronlgy typed PWM pin
|
||||||
|
pub fn new(
|
||||||
|
pin_and_tim: (Pin, Tim),
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
clocks: &Clocks,
|
||||||
|
initial_period: impl Into<Hertz> + Copy,
|
||||||
|
) -> Self {
|
||||||
|
let mut pin = PwmPin {
|
||||||
|
pwm_base: PwmBase {
|
||||||
|
current_duty: 0,
|
||||||
|
current_lower_limit: 0,
|
||||||
|
current_period: initial_period.into(),
|
||||||
|
current_rst_val: 0,
|
||||||
|
clock: Tim::clock(clocks),
|
||||||
|
},
|
||||||
|
reg: unsafe { TimAndPinRegister::new(pin_and_tim.0, pin_and_tim.1) },
|
||||||
|
mode: PhantomData,
|
||||||
|
};
|
||||||
|
sys_cfg
|
||||||
|
.tim_clk_enable()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | pin.reg.mask_32()) });
|
||||||
|
pin.enable_pwm_a();
|
||||||
|
pin.set_period(initial_period);
|
||||||
|
pin
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(self) -> (Pin, Tim) {
|
||||||
|
self.reg.release()
|
||||||
|
}
|
||||||
|
|
||||||
|
pwm_common_func!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> From<PwmPin<Pin, Tim, PwmA>> for PwmPin<Pin, Tim, PwmB>
|
||||||
|
where
|
||||||
|
(Pin, Tim): ValidTimAndPin<Pin, Tim>,
|
||||||
|
{
|
||||||
|
fn from(other: PwmPin<Pin, Tim, PwmA>) -> Self {
|
||||||
|
let mut pwmb = Self {
|
||||||
|
reg: other.reg,
|
||||||
|
pwm_base: other.pwm_base,
|
||||||
|
mode: PhantomData,
|
||||||
|
};
|
||||||
|
pwmb.enable_pwm_b();
|
||||||
|
pwmb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<PIN: TimPin, TIM: ValidTim> From<PwmPin<PIN, TIM, PwmB>> for PwmPin<PIN, TIM, PwmA>
|
||||||
|
where
|
||||||
|
(PIN, TIM): ValidTimAndPin<PIN, TIM>,
|
||||||
|
{
|
||||||
|
fn from(other: PwmPin<PIN, TIM, PwmB>) -> Self {
|
||||||
|
let mut pwmb = Self {
|
||||||
|
reg: other.reg,
|
||||||
|
pwm_base: other.pwm_base,
|
||||||
|
mode: PhantomData,
|
||||||
|
};
|
||||||
|
pwmb.enable_pwm_a();
|
||||||
|
pwmb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> PwmPin<Pin, Tim, PwmA>
|
||||||
|
where
|
||||||
|
(Pin, Tim): ValidTimAndPin<Pin, Tim>,
|
||||||
|
{
|
||||||
|
pub fn pwma(
|
||||||
|
tim_and_pin: (Pin, Tim),
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
clocks: &Clocks,
|
||||||
|
initial_period: impl Into<Hertz> + Copy,
|
||||||
|
) -> Self {
|
||||||
|
let mut pin: PwmPin<Pin, Tim, PwmA> =
|
||||||
|
Self::new(tim_and_pin, sys_cfg, clocks, initial_period);
|
||||||
|
pin.enable_pwm_a();
|
||||||
|
pin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> PwmPin<Pin, Tim, PwmB>
|
||||||
|
where
|
||||||
|
(Pin, Tim): ValidTimAndPin<Pin, Tim>,
|
||||||
|
{
|
||||||
|
pub fn pwmb(
|
||||||
|
tim_and_pin: (Pin, Tim),
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
clocks: &Clocks,
|
||||||
|
initial_period: impl Into<Hertz> + Copy,
|
||||||
|
) -> Self {
|
||||||
|
let mut pin: PwmPin<Pin, Tim, PwmB> =
|
||||||
|
Self::new(tim_and_pin, sys_cfg, clocks, initial_period);
|
||||||
|
pin.enable_pwm_b();
|
||||||
|
pin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Reduced PWM pin
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Reduced version where type information is deleted
|
||||||
|
pub struct ReducedPwmPin<Mode = PwmA> {
|
||||||
|
reg: TimDynRegister,
|
||||||
|
pwm_base: PwmBase,
|
||||||
|
pin_id: DynPinId,
|
||||||
|
mode: PhantomData<Mode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<PIN: TimPin, TIM: ValidTim> From<PwmPin<PIN, TIM>> for ReducedPwmPin<PwmA> {
|
||||||
|
fn from(pwm_pin: PwmPin<PIN, TIM>) -> Self {
|
||||||
|
ReducedPwmPin {
|
||||||
|
reg: TimDynRegister::from(pwm_pin.reg),
|
||||||
|
pwm_base: pwm_pin.pwm_base,
|
||||||
|
pin_id: PIN::DYN,
|
||||||
|
mode: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<MODE> ReducedPwmPin<MODE> {
|
||||||
|
pwm_common_func!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ReducedPwmPin<PwmA>> for ReducedPwmPin<PwmB> {
|
||||||
|
fn from(other: ReducedPwmPin<PwmA>) -> Self {
|
||||||
|
let mut pwmb = Self {
|
||||||
|
reg: other.reg,
|
||||||
|
pwm_base: other.pwm_base,
|
||||||
|
pin_id: other.pin_id,
|
||||||
|
mode: PhantomData,
|
||||||
|
};
|
||||||
|
pwmb.enable_pwm_b();
|
||||||
|
pwmb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ReducedPwmPin<PwmB>> for ReducedPwmPin<PwmA> {
|
||||||
|
fn from(other: ReducedPwmPin<PwmB>) -> Self {
|
||||||
|
let mut pwmb = Self {
|
||||||
|
reg: other.reg,
|
||||||
|
pwm_base: other.pwm_base,
|
||||||
|
pin_id: other.pin_id,
|
||||||
|
mode: PhantomData,
|
||||||
|
};
|
||||||
|
pwmb.enable_pwm_a();
|
||||||
|
pwmb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// PWMB implementations
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
impl<PIN: TimPin, TIM: ValidTim> PwmPin<PIN, TIM, PwmB>
|
||||||
|
where
|
||||||
|
(PIN, TIM): ValidTimAndPin<PIN, TIM>,
|
||||||
|
{
|
||||||
|
pwmb_func!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReducedPwmPin<PwmB> {
|
||||||
|
pwmb_func!();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Embedded HAL implementation: PWMA only
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> embedded_hal::pwm::ErrorType for PwmPin<Pin, Tim> {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_hal::pwm::ErrorType for ReducedPwmPin {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_hal::pwm::SetDutyCycle for ReducedPwmPin {
|
||||||
|
#[inline]
|
||||||
|
fn max_duty_cycle(&self) -> u16 {
|
||||||
|
DUTY_MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
|
||||||
|
self.pwm_base.current_duty = duty;
|
||||||
|
let pwma_val: u64 = (self.pwm_base.current_rst_val as u64
|
||||||
|
* (DUTY_MAX as u64 - self.pwm_base.current_duty as u64))
|
||||||
|
/ DUTY_MAX as u64;
|
||||||
|
self.reg
|
||||||
|
.reg()
|
||||||
|
.pwma_value()
|
||||||
|
.write(|w| unsafe { w.bits(pwma_val as u32) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> embedded_hal::pwm::SetDutyCycle for PwmPin<Pin, Tim> {
|
||||||
|
#[inline]
|
||||||
|
fn max_duty_cycle(&self) -> u16 {
|
||||||
|
DUTY_MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
|
||||||
|
self.pwm_base.current_duty = duty;
|
||||||
|
let pwma_val: u64 = (self.pwm_base.current_rst_val as u64
|
||||||
|
* (DUTY_MAX as u64 - self.pwm_base.current_duty as u64))
|
||||||
|
/ DUTY_MAX as u64;
|
||||||
|
self.reg
|
||||||
|
.reg()
|
||||||
|
.pwma_value()
|
||||||
|
.write(|w| unsafe { w.bits(pwma_val as u32) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the corresponding u16 duty cycle from a percent value ranging between 0.0 and 1.0.
|
||||||
|
///
|
||||||
|
/// Please note that this might load a lot of floating point code because this processor does not
|
||||||
|
/// have a FPU
|
||||||
|
pub fn get_duty_from_percent(percent: f32) -> u16 {
|
||||||
|
if percent > 1.0 {
|
||||||
|
DUTY_MAX
|
||||||
|
} else if percent <= 0.0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(percent * DUTY_MAX as f32) as u16
|
||||||
|
}
|
||||||
|
}
|
978
va416xx-hal/src/spi.rs
Normal file
978
va416xx-hal/src/spi.rs
Normal file
@ -0,0 +1,978 @@
|
|||||||
|
//! API for the SPI peripheral
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! - [Blocking SPI example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/spi.rs)
|
||||||
|
use core::{convert::Infallible, marker::PhantomData, ops::Deref};
|
||||||
|
|
||||||
|
use embedded_hal::spi::Mode;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
clock::PeripheralSelect,
|
||||||
|
gpio::{
|
||||||
|
AltFunc1, AltFunc2, AltFunc3, Pin, PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PB0,
|
||||||
|
PB1, PB10, PB11, PB12, PB13, PB14, PB15, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PC0, PC1,
|
||||||
|
PC10, PC11, PC7, PC8, PC9, PE10, PE11, PE12, PE13, PE14, PE15, PE5, PE6, PE7, PE8, PE9,
|
||||||
|
PF0, PF1, PF2, PF3, PF4, PF5, PF6, PF7, PG2, PG3, PG4,
|
||||||
|
},
|
||||||
|
pac,
|
||||||
|
time::Hertz,
|
||||||
|
typelevel::{NoneT, Sealed},
|
||||||
|
};
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Defintions
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
// FIFO has a depth of 16.
|
||||||
|
const FILL_DEPTH: usize = 12;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub enum HwChipSelectId {
|
||||||
|
Id0 = 0,
|
||||||
|
Id1 = 1,
|
||||||
|
Id2 = 2,
|
||||||
|
Id3 = 3,
|
||||||
|
Id4 = 4,
|
||||||
|
Id5 = 5,
|
||||||
|
Id6 = 6,
|
||||||
|
Id7 = 7,
|
||||||
|
Invalid = 0xff,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SpiId {
|
||||||
|
Spi0,
|
||||||
|
Spi1,
|
||||||
|
Spi2,
|
||||||
|
Spi3,
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub enum WordSize {
|
||||||
|
OneBit = 0x00,
|
||||||
|
FourBits = 0x03,
|
||||||
|
EightBits = 0x07,
|
||||||
|
SixteenBits = 0x0f,
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Pin type definitions
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub trait PinSck<SPI>: Sealed {}
|
||||||
|
pub trait PinMosi<SPI>: Sealed {}
|
||||||
|
pub trait PinMiso<SPI>: Sealed {}
|
||||||
|
|
||||||
|
pub trait HwCsProvider: Sealed {
|
||||||
|
const CS_ID: HwChipSelectId;
|
||||||
|
const SPI_ID: SpiId;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait OptionalHwCs<Spi>: HwCsProvider + Sealed {}
|
||||||
|
|
||||||
|
macro_rules! hw_cs_pins {
|
||||||
|
($SPIx:path, $portId: path:
|
||||||
|
$(
|
||||||
|
($PXx:ident, $AFx:ident, $HwCsIdent:path, $typedef:ident),
|
||||||
|
)+
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
impl HwCsProvider for Pin<$PXx, $AFx> {
|
||||||
|
const CS_ID: HwChipSelectId = $HwCsIdent;
|
||||||
|
const SPI_ID: SpiId = $portId;
|
||||||
|
}
|
||||||
|
impl OptionalHwCs<$SPIx> for Pin<$PXx, $AFx> {}
|
||||||
|
pub type $typedef = Pin<$PXx, $AFx>;
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HwCsProvider for NoneT {
|
||||||
|
const CS_ID: HwChipSelectId = HwChipSelectId::Invalid;
|
||||||
|
const SPI_ID: SpiId = SpiId::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OptionalHwCs<pac::Spi0> for NoneT {}
|
||||||
|
impl OptionalHwCs<pac::Spi1> for NoneT {}
|
||||||
|
impl OptionalHwCs<pac::Spi2> for NoneT {}
|
||||||
|
impl OptionalHwCs<pac::Spi3> for NoneT {}
|
||||||
|
|
||||||
|
// SPI 0
|
||||||
|
|
||||||
|
impl PinSck<pac::Spi0> for Pin<PB15, AltFunc1> {}
|
||||||
|
impl PinMosi<pac::Spi0> for Pin<PC1, AltFunc1> {}
|
||||||
|
impl PinMiso<pac::Spi0> for Pin<PC0, AltFunc1> {}
|
||||||
|
|
||||||
|
// SPI 1
|
||||||
|
|
||||||
|
impl PinSck<pac::Spi1> for Pin<PB8, AltFunc3> {}
|
||||||
|
impl PinMosi<pac::Spi1> for Pin<PB10, AltFunc3> {}
|
||||||
|
impl PinMiso<pac::Spi1> for Pin<PB9, AltFunc3> {}
|
||||||
|
|
||||||
|
impl PinSck<pac::Spi1> for Pin<PC9, AltFunc2> {}
|
||||||
|
impl PinMosi<pac::Spi1> for Pin<PC11, AltFunc2> {}
|
||||||
|
impl PinMiso<pac::Spi1> for Pin<PC10, AltFunc2> {}
|
||||||
|
|
||||||
|
impl PinSck<pac::Spi1> for Pin<PG3, AltFunc2> {}
|
||||||
|
impl PinMiso<pac::Spi1> for Pin<PG4, AltFunc2> {}
|
||||||
|
|
||||||
|
impl PinSck<pac::Spi1> for Pin<PE13, AltFunc2> {}
|
||||||
|
impl PinMosi<pac::Spi1> for Pin<PE15, AltFunc2> {}
|
||||||
|
impl PinMiso<pac::Spi1> for Pin<PE14, AltFunc2> {}
|
||||||
|
|
||||||
|
impl PinSck<pac::Spi1> for Pin<PF3, AltFunc1> {}
|
||||||
|
impl PinMosi<pac::Spi1> for Pin<PF5, AltFunc1> {}
|
||||||
|
impl PinMiso<pac::Spi1> for Pin<PF4, AltFunc1> {}
|
||||||
|
|
||||||
|
// SPI 2
|
||||||
|
|
||||||
|
impl PinSck<pac::Spi2> for Pin<PA5, AltFunc2> {}
|
||||||
|
impl PinMosi<pac::Spi2> for Pin<PA7, AltFunc2> {}
|
||||||
|
impl PinMiso<pac::Spi2> for Pin<PA6, AltFunc2> {}
|
||||||
|
|
||||||
|
impl PinSck<pac::Spi2> for Pin<PF5, AltFunc2> {}
|
||||||
|
impl PinMosi<pac::Spi2> for Pin<PF7, AltFunc2> {}
|
||||||
|
impl PinMiso<pac::Spi2> for Pin<PF6, AltFunc2> {}
|
||||||
|
|
||||||
|
// SPI3 is shared with the ROM SPI pins and has its own dedicated pins.
|
||||||
|
|
||||||
|
// SPI 0 HW CS pins
|
||||||
|
|
||||||
|
hw_cs_pins!(
|
||||||
|
pac::Spi0, SpiId::Spi0:
|
||||||
|
(PB14, AltFunc1, HwChipSelectId::Id0, HwCs0Spi0),
|
||||||
|
(PB13, AltFunc1, HwChipSelectId::Id1, HwCs1Spi0),
|
||||||
|
(PB12, AltFunc1, HwChipSelectId::Id2, HwCs2Spi0),
|
||||||
|
(PB11, AltFunc1, HwChipSelectId::Id3, HwCs3Spi0),
|
||||||
|
);
|
||||||
|
|
||||||
|
hw_cs_pins!(
|
||||||
|
pac::Spi1, SpiId::Spi1:
|
||||||
|
(PB7, AltFunc3, HwChipSelectId::Id0, HwCs0Spi1Pb),
|
||||||
|
(PB6, AltFunc3, HwChipSelectId::Id1, HwCs1Spi1Pb),
|
||||||
|
(PB5, AltFunc3, HwChipSelectId::Id2, HwCs2Spi1Pb),
|
||||||
|
(PB4, AltFunc3, HwChipSelectId::Id3, HwCs3Spi1Pb),
|
||||||
|
(PB3, AltFunc3, HwChipSelectId::Id4, HwCs4Spi1Pb),
|
||||||
|
(PB2, AltFunc3, HwChipSelectId::Id5, HwCs5Spi1Pb),
|
||||||
|
(PB1, AltFunc3, HwChipSelectId::Id6, HwCs6Spi1Pb),
|
||||||
|
(PB0, AltFunc3, HwChipSelectId::Id7, HwCs7Spi1Pb),
|
||||||
|
(PC8, AltFunc2, HwChipSelectId::Id0, HwCs0Spi1Pc),
|
||||||
|
(PC7, AltFunc2, HwChipSelectId::Id1, HwCs1Spi1Pc),
|
||||||
|
(PE12, AltFunc2, HwChipSelectId::Id0, HwCs0Spi1Pe),
|
||||||
|
(PE11, AltFunc2, HwChipSelectId::Id1, HwCs1Spi1Pe),
|
||||||
|
(PE10, AltFunc2, HwChipSelectId::Id2, HwCs2Spi1Pe),
|
||||||
|
(PE9, AltFunc2, HwChipSelectId::Id3, HwCs3Spi1Pe),
|
||||||
|
(PE8, AltFunc2, HwChipSelectId::Id4, HwCs4Spi1Pe),
|
||||||
|
(PE7, AltFunc3, HwChipSelectId::Id5, HwCs5Spi1Pe),
|
||||||
|
(PE6, AltFunc3, HwChipSelectId::Id6, HwCs6Spi1Pe),
|
||||||
|
(PE5, AltFunc3, HwChipSelectId::Id7, HwCs7Spi1Pe),
|
||||||
|
(PF2, AltFunc1, HwChipSelectId::Id0, HwCs0Spi1Pf),
|
||||||
|
(PG2, AltFunc2, HwChipSelectId::Id0, HwCs0Spi1Pg),
|
||||||
|
);
|
||||||
|
|
||||||
|
hw_cs_pins!(
|
||||||
|
pac::Spi2, SpiId::Spi2:
|
||||||
|
(PA4, AltFunc2, HwChipSelectId::Id0, HwCs0Spi2Pa),
|
||||||
|
(PA3, AltFunc2, HwChipSelectId::Id1, HwCs1Spi2Pa),
|
||||||
|
(PA2, AltFunc2, HwChipSelectId::Id2, HwCs2Spi2Pa),
|
||||||
|
(PA1, AltFunc2, HwChipSelectId::Id3, HwCs3Spi2Pa),
|
||||||
|
(PA0, AltFunc2, HwChipSelectId::Id4, HwCs4Spi2Pa),
|
||||||
|
(PA8, AltFunc2, HwChipSelectId::Id6, HwCs6Spi2Pa),
|
||||||
|
(PA9, AltFunc2, HwChipSelectId::Id5, HwCs5Spi2Pa),
|
||||||
|
(PF0, AltFunc2, HwChipSelectId::Id4, HwCs4Spi2Pf),
|
||||||
|
(PF1, AltFunc2, HwChipSelectId::Id3, HwCs3Spi2Pf),
|
||||||
|
(PF2, AltFunc2, HwChipSelectId::Id2, HwCs2Spi2Pf),
|
||||||
|
(PF3, AltFunc2, HwChipSelectId::Id1, HwCs1Spi2Pf),
|
||||||
|
(PF4, AltFunc2, HwChipSelectId::Id0, HwCs0Spi2Pf),
|
||||||
|
);
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Config
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub trait TransferConfigProvider {
|
||||||
|
fn sod(&mut self, sod: bool);
|
||||||
|
fn blockmode(&mut self, blockmode: bool);
|
||||||
|
fn mode(&mut self, mode: Mode);
|
||||||
|
fn frequency(&mut self, spi_clk: Hertz);
|
||||||
|
fn hw_cs_id(&self) -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This struct contains all configuration parameter which are transfer specific
|
||||||
|
/// and might change for transfers to different SPI slaves
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct TransferConfig<HwCs> {
|
||||||
|
pub spi_clk: Hertz,
|
||||||
|
pub mode: Mode,
|
||||||
|
/// This only works if the Slave Output Disable (SOD) bit of the [`SpiConfig`] is set to
|
||||||
|
/// false
|
||||||
|
pub hw_cs: Option<HwCs>,
|
||||||
|
pub sod: bool,
|
||||||
|
/// If this is enabled, all data in the FIFO is transmitted in a single frame unless
|
||||||
|
/// the BMSTOP bit is set on a dataword. A frame is defined as CSn being active for the
|
||||||
|
/// duration of multiple data words
|
||||||
|
pub blockmode: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type erased variant of the transfer configuration. This is required to avoid generics in
|
||||||
|
/// the SPI constructor.
|
||||||
|
pub struct ErasedTransferConfig {
|
||||||
|
pub spi_clk: Hertz,
|
||||||
|
pub mode: Mode,
|
||||||
|
pub sod: bool,
|
||||||
|
/// If this is enabled, all data in the FIFO is transmitted in a single frame unless
|
||||||
|
/// the BMSTOP bit is set on a dataword. A frame is defined as CSn being active for the
|
||||||
|
/// duration of multiple data words
|
||||||
|
pub blockmode: bool,
|
||||||
|
pub hw_cs: HwChipSelectId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransferConfig<NoneT> {
|
||||||
|
pub fn new_no_hw_cs(spi_clk: impl Into<Hertz>, mode: Mode, blockmode: bool, sod: bool) -> Self {
|
||||||
|
TransferConfig {
|
||||||
|
spi_clk: spi_clk.into(),
|
||||||
|
mode,
|
||||||
|
hw_cs: None,
|
||||||
|
sod,
|
||||||
|
blockmode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HwCs: HwCsProvider> TransferConfig<HwCs> {
|
||||||
|
pub fn new(
|
||||||
|
spi_clk: impl Into<Hertz>,
|
||||||
|
mode: Mode,
|
||||||
|
hw_cs: Option<HwCs>,
|
||||||
|
blockmode: bool,
|
||||||
|
sod: bool,
|
||||||
|
) -> Self {
|
||||||
|
TransferConfig {
|
||||||
|
spi_clk: spi_clk.into(),
|
||||||
|
mode,
|
||||||
|
hw_cs,
|
||||||
|
sod,
|
||||||
|
blockmode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downgrade(self) -> ErasedTransferConfig {
|
||||||
|
ErasedTransferConfig {
|
||||||
|
spi_clk: self.spi_clk,
|
||||||
|
mode: self.mode,
|
||||||
|
sod: self.sod,
|
||||||
|
blockmode: self.blockmode,
|
||||||
|
hw_cs: HwCs::CS_ID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HwCs: HwCsProvider> TransferConfigProvider for TransferConfig<HwCs> {
|
||||||
|
/// Slave Output Disable
|
||||||
|
fn sod(&mut self, sod: bool) {
|
||||||
|
self.sod = sod;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blockmode(&mut self, blockmode: bool) {
|
||||||
|
self.blockmode = blockmode;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mode(&mut self, mode: Mode) {
|
||||||
|
self.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frequency(&mut self, spi_clk: Hertz) {
|
||||||
|
self.spi_clk = spi_clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hw_cs_id(&self) -> u8 {
|
||||||
|
HwCs::CS_ID as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
/// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details
|
||||||
|
pub struct SpiConfig {
|
||||||
|
/// Serial clock rate divider. Together with the CLKPRESCALE register, it determines
|
||||||
|
/// the SPI clock rate in master mode. 0 by default. Specifying a higher value
|
||||||
|
/// limits the maximum attainable SPI speed
|
||||||
|
pub ser_clock_rate_div: u8,
|
||||||
|
/// By default, configure SPI for master mode (ms == false)
|
||||||
|
ms: bool,
|
||||||
|
/// Slave output disable. Useful if separate GPIO pins or decoders are used for CS control
|
||||||
|
pub slave_output_disable: bool,
|
||||||
|
/// Loopback mode. If you use this, don't connect MISO to MOSI, they will be tied internally
|
||||||
|
pub loopback_mode: bool,
|
||||||
|
/// Enable Master Delayer Capture Mode. See Programmers Guide p.92 for more details
|
||||||
|
pub master_delayer_capture: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpiConfig {
|
||||||
|
pub fn loopback(mut self, enable: bool) -> Self {
|
||||||
|
self.loopback_mode = enable;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn master_mode(mut self, master: bool) -> Self {
|
||||||
|
self.ms = !master;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn slave_output_disable(mut self, sod: bool) -> Self {
|
||||||
|
self.slave_output_disable = sod;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Word Size
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Configuration trait for the Word Size used by the SPI peripheral
|
||||||
|
pub trait WordProvider: Copy + Default + Into<u32> + TryFrom<u32> + 'static {
|
||||||
|
const MASK: u32;
|
||||||
|
fn word_reg() -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WordProvider for u8 {
|
||||||
|
const MASK: u32 = 0xff;
|
||||||
|
fn word_reg() -> u8 {
|
||||||
|
0x07
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WordProvider for u16 {
|
||||||
|
const MASK: u32 = 0xffff;
|
||||||
|
fn word_reg() -> u8 {
|
||||||
|
0x0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type SpiRegBlock = pac::spi0::RegisterBlock;
|
||||||
|
|
||||||
|
/// Common trait implemented by all PAC peripheral access structures. The register block
|
||||||
|
/// format is the same for all SPI blocks.
|
||||||
|
pub trait Instance: Deref<Target = SpiRegBlock> {
|
||||||
|
const IDX: u8;
|
||||||
|
const PERIPH_SEL: PeripheralSelect;
|
||||||
|
|
||||||
|
fn ptr() -> *const SpiRegBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for pac::Spi0 {
|
||||||
|
const IDX: u8 = 0;
|
||||||
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0;
|
||||||
|
|
||||||
|
fn ptr() -> *const SpiRegBlock {
|
||||||
|
Self::ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for pac::Spi1 {
|
||||||
|
const IDX: u8 = 1;
|
||||||
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1;
|
||||||
|
|
||||||
|
fn ptr() -> *const SpiRegBlock {
|
||||||
|
Self::ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for pac::Spi2 {
|
||||||
|
const IDX: u8 = 2;
|
||||||
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2;
|
||||||
|
|
||||||
|
fn ptr() -> *const SpiRegBlock {
|
||||||
|
Self::ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Spi
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub struct SpiBase<SpiInstance, Word = u8> {
|
||||||
|
spi: SpiInstance,
|
||||||
|
cfg: SpiConfig,
|
||||||
|
apb1_clk: Hertz,
|
||||||
|
/// Fill word for read-only SPI transactions.
|
||||||
|
pub fill_word: Word,
|
||||||
|
blockmode: bool,
|
||||||
|
word: PhantomData<Word>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Spi<SpiInstance, Pins, Word = u8> {
|
||||||
|
inner: SpiBase<SpiInstance, Word>,
|
||||||
|
pins: Pins,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) {
|
||||||
|
match mode {
|
||||||
|
embedded_hal::spi::MODE_0 => (false, false),
|
||||||
|
embedded_hal::spi::MODE_1 => (false, true),
|
||||||
|
embedded_hal::spi::MODE_2 => (true, false),
|
||||||
|
embedded_hal::spi::MODE_3 => (true, true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SpiInstance: Instance, Word: WordProvider> SpiBase<SpiInstance, Word>
|
||||||
|
where
|
||||||
|
<Word as TryFrom<u32>>::Error: core::fmt::Debug,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
pub fn cfg_clock(&mut self, spi_clk: impl Into<Hertz>) {
|
||||||
|
let clk_prescale =
|
||||||
|
self.apb1_clk.raw() / (spi_clk.into().raw() * (self.cfg.ser_clock_rate_div as u32 + 1));
|
||||||
|
self.spi
|
||||||
|
.clkprescale()
|
||||||
|
.write(|w| unsafe { w.bits(clk_prescale) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cfg_mode(&mut self, mode: Mode) {
|
||||||
|
let (cpo_bit, cph_bit) = mode_to_cpo_cph_bit(mode);
|
||||||
|
self.spi.ctrl0().modify(|_, w| {
|
||||||
|
w.spo().bit(cpo_bit);
|
||||||
|
w.sph().bit(cph_bit)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_tx_fifo(&self) {
|
||||||
|
self.spi.fifo_clr().write(|w| w.txfifo().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_rx_fifo(&self) {
|
||||||
|
self.spi.fifo_clr().write(|w| w.rxfifo().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn perid(&self) -> u32 {
|
||||||
|
self.spi.perid().read().bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cfg_hw_cs(&mut self, hw_cs: HwChipSelectId) {
|
||||||
|
if hw_cs == HwChipSelectId::Invalid {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.spi.ctrl1().modify(|_, w| {
|
||||||
|
w.sod().clear_bit();
|
||||||
|
unsafe {
|
||||||
|
w.ss().bits(hw_cs as u8);
|
||||||
|
}
|
||||||
|
w
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cfg_hw_cs_with_pin<HwCs: OptionalHwCs<SpiInstance>>(&mut self, _: &HwCs) {
|
||||||
|
self.cfg_hw_cs(HwCs::CS_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cfg_hw_cs_disable(&mut self) {
|
||||||
|
self.spi.ctrl1().modify(|_, w| {
|
||||||
|
w.sod().set_bit();
|
||||||
|
w
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cfg_transfer<HwCs: OptionalHwCs<SpiInstance>>(
|
||||||
|
&mut self,
|
||||||
|
transfer_cfg: &TransferConfig<HwCs>,
|
||||||
|
) {
|
||||||
|
self.cfg_clock(transfer_cfg.spi_clk);
|
||||||
|
self.cfg_mode(transfer_cfg.mode);
|
||||||
|
self.blockmode = transfer_cfg.blockmode;
|
||||||
|
self.spi.ctrl1().modify(|_, w| {
|
||||||
|
if transfer_cfg.sod {
|
||||||
|
w.sod().set_bit();
|
||||||
|
} else if transfer_cfg.hw_cs.is_some() {
|
||||||
|
w.sod().clear_bit();
|
||||||
|
unsafe {
|
||||||
|
w.ss().bits(HwCs::CS_ID as u8);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w.sod().clear_bit();
|
||||||
|
}
|
||||||
|
if transfer_cfg.blockmode {
|
||||||
|
w.blockmode().set_bit();
|
||||||
|
} else {
|
||||||
|
w.blockmode().clear_bit();
|
||||||
|
}
|
||||||
|
w
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends a word to the slave
|
||||||
|
#[inline(always)]
|
||||||
|
fn send_blocking(&self, word: Word) {
|
||||||
|
// TODO: Upper limit for wait cycles to avoid complete hangups?
|
||||||
|
while self.spi.status().read().tnf().bit_is_clear() {}
|
||||||
|
self.send(word)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn send(&self, word: Word) {
|
||||||
|
self.spi.data().write(|w| unsafe { w.bits(word.into()) });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a word from the slave. Must be preceeded by a [`send`](Self::send) call
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_blocking(&self) -> Word {
|
||||||
|
// TODO: Upper limit for wait cycles to avoid complete hangups?
|
||||||
|
while self.spi.status().read().rne().bit_is_clear() {}
|
||||||
|
self.read_single_word()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_single_word(&self) -> Word {
|
||||||
|
(self.spi.data().read().bits() & Word::MASK)
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer_preparation(&self, words: &[Word]) -> Result<(), Infallible> {
|
||||||
|
if words.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let mut status_reg = self.spi.status().read();
|
||||||
|
// Wait until all bytes have been transferred.
|
||||||
|
while status_reg.tfe().bit_is_clear() {
|
||||||
|
// Ignore all received read words.
|
||||||
|
if status_reg.rne().bit_is_set() {
|
||||||
|
self.clear_rx_fifo();
|
||||||
|
}
|
||||||
|
status_reg = self.spi.status().read();
|
||||||
|
}
|
||||||
|
// Ignore all received read words.
|
||||||
|
if status_reg.rne().bit_is_set() {
|
||||||
|
self.clear_rx_fifo();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initial_send_fifo_pumping(&self, words: Option<&[Word]>) -> usize {
|
||||||
|
if self.blockmode {
|
||||||
|
self.spi.ctrl1().modify(|_, w| w.mtxpause().set_bit())
|
||||||
|
}
|
||||||
|
// Fill the first half of the write FIFO
|
||||||
|
let mut current_write_idx = 0;
|
||||||
|
for _ in 0..core::cmp::min(FILL_DEPTH, words.map_or(0, |words| words.len())) {
|
||||||
|
self.send_blocking(words.map_or(self.fill_word, |words| words[current_write_idx]));
|
||||||
|
current_write_idx += 1;
|
||||||
|
}
|
||||||
|
if self.blockmode {
|
||||||
|
self.spi.ctrl1().modify(|_, w| w.mtxpause().clear_bit())
|
||||||
|
}
|
||||||
|
current_write_idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
macro_rules! spi_ctor {
|
||||||
|
($spiI:ident, $PeriphSel: path) => {
|
||||||
|
/// Create a new SPI struct
|
||||||
|
///
|
||||||
|
/// You can delete the pin type information by calling the
|
||||||
|
/// [`downgrade`](Self::downgrade) function
|
||||||
|
///
|
||||||
|
/// ## Arguments
|
||||||
|
/// * `spi` - SPI bus to use
|
||||||
|
/// * `pins` - Pins to be used for SPI transactions. These pins are consumed
|
||||||
|
/// to ensure the pins can not be used for other purposes anymore
|
||||||
|
/// * `spi_cfg` - Configuration specific to the SPI bus
|
||||||
|
/// * `transfer_cfg` - Optional initial transfer configuration which includes
|
||||||
|
/// configuration which can change across individual SPI transfers like SPI mode
|
||||||
|
/// or SPI clock. If only one device is connected, this configuration only needs
|
||||||
|
/// to be done once.
|
||||||
|
/// * `syscfg` - Can be passed optionally to enable the peripheral clock
|
||||||
|
pub fn $spiI(
|
||||||
|
spi: SpiI,
|
||||||
|
pins: (Sck, Miso, Mosi),
|
||||||
|
clocks: &crate::clock::Clocks,
|
||||||
|
spi_cfg: SpiConfig,
|
||||||
|
syscfg: &mut pac::Sysconfig,
|
||||||
|
transfer_cfg: Option<&ErasedTransferConfig>,
|
||||||
|
) -> Self {
|
||||||
|
crate::clock::enable_peripheral_clock(syscfg, $PeriphSel);
|
||||||
|
let SpiConfig {
|
||||||
|
ser_clock_rate_div,
|
||||||
|
ms,
|
||||||
|
slave_output_disable,
|
||||||
|
loopback_mode,
|
||||||
|
master_delayer_capture,
|
||||||
|
} = spi_cfg;
|
||||||
|
let mut mode = embedded_hal::spi::MODE_0;
|
||||||
|
let mut clk_prescale = 0x02;
|
||||||
|
let mut ss = 0;
|
||||||
|
let mut init_blockmode = false;
|
||||||
|
let apb1_clk = clocks.apb1();
|
||||||
|
if let Some(transfer_cfg) = transfer_cfg {
|
||||||
|
mode = transfer_cfg.mode;
|
||||||
|
clk_prescale =
|
||||||
|
apb1_clk.raw() / (transfer_cfg.spi_clk.raw() * (ser_clock_rate_div as u32 + 1));
|
||||||
|
if transfer_cfg.hw_cs != HwChipSelectId::Invalid {
|
||||||
|
ss = transfer_cfg.hw_cs as u8;
|
||||||
|
}
|
||||||
|
init_blockmode = transfer_cfg.blockmode;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (cpo_bit, cph_bit) = mode_to_cpo_cph_bit(mode);
|
||||||
|
spi.ctrl0().write(|w| {
|
||||||
|
unsafe {
|
||||||
|
w.size().bits(Word::word_reg());
|
||||||
|
w.scrdv().bits(ser_clock_rate_div);
|
||||||
|
// Clear clock phase and polarity. Will be set to correct value for each
|
||||||
|
// transfer
|
||||||
|
w.spo().bit(cpo_bit);
|
||||||
|
w.sph().bit(cph_bit)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
spi.ctrl1().write(|w| {
|
||||||
|
w.lbm().bit(loopback_mode);
|
||||||
|
w.sod().bit(slave_output_disable);
|
||||||
|
w.ms().bit(ms);
|
||||||
|
w.mdlycap().bit(master_delayer_capture);
|
||||||
|
w.blockmode().bit(init_blockmode);
|
||||||
|
unsafe { w.ss().bits(ss) }
|
||||||
|
});
|
||||||
|
|
||||||
|
spi.fifo_clr().write(|w| {
|
||||||
|
w.rxfifo().set_bit();
|
||||||
|
w.txfifo().set_bit()
|
||||||
|
});
|
||||||
|
spi.clkprescale().write(|w| unsafe { w.bits(clk_prescale) });
|
||||||
|
// Enable the peripheral as the last step as recommended in the
|
||||||
|
// programmers guide
|
||||||
|
spi.ctrl1().modify(|_, w| w.enable().set_bit());
|
||||||
|
Spi {
|
||||||
|
inner: SpiBase {
|
||||||
|
spi,
|
||||||
|
cfg: spi_cfg,
|
||||||
|
apb1_clk,
|
||||||
|
fill_word: Default::default(),
|
||||||
|
blockmode: init_blockmode,
|
||||||
|
word: PhantomData,
|
||||||
|
},
|
||||||
|
pins,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl<
|
||||||
|
SpiI: Instance,
|
||||||
|
Sck: PinSck<SpiI>,
|
||||||
|
Miso: PinMiso<SpiI>,
|
||||||
|
Mosi: PinMosi<SpiI>,
|
||||||
|
Word: WordProvider,
|
||||||
|
> Spi<SpiI, (Sck, Miso, Mosi), Word>
|
||||||
|
where
|
||||||
|
<Word as TryFrom<u32>>::Error: core::fmt::Debug,
|
||||||
|
{
|
||||||
|
/// Create a new SPI struct
|
||||||
|
///
|
||||||
|
/// You can delete the pin type information by calling the
|
||||||
|
/// [`downgrade`](Self::downgrade) function
|
||||||
|
///
|
||||||
|
/// ## Arguments
|
||||||
|
/// * `spi` - SPI bus to use
|
||||||
|
/// * `pins` - Pins to be used for SPI transactions. These pins are consumed
|
||||||
|
/// to ensure the pins can not be used for other purposes anymore
|
||||||
|
/// * `spi_cfg` - Configuration specific to the SPI bus
|
||||||
|
/// * `transfer_cfg` - Optional initial transfer configuration which includes
|
||||||
|
/// configuration which can change across individual SPI transfers like SPI mode
|
||||||
|
/// or SPI clock. If only one device is connected, this configuration only needs
|
||||||
|
/// to be done once.
|
||||||
|
/// * `syscfg` - Can be passed optionally to enable the peripheral clock
|
||||||
|
pub fn new(
|
||||||
|
spi: SpiI,
|
||||||
|
pins: (Sck, Miso, Mosi),
|
||||||
|
clocks: &crate::clock::Clocks,
|
||||||
|
spi_cfg: SpiConfig,
|
||||||
|
syscfg: &mut pac::Sysconfig,
|
||||||
|
transfer_cfg: Option<&ErasedTransferConfig>,
|
||||||
|
) -> Self {
|
||||||
|
crate::clock::enable_peripheral_clock(syscfg, SpiI::PERIPH_SEL);
|
||||||
|
let SpiConfig {
|
||||||
|
ser_clock_rate_div,
|
||||||
|
ms,
|
||||||
|
slave_output_disable,
|
||||||
|
loopback_mode,
|
||||||
|
master_delayer_capture,
|
||||||
|
} = spi_cfg;
|
||||||
|
let mut mode = embedded_hal::spi::MODE_0;
|
||||||
|
let mut clk_prescale = 0x02;
|
||||||
|
let mut ss = 0;
|
||||||
|
let mut init_blockmode = false;
|
||||||
|
let apb1_clk = clocks.apb1();
|
||||||
|
if let Some(transfer_cfg) = transfer_cfg {
|
||||||
|
mode = transfer_cfg.mode;
|
||||||
|
clk_prescale =
|
||||||
|
apb1_clk.raw() / (transfer_cfg.spi_clk.raw() * (ser_clock_rate_div as u32 + 1));
|
||||||
|
if transfer_cfg.hw_cs != HwChipSelectId::Invalid {
|
||||||
|
ss = transfer_cfg.hw_cs as u8;
|
||||||
|
}
|
||||||
|
init_blockmode = transfer_cfg.blockmode;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (cpo_bit, cph_bit) = mode_to_cpo_cph_bit(mode);
|
||||||
|
spi.ctrl0().write(|w| {
|
||||||
|
unsafe {
|
||||||
|
w.size().bits(Word::word_reg());
|
||||||
|
w.scrdv().bits(ser_clock_rate_div);
|
||||||
|
// Clear clock phase and polarity. Will be set to correct value for each
|
||||||
|
// transfer
|
||||||
|
w.spo().bit(cpo_bit);
|
||||||
|
w.sph().bit(cph_bit)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
spi.ctrl1().write(|w| {
|
||||||
|
w.lbm().bit(loopback_mode);
|
||||||
|
w.sod().bit(slave_output_disable);
|
||||||
|
w.ms().bit(ms);
|
||||||
|
w.mdlycap().bit(master_delayer_capture);
|
||||||
|
w.blockmode().bit(init_blockmode);
|
||||||
|
unsafe { w.ss().bits(ss) }
|
||||||
|
});
|
||||||
|
|
||||||
|
spi.fifo_clr().write(|w| {
|
||||||
|
w.rxfifo().set_bit();
|
||||||
|
w.txfifo().set_bit()
|
||||||
|
});
|
||||||
|
spi.clkprescale().write(|w| unsafe { w.bits(clk_prescale) });
|
||||||
|
// Enable the peripheral as the last step as recommended in the
|
||||||
|
// programmers guide
|
||||||
|
spi.ctrl1().modify(|_, w| w.enable().set_bit());
|
||||||
|
Spi {
|
||||||
|
inner: SpiBase {
|
||||||
|
spi,
|
||||||
|
cfg: spi_cfg,
|
||||||
|
apb1_clk,
|
||||||
|
fill_word: Default::default(),
|
||||||
|
blockmode: init_blockmode,
|
||||||
|
word: PhantomData,
|
||||||
|
},
|
||||||
|
pins,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cfg_clock(&mut self, spi_clk: impl Into<Hertz>) {
|
||||||
|
self.inner.cfg_clock(spi_clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cfg_mode(&mut self, mode: Mode) {
|
||||||
|
self.inner.cfg_mode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_fill_word(&mut self, fill_word: Word) {
|
||||||
|
self.inner.fill_word = fill_word;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill_word(&self) -> Word {
|
||||||
|
self.inner.fill_word
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn perid(&self) -> u32 {
|
||||||
|
self.inner.perid()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cfg_transfer<HwCs: OptionalHwCs<SpiI>>(&mut self, transfer_cfg: &TransferConfig<HwCs>) {
|
||||||
|
self.inner.cfg_transfer(transfer_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Releases the SPI peripheral and associated pins
|
||||||
|
pub fn release(self) -> (SpiI, (Sck, Miso, Mosi), SpiConfig) {
|
||||||
|
(self.inner.spi, self.pins, self.inner.cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downgrade(self) -> SpiBase<SpiI, Word> {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Changing the word size also requires a type conversion
|
||||||
|
impl<SpiI: Instance, Sck: PinSck<SpiI>, Miso: PinMiso<SpiI>, Mosi: PinMosi<SpiI>>
|
||||||
|
From<Spi<SpiI, (Sck, Miso, Mosi), u8>> for Spi<SpiI, (Sck, Miso, Mosi), u16>
|
||||||
|
{
|
||||||
|
fn from(old_spi: Spi<SpiI, (Sck, Miso, Mosi), u8>) -> Self {
|
||||||
|
old_spi
|
||||||
|
.inner
|
||||||
|
.spi
|
||||||
|
.ctrl0()
|
||||||
|
.modify(|_, w| unsafe { w.size().bits(WordSize::SixteenBits as u8) });
|
||||||
|
Spi {
|
||||||
|
inner: SpiBase {
|
||||||
|
spi: old_spi.inner.spi,
|
||||||
|
cfg: old_spi.inner.cfg,
|
||||||
|
blockmode: old_spi.inner.blockmode,
|
||||||
|
fill_word: Default::default(),
|
||||||
|
apb1_clk: old_spi.inner.apb1_clk,
|
||||||
|
word: PhantomData,
|
||||||
|
},
|
||||||
|
pins: old_spi.pins,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Changing the word size also requires a type conversion
|
||||||
|
impl<SpiI: Instance, Sck: PinSck<SpiI>, Miso: PinMiso<SpiI>, Mosi: PinMosi<SpiI>>
|
||||||
|
From<Spi<SpiI, (Sck, Miso, Mosi), u16>> for Spi<SpiI, (Sck, Miso, Mosi), u8>
|
||||||
|
{
|
||||||
|
fn from(old_spi: Spi<SpiI, (Sck, Miso, Mosi), u16>) -> Self {
|
||||||
|
old_spi
|
||||||
|
.inner
|
||||||
|
.spi
|
||||||
|
.ctrl0()
|
||||||
|
.modify(|_, w| unsafe { w.size().bits(WordSize::EightBits as u8) });
|
||||||
|
Spi {
|
||||||
|
inner: SpiBase {
|
||||||
|
spi: old_spi.inner.spi,
|
||||||
|
cfg: old_spi.inner.cfg,
|
||||||
|
blockmode: old_spi.inner.blockmode,
|
||||||
|
apb1_clk: old_spi.inner.apb1_clk,
|
||||||
|
fill_word: Default::default(),
|
||||||
|
word: PhantomData,
|
||||||
|
},
|
||||||
|
pins: old_spi.pins,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SpiI: Instance, Word: WordProvider> embedded_hal::spi::ErrorType for SpiBase<SpiI, Word> {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SpiI: Instance, Word: WordProvider> embedded_hal::spi::SpiBus<Word> for SpiBase<SpiI, Word>
|
||||||
|
where
|
||||||
|
<Word as TryFrom<u32>>::Error: core::fmt::Debug,
|
||||||
|
{
|
||||||
|
fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||||
|
self.transfer_preparation(words)?;
|
||||||
|
let mut current_read_idx = 0;
|
||||||
|
let mut current_write_idx = self.initial_send_fifo_pumping(None);
|
||||||
|
loop {
|
||||||
|
if current_write_idx < words.len() {
|
||||||
|
self.send_blocking(self.fill_word);
|
||||||
|
current_write_idx += 1;
|
||||||
|
}
|
||||||
|
if current_read_idx < words.len() {
|
||||||
|
words[current_read_idx] = self.read_blocking();
|
||||||
|
current_read_idx += 1;
|
||||||
|
}
|
||||||
|
if current_read_idx >= words.len() && current_write_idx >= words.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
|
||||||
|
self.transfer_preparation(words)?;
|
||||||
|
let mut current_write_idx = self.initial_send_fifo_pumping(Some(words));
|
||||||
|
while current_write_idx < words.len() {
|
||||||
|
self.send_blocking(words[current_write_idx]);
|
||||||
|
current_write_idx += 1;
|
||||||
|
// Ignore received words.
|
||||||
|
if self.spi.status().read().rne().bit_is_set() {
|
||||||
|
self.clear_rx_fifo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
|
||||||
|
self.transfer_preparation(write)?;
|
||||||
|
let mut current_read_idx = 0;
|
||||||
|
let mut current_write_idx = self.initial_send_fifo_pumping(Some(write));
|
||||||
|
while current_read_idx < read.len() || current_write_idx < write.len() {
|
||||||
|
if current_write_idx < write.len() {
|
||||||
|
self.send_blocking(write[current_write_idx]);
|
||||||
|
current_write_idx += 1;
|
||||||
|
}
|
||||||
|
if current_read_idx < read.len() {
|
||||||
|
read[current_read_idx] = self.read_blocking();
|
||||||
|
current_read_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||||
|
self.transfer_preparation(words)?;
|
||||||
|
let mut current_read_idx = 0;
|
||||||
|
let mut current_write_idx = self.initial_send_fifo_pumping(Some(words));
|
||||||
|
|
||||||
|
while current_read_idx < words.len() || current_write_idx < words.len() {
|
||||||
|
if current_write_idx < words.len() {
|
||||||
|
self.send_blocking(words[current_write_idx]);
|
||||||
|
current_write_idx += 1;
|
||||||
|
}
|
||||||
|
if current_read_idx < words.len() && current_read_idx < current_write_idx {
|
||||||
|
words[current_read_idx] = self.read_blocking();
|
||||||
|
current_read_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
let status_reg = self.spi.status().read();
|
||||||
|
while status_reg.tfe().bit_is_clear() || status_reg.rne().bit_is_set() {
|
||||||
|
if status_reg.rne().bit_is_set() {
|
||||||
|
self.read_single_word();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
SpiI: Instance,
|
||||||
|
Word: WordProvider,
|
||||||
|
Sck: PinSck<SpiI>,
|
||||||
|
Miso: PinMiso<SpiI>,
|
||||||
|
Mosi: PinMosi<SpiI>,
|
||||||
|
> embedded_hal::spi::ErrorType for Spi<SpiI, (Sck, Miso, Mosi), Word>
|
||||||
|
{
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
SpiI: Instance,
|
||||||
|
Word: WordProvider,
|
||||||
|
Sck: PinSck<SpiI>,
|
||||||
|
Miso: PinMiso<SpiI>,
|
||||||
|
Mosi: PinMosi<SpiI>,
|
||||||
|
> embedded_hal::spi::SpiBus<Word> for Spi<SpiI, (Sck, Miso, Mosi), Word>
|
||||||
|
where
|
||||||
|
<Word as TryFrom<u32>>::Error: core::fmt::Debug,
|
||||||
|
{
|
||||||
|
fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||||
|
self.inner.read(words)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
|
||||||
|
self.inner.write(words)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
|
||||||
|
self.inner.transfer(read, write)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||||
|
self.inner.transfer_in_place(words)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.inner.flush()
|
||||||
|
}
|
||||||
|
}
|
26
va416xx-hal/src/time.rs
Normal file
26
va416xx-hal/src/time.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//! Time units
|
||||||
|
|
||||||
|
// Frequency based
|
||||||
|
|
||||||
|
/// Hertz
|
||||||
|
pub type Hertz = fugit::HertzU32;
|
||||||
|
|
||||||
|
/// KiloHertz
|
||||||
|
pub type KiloHertz = fugit::KilohertzU32;
|
||||||
|
|
||||||
|
/// MegaHertz
|
||||||
|
pub type MegaHertz = fugit::MegahertzU32;
|
||||||
|
|
||||||
|
// Period based
|
||||||
|
|
||||||
|
/// Seconds
|
||||||
|
pub type Seconds = fugit::SecsDurationU32;
|
||||||
|
|
||||||
|
/// Milliseconds
|
||||||
|
pub type Milliseconds = fugit::MillisDurationU32;
|
||||||
|
|
||||||
|
/// Microseconds
|
||||||
|
pub type Microseconds = fugit::MicrosDurationU32;
|
||||||
|
|
||||||
|
/// Nanoseconds
|
||||||
|
pub type Nanoseconds = fugit::NanosDurationU32;
|
801
va416xx-hal/src/timer.rs
Normal file
801
va416xx-hal/src/timer.rs
Normal file
@ -0,0 +1,801 @@
|
|||||||
|
//! API for the TIM peripherals
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! TODO.
|
||||||
|
use core::cell::Cell;
|
||||||
|
|
||||||
|
use cortex_m::interrupt::Mutex;
|
||||||
|
|
||||||
|
use crate::clock::Clocks;
|
||||||
|
use crate::gpio::{
|
||||||
|
AltFunc1, AltFunc2, AltFunc3, DynPinId, Pin, PinId, PA0, PA1, PA10, PA11, PA12, PA13, PA14,
|
||||||
|
PA15, PA2, PA3, PA4, PA5, PA6, PA7, PB0, PB1, PB10, PB11, PB12, PB13, PB14, PB15, PB2, PB3,
|
||||||
|
PB4, PB5, PB6, PB7, PB8, PB9, PC0, PC1, PD0, PD1, PD10, PD11, PD12, PD13, PD14, PD15, PD2, PD3,
|
||||||
|
PD4, PD5, PD6, PD7, PD8, PD9, PE0, PE1, PE10, PE11, PE12, PE13, PE14, PE15, PE2, PE3, PE4, PE5,
|
||||||
|
PE6, PE7, PE8, PE9, PF0, PF1, PF10, PF11, PF12, PF13, PF14, PF15, PF2, PF3, PF4, PF5, PF6, PF7,
|
||||||
|
PF8, PF9, PG0, PG1, PG2, PG3, PG6,
|
||||||
|
};
|
||||||
|
use crate::time::Hertz;
|
||||||
|
use crate::typelevel::Sealed;
|
||||||
|
use crate::{disable_interrupt, prelude::*};
|
||||||
|
use crate::{enable_interrupt, pac};
|
||||||
|
|
||||||
|
pub static MS_COUNTER: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Defintions
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Interrupt events
|
||||||
|
//pub enum Event {
|
||||||
|
/// Timer timed out / count down ended
|
||||||
|
//TimeOut,
|
||||||
|
//}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub struct CascadeCtrl {
|
||||||
|
/// Enable Cascade 0 signal active as a requirement for counting
|
||||||
|
pub enb_start_src_csd0: bool,
|
||||||
|
/// Invert Cascade 0, making it active low
|
||||||
|
pub inv_csd0: bool,
|
||||||
|
/// Enable Cascade 1 signal active as a requirement for counting
|
||||||
|
pub enb_start_src_csd1: bool,
|
||||||
|
/// Invert Cascade 1, making it active low
|
||||||
|
pub inv_csd1: bool,
|
||||||
|
/// Specify required operation if both Cascade 0 and Cascade 1 are active.
|
||||||
|
/// 0 is a logical AND of both cascade signals, 1 is a logical OR
|
||||||
|
pub dual_csd_op: bool,
|
||||||
|
/// Enable trigger mode for Cascade 0. In trigger mode, couting will start with the selected
|
||||||
|
/// cascade signal active, but once the counter is active, cascade control will be ignored
|
||||||
|
pub trg_csd0: bool,
|
||||||
|
/// Trigger mode, identical to [`trg_csd0`](CascadeCtrl) but for Cascade 1
|
||||||
|
pub trg_csd1: bool,
|
||||||
|
/// Enable Cascade 2 signal active as a requirement to stop counting. This mode is similar
|
||||||
|
/// to the REQ_STOP control bit, but signalled by a Cascade source
|
||||||
|
pub enb_stop_src_csd2: bool,
|
||||||
|
/// Invert Cascade 2, making it active low
|
||||||
|
pub inv_csd2: bool,
|
||||||
|
/// The counter is automatically disabled if the corresponding Cascade 2 level-sensitive input
|
||||||
|
/// souce is active when the count reaches 0. If the counter is not 0, the cascade control is
|
||||||
|
/// ignored
|
||||||
|
pub trg_csd2: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum CascadeSel {
|
||||||
|
Sel0 = 0,
|
||||||
|
Sel1 = 1,
|
||||||
|
Sel2 = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct InvalidCascadeSourceId;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum CascadeSource {
|
||||||
|
PortA(u8),
|
||||||
|
PortB(u8),
|
||||||
|
PortC(u8),
|
||||||
|
PortD(u8),
|
||||||
|
PortE(u8),
|
||||||
|
Tim(u8),
|
||||||
|
TxEv,
|
||||||
|
AdcIrq,
|
||||||
|
RomSbe,
|
||||||
|
RomMbe,
|
||||||
|
Ram0Sbe,
|
||||||
|
Ram0Mbe,
|
||||||
|
Ram1Sbe,
|
||||||
|
Ram2Mbe,
|
||||||
|
WdogIrq,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CascadeSource {
|
||||||
|
fn id(&self) -> Result<u8, InvalidCascadeSourceId> {
|
||||||
|
let port_check = |base: u8, id: u8| {
|
||||||
|
if id > 15 {
|
||||||
|
return Err(InvalidCascadeSourceId);
|
||||||
|
}
|
||||||
|
Ok(base + id)
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
CascadeSource::PortA(id) => port_check(0, *id),
|
||||||
|
CascadeSource::PortB(id) => port_check(16, *id),
|
||||||
|
CascadeSource::PortC(id) => port_check(32, *id),
|
||||||
|
CascadeSource::PortD(id) => port_check(48, *id),
|
||||||
|
CascadeSource::PortE(id) => port_check(65, *id),
|
||||||
|
CascadeSource::Tim(id) => {
|
||||||
|
if *id > 23 {
|
||||||
|
return Err(InvalidCascadeSourceId);
|
||||||
|
}
|
||||||
|
Ok(80 + id)
|
||||||
|
}
|
||||||
|
CascadeSource::TxEv => Ok(104),
|
||||||
|
CascadeSource::AdcIrq => Ok(105),
|
||||||
|
CascadeSource::RomSbe => Ok(106),
|
||||||
|
CascadeSource::RomMbe => Ok(106),
|
||||||
|
CascadeSource::Ram0Sbe => Ok(108),
|
||||||
|
CascadeSource::Ram0Mbe => Ok(109),
|
||||||
|
CascadeSource::Ram1Sbe => Ok(110),
|
||||||
|
CascadeSource::Ram2Mbe => Ok(111),
|
||||||
|
CascadeSource::WdogIrq => Ok(112),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Valid TIM and PIN combinations
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub trait TimPin {
|
||||||
|
const DYN: DynPinId;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ValidTim {
|
||||||
|
// TIM ID ranging from 0 to 23 for 24 TIM peripherals
|
||||||
|
const TIM_ID: u8;
|
||||||
|
const IRQ: pac::Interrupt;
|
||||||
|
|
||||||
|
fn clock(clocks: &Clocks) -> Hertz {
|
||||||
|
if Self::TIM_ID <= 15 {
|
||||||
|
clocks.apb1()
|
||||||
|
} else {
|
||||||
|
clocks.apb2()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! tim_markers {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
($TimX:path, $id:expr, $Irq:path),
|
||||||
|
)+
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
impl ValidTim for $TimX {
|
||||||
|
const TIM_ID: u8 = $id;
|
||||||
|
const IRQ: pac::Interrupt = $Irq;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tim_markers!(
|
||||||
|
(pac::Tim0, 0, pac::Interrupt::TIM0),
|
||||||
|
(pac::Tim1, 1, pac::Interrupt::TIM1),
|
||||||
|
(pac::Tim2, 2, pac::Interrupt::TIM2),
|
||||||
|
(pac::Tim3, 3, pac::Interrupt::TIM3),
|
||||||
|
(pac::Tim4, 4, pac::Interrupt::TIM4),
|
||||||
|
(pac::Tim5, 5, pac::Interrupt::TIM5),
|
||||||
|
(pac::Tim6, 6, pac::Interrupt::TIM6),
|
||||||
|
(pac::Tim7, 7, pac::Interrupt::TIM7),
|
||||||
|
(pac::Tim8, 8, pac::Interrupt::TIM8),
|
||||||
|
(pac::Tim9, 9, pac::Interrupt::TIM9),
|
||||||
|
(pac::Tim10, 10, pac::Interrupt::TIM10),
|
||||||
|
(pac::Tim11, 11, pac::Interrupt::TIM11),
|
||||||
|
(pac::Tim12, 12, pac::Interrupt::TIM12),
|
||||||
|
(pac::Tim13, 13, pac::Interrupt::TIM13),
|
||||||
|
(pac::Tim14, 14, pac::Interrupt::TIM14),
|
||||||
|
(pac::Tim15, 15, pac::Interrupt::TIM15),
|
||||||
|
(pac::Tim16, 16, pac::Interrupt::TIM16),
|
||||||
|
(pac::Tim17, 17, pac::Interrupt::TIM17),
|
||||||
|
(pac::Tim18, 18, pac::Interrupt::TIM18),
|
||||||
|
(pac::Tim19, 19, pac::Interrupt::TIM19),
|
||||||
|
(pac::Tim20, 20, pac::Interrupt::TIM20),
|
||||||
|
(pac::Tim21, 21, pac::Interrupt::TIM21),
|
||||||
|
(pac::Tim22, 22, pac::Interrupt::TIM22),
|
||||||
|
(pac::Tim23, 23, pac::Interrupt::TIM23),
|
||||||
|
);
|
||||||
|
|
||||||
|
pub trait ValidTimAndPin<Pin: TimPin, Tim: ValidTim>: Sealed {}
|
||||||
|
|
||||||
|
macro_rules! valid_pin_and_tims {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
($PinX:ident, $AltFunc:ident, $TimX:path),
|
||||||
|
)+
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
impl TimPin for Pin<$PinX, $AltFunc>
|
||||||
|
where
|
||||||
|
$PinX: PinId,
|
||||||
|
{
|
||||||
|
const DYN: DynPinId = $PinX::DYN;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
PinInstance: TimPin,
|
||||||
|
Tim: ValidTim
|
||||||
|
> ValidTimAndPin<PinInstance, Tim> for (Pin<$PinX, $AltFunc>, $TimX)
|
||||||
|
where
|
||||||
|
Pin<$PinX, $AltFunc>: TimPin,
|
||||||
|
$PinX: PinId,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sealed for (Pin<$PinX, $AltFunc>, $TimX) {}
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
valid_pin_and_tims!(
|
||||||
|
(PA0, AltFunc1, pac::Tim0),
|
||||||
|
(PA1, AltFunc1, pac::Tim1),
|
||||||
|
(PA2, AltFunc1, pac::Tim2),
|
||||||
|
(PA3, AltFunc1, pac::Tim3),
|
||||||
|
(PA4, AltFunc1, pac::Tim4),
|
||||||
|
(PA5, AltFunc1, pac::Tim5),
|
||||||
|
(PA6, AltFunc1, pac::Tim6),
|
||||||
|
(PA7, AltFunc1, pac::Tim7),
|
||||||
|
(PA10, AltFunc2, pac::Tim23),
|
||||||
|
(PA11, AltFunc2, pac::Tim22),
|
||||||
|
(PA12, AltFunc2, pac::Tim21),
|
||||||
|
(PA13, AltFunc2, pac::Tim20),
|
||||||
|
(PA14, AltFunc2, pac::Tim19),
|
||||||
|
(PA15, AltFunc2, pac::Tim18),
|
||||||
|
(PB0, AltFunc2, pac::Tim17),
|
||||||
|
(PB1, AltFunc2, pac::Tim16),
|
||||||
|
(PB2, AltFunc2, pac::Tim15),
|
||||||
|
(PB3, AltFunc2, pac::Tim14),
|
||||||
|
(PB4, AltFunc2, pac::Tim13),
|
||||||
|
(PB5, AltFunc2, pac::Tim12),
|
||||||
|
(PB6, AltFunc2, pac::Tim11),
|
||||||
|
(PB7, AltFunc2, pac::Tim10),
|
||||||
|
(PB8, AltFunc2, pac::Tim9),
|
||||||
|
(PB9, AltFunc2, pac::Tim8),
|
||||||
|
(PB10, AltFunc2, pac::Tim7),
|
||||||
|
(PB11, AltFunc2, pac::Tim6),
|
||||||
|
(PB12, AltFunc2, pac::Tim5),
|
||||||
|
(PB13, AltFunc2, pac::Tim4),
|
||||||
|
(PB14, AltFunc2, pac::Tim3),
|
||||||
|
(PB15, AltFunc2, pac::Tim2),
|
||||||
|
(PC0, AltFunc2, pac::Tim1),
|
||||||
|
(PC1, AltFunc2, pac::Tim0),
|
||||||
|
(PD0, AltFunc2, pac::Tim0),
|
||||||
|
(PD1, AltFunc2, pac::Tim1),
|
||||||
|
(PD2, AltFunc2, pac::Tim2),
|
||||||
|
(PD3, AltFunc2, pac::Tim3),
|
||||||
|
(PD4, AltFunc2, pac::Tim4),
|
||||||
|
(PD5, AltFunc2, pac::Tim5),
|
||||||
|
(PD6, AltFunc2, pac::Tim6),
|
||||||
|
(PD7, AltFunc2, pac::Tim7),
|
||||||
|
(PD8, AltFunc2, pac::Tim8),
|
||||||
|
(PD9, AltFunc2, pac::Tim9),
|
||||||
|
(PD10, AltFunc2, pac::Tim10),
|
||||||
|
(PD11, AltFunc2, pac::Tim11),
|
||||||
|
(PD12, AltFunc2, pac::Tim12),
|
||||||
|
(PD13, AltFunc2, pac::Tim13),
|
||||||
|
(PD14, AltFunc2, pac::Tim14),
|
||||||
|
(PD15, AltFunc2, pac::Tim15),
|
||||||
|
(PE0, AltFunc2, pac::Tim16),
|
||||||
|
(PE1, AltFunc2, pac::Tim17),
|
||||||
|
(PE2, AltFunc2, pac::Tim18),
|
||||||
|
(PE3, AltFunc2, pac::Tim19),
|
||||||
|
(PE4, AltFunc2, pac::Tim20),
|
||||||
|
(PE5, AltFunc2, pac::Tim21),
|
||||||
|
(PE6, AltFunc2, pac::Tim22),
|
||||||
|
(PE7, AltFunc2, pac::Tim23),
|
||||||
|
(PE8, AltFunc3, pac::Tim16),
|
||||||
|
(PE9, AltFunc3, pac::Tim17),
|
||||||
|
(PE10, AltFunc3, pac::Tim18),
|
||||||
|
(PE11, AltFunc3, pac::Tim19),
|
||||||
|
(PE12, AltFunc3, pac::Tim20),
|
||||||
|
(PE13, AltFunc3, pac::Tim21),
|
||||||
|
(PE14, AltFunc3, pac::Tim22),
|
||||||
|
(PE15, AltFunc3, pac::Tim23),
|
||||||
|
(PF0, AltFunc3, pac::Tim0),
|
||||||
|
(PF1, AltFunc3, pac::Tim1),
|
||||||
|
(PF2, AltFunc3, pac::Tim2),
|
||||||
|
(PF3, AltFunc3, pac::Tim3),
|
||||||
|
(PF4, AltFunc3, pac::Tim4),
|
||||||
|
(PF5, AltFunc3, pac::Tim5),
|
||||||
|
(PF6, AltFunc3, pac::Tim6),
|
||||||
|
(PF7, AltFunc3, pac::Tim7),
|
||||||
|
(PF8, AltFunc3, pac::Tim8),
|
||||||
|
(PF9, AltFunc3, pac::Tim9),
|
||||||
|
(PF10, AltFunc3, pac::Tim10),
|
||||||
|
(PF11, AltFunc3, pac::Tim11),
|
||||||
|
(PF12, AltFunc3, pac::Tim12),
|
||||||
|
(PF13, AltFunc2, pac::Tim19),
|
||||||
|
(PF14, AltFunc2, pac::Tim20),
|
||||||
|
(PF15, AltFunc2, pac::Tim21),
|
||||||
|
(PG0, AltFunc2, pac::Tim22),
|
||||||
|
(PG1, AltFunc2, pac::Tim23),
|
||||||
|
(PG2, AltFunc1, pac::Tim9),
|
||||||
|
(PG3, AltFunc1, pac::Tim10),
|
||||||
|
(PG6, AltFunc1, pac::Tim12),
|
||||||
|
);
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Register Interface for TIM registers and TIM pins
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Clear the reset bit of the TIM, holding it in reset
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Only the bit related to the corresponding TIM peripheral is modified
|
||||||
|
#[inline]
|
||||||
|
fn assert_tim_reset(syscfg: &mut pac::Sysconfig, tim_id: u8) {
|
||||||
|
syscfg
|
||||||
|
.tim_reset()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << tim_id as u32)) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deassert_tim_reset(syscfg: &mut pac::Sysconfig, tim_id: u8) {
|
||||||
|
syscfg
|
||||||
|
.tim_reset()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << tim_id as u32)) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TimRegBlock = pac::tim0::RegisterBlock;
|
||||||
|
|
||||||
|
/// Register interface.
|
||||||
|
///
|
||||||
|
/// This interface provides valid TIM pins a way to access their corresponding TIM
|
||||||
|
/// registers
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Users should only implement the [`tim_id`] function. No default function
|
||||||
|
/// implementations should be overridden. The implementing type must also have
|
||||||
|
/// "control" over the corresponding pin ID, i.e. it must guarantee that a each
|
||||||
|
/// pin ID is a singleton.
|
||||||
|
pub(super) unsafe trait TimRegInterface {
|
||||||
|
fn tim_id(&self) -> u8;
|
||||||
|
|
||||||
|
const PORT_BASE: *const pac::tim0::RegisterBlock = pac::Tim0::ptr() as *const _;
|
||||||
|
|
||||||
|
/// All 24 TIM blocks are identical. This helper functions returns the correct
|
||||||
|
/// memory mapped peripheral depending on the TIM ID.
|
||||||
|
#[inline(always)]
|
||||||
|
fn reg(&self) -> &TimRegBlock {
|
||||||
|
unsafe { &*Self::PORT_BASE.offset(self.tim_id() as isize) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn mask_32(&self) -> u32 {
|
||||||
|
1 << self.tim_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the reset bit of the TIM, holding it in reset
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Only the bit related to the corresponding TIM peripheral is modified
|
||||||
|
#[inline]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn assert_tim_reset(&self, syscfg: &mut pac::Sysconfig) {
|
||||||
|
assert_tim_reset(syscfg, self.tim_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn deassert_time_reset(&self, syscfg: &mut pac::Sysconfig) {
|
||||||
|
deassert_tim_reset(syscfg, self.tim_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provide a safe register interface for [`ValidTimAndPin`]s
|
||||||
|
///
|
||||||
|
/// This `struct` takes ownership of a [`ValidTimAndPin`] and provides an API to
|
||||||
|
/// access the corresponding registers.
|
||||||
|
pub(super) struct TimAndPinRegister<Pin: TimPin, Tim: ValidTim> {
|
||||||
|
pin: Pin,
|
||||||
|
tim: Tim,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct TimRegister<TIM: ValidTim> {
|
||||||
|
tim: TIM,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TIM: ValidTim> TimRegister<TIM> {
|
||||||
|
#[inline]
|
||||||
|
pub(super) unsafe fn new(tim: TIM) -> Self {
|
||||||
|
TimRegister { tim }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn release(self) -> TIM {
|
||||||
|
self.tim
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<Tim: ValidTim> TimRegInterface for TimRegister<Tim> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn tim_id(&self) -> u8 {
|
||||||
|
Tim::TIM_ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> TimAndPinRegister<Pin, Tim>
|
||||||
|
where
|
||||||
|
(Pin, Tim): ValidTimAndPin<Pin, Tim>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
pub(super) unsafe fn new(pin: Pin, tim: Tim) -> Self {
|
||||||
|
TimAndPinRegister { pin, tim }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn release(self) -> (Pin, Tim) {
|
||||||
|
(self.pin, self.tim)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<Pin: TimPin, Tim: ValidTim> TimRegInterface for TimAndPinRegister<Pin, Tim> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn tim_id(&self) -> u8 {
|
||||||
|
Tim::TIM_ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct TimDynRegister {
|
||||||
|
tim_id: u8,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pin_id: DynPinId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> From<TimAndPinRegister<Pin, Tim>> for TimDynRegister {
|
||||||
|
fn from(_reg: TimAndPinRegister<Pin, Tim>) -> Self {
|
||||||
|
Self {
|
||||||
|
tim_id: Tim::TIM_ID,
|
||||||
|
pin_id: Pin::DYN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl TimRegInterface for TimDynRegister {
|
||||||
|
#[inline(always)]
|
||||||
|
fn tim_id(&self) -> u8 {
|
||||||
|
self.tim_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Timers
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
/// Hardware timers
|
||||||
|
pub struct CountdownTimer<TIM: ValidTim> {
|
||||||
|
tim: TimRegister<TIM>,
|
||||||
|
curr_freq: Hertz,
|
||||||
|
clock: Hertz,
|
||||||
|
rst_val: u32,
|
||||||
|
last_cnt: u32,
|
||||||
|
listening: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn enable_tim_clk(syscfg: &mut pac::Sysconfig, idx: u8) {
|
||||||
|
syscfg
|
||||||
|
.tim_clk_enable()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << idx)) });
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<TIM: ValidTim> TimRegInterface for CountdownTimer<TIM> {
|
||||||
|
#[inline]
|
||||||
|
fn tim_id(&self) -> u8 {
|
||||||
|
TIM::TIM_ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Tim: ValidTim> CountdownTimer<Tim> {
|
||||||
|
/// Create a new countdown timer, but does not start it.
|
||||||
|
///
|
||||||
|
/// You can use [Self::start] to start the countdown timer, and you may optionally call
|
||||||
|
/// [Self::listen] to enable interrupts for the TIM peripheral as well.
|
||||||
|
pub fn new(syscfg: &mut pac::Sysconfig, tim: Tim, clocks: &Clocks) -> Self {
|
||||||
|
enable_tim_clk(syscfg, Tim::TIM_ID);
|
||||||
|
assert_tim_reset(syscfg, Tim::TIM_ID);
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
deassert_tim_reset(syscfg, Tim::TIM_ID);
|
||||||
|
|
||||||
|
CountdownTimer {
|
||||||
|
tim: unsafe { TimRegister::new(tim) },
|
||||||
|
clock: Tim::clock(clocks),
|
||||||
|
rst_val: 0,
|
||||||
|
curr_freq: 0_u32.Hz(),
|
||||||
|
listening: false,
|
||||||
|
last_cnt: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn start(&mut self, timeout: impl Into<Hertz>) {
|
||||||
|
self.load(timeout);
|
||||||
|
self.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Listen for events. Depending on the IRQ configuration, this also activates the IRQ in the
|
||||||
|
/// IRQSEL peripheral for the provided interrupt and unmasks the interrupt
|
||||||
|
pub fn listen(&mut self) {
|
||||||
|
self.listening = true;
|
||||||
|
self.enable_interrupt();
|
||||||
|
unsafe { enable_interrupt(Tim::IRQ) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return `Ok` if the timer has wrapped. Peripheral will automatically clear the
|
||||||
|
/// flag and restart the time if configured correctly
|
||||||
|
pub fn wait(&mut self) -> nb::Result<(), void::Void> {
|
||||||
|
let cnt = self.tim.reg().cnt_value().read().bits();
|
||||||
|
if (cnt > self.last_cnt) || cnt == 0 {
|
||||||
|
self.last_cnt = self.rst_val;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
self.last_cnt = cnt;
|
||||||
|
Err(nb::Error::WouldBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&mut self) {
|
||||||
|
self.tim.reg().ctrl().write(|w| w.enable().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unlisten(&mut self) {
|
||||||
|
self.listening = true;
|
||||||
|
self.disable_interrupt();
|
||||||
|
disable_interrupt(Tim::IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn enable_interrupt(&mut self) {
|
||||||
|
self.tim.reg().ctrl().modify(|_, w| w.irq_enb().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn disable_interrupt(&mut self) {
|
||||||
|
self.tim.reg().ctrl().modify(|_, w| w.irq_enb().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(self, syscfg: &mut pac::Sysconfig) -> Tim {
|
||||||
|
self.tim.reg().ctrl().write(|w| w.enable().clear_bit());
|
||||||
|
syscfg
|
||||||
|
.tim_clk_enable()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << Tim::TIM_ID)) });
|
||||||
|
self.tim.release()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load the count down timer with a timeout but do not start it.
|
||||||
|
pub fn load(&mut self, timeout: impl Into<Hertz>) {
|
||||||
|
self.tim.reg().ctrl().modify(|_, w| w.enable().clear_bit());
|
||||||
|
self.curr_freq = timeout.into();
|
||||||
|
self.rst_val = self.clock.raw() / self.curr_freq.raw();
|
||||||
|
self.set_reload(self.rst_val);
|
||||||
|
self.set_count(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_reload(&mut self, val: u32) {
|
||||||
|
self.tim.reg().rst_value().write(|w| unsafe { w.bits(val) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_count(&mut self, val: u32) {
|
||||||
|
self.tim.reg().cnt_value().write(|w| unsafe { w.bits(val) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn count(&self) -> u32 {
|
||||||
|
self.tim.reg().cnt_value().read().bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn enable(&mut self) {
|
||||||
|
self.tim.reg().ctrl().modify(|_, w| w.enable().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn disable(&mut self) {
|
||||||
|
self.tim.reg().ctrl().modify(|_, w| w.enable().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable the counter, setting both enable and active bit to 0
|
||||||
|
#[inline]
|
||||||
|
pub fn auto_disable(self, enable: bool) -> Self {
|
||||||
|
if enable {
|
||||||
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.ctrl()
|
||||||
|
.modify(|_, w| w.auto_disable().set_bit());
|
||||||
|
} else {
|
||||||
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.ctrl()
|
||||||
|
.modify(|_, w| w.auto_disable().clear_bit());
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This option only applies when the Auto-Disable functionality is 0.
|
||||||
|
///
|
||||||
|
/// The active bit is changed to 0 when count reaches 0, but the counter stays
|
||||||
|
/// enabled. When Auto-Disable is 1, Auto-Deactivate is implied
|
||||||
|
#[inline]
|
||||||
|
pub fn auto_deactivate(self, enable: bool) -> Self {
|
||||||
|
if enable {
|
||||||
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.ctrl()
|
||||||
|
.modify(|_, w| w.auto_deactivate().set_bit());
|
||||||
|
} else {
|
||||||
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.ctrl()
|
||||||
|
.modify(|_, w| w.auto_deactivate().clear_bit());
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the cascade parameters
|
||||||
|
#[inline]
|
||||||
|
pub fn cascade_control(&mut self, ctrl: CascadeCtrl) {
|
||||||
|
self.tim.reg().csd_ctrl().write(|w| {
|
||||||
|
w.csden0().bit(ctrl.enb_start_src_csd0);
|
||||||
|
w.csdinv0().bit(ctrl.inv_csd0);
|
||||||
|
w.csden1().bit(ctrl.enb_start_src_csd1);
|
||||||
|
w.csdinv1().bit(ctrl.inv_csd1);
|
||||||
|
w.dcasop().bit(ctrl.dual_csd_op);
|
||||||
|
w.csdtrg0().bit(ctrl.trg_csd0);
|
||||||
|
w.csdtrg1().bit(ctrl.trg_csd1);
|
||||||
|
w.csden2().bit(ctrl.enb_stop_src_csd2);
|
||||||
|
w.csdinv2().bit(ctrl.inv_csd2);
|
||||||
|
w.csdtrg2().bit(ctrl.trg_csd2)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cascade_0_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
|
||||||
|
let id = src.id()?;
|
||||||
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.cascade0()
|
||||||
|
.write(|w| unsafe { w.cassel().bits(id) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cascade_1_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
|
||||||
|
let id = src.id()?;
|
||||||
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.cascade1()
|
||||||
|
.write(|w| unsafe { w.cassel().bits(id) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cascade_2_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
|
||||||
|
let id = src.id()?;
|
||||||
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.cascade2()
|
||||||
|
.write(|w| unsafe { w.cassel().bits(id) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn curr_freq(&self) -> Hertz {
|
||||||
|
self.curr_freq
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn listening(&self) -> bool {
|
||||||
|
self.listening
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Tim: ValidTim> embedded_hal::delay::DelayNs for CountdownTimer<Tim> {
|
||||||
|
fn delay_ns(&mut self, ns: u32) {
|
||||||
|
let ticks = (u64::from(ns)) * (u64::from(self.clock.raw())) / 1_000_000_000;
|
||||||
|
|
||||||
|
let full_cycles = ticks >> 32;
|
||||||
|
let mut last_count;
|
||||||
|
let mut new_count;
|
||||||
|
if full_cycles > 0 {
|
||||||
|
self.set_reload(u32::MAX);
|
||||||
|
self.set_count(u32::MAX);
|
||||||
|
self.enable();
|
||||||
|
|
||||||
|
for _ in 0..full_cycles {
|
||||||
|
// Always ensure that both values are the same at the start.
|
||||||
|
new_count = self.count();
|
||||||
|
last_count = new_count;
|
||||||
|
loop {
|
||||||
|
new_count = self.count();
|
||||||
|
if new_count == 0 {
|
||||||
|
// Wait till timer has wrapped.
|
||||||
|
while self.count() == 0 {
|
||||||
|
cortex_m::asm::nop()
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Timer has definitely wrapped.
|
||||||
|
if new_count > last_count {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_count = new_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let ticks = (ticks & u32::MAX as u64) as u32;
|
||||||
|
self.disable();
|
||||||
|
if ticks > 1 {
|
||||||
|
self.set_reload(ticks);
|
||||||
|
self.set_count(ticks);
|
||||||
|
self.enable();
|
||||||
|
last_count = ticks;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
new_count = self.count();
|
||||||
|
if new_count == 0 || (new_count > last_count) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_count = new_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// MS tick implementations
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
// Set up a millisecond timer on TIM0. Please note that the user still has to provide an IRQ handler
|
||||||
|
// which should call [default_ms_irq_handler].
|
||||||
|
pub fn set_up_ms_tick<Tim: ValidTim>(
|
||||||
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
|
tim: Tim,
|
||||||
|
clocks: &Clocks,
|
||||||
|
) -> CountdownTimer<Tim> {
|
||||||
|
let mut ms_timer = CountdownTimer::new(sys_cfg, tim, clocks);
|
||||||
|
ms_timer.listen();
|
||||||
|
ms_timer.start(1000.Hz());
|
||||||
|
ms_timer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function can be called in a specified interrupt handler to increment
|
||||||
|
/// the MS counter
|
||||||
|
pub fn default_ms_irq_handler() {
|
||||||
|
cortex_m::interrupt::free(|cs| {
|
||||||
|
let mut ms = MS_COUNTER.borrow(cs).get();
|
||||||
|
ms += 1;
|
||||||
|
MS_COUNTER.borrow(cs).set(ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current MS tick count
|
||||||
|
pub fn get_ms_ticks() -> u32 {
|
||||||
|
cortex_m::interrupt::free(|cs| MS_COUNTER.borrow(cs).get())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DelayMs<Tim: ValidTim = pac::Tim0>(CountdownTimer<Tim>);
|
||||||
|
|
||||||
|
impl<Tim: ValidTim> DelayMs<Tim> {
|
||||||
|
pub fn new(timer: CountdownTimer<Tim>) -> Option<Self> {
|
||||||
|
if timer.curr_freq() != Hertz::from_raw(1000) || !timer.listening() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Self(timer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This assumes that the user has already set up a MS tick timer with [set_up_ms_tick]
|
||||||
|
impl embedded_hal::delay::DelayNs for DelayMs {
|
||||||
|
fn delay_ns(&mut self, ns: u32) {
|
||||||
|
let ns_as_ms = ns / 1_000_000;
|
||||||
|
if self.0.curr_freq() != Hertz::from_raw(1000) || !self.0.listening() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let start_time = get_ms_ticks();
|
||||||
|
while get_ms_ticks() - start_time < ns_as_ms {
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
155
va416xx-hal/src/typelevel.rs
Normal file
155
va416xx-hal/src/typelevel.rs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
//! Module supporting type-level programming
|
||||||
|
//!
|
||||||
|
//! This module is identical to the
|
||||||
|
//! [atsamd typelevel](https://docs.rs/atsamd-hal/latest/atsamd_hal/typelevel/index.html).
|
||||||
|
|
||||||
|
use core::ops::{Add, Sub};
|
||||||
|
|
||||||
|
use typenum::{Add1, Bit, Sub1, UInt, Unsigned, B1, U0};
|
||||||
|
|
||||||
|
mod private {
|
||||||
|
/// Super trait used to mark traits with an exhaustive set of
|
||||||
|
/// implementations
|
||||||
|
pub trait Sealed {}
|
||||||
|
|
||||||
|
impl Sealed for u8 {}
|
||||||
|
impl Sealed for i8 {}
|
||||||
|
impl Sealed for u16 {}
|
||||||
|
impl Sealed for i16 {}
|
||||||
|
impl Sealed for u32 {}
|
||||||
|
impl Sealed for i32 {}
|
||||||
|
impl Sealed for f32 {}
|
||||||
|
|
||||||
|
/// Mapping from an instance of a countable type to its successor
|
||||||
|
pub trait Increment {
|
||||||
|
/// Successor type of `Self`
|
||||||
|
type Inc;
|
||||||
|
/// Consume an instance of `Self` and return its successor
|
||||||
|
fn inc(self) -> Self::Inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mapping from an instance of a countable type to its predecessor
|
||||||
|
pub trait Decrement {
|
||||||
|
/// Predecessor type of `Self`
|
||||||
|
type Dec;
|
||||||
|
/// Consume an instance of `Self` and return its predecessor
|
||||||
|
fn dec(self) -> Self::Dec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use private::Decrement as PrivateDecrement;
|
||||||
|
pub(crate) use private::Increment as PrivateIncrement;
|
||||||
|
pub(crate) use private::Sealed;
|
||||||
|
|
||||||
|
/// Type-level version of the [`None`] variant
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct NoneT;
|
||||||
|
|
||||||
|
impl Sealed for NoneT {}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Is
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/// Marker trait for type identity
|
||||||
|
///
|
||||||
|
/// This trait is used as part of the [`AnyKind`] trait pattern. It represents
|
||||||
|
/// the concept of type identity, because all implementors have
|
||||||
|
/// `<Self as Is>::Type == Self`. When used as a trait bound with a specific
|
||||||
|
/// type, it guarantees that the corresponding type parameter is exactly the
|
||||||
|
/// specific type. Stated differently, it guarantees that `T == Specific` in
|
||||||
|
/// the following example.
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// where T: Is<Type = Specific>
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Moreover, the super traits guarantee that any instance of or reference to a
|
||||||
|
/// type `T` can be converted into the `Specific` type.
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// fn example<T>(mut any: T)
|
||||||
|
/// where
|
||||||
|
/// T: Is<Type = Specific>,
|
||||||
|
/// {
|
||||||
|
/// let specific_mut: &mut Specific = any.as_mut();
|
||||||
|
/// let specific_ref: &Specific = any.as_ref();
|
||||||
|
/// let specific: Specific = any.into();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`AnyKind`]: #anykind-trait-pattern
|
||||||
|
pub trait Is
|
||||||
|
where
|
||||||
|
Self: Sealed,
|
||||||
|
Self: From<IsType<Self>>,
|
||||||
|
Self: Into<IsType<Self>>,
|
||||||
|
Self: AsRef<IsType<Self>>,
|
||||||
|
Self: AsMut<IsType<Self>>,
|
||||||
|
{
|
||||||
|
type Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type alias for [`Is::Type`]
|
||||||
|
pub type IsType<T> = <T as Is>::Type;
|
||||||
|
|
||||||
|
impl<T> Is for T
|
||||||
|
where
|
||||||
|
T: Sealed + AsRef<T> + AsMut<T>,
|
||||||
|
{
|
||||||
|
type Type = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Counting
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/// Implement `Sealed` for [`U0`]
|
||||||
|
impl Sealed for U0 {}
|
||||||
|
|
||||||
|
/// Implement `Sealed` for all type-level, [`Unsigned`] integers *except* [`U0`]
|
||||||
|
impl<U: Unsigned, B: Bit> Sealed for UInt<U, B> {}
|
||||||
|
|
||||||
|
/// Trait mapping each countable type to its successor
|
||||||
|
///
|
||||||
|
/// This trait maps each countable type to its corresponding successor type. The
|
||||||
|
/// actual implementation of this trait is contained within `PrivateIncrement`.
|
||||||
|
/// Access to `PrivateIncrement` is restricted, so that safe HAL APIs can be
|
||||||
|
/// built with it.
|
||||||
|
pub trait Increment: PrivateIncrement {}
|
||||||
|
|
||||||
|
impl<T: PrivateIncrement> Increment for T {}
|
||||||
|
|
||||||
|
/// Trait mapping each countable type to its predecessor
|
||||||
|
///
|
||||||
|
/// This trait maps each countable type to its corresponding predecessor type.
|
||||||
|
/// The actual implementation of this trait is contained within
|
||||||
|
/// `PrivateDecrement`. Access to `PrivateDecrement` is restricted, so that safe
|
||||||
|
/// HAL APIs can be built with it.
|
||||||
|
pub trait Decrement: PrivateDecrement {}
|
||||||
|
|
||||||
|
impl<T: PrivateDecrement> Decrement for T {}
|
||||||
|
|
||||||
|
impl<N> PrivateIncrement for N
|
||||||
|
where
|
||||||
|
N: Unsigned + Add<B1>,
|
||||||
|
Add1<N>: Unsigned,
|
||||||
|
{
|
||||||
|
type Inc = Add1<N>;
|
||||||
|
#[inline]
|
||||||
|
fn inc(self) -> Self::Inc {
|
||||||
|
Self::Inc::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N> PrivateDecrement for N
|
||||||
|
where
|
||||||
|
N: Unsigned + Sub<B1>,
|
||||||
|
Sub1<N>: Unsigned,
|
||||||
|
{
|
||||||
|
type Dec = Sub1<N>;
|
||||||
|
#[inline]
|
||||||
|
fn dec(self) -> Self::Dec {
|
||||||
|
Self::Dec::default()
|
||||||
|
}
|
||||||
|
}
|
1014
va416xx-hal/src/uart.rs
Normal file
1014
va416xx-hal/src/uart.rs
Normal file
File diff suppressed because it is too large
Load Diff
118
va416xx-hal/src/wdt.rs
Normal file
118
va416xx-hal/src/wdt.rs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
//! # API for the Watchdog peripheral
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! - [Watchdog simple example](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/examples/simple/examples/wdt.rs)
|
||||||
|
use crate::time::Hertz;
|
||||||
|
use crate::{
|
||||||
|
clock::{Clocks, PeripheralSelect},
|
||||||
|
pac,
|
||||||
|
prelude::SyscfgExt,
|
||||||
|
};
|
||||||
|
use crate::{disable_interrupt, enable_interrupt};
|
||||||
|
|
||||||
|
pub const WDT_UNLOCK_VALUE: u32 = 0x1ACC_E551;
|
||||||
|
|
||||||
|
pub struct WdtController {
|
||||||
|
clock_freq: Hertz,
|
||||||
|
wdt: pac::WatchDog,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable the watchdog interrupt
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is `unsafe` because it can break mask-based critical sections.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn enable_wdt_interrupts() {
|
||||||
|
enable_interrupt(pac::Interrupt::WATCHDOG)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_wdt_interrupts() {
|
||||||
|
disable_interrupt(pac::Interrupt::WATCHDOG)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WdtController {
|
||||||
|
pub fn new(
|
||||||
|
&self,
|
||||||
|
syscfg: &mut pac::Sysconfig,
|
||||||
|
wdt: pac::WatchDog,
|
||||||
|
clocks: &Clocks,
|
||||||
|
wdt_freq_ms: u32,
|
||||||
|
) -> Self {
|
||||||
|
Self::start(syscfg, wdt, clocks, wdt_freq_ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(
|
||||||
|
syscfg: &mut pac::Sysconfig,
|
||||||
|
wdt: pac::WatchDog,
|
||||||
|
clocks: &Clocks,
|
||||||
|
wdt_freq_ms: u32,
|
||||||
|
) -> Self {
|
||||||
|
syscfg.enable_peripheral_clock(PeripheralSelect::Watchdog);
|
||||||
|
// It's done like that in Vorago examples. Not exactly sure why the reset is necessary
|
||||||
|
// though..
|
||||||
|
syscfg.assert_periph_reset(PeripheralSelect::Watchdog);
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
syscfg.deassert_periph_reset(PeripheralSelect::Watchdog);
|
||||||
|
|
||||||
|
let wdt_clock = clocks.apb2();
|
||||||
|
let mut wdt_ctrl = Self {
|
||||||
|
clock_freq: wdt_clock,
|
||||||
|
wdt,
|
||||||
|
};
|
||||||
|
wdt_ctrl.set_freq(wdt_freq_ms);
|
||||||
|
wdt_ctrl.wdt.wdogcontrol().write(|w| w.inten().set_bit());
|
||||||
|
wdt_ctrl.feed();
|
||||||
|
// Unmask the watchdog interrupt
|
||||||
|
unsafe {
|
||||||
|
enable_wdt_interrupts();
|
||||||
|
}
|
||||||
|
wdt_ctrl
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_freq(&mut self, freq_ms: u32) {
|
||||||
|
let counter = (self.clock_freq.raw() / 1000) * freq_ms;
|
||||||
|
self.wdt.wdogload().write(|w| unsafe { w.bits(counter) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_reset(&mut self) {
|
||||||
|
self.wdt.wdogcontrol().modify(|_, w| w.resen().clear_bit())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_reset(&mut self) {
|
||||||
|
self.wdt.wdogcontrol().modify(|_, w| w.resen().set_bit())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn counter(&self) -> u32 {
|
||||||
|
self.wdt.wdogvalue().read().bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn feed(&self) {
|
||||||
|
self.wdt.wdogintclr().write(|w| unsafe { w.bits(1) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn lock(&self) {
|
||||||
|
self.wdt.wdoglock().write(|w| unsafe { w.bits(0) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn unlock(&self) {
|
||||||
|
self.wdt
|
||||||
|
.wdoglock()
|
||||||
|
.write(|w| unsafe { w.bits(WDT_UNLOCK_VALUE) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_locked(&self) -> bool {
|
||||||
|
self.wdt.wdogload().read().bits() == 1
|
||||||
|
}
|
||||||
|
}
|
2
va416xx/.github/bors.toml
vendored
Normal file
2
va416xx/.github/bors.toml
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
status = ["ci"]
|
||||||
|
delete_merged_branches = true
|
20
va416xx/.github/workflows/changelog.yml
vendored
Normal file
20
va416xx/.github/workflows/changelog.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
|
||||||
|
name: Changelog check
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
changelog:
|
||||||
|
name: Changelog check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Changelog updated
|
||||||
|
uses: Zomzog/changelog-checker@v1.2.0
|
||||||
|
with:
|
||||||
|
fileName: CHANGELOG.md
|
||||||
|
noChangelogLabel: no changelog
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
64
va416xx/.github/workflows/ci.yml
vendored
Normal file
64
va416xx/.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
on: [push]
|
||||||
|
|
||||||
|
name: build
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
target: thumbv7em-none-eabihf
|
||||||
|
override: true
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
use-cross: true
|
||||||
|
command: check
|
||||||
|
args: --target thumbv7em-none-eabihf
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
name: Rustfmt
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
- run: rustup component add rustfmt
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --all -- --check
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
name: Clippy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
target: thumbv7em-none-eabihf
|
||||||
|
override: true
|
||||||
|
- run: rustup component add clippy
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
use-cross: true
|
||||||
|
command: clippy
|
||||||
|
args: --target thumbv7em-none-eabihf -- -D warnings
|
||||||
|
|
||||||
|
ci:
|
||||||
|
if: ${{ success() }}
|
||||||
|
# all new jobs must be added to this list
|
||||||
|
needs: [check, fmt, clippy]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: CI succeeded
|
||||||
|
run: exit 0
|
2
va416xx/.gitignore
vendored
Normal file
2
va416xx/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
21
va416xx/CHANGELOG.md
Normal file
21
va416xx/CHANGELOG.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Change Log
|
||||||
|
=======
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [unreleased]
|
||||||
|
|
||||||
|
## [v0.1.1]
|
||||||
|
|
||||||
|
- Clippy issue fixed by regenerating PAC with patched `svd2rust`:
|
||||||
|
https://github.com/rust-embedded/svd2rust/pull/558
|
||||||
|
|
||||||
|
## [v0.1.0]
|
||||||
|
|
||||||
|
- Clippy currently complains about unsound code which should still work.
|
||||||
|
Related issue: https://github.com/rust-embedded/svd2rust/issues/557
|
||||||
|
Clippy is disabled in CI/CD for now.
|
||||||
|
- Initial release
|
29
va416xx/Cargo.toml
Normal file
29
va416xx/Cargo.toml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[package]
|
||||||
|
name = "va416xx"
|
||||||
|
version = "0.1.1"
|
||||||
|
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||||
|
edition = "2021"
|
||||||
|
description = "PAC for the Vorago VA416xx family of MCUs"
|
||||||
|
homepage = "https://egit.irs.uni-stuttgart.de/rust/va416xx"
|
||||||
|
repository = "https://egit.irs.uni-stuttgart.de/rust/va416xx"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
keywords = ["no-std", "arm", "cortex-m", "vorago", "va416xx"]
|
||||||
|
categories = ["embedded", "no-std", "hardware-support"]
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cortex-m = "0.7"
|
||||||
|
vcell = "0.1.3"
|
||||||
|
critical-section = { version = "1", optional = true }
|
||||||
|
|
||||||
|
[dependencies.cortex-m-rt]
|
||||||
|
optional = true
|
||||||
|
version = ">=0.6.15,<0.8"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
rt = ["cortex-m-rt/device"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--generate-link-to-definition"]
|
201
va416xx/LICENSE-APACHE
Normal file
201
va416xx/LICENSE-APACHE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
3
va416xx/NOTICE
Normal file
3
va416xx/NOTICE
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Rust Peripheral Access Crate (PAC) crate for the Vorago VA416xx family of MCUs
|
||||||
|
|
||||||
|
This software contains code developed at the University of Stuttgart.
|
58
va416xx/README.md
Normal file
58
va416xx/README.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
[![Crates.io](https://img.shields.io/crates/v/va416xx)](https://crates.io/crates/va416xx)
|
||||||
|
[![docs.rs](https://img.shields.io/docsrs/va416xx)](https://docs.rs/va416xx)
|
||||||
|
|
||||||
|
# PAC for the Vorago VA416xx microcontroller family
|
||||||
|
|
||||||
|
This repository contains the Peripheral Access Crate (PAC) for
|
||||||
|
Voragos VA416xx series of Cortex-M4 based microcontrollers.
|
||||||
|
|
||||||
|
The crate was generated using [`svd2rust`](https://github.com/rust-embedded/svd2rust).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
To use this crate, add this to your `Cargo.toml`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies.va416xx]
|
||||||
|
version = "<MostRecentVersion>"
|
||||||
|
features = ["rt"]
|
||||||
|
```
|
||||||
|
|
||||||
|
The `rt` feature is optional and recommended. It brings in support for `cortex-m-rt`.
|
||||||
|
|
||||||
|
For full details on the autgenerated API, you can read the
|
||||||
|
[svd2rust documentation](https://docs.rs/svd2rust/latest/svd2rust/).
|
||||||
|
|
||||||
|
## Regenerating the PAC
|
||||||
|
|
||||||
|
If you want to re-generate the PAC, for example if the register file `va416xx.svd` changes
|
||||||
|
or the `svd2rust` version is updated, you can do some using the following these steps:
|
||||||
|
|
||||||
|
1. Make sure all necessary tools are installed: [`svd2rust`](https://docs.rs/svd2rust/latest/svd2rust/),
|
||||||
|
[`svdtools`](https://github.com/rust-embedded/svdtools) and [`form`](https://crates.io/crates/form).
|
||||||
|
You can install all tools with `cargo`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install --locked svd2rust svdtools form
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Patch the vendor-provided SVD file `svd/va41xx.svd`. This can be done using `svdtools` in
|
||||||
|
conjunction with the `svd/va416xx-patch.yml` file.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
svdtools patch svd/va416xx-patch.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Use `svd2rust` to generate the Rust library
|
||||||
|
|
||||||
|
```sh
|
||||||
|
svd2rust -i svd/va416xx.svd.patched
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Use the `form` tool to split the generated `lib.rs` into individual modules.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
form -i lib.rs -o src/
|
||||||
|
```
|
||||||
|
|
||||||
|
The `gen-helper.sh` automates steps 2-4.
|
11
va416xx/automation/Dockerfile
Normal file
11
va416xx/automation/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Run the following commands from root directory to build and run locally
|
||||||
|
# docker build -f automation/Dockerfile -t <NAME> .
|
||||||
|
# docker run -it <NAME>
|
||||||
|
FROM rust:latest
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get --yes upgrade
|
||||||
|
# tzdata is a dependency, won't install otherwise
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN rustup target add thumbv7em-none-eabihf && \
|
||||||
|
rustup component add rustfmt clippy
|
39
va416xx/automation/Jenkinsfile
vendored
Normal file
39
va416xx/automation/Jenkinsfile
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Clippy') {
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
dir 'automation'
|
||||||
|
reuseNode true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
sh 'cargo clippy'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Rustfmt') {
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
dir 'automation'
|
||||||
|
reuseNode true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
sh 'cargo fmt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Check') {
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
dir 'automation'
|
||||||
|
reuseNode true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
sh 'cargo check --target thumbv7em-none-eabihf'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
va416xx/build.rs
Normal file
17
va416xx/build.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#![doc = r" Builder file for Peripheral access crate generated by svd2rust tool"]
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
fn main() {
|
||||||
|
if env::var_os("CARGO_FEATURE_RT").is_some() {
|
||||||
|
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
|
File::create(out.join("device.x"))
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("device.x"))
|
||||||
|
.unwrap();
|
||||||
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
println!("cargo:rerun-if-changed=device.x");
|
||||||
|
}
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
}
|
197
va416xx/device.x
Normal file
197
va416xx/device.x
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
PROVIDE(U0 = DefaultHandler);
|
||||||
|
PROVIDE(U1 = DefaultHandler);
|
||||||
|
PROVIDE(U2 = DefaultHandler);
|
||||||
|
PROVIDE(U3 = DefaultHandler);
|
||||||
|
PROVIDE(U4 = DefaultHandler);
|
||||||
|
PROVIDE(U5 = DefaultHandler);
|
||||||
|
PROVIDE(U6 = DefaultHandler);
|
||||||
|
PROVIDE(U7 = DefaultHandler);
|
||||||
|
PROVIDE(U8 = DefaultHandler);
|
||||||
|
PROVIDE(U9 = DefaultHandler);
|
||||||
|
PROVIDE(U10 = DefaultHandler);
|
||||||
|
PROVIDE(U11 = DefaultHandler);
|
||||||
|
PROVIDE(U12 = DefaultHandler);
|
||||||
|
PROVIDE(U13 = DefaultHandler);
|
||||||
|
PROVIDE(U14 = DefaultHandler);
|
||||||
|
PROVIDE(U15 = DefaultHandler);
|
||||||
|
PROVIDE(SPI0_TX = DefaultHandler);
|
||||||
|
PROVIDE(SPI0_RX = DefaultHandler);
|
||||||
|
PROVIDE(SPI1_TX = DefaultHandler);
|
||||||
|
PROVIDE(SPI1_RX = DefaultHandler);
|
||||||
|
PROVIDE(SPI2_TX = DefaultHandler);
|
||||||
|
PROVIDE(SPI2_RX = DefaultHandler);
|
||||||
|
PROVIDE(SPI3_TX = DefaultHandler);
|
||||||
|
PROVIDE(SPI3_RX = DefaultHandler);
|
||||||
|
PROVIDE(UART0_TX = DefaultHandler);
|
||||||
|
PROVIDE(UART0_RX = DefaultHandler);
|
||||||
|
PROVIDE(UART1_TX = DefaultHandler);
|
||||||
|
PROVIDE(UART1_RX = DefaultHandler);
|
||||||
|
PROVIDE(UART2_TX = DefaultHandler);
|
||||||
|
PROVIDE(UART2_RX = DefaultHandler);
|
||||||
|
PROVIDE(I2C0_MS = DefaultHandler);
|
||||||
|
PROVIDE(I2C0_SL = DefaultHandler);
|
||||||
|
PROVIDE(I2C1_MS = DefaultHandler);
|
||||||
|
PROVIDE(I2C1_SL = DefaultHandler);
|
||||||
|
PROVIDE(I2C2_MS = DefaultHandler);
|
||||||
|
PROVIDE(I2C2_SL = DefaultHandler);
|
||||||
|
PROVIDE(Ethernet = DefaultHandler);
|
||||||
|
PROVIDE(U37 = DefaultHandler);
|
||||||
|
PROVIDE(SpW = DefaultHandler);
|
||||||
|
PROVIDE(U39 = DefaultHandler);
|
||||||
|
PROVIDE(DAC0 = DefaultHandler);
|
||||||
|
PROVIDE(DAC1 = DefaultHandler);
|
||||||
|
PROVIDE(TRNG = DefaultHandler);
|
||||||
|
PROVIDE(DMA_ERROR = DefaultHandler);
|
||||||
|
PROVIDE(ADC = DefaultHandler);
|
||||||
|
PROVIDE(LoCLK = DefaultHandler);
|
||||||
|
PROVIDE(LVD = DefaultHandler);
|
||||||
|
PROVIDE(WATCHDOG = DefaultHandler);
|
||||||
|
PROVIDE(TIM0 = DefaultHandler);
|
||||||
|
PROVIDE(TIM1 = DefaultHandler);
|
||||||
|
PROVIDE(TIM2 = DefaultHandler);
|
||||||
|
PROVIDE(TIM3 = DefaultHandler);
|
||||||
|
PROVIDE(TIM4 = DefaultHandler);
|
||||||
|
PROVIDE(TIM5 = DefaultHandler);
|
||||||
|
PROVIDE(TIM6 = DefaultHandler);
|
||||||
|
PROVIDE(TIM7 = DefaultHandler);
|
||||||
|
PROVIDE(TIM8 = DefaultHandler);
|
||||||
|
PROVIDE(TIM9 = DefaultHandler);
|
||||||
|
PROVIDE(TIM10 = DefaultHandler);
|
||||||
|
PROVIDE(TIM11 = DefaultHandler);
|
||||||
|
PROVIDE(TIM12 = DefaultHandler);
|
||||||
|
PROVIDE(TIM13 = DefaultHandler);
|
||||||
|
PROVIDE(TIM14 = DefaultHandler);
|
||||||
|
PROVIDE(TIM15 = DefaultHandler);
|
||||||
|
PROVIDE(TIM16 = DefaultHandler);
|
||||||
|
PROVIDE(TIM17 = DefaultHandler);
|
||||||
|
PROVIDE(TIM18 = DefaultHandler);
|
||||||
|
PROVIDE(TIM19 = DefaultHandler);
|
||||||
|
PROVIDE(TIM20 = DefaultHandler);
|
||||||
|
PROVIDE(TIM21 = DefaultHandler);
|
||||||
|
PROVIDE(TIM22 = DefaultHandler);
|
||||||
|
PROVIDE(TIM23 = DefaultHandler);
|
||||||
|
PROVIDE(CAN0 = DefaultHandler);
|
||||||
|
PROVIDE(U73 = DefaultHandler);
|
||||||
|
PROVIDE(CAN1 = DefaultHandler);
|
||||||
|
PROVIDE(U75 = DefaultHandler);
|
||||||
|
PROVIDE(EDAC_MBE = DefaultHandler);
|
||||||
|
PROVIDE(EDAC_SBE = DefaultHandler);
|
||||||
|
PROVIDE(PORTA0 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA1 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA2 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA3 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA4 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA5 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA6 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA7 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA8 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA9 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA10 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA11 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA12 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA13 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA14 = DefaultHandler);
|
||||||
|
PROVIDE(PORTA15 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB0 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB1 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB2 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB3 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB4 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB5 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB6 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB7 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB8 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB9 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB10 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB11 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB12 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB13 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB14 = DefaultHandler);
|
||||||
|
PROVIDE(PORTB15 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC0 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC1 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC2 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC3 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC4 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC5 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC6 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC7 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC8 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC9 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC10 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC11 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC12 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC13 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC14 = DefaultHandler);
|
||||||
|
PROVIDE(PORTC15 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD0 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD1 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD2 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD3 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD4 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD5 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD6 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD7 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD8 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD9 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD10 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD11 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD12 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD13 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD14 = DefaultHandler);
|
||||||
|
PROVIDE(PORTD15 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE0 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE1 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE2 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE3 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE4 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE5 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE6 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE7 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE8 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE9 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE10 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE11 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE12 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE13 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE14 = DefaultHandler);
|
||||||
|
PROVIDE(PORTE15 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF0 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF1 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF2 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF3 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF4 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF5 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF6 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF7 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF8 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF9 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF10 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF11 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF12 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF13 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF14 = DefaultHandler);
|
||||||
|
PROVIDE(PORTF15 = DefaultHandler);
|
||||||
|
PROVIDE(DMA_ACTIVE0 = DefaultHandler);
|
||||||
|
PROVIDE(DMA_ACTIVE1 = DefaultHandler);
|
||||||
|
PROVIDE(DMA_ACTIVE2 = DefaultHandler);
|
||||||
|
PROVIDE(DMA_ACTIVE3 = DefaultHandler);
|
||||||
|
PROVIDE(DMA_DONE0 = DefaultHandler);
|
||||||
|
PROVIDE(DMA_DONE1 = DefaultHandler);
|
||||||
|
PROVIDE(DMA_DONE2 = DefaultHandler);
|
||||||
|
PROVIDE(DMA_DONE3 = DefaultHandler);
|
||||||
|
PROVIDE(I2C0_MS_RX = DefaultHandler);
|
||||||
|
PROVIDE(I2C0_MS_TX = DefaultHandler);
|
||||||
|
PROVIDE(I2C0_SL_RX = DefaultHandler);
|
||||||
|
PROVIDE(I2C0_SL_TX = DefaultHandler);
|
||||||
|
PROVIDE(I2C1_MS_RX = DefaultHandler);
|
||||||
|
PROVIDE(I2C1_MS_TX = DefaultHandler);
|
||||||
|
PROVIDE(I2C1_SL_RX = DefaultHandler);
|
||||||
|
PROVIDE(I2C1_SL_TX = DefaultHandler);
|
||||||
|
PROVIDE(I2C2_MS_RX = DefaultHandler);
|
||||||
|
PROVIDE(I2C2_MS_TX = DefaultHandler);
|
||||||
|
PROVIDE(I2C2_SL_RX = DefaultHandler);
|
||||||
|
PROVIDE(I2C2_SL_TX = DefaultHandler);
|
||||||
|
PROVIDE(FPU = DefaultHandler);
|
||||||
|
PROVIDE(TXEV = DefaultHandler);
|
||||||
|
|
42
va416xx/gen-helper.sh
Executable file
42
va416xx/gen-helper.sh
Executable file
@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Use installed tool by default
|
||||||
|
svd2rust_bin="svd2rust"
|
||||||
|
# Automates the steps specified in https://docs.rs/svd2rust/0.19.0/svd2rust/
|
||||||
|
if [ -f svd2rust ]; then
|
||||||
|
# If the local directory contains svd2rust, use that version instead
|
||||||
|
svd2rust_bin="./svd2rust"
|
||||||
|
elif [ -f ../svd2rust ]; then
|
||||||
|
# Keeps the repository clean
|
||||||
|
svd2rust_bin="../svd2rust"
|
||||||
|
fi
|
||||||
|
if [ -x "$(${svd2rust_bin} --version)" ]; then
|
||||||
|
echo "No svd2rust found locally or installed." \
|
||||||
|
"Install it with cargo install svd2rust"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v form &> /dev/null
|
||||||
|
then
|
||||||
|
echo "form tool was not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v svdtools &> /dev/null
|
||||||
|
then
|
||||||
|
echo "svdtools was not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
svdtools patch svd/va416xx-patch.yml
|
||||||
|
${svd2rust_bin} --reexport-interrupt -i svd/va416xx.svd.patched
|
||||||
|
|
||||||
|
result=$?
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "svd2rust failed with code $result"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf src
|
||||||
|
form -i lib.rs -o src/ && rm lib.rs
|
||||||
|
cargo fmt
|
127
va416xx/src/adc.rs
Normal file
127
va416xx/src/adc.rs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#[repr(C)]
|
||||||
|
#[doc = "Register block"]
|
||||||
|
pub struct RegisterBlock {
|
||||||
|
ctrl: Ctrl,
|
||||||
|
fifo_data: FifoData,
|
||||||
|
status: Status,
|
||||||
|
irq_enb: IrqEnb,
|
||||||
|
irq_raw: IrqRaw,
|
||||||
|
irq_end: IrqEnd,
|
||||||
|
irq_clr: IrqClr,
|
||||||
|
rxfifoirqtrg: Rxfifoirqtrg,
|
||||||
|
fifo_clr: FifoClr,
|
||||||
|
_reserved9: [u8; 0x0fd8],
|
||||||
|
perid: Perid,
|
||||||
|
}
|
||||||
|
impl RegisterBlock {
|
||||||
|
#[doc = "0x00 - Control Register"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn ctrl(&self) -> &Ctrl {
|
||||||
|
&self.ctrl
|
||||||
|
}
|
||||||
|
#[doc = "0x04 - FIFO data"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn fifo_data(&self) -> &FifoData {
|
||||||
|
&self.fifo_data
|
||||||
|
}
|
||||||
|
#[doc = "0x08 - Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn status(&self) -> &Status {
|
||||||
|
&self.status
|
||||||
|
}
|
||||||
|
#[doc = "0x0c - Interrupt Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn irq_enb(&self) -> &IrqEnb {
|
||||||
|
&self.irq_enb
|
||||||
|
}
|
||||||
|
#[doc = "0x10 - Raw Interrupt Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn irq_raw(&self) -> &IrqRaw {
|
||||||
|
&self.irq_raw
|
||||||
|
}
|
||||||
|
#[doc = "0x14 - Enabled Interrupt Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn irq_end(&self) -> &IrqEnd {
|
||||||
|
&self.irq_end
|
||||||
|
}
|
||||||
|
#[doc = "0x18 - Clear Interrupt"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn irq_clr(&self) -> &IrqClr {
|
||||||
|
&self.irq_clr
|
||||||
|
}
|
||||||
|
#[doc = "0x1c - Receive FIFO Interrupt Trigger Value"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn rxfifoirqtrg(&self) -> &Rxfifoirqtrg {
|
||||||
|
&self.rxfifoirqtrg
|
||||||
|
}
|
||||||
|
#[doc = "0x20 - FIFO Clear"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn fifo_clr(&self) -> &FifoClr {
|
||||||
|
&self.fifo_clr
|
||||||
|
}
|
||||||
|
#[doc = "0xffc - Peripheral ID Register"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn perid(&self) -> &Perid {
|
||||||
|
&self.perid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CTRL (rw) register accessor: Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`ctrl::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`ctrl::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@ctrl`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "CTRL")]
|
||||||
|
pub type Ctrl = crate::Reg<ctrl::CtrlSpec>;
|
||||||
|
#[doc = "Control Register"]
|
||||||
|
pub mod ctrl;
|
||||||
|
#[doc = "FIFO_DATA (r) register accessor: FIFO data\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`fifo_data::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@fifo_data`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "FIFO_DATA")]
|
||||||
|
pub type FifoData = crate::Reg<fifo_data::FifoDataSpec>;
|
||||||
|
#[doc = "FIFO data"]
|
||||||
|
pub mod fifo_data;
|
||||||
|
#[doc = "STATUS (r) register accessor: Status\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`status::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@status`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "STATUS")]
|
||||||
|
pub type Status = crate::Reg<status::StatusSpec>;
|
||||||
|
#[doc = "Status"]
|
||||||
|
pub mod status;
|
||||||
|
#[doc = "IRQ_ENB (rw) register accessor: Interrupt Enable\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`irq_enb::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`irq_enb::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@irq_enb`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "IRQ_ENB")]
|
||||||
|
pub type IrqEnb = crate::Reg<irq_enb::IrqEnbSpec>;
|
||||||
|
#[doc = "Interrupt Enable"]
|
||||||
|
pub mod irq_enb;
|
||||||
|
#[doc = "IRQ_RAW (r) register accessor: Raw Interrupt Status\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`irq_raw::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@irq_raw`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "IRQ_RAW")]
|
||||||
|
pub type IrqRaw = crate::Reg<irq_raw::IrqRawSpec>;
|
||||||
|
#[doc = "Raw Interrupt Status"]
|
||||||
|
pub mod irq_raw;
|
||||||
|
#[doc = "IRQ_END (r) register accessor: Enabled Interrupt Status\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`irq_end::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@irq_end`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "IRQ_END")]
|
||||||
|
pub type IrqEnd = crate::Reg<irq_end::IrqEndSpec>;
|
||||||
|
#[doc = "Enabled Interrupt Status"]
|
||||||
|
pub mod irq_end;
|
||||||
|
#[doc = "IRQ_CLR (w) register accessor: Clear Interrupt\n\nYou can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`irq_clr::W`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@irq_clr`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "IRQ_CLR")]
|
||||||
|
pub type IrqClr = crate::Reg<irq_clr::IrqClrSpec>;
|
||||||
|
#[doc = "Clear Interrupt"]
|
||||||
|
pub mod irq_clr;
|
||||||
|
#[doc = "RXFIFOIRQTRG (rw) register accessor: Receive FIFO Interrupt Trigger Value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`rxfifoirqtrg::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`rxfifoirqtrg::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@rxfifoirqtrg`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "RXFIFOIRQTRG")]
|
||||||
|
pub type Rxfifoirqtrg = crate::Reg<rxfifoirqtrg::RxfifoirqtrgSpec>;
|
||||||
|
#[doc = "Receive FIFO Interrupt Trigger Value"]
|
||||||
|
pub mod rxfifoirqtrg;
|
||||||
|
#[doc = "FIFO_CLR (rw) register accessor: FIFO Clear\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`fifo_clr::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`fifo_clr::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@fifo_clr`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "FIFO_CLR")]
|
||||||
|
pub type FifoClr = crate::Reg<fifo_clr::FifoClrSpec>;
|
||||||
|
#[doc = "FIFO Clear"]
|
||||||
|
pub mod fifo_clr;
|
||||||
|
#[doc = "PERID (r) register accessor: Peripheral ID Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`perid::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@perid`]
|
||||||
|
module"]
|
||||||
|
#[doc(alias = "PERID")]
|
||||||
|
pub type Perid = crate::Reg<perid::PeridSpec>;
|
||||||
|
#[doc = "Peripheral ID Register"]
|
||||||
|
pub mod perid;
|
115
va416xx/src/adc/ctrl.rs
Normal file
115
va416xx/src/adc/ctrl.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#[doc = "Register `CTRL` reader"]
|
||||||
|
pub type R = crate::R<CtrlSpec>;
|
||||||
|
#[doc = "Register `CTRL` writer"]
|
||||||
|
pub type W = crate::W<CtrlSpec>;
|
||||||
|
#[doc = "Field `CHAN_EN` reader - Enables the channel for data collection"]
|
||||||
|
pub type ChanEnR = crate::FieldReader<u16>;
|
||||||
|
#[doc = "Field `CHAN_EN` writer - Enables the channel for data collection"]
|
||||||
|
pub type ChanEnW<'a, REG> = crate::FieldWriter<'a, REG, 16, u16>;
|
||||||
|
#[doc = "Field `CHAN_TAG_EN` reader - Enables the channel tag to be saved with the ADC data"]
|
||||||
|
pub type ChanTagEnR = crate::BitReader;
|
||||||
|
#[doc = "Field `CHAN_TAG_EN` writer - Enables the channel tag to be saved with the ADC data"]
|
||||||
|
pub type ChanTagEnW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `SWEEP_EN` reader - ADC data acquisition for all enabled channel"]
|
||||||
|
pub type SweepEnR = crate::BitReader;
|
||||||
|
#[doc = "Field `SWEEP_EN` writer - ADC data acquisition for all enabled channel"]
|
||||||
|
pub type SweepEnW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `EXT_TRIG_EN` reader - Allows the external trigger to start analog acquisition"]
|
||||||
|
pub type ExtTrigEnR = crate::BitReader;
|
||||||
|
#[doc = "Field `EXT_TRIG_EN` writer - Allows the external trigger to start analog acquisition"]
|
||||||
|
pub type ExtTrigEnW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `MANUAL_TRIG` reader - Starts analog acquisition"]
|
||||||
|
pub type ManualTrigR = crate::BitReader;
|
||||||
|
#[doc = "Field `MANUAL_TRIG` writer - Starts analog acquisition"]
|
||||||
|
pub type ManualTrigW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `CONV_CNT` reader - Conversion count describes the number of conversions to be applied for triggers/sweeps. (N+1 conversions)"]
|
||||||
|
pub type ConvCntR = crate::FieldReader;
|
||||||
|
#[doc = "Field `CONV_CNT` writer - Conversion count describes the number of conversions to be applied for triggers/sweeps. (N+1 conversions)"]
|
||||||
|
pub type ConvCntW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:15 - Enables the channel for data collection"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn chan_en(&self) -> ChanEnR {
|
||||||
|
ChanEnR::new((self.bits & 0xffff) as u16)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 16 - Enables the channel tag to be saved with the ADC data"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn chan_tag_en(&self) -> ChanTagEnR {
|
||||||
|
ChanTagEnR::new(((self.bits >> 16) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 17 - ADC data acquisition for all enabled channel"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sweep_en(&self) -> SweepEnR {
|
||||||
|
SweepEnR::new(((self.bits >> 17) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 18 - Allows the external trigger to start analog acquisition"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ext_trig_en(&self) -> ExtTrigEnR {
|
||||||
|
ExtTrigEnR::new(((self.bits >> 18) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 19 - Starts analog acquisition"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn manual_trig(&self) -> ManualTrigR {
|
||||||
|
ManualTrigR::new(((self.bits >> 19) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 20:23 - Conversion count describes the number of conversions to be applied for triggers/sweeps. (N+1 conversions)"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn conv_cnt(&self) -> ConvCntR {
|
||||||
|
ConvCntR::new(((self.bits >> 20) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:15 - Enables the channel for data collection"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn chan_en(&mut self) -> ChanEnW<CtrlSpec> {
|
||||||
|
ChanEnW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 16 - Enables the channel tag to be saved with the ADC data"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn chan_tag_en(&mut self) -> ChanTagEnW<CtrlSpec> {
|
||||||
|
ChanTagEnW::new(self, 16)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 17 - ADC data acquisition for all enabled channel"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn sweep_en(&mut self) -> SweepEnW<CtrlSpec> {
|
||||||
|
SweepEnW::new(self, 17)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 18 - Allows the external trigger to start analog acquisition"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ext_trig_en(&mut self) -> ExtTrigEnW<CtrlSpec> {
|
||||||
|
ExtTrigEnW::new(self, 18)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 19 - Starts analog acquisition"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn manual_trig(&mut self) -> ManualTrigW<CtrlSpec> {
|
||||||
|
ManualTrigW::new(self, 19)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 20:23 - Conversion count describes the number of conversions to be applied for triggers/sweeps. (N+1 conversions)"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn conv_cnt(&mut self) -> ConvCntW<CtrlSpec> {
|
||||||
|
ConvCntW::new(self, 20)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`ctrl::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`ctrl::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CtrlSpec;
|
||||||
|
impl crate::RegisterSpec for CtrlSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`ctrl::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CtrlSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`ctrl::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CtrlSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CTRL to value 0"]
|
||||||
|
impl crate::Resettable for CtrlSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
31
va416xx/src/adc/fifo_clr.rs
Normal file
31
va416xx/src/adc/fifo_clr.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#[doc = "Register `FIFO_CLR` reader"]
|
||||||
|
pub type R = crate::R<FifoClrSpec>;
|
||||||
|
#[doc = "Register `FIFO_CLR` writer"]
|
||||||
|
pub type W = crate::W<FifoClrSpec>;
|
||||||
|
#[doc = "Field `FIFO_CLR` writer - Clears the ADC FIFO. Always reads 0"]
|
||||||
|
pub type FifoClrW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bit 0 - Clears the ADC FIFO. Always reads 0"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn fifo_clr(&mut self) -> FifoClrW<FifoClrSpec> {
|
||||||
|
FifoClrW::new(self, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "FIFO Clear\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`fifo_clr::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`fifo_clr::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct FifoClrSpec;
|
||||||
|
impl crate::RegisterSpec for FifoClrSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`fifo_clr::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for FifoClrSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`fifo_clr::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for FifoClrSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets FIFO_CLR to value 0"]
|
||||||
|
impl crate::Resettable for FifoClrSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
29
va416xx/src/adc/fifo_data.rs
Normal file
29
va416xx/src/adc/fifo_data.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#[doc = "Register `FIFO_DATA` reader"]
|
||||||
|
pub type R = crate::R<FifoDataSpec>;
|
||||||
|
#[doc = "Field `ADC_DATA` reader - ADC acquisition data from the FIFO"]
|
||||||
|
pub type AdcDataR = crate::FieldReader<u16>;
|
||||||
|
#[doc = "Field `CHAN_TAG` reader - If enabled, this will include the number of the channel corresponding to the measurement"]
|
||||||
|
pub type ChanTagR = crate::FieldReader;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:11 - ADC acquisition data from the FIFO"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn adc_data(&self) -> AdcDataR {
|
||||||
|
AdcDataR::new((self.bits & 0x0fff) as u16)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - If enabled, this will include the number of the channel corresponding to the measurement"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn chan_tag(&self) -> ChanTagR {
|
||||||
|
ChanTagR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "FIFO data\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`fifo_data::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct FifoDataSpec;
|
||||||
|
impl crate::RegisterSpec for FifoDataSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`fifo_data::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for FifoDataSpec {}
|
||||||
|
#[doc = "`reset()` method sets FIFO_DATA to value 0"]
|
||||||
|
impl crate::Resettable for FifoDataSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
51
va416xx/src/adc/irq_clr.rs
Normal file
51
va416xx/src/adc/irq_clr.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#[doc = "Register `IRQ_CLR` writer"]
|
||||||
|
pub type W = crate::W<IrqClrSpec>;
|
||||||
|
#[doc = "Field `FIFO_OFLOW` writer - Clears the FIFO overflow interrupt status. Always reads 0"]
|
||||||
|
pub type FifoOflowW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `FIFO_UFLOW` writer - Clears the FIFO underflow interrupt status. Always reads 0"]
|
||||||
|
pub type FifoUflowW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `ADC_DONE` writer - Clears the ADC done interrupt status. Always reads 0"]
|
||||||
|
pub type AdcDoneW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `TRIG_ERROR` writer - Clears the trigger error interrupt status. Always reads 0"]
|
||||||
|
pub type TrigErrorW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bit 0 - Clears the FIFO overflow interrupt status. Always reads 0"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn fifo_oflow(&mut self) -> FifoOflowW<IrqClrSpec> {
|
||||||
|
FifoOflowW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 1 - Clears the FIFO underflow interrupt status. Always reads 0"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn fifo_uflow(&mut self) -> FifoUflowW<IrqClrSpec> {
|
||||||
|
FifoUflowW::new(self, 1)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 2 - Clears the ADC done interrupt status. Always reads 0"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn adc_done(&mut self) -> AdcDoneW<IrqClrSpec> {
|
||||||
|
AdcDoneW::new(self, 2)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Clears the trigger error interrupt status. Always reads 0"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn trig_error(&mut self) -> TrigErrorW<IrqClrSpec> {
|
||||||
|
TrigErrorW::new(self, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Clear Interrupt\n\nYou can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`irq_clr::W`](W). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct IrqClrSpec;
|
||||||
|
impl crate::RegisterSpec for IrqClrSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`irq_clr::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for IrqClrSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets IRQ_CLR to value 0"]
|
||||||
|
impl crate::Resettable for IrqClrSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
130
va416xx/src/adc/irq_enb.rs
Normal file
130
va416xx/src/adc/irq_enb.rs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#[doc = "Register `IRQ_ENB` reader"]
|
||||||
|
pub type R = crate::R<IrqEnbSpec>;
|
||||||
|
#[doc = "Register `IRQ_ENB` writer"]
|
||||||
|
pub type W = crate::W<IrqEnbSpec>;
|
||||||
|
#[doc = "Field `FIFO_EMPTY` reader - Enables the interrupt for FIFO empty"]
|
||||||
|
pub type FifoEmptyR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_EMPTY` writer - Enables the interrupt for FIFO empty"]
|
||||||
|
pub type FifoEmptyW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `FIFO_FULL` reader - Enables the interrupt for FIFO full"]
|
||||||
|
pub type FifoFullR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_FULL` writer - Enables the interrupt for FIFO full"]
|
||||||
|
pub type FifoFullW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `FIFO_OFLOW` reader - Enables the interrupt for a FIFO overflow"]
|
||||||
|
pub type FifoOflowR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_OFLOW` writer - Enables the interrupt for a FIFO overflow"]
|
||||||
|
pub type FifoOflowW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `FIFO_UFLOW` reader - Enables the interrupt for a FIFO underflow"]
|
||||||
|
pub type FifoUflowR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_UFLOW` writer - Enables the interrupt for a FIFO underflow"]
|
||||||
|
pub type FifoUflowW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `ADC_DONE` reader - Enables the interrupt for an ADC data acquisition completion"]
|
||||||
|
pub type AdcDoneR = crate::BitReader;
|
||||||
|
#[doc = "Field `ADC_DONE` writer - Enables the interrupt for an ADC data acquisition completion"]
|
||||||
|
pub type AdcDoneW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `TRIG_ERROR` reader - Enables the interrupt for a trigger error"]
|
||||||
|
pub type TrigErrorR = crate::BitReader;
|
||||||
|
#[doc = "Field `TRIG_ERROR` writer - Enables the interrupt for a trigger error"]
|
||||||
|
pub type TrigErrorW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `FIFO_DEPTH_TRIG` reader - Enables the interrupt for the FIFO entry count meets or exceeds the trigger level"]
|
||||||
|
pub type FifoDepthTrigR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_DEPTH_TRIG` writer - Enables the interrupt for the FIFO entry count meets or exceeds the trigger level"]
|
||||||
|
pub type FifoDepthTrigW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bit 0 - Enables the interrupt for FIFO empty"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_empty(&self) -> FifoEmptyR {
|
||||||
|
FifoEmptyR::new((self.bits & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 1 - Enables the interrupt for FIFO full"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_full(&self) -> FifoFullR {
|
||||||
|
FifoFullR::new(((self.bits >> 1) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 2 - Enables the interrupt for a FIFO overflow"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_oflow(&self) -> FifoOflowR {
|
||||||
|
FifoOflowR::new(((self.bits >> 2) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Enables the interrupt for a FIFO underflow"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_uflow(&self) -> FifoUflowR {
|
||||||
|
FifoUflowR::new(((self.bits >> 3) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 4 - Enables the interrupt for an ADC data acquisition completion"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn adc_done(&self) -> AdcDoneR {
|
||||||
|
AdcDoneR::new(((self.bits >> 4) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 5 - Enables the interrupt for a trigger error"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn trig_error(&self) -> TrigErrorR {
|
||||||
|
TrigErrorR::new(((self.bits >> 5) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 6 - Enables the interrupt for the FIFO entry count meets or exceeds the trigger level"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_depth_trig(&self) -> FifoDepthTrigR {
|
||||||
|
FifoDepthTrigR::new(((self.bits >> 6) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bit 0 - Enables the interrupt for FIFO empty"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn fifo_empty(&mut self) -> FifoEmptyW<IrqEnbSpec> {
|
||||||
|
FifoEmptyW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 1 - Enables the interrupt for FIFO full"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn fifo_full(&mut self) -> FifoFullW<IrqEnbSpec> {
|
||||||
|
FifoFullW::new(self, 1)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 2 - Enables the interrupt for a FIFO overflow"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn fifo_oflow(&mut self) -> FifoOflowW<IrqEnbSpec> {
|
||||||
|
FifoOflowW::new(self, 2)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Enables the interrupt for a FIFO underflow"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn fifo_uflow(&mut self) -> FifoUflowW<IrqEnbSpec> {
|
||||||
|
FifoUflowW::new(self, 3)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 4 - Enables the interrupt for an ADC data acquisition completion"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn adc_done(&mut self) -> AdcDoneW<IrqEnbSpec> {
|
||||||
|
AdcDoneW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 5 - Enables the interrupt for a trigger error"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn trig_error(&mut self) -> TrigErrorW<IrqEnbSpec> {
|
||||||
|
TrigErrorW::new(self, 5)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 6 - Enables the interrupt for the FIFO entry count meets or exceeds the trigger level"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn fifo_depth_trig(&mut self) -> FifoDepthTrigW<IrqEnbSpec> {
|
||||||
|
FifoDepthTrigW::new(self, 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Interrupt Enable\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`irq_enb::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`irq_enb::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct IrqEnbSpec;
|
||||||
|
impl crate::RegisterSpec for IrqEnbSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`irq_enb::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for IrqEnbSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`irq_enb::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for IrqEnbSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets IRQ_ENB to value 0"]
|
||||||
|
impl crate::Resettable for IrqEnbSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
64
va416xx/src/adc/irq_end.rs
Normal file
64
va416xx/src/adc/irq_end.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#[doc = "Register `IRQ_END` reader"]
|
||||||
|
pub type R = crate::R<IrqEndSpec>;
|
||||||
|
#[doc = "Field `FIFO_EMPTY` reader - Indicates the FIFO is empty and the interrupt is enabled"]
|
||||||
|
pub type FifoEmptyR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_FULL` reader - Indicates the FIFO is full and the interrupt is enabled"]
|
||||||
|
pub type FifoFullR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_OFLOW` reader - Indicates a FIFO overflow occurred and the interrupt is enabled"]
|
||||||
|
pub type FifoOflowR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_UFLOW` reader - Indicates a FIFO underflow occurred and the interrupt is enabled"]
|
||||||
|
pub type FifoUflowR = crate::BitReader;
|
||||||
|
#[doc = "Field `ADC_DONE` reader - Indicates that a ADC conversion is done and the interrupt is enabled"]
|
||||||
|
pub type AdcDoneR = crate::BitReader;
|
||||||
|
#[doc = "Field `TRIG_ERROR` reader - Indicates a manual or external trigger occurred when the ADC was BUSY doing a conversion and the interrupt is enabled"]
|
||||||
|
pub type TrigErrorR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_DEPTH_TRIG` reader - Indicates the interrupt for the FIFO entry count meets or exceeds the trigger level"]
|
||||||
|
pub type FifoDepthTrigR = crate::BitReader;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bit 0 - Indicates the FIFO is empty and the interrupt is enabled"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_empty(&self) -> FifoEmptyR {
|
||||||
|
FifoEmptyR::new((self.bits & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 1 - Indicates the FIFO is full and the interrupt is enabled"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_full(&self) -> FifoFullR {
|
||||||
|
FifoFullR::new(((self.bits >> 1) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 2 - Indicates a FIFO overflow occurred and the interrupt is enabled"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_oflow(&self) -> FifoOflowR {
|
||||||
|
FifoOflowR::new(((self.bits >> 2) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Indicates a FIFO underflow occurred and the interrupt is enabled"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_uflow(&self) -> FifoUflowR {
|
||||||
|
FifoUflowR::new(((self.bits >> 3) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 4 - Indicates that a ADC conversion is done and the interrupt is enabled"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn adc_done(&self) -> AdcDoneR {
|
||||||
|
AdcDoneR::new(((self.bits >> 4) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 5 - Indicates a manual or external trigger occurred when the ADC was BUSY doing a conversion and the interrupt is enabled"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn trig_error(&self) -> TrigErrorR {
|
||||||
|
TrigErrorR::new(((self.bits >> 5) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 6 - Indicates the interrupt for the FIFO entry count meets or exceeds the trigger level"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_depth_trig(&self) -> FifoDepthTrigR {
|
||||||
|
FifoDepthTrigR::new(((self.bits >> 6) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Enabled Interrupt Status\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`irq_end::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct IrqEndSpec;
|
||||||
|
impl crate::RegisterSpec for IrqEndSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`irq_end::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for IrqEndSpec {}
|
||||||
|
#[doc = "`reset()` method sets IRQ_END to value 0"]
|
||||||
|
impl crate::Resettable for IrqEndSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
64
va416xx/src/adc/irq_raw.rs
Normal file
64
va416xx/src/adc/irq_raw.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#[doc = "Register `IRQ_RAW` reader"]
|
||||||
|
pub type R = crate::R<IrqRawSpec>;
|
||||||
|
#[doc = "Field `FIFO_EMPTY` reader - Indicates the FIFO is empty"]
|
||||||
|
pub type FifoEmptyR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_FULL` reader - Indicates the FIFO is full"]
|
||||||
|
pub type FifoFullR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_OFLOW` reader - Indicates a FIFO overflow occurred (FIFO was full when new data was written)"]
|
||||||
|
pub type FifoOflowR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_UFLOW` reader - Indicates data was unavailable when a new trigger for ADC update is received"]
|
||||||
|
pub type FifoUflowR = crate::BitReader;
|
||||||
|
#[doc = "Field `ADC_DONE` reader - Indicates that a ADC conversion is done"]
|
||||||
|
pub type AdcDoneR = crate::BitReader;
|
||||||
|
#[doc = "Field `TRIG_ERROR` reader - Indicates a manual or external trigger occurred when the ADC was BUSY doing a conversion"]
|
||||||
|
pub type TrigErrorR = crate::BitReader;
|
||||||
|
#[doc = "Field `FIFO_DEPTH_TRIG` reader - Indicates the interrupt for the FIFO entry count meets or exceeds the trigger level"]
|
||||||
|
pub type FifoDepthTrigR = crate::BitReader;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bit 0 - Indicates the FIFO is empty"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_empty(&self) -> FifoEmptyR {
|
||||||
|
FifoEmptyR::new((self.bits & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 1 - Indicates the FIFO is full"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_full(&self) -> FifoFullR {
|
||||||
|
FifoFullR::new(((self.bits >> 1) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 2 - Indicates a FIFO overflow occurred (FIFO was full when new data was written)"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_oflow(&self) -> FifoOflowR {
|
||||||
|
FifoOflowR::new(((self.bits >> 2) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Indicates data was unavailable when a new trigger for ADC update is received"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_uflow(&self) -> FifoUflowR {
|
||||||
|
FifoUflowR::new(((self.bits >> 3) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 4 - Indicates that a ADC conversion is done"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn adc_done(&self) -> AdcDoneR {
|
||||||
|
AdcDoneR::new(((self.bits >> 4) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 5 - Indicates a manual or external trigger occurred when the ADC was BUSY doing a conversion"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn trig_error(&self) -> TrigErrorR {
|
||||||
|
TrigErrorR::new(((self.bits >> 5) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 6 - Indicates the interrupt for the FIFO entry count meets or exceeds the trigger level"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_depth_trig(&self) -> FifoDepthTrigR {
|
||||||
|
FifoDepthTrigR::new(((self.bits >> 6) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Raw Interrupt Status\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`irq_raw::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct IrqRawSpec;
|
||||||
|
impl crate::RegisterSpec for IrqRawSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`irq_raw::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for IrqRawSpec {}
|
||||||
|
#[doc = "`reset()` method sets IRQ_RAW to value 0x01"]
|
||||||
|
impl crate::Resettable for IrqRawSpec {
|
||||||
|
const RESET_VALUE: u32 = 0x01;
|
||||||
|
}
|
18
va416xx/src/adc/perid.rs
Normal file
18
va416xx/src/adc/perid.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#[doc = "Register `PERID` reader"]
|
||||||
|
pub type R = crate::R<PeridSpec>;
|
||||||
|
impl core::fmt::Debug for R {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
|
write!(f, "{}", self.bits())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Peripheral ID Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`perid::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct PeridSpec;
|
||||||
|
impl crate::RegisterSpec for PeridSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`perid::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for PeridSpec {}
|
||||||
|
#[doc = "`reset()` method sets PERID to value 0x0019_07e9"]
|
||||||
|
impl crate::Resettable for PeridSpec {
|
||||||
|
const RESET_VALUE: u32 = 0x0019_07e9;
|
||||||
|
}
|
40
va416xx/src/adc/rxfifoirqtrg.rs
Normal file
40
va416xx/src/adc/rxfifoirqtrg.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#[doc = "Register `RXFIFOIRQTRG` reader"]
|
||||||
|
pub type R = crate::R<RxfifoirqtrgSpec>;
|
||||||
|
#[doc = "Register `RXFIFOIRQTRG` writer"]
|
||||||
|
pub type W = crate::W<RxfifoirqtrgSpec>;
|
||||||
|
#[doc = "Field `LEVEL` reader - Sets the FIFO_ENTRY_CNT value that asserts the FIFO_DEPTH_TRIG interrupt"]
|
||||||
|
pub type LevelR = crate::FieldReader;
|
||||||
|
#[doc = "Field `LEVEL` writer - Sets the FIFO_ENTRY_CNT value that asserts the FIFO_DEPTH_TRIG interrupt"]
|
||||||
|
pub type LevelW<'a, REG> = crate::FieldWriter<'a, REG, 5>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:4 - Sets the FIFO_ENTRY_CNT value that asserts the FIFO_DEPTH_TRIG interrupt"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn level(&self) -> LevelR {
|
||||||
|
LevelR::new((self.bits & 0x1f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:4 - Sets the FIFO_ENTRY_CNT value that asserts the FIFO_DEPTH_TRIG interrupt"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn level(&mut self) -> LevelW<RxfifoirqtrgSpec> {
|
||||||
|
LevelW::new(self, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Receive FIFO Interrupt Trigger Value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`rxfifoirqtrg::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`rxfifoirqtrg::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct RxfifoirqtrgSpec;
|
||||||
|
impl crate::RegisterSpec for RxfifoirqtrgSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`rxfifoirqtrg::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for RxfifoirqtrgSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`rxfifoirqtrg::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for RxfifoirqtrgSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets RXFIFOIRQTRG to value 0x10"]
|
||||||
|
impl crate::Resettable for RxfifoirqtrgSpec {
|
||||||
|
const RESET_VALUE: u32 = 0x10;
|
||||||
|
}
|
29
va416xx/src/adc/status.rs
Normal file
29
va416xx/src/adc/status.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#[doc = "Register `STATUS` reader"]
|
||||||
|
pub type R = crate::R<StatusSpec>;
|
||||||
|
#[doc = "Field `FIFO_ENTRY_CNT` reader - Indicates the number of entries in the FIFO"]
|
||||||
|
pub type FifoEntryCntR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ADC_BUSY` reader - Indicates an ADC data acquisition is in process"]
|
||||||
|
pub type AdcBusyR = crate::BitReader;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:5 - Indicates the number of entries in the FIFO"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fifo_entry_cnt(&self) -> FifoEntryCntR {
|
||||||
|
FifoEntryCntR::new((self.bits & 0x3f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 7 - Indicates an ADC data acquisition is in process"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn adc_busy(&self) -> AdcBusyR {
|
||||||
|
AdcBusyR::new(((self.bits >> 7) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Status\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`status::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct StatusSpec;
|
||||||
|
impl crate::RegisterSpec for StatusSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`status::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for StatusSpec {}
|
||||||
|
#[doc = "`reset()` method sets STATUS to value 0"]
|
||||||
|
impl crate::Resettable for StatusSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
1710
va416xx/src/can0.rs
Normal file
1710
va416xx/src/can0.rs
Normal file
File diff suppressed because it is too large
Load Diff
105
va416xx/src/can0/bmskb.rs
Normal file
105
va416xx/src/can0/bmskb.rs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#[doc = "Register `BMSKB` reader"]
|
||||||
|
pub type R = crate::R<BmskbSpec>;
|
||||||
|
#[doc = "Register `BMSKB` writer"]
|
||||||
|
pub type W = crate::W<BmskbSpec>;
|
||||||
|
#[doc = "Field `BM0` reader - BM\\[17:15\\]
|
||||||
|
- Unused in standard, ID\\[17:15\\]
|
||||||
|
in extended"]
|
||||||
|
pub type Bm0R = crate::FieldReader;
|
||||||
|
#[doc = "Field `BM0` writer - BM\\[17:15\\]
|
||||||
|
- Unused in standard, ID\\[17:15\\]
|
||||||
|
in extended"]
|
||||||
|
pub type Bm0W<'a, REG> = crate::FieldWriter<'a, REG, 3>;
|
||||||
|
#[doc = "Field `IDE` reader - Identifier Extension Bit"]
|
||||||
|
pub type IdeR = crate::BitReader;
|
||||||
|
#[doc = "Field `IDE` writer - Identifier Extension Bit"]
|
||||||
|
pub type IdeW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `RTR` reader - Remote Transmission Request in Standard, Substitute Remote Request (SRR) in extended"]
|
||||||
|
pub type RtrR = crate::BitReader;
|
||||||
|
#[doc = "Field `RTR` writer - Remote Transmission Request in Standard, Substitute Remote Request (SRR) in extended"]
|
||||||
|
pub type RtrW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `BM1` reader - BM\\[28:18\\]
|
||||||
|
- ID\\[10:0\\]
|
||||||
|
in standard, ID\\[28:18\\]
|
||||||
|
in extended"]
|
||||||
|
pub type Bm1R = crate::FieldReader<u16>;
|
||||||
|
#[doc = "Field `BM1` writer - BM\\[28:18\\]
|
||||||
|
- ID\\[10:0\\]
|
||||||
|
in standard, ID\\[28:18\\]
|
||||||
|
in extended"]
|
||||||
|
pub type Bm1W<'a, REG> = crate::FieldWriter<'a, REG, 11, u16>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:2 - BM\\[17:15\\]
|
||||||
|
- Unused in standard, ID\\[17:15\\]
|
||||||
|
in extended"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn bm0(&self) -> Bm0R {
|
||||||
|
Bm0R::new((self.bits & 7) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Identifier Extension Bit"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ide(&self) -> IdeR {
|
||||||
|
IdeR::new(((self.bits >> 3) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 4 - Remote Transmission Request in Standard, Substitute Remote Request (SRR) in extended"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn rtr(&self) -> RtrR {
|
||||||
|
RtrR::new(((self.bits >> 4) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 5:15 - BM\\[28:18\\]
|
||||||
|
- ID\\[10:0\\]
|
||||||
|
in standard, ID\\[28:18\\]
|
||||||
|
in extended"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn bm1(&self) -> Bm1R {
|
||||||
|
Bm1R::new(((self.bits >> 5) & 0x07ff) as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:2 - BM\\[17:15\\]
|
||||||
|
- Unused in standard, ID\\[17:15\\]
|
||||||
|
in extended"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn bm0(&mut self) -> Bm0W<BmskbSpec> {
|
||||||
|
Bm0W::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Identifier Extension Bit"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ide(&mut self) -> IdeW<BmskbSpec> {
|
||||||
|
IdeW::new(self, 3)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 4 - Remote Transmission Request in Standard, Substitute Remote Request (SRR) in extended"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn rtr(&mut self) -> RtrW<BmskbSpec> {
|
||||||
|
RtrW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 5:15 - BM\\[28:18\\]
|
||||||
|
- ID\\[10:0\\]
|
||||||
|
in standard, ID\\[28:18\\]
|
||||||
|
in extended"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn bm1(&mut self) -> Bm1W<BmskbSpec> {
|
||||||
|
Bm1W::new(self, 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Basic Mask Base\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`bmskb::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`bmskb::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct BmskbSpec;
|
||||||
|
impl crate::RegisterSpec for BmskbSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`bmskb::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for BmskbSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`bmskb::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for BmskbSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets BMSKB to value 0"]
|
||||||
|
impl crate::Resettable for BmskbSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
63
va416xx/src/can0/bmskx.rs
Normal file
63
va416xx/src/can0/bmskx.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#[doc = "Register `BMSKX` reader"]
|
||||||
|
pub type R = crate::R<BmskxSpec>;
|
||||||
|
#[doc = "Register `BMSKX` writer"]
|
||||||
|
pub type W = crate::W<BmskxSpec>;
|
||||||
|
#[doc = "Field `XRTR` reader - Extended Remote transmission Request Bit"]
|
||||||
|
pub type XrtrR = crate::BitReader;
|
||||||
|
#[doc = "Field `XRTR` writer - Extended Remote transmission Request Bit"]
|
||||||
|
pub type XrtrW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `BM` reader - BM\\[14:0\\]
|
||||||
|
used when an extended frame is received. ID\\[14:0\\]
|
||||||
|
in extended, unused standard"]
|
||||||
|
pub type BmR = crate::FieldReader<u16>;
|
||||||
|
#[doc = "Field `BM` writer - BM\\[14:0\\]
|
||||||
|
used when an extended frame is received. ID\\[14:0\\]
|
||||||
|
in extended, unused standard"]
|
||||||
|
pub type BmW<'a, REG> = crate::FieldWriter<'a, REG, 15, u16>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bit 0 - Extended Remote transmission Request Bit"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn xrtr(&self) -> XrtrR {
|
||||||
|
XrtrR::new((self.bits & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 1:15 - BM\\[14:0\\]
|
||||||
|
used when an extended frame is received. ID\\[14:0\\]
|
||||||
|
in extended, unused standard"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn bm(&self) -> BmR {
|
||||||
|
BmR::new(((self.bits >> 1) & 0x7fff) as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bit 0 - Extended Remote transmission Request Bit"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn xrtr(&mut self) -> XrtrW<BmskxSpec> {
|
||||||
|
XrtrW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 1:15 - BM\\[14:0\\]
|
||||||
|
used when an extended frame is received. ID\\[14:0\\]
|
||||||
|
in extended, unused standard"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn bm(&mut self) -> BmW<BmskxSpec> {
|
||||||
|
BmW::new(self, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Basic Mask Extension\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`bmskx::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`bmskx::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct BmskxSpec;
|
||||||
|
impl crate::RegisterSpec for BmskxSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`bmskx::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for BmskxSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`bmskx::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for BmskxSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets BMSKX to value 0"]
|
||||||
|
impl crate::Resettable for BmskxSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
55
va416xx/src/can0/canec.rs
Normal file
55
va416xx/src/can0/canec.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#[doc = "Register `CANEC` reader"]
|
||||||
|
pub type R = crate::R<CanecSpec>;
|
||||||
|
#[doc = "Register `CANEC` writer"]
|
||||||
|
pub type W = crate::W<CanecSpec>;
|
||||||
|
#[doc = "Field `TEC` reader - Transmit Error Counter"]
|
||||||
|
pub type TecR = crate::FieldReader;
|
||||||
|
#[doc = "Field `TEC` writer - Transmit Error Counter"]
|
||||||
|
pub type TecW<'a, REG> = crate::FieldWriter<'a, REG, 8>;
|
||||||
|
#[doc = "Field `REC` reader - Receive Error Counter"]
|
||||||
|
pub type RecR = crate::FieldReader;
|
||||||
|
#[doc = "Field `REC` writer - Receive Error Counter"]
|
||||||
|
pub type RecW<'a, REG> = crate::FieldWriter<'a, REG, 8>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:7 - Transmit Error Counter"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn tec(&self) -> TecR {
|
||||||
|
TecR::new((self.bits & 0xff) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 8:15 - Receive Error Counter"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn rec(&self) -> RecR {
|
||||||
|
RecR::new(((self.bits >> 8) & 0xff) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:7 - Transmit Error Counter"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn tec(&mut self) -> TecW<CanecSpec> {
|
||||||
|
TecW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 8:15 - Receive Error Counter"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn rec(&mut self) -> RecW<CanecSpec> {
|
||||||
|
RecW::new(self, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Error Counter Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`canec::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`canec::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CanecSpec;
|
||||||
|
impl crate::RegisterSpec for CanecSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`canec::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CanecSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`canec::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CanecSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CANEC to value 0"]
|
||||||
|
impl crate::Resettable for CanecSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
130
va416xx/src/can0/cediag.rs
Normal file
130
va416xx/src/can0/cediag.rs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#[doc = "Register `CEDIAG` reader"]
|
||||||
|
pub type R = crate::R<CediagSpec>;
|
||||||
|
#[doc = "Register `CEDIAG` writer"]
|
||||||
|
pub type W = crate::W<CediagSpec>;
|
||||||
|
#[doc = "Field `EFID` reader - Error Field Identifier"]
|
||||||
|
pub type EfidR = crate::FieldReader;
|
||||||
|
#[doc = "Field `EFID` writer - Error Field Identifier"]
|
||||||
|
pub type EfidW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `EBID` reader - Error Bit Identifier"]
|
||||||
|
pub type EbidR = crate::FieldReader;
|
||||||
|
#[doc = "Field `EBID` writer - Error Bit Identifier"]
|
||||||
|
pub type EbidW<'a, REG> = crate::FieldWriter<'a, REG, 6>;
|
||||||
|
#[doc = "Field `TXE` reader - Transmit Error"]
|
||||||
|
pub type TxeR = crate::BitReader;
|
||||||
|
#[doc = "Field `TXE` writer - Transmit Error"]
|
||||||
|
pub type TxeW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `STUFF` reader - Stuff Error"]
|
||||||
|
pub type StuffR = crate::BitReader;
|
||||||
|
#[doc = "Field `STUFF` writer - Stuff Error"]
|
||||||
|
pub type StuffW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `CRC` reader - CRC"]
|
||||||
|
pub type CrcR = crate::BitReader;
|
||||||
|
#[doc = "Field `CRC` writer - CRC"]
|
||||||
|
pub type CrcW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `MON` reader - Monitor"]
|
||||||
|
pub type MonR = crate::BitReader;
|
||||||
|
#[doc = "Field `MON` writer - Monitor"]
|
||||||
|
pub type MonW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `DRIVE` reader - Drive"]
|
||||||
|
pub type DriveR = crate::BitReader;
|
||||||
|
#[doc = "Field `DRIVE` writer - Drive"]
|
||||||
|
pub type DriveW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Error Field Identifier"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn efid(&self) -> EfidR {
|
||||||
|
EfidR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:9 - Error Bit Identifier"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ebid(&self) -> EbidR {
|
||||||
|
EbidR::new(((self.bits >> 4) & 0x3f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 10 - Transmit Error"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn txe(&self) -> TxeR {
|
||||||
|
TxeR::new(((self.bits >> 10) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 11 - Stuff Error"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn stuff(&self) -> StuffR {
|
||||||
|
StuffR::new(((self.bits >> 11) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 12 - CRC"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn crc(&self) -> CrcR {
|
||||||
|
CrcR::new(((self.bits >> 12) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 13 - Monitor"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn mon(&self) -> MonR {
|
||||||
|
MonR::new(((self.bits >> 13) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 14 - Drive"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn drive(&self) -> DriveR {
|
||||||
|
DriveR::new(((self.bits >> 14) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Error Field Identifier"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn efid(&mut self) -> EfidW<CediagSpec> {
|
||||||
|
EfidW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:9 - Error Bit Identifier"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ebid(&mut self) -> EbidW<CediagSpec> {
|
||||||
|
EbidW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 10 - Transmit Error"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn txe(&mut self) -> TxeW<CediagSpec> {
|
||||||
|
TxeW::new(self, 10)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 11 - Stuff Error"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn stuff(&mut self) -> StuffW<CediagSpec> {
|
||||||
|
StuffW::new(self, 11)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 12 - CRC"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn crc(&mut self) -> CrcW<CediagSpec> {
|
||||||
|
CrcW::new(self, 12)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 13 - Monitor"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn mon(&mut self) -> MonW<CediagSpec> {
|
||||||
|
MonW::new(self, 13)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 14 - Drive"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn drive(&mut self) -> DriveW<CediagSpec> {
|
||||||
|
DriveW::new(self, 14)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Error Diagnostic Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cediag::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cediag::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CediagSpec;
|
||||||
|
impl crate::RegisterSpec for CediagSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cediag::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CediagSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cediag::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CediagSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CEDIAG to value 0"]
|
||||||
|
impl crate::Resettable for CediagSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
205
va416xx/src/can0/cgcr.rs
Normal file
205
va416xx/src/can0/cgcr.rs
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
#[doc = "Register `CGCR` reader"]
|
||||||
|
pub type R = crate::R<CgcrSpec>;
|
||||||
|
#[doc = "Register `CGCR` writer"]
|
||||||
|
pub type W = crate::W<CgcrSpec>;
|
||||||
|
#[doc = "Field `CANEN` reader - CAN Enable"]
|
||||||
|
pub type CanenR = crate::BitReader;
|
||||||
|
#[doc = "Field `CANEN` writer - CAN Enable"]
|
||||||
|
pub type CanenW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `CRX` reader - RW,Control Receive"]
|
||||||
|
pub type CrxR = crate::BitReader;
|
||||||
|
#[doc = "Field `CRX` writer - RW,Control Receive"]
|
||||||
|
pub type CrxW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `CTX` reader - RW,Control Transmit"]
|
||||||
|
pub type CtxR = crate::BitReader;
|
||||||
|
#[doc = "Field `CTX` writer - RW,Control Transmit"]
|
||||||
|
pub type CtxW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `BUFFLOCK` reader - Buffer Lock"]
|
||||||
|
pub type BufflockR = crate::BitReader;
|
||||||
|
#[doc = "Field `BUFFLOCK` writer - Buffer Lock"]
|
||||||
|
pub type BufflockW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `TSTPEN` reader - Time Sync Enable"]
|
||||||
|
pub type TstpenR = crate::BitReader;
|
||||||
|
#[doc = "Field `TSTPEN` writer - Time Sync Enable"]
|
||||||
|
pub type TstpenW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `DDIR` reader - Data Direction"]
|
||||||
|
pub type DdirR = crate::BitReader;
|
||||||
|
#[doc = "Field `DDIR` writer - Data Direction"]
|
||||||
|
pub type DdirW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `LO` reader - Listen Only"]
|
||||||
|
pub type LoR = crate::BitReader;
|
||||||
|
#[doc = "Field `LO` writer - Listen Only"]
|
||||||
|
pub type LoW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `IGNACK` reader - Ignore Acknowledge"]
|
||||||
|
pub type IgnackR = crate::BitReader;
|
||||||
|
#[doc = "Field `IGNACK` writer - Ignore Acknowledge"]
|
||||||
|
pub type IgnackW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `LOOPBACK` reader - Loopback"]
|
||||||
|
pub type LoopbackR = crate::BitReader;
|
||||||
|
#[doc = "Field `LOOPBACK` writer - Loopback"]
|
||||||
|
pub type LoopbackW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `INTERNAL` reader - Internal"]
|
||||||
|
pub type InternalR = crate::BitReader;
|
||||||
|
#[doc = "Field `INTERNAL` writer - Internal"]
|
||||||
|
pub type InternalW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `DIAGEN` reader - Diagnostic Enable"]
|
||||||
|
pub type DiagenR = crate::BitReader;
|
||||||
|
#[doc = "Field `DIAGEN` writer - Diagnostic Enable"]
|
||||||
|
pub type DiagenW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
#[doc = "Field `EIT` reader - Error Interrupt Type"]
|
||||||
|
pub type EitR = crate::BitReader;
|
||||||
|
#[doc = "Field `EIT` writer - Error Interrupt Type"]
|
||||||
|
pub type EitW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bit 0 - CAN Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn canen(&self) -> CanenR {
|
||||||
|
CanenR::new((self.bits & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 1 - RW,Control Receive"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn crx(&self) -> CrxR {
|
||||||
|
CrxR::new(((self.bits >> 1) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 2 - RW,Control Transmit"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ctx(&self) -> CtxR {
|
||||||
|
CtxR::new(((self.bits >> 2) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Buffer Lock"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn bufflock(&self) -> BufflockR {
|
||||||
|
BufflockR::new(((self.bits >> 3) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 4 - Time Sync Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn tstpen(&self) -> TstpenR {
|
||||||
|
TstpenR::new(((self.bits >> 4) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 5 - Data Direction"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ddir(&self) -> DdirR {
|
||||||
|
DdirR::new(((self.bits >> 5) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 6 - Listen Only"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn lo(&self) -> LoR {
|
||||||
|
LoR::new(((self.bits >> 6) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 7 - Ignore Acknowledge"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ignack(&self) -> IgnackR {
|
||||||
|
IgnackR::new(((self.bits >> 7) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 8 - Loopback"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn loopback(&self) -> LoopbackR {
|
||||||
|
LoopbackR::new(((self.bits >> 8) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 9 - Internal"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn internal(&self) -> InternalR {
|
||||||
|
InternalR::new(((self.bits >> 9) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 10 - Diagnostic Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn diagen(&self) -> DiagenR {
|
||||||
|
DiagenR::new(((self.bits >> 10) & 1) != 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 11 - Error Interrupt Type"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn eit(&self) -> EitR {
|
||||||
|
EitR::new(((self.bits >> 11) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bit 0 - CAN Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn canen(&mut self) -> CanenW<CgcrSpec> {
|
||||||
|
CanenW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 1 - RW,Control Receive"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn crx(&mut self) -> CrxW<CgcrSpec> {
|
||||||
|
CrxW::new(self, 1)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 2 - RW,Control Transmit"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ctx(&mut self) -> CtxW<CgcrSpec> {
|
||||||
|
CtxW::new(self, 2)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 3 - Buffer Lock"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn bufflock(&mut self) -> BufflockW<CgcrSpec> {
|
||||||
|
BufflockW::new(self, 3)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 4 - Time Sync Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn tstpen(&mut self) -> TstpenW<CgcrSpec> {
|
||||||
|
TstpenW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 5 - Data Direction"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ddir(&mut self) -> DdirW<CgcrSpec> {
|
||||||
|
DdirW::new(self, 5)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 6 - Listen Only"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn lo(&mut self) -> LoW<CgcrSpec> {
|
||||||
|
LoW::new(self, 6)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 7 - Ignore Acknowledge"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ignack(&mut self) -> IgnackW<CgcrSpec> {
|
||||||
|
IgnackW::new(self, 7)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 8 - Loopback"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn loopback(&mut self) -> LoopbackW<CgcrSpec> {
|
||||||
|
LoopbackW::new(self, 8)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 9 - Internal"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn internal(&mut self) -> InternalW<CgcrSpec> {
|
||||||
|
InternalW::new(self, 9)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 10 - Diagnostic Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn diagen(&mut self) -> DiagenW<CgcrSpec> {
|
||||||
|
DiagenW::new(self, 10)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 11 - Error Interrupt Type"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn eit(&mut self) -> EitW<CgcrSpec> {
|
||||||
|
EitW::new(self, 11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Global Configuration Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cgcr::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cgcr::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CgcrSpec;
|
||||||
|
impl crate::RegisterSpec for CgcrSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cgcr::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CgcrSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cgcr::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CgcrSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CGCR to value 0"]
|
||||||
|
impl crate::Resettable for CgcrSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
55
va416xx/src/can0/cicen.rs
Normal file
55
va416xx/src/can0/cicen.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#[doc = "Register `CICEN` reader"]
|
||||||
|
pub type R = crate::R<CicenSpec>;
|
||||||
|
#[doc = "Register `CICEN` writer"]
|
||||||
|
pub type W = crate::W<CicenSpec>;
|
||||||
|
#[doc = "Field `ICEN` reader - Buffer Interrupt Code Enable\\[14:0\\]"]
|
||||||
|
pub type IcenR = crate::FieldReader<u16>;
|
||||||
|
#[doc = "Field `ICEN` writer - Buffer Interrupt Code Enable\\[14:0\\]"]
|
||||||
|
pub type IcenW<'a, REG> = crate::FieldWriter<'a, REG, 15, u16>;
|
||||||
|
#[doc = "Field `EICEN` reader - Error Interrupt Code Enable"]
|
||||||
|
pub type EicenR = crate::BitReader;
|
||||||
|
#[doc = "Field `EICEN` writer - Error Interrupt Code Enable"]
|
||||||
|
pub type EicenW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:14 - Buffer Interrupt Code Enable\\[14:0\\]"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn icen(&self) -> IcenR {
|
||||||
|
IcenR::new((self.bits & 0x7fff) as u16)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 15 - Error Interrupt Code Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn eicen(&self) -> EicenR {
|
||||||
|
EicenR::new(((self.bits >> 15) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:14 - Buffer Interrupt Code Enable\\[14:0\\]"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn icen(&mut self) -> IcenW<CicenSpec> {
|
||||||
|
IcenW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 15 - Error Interrupt Code Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn eicen(&mut self) -> EicenW<CicenSpec> {
|
||||||
|
EicenW::new(self, 15)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Interrupt Code Enable Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cicen::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cicen::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CicenSpec;
|
||||||
|
impl crate::RegisterSpec for CicenSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cicen::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CicenSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cicen::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CicenSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CICEN to value 0"]
|
||||||
|
impl crate::Resettable for CicenSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
55
va416xx/src/can0/ciclr.rs
Normal file
55
va416xx/src/can0/ciclr.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#[doc = "Register `CICLR` reader"]
|
||||||
|
pub type R = crate::R<CiclrSpec>;
|
||||||
|
#[doc = "Register `CICLR` writer"]
|
||||||
|
pub type W = crate::W<CiclrSpec>;
|
||||||
|
#[doc = "Field `ICLR` reader - Buffer Interrupt Clear\\[14:0\\]"]
|
||||||
|
pub type IclrR = crate::FieldReader<u16>;
|
||||||
|
#[doc = "Field `ICLR` writer - Buffer Interrupt Clear\\[14:0\\]"]
|
||||||
|
pub type IclrW<'a, REG> = crate::FieldWriter<'a, REG, 15, u16>;
|
||||||
|
#[doc = "Field `EICLR` reader - Error Interrupt Clear"]
|
||||||
|
pub type EiclrR = crate::BitReader;
|
||||||
|
#[doc = "Field `EICLR` writer - Error Interrupt Clear"]
|
||||||
|
pub type EiclrW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:14 - Buffer Interrupt Clear\\[14:0\\]"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn iclr(&self) -> IclrR {
|
||||||
|
IclrR::new((self.bits & 0x7fff) as u16)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 15 - Error Interrupt Clear"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn eiclr(&self) -> EiclrR {
|
||||||
|
EiclrR::new(((self.bits >> 15) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:14 - Buffer Interrupt Clear\\[14:0\\]"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn iclr(&mut self) -> IclrW<CiclrSpec> {
|
||||||
|
IclrW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 15 - Error Interrupt Clear"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn eiclr(&mut self) -> EiclrW<CiclrSpec> {
|
||||||
|
EiclrW::new(self, 15)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Interrupt Clear Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`ciclr::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`ciclr::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CiclrSpec;
|
||||||
|
impl crate::RegisterSpec for CiclrSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`ciclr::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CiclrSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`ciclr::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CiclrSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CICLR to value 0"]
|
||||||
|
impl crate::Resettable for CiclrSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
55
va416xx/src/can0/cien.rs
Normal file
55
va416xx/src/can0/cien.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#[doc = "Register `CIEN` reader"]
|
||||||
|
pub type R = crate::R<CienSpec>;
|
||||||
|
#[doc = "Register `CIEN` writer"]
|
||||||
|
pub type W = crate::W<CienSpec>;
|
||||||
|
#[doc = "Field `IEN` reader - Buffer Interrupt Enable\\[14:0\\]"]
|
||||||
|
pub type IenR = crate::FieldReader<u16>;
|
||||||
|
#[doc = "Field `IEN` writer - Buffer Interrupt Enable\\[14:0\\]"]
|
||||||
|
pub type IenW<'a, REG> = crate::FieldWriter<'a, REG, 15, u16>;
|
||||||
|
#[doc = "Field `EIEN` reader - Error Interrupt Enable"]
|
||||||
|
pub type EienR = crate::BitReader;
|
||||||
|
#[doc = "Field `EIEN` writer - Error Interrupt Enable"]
|
||||||
|
pub type EienW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:14 - Buffer Interrupt Enable\\[14:0\\]"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ien(&self) -> IenR {
|
||||||
|
IenR::new((self.bits & 0x7fff) as u16)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 15 - Error Interrupt Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn eien(&self) -> EienR {
|
||||||
|
EienR::new(((self.bits >> 15) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:14 - Buffer Interrupt Enable\\[14:0\\]"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ien(&mut self) -> IenW<CienSpec> {
|
||||||
|
IenW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 15 - Error Interrupt Enable"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn eien(&mut self) -> EienW<CienSpec> {
|
||||||
|
EienW::new(self, 15)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Interrupt Enable Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cien::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cien::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CienSpec;
|
||||||
|
impl crate::RegisterSpec for CienSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cien::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CienSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cien::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CienSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CIEN to value 0"]
|
||||||
|
impl crate::Resettable for CienSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
55
va416xx/src/can0/cipnd.rs
Normal file
55
va416xx/src/can0/cipnd.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#[doc = "Register `CIPND` reader"]
|
||||||
|
pub type R = crate::R<CipndSpec>;
|
||||||
|
#[doc = "Register `CIPND` writer"]
|
||||||
|
pub type W = crate::W<CipndSpec>;
|
||||||
|
#[doc = "Field `IPND` reader - Buffer Interrupt Pending\\[14:0\\]"]
|
||||||
|
pub type IpndR = crate::FieldReader<u16>;
|
||||||
|
#[doc = "Field `IPND` writer - Buffer Interrupt Pending\\[14:0\\]"]
|
||||||
|
pub type IpndW<'a, REG> = crate::FieldWriter<'a, REG, 15, u16>;
|
||||||
|
#[doc = "Field `EIPND` reader - Error Interrupt Pending"]
|
||||||
|
pub type EipndR = crate::BitReader;
|
||||||
|
#[doc = "Field `EIPND` writer - Error Interrupt Pending"]
|
||||||
|
pub type EipndW<'a, REG> = crate::BitWriter<'a, REG>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:14 - Buffer Interrupt Pending\\[14:0\\]"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ipnd(&self) -> IpndR {
|
||||||
|
IpndR::new((self.bits & 0x7fff) as u16)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 15 - Error Interrupt Pending"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn eipnd(&self) -> EipndR {
|
||||||
|
EipndR::new(((self.bits >> 15) & 1) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:14 - Buffer Interrupt Pending\\[14:0\\]"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ipnd(&mut self) -> IpndW<CipndSpec> {
|
||||||
|
IpndW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bit 15 - Error Interrupt Pending"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn eipnd(&mut self) -> EipndW<CipndSpec> {
|
||||||
|
EipndW::new(self, 15)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "CAN Interrupt Pending Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cipnd::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cipnd::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CipndSpec;
|
||||||
|
impl crate::RegisterSpec for CipndSpec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cipnd::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CipndSpec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cipnd::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CipndSpec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CIPND to value 0"]
|
||||||
|
impl crate::Resettable for CipndSpec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
70
va416xx/src/can0/cnstat_cmb0.rs
Normal file
70
va416xx/src/can0/cnstat_cmb0.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#[doc = "Register `CNSTAT_CMB0` reader"]
|
||||||
|
pub type R = crate::R<CnstatCmb0Spec>;
|
||||||
|
#[doc = "Register `CNSTAT_CMB0` writer"]
|
||||||
|
pub type W = crate::W<CnstatCmb0Spec>;
|
||||||
|
#[doc = "Field `ST` reader - Buffer Status"]
|
||||||
|
pub type StR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ST` writer - Buffer Status"]
|
||||||
|
pub type StW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `PRI` reader - Transmit Priority Code"]
|
||||||
|
pub type PriR = crate::FieldReader;
|
||||||
|
#[doc = "Field `PRI` writer - Transmit Priority Code"]
|
||||||
|
pub type PriW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `DLC` reader - Data Length Code"]
|
||||||
|
pub type DlcR = crate::FieldReader;
|
||||||
|
#[doc = "Field `DLC` writer - Data Length Code"]
|
||||||
|
pub type DlcW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn st(&self) -> StR {
|
||||||
|
StR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pri(&self) -> PriR {
|
||||||
|
PriR::new(((self.bits >> 4) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dlc(&self) -> DlcR {
|
||||||
|
DlcR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn st(&mut self) -> StW<CnstatCmb0Spec> {
|
||||||
|
StW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn pri(&mut self) -> PriW<CnstatCmb0Spec> {
|
||||||
|
PriW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn dlc(&mut self) -> DlcW<CnstatCmb0Spec> {
|
||||||
|
DlcW::new(self, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Buffer Status / Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cnstat_cmb0::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cnstat_cmb0::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CnstatCmb0Spec;
|
||||||
|
impl crate::RegisterSpec for CnstatCmb0Spec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cnstat_cmb0::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CnstatCmb0Spec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cnstat_cmb0::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CnstatCmb0Spec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CNSTAT_CMB0 to value 0"]
|
||||||
|
impl crate::Resettable for CnstatCmb0Spec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
70
va416xx/src/can0/cnstat_cmb1.rs
Normal file
70
va416xx/src/can0/cnstat_cmb1.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#[doc = "Register `CNSTAT_CMB1` reader"]
|
||||||
|
pub type R = crate::R<CnstatCmb1Spec>;
|
||||||
|
#[doc = "Register `CNSTAT_CMB1` writer"]
|
||||||
|
pub type W = crate::W<CnstatCmb1Spec>;
|
||||||
|
#[doc = "Field `ST` reader - Buffer Status"]
|
||||||
|
pub type StR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ST` writer - Buffer Status"]
|
||||||
|
pub type StW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `PRI` reader - Transmit Priority Code"]
|
||||||
|
pub type PriR = crate::FieldReader;
|
||||||
|
#[doc = "Field `PRI` writer - Transmit Priority Code"]
|
||||||
|
pub type PriW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `DLC` reader - Data Length Code"]
|
||||||
|
pub type DlcR = crate::FieldReader;
|
||||||
|
#[doc = "Field `DLC` writer - Data Length Code"]
|
||||||
|
pub type DlcW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn st(&self) -> StR {
|
||||||
|
StR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pri(&self) -> PriR {
|
||||||
|
PriR::new(((self.bits >> 4) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dlc(&self) -> DlcR {
|
||||||
|
DlcR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn st(&mut self) -> StW<CnstatCmb1Spec> {
|
||||||
|
StW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn pri(&mut self) -> PriW<CnstatCmb1Spec> {
|
||||||
|
PriW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn dlc(&mut self) -> DlcW<CnstatCmb1Spec> {
|
||||||
|
DlcW::new(self, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Buffer Status / Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cnstat_cmb1::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cnstat_cmb1::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CnstatCmb1Spec;
|
||||||
|
impl crate::RegisterSpec for CnstatCmb1Spec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cnstat_cmb1::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CnstatCmb1Spec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cnstat_cmb1::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CnstatCmb1Spec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CNSTAT_CMB1 to value 0"]
|
||||||
|
impl crate::Resettable for CnstatCmb1Spec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
70
va416xx/src/can0/cnstat_cmb10.rs
Normal file
70
va416xx/src/can0/cnstat_cmb10.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#[doc = "Register `CNSTAT_CMB10` reader"]
|
||||||
|
pub type R = crate::R<CnstatCmb10Spec>;
|
||||||
|
#[doc = "Register `CNSTAT_CMB10` writer"]
|
||||||
|
pub type W = crate::W<CnstatCmb10Spec>;
|
||||||
|
#[doc = "Field `ST` reader - Buffer Status"]
|
||||||
|
pub type StR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ST` writer - Buffer Status"]
|
||||||
|
pub type StW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `PRI` reader - Transmit Priority Code"]
|
||||||
|
pub type PriR = crate::FieldReader;
|
||||||
|
#[doc = "Field `PRI` writer - Transmit Priority Code"]
|
||||||
|
pub type PriW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `DLC` reader - Data Length Code"]
|
||||||
|
pub type DlcR = crate::FieldReader;
|
||||||
|
#[doc = "Field `DLC` writer - Data Length Code"]
|
||||||
|
pub type DlcW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn st(&self) -> StR {
|
||||||
|
StR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pri(&self) -> PriR {
|
||||||
|
PriR::new(((self.bits >> 4) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dlc(&self) -> DlcR {
|
||||||
|
DlcR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn st(&mut self) -> StW<CnstatCmb10Spec> {
|
||||||
|
StW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn pri(&mut self) -> PriW<CnstatCmb10Spec> {
|
||||||
|
PriW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn dlc(&mut self) -> DlcW<CnstatCmb10Spec> {
|
||||||
|
DlcW::new(self, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Buffer Status / Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cnstat_cmb10::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cnstat_cmb10::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CnstatCmb10Spec;
|
||||||
|
impl crate::RegisterSpec for CnstatCmb10Spec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cnstat_cmb10::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CnstatCmb10Spec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cnstat_cmb10::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CnstatCmb10Spec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CNSTAT_CMB10 to value 0"]
|
||||||
|
impl crate::Resettable for CnstatCmb10Spec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
70
va416xx/src/can0/cnstat_cmb11.rs
Normal file
70
va416xx/src/can0/cnstat_cmb11.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#[doc = "Register `CNSTAT_CMB11` reader"]
|
||||||
|
pub type R = crate::R<CnstatCmb11Spec>;
|
||||||
|
#[doc = "Register `CNSTAT_CMB11` writer"]
|
||||||
|
pub type W = crate::W<CnstatCmb11Spec>;
|
||||||
|
#[doc = "Field `ST` reader - Buffer Status"]
|
||||||
|
pub type StR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ST` writer - Buffer Status"]
|
||||||
|
pub type StW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `PRI` reader - Transmit Priority Code"]
|
||||||
|
pub type PriR = crate::FieldReader;
|
||||||
|
#[doc = "Field `PRI` writer - Transmit Priority Code"]
|
||||||
|
pub type PriW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `DLC` reader - Data Length Code"]
|
||||||
|
pub type DlcR = crate::FieldReader;
|
||||||
|
#[doc = "Field `DLC` writer - Data Length Code"]
|
||||||
|
pub type DlcW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn st(&self) -> StR {
|
||||||
|
StR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pri(&self) -> PriR {
|
||||||
|
PriR::new(((self.bits >> 4) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dlc(&self) -> DlcR {
|
||||||
|
DlcR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn st(&mut self) -> StW<CnstatCmb11Spec> {
|
||||||
|
StW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn pri(&mut self) -> PriW<CnstatCmb11Spec> {
|
||||||
|
PriW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn dlc(&mut self) -> DlcW<CnstatCmb11Spec> {
|
||||||
|
DlcW::new(self, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Buffer Status / Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cnstat_cmb11::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cnstat_cmb11::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CnstatCmb11Spec;
|
||||||
|
impl crate::RegisterSpec for CnstatCmb11Spec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cnstat_cmb11::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CnstatCmb11Spec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cnstat_cmb11::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CnstatCmb11Spec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CNSTAT_CMB11 to value 0"]
|
||||||
|
impl crate::Resettable for CnstatCmb11Spec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
70
va416xx/src/can0/cnstat_cmb12.rs
Normal file
70
va416xx/src/can0/cnstat_cmb12.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#[doc = "Register `CNSTAT_CMB12` reader"]
|
||||||
|
pub type R = crate::R<CnstatCmb12Spec>;
|
||||||
|
#[doc = "Register `CNSTAT_CMB12` writer"]
|
||||||
|
pub type W = crate::W<CnstatCmb12Spec>;
|
||||||
|
#[doc = "Field `ST` reader - Buffer Status"]
|
||||||
|
pub type StR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ST` writer - Buffer Status"]
|
||||||
|
pub type StW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `PRI` reader - Transmit Priority Code"]
|
||||||
|
pub type PriR = crate::FieldReader;
|
||||||
|
#[doc = "Field `PRI` writer - Transmit Priority Code"]
|
||||||
|
pub type PriW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `DLC` reader - Data Length Code"]
|
||||||
|
pub type DlcR = crate::FieldReader;
|
||||||
|
#[doc = "Field `DLC` writer - Data Length Code"]
|
||||||
|
pub type DlcW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn st(&self) -> StR {
|
||||||
|
StR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pri(&self) -> PriR {
|
||||||
|
PriR::new(((self.bits >> 4) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dlc(&self) -> DlcR {
|
||||||
|
DlcR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn st(&mut self) -> StW<CnstatCmb12Spec> {
|
||||||
|
StW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn pri(&mut self) -> PriW<CnstatCmb12Spec> {
|
||||||
|
PriW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn dlc(&mut self) -> DlcW<CnstatCmb12Spec> {
|
||||||
|
DlcW::new(self, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Buffer Status / Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cnstat_cmb12::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cnstat_cmb12::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CnstatCmb12Spec;
|
||||||
|
impl crate::RegisterSpec for CnstatCmb12Spec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cnstat_cmb12::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CnstatCmb12Spec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cnstat_cmb12::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CnstatCmb12Spec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CNSTAT_CMB12 to value 0"]
|
||||||
|
impl crate::Resettable for CnstatCmb12Spec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
70
va416xx/src/can0/cnstat_cmb13.rs
Normal file
70
va416xx/src/can0/cnstat_cmb13.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#[doc = "Register `CNSTAT_CMB13` reader"]
|
||||||
|
pub type R = crate::R<CnstatCmb13Spec>;
|
||||||
|
#[doc = "Register `CNSTAT_CMB13` writer"]
|
||||||
|
pub type W = crate::W<CnstatCmb13Spec>;
|
||||||
|
#[doc = "Field `ST` reader - Buffer Status"]
|
||||||
|
pub type StR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ST` writer - Buffer Status"]
|
||||||
|
pub type StW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `PRI` reader - Transmit Priority Code"]
|
||||||
|
pub type PriR = crate::FieldReader;
|
||||||
|
#[doc = "Field `PRI` writer - Transmit Priority Code"]
|
||||||
|
pub type PriW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `DLC` reader - Data Length Code"]
|
||||||
|
pub type DlcR = crate::FieldReader;
|
||||||
|
#[doc = "Field `DLC` writer - Data Length Code"]
|
||||||
|
pub type DlcW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn st(&self) -> StR {
|
||||||
|
StR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pri(&self) -> PriR {
|
||||||
|
PriR::new(((self.bits >> 4) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dlc(&self) -> DlcR {
|
||||||
|
DlcR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn st(&mut self) -> StW<CnstatCmb13Spec> {
|
||||||
|
StW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn pri(&mut self) -> PriW<CnstatCmb13Spec> {
|
||||||
|
PriW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn dlc(&mut self) -> DlcW<CnstatCmb13Spec> {
|
||||||
|
DlcW::new(self, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Buffer Status / Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cnstat_cmb13::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cnstat_cmb13::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CnstatCmb13Spec;
|
||||||
|
impl crate::RegisterSpec for CnstatCmb13Spec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cnstat_cmb13::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CnstatCmb13Spec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cnstat_cmb13::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CnstatCmb13Spec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CNSTAT_CMB13 to value 0"]
|
||||||
|
impl crate::Resettable for CnstatCmb13Spec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
70
va416xx/src/can0/cnstat_cmb14.rs
Normal file
70
va416xx/src/can0/cnstat_cmb14.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#[doc = "Register `CNSTAT_CMB14` reader"]
|
||||||
|
pub type R = crate::R<CnstatCmb14Spec>;
|
||||||
|
#[doc = "Register `CNSTAT_CMB14` writer"]
|
||||||
|
pub type W = crate::W<CnstatCmb14Spec>;
|
||||||
|
#[doc = "Field `ST` reader - Buffer Status"]
|
||||||
|
pub type StR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ST` writer - Buffer Status"]
|
||||||
|
pub type StW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `PRI` reader - Transmit Priority Code"]
|
||||||
|
pub type PriR = crate::FieldReader;
|
||||||
|
#[doc = "Field `PRI` writer - Transmit Priority Code"]
|
||||||
|
pub type PriW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `DLC` reader - Data Length Code"]
|
||||||
|
pub type DlcR = crate::FieldReader;
|
||||||
|
#[doc = "Field `DLC` writer - Data Length Code"]
|
||||||
|
pub type DlcW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn st(&self) -> StR {
|
||||||
|
StR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pri(&self) -> PriR {
|
||||||
|
PriR::new(((self.bits >> 4) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dlc(&self) -> DlcR {
|
||||||
|
DlcR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn st(&mut self) -> StW<CnstatCmb14Spec> {
|
||||||
|
StW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn pri(&mut self) -> PriW<CnstatCmb14Spec> {
|
||||||
|
PriW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn dlc(&mut self) -> DlcW<CnstatCmb14Spec> {
|
||||||
|
DlcW::new(self, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Buffer Status / Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cnstat_cmb14::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cnstat_cmb14::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CnstatCmb14Spec;
|
||||||
|
impl crate::RegisterSpec for CnstatCmb14Spec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cnstat_cmb14::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CnstatCmb14Spec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cnstat_cmb14::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CnstatCmb14Spec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CNSTAT_CMB14 to value 0"]
|
||||||
|
impl crate::Resettable for CnstatCmb14Spec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
70
va416xx/src/can0/cnstat_cmb2.rs
Normal file
70
va416xx/src/can0/cnstat_cmb2.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#[doc = "Register `CNSTAT_CMB2` reader"]
|
||||||
|
pub type R = crate::R<CnstatCmb2Spec>;
|
||||||
|
#[doc = "Register `CNSTAT_CMB2` writer"]
|
||||||
|
pub type W = crate::W<CnstatCmb2Spec>;
|
||||||
|
#[doc = "Field `ST` reader - Buffer Status"]
|
||||||
|
pub type StR = crate::FieldReader;
|
||||||
|
#[doc = "Field `ST` writer - Buffer Status"]
|
||||||
|
pub type StW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `PRI` reader - Transmit Priority Code"]
|
||||||
|
pub type PriR = crate::FieldReader;
|
||||||
|
#[doc = "Field `PRI` writer - Transmit Priority Code"]
|
||||||
|
pub type PriW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
#[doc = "Field `DLC` reader - Data Length Code"]
|
||||||
|
pub type DlcR = crate::FieldReader;
|
||||||
|
#[doc = "Field `DLC` writer - Data Length Code"]
|
||||||
|
pub type DlcW<'a, REG> = crate::FieldWriter<'a, REG, 4>;
|
||||||
|
impl R {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn st(&self) -> StR {
|
||||||
|
StR::new((self.bits & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pri(&self) -> PriR {
|
||||||
|
PriR::new(((self.bits >> 4) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dlc(&self) -> DlcR {
|
||||||
|
DlcR::new(((self.bits >> 12) & 0x0f) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl W {
|
||||||
|
#[doc = "Bits 0:3 - Buffer Status"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn st(&mut self) -> StW<CnstatCmb2Spec> {
|
||||||
|
StW::new(self, 0)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 4:7 - Transmit Priority Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn pri(&mut self) -> PriW<CnstatCmb2Spec> {
|
||||||
|
PriW::new(self, 4)
|
||||||
|
}
|
||||||
|
#[doc = "Bits 12:15 - Data Length Code"]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn dlc(&mut self) -> DlcW<CnstatCmb2Spec> {
|
||||||
|
DlcW::new(self, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = "Buffer Status / Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cnstat_cmb2::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cnstat_cmb2::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
|
||||||
|
pub struct CnstatCmb2Spec;
|
||||||
|
impl crate::RegisterSpec for CnstatCmb2Spec {
|
||||||
|
type Ux = u32;
|
||||||
|
}
|
||||||
|
#[doc = "`read()` method returns [`cnstat_cmb2::R`](R) reader structure"]
|
||||||
|
impl crate::Readable for CnstatCmb2Spec {}
|
||||||
|
#[doc = "`write(|w| ..)` method takes [`cnstat_cmb2::W`](W) writer structure"]
|
||||||
|
impl crate::Writable for CnstatCmb2Spec {
|
||||||
|
type Safety = crate::Unsafe;
|
||||||
|
const ZERO_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
const ONE_TO_MODIFY_FIELDS_BITMAP: u32 = 0;
|
||||||
|
}
|
||||||
|
#[doc = "`reset()` method sets CNSTAT_CMB2 to value 0"]
|
||||||
|
impl crate::Resettable for CnstatCmb2Spec {
|
||||||
|
const RESET_VALUE: u32 = 0;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user