Port FDCAN HAL to use PAC directly instead of fdcan crate.

- Provide separate FDCAN capable and Classic CAN API's
- Don't use fdcan crate dep anymore
- Provide embedded-can traits.
This commit is contained in:
Corey Schuhen 2024-02-03 09:44:00 +10:00
parent 377e58e408
commit 70b3c4374d
23 changed files with 4659 additions and 916 deletions

View File

@ -55,10 +55,12 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["un
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
embedded-hal-async = { version = "1.0" }
embedded-hal-nb = { version = "1.0" }
embedded-can = "0.4"
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
cortex-m-rt = ">=0.6.15,<0.8"
@ -80,7 +82,10 @@ chrono = { version = "^0.4", default-features = false, optional = true}
bit_field = "0.10.2"
document-features = "0.2.7"
fdcan = { version = "0.2.0", optional = true }
static_assertions = { version = "1.1" }
volatile-register = { version = "0.2.1" }
[dev-dependencies]
critical-section = { version = "1.1", features = ["std"] }
@ -695,373 +700,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ]
stm32f779bi = [ "stm32-metapac/stm32f779bi" ]
stm32f779ii = [ "stm32-metapac/stm32f779ii" ]
stm32f779ni = [ "stm32-metapac/stm32f779ni" ]
stm32g030c6 = [ "stm32-metapac/stm32g030c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g030c8 = [ "stm32-metapac/stm32g030c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g030f6 = [ "stm32-metapac/stm32g030f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g030j6 = [ "stm32-metapac/stm32g030j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g030k6 = [ "stm32-metapac/stm32g030k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g030k8 = [ "stm32-metapac/stm32g030k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031c4 = [ "stm32-metapac/stm32g031c4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031c6 = [ "stm32-metapac/stm32g031c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031c8 = [ "stm32-metapac/stm32g031c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031f4 = [ "stm32-metapac/stm32g031f4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031f6 = [ "stm32-metapac/stm32g031f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031f8 = [ "stm32-metapac/stm32g031f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031g4 = [ "stm32-metapac/stm32g031g4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031g6 = [ "stm32-metapac/stm32g031g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031g8 = [ "stm32-metapac/stm32g031g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031j4 = [ "stm32-metapac/stm32g031j4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031j6 = [ "stm32-metapac/stm32g031j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031k4 = [ "stm32-metapac/stm32g031k4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031k6 = [ "stm32-metapac/stm32g031k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031k8 = [ "stm32-metapac/stm32g031k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g031y8 = [ "stm32-metapac/stm32g031y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041c6 = [ "stm32-metapac/stm32g041c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041c8 = [ "stm32-metapac/stm32g041c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041f6 = [ "stm32-metapac/stm32g041f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041f8 = [ "stm32-metapac/stm32g041f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041g6 = [ "stm32-metapac/stm32g041g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041g8 = [ "stm32-metapac/stm32g041g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041j6 = [ "stm32-metapac/stm32g041j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041k6 = [ "stm32-metapac/stm32g041k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041k8 = [ "stm32-metapac/stm32g041k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g041y8 = [ "stm32-metapac/stm32g041y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g050c6 = [ "stm32-metapac/stm32g050c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g050c8 = [ "stm32-metapac/stm32g050c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g050f6 = [ "stm32-metapac/stm32g050f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g050k6 = [ "stm32-metapac/stm32g050k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g050k8 = [ "stm32-metapac/stm32g050k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g051c6 = [ "stm32-metapac/stm32g051c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g051c8 = [ "stm32-metapac/stm32g051c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g051f6 = [ "stm32-metapac/stm32g051f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g051f8 = [ "stm32-metapac/stm32g051f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g051g6 = [ "stm32-metapac/stm32g051g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g051g8 = [ "stm32-metapac/stm32g051g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g051k6 = [ "stm32-metapac/stm32g051k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g051k8 = [ "stm32-metapac/stm32g051k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g061c6 = [ "stm32-metapac/stm32g061c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g061c8 = [ "stm32-metapac/stm32g061c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g061f6 = [ "stm32-metapac/stm32g061f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g061f8 = [ "stm32-metapac/stm32g061f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g061g6 = [ "stm32-metapac/stm32g061g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g061g8 = [ "stm32-metapac/stm32g061g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g061k6 = [ "stm32-metapac/stm32g061k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g061k8 = [ "stm32-metapac/stm32g061k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g070cb = [ "stm32-metapac/stm32g070cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g070kb = [ "stm32-metapac/stm32g070kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g070rb = [ "stm32-metapac/stm32g070rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071c6 = [ "stm32-metapac/stm32g071c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071c8 = [ "stm32-metapac/stm32g071c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071cb = [ "stm32-metapac/stm32g071cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071eb = [ "stm32-metapac/stm32g071eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071g6 = [ "stm32-metapac/stm32g071g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071g8 = [ "stm32-metapac/stm32g071g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071gb = [ "stm32-metapac/stm32g071gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071k6 = [ "stm32-metapac/stm32g071k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071k8 = [ "stm32-metapac/stm32g071k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071kb = [ "stm32-metapac/stm32g071kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071r6 = [ "stm32-metapac/stm32g071r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071r8 = [ "stm32-metapac/stm32g071r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g071rb = [ "stm32-metapac/stm32g071rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g081cb = [ "stm32-metapac/stm32g081cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g081eb = [ "stm32-metapac/stm32g081eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g081gb = [ "stm32-metapac/stm32g081gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g081kb = [ "stm32-metapac/stm32g081kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g081rb = [ "stm32-metapac/stm32g081rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b0re = [ "stm32-metapac/stm32g0b0re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1me = [ "stm32-metapac/stm32g0b1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1re = [ "stm32-metapac/stm32g0b1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1me = [ "stm32-metapac/stm32g0c1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1re = [ "stm32-metapac/stm32g0c1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431c6 = [ "stm32-metapac/stm32g431c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431c8 = [ "stm32-metapac/stm32g431c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431cb = [ "stm32-metapac/stm32g431cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431k6 = [ "stm32-metapac/stm32g431k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431k8 = [ "stm32-metapac/stm32g431k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431kb = [ "stm32-metapac/stm32g431kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431m6 = [ "stm32-metapac/stm32g431m6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431m8 = [ "stm32-metapac/stm32g431m8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431mb = [ "stm32-metapac/stm32g431mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431r6 = [ "stm32-metapac/stm32g431r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431r8 = [ "stm32-metapac/stm32g431r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431rb = [ "stm32-metapac/stm32g431rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431v6 = [ "stm32-metapac/stm32g431v6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431v8 = [ "stm32-metapac/stm32g431v8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g431vb = [ "stm32-metapac/stm32g431vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g441cb = [ "stm32-metapac/stm32g441cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g441kb = [ "stm32-metapac/stm32g441kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g441mb = [ "stm32-metapac/stm32g441mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g441rb = [ "stm32-metapac/stm32g441rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g441vb = [ "stm32-metapac/stm32g441vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471cc = [ "stm32-metapac/stm32g471cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471ce = [ "stm32-metapac/stm32g471ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471mc = [ "stm32-metapac/stm32g471mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471me = [ "stm32-metapac/stm32g471me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471qc = [ "stm32-metapac/stm32g471qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471qe = [ "stm32-metapac/stm32g471qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471rc = [ "stm32-metapac/stm32g471rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471re = [ "stm32-metapac/stm32g471re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471vc = [ "stm32-metapac/stm32g471vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g471ve = [ "stm32-metapac/stm32g471ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473cb = [ "stm32-metapac/stm32g473cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473cc = [ "stm32-metapac/stm32g473cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473ce = [ "stm32-metapac/stm32g473ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473mb = [ "stm32-metapac/stm32g473mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473mc = [ "stm32-metapac/stm32g473mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473me = [ "stm32-metapac/stm32g473me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473pb = [ "stm32-metapac/stm32g473pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473pc = [ "stm32-metapac/stm32g473pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473pe = [ "stm32-metapac/stm32g473pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473qb = [ "stm32-metapac/stm32g473qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473qc = [ "stm32-metapac/stm32g473qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473qe = [ "stm32-metapac/stm32g473qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473rb = [ "stm32-metapac/stm32g473rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473rc = [ "stm32-metapac/stm32g473rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473re = [ "stm32-metapac/stm32g473re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473vb = [ "stm32-metapac/stm32g473vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473vc = [ "stm32-metapac/stm32g473vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g473ve = [ "stm32-metapac/stm32g473ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474cb = [ "stm32-metapac/stm32g474cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474cc = [ "stm32-metapac/stm32g474cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474ce = [ "stm32-metapac/stm32g474ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474mb = [ "stm32-metapac/stm32g474mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474mc = [ "stm32-metapac/stm32g474mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474me = [ "stm32-metapac/stm32g474me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474pb = [ "stm32-metapac/stm32g474pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474pc = [ "stm32-metapac/stm32g474pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474pe = [ "stm32-metapac/stm32g474pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474qb = [ "stm32-metapac/stm32g474qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474qc = [ "stm32-metapac/stm32g474qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474qe = [ "stm32-metapac/stm32g474qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474rb = [ "stm32-metapac/stm32g474rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474rc = [ "stm32-metapac/stm32g474rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474re = [ "stm32-metapac/stm32g474re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474vb = [ "stm32-metapac/stm32g474vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474vc = [ "stm32-metapac/stm32g474vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g474ve = [ "stm32-metapac/stm32g474ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g483ce = [ "stm32-metapac/stm32g483ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g483me = [ "stm32-metapac/stm32g483me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g483pe = [ "stm32-metapac/stm32g483pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g483qe = [ "stm32-metapac/stm32g483qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g483re = [ "stm32-metapac/stm32g483re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g483ve = [ "stm32-metapac/stm32g483ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g484ce = [ "stm32-metapac/stm32g484ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g484me = [ "stm32-metapac/stm32g484me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g484pe = [ "stm32-metapac/stm32g484pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g484qe = [ "stm32-metapac/stm32g484qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g484re = [ "stm32-metapac/stm32g484re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g484ve = [ "stm32-metapac/stm32g484ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491cc = [ "stm32-metapac/stm32g491cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491ce = [ "stm32-metapac/stm32g491ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491kc = [ "stm32-metapac/stm32g491kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491ke = [ "stm32-metapac/stm32g491ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491mc = [ "stm32-metapac/stm32g491mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491me = [ "stm32-metapac/stm32g491me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491rc = [ "stm32-metapac/stm32g491rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491re = [ "stm32-metapac/stm32g491re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491vc = [ "stm32-metapac/stm32g491vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g491ve = [ "stm32-metapac/stm32g491ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g4a1me = [ "stm32-metapac/stm32g4a1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g4a1re = [ "stm32-metapac/stm32g4a1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h503cb = [ "stm32-metapac/stm32h503cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h503eb = [ "stm32-metapac/stm32h503eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h503kb = [ "stm32-metapac/stm32h503kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h503rb = [ "stm32-metapac/stm32h503rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562ag = [ "stm32-metapac/stm32h562ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562ai = [ "stm32-metapac/stm32h562ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562ig = [ "stm32-metapac/stm32h562ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562ii = [ "stm32-metapac/stm32h562ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562rg = [ "stm32-metapac/stm32h562rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562ri = [ "stm32-metapac/stm32h562ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562vg = [ "stm32-metapac/stm32h562vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562vi = [ "stm32-metapac/stm32h562vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562zg = [ "stm32-metapac/stm32h562zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h562zi = [ "stm32-metapac/stm32h562zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563ag = [ "stm32-metapac/stm32h563ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563ai = [ "stm32-metapac/stm32h563ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563ig = [ "stm32-metapac/stm32h563ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563ii = [ "stm32-metapac/stm32h563ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563mi = [ "stm32-metapac/stm32h563mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563rg = [ "stm32-metapac/stm32h563rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563ri = [ "stm32-metapac/stm32h563ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563vg = [ "stm32-metapac/stm32h563vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563vi = [ "stm32-metapac/stm32h563vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563zg = [ "stm32-metapac/stm32h563zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h563zi = [ "stm32-metapac/stm32h563zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h573ai = [ "stm32-metapac/stm32h573ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h573ii = [ "stm32-metapac/stm32h573ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h573mi = [ "stm32-metapac/stm32h573mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h573ri = [ "stm32-metapac/stm32h573ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h573vi = [ "stm32-metapac/stm32h573vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h573zi = [ "stm32-metapac/stm32h573zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32h723ve = [ "stm32-metapac/stm32h723ve", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h723vg = [ "stm32-metapac/stm32h723vg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h723ze = [ "stm32-metapac/stm32h723ze", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h723zg = [ "stm32-metapac/stm32h723zg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725ae = [ "stm32-metapac/stm32h725ae", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725ag = [ "stm32-metapac/stm32h725ag", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725ie = [ "stm32-metapac/stm32h725ie", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725ig = [ "stm32-metapac/stm32h725ig", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725re = [ "stm32-metapac/stm32h725re", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725rg = [ "stm32-metapac/stm32h725rg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725ve = [ "stm32-metapac/stm32h725ve", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725vg = [ "stm32-metapac/stm32h725vg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725ze = [ "stm32-metapac/stm32h725ze", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h725zg = [ "stm32-metapac/stm32h725zg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h730ab = [ "stm32-metapac/stm32h730ab", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h730ib = [ "stm32-metapac/stm32h730ib", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h730vb = [ "stm32-metapac/stm32h730vb", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h730zb = [ "stm32-metapac/stm32h730zb", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h733vg = [ "stm32-metapac/stm32h733vg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h733zg = [ "stm32-metapac/stm32h733zg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h735ag = [ "stm32-metapac/stm32h735ag", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h735ig = [ "stm32-metapac/stm32h735ig", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h735rg = [ "stm32-metapac/stm32h735rg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h735vg = [ "stm32-metapac/stm32h735vg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h735zg = [ "stm32-metapac/stm32h735zg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742ag = [ "stm32-metapac/stm32h742ag", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742ai = [ "stm32-metapac/stm32h742ai", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742bg = [ "stm32-metapac/stm32h742bg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742bi = [ "stm32-metapac/stm32h742bi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742ig = [ "stm32-metapac/stm32h742ig", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742ii = [ "stm32-metapac/stm32h742ii", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742vg = [ "stm32-metapac/stm32h742vg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742vi = [ "stm32-metapac/stm32h742vi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742xg = [ "stm32-metapac/stm32h742xg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742xi = [ "stm32-metapac/stm32h742xi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742zg = [ "stm32-metapac/stm32h742zg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h742zi = [ "stm32-metapac/stm32h742zi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743ag = [ "stm32-metapac/stm32h743ag", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743ai = [ "stm32-metapac/stm32h743ai", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743bg = [ "stm32-metapac/stm32h743bg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743bi = [ "stm32-metapac/stm32h743bi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743ig = [ "stm32-metapac/stm32h743ig", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743ii = [ "stm32-metapac/stm32h743ii", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743vg = [ "stm32-metapac/stm32h743vg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743vi = [ "stm32-metapac/stm32h743vi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743xg = [ "stm32-metapac/stm32h743xg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743xi = [ "stm32-metapac/stm32h743xi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743zg = [ "stm32-metapac/stm32h743zg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h743zi = [ "stm32-metapac/stm32h743zi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h750ib = [ "stm32-metapac/stm32h750ib", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h750vb = [ "stm32-metapac/stm32h750vb", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h750xb = [ "stm32-metapac/stm32h750xb", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h750zb = [ "stm32-metapac/stm32h750zb", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h753ai = [ "stm32-metapac/stm32h753ai", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h753bi = [ "stm32-metapac/stm32h753bi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h753ii = [ "stm32-metapac/stm32h753ii", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h753vi = [ "stm32-metapac/stm32h753vi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h753xi = [ "stm32-metapac/stm32h753xi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h753zi = [ "stm32-metapac/stm32h753zi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3li = [ "stm32-metapac/stm32h7a3li", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b3li = [ "stm32-metapac/stm32h7b3li", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi", "dep:fdcan", "fdcan/fdcan_h7" ]
stm32g030c6 = [ "stm32-metapac/stm32g030c6" ]
stm32g030c8 = [ "stm32-metapac/stm32g030c8" ]
stm32g030f6 = [ "stm32-metapac/stm32g030f6" ]
stm32g030j6 = [ "stm32-metapac/stm32g030j6" ]
stm32g030k6 = [ "stm32-metapac/stm32g030k6" ]
stm32g030k8 = [ "stm32-metapac/stm32g030k8" ]
stm32g031c4 = [ "stm32-metapac/stm32g031c4" ]
stm32g031c6 = [ "stm32-metapac/stm32g031c6" ]
stm32g031c8 = [ "stm32-metapac/stm32g031c8" ]
stm32g031f4 = [ "stm32-metapac/stm32g031f4" ]
stm32g031f6 = [ "stm32-metapac/stm32g031f6" ]
stm32g031f8 = [ "stm32-metapac/stm32g031f8" ]
stm32g031g4 = [ "stm32-metapac/stm32g031g4" ]
stm32g031g6 = [ "stm32-metapac/stm32g031g6" ]
stm32g031g8 = [ "stm32-metapac/stm32g031g8" ]
stm32g031j4 = [ "stm32-metapac/stm32g031j4" ]
stm32g031j6 = [ "stm32-metapac/stm32g031j6" ]
stm32g031k4 = [ "stm32-metapac/stm32g031k4" ]
stm32g031k6 = [ "stm32-metapac/stm32g031k6" ]
stm32g031k8 = [ "stm32-metapac/stm32g031k8" ]
stm32g031y8 = [ "stm32-metapac/stm32g031y8" ]
stm32g041c6 = [ "stm32-metapac/stm32g041c6" ]
stm32g041c8 = [ "stm32-metapac/stm32g041c8" ]
stm32g041f6 = [ "stm32-metapac/stm32g041f6" ]
stm32g041f8 = [ "stm32-metapac/stm32g041f8" ]
stm32g041g6 = [ "stm32-metapac/stm32g041g6" ]
stm32g041g8 = [ "stm32-metapac/stm32g041g8" ]
stm32g041j6 = [ "stm32-metapac/stm32g041j6" ]
stm32g041k6 = [ "stm32-metapac/stm32g041k6" ]
stm32g041k8 = [ "stm32-metapac/stm32g041k8" ]
stm32g041y8 = [ "stm32-metapac/stm32g041y8" ]
stm32g050c6 = [ "stm32-metapac/stm32g050c6" ]
stm32g050c8 = [ "stm32-metapac/stm32g050c8" ]
stm32g050f6 = [ "stm32-metapac/stm32g050f6" ]
stm32g050k6 = [ "stm32-metapac/stm32g050k6" ]
stm32g050k8 = [ "stm32-metapac/stm32g050k8" ]
stm32g051c6 = [ "stm32-metapac/stm32g051c6" ]
stm32g051c8 = [ "stm32-metapac/stm32g051c8" ]
stm32g051f6 = [ "stm32-metapac/stm32g051f6" ]
stm32g051f8 = [ "stm32-metapac/stm32g051f8" ]
stm32g051g6 = [ "stm32-metapac/stm32g051g6" ]
stm32g051g8 = [ "stm32-metapac/stm32g051g8" ]
stm32g051k6 = [ "stm32-metapac/stm32g051k6" ]
stm32g051k8 = [ "stm32-metapac/stm32g051k8" ]
stm32g061c6 = [ "stm32-metapac/stm32g061c6" ]
stm32g061c8 = [ "stm32-metapac/stm32g061c8" ]
stm32g061f6 = [ "stm32-metapac/stm32g061f6" ]
stm32g061f8 = [ "stm32-metapac/stm32g061f8" ]
stm32g061g6 = [ "stm32-metapac/stm32g061g6" ]
stm32g061g8 = [ "stm32-metapac/stm32g061g8" ]
stm32g061k6 = [ "stm32-metapac/stm32g061k6" ]
stm32g061k8 = [ "stm32-metapac/stm32g061k8" ]
stm32g070cb = [ "stm32-metapac/stm32g070cb" ]
stm32g070kb = [ "stm32-metapac/stm32g070kb" ]
stm32g070rb = [ "stm32-metapac/stm32g070rb" ]
stm32g071c6 = [ "stm32-metapac/stm32g071c6" ]
stm32g071c8 = [ "stm32-metapac/stm32g071c8" ]
stm32g071cb = [ "stm32-metapac/stm32g071cb" ]
stm32g071eb = [ "stm32-metapac/stm32g071eb" ]
stm32g071g6 = [ "stm32-metapac/stm32g071g6" ]
stm32g071g8 = [ "stm32-metapac/stm32g071g8" ]
stm32g071gb = [ "stm32-metapac/stm32g071gb" ]
stm32g071k6 = [ "stm32-metapac/stm32g071k6" ]
stm32g071k8 = [ "stm32-metapac/stm32g071k8" ]
stm32g071kb = [ "stm32-metapac/stm32g071kb" ]
stm32g071r6 = [ "stm32-metapac/stm32g071r6" ]
stm32g071r8 = [ "stm32-metapac/stm32g071r8" ]
stm32g071rb = [ "stm32-metapac/stm32g071rb" ]
stm32g081cb = [ "stm32-metapac/stm32g081cb" ]
stm32g081eb = [ "stm32-metapac/stm32g081eb" ]
stm32g081gb = [ "stm32-metapac/stm32g081gb" ]
stm32g081kb = [ "stm32-metapac/stm32g081kb" ]
stm32g081rb = [ "stm32-metapac/stm32g081rb" ]
stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce" ]
stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke" ]
stm32g0b0re = [ "stm32-metapac/stm32g0b0re" ]
stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve" ]
stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb" ]
stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc" ]
stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce" ]
stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb" ]
stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc" ]
stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke" ]
stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb" ]
stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc" ]
stm32g0b1me = [ "stm32-metapac/stm32g0b1me" ]
stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne" ]
stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb" ]
stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc" ]
stm32g0b1re = [ "stm32-metapac/stm32g0b1re" ]
stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb" ]
stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc" ]
stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve" ]
stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc" ]
stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce" ]
stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc" ]
stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke" ]
stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc" ]
stm32g0c1me = [ "stm32-metapac/stm32g0c1me" ]
stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne" ]
stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc" ]
stm32g0c1re = [ "stm32-metapac/stm32g0c1re" ]
stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc" ]
stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve" ]
stm32g431c6 = [ "stm32-metapac/stm32g431c6" ]
stm32g431c8 = [ "stm32-metapac/stm32g431c8" ]
stm32g431cb = [ "stm32-metapac/stm32g431cb" ]
stm32g431k6 = [ "stm32-metapac/stm32g431k6" ]
stm32g431k8 = [ "stm32-metapac/stm32g431k8" ]
stm32g431kb = [ "stm32-metapac/stm32g431kb" ]
stm32g431m6 = [ "stm32-metapac/stm32g431m6" ]
stm32g431m8 = [ "stm32-metapac/stm32g431m8" ]
stm32g431mb = [ "stm32-metapac/stm32g431mb" ]
stm32g431r6 = [ "stm32-metapac/stm32g431r6" ]
stm32g431r8 = [ "stm32-metapac/stm32g431r8" ]
stm32g431rb = [ "stm32-metapac/stm32g431rb" ]
stm32g431v6 = [ "stm32-metapac/stm32g431v6" ]
stm32g431v8 = [ "stm32-metapac/stm32g431v8" ]
stm32g431vb = [ "stm32-metapac/stm32g431vb" ]
stm32g441cb = [ "stm32-metapac/stm32g441cb" ]
stm32g441kb = [ "stm32-metapac/stm32g441kb" ]
stm32g441mb = [ "stm32-metapac/stm32g441mb" ]
stm32g441rb = [ "stm32-metapac/stm32g441rb" ]
stm32g441vb = [ "stm32-metapac/stm32g441vb" ]
stm32g471cc = [ "stm32-metapac/stm32g471cc" ]
stm32g471ce = [ "stm32-metapac/stm32g471ce" ]
stm32g471mc = [ "stm32-metapac/stm32g471mc" ]
stm32g471me = [ "stm32-metapac/stm32g471me" ]
stm32g471qc = [ "stm32-metapac/stm32g471qc" ]
stm32g471qe = [ "stm32-metapac/stm32g471qe" ]
stm32g471rc = [ "stm32-metapac/stm32g471rc" ]
stm32g471re = [ "stm32-metapac/stm32g471re" ]
stm32g471vc = [ "stm32-metapac/stm32g471vc" ]
stm32g471ve = [ "stm32-metapac/stm32g471ve" ]
stm32g473cb = [ "stm32-metapac/stm32g473cb" ]
stm32g473cc = [ "stm32-metapac/stm32g473cc" ]
stm32g473ce = [ "stm32-metapac/stm32g473ce" ]
stm32g473mb = [ "stm32-metapac/stm32g473mb" ]
stm32g473mc = [ "stm32-metapac/stm32g473mc" ]
stm32g473me = [ "stm32-metapac/stm32g473me" ]
stm32g473pb = [ "stm32-metapac/stm32g473pb" ]
stm32g473pc = [ "stm32-metapac/stm32g473pc" ]
stm32g473pe = [ "stm32-metapac/stm32g473pe" ]
stm32g473qb = [ "stm32-metapac/stm32g473qb" ]
stm32g473qc = [ "stm32-metapac/stm32g473qc" ]
stm32g473qe = [ "stm32-metapac/stm32g473qe" ]
stm32g473rb = [ "stm32-metapac/stm32g473rb" ]
stm32g473rc = [ "stm32-metapac/stm32g473rc" ]
stm32g473re = [ "stm32-metapac/stm32g473re" ]
stm32g473vb = [ "stm32-metapac/stm32g473vb" ]
stm32g473vc = [ "stm32-metapac/stm32g473vc" ]
stm32g473ve = [ "stm32-metapac/stm32g473ve" ]
stm32g474cb = [ "stm32-metapac/stm32g474cb" ]
stm32g474cc = [ "stm32-metapac/stm32g474cc" ]
stm32g474ce = [ "stm32-metapac/stm32g474ce" ]
stm32g474mb = [ "stm32-metapac/stm32g474mb" ]
stm32g474mc = [ "stm32-metapac/stm32g474mc" ]
stm32g474me = [ "stm32-metapac/stm32g474me" ]
stm32g474pb = [ "stm32-metapac/stm32g474pb" ]
stm32g474pc = [ "stm32-metapac/stm32g474pc" ]
stm32g474pe = [ "stm32-metapac/stm32g474pe" ]
stm32g474qb = [ "stm32-metapac/stm32g474qb" ]
stm32g474qc = [ "stm32-metapac/stm32g474qc" ]
stm32g474qe = [ "stm32-metapac/stm32g474qe" ]
stm32g474rb = [ "stm32-metapac/stm32g474rb" ]
stm32g474rc = [ "stm32-metapac/stm32g474rc" ]
stm32g474re = [ "stm32-metapac/stm32g474re" ]
stm32g474vb = [ "stm32-metapac/stm32g474vb" ]
stm32g474vc = [ "stm32-metapac/stm32g474vc" ]
stm32g474ve = [ "stm32-metapac/stm32g474ve" ]
stm32g483ce = [ "stm32-metapac/stm32g483ce" ]
stm32g483me = [ "stm32-metapac/stm32g483me" ]
stm32g483pe = [ "stm32-metapac/stm32g483pe" ]
stm32g483qe = [ "stm32-metapac/stm32g483qe" ]
stm32g483re = [ "stm32-metapac/stm32g483re" ]
stm32g483ve = [ "stm32-metapac/stm32g483ve" ]
stm32g484ce = [ "stm32-metapac/stm32g484ce" ]
stm32g484me = [ "stm32-metapac/stm32g484me" ]
stm32g484pe = [ "stm32-metapac/stm32g484pe" ]
stm32g484qe = [ "stm32-metapac/stm32g484qe" ]
stm32g484re = [ "stm32-metapac/stm32g484re" ]
stm32g484ve = [ "stm32-metapac/stm32g484ve" ]
stm32g491cc = [ "stm32-metapac/stm32g491cc" ]
stm32g491ce = [ "stm32-metapac/stm32g491ce" ]
stm32g491kc = [ "stm32-metapac/stm32g491kc" ]
stm32g491ke = [ "stm32-metapac/stm32g491ke" ]
stm32g491mc = [ "stm32-metapac/stm32g491mc" ]
stm32g491me = [ "stm32-metapac/stm32g491me" ]
stm32g491rc = [ "stm32-metapac/stm32g491rc" ]
stm32g491re = [ "stm32-metapac/stm32g491re" ]
stm32g491vc = [ "stm32-metapac/stm32g491vc" ]
stm32g491ve = [ "stm32-metapac/stm32g491ve" ]
stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce" ]
stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ]
stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ]
stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ]
stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ]
stm32h503cb = [ "stm32-metapac/stm32h503cb" ]
stm32h503eb = [ "stm32-metapac/stm32h503eb" ]
stm32h503kb = [ "stm32-metapac/stm32h503kb" ]
stm32h503rb = [ "stm32-metapac/stm32h503rb" ]
stm32h562ag = [ "stm32-metapac/stm32h562ag" ]
stm32h562ai = [ "stm32-metapac/stm32h562ai" ]
stm32h562ig = [ "stm32-metapac/stm32h562ig" ]
stm32h562ii = [ "stm32-metapac/stm32h562ii" ]
stm32h562rg = [ "stm32-metapac/stm32h562rg" ]
stm32h562ri = [ "stm32-metapac/stm32h562ri" ]
stm32h562vg = [ "stm32-metapac/stm32h562vg" ]
stm32h562vi = [ "stm32-metapac/stm32h562vi" ]
stm32h562zg = [ "stm32-metapac/stm32h562zg" ]
stm32h562zi = [ "stm32-metapac/stm32h562zi" ]
stm32h563ag = [ "stm32-metapac/stm32h563ag" ]
stm32h563ai = [ "stm32-metapac/stm32h563ai" ]
stm32h563ig = [ "stm32-metapac/stm32h563ig" ]
stm32h563ii = [ "stm32-metapac/stm32h563ii" ]
stm32h563mi = [ "stm32-metapac/stm32h563mi" ]
stm32h563rg = [ "stm32-metapac/stm32h563rg" ]
stm32h563ri = [ "stm32-metapac/stm32h563ri" ]
stm32h563vg = [ "stm32-metapac/stm32h563vg" ]
stm32h563vi = [ "stm32-metapac/stm32h563vi" ]
stm32h563zg = [ "stm32-metapac/stm32h563zg" ]
stm32h563zi = [ "stm32-metapac/stm32h563zi" ]
stm32h573ai = [ "stm32-metapac/stm32h573ai" ]
stm32h573ii = [ "stm32-metapac/stm32h573ii" ]
stm32h573mi = [ "stm32-metapac/stm32h573mi" ]
stm32h573ri = [ "stm32-metapac/stm32h573ri" ]
stm32h573vi = [ "stm32-metapac/stm32h573vi" ]
stm32h573zi = [ "stm32-metapac/stm32h573zi" ]
stm32h723ve = [ "stm32-metapac/stm32h723ve" ]
stm32h723vg = [ "stm32-metapac/stm32h723vg" ]
stm32h723ze = [ "stm32-metapac/stm32h723ze" ]
stm32h723zg = [ "stm32-metapac/stm32h723zg" ]
stm32h725ae = [ "stm32-metapac/stm32h725ae" ]
stm32h725ag = [ "stm32-metapac/stm32h725ag" ]
stm32h725ie = [ "stm32-metapac/stm32h725ie" ]
stm32h725ig = [ "stm32-metapac/stm32h725ig" ]
stm32h725re = [ "stm32-metapac/stm32h725re" ]
stm32h725rg = [ "stm32-metapac/stm32h725rg" ]
stm32h725ve = [ "stm32-metapac/stm32h725ve" ]
stm32h725vg = [ "stm32-metapac/stm32h725vg" ]
stm32h725ze = [ "stm32-metapac/stm32h725ze" ]
stm32h725zg = [ "stm32-metapac/stm32h725zg" ]
stm32h730ab = [ "stm32-metapac/stm32h730ab" ]
stm32h730ib = [ "stm32-metapac/stm32h730ib" ]
stm32h730vb = [ "stm32-metapac/stm32h730vb" ]
stm32h730zb = [ "stm32-metapac/stm32h730zb" ]
stm32h733vg = [ "stm32-metapac/stm32h733vg" ]
stm32h733zg = [ "stm32-metapac/stm32h733zg" ]
stm32h735ag = [ "stm32-metapac/stm32h735ag" ]
stm32h735ig = [ "stm32-metapac/stm32h735ig" ]
stm32h735rg = [ "stm32-metapac/stm32h735rg" ]
stm32h735vg = [ "stm32-metapac/stm32h735vg" ]
stm32h735zg = [ "stm32-metapac/stm32h735zg" ]
stm32h742ag = [ "stm32-metapac/stm32h742ag" ]
stm32h742ai = [ "stm32-metapac/stm32h742ai" ]
stm32h742bg = [ "stm32-metapac/stm32h742bg" ]
stm32h742bi = [ "stm32-metapac/stm32h742bi" ]
stm32h742ig = [ "stm32-metapac/stm32h742ig" ]
stm32h742ii = [ "stm32-metapac/stm32h742ii" ]
stm32h742vg = [ "stm32-metapac/stm32h742vg" ]
stm32h742vi = [ "stm32-metapac/stm32h742vi" ]
stm32h742xg = [ "stm32-metapac/stm32h742xg" ]
stm32h742xi = [ "stm32-metapac/stm32h742xi" ]
stm32h742zg = [ "stm32-metapac/stm32h742zg" ]
stm32h742zi = [ "stm32-metapac/stm32h742zi" ]
stm32h743ag = [ "stm32-metapac/stm32h743ag" ]
stm32h743ai = [ "stm32-metapac/stm32h743ai" ]
stm32h743bg = [ "stm32-metapac/stm32h743bg" ]
stm32h743bi = [ "stm32-metapac/stm32h743bi" ]
stm32h743ig = [ "stm32-metapac/stm32h743ig" ]
stm32h743ii = [ "stm32-metapac/stm32h743ii" ]
stm32h743vg = [ "stm32-metapac/stm32h743vg" ]
stm32h743vi = [ "stm32-metapac/stm32h743vi" ]
stm32h743xg = [ "stm32-metapac/stm32h743xg" ]
stm32h743xi = [ "stm32-metapac/stm32h743xi" ]
stm32h743zg = [ "stm32-metapac/stm32h743zg" ]
stm32h743zi = [ "stm32-metapac/stm32h743zi" ]
stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ]
stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ]
stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ]
stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ]
stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ]
stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ]
stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ]
stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ]
stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ]
stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ]
stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ]
stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ]
stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ]
stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ]
stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ]
stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ]
stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ]
stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ]
stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ]
stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ]
stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ]
stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ]
stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ]
stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ]
stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ]
stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ]
stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ]
stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ]
stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ]
stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ]
stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ]
stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ]
stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ]
stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ]
stm32h750ib = [ "stm32-metapac/stm32h750ib" ]
stm32h750vb = [ "stm32-metapac/stm32h750vb" ]
stm32h750xb = [ "stm32-metapac/stm32h750xb" ]
stm32h750zb = [ "stm32-metapac/stm32h750zb" ]
stm32h753ai = [ "stm32-metapac/stm32h753ai" ]
stm32h753bi = [ "stm32-metapac/stm32h753bi" ]
stm32h753ii = [ "stm32-metapac/stm32h753ii" ]
stm32h753vi = [ "stm32-metapac/stm32h753vi" ]
stm32h753xi = [ "stm32-metapac/stm32h753xi" ]
stm32h753zi = [ "stm32-metapac/stm32h753zi" ]
stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ]
stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ]
stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ]
stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ]
stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ]
stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ]
stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ]
stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ]
stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ]
stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ]
stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ]
stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ]
stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ]
stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ]
stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ]
stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ]
stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ]
stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ]
stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ]
stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ]
stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ]
stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii" ]
stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg" ]
stm32h7a3li = [ "stm32-metapac/stm32h7a3li" ]
stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng" ]
stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni" ]
stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi" ]
stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg" ]
stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri" ]
stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg" ]
stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi" ]
stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg" ]
stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi" ]
stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab" ]
stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib" ]
stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb" ]
stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb" ]
stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb" ]
stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai" ]
stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii" ]
stm32h7b3li = [ "stm32-metapac/stm32h7b3li" ]
stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni" ]
stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ]
stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ]
stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ]
stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ]
stm32l010c6 = [ "stm32-metapac/stm32l010c6" ]
stm32l010f4 = [ "stm32-metapac/stm32l010f4" ]
stm32l010k4 = [ "stm32-metapac/stm32l010k4" ]
@ -1388,86 +1393,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ]
stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ]
stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ]
stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ]
stm32l552cc = [ "stm32-metapac/stm32l552cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552ce = [ "stm32-metapac/stm32l552ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552me = [ "stm32-metapac/stm32l552me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552qc = [ "stm32-metapac/stm32l552qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552qe = [ "stm32-metapac/stm32l552qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552rc = [ "stm32-metapac/stm32l552rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552re = [ "stm32-metapac/stm32l552re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552vc = [ "stm32-metapac/stm32l552vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552ve = [ "stm32-metapac/stm32l552ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552zc = [ "stm32-metapac/stm32l552zc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552ze = [ "stm32-metapac/stm32l552ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l562ce = [ "stm32-metapac/stm32l562ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l562me = [ "stm32-metapac/stm32l562me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l562qe = [ "stm32-metapac/stm32l562qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l562re = [ "stm32-metapac/stm32l562re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l562ve = [ "stm32-metapac/stm32l562ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l562ze = [ "stm32-metapac/stm32l562ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535cb = [ "stm32-metapac/stm32u535cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535cc = [ "stm32-metapac/stm32u535cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535ce = [ "stm32-metapac/stm32u535ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535je = [ "stm32-metapac/stm32u535je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535nc = [ "stm32-metapac/stm32u535nc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535ne = [ "stm32-metapac/stm32u535ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535rb = [ "stm32-metapac/stm32u535rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535rc = [ "stm32-metapac/stm32u535rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535re = [ "stm32-metapac/stm32u535re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535vc = [ "stm32-metapac/stm32u535vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u535ve = [ "stm32-metapac/stm32u535ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u545ce = [ "stm32-metapac/stm32u545ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u545je = [ "stm32-metapac/stm32u545je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u545ne = [ "stm32-metapac/stm32u545ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u545re = [ "stm32-metapac/stm32u545re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u545ve = [ "stm32-metapac/stm32u545ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575ag = [ "stm32-metapac/stm32u575ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575ai = [ "stm32-metapac/stm32u575ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575cg = [ "stm32-metapac/stm32u575cg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575ci = [ "stm32-metapac/stm32u575ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575og = [ "stm32-metapac/stm32u575og", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575oi = [ "stm32-metapac/stm32u575oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575qg = [ "stm32-metapac/stm32u575qg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575qi = [ "stm32-metapac/stm32u575qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575rg = [ "stm32-metapac/stm32u575rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575ri = [ "stm32-metapac/stm32u575ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575vg = [ "stm32-metapac/stm32u575vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575vi = [ "stm32-metapac/stm32u575vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575zg = [ "stm32-metapac/stm32u575zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u575zi = [ "stm32-metapac/stm32u575zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u585ai = [ "stm32-metapac/stm32u585ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u585ci = [ "stm32-metapac/stm32u585ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u585oi = [ "stm32-metapac/stm32u585oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u585qi = [ "stm32-metapac/stm32u585qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u585ri = [ "stm32-metapac/stm32u585ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u585vi = [ "stm32-metapac/stm32u585vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u585zi = [ "stm32-metapac/stm32u585zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595ai = [ "stm32-metapac/stm32u595ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595aj = [ "stm32-metapac/stm32u595aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595qi = [ "stm32-metapac/stm32u595qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595qj = [ "stm32-metapac/stm32u595qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595ri = [ "stm32-metapac/stm32u595ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595rj = [ "stm32-metapac/stm32u595rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595vi = [ "stm32-metapac/stm32u595vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595vj = [ "stm32-metapac/stm32u595vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595zi = [ "stm32-metapac/stm32u595zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u595zj = [ "stm32-metapac/stm32u595zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u599bj = [ "stm32-metapac/stm32u599bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u599ni = [ "stm32-metapac/stm32u599ni", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u599nj = [ "stm32-metapac/stm32u599nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u599vi = [ "stm32-metapac/stm32u599vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u599vj = [ "stm32-metapac/stm32u599vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u599zi = [ "stm32-metapac/stm32u599zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u599zj = [ "stm32-metapac/stm32u599zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
stm32l552cc = [ "stm32-metapac/stm32l552cc" ]
stm32l552ce = [ "stm32-metapac/stm32l552ce" ]
stm32l552me = [ "stm32-metapac/stm32l552me" ]
stm32l552qc = [ "stm32-metapac/stm32l552qc" ]
stm32l552qe = [ "stm32-metapac/stm32l552qe" ]
stm32l552rc = [ "stm32-metapac/stm32l552rc" ]
stm32l552re = [ "stm32-metapac/stm32l552re" ]
stm32l552vc = [ "stm32-metapac/stm32l552vc" ]
stm32l552ve = [ "stm32-metapac/stm32l552ve" ]
stm32l552zc = [ "stm32-metapac/stm32l552zc" ]
stm32l552ze = [ "stm32-metapac/stm32l552ze" ]
stm32l562ce = [ "stm32-metapac/stm32l562ce" ]
stm32l562me = [ "stm32-metapac/stm32l562me" ]
stm32l562qe = [ "stm32-metapac/stm32l562qe" ]
stm32l562re = [ "stm32-metapac/stm32l562re" ]
stm32l562ve = [ "stm32-metapac/stm32l562ve" ]
stm32l562ze = [ "stm32-metapac/stm32l562ze" ]
stm32u535cb = [ "stm32-metapac/stm32u535cb" ]
stm32u535cc = [ "stm32-metapac/stm32u535cc" ]
stm32u535ce = [ "stm32-metapac/stm32u535ce" ]
stm32u535je = [ "stm32-metapac/stm32u535je" ]
stm32u535nc = [ "stm32-metapac/stm32u535nc" ]
stm32u535ne = [ "stm32-metapac/stm32u535ne" ]
stm32u535rb = [ "stm32-metapac/stm32u535rb" ]
stm32u535rc = [ "stm32-metapac/stm32u535rc" ]
stm32u535re = [ "stm32-metapac/stm32u535re" ]
stm32u535vc = [ "stm32-metapac/stm32u535vc" ]
stm32u535ve = [ "stm32-metapac/stm32u535ve" ]
stm32u545ce = [ "stm32-metapac/stm32u545ce" ]
stm32u545je = [ "stm32-metapac/stm32u545je" ]
stm32u545ne = [ "stm32-metapac/stm32u545ne" ]
stm32u545re = [ "stm32-metapac/stm32u545re" ]
stm32u545ve = [ "stm32-metapac/stm32u545ve" ]
stm32u575ag = [ "stm32-metapac/stm32u575ag" ]
stm32u575ai = [ "stm32-metapac/stm32u575ai" ]
stm32u575cg = [ "stm32-metapac/stm32u575cg" ]
stm32u575ci = [ "stm32-metapac/stm32u575ci" ]
stm32u575og = [ "stm32-metapac/stm32u575og" ]
stm32u575oi = [ "stm32-metapac/stm32u575oi" ]
stm32u575qg = [ "stm32-metapac/stm32u575qg" ]
stm32u575qi = [ "stm32-metapac/stm32u575qi" ]
stm32u575rg = [ "stm32-metapac/stm32u575rg" ]
stm32u575ri = [ "stm32-metapac/stm32u575ri" ]
stm32u575vg = [ "stm32-metapac/stm32u575vg" ]
stm32u575vi = [ "stm32-metapac/stm32u575vi" ]
stm32u575zg = [ "stm32-metapac/stm32u575zg" ]
stm32u575zi = [ "stm32-metapac/stm32u575zi" ]
stm32u585ai = [ "stm32-metapac/stm32u585ai" ]
stm32u585ci = [ "stm32-metapac/stm32u585ci" ]
stm32u585oi = [ "stm32-metapac/stm32u585oi" ]
stm32u585qi = [ "stm32-metapac/stm32u585qi" ]
stm32u585ri = [ "stm32-metapac/stm32u585ri" ]
stm32u585vi = [ "stm32-metapac/stm32u585vi" ]
stm32u585zi = [ "stm32-metapac/stm32u585zi" ]
stm32u595ai = [ "stm32-metapac/stm32u595ai" ]
stm32u595aj = [ "stm32-metapac/stm32u595aj" ]
stm32u595qi = [ "stm32-metapac/stm32u595qi" ]
stm32u595qj = [ "stm32-metapac/stm32u595qj" ]
stm32u595ri = [ "stm32-metapac/stm32u595ri" ]
stm32u595rj = [ "stm32-metapac/stm32u595rj" ]
stm32u595vi = [ "stm32-metapac/stm32u595vi" ]
stm32u595vj = [ "stm32-metapac/stm32u595vj" ]
stm32u595zi = [ "stm32-metapac/stm32u595zi" ]
stm32u595zj = [ "stm32-metapac/stm32u595zj" ]
stm32u599bj = [ "stm32-metapac/stm32u599bj" ]
stm32u599ni = [ "stm32-metapac/stm32u599ni" ]
stm32u599nj = [ "stm32-metapac/stm32u599nj" ]
stm32u599vi = [ "stm32-metapac/stm32u599vi" ]
stm32u599vj = [ "stm32-metapac/stm32u599vj" ]
stm32u599zi = [ "stm32-metapac/stm32u599zi" ]
stm32u599zj = [ "stm32-metapac/stm32u599zj" ]
stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ]
stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ]
stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ]
stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ]
stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ]
stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ]
stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ]
stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ]
stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ]
stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ]
stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ]
stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ]

View File

@ -1,4 +1,5 @@
//! Enums shared between CAN controller types.
use core::convert::TryFrom;
/// Bus error
#[derive(Debug)]
@ -28,3 +29,19 @@ pub enum BusError {
/// At least one of error counter has reached the Error_Warning limit of 96.
BusWarning,
}
impl TryFrom<u8> for BusError {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
//0b000 => None,
0b001 => Ok(Self::Stuff),
0b010 => Ok(Self::Form),
0b011 => Ok(Self::Acknowledge),
0b100 => Ok(Self::BitRecessive),
0b101 => Ok(Self::BitDominant),
0b110 => Ok(Self::Crc),
//0b111 => Ok(Self::NoError),
_ => Err(()),
}
}
}

View File

@ -0,0 +1,438 @@
//! Configuration for FDCAN Module
//! Note: This file is copied and modified from fdcan crate by Richard Meadows
use core::num::{NonZeroU16, NonZeroU8};
/// Configures the bit timings.
///
/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
/// parameters as follows:
///
/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
/// - *Sample Point*: Should normally be left at the default value of 87.5%.
/// - *SJW*: Should normally be left at the default value of 1.
///
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
/// parameter to this method.
#[derive(Clone, Copy, Debug)]
pub struct NominalBitTiming {
/// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit
/// time is built up from a multiple of this quanta. Valid values are 1 to 512.
pub prescaler: NonZeroU16,
/// Valid values are 1 to 128.
pub seg1: NonZeroU8,
/// Valid values are 1 to 255.
pub seg2: NonZeroU8,
/// Valid values are 1 to 128.
pub sync_jump_width: NonZeroU8,
}
impl NominalBitTiming {
#[inline]
pub(crate) fn nbrp(&self) -> u16 {
u16::from(self.prescaler) & 0x1FF
}
#[inline]
pub(crate) fn ntseg1(&self) -> u8 {
u8::from(self.seg1)
}
#[inline]
pub(crate) fn ntseg2(&self) -> u8 {
u8::from(self.seg2) & 0x7F
}
#[inline]
pub(crate) fn nsjw(&self) -> u8 {
u8::from(self.sync_jump_width) & 0x7F
}
}
impl Default for NominalBitTiming {
#[inline]
fn default() -> Self {
// Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a NBTP
// register value of 0x0600_0A03
Self {
prescaler: NonZeroU16::new(1).unwrap(),
seg1: NonZeroU8::new(11).unwrap(),
seg2: NonZeroU8::new(4).unwrap(),
sync_jump_width: NonZeroU8::new(4).unwrap(),
}
}
}
/// Configures the data bit timings for the FdCan Variable Bitrates.
/// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
#[derive(Clone, Copy, Debug)]
pub struct DataBitTiming {
/// Tranceiver Delay Compensation
pub transceiver_delay_compensation: bool,
/// The value by which the oscillator frequency is divided to generate the bit time quanta. The bit
/// time is built up from a multiple of this quanta. Valid values for the Baud Rate Prescaler are 1
/// to 31.
pub prescaler: NonZeroU16,
/// Valid values are 1 to 31.
pub seg1: NonZeroU8,
/// Valid values are 1 to 15.
pub seg2: NonZeroU8,
/// Must always be smaller than DTSEG2, valid values are 1 to 15.
pub sync_jump_width: NonZeroU8,
}
impl DataBitTiming {
// #[inline]
// fn tdc(&self) -> u8 {
// let tsd = self.transceiver_delay_compensation as u8;
// //TODO: stm32g4 does not export the TDC field
// todo!()
// }
#[inline]
pub(crate) fn dbrp(&self) -> u8 {
(u16::from(self.prescaler) & 0x001F) as u8
}
#[inline]
pub(crate) fn dtseg1(&self) -> u8 {
u8::from(self.seg1) & 0x1F
}
#[inline]
pub(crate) fn dtseg2(&self) -> u8 {
u8::from(self.seg2) & 0x0F
}
#[inline]
pub(crate) fn dsjw(&self) -> u8 {
u8::from(self.sync_jump_width) & 0x0F
}
}
impl Default for DataBitTiming {
#[inline]
fn default() -> Self {
// Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a DBTP
// register value of 0x0000_0A33
Self {
transceiver_delay_compensation: false,
prescaler: NonZeroU16::new(1).unwrap(),
seg1: NonZeroU8::new(11).unwrap(),
seg2: NonZeroU8::new(4).unwrap(),
sync_jump_width: NonZeroU8::new(4).unwrap(),
}
}
}
/// Configures which modes to use
/// Individual headers can contain a desire to be send via FdCan
/// or use Bit rate switching. But if this general setting does not allow
/// that, only classic CAN is used instead.
#[derive(Clone, Copy, Debug)]
pub enum FrameTransmissionConfig {
/// Only allow Classic CAN message Frames
ClassicCanOnly,
/// Allow (non-brs) FdCAN Message Frames
AllowFdCan,
/// Allow FdCAN Message Frames and allow Bit Rate Switching
AllowFdCanAndBRS,
}
///
#[derive(Clone, Copy, Debug)]
pub enum ClockDivider {
/// Divide by 1
_1 = 0b0000,
/// Divide by 2
_2 = 0b0001,
/// Divide by 4
_4 = 0b0010,
/// Divide by 6
_6 = 0b0011,
/// Divide by 8
_8 = 0b0100,
/// Divide by 10
_10 = 0b0101,
/// Divide by 12
_12 = 0b0110,
/// Divide by 14
_14 = 0b0111,
/// Divide by 16
_16 = 0b1000,
/// Divide by 18
_18 = 0b1001,
/// Divide by 20
_20 = 0b1010,
/// Divide by 22
_22 = 0b1011,
/// Divide by 24
_24 = 0b1100,
/// Divide by 26
_26 = 0b1101,
/// Divide by 28
_28 = 0b1110,
/// Divide by 30
_30 = 0b1111,
}
/// Prescaler of the Timestamp counter
#[derive(Clone, Copy, Debug)]
pub enum TimestampPrescaler {
/// 1
_1 = 1,
/// 2
_2 = 2,
/// 3
_3 = 3,
/// 4
_4 = 4,
/// 5
_5 = 5,
/// 6
_6 = 6,
/// 7
_7 = 7,
/// 8
_8 = 8,
/// 9
_9 = 9,
/// 10
_10 = 10,
/// 11
_11 = 11,
/// 12
_12 = 12,
/// 13
_13 = 13,
/// 14
_14 = 14,
/// 15
_15 = 15,
/// 16
_16 = 16,
}
/// Selects the source of the Timestamp counter
#[derive(Clone, Copy, Debug)]
pub enum TimestampSource {
/// The Timestamp counter is disabled
None,
/// Using the FdCan input clock as the Timstamp counter's source,
/// and using a specific prescaler
Prescaler(TimestampPrescaler),
/// Using TIM3 as a source
FromTIM3,
}
/// How to handle frames in the global filter
#[derive(Clone, Copy, Debug)]
pub enum NonMatchingFilter {
/// Frames will go to Fifo0 when they do no match any specific filter
IntoRxFifo0 = 0b00,
/// Frames will go to Fifo1 when they do no match any specific filter
IntoRxFifo1 = 0b01,
/// Frames will be rejected when they do not match any specific filter
Reject = 0b11,
}
/// How to handle frames which do not match a specific filter
#[derive(Clone, Copy, Debug)]
pub struct GlobalFilter {
/// How to handle non-matching standard frames
pub handle_standard_frames: NonMatchingFilter,
/// How to handle non-matching extended frames
pub handle_extended_frames: NonMatchingFilter,
/// How to handle remote standard frames
pub reject_remote_standard_frames: bool,
/// How to handle remote extended frames
pub reject_remote_extended_frames: bool,
}
impl GlobalFilter {
/// Reject all non-matching and remote frames
pub const fn reject_all() -> Self {
Self {
handle_standard_frames: NonMatchingFilter::Reject,
handle_extended_frames: NonMatchingFilter::Reject,
reject_remote_standard_frames: true,
reject_remote_extended_frames: true,
}
}
/// How to handle non-matching standard frames
pub const fn set_handle_standard_frames(mut self, filter: NonMatchingFilter) -> Self {
self.handle_standard_frames = filter;
self
}
/// How to handle non-matching exteded frames
pub const fn set_handle_extended_frames(mut self, filter: NonMatchingFilter) -> Self {
self.handle_extended_frames = filter;
self
}
/// How to handle remote standard frames
pub const fn set_reject_remote_standard_frames(mut self, filter: bool) -> Self {
self.reject_remote_standard_frames = filter;
self
}
/// How to handle remote extended frames
pub const fn set_reject_remote_extended_frames(mut self, filter: bool) -> Self {
self.reject_remote_extended_frames = filter;
self
}
}
impl Default for GlobalFilter {
#[inline]
fn default() -> Self {
Self {
handle_standard_frames: NonMatchingFilter::IntoRxFifo0,
handle_extended_frames: NonMatchingFilter::IntoRxFifo0,
reject_remote_standard_frames: false,
reject_remote_extended_frames: false,
}
}
}
/// FdCan Config Struct
#[derive(Clone, Copy, Debug)]
pub struct FdCanConfig {
/// Nominal Bit Timings
pub nbtr: NominalBitTiming,
/// (Variable) Data Bit Timings
pub dbtr: DataBitTiming,
/// Enables or disables automatic retransmission of messages
///
/// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
/// util it can be sent. Otherwise, it will try only once to send each frame.
///
/// Automatic retransmission is enabled by default.
pub automatic_retransmit: bool,
/// Enabled or disables the pausing between transmissions
///
/// This feature looses up burst transmissions coming from a single node and it protects against
/// "babbling idiot" scenarios where the application program erroneously requests too many
/// transmissions.
pub transmit_pause: bool,
/// Enabled or disables the pausing between transmissions
///
/// This feature looses up burst transmissions coming from a single node and it protects against
/// "babbling idiot" scenarios where the application program erroneously requests too many
/// transmissions.
pub frame_transmit: FrameTransmissionConfig,
/// Non Isoe Mode
/// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
/// FD Specification V1.0.
pub non_iso_mode: bool,
/// Edge Filtering: Two consecutive dominant tq required to detect an edge for hard synchronization
pub edge_filtering: bool,
/// Enables protocol exception handling
pub protocol_exception_handling: bool,
/// Sets the general clock divider for this FdCAN instance
pub clock_divider: ClockDivider,
/// Sets the timestamp source
pub timestamp_source: TimestampSource,
/// Configures the Global Filter
pub global_filter: GlobalFilter,
}
impl FdCanConfig {
/// Configures the bit timings.
#[inline]
pub const fn set_nominal_bit_timing(mut self, btr: NominalBitTiming) -> Self {
self.nbtr = btr;
self
}
/// Configures the bit timings.
#[inline]
pub const fn set_data_bit_timing(mut self, btr: DataBitTiming) -> Self {
self.dbtr = btr;
self
}
/// Enables or disables automatic retransmission of messages
///
/// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
/// util it can be sent. Otherwise, it will try only once to send each frame.
///
/// Automatic retransmission is enabled by default.
#[inline]
pub const fn set_automatic_retransmit(mut self, enabled: bool) -> Self {
self.automatic_retransmit = enabled;
self
}
/// Enabled or disables the pausing between transmissions
///
/// This feature looses up burst transmissions coming from a single node and it protects against
/// "babbling idiot" scenarios where the application program erroneously requests too many
/// transmissions.
#[inline]
pub const fn set_transmit_pause(mut self, enabled: bool) -> Self {
self.transmit_pause = enabled;
self
}
/// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
/// FD Specification V1.0.
#[inline]
pub const fn set_non_iso_mode(mut self, enabled: bool) -> Self {
self.non_iso_mode = enabled;
self
}
/// Two consecutive dominant tq required to detect an edge for hard synchronization
#[inline]
pub const fn set_edge_filtering(mut self, enabled: bool) -> Self {
self.edge_filtering = enabled;
self
}
/// Sets the allowed transmission types for messages.
#[inline]
pub const fn set_frame_transmit(mut self, fts: FrameTransmissionConfig) -> Self {
self.frame_transmit = fts;
self
}
/// Enables protocol exception handling
#[inline]
pub const fn set_protocol_exception_handling(mut self, peh: bool) -> Self {
self.protocol_exception_handling = peh;
self
}
/// Sets the general clock divider for this FdCAN instance
#[inline]
pub const fn set_clock_divider(mut self, div: ClockDivider) -> Self {
self.clock_divider = div;
self
}
/// Sets the timestamp source
#[inline]
pub const fn set_timestamp_source(mut self, tss: TimestampSource) -> Self {
self.timestamp_source = tss;
self
}
/// Sets the global filter settings
#[inline]
pub const fn set_global_filter(mut self, filter: GlobalFilter) -> Self {
self.global_filter = filter;
self
}
}
impl Default for FdCanConfig {
#[inline]
fn default() -> Self {
Self {
nbtr: NominalBitTiming::default(),
dbtr: DataBitTiming::default(),
automatic_retransmit: true,
transmit_pause: false,
frame_transmit: FrameTransmissionConfig::ClassicCanOnly,
non_iso_mode: false,
edge_filtering: false,
protocol_exception_handling: true,
clock_divider: ClockDivider::_1,
timestamp_source: TimestampSource::None,
global_filter: GlobalFilter::default(),
}
}
}

View File

@ -0,0 +1,379 @@
//! Definition of Filter structs for FDCAN Module
//! Note: This file is copied and modified from fdcan crate by Richard Meadows
use embedded_can::{ExtendedId, StandardId};
use crate::can::fd::message_ram;
pub use crate::can::fd::message_ram::{EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX};
/// A Standard Filter
pub type StandardFilter = Filter<StandardId, u16>;
/// An Extended Filter
pub type ExtendedFilter = Filter<ExtendedId, u32>;
impl Default for StandardFilter {
fn default() -> Self {
StandardFilter::disable()
}
}
impl Default for ExtendedFilter {
fn default() -> Self {
ExtendedFilter::disable()
}
}
impl StandardFilter {
/// Accept all messages in FIFO 0
pub fn accept_all_into_fifo0() -> StandardFilter {
StandardFilter {
filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
action: Action::StoreInFifo0,
}
}
/// Accept all messages in FIFO 1
pub fn accept_all_into_fifo1() -> StandardFilter {
StandardFilter {
filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
action: Action::StoreInFifo1,
}
}
/// Reject all messages
pub fn reject_all() -> StandardFilter {
StandardFilter {
filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
action: Action::Reject,
}
}
/// Disable the filter
pub fn disable() -> StandardFilter {
StandardFilter {
filter: FilterType::Disabled,
action: Action::Disable,
}
}
}
impl ExtendedFilter {
/// Accept all messages in FIFO 0
pub fn accept_all_into_fifo0() -> ExtendedFilter {
ExtendedFilter {
filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
action: Action::StoreInFifo0,
}
}
/// Accept all messages in FIFO 1
pub fn accept_all_into_fifo1() -> ExtendedFilter {
ExtendedFilter {
filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
action: Action::StoreInFifo1,
}
}
/// Reject all messages
pub fn reject_all() -> ExtendedFilter {
ExtendedFilter {
filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
action: Action::Reject,
}
}
/// Disable the filter
pub fn disable() -> ExtendedFilter {
ExtendedFilter {
filter: FilterType::Disabled,
action: Action::Disable,
}
}
}
/// Filter Type
#[derive(Clone, Copy, Debug)]
pub enum FilterType<ID, UNIT>
where
ID: Copy + Clone + core::fmt::Debug,
UNIT: Copy + Clone + core::fmt::Debug,
{
/// Match with a range between two messages
Range {
/// First Id of the range
from: ID,
/// Last Id of the range
to: ID,
},
/// Match with a bitmask
BitMask {
/// Filter of the bitmask
filter: UNIT,
/// Mask of the bitmask
mask: UNIT,
},
/// Match with a single ID
DedicatedSingle(ID),
/// Match with one of two ID's
DedicatedDual(ID, ID),
/// Filter is disabled
Disabled,
}
impl<ID, UNIT> From<FilterType<ID, UNIT>> for message_ram::enums::FilterType
where
ID: Copy + Clone + core::fmt::Debug,
UNIT: Copy + Clone + core::fmt::Debug,
{
fn from(f: FilterType<ID, UNIT>) -> Self {
match f {
FilterType::Range { to: _, from: _ } => Self::RangeFilter,
FilterType::BitMask { filter: _, mask: _ } => Self::ClassicFilter,
FilterType::DedicatedSingle(_) => Self::DualIdFilter,
FilterType::DedicatedDual(_, _) => Self::DualIdFilter,
FilterType::Disabled => Self::FilterDisabled,
}
}
}
/// Filter Action
#[derive(Clone, Copy, Debug)]
pub enum Action {
/// No Action
Disable = 0b000,
/// Store an matching message in FIFO 0
StoreInFifo0 = 0b001,
/// Store an matching message in FIFO 1
StoreInFifo1 = 0b010,
/// Reject an matching message
Reject = 0b011,
/// Flag a matching message (But not store?!?)
FlagHighPrio = 0b100,
/// Flag a matching message as a High Priority message and store it in FIFO 0
FlagHighPrioAndStoreInFifo0 = 0b101,
/// Flag a matching message as a High Priority message and store it in FIFO 1
FlagHighPrioAndStoreInFifo1 = 0b110,
}
impl From<Action> for message_ram::enums::FilterElementConfig {
fn from(a: Action) -> Self {
match a {
Action::Disable => Self::DisableFilterElement,
Action::StoreInFifo0 => Self::StoreInFifo0,
Action::StoreInFifo1 => Self::StoreInFifo1,
Action::Reject => Self::Reject,
Action::FlagHighPrio => Self::SetPriority,
Action::FlagHighPrioAndStoreInFifo0 => Self::SetPriorityAndStoreInFifo0,
Action::FlagHighPrioAndStoreInFifo1 => Self::SetPriorityAndStoreInFifo1,
}
}
}
/// Filter
#[derive(Clone, Copy, Debug)]
pub struct Filter<ID, UNIT>
where
ID: Copy + Clone + core::fmt::Debug,
UNIT: Copy + Clone + core::fmt::Debug,
{
/// How to match an incoming message
pub filter: FilterType<ID, UNIT>,
/// What to do with a matching message
pub action: Action,
}
/// Standard Filter Slot
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum StandardFilterSlot {
/// 0
_0 = 0,
/// 1
_1 = 1,
/// 2
_2 = 2,
/// 3
_3 = 3,
/// 4
_4 = 4,
/// 5
_5 = 5,
/// 6
_6 = 6,
/// 7
_7 = 7,
/// 8
_8 = 8,
/// 9
_9 = 9,
/// 10
_10 = 10,
/// 11
_11 = 11,
/// 12
_12 = 12,
/// 13
_13 = 13,
/// 14
_14 = 14,
/// 15
_15 = 15,
/// 16
_16 = 16,
/// 17
_17 = 17,
/// 18
_18 = 18,
/// 19
_19 = 19,
/// 20
_20 = 20,
/// 21
_21 = 21,
/// 22
_22 = 22,
/// 23
_23 = 23,
/// 24
_24 = 24,
/// 25
_25 = 25,
/// 26
_26 = 26,
/// 27
_27 = 27,
}
impl From<u8> for StandardFilterSlot {
fn from(u: u8) -> Self {
match u {
0 => StandardFilterSlot::_0,
1 => StandardFilterSlot::_1,
2 => StandardFilterSlot::_2,
3 => StandardFilterSlot::_3,
4 => StandardFilterSlot::_4,
5 => StandardFilterSlot::_5,
6 => StandardFilterSlot::_6,
7 => StandardFilterSlot::_7,
8 => StandardFilterSlot::_8,
9 => StandardFilterSlot::_9,
10 => StandardFilterSlot::_10,
11 => StandardFilterSlot::_11,
12 => StandardFilterSlot::_12,
13 => StandardFilterSlot::_13,
14 => StandardFilterSlot::_14,
15 => StandardFilterSlot::_15,
16 => StandardFilterSlot::_16,
17 => StandardFilterSlot::_17,
18 => StandardFilterSlot::_18,
19 => StandardFilterSlot::_19,
20 => StandardFilterSlot::_20,
21 => StandardFilterSlot::_21,
22 => StandardFilterSlot::_22,
23 => StandardFilterSlot::_23,
24 => StandardFilterSlot::_24,
25 => StandardFilterSlot::_25,
26 => StandardFilterSlot::_26,
27 => StandardFilterSlot::_27,
_ => panic!("Standard Filter Slot Too High!"),
}
}
}
/// Extended Filter Slot
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ExtendedFilterSlot {
/// 0
_0 = 0,
/// 1
_1 = 1,
/// 2
_2 = 2,
/// 3
_3 = 3,
/// 4
_4 = 4,
/// 5
_5 = 5,
/// 6
_6 = 6,
/// 7
_7 = 7,
}
impl From<u8> for ExtendedFilterSlot {
fn from(u: u8) -> Self {
match u {
0 => ExtendedFilterSlot::_0,
1 => ExtendedFilterSlot::_1,
2 => ExtendedFilterSlot::_2,
3 => ExtendedFilterSlot::_3,
4 => ExtendedFilterSlot::_4,
5 => ExtendedFilterSlot::_5,
6 => ExtendedFilterSlot::_6,
7 => ExtendedFilterSlot::_7,
_ => panic!("Extended Filter Slot Too High!"), // Should be unreachable
}
}
}
/// Enum over both Standard and Extended Filter ID's
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum FilterId {
/// Standard Filter Slots
Standard(StandardFilterSlot),
/// Extended Filter Slots
Extended(ExtendedFilterSlot),
}
pub(crate) trait ActivateFilter<ID, UNIT>
where
ID: Copy + Clone + core::fmt::Debug,
UNIT: Copy + Clone + core::fmt::Debug,
{
fn activate(&mut self, f: Filter<ID, UNIT>);
// fn read(&self) -> Filter<ID, UNIT>;
}
impl ActivateFilter<StandardId, u16> for message_ram::StandardFilter {
fn activate(&mut self, f: Filter<StandardId, u16>) {
let sft = f.filter.into();
let (sfid1, sfid2) = match f.filter {
FilterType::Range { to, from } => (to.as_raw(), from.as_raw()),
FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()),
FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()),
FilterType::BitMask { filter, mask } => (filter, mask),
FilterType::Disabled => (0x0, 0x0),
};
let sfec = f.action.into();
self.write(|w| {
unsafe { w.sfid1().bits(sfid1).sfid2().bits(sfid2) }
.sft()
.set_filter_type(sft)
.sfec()
.set_filter_element_config(sfec)
});
}
// fn read(&self) -> Filter<StandardId, u16> {
// todo!()
// }
}
impl ActivateFilter<ExtendedId, u32> for message_ram::ExtendedFilter {
fn activate(&mut self, f: Filter<ExtendedId, u32>) {
let eft = f.filter.into();
let (efid1, efid2) = match f.filter {
FilterType::Range { to, from } => (to.as_raw(), from.as_raw()),
FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()),
FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()),
FilterType::BitMask { filter, mask } => (filter, mask),
FilterType::Disabled => (0x0, 0x0),
};
let efec = f.action.into();
self.write(|w| {
unsafe { w.efid1().bits(efid1).efid2().bits(efid2) }
.eft()
.set_filter_type(eft)
.efec()
.set_filter_element_config(efec)
});
}
// fn read(&self) -> Filter<ExtendedId, u32> {
// todo!()
// }
}

View File

@ -0,0 +1,134 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
use super::enums::{
BitRateSwitching, ErrorStateIndicator, FilterElementConfig, FilterType, FrameFormat, IdType,
RemoteTransmissionRequest,
};
use super::generic;
#[doc = "Reader of field `ID`"]
pub type ID_R = generic::R<u32, u32>;
#[doc = "Reader of field `RTR`"]
pub type RTR_R = generic::R<bool, RemoteTransmissionRequest>;
impl RTR_R {
pub fn rtr(&self) -> RemoteTransmissionRequest {
match self.bits {
false => RemoteTransmissionRequest::TransmitDataFrame,
true => RemoteTransmissionRequest::TransmitRemoteFrame,
}
}
pub fn is_transmit_remote_frame(&self) -> bool {
*self == RemoteTransmissionRequest::TransmitRemoteFrame
}
pub fn is_transmit_data_frame(&self) -> bool {
*self == RemoteTransmissionRequest::TransmitDataFrame
}
}
#[doc = "Reader of field `XTD`"]
pub type XTD_R = generic::R<bool, IdType>;
impl XTD_R {
pub fn id_type(&self) -> IdType {
match self.bits() {
false => IdType::StandardId,
true => IdType::ExtendedId,
}
}
pub fn is_standard_id(&self) -> bool {
*self == IdType::StandardId
}
pub fn is_exteded_id(&self) -> bool {
*self == IdType::ExtendedId
}
}
#[doc = "Reader of field `ESI`"]
pub type ESI_R = generic::R<bool, ErrorStateIndicator>;
impl ESI_R {
pub fn error_state(&self) -> ErrorStateIndicator {
match self.bits() {
false => ErrorStateIndicator::ErrorActive,
true => ErrorStateIndicator::ErrorPassive,
}
}
pub fn is_error_active(&self) -> bool {
*self == ErrorStateIndicator::ErrorActive
}
pub fn is_error_passive(&self) -> bool {
*self == ErrorStateIndicator::ErrorPassive
}
}
#[doc = "Reader of field `DLC`"]
pub type DLC_R = generic::R<u8, u8>;
#[doc = "Reader of field `BRS`"]
pub type BRS_R = generic::R<bool, BitRateSwitching>;
impl BRS_R {
pub fn bit_rate_switching(&self) -> BitRateSwitching {
match self.bits() {
true => BitRateSwitching::WithBRS,
false => BitRateSwitching::WithoutBRS,
}
}
pub fn is_with_brs(&self) -> bool {
*self == BitRateSwitching::WithBRS
}
pub fn is_without_brs(&self) -> bool {
*self == BitRateSwitching::WithoutBRS
}
}
#[doc = "Reader of field `FDF`"]
pub type FDF_R = generic::R<bool, FrameFormat>;
impl FDF_R {
pub fn frame_format(&self) -> FrameFormat {
match self.bits() {
false => FrameFormat::Standard,
true => FrameFormat::Fdcan,
}
}
pub fn is_standard_format(&self) -> bool {
*self == FrameFormat::Standard
}
pub fn is_fdcan_format(&self) -> bool {
*self == FrameFormat::Fdcan
}
}
#[doc = "Reader of field `(X|S)FT`"]
pub type ESFT_R = generic::R<u8, FilterType>;
impl ESFT_R {
#[doc = r"Gets the Filtertype"]
#[inline(always)]
pub fn to_filter_type(&self) -> FilterType {
match self.bits() {
0b00 => FilterType::RangeFilter,
0b01 => FilterType::DualIdFilter,
0b10 => FilterType::ClassicFilter,
0b11 => FilterType::FilterDisabled,
_ => unreachable!(),
}
}
}
#[doc = "Reader of field `(E|S)FEC`"]
pub type ESFEC_R = generic::R<u8, FilterElementConfig>;
impl ESFEC_R {
pub fn to_filter_element_config(&self) -> FilterElementConfig {
match self.bits() {
0b000 => FilterElementConfig::DisableFilterElement,
0b001 => FilterElementConfig::StoreInFifo0,
0b010 => FilterElementConfig::StoreInFifo1,
0b011 => FilterElementConfig::Reject,
0b100 => FilterElementConfig::SetPriority,
0b101 => FilterElementConfig::SetPriorityAndStoreInFifo0,
0b110 => FilterElementConfig::SetPriorityAndStoreInFifo1,
_ => unimplemented!(),
}
}
}

View File

@ -0,0 +1,233 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
/// Datalength is the message length generalised over
/// the Standard (Classic) and FDCAN message types
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DataLength {
Standard(u8),
Fdcan(u8),
}
impl DataLength {
/// Creates a DataLength type
///
/// Uses the byte length and Type of frame as input
pub fn new(len: u8, ff: FrameFormat) -> DataLength {
match ff {
FrameFormat::Standard => match len {
0..=8 => DataLength::Standard(len),
_ => panic!("DataLength > 8"),
},
FrameFormat::Fdcan => match len {
0..=64 => DataLength::Fdcan(len),
_ => panic!("DataLength > 64"),
},
}
}
/// Specialised function to create standard frames
pub fn new_standard(len: u8) -> DataLength {
Self::new(len, FrameFormat::Standard)
}
/// Specialised function to create FDCAN frames
pub fn new_fdcan(len: u8) -> DataLength {
Self::new(len, FrameFormat::Fdcan)
}
/// returns the length in bytes
pub fn len(&self) -> u8 {
match self {
DataLength::Standard(l) | DataLength::Fdcan(l) => *l,
}
}
pub(crate) fn dlc(&self) -> u8 {
match self {
DataLength::Standard(l) => *l,
// See RM0433 Rev 7 Table 475. DLC coding
DataLength::Fdcan(l) => match l {
0..=8 => *l,
9..=12 => 9,
13..=16 => 10,
17..=20 => 11,
21..=24 => 12,
25..=32 => 13,
33..=48 => 14,
49..=64 => 15,
_ => panic!("DataLength > 64"),
},
}
}
}
impl From<DataLength> for FrameFormat {
fn from(dl: DataLength) -> FrameFormat {
match dl {
DataLength::Standard(_) => FrameFormat::Standard,
DataLength::Fdcan(_) => FrameFormat::Fdcan,
}
}
}
/// Wheter or not to generate an Tx Event
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Event {
/// Do not generate an Tx Event
NoEvent,
/// Generate an Tx Event with a specified ID
Event(u8),
}
impl From<Event> for EventControl {
fn from(e: Event) -> Self {
match e {
Event::NoEvent => EventControl::DoNotStore,
Event::Event(_) => EventControl::Store,
}
}
}
impl From<Option<u8>> for Event {
fn from(mm: Option<u8>) -> Self {
match mm {
None => Event::NoEvent,
Some(mm) => Event::Event(mm),
}
}
}
impl From<Event> for Option<u8> {
fn from(e: Event) -> Option<u8> {
match e {
Event::NoEvent => None,
Event::Event(mm) => Some(mm),
}
}
}
/// TODO
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ErrorStateIndicator {
/// TODO
ErrorActive = 0,
/// TODO
ErrorPassive = 1,
}
impl From<ErrorStateIndicator> for bool {
#[inline(always)]
fn from(e: ErrorStateIndicator) -> Self {
e as u8 != 0
}
}
/// Type of frame, standard (classic) or FdCAN
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum FrameFormat {
Standard = 0,
Fdcan = 1,
}
impl From<FrameFormat> for bool {
#[inline(always)]
fn from(e: FrameFormat) -> Self {
e as u8 != 0
}
}
/// Type of Id, Standard or Extended
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum IdType {
/// Standard ID
StandardId = 0,
/// Extended ID
ExtendedId = 1,
}
impl From<IdType> for bool {
#[inline(always)]
fn from(e: IdType) -> Self {
e as u8 != 0
}
}
/// Whether the frame contains data or requests data
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RemoteTransmissionRequest {
/// Frame contains data
TransmitDataFrame = 0,
/// frame does not contain data
TransmitRemoteFrame = 1,
}
impl From<RemoteTransmissionRequest> for bool {
#[inline(always)]
fn from(e: RemoteTransmissionRequest) -> Self {
e as u8 != 0
}
}
/// Whether BitRateSwitching should be or was enabled
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BitRateSwitching {
/// disable bit rate switching
WithoutBRS = 0,
/// enable bit rate switching
WithBRS = 1,
}
impl From<BitRateSwitching> for bool {
#[inline(always)]
fn from(e: BitRateSwitching) -> Self {
e as u8 != 0
}
}
/// Whether to store transmit Events
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum EventControl {
/// do not store an tx event
DoNotStore,
/// store transmit events
Store,
}
impl From<EventControl> for bool {
#[inline(always)]
fn from(e: EventControl) -> Self {
e as u8 != 0
}
}
/// If an received message matched any filters
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum FilterFrameMatch {
/// This did match filter <id>
DidMatch(u8),
/// This received frame did not match any specific filters
DidNotMatch,
}
/// Type of filter to be used
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum FilterType {
/// Filter uses the range between two id's
RangeFilter = 0b00,
/// The filter matches on two specific id's (or one ID checked twice)
DualIdFilter = 0b01,
/// Filter is using a bitmask
ClassicFilter = 0b10,
/// Filter is disabled
FilterDisabled = 0b11,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum FilterElementConfig {
/// Filter is disabled
DisableFilterElement = 0b000,
/// Store a matching message in FIFO 0
StoreInFifo0 = 0b001,
/// Store a matching message in FIFO 1
StoreInFifo1 = 0b010,
/// Reject a matching message
Reject = 0b011,
/// Flag that a priority message has been received, *But do note store!*??
SetPriority = 0b100,
/// Flag and store message in FIFO 0
SetPriorityAndStoreInFifo0 = 0b101,
/// Flag and store message in FIFO 1
SetPriorityAndStoreInFifo1 = 0b110,
//_Unused = 0b111,
}

View File

@ -0,0 +1,136 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
use super::common::{ESFEC_R, ESFT_R};
use super::enums::{FilterElementConfig, FilterType};
use super::generic;
#[doc = "Reader of register ExtendedFilter"]
pub(crate) type R = generic::R<super::ExtendedFilterType, super::ExtendedFilter>;
#[doc = "Writer for register ExtendedFilter"]
pub(crate) type W = generic::W<super::ExtendedFilterType, super::ExtendedFilter>;
#[doc = "Register ExtendedFilter `reset()`'s"]
impl generic::ResetValue for super::ExtendedFilter {
type Type = super::ExtendedFilterType;
#[inline(always)]
fn reset_value() -> Self::Type {
// Sets filter element to Disabled
[0x0, 0x0]
}
}
#[doc = "Reader of field `EFID2`"]
pub(crate) type EFID2_R = generic::R<u32, u32>;
#[doc = "Write proxy for field `EFID2`"]
pub(crate) struct EFID2_W<'a> {
w: &'a mut W,
}
impl<'a> EFID2_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u32) -> &'a mut W {
self.w.bits[1] = (self.w.bits[1] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
self.w
}
}
#[doc = "Reader of field `EFID1`"]
pub(crate) type EFID1_R = generic::R<u32, u32>;
#[doc = "Write proxy for field `EFID1`"]
pub(crate) struct EFID1_W<'a> {
w: &'a mut W,
}
impl<'a> EFID1_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u32) -> &'a mut W {
self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
self.w
}
}
#[doc = "Write proxy for field `EFEC`"]
pub(crate) struct EFEC_W<'a> {
w: &'a mut W,
}
impl<'a> EFEC_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u8) -> &'a mut W {
self.w.bits[0] = (self.w.bits[0] & !(0x07 << 29)) | (((value as u32) & 0x07) << 29);
self.w
}
#[doc = r"Sets the field according to FilterElementConfig"]
#[inline(always)]
pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W {
//SAFETY: FilterElementConfig only be valid options
unsafe { self.bits(fec as u8) }
}
}
#[doc = "Write proxy for field `EFT`"]
pub(crate) struct EFT_W<'a> {
w: &'a mut W,
}
impl<'a> EFT_W<'a> {
#[doc = r"Sets the field according the FilterType"]
#[inline(always)]
pub fn set_filter_type(self, filter: FilterType) -> &'a mut W {
//SAFETY: FilterType only be valid options
unsafe { self.bits(filter as u8) }
}
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u8) -> &'a mut W {
self.w.bits[1] = (self.w.bits[1] & !(0x03 << 30)) | (((value as u32) & 0x03) << 30);
self.w
}
}
impl R {
#[doc = "Byte 0 - Bits 0:28 - EFID1"]
#[inline(always)]
pub fn sfid1(&self) -> EFID1_R {
EFID1_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
}
#[doc = "Byte 0 - Bits 29:31 - EFEC"]
#[inline(always)]
pub fn efec(&self) -> ESFEC_R {
ESFEC_R::new(((self.bits[0] >> 29) & 0x07) as u8)
}
#[doc = "Byte 1 - Bits 0:28 - EFID2"]
#[inline(always)]
pub fn sfid2(&self) -> EFID2_R {
EFID2_R::new(((self.bits[1]) & 0x1FFFFFFF) as u32)
}
#[doc = "Byte 1 - Bits 30:31 - EFT"]
#[inline(always)]
pub fn eft(&self) -> ESFT_R {
ESFT_R::new(((self.bits[1] >> 30) & 0x03) as u8)
}
}
impl W {
#[doc = "Byte 0 - Bits 0:28 - EFID1"]
#[inline(always)]
pub fn efid1(&mut self) -> EFID1_W {
EFID1_W { w: self }
}
#[doc = "Byte 0 - Bits 29:31 - EFEC"]
#[inline(always)]
pub fn efec(&mut self) -> EFEC_W {
EFEC_W { w: self }
}
#[doc = "Byte 1 - Bits 0:28 - EFID2"]
#[inline(always)]
pub fn efid2(&mut self) -> EFID2_W {
EFID2_W { w: self }
}
#[doc = "Byte 1 - Bits 30:31 - EFT"]
#[inline(always)]
pub fn eft(&mut self) -> EFT_W {
EFT_W { w: self }
}
}

View File

@ -0,0 +1,168 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
use core::marker;
///This trait shows that register has `read` method
///
///Registers marked with `Writable` can be also `modify`'ed
pub trait Readable {}
///This trait shows that register has `write`, `write_with_zero` and `reset` method
///
///Registers marked with `Readable` can be also `modify`'ed
pub trait Writable {}
///Reset value of the register
///
///This value is initial value for `write` method.
///It can be also directly writed to register by `reset` method.
pub trait ResetValue {
///Register size
type Type;
///Reset value of the register
fn reset_value() -> Self::Type;
}
///This structure provides volatile access to register
pub struct Reg<U, REG> {
register: vcell::VolatileCell<U>,
_marker: marker::PhantomData<REG>,
}
unsafe impl<U: Send, REG> Send for Reg<U, REG> {}
impl<U, REG> Reg<U, REG>
where
Self: Readable,
U: Copy,
{
///Reads the contents of `Readable` register
///
///You can read the contents of a register in such way:
///```ignore
///let bits = periph.reg.read().bits();
///```
///or get the content of a particular field of a register.
///```ignore
///let reader = periph.reg.read();
///let bits = reader.field1().bits();
///let flag = reader.field2().bit_is_set();
///```
#[inline(always)]
pub fn read(&self) -> R<U, Self> {
R {
bits: self.register.get(),
_reg: marker::PhantomData,
}
}
}
impl<U, REG> Reg<U, REG>
where
Self: ResetValue<Type = U> + Writable,
U: Copy,
{
///Writes the reset value to `Writable` register
///
///Resets the register to its initial state
#[inline(always)]
pub fn reset(&self) {
self.register.set(Self::reset_value())
}
}
impl<U, REG> Reg<U, REG>
where
Self: ResetValue<Type = U> + Writable,
U: Copy,
{
///Writes bits to `Writable` register
///
///You can write raw bits into a register:
///```ignore
///periph.reg.write(|w| unsafe { w.bits(rawbits) });
///```
///or write only the fields you need:
///```ignore
///periph.reg.write(|w| w
/// .field1().bits(newfield1bits)
/// .field2().set_bit()
/// .field3().variant(VARIANT)
///);
///```
///Other fields will have reset value.
#[inline(always)]
pub fn write<F>(&self, f: F)
where
F: FnOnce(&mut W<U, Self>) -> &mut W<U, Self>,
{
self.register.set(
f(&mut W {
bits: Self::reset_value(),
_reg: marker::PhantomData,
})
.bits,
);
}
}
///Register/field reader
///
///Result of the [`read`](Reg::read) method of a register.
///Also it can be used in the [`modify`](Reg::read) method
pub struct R<U, T> {
pub(crate) bits: U,
_reg: marker::PhantomData<T>,
}
impl<U, T> R<U, T>
where
U: Copy,
{
///Create new instance of reader
#[inline(always)]
pub(crate) fn new(bits: U) -> Self {
Self {
bits,
_reg: marker::PhantomData,
}
}
///Read raw bits from register/field
#[inline(always)]
pub fn bits(&self) -> U {
self.bits
}
}
impl<U, T, FI> PartialEq<FI> for R<U, T>
where
U: PartialEq,
FI: Copy + Into<U>,
{
#[inline(always)]
fn eq(&self, other: &FI) -> bool {
self.bits.eq(&(*other).into())
}
}
impl<FI> R<bool, FI> {
///Value of the field as raw bits
#[inline(always)]
pub fn bit(&self) -> bool {
self.bits
}
///Returns `true` if the bit is clear (0)
#[inline(always)]
pub fn bit_is_clear(&self) -> bool {
!self.bit()
}
}
///Register writer
///
///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register
pub struct W<U, REG> {
///Writable bits
pub(crate) bits: U,
_reg: marker::PhantomData<REG>,
}

View File

@ -0,0 +1,170 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
use volatile_register::RW;
pub(crate) mod common;
pub(crate) mod enums;
pub(crate) mod generic;
/// Number of Receive Fifos configured by this module
pub const RX_FIFOS_MAX: u8 = 2;
/// Number of Receive Messages per RxFifo configured by this module
pub const RX_FIFO_MAX: u8 = 3;
/// Number of Transmit Messages configured by this module
pub const TX_FIFO_MAX: u8 = 3;
/// Number of Transmit Events configured by this module
pub const TX_EVENT_MAX: u8 = 3;
/// Number of Standard Filters configured by this module
pub const STANDARD_FILTER_MAX: u8 = 28;
/// Number of Extended Filters configured by this module
pub const EXTENDED_FILTER_MAX: u8 = 8;
/// MessageRam Overlay
#[repr(C)]
pub struct RegisterBlock {
pub(crate) filters: Filters,
pub(crate) receive: [Receive; RX_FIFOS_MAX as usize],
pub(crate) transmit: Transmit,
}
impl RegisterBlock {
pub fn reset(&mut self) {
self.filters.reset();
self.receive[0].reset();
self.receive[1].reset();
self.transmit.reset();
}
}
#[repr(C)]
pub(crate) struct Filters {
pub(crate) flssa: [StandardFilter; STANDARD_FILTER_MAX as usize],
pub(crate) flesa: [ExtendedFilter; EXTENDED_FILTER_MAX as usize],
}
impl Filters {
pub fn reset(&mut self) {
for sf in &mut self.flssa {
sf.reset();
}
for ef in &mut self.flesa {
ef.reset();
}
}
}
#[repr(C)]
pub(crate) struct Receive {
pub(crate) fxsa: [RxFifoElement; RX_FIFO_MAX as usize],
}
impl Receive {
pub fn reset(&mut self) {
for fe in &mut self.fxsa {
fe.reset();
}
}
}
#[repr(C)]
pub(crate) struct Transmit {
pub(crate) efsa: [TxEventElement; TX_EVENT_MAX as usize],
pub(crate) tbsa: [TxBufferElement; TX_FIFO_MAX as usize],
}
impl Transmit {
pub fn reset(&mut self) {
for ee in &mut self.efsa {
ee.reset();
}
for be in &mut self.tbsa {
be.reset();
}
}
}
pub(crate) mod standard_filter;
pub(crate) type StandardFilterType = u32;
pub(crate) type StandardFilter = generic::Reg<StandardFilterType, _StandardFilter>;
pub(crate) struct _StandardFilter;
impl generic::Readable for StandardFilter {}
impl generic::Writable for StandardFilter {}
pub(crate) mod extended_filter;
pub(crate) type ExtendedFilterType = [u32; 2];
pub(crate) type ExtendedFilter = generic::Reg<ExtendedFilterType, _ExtendedFilter>;
pub(crate) struct _ExtendedFilter;
impl generic::Readable for ExtendedFilter {}
impl generic::Writable for ExtendedFilter {}
pub(crate) mod txevent_element;
pub(crate) type TxEventElementType = [u32; 2];
pub(crate) type TxEventElement = generic::Reg<TxEventElementType, _TxEventElement>;
pub(crate) struct _TxEventElement;
impl generic::Readable for TxEventElement {}
impl generic::Writable for TxEventElement {}
pub(crate) mod rxfifo_element;
#[repr(C)]
pub(crate) struct RxFifoElement {
pub(crate) header: RxFifoElementHeader,
pub(crate) data: [RW<u32>; 16],
}
impl RxFifoElement {
pub(crate) fn reset(&mut self) {
self.header.reset();
for byte in self.data.iter_mut() {
unsafe { byte.write(0) };
}
}
}
pub(crate) type RxFifoElementHeaderType = [u32; 2];
pub(crate) type RxFifoElementHeader = generic::Reg<RxFifoElementHeaderType, _RxFifoElement>;
pub(crate) struct _RxFifoElement;
impl generic::Readable for RxFifoElementHeader {}
impl generic::Writable for RxFifoElementHeader {}
pub(crate) mod txbuffer_element;
#[repr(C)]
pub(crate) struct TxBufferElement {
pub(crate) header: TxBufferElementHeader,
pub(crate) data: [RW<u32>; 16],
}
impl TxBufferElement {
pub(crate) fn reset(&mut self) {
self.header.reset();
for byte in self.data.iter_mut() {
unsafe { byte.write(0) };
}
}
}
pub(crate) type TxBufferElementHeader = generic::Reg<TxBufferElementHeaderType, _TxBufferElement>;
pub(crate) type TxBufferElementHeaderType = [u32; 2];
pub(crate) struct _TxBufferElement;
impl generic::Readable for TxBufferElementHeader {}
impl generic::Writable for TxBufferElementHeader {}
/// FdCan Message RAM instance.
///
/// # Safety
///
/// It is only safe to implement this trait, when:
///
/// * The implementing type has ownership of the Message RAM, preventing any
/// other accesses to the register block.
/// * `MSG_RAM` is a pointer to the Message RAM block and can be safely accessed
/// for as long as ownership or a borrow of the implementing type is present.
pub unsafe trait Instance {
const MSG_RAM: *mut RegisterBlock;
fn msg_ram(&self) -> &RegisterBlock {
unsafe { &*Self::MSG_RAM }
}
fn msg_ram_mut(&mut self) -> &mut RegisterBlock {
unsafe { &mut *Self::MSG_RAM }
}
}
// Ensure the RegisterBlock is the same size as on pg 1957 of RM0440.
static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]);
static_assertions::assert_eq_size!(Receive, [u32; 54]);
static_assertions::assert_eq_size!(Transmit, [u32; 6 + 54]);
static_assertions::assert_eq_size!(
RegisterBlock,
[u32; 28 /*Standard Filters*/ +16 /*Extended Filters*/ +54 /*RxFifo0*/ +54 /*RxFifo1*/ +6 /*TxEvent*/ +54 /*TxFifo */]
);

View File

@ -0,0 +1,122 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R};
use super::enums::{DataLength, FilterFrameMatch, FrameFormat};
use super::generic;
#[doc = "Reader of register RxFifoElement"]
pub(crate) type R = generic::R<super::RxFifoElementHeaderType, super::RxFifoElementHeader>;
// #[doc = "Writer for register ExtendedFilter"]
// pub(crate) type W = generic::W<super::RxFifoElementHeaderType, super::RxFifoElementHeader>;
#[doc = "Register ExtendedFilter `reset()`'s"]
impl generic::ResetValue for super::RxFifoElementHeader {
type Type = super::RxFifoElementHeaderType;
#[inline(always)]
fn reset_value() -> Self::Type {
[0x0, 0x0]
}
}
#[doc = "Reader of field `RXTS`"]
pub(crate) type RXTS_R = generic::R<u16, u16>;
#[doc = "Reader of field `FIDX`"]
pub(crate) type FIDX_R = generic::R<u8, u8>;
pub(crate) struct _ANMF;
#[doc = "Reader of field `ANMF`"]
pub(crate) type ANMF_R = generic::R<bool, _ANMF>;
impl ANMF_R {
pub fn is_matching_frame(&self) -> bool {
self.bit_is_clear()
}
}
impl R {
#[doc = "Byte 0 - Bits 0:28 - ID"]
#[inline(always)]
pub fn id(&self) -> ID_R {
ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
}
#[doc = "Byte 0 - Bit 29 - RTR"]
#[inline(always)]
pub fn rtr(&self) -> RTR_R {
RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
}
#[doc = "Byte 0 - Bit 30 - XTD"]
#[inline(always)]
pub fn xtd(&self) -> XTD_R {
XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
}
#[doc = "Byte 0 - Bit 30 - ESI"]
#[inline(always)]
pub fn esi(&self) -> ESI_R {
ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 0:15 - RXTS"]
#[inline(always)]
pub fn txts(&self) -> RXTS_R {
RXTS_R::new(((self.bits[1]) & 0xFFFF) as u16)
}
#[doc = "Byte 1 - Bits 16:19 - DLC"]
#[inline(always)]
pub fn dlc(&self) -> DLC_R {
DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
}
#[doc = "Byte 1 - Bits 20 - BRS"]
#[inline(always)]
pub fn brs(&self) -> BRS_R {
BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 20 - FDF"]
#[inline(always)]
pub fn fdf(&self) -> FDF_R {
FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 24:30 - FIDX"]
#[inline(always)]
pub fn fidx(&self) -> FIDX_R {
FIDX_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
}
#[doc = "Byte 1 - Bits 31 - ANMF"]
#[inline(always)]
pub fn anmf(&self) -> ANMF_R {
ANMF_R::new(((self.bits[1] >> 31) & 0x01) != 0)
}
pub fn to_data_length(&self) -> DataLength {
let dlc = self.dlc().bits();
let ff = self.fdf().frame_format();
let len = if ff == FrameFormat::Fdcan {
// See RM0433 Rev 7 Table 475. DLC coding
match dlc {
0..=8 => dlc,
9 => 12,
10 => 16,
11 => 20,
12 => 24,
13 => 32,
14 => 48,
15 => 64,
_ => panic!("DLC > 15"),
}
} else {
match dlc {
0..=8 => dlc,
9..=15 => 8,
_ => panic!("DLC > 15"),
}
};
DataLength::new(len, ff)
}
pub fn to_filter_match(&self) -> FilterFrameMatch {
if self.anmf().is_matching_frame() {
FilterFrameMatch::DidMatch(self.fidx().bits())
} else {
FilterFrameMatch::DidNotMatch
}
}
}

View File

@ -0,0 +1,136 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
use super::common::{ESFEC_R, ESFT_R};
use super::enums::{FilterElementConfig, FilterType};
use super::generic;
#[doc = "Reader of register StandardFilter"]
pub(crate) type R = generic::R<super::StandardFilterType, super::StandardFilter>;
#[doc = "Writer for register StandardFilter"]
pub(crate) type W = generic::W<super::StandardFilterType, super::StandardFilter>;
#[doc = "Register StandardFilter `reset()`'s with value 0xC0000"]
impl generic::ResetValue for super::StandardFilter {
type Type = super::StandardFilterType;
#[inline(always)]
fn reset_value() -> Self::Type {
// Sets filter element to Disabled
0xC000
}
}
#[doc = "Reader of field `SFID2`"]
pub(crate) type SFID2_R = generic::R<u16, u16>;
#[doc = "Write proxy for field `SFID2`"]
pub(crate) struct SFID2_W<'a> {
w: &'a mut W,
}
impl<'a> SFID2_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u16) -> &'a mut W {
self.w.bits = (self.w.bits & !(0x07ff)) | ((value as u32) & 0x07ff);
self.w
}
}
#[doc = "Reader of field `SFID1`"]
pub(crate) type SFID1_R = generic::R<u16, u16>;
#[doc = "Write proxy for field `SFID1`"]
pub(crate) struct SFID1_W<'a> {
w: &'a mut W,
}
impl<'a> SFID1_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u16) -> &'a mut W {
self.w.bits = (self.w.bits & !(0x07ff << 16)) | (((value as u32) & 0x07ff) << 16);
self.w
}
}
#[doc = "Write proxy for field `SFEC`"]
pub(crate) struct SFEC_W<'a> {
w: &'a mut W,
}
impl<'a> SFEC_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u8) -> &'a mut W {
self.w.bits = (self.w.bits & !(0x07 << 27)) | (((value as u32) & 0x07) << 27);
self.w
}
#[doc = r"Sets the field according to FilterElementConfig"]
#[inline(always)]
pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W {
//SAFETY: FilterElementConfig only be valid options
unsafe { self.bits(fec as u8) }
}
}
#[doc = "Write proxy for field `SFT`"]
pub(crate) struct SFT_W<'a> {
w: &'a mut W,
}
impl<'a> SFT_W<'a> {
#[doc = r"Sets the field according the FilterType"]
#[inline(always)]
pub fn set_filter_type(self, filter: FilterType) -> &'a mut W {
//SAFETY: FilterType only be valid options
unsafe { self.bits(filter as u8) }
}
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u8) -> &'a mut W {
self.w.bits = (self.w.bits & !(0x03 << 30)) | (((value as u32) & 0x03) << 30);
self.w
}
}
impl R {
#[doc = "Bits 0:10 - SFID2"]
#[inline(always)]
pub fn sfid2(&self) -> SFID2_R {
SFID2_R::new((self.bits & 0x07ff) as u16)
}
#[doc = "Bits 16:26 - SFID1"]
#[inline(always)]
pub fn sfid1(&self) -> SFID1_R {
SFID1_R::new(((self.bits >> 16) & 0x07ff) as u16)
}
#[doc = "Bits 27:29 - SFEC"]
#[inline(always)]
pub fn sfec(&self) -> ESFEC_R {
ESFEC_R::new(((self.bits >> 27) & 0x07) as u8)
}
#[doc = "Bits 30:31 - SFT"]
#[inline(always)]
pub fn sft(&self) -> ESFT_R {
ESFT_R::new(((self.bits >> 30) & 0x03) as u8)
}
}
impl W {
#[doc = "Bits 0:10 - SFID2"]
#[inline(always)]
pub fn sfid2(&mut self) -> SFID2_W {
SFID2_W { w: self }
}
#[doc = "Bits 16:26 - SFID1"]
#[inline(always)]
pub fn sfid1(&mut self) -> SFID1_W {
SFID1_W { w: self }
}
#[doc = "Bits 27:29 - SFEC"]
#[inline(always)]
pub fn sfec(&mut self) -> SFEC_W {
SFEC_W { w: self }
}
#[doc = "Bits 30:31 - SFT"]
#[inline(always)]
pub fn sft(&mut self) -> SFT_W {
SFT_W { w: self }
}
}

View File

@ -0,0 +1,433 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R};
use super::enums::{
BitRateSwitching, DataLength, ErrorStateIndicator, Event, EventControl, FrameFormat, IdType,
RemoteTransmissionRequest,
};
use super::generic;
#[doc = "Reader of register TxBufferElement"]
pub(crate) type R = generic::R<super::TxBufferElementHeaderType, super::TxBufferElementHeader>;
#[doc = "Writer for register TxBufferElement"]
pub(crate) type W = generic::W<super::TxBufferElementHeaderType, super::TxBufferElementHeader>;
impl generic::ResetValue for super::TxBufferElementHeader {
type Type = super::TxBufferElementHeaderType;
#[allow(dead_code)]
#[inline(always)]
fn reset_value() -> Self::Type {
[0; 2]
}
}
#[doc = "Write proxy for field `ESI`"]
pub(crate) struct ESI_W<'a> {
w: &'a mut W,
}
impl<'a> ESI_W<'a> {
#[doc = r"Writes `variant` to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_error_indicator(self, esi: ErrorStateIndicator) -> &'a mut W {
self.bit(esi as u8 != 0)
}
#[doc = r"Sets the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_bit(self) -> &'a mut W {
self.bit(true)
}
#[doc = r"Clears the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn clear_bit(self) -> &'a mut W {
self.bit(false)
}
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn bit(self, value: bool) -> &'a mut W {
self.w.bits[0] = (self.w.bits[0] & !(0x01 << 31)) | (((value as u32) & 0x01) << 31);
self.w
}
}
#[doc = "Write proxy for field `XTD`"]
pub(crate) struct XTD_W<'a> {
w: &'a mut W,
}
impl<'a> XTD_W<'a> {
#[doc = r"Writes `variant` to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_id_type(self, idt: IdType) -> &'a mut W {
self.bit(idt as u8 != 0)
}
#[doc = r"Sets the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_bit(self) -> &'a mut W {
self.bit(true)
}
#[doc = r"Clears the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn clear_bit(self) -> &'a mut W {
self.bit(false)
}
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn bit(self, value: bool) -> &'a mut W {
self.w.bits[0] = (self.w.bits[0] & !(0x01 << 30)) | (((value as u32) & 0x01) << 30);
self.w
}
}
#[doc = "Write proxy for field `RTR`"]
pub(crate) struct RTR_W<'a> {
w: &'a mut W,
}
impl<'a> RTR_W<'a> {
#[doc = r"Writes `variant` to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_rtr(self, rtr: RemoteTransmissionRequest) -> &'a mut W {
self.bit(rtr as u8 != 0)
}
#[doc = r"Sets the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_bit(self) -> &'a mut W {
self.bit(true)
}
#[doc = r"Clears the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn clear_bit(self) -> &'a mut W {
self.bit(false)
}
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn bit(self, value: bool) -> &'a mut W {
self.w.bits[0] = (self.w.bits[0] & !(0x01 << 29)) | (((value as u32) & 0x01) << 29);
self.w
}
}
#[doc = "Write proxy for field `ID`"]
pub(crate) struct ID_W<'a> {
w: &'a mut W,
}
impl<'a> ID_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
#[allow(dead_code)]
pub unsafe fn bits(self, value: u32) -> &'a mut W {
self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
self.w
}
}
#[doc = "Write proxy for field `DLC`"]
pub(crate) struct DLC_W<'a> {
w: &'a mut W,
}
impl<'a> DLC_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
#[allow(dead_code)]
pub unsafe fn bits(self, value: u8) -> &'a mut W {
self.w.bits[1] = (self.w.bits[1] & !(0x0F << 16)) | (((value as u32) & 0x0F) << 16);
self.w
}
}
#[doc = "Write proxy for field `BRS`"]
pub(crate) struct BRS_W<'a> {
w: &'a mut W,
}
impl<'a> BRS_W<'a> {
#[doc = r"Writes `variant` to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_brs(self, brs: BitRateSwitching) -> &'a mut W {
self.bit(brs as u8 != 0)
}
#[doc = r"Sets the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_bit(self) -> &'a mut W {
self.bit(true)
}
#[doc = r"Clears the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn clear_bit(self) -> &'a mut W {
self.bit(false)
}
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn bit(self, value: bool) -> &'a mut W {
self.w.bits[1] = (self.w.bits[1] & !(0x01 << 20)) | (((value as u32) & 0x01) << 20);
self.w
}
}
#[doc = "Write proxy for field `FDF`"]
pub(crate) struct FDF_W<'a> {
w: &'a mut W,
}
impl<'a> FDF_W<'a> {
#[doc = r"Writes `variant` to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_format(self, fdf: FrameFormat) -> &'a mut W {
self.bit(fdf as u8 != 0)
}
#[doc = r"Sets the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_bit(self) -> &'a mut W {
self.bit(true)
}
#[doc = r"Clears the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn clear_bit(self) -> &'a mut W {
self.bit(false)
}
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn bit(self, value: bool) -> &'a mut W {
self.w.bits[1] = (self.w.bits[1] & !(0x01 << 21)) | (((value as u32) & 0x01) << 21);
self.w
}
}
#[doc = "Reader of field `EFC`"]
pub(crate) type EFC_R = generic::R<bool, EventControl>;
impl EFC_R {
pub fn to_event_control(&self) -> EventControl {
match self.bit() {
false => EventControl::DoNotStore,
true => EventControl::Store,
}
}
}
#[doc = "Write proxy for field `EFC`"]
pub(crate) struct EFC_W<'a> {
w: &'a mut W,
}
impl<'a> EFC_W<'a> {
#[doc = r"Writes `variant` to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_event_control(self, efc: EventControl) -> &'a mut W {
self.bit(match efc {
EventControl::DoNotStore => false,
EventControl::Store => true,
})
}
#[doc = r"Sets the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn set_bit(self) -> &'a mut W {
self.bit(true)
}
#[doc = r"Clears the field bit"]
#[inline(always)]
#[allow(dead_code)]
pub fn clear_bit(self) -> &'a mut W {
self.bit(false)
}
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
#[allow(dead_code)]
pub fn bit(self, value: bool) -> &'a mut W {
self.w.bits[1] = (self.w.bits[1] & !(0x01 << 23)) | (((value as u32) & 0x01) << 23);
self.w
}
}
struct Marker(u8);
impl From<Event> for Marker {
fn from(e: Event) -> Marker {
match e {
Event::NoEvent => Marker(0),
Event::Event(mm) => Marker(mm),
}
}
}
#[doc = "Reader of field `MM`"]
pub(crate) type MM_R = generic::R<u8, u8>;
#[doc = "Write proxy for field `MM`"]
pub(crate) struct MM_W<'a> {
w: &'a mut W,
}
impl<'a> MM_W<'a> {
#[doc = r"Writes raw bits to the field"]
#[inline(always)]
pub unsafe fn bits(self, value: u8) -> &'a mut W {
self.w.bits[1] = (self.w.bits[1] & !(0x7F << 24)) | (((value as u32) & 0x7F) << 24);
self.w
}
fn set_message_marker(self, mm: Marker) -> &'a mut W {
unsafe { self.bits(mm.0) }
}
}
impl R {
#[doc = "Byte 0 - Bits 0:28 - ID"]
#[inline(always)]
pub fn id(&self) -> ID_R {
ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
}
#[doc = "Byte 0 - Bit 29 - RTR"]
#[inline(always)]
pub fn rtr(&self) -> RTR_R {
RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
}
#[doc = "Byte 0 - Bit 30 - XTD"]
#[inline(always)]
pub fn xtd(&self) -> XTD_R {
XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
}
#[doc = "Byte 0 - Bit 30 - ESI"]
#[inline(always)]
pub fn esi(&self) -> ESI_R {
ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 16:19 - DLC"]
#[inline(always)]
pub fn dlc(&self) -> DLC_R {
DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
}
#[doc = "Byte 1 - Bits 20 - BRS"]
#[inline(always)]
pub fn brs(&self) -> BRS_R {
BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 20 - FDF"]
#[inline(always)]
pub fn fdf(&self) -> FDF_R {
FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 23 - EFC"]
#[inline(always)]
pub fn efc(&self) -> EFC_R {
EFC_R::new(((self.bits[1] >> 23) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 24:31 - MM"]
#[inline(always)]
pub fn mm(&self) -> MM_R {
MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
}
pub fn to_data_length(&self) -> DataLength {
let dlc = self.dlc().bits();
let ff = self.fdf().frame_format();
let len = if ff == FrameFormat::Fdcan {
// See RM0433 Rev 7 Table 475. DLC coding
match dlc {
0..=8 => dlc,
9 => 12,
10 => 16,
11 => 20,
12 => 24,
13 => 32,
14 => 48,
15 => 64,
_ => panic!("DLC > 15"),
}
} else {
match dlc {
0..=8 => dlc,
9..=15 => 8,
_ => panic!("DLC > 15"),
}
};
DataLength::new(len, ff)
}
pub fn to_event(&self) -> Event {
let mm = self.mm().bits();
let efc = self.efc().to_event_control();
match efc {
EventControl::DoNotStore => Event::NoEvent,
EventControl::Store => Event::Event(mm),
}
}
}
impl W {
#[doc = "Byte 0 - Bits 0:28 - ID"]
#[inline(always)]
pub fn id(&mut self) -> ID_W {
ID_W { w: self }
}
#[doc = "Byte 0 - Bit 29 - RTR"]
#[inline(always)]
pub fn rtr(&mut self) -> RTR_W {
RTR_W { w: self }
}
#[doc = "Byte 0 - Bit 30 - XTD"]
#[inline(always)]
pub fn xtd(&mut self) -> XTD_W {
XTD_W { w: self }
}
#[doc = "Byte 0 - Bit 31 - ESI"]
#[inline(always)]
pub fn esi(&mut self) -> ESI_W {
ESI_W { w: self }
}
#[doc = "Byte 1 - Bit 16:19 - DLC"]
#[inline(always)]
pub fn dlc(&mut self) -> DLC_W {
DLC_W { w: self }
}
#[doc = "Byte 1 - Bit 20 - BRS"]
#[inline(always)]
pub fn brs(&mut self) -> BRS_W {
BRS_W { w: self }
}
#[doc = "Byte 1 - Bit 21 - FDF"]
#[inline(always)]
pub fn fdf(&mut self) -> FDF_W {
FDF_W { w: self }
}
#[doc = "Byte 1 - Bit 23 - EFC"]
#[inline(always)]
pub fn efc(&mut self) -> EFC_W {
EFC_W { w: self }
}
#[doc = "Byte 1 - Bit 24:31 - MM"]
#[inline(always)]
pub fn mm(&mut self) -> MM_W {
MM_W { w: self }
}
#[doc = "Convenience function for setting the data length and frame format"]
#[inline(always)]
pub fn set_len(&mut self, dl: impl Into<DataLength>) -> &mut Self {
let dl: DataLength = dl.into();
self.fdf().set_format(dl.into());
unsafe { self.dlc().bits(dl.dlc()) }
}
pub fn set_event(&mut self, event: Event) -> &mut Self {
self.mm().set_message_marker(event.into());
self.efc().set_event_control(event.into())
}
}

View File

@ -0,0 +1,138 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
use super::common::{BRS_R, DLC_R, ESI_R, RTR_R, XTD_R};
use super::generic;
#[doc = "Reader of register TxEventElement"]
pub(crate) type R = generic::R<super::TxEventElementType, super::TxEventElement>;
// #[doc = "Writer for register TxEventElement"]
// pub(crate) type W = generic::W<super::TxEventElementType, super::TxEventElement>;
#[doc = "Register TxEventElement `reset()`'s"]
impl generic::ResetValue for super::TxEventElement {
type Type = super::TxEventElementType;
#[inline(always)]
fn reset_value() -> Self::Type {
[0, 0]
}
}
#[doc = "Reader of field `ID`"]
pub(crate) type ID_R = generic::R<u32, u32>;
#[doc = "Reader of field `TXTS`"]
pub(crate) type TXTS_R = generic::R<u16, u16>;
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum DataLengthFormat {
StandardLength = 0,
FDCANLength = 1,
}
impl From<DataLengthFormat> for bool {
#[inline(always)]
fn from(dlf: DataLengthFormat) -> Self {
dlf as u8 != 0
}
}
#[doc = "Reader of field `EDL`"]
pub(crate) type EDL_R = generic::R<bool, DataLengthFormat>;
impl EDL_R {
pub fn data_length_format(&self) -> DataLengthFormat {
match self.bits() {
false => DataLengthFormat::StandardLength,
true => DataLengthFormat::FDCANLength,
}
}
pub fn is_standard_length(&self) -> bool {
*self == DataLengthFormat::StandardLength
}
pub fn is_fdcan_length(&self) -> bool {
*self == DataLengthFormat::FDCANLength
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum EventType {
//_Reserved = 0b00,
TxEvent = 0b01,
TxDespiteAbort = 0b10,
//_Reserved = 0b10,
}
#[doc = "Reader of field `EFC`"]
pub(crate) type EFC_R = generic::R<u8, EventType>;
impl EFC_R {
pub fn event_type(&self) -> EventType {
match self.bits() {
0b01 => EventType::TxEvent,
0b10 => EventType::TxDespiteAbort,
_ => unimplemented!(),
}
}
pub fn is_tx_event(&self) -> bool {
self.event_type() == EventType::TxEvent
}
pub fn is_despite_abort(&self) -> bool {
self.event_type() == EventType::TxDespiteAbort
}
}
#[doc = "Reader of field `MM`"]
pub(crate) type MM_R = generic::R<u8, u8>;
impl R {
#[doc = "Byte 0 - Bits 0:28 - ID"]
#[inline(always)]
pub fn id(&self) -> ID_R {
ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
}
#[doc = "Byte 0 - Bit 29 - RTR"]
#[inline(always)]
pub fn rtr(&self) -> RTR_R {
RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
}
#[doc = "Byte 0 - Bit 30 - XTD"]
#[inline(always)]
pub fn xtd(&self) -> XTD_R {
XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
}
#[doc = "Byte 0 - Bit 30 - ESI"]
#[inline(always)]
pub fn esi(&self) -> ESI_R {
ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 0:15 - TXTS"]
#[inline(always)]
pub fn txts(&self) -> TXTS_R {
TXTS_R::new(((self.bits[1]) & 0xFFFF) as u16)
}
#[doc = "Byte 1 - Bits 16:19 - DLC"]
#[inline(always)]
pub fn dlc(&self) -> DLC_R {
DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
}
#[doc = "Byte 1 - Bits 20 - BRS"]
#[inline(always)]
pub fn brs(&self) -> BRS_R {
BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 21 - EDL"]
#[inline(always)]
pub fn edl(&self) -> EDL_R {
EDL_R::new(((self.bits[1] >> 21) & 0x01) != 0)
}
#[doc = "Byte 1 - Bits 22:23 - EFC"]
#[inline(always)]
pub fn efc(&self) -> EFC_R {
EFC_R::new(((self.bits[1] >> 22) & 0x03) as u8)
}
#[doc = "Byte 1 - Bits 24:31 - MM"]
#[inline(always)]
pub fn mm(&self) -> MM_R {
MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
}
}

View File

@ -0,0 +1,6 @@
//! Module containing that which is speciffic to fdcan hardware variant
pub mod config;
pub mod filter;
pub(crate) mod message_ram;
pub(crate) mod peripheral;

View File

@ -0,0 +1,776 @@
// Note: This file is copied and modified from fdcan crate by Richard Meadows
use core::convert::Infallible;
use core::slice;
use crate::can::fd::config::*;
use crate::can::fd::message_ram::enums::*;
use crate::can::fd::message_ram::{RegisterBlock, RxFifoElement, TxBufferElement};
use crate::can::frame::*;
/// Loopback Mode
#[derive(Clone, Copy, Debug)]
enum LoopbackMode {
None,
Internal,
External,
}
pub struct Registers {
pub regs: &'static crate::pac::can::Fdcan,
pub msgram: &'static crate::pac::fdcanram::Fdcanram,
}
impl Registers {
fn tx_buffer_element(&self, bufidx: usize) -> &mut TxBufferElement {
&mut self.msg_ram_mut().transmit.tbsa[bufidx]
}
pub fn msg_ram_mut(&self) -> &mut RegisterBlock {
let ptr = self.msgram.as_ptr() as *mut RegisterBlock;
unsafe { &mut (*ptr) }
}
fn rx_fifo_element(&self, fifonr: usize, bufnum: usize) -> &mut RxFifoElement {
&mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum]
}
pub fn read_classic(&self, fifonr: usize) -> Option<(ClassicFrame, u16)> {
// Fill level - do we have a msg?
if self.regs.rxfs(fifonr).read().ffl() < 1 {
return None;
}
let read_idx = self.regs.rxfs(fifonr).read().fgi();
let mailbox = self.rx_fifo_element(fifonr, read_idx as usize);
let mut buffer: [u8; 8] = [0; 8];
let maybe_header = extract_frame(mailbox, &mut buffer);
// Clear FIFO, reduces count and increments read buf
self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx));
match maybe_header {
Some((header, ts)) => {
let data = ClassicData::new(&buffer[0..header.len() as usize]);
Some((ClassicFrame::new(header, data.unwrap()), ts))
}
None => None,
}
}
pub fn read_fd(&self, fifonr: usize) -> Option<(FdFrame, u16)> {
// Fill level - do we have a msg?
if self.regs.rxfs(fifonr).read().ffl() < 1 {
return None;
}
let read_idx = self.regs.rxfs(fifonr).read().fgi();
let mailbox = self.rx_fifo_element(fifonr, read_idx as usize);
let mut buffer: [u8; 64] = [0; 64];
let maybe_header = extract_frame(mailbox, &mut buffer);
// Clear FIFO, reduces count and increments read buf
self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx));
match maybe_header {
Some((header, ts)) => {
let data = FdData::new(&buffer[0..header.len() as usize]);
Some((FdFrame::new(header, data.unwrap()), ts))
}
None => None,
}
}
pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) {
// Fill level - do we have a msg?
//if self.regs.rxfs(fifonr).read().ffl() < 1 { return None; }
//let read_idx = self.regs.rxfs(fifonr).read().fgi();
let mailbox = self.tx_buffer_element(bufidx);
mailbox.reset();
put_tx_header(mailbox, header);
put_tx_data(mailbox, &buffer[..header.len() as usize]);
// Set <idx as Mailbox> as ready to transmit
self.regs.txbar().modify(|w| w.set_ar(bufidx, true));
}
/// Returns if the tx queue is able to accept new messages without having to cancel an existing one
#[inline]
pub fn tx_queue_is_full(&self) -> bool {
self.regs.txfqs().read().tfqf()
}
#[inline]
pub fn has_pending_frame(&self, idx: usize) -> bool {
self.regs.txbrp().read().trp(idx)
}
/// Returns `Ok` when the mailbox is free or if it contains pending frame with a
/// lower priority (higher ID) than the identifier `id`.
#[inline]
pub fn is_available(&self, bufidx: usize, id: &embedded_can::Id) -> bool {
if self.has_pending_frame(bufidx) {
let mailbox = self.tx_buffer_element(bufidx);
let header_reg = mailbox.header.read();
let old_id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
*id > old_id
} else {
true
}
}
/// Attempts to abort the sending of a frame that is pending in a mailbox.
///
/// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
/// aborted, this function has no effect and returns `false`.
///
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
/// returns `true`.
#[inline]
pub fn abort(&self, bufidx: usize) -> bool {
let can = self.regs;
// Check if there is a request pending to abort
if self.has_pending_frame(bufidx) {
// Abort Request
can.txbcr().write(|w| w.set_cr(bufidx, true));
// Wait for the abort request to be finished.
loop {
if can.txbcf().read().cf(bufidx) {
// Return false when a transmission has occured
break can.txbto().read().to(bufidx) == false;
}
}
} else {
false
}
}
#[inline]
//fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R>
pub fn abort_pending_mailbox(&self, bufidx: usize) -> Option<ClassicFrame>
//where
// PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
{
if self.abort(bufidx) {
let mailbox = self.tx_buffer_element(bufidx);
let header_reg = mailbox.header.read();
let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
let len = match header_reg.to_data_length() {
DataLength::Fdcan(len) => len,
DataLength::Standard(len) => len,
};
if len as usize > ClassicFrame::MAX_DATA_LEN {
return None;
}
//let tx_ram = self.tx_msg_ram();
let mut data = [0u8; 64];
data_from_tx_buffer(&mut data, mailbox, len as usize);
let cd = ClassicData::new(&data).unwrap();
Some(ClassicFrame::new(Header::new(id, len, header_reg.rtr().bit()), cd))
} else {
// Abort request failed because the frame was already sent (or being sent) on
// the bus. All mailboxes are now free. This can happen for small prescaler
// values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
// has preempted the execution.
None
}
}
#[inline]
//fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R>
pub fn abort_pending_fd_mailbox(&self, bufidx: usize) -> Option<FdFrame>
//where
// PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
{
if self.abort(bufidx) {
let mailbox = self.tx_buffer_element(bufidx);
let header_reg = mailbox.header.read();
let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
let len = match header_reg.to_data_length() {
DataLength::Fdcan(len) => len,
DataLength::Standard(len) => len,
};
if len as usize > FdFrame::MAX_DATA_LEN {
return None;
}
//let tx_ram = self.tx_msg_ram();
let mut data = [0u8; 64];
data_from_tx_buffer(&mut data, mailbox, len as usize);
let cd = FdData::new(&data).unwrap();
let header = if header_reg.fdf().frame_format() == FrameFormat::Fdcan {
Header::new_fd(id, len, header_reg.rtr().bit(), header_reg.brs().bit())
} else {
Header::new(id, len, header_reg.rtr().bit())
};
Some(FdFrame::new(header, cd))
} else {
// Abort request failed because the frame was already sent (or being sent) on
// the bus. All mailboxes are now free. This can happen for small prescaler
// values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
// has preempted the execution.
None
}
}
/// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can
/// be preserved.
//pub fn transmit_preserve<PTX, P>(
pub fn write_classic(&self, frame: &ClassicFrame) -> nb::Result<Option<ClassicFrame>, Infallible> {
let queue_is_full = self.tx_queue_is_full();
let id = frame.header().id();
// If the queue is full,
// Discard the first slot with a lower priority message
let (idx, pending_frame) = if queue_is_full {
if self.is_available(0, id) {
(0, self.abort_pending_mailbox(0))
} else if self.is_available(1, id) {
(1, self.abort_pending_mailbox(1))
} else if self.is_available(2, id) {
(2, self.abort_pending_mailbox(2))
} else {
// For now we bail when there is no lower priority slot available
// Can this lead to priority inversion?
return Err(nb::Error::WouldBlock);
}
} else {
// Read the Write Pointer
let idx = self.regs.txfqs().read().tfqpi();
(idx, None)
};
self.put_tx_frame(idx as usize, frame.header(), frame.data());
Ok(pending_frame)
}
/// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can
/// be preserved.
//pub fn transmit_preserve<PTX, P>(
pub fn write_fd(&self, frame: &FdFrame) -> nb::Result<Option<FdFrame>, Infallible> {
let queue_is_full = self.tx_queue_is_full();
let id = frame.header().id();
// If the queue is full,
// Discard the first slot with a lower priority message
let (idx, pending_frame) = if queue_is_full {
if self.is_available(0, id) {
(0, self.abort_pending_fd_mailbox(0))
} else if self.is_available(1, id) {
(1, self.abort_pending_fd_mailbox(1))
} else if self.is_available(2, id) {
(2, self.abort_pending_fd_mailbox(2))
} else {
// For now we bail when there is no lower priority slot available
// Can this lead to priority inversion?
return Err(nb::Error::WouldBlock);
}
} else {
// Read the Write Pointer
let idx = self.regs.txfqs().read().tfqpi();
(idx, None)
};
self.put_tx_frame(idx as usize, frame.header(), frame.data());
Ok(pending_frame)
}
#[inline]
fn reset_msg_ram(&mut self) {
self.msg_ram_mut().reset();
}
#[inline]
fn enter_init_mode(&mut self) {
self.regs.cccr().modify(|w| w.set_init(true));
while false == self.regs.cccr().read().init() {}
self.regs.cccr().modify(|w| w.set_cce(true));
}
/// Enables or disables loopback mode: Internally connects the TX and RX
/// signals together.
#[inline]
fn set_loopback_mode(&mut self, mode: LoopbackMode) {
let (test, mon, lbck) = match mode {
LoopbackMode::None => (false, false, false),
LoopbackMode::Internal => (true, true, true),
LoopbackMode::External => (true, false, true),
};
self.set_test_mode(test);
self.set_bus_monitoring_mode(mon);
self.regs.test().modify(|w| w.set_lbck(lbck));
}
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
#[inline]
fn set_bus_monitoring_mode(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_mon(enabled));
}
#[inline]
fn set_restricted_operations(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_asm(enabled));
}
#[inline]
fn set_normal_operations(&mut self, _enabled: bool) {
self.set_loopback_mode(LoopbackMode::None);
}
#[inline]
fn set_test_mode(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_test(enabled));
}
#[inline]
fn set_power_down_mode(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_csr(enabled));
while self.regs.cccr().read().csa() != enabled {}
}
/// Moves out of PoweredDownMode and into ConfigMode
#[inline]
pub fn into_config_mode(mut self, _config: FdCanConfig) {
self.set_power_down_mode(false);
self.enter_init_mode();
self.reset_msg_ram();
// check the FDCAN core matches our expections
assert!(
self.regs.crel().read().rel() == 3,
"Expected FDCAN core major release 3"
);
assert!(
self.regs.endn().read().etv() == 0x87654321_u32,
"Error reading endianness test value from FDCAN core"
);
// Framework specific settings are set here
// set TxBuffer to Queue Mode
self.regs.txbc().write(|w| w.set_tfqm(true));
// set standard filters list size to 28
// set extended filters list size to 8
// REQUIRED: we use the memory map as if these settings are set
// instead of re-calculating them.
#[cfg(not(stm32h7))]
{
self.regs.rxgfc().modify(|w| {
w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX);
w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX);
});
}
#[cfg(stm32h7)]
{
self.regs
.sidfc()
.modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX));
self.regs
.xidfc()
.modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX));
}
/*
for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX {
self.set_standard_filter((fid as u8).into(), StandardFilter::disable());
}
for fid in 0..Ecrate::can::message_ram::XTENDED_FILTER_MAX {
self.set_extended_filter(fid.into(), ExtendedFilter::disable());
}
*/
}
/// Disables the CAN interface and returns back the raw peripheral it was created from.
#[inline]
pub fn free(mut self) {
//self.disable_interrupts(Interrupts::all());
//TODO check this!
self.enter_init_mode();
self.set_power_down_mode(true);
//self.control.instance
}
/// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
#[inline]
pub fn apply_config(&mut self, config: FdCanConfig) {
self.set_data_bit_timing(config.dbtr);
self.set_nominal_bit_timing(config.nbtr);
self.set_automatic_retransmit(config.automatic_retransmit);
self.set_transmit_pause(config.transmit_pause);
self.set_frame_transmit(config.frame_transmit);
//self.set_interrupt_line_config(config.interrupt_line_config);
self.set_non_iso_mode(config.non_iso_mode);
self.set_edge_filtering(config.edge_filtering);
self.set_protocol_exception_handling(config.protocol_exception_handling);
self.set_global_filter(config.global_filter);
}
#[inline]
fn leave_init_mode(&mut self, config: FdCanConfig) {
self.apply_config(config);
self.regs.cccr().modify(|w| w.set_cce(false));
self.regs.cccr().modify(|w| w.set_init(false));
while self.regs.cccr().read().init() == true {}
}
/// Moves out of ConfigMode and into InternalLoopbackMode
#[inline]
pub fn into_internal_loopback(mut self, config: FdCanConfig) {
self.set_loopback_mode(LoopbackMode::Internal);
self.leave_init_mode(config);
}
/// Moves out of ConfigMode and into ExternalLoopbackMode
#[inline]
pub fn into_external_loopback(mut self, config: FdCanConfig) {
self.set_loopback_mode(LoopbackMode::External);
self.leave_init_mode(config);
}
/// Moves out of ConfigMode and into RestrictedOperationMode
#[inline]
pub fn into_restricted(mut self, config: FdCanConfig) {
self.set_restricted_operations(true);
self.leave_init_mode(config);
}
/// Moves out of ConfigMode and into NormalOperationMode
#[inline]
pub fn into_normal(mut self, config: FdCanConfig) {
self.set_normal_operations(true);
self.leave_init_mode(config);
}
/// Moves out of ConfigMode and into BusMonitoringMode
#[inline]
pub fn into_bus_monitoring(mut self, config: FdCanConfig) {
self.set_bus_monitoring_mode(true);
self.leave_init_mode(config);
}
/// Moves out of ConfigMode and into Testmode
#[inline]
pub fn into_test_mode(mut self, config: FdCanConfig) {
self.set_test_mode(true);
self.leave_init_mode(config);
}
/// Moves out of ConfigMode and into PoweredDownmode
#[inline]
pub fn into_powered_down(mut self, config: FdCanConfig) {
self.set_power_down_mode(true);
self.leave_init_mode(config);
}
/// Configures the bit timings.
///
/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
/// parameters as follows:
///
/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
/// - *Sample Point*: Should normally be left at the default value of 87.5%.
/// - *SJW*: Should normally be left at the default value of 1.
///
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
/// parameter to this method.
#[inline]
pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) {
//self.control.config.nbtr = btr;
self.regs.nbtp().write(|w| {
w.set_nbrp(btr.nbrp() - 1);
w.set_ntseg1(btr.ntseg1() - 1);
w.set_ntseg2(btr.ntseg2() - 1);
w.set_nsjw(btr.nsjw() - 1);
});
}
/// Configures the data bit timings for the FdCan Variable Bitrates.
/// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
#[inline]
pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) {
//self.control.config.dbtr = btr;
self.regs.dbtp().write(|w| {
w.set_dbrp(btr.dbrp() - 1);
w.set_dtseg1(btr.dtseg1() - 1);
w.set_dtseg2(btr.dtseg2() - 1);
w.set_dsjw(btr.dsjw() - 1);
});
}
/// Enables or disables automatic retransmission of messages
///
/// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
/// util it can be sent. Otherwise, it will try only once to send each frame.
///
/// Automatic retransmission is enabled by default.
#[inline]
pub fn set_automatic_retransmit(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_dar(!enabled));
//self.control.config.automatic_retransmit = enabled;
}
/// Configures the transmit pause feature. See
/// [`FdCanConfig::set_transmit_pause`]
#[inline]
pub fn set_transmit_pause(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_txp(!enabled));
//self.control.config.transmit_pause = enabled;
}
/// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`]
#[inline]
pub fn set_non_iso_mode(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_niso(enabled));
//self.control.config.non_iso_mode = enabled;
}
/// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`]
#[inline]
pub fn set_edge_filtering(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_efbi(enabled));
//self.control.config.edge_filtering = enabled;
}
/// Configures frame transmission mode. See
/// [`FdCanConfig::set_frame_transmit`]
#[inline]
pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) {
let (fdoe, brse) = match fts {
FrameTransmissionConfig::ClassicCanOnly => (false, false),
FrameTransmissionConfig::AllowFdCan => (true, false),
FrameTransmissionConfig::AllowFdCanAndBRS => (true, true),
};
self.regs.cccr().modify(|w| {
w.set_fdoe(fdoe);
#[cfg(stm32h7)]
w.set_bse(brse);
#[cfg(not(stm32h7))]
w.set_brse(brse);
});
//self.control.config.frame_transmit = fts;
}
/// Sets the protocol exception handling on/off
#[inline]
pub fn set_protocol_exception_handling(&mut self, enabled: bool) {
self.regs.cccr().modify(|w| w.set_pxhd(!enabled));
//self.control.config.protocol_exception_handling = enabled;
}
/// Configures and resets the timestamp counter
#[inline]
pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) {
#[cfg(stm32h7)]
let (tcp, tss) = match select {
TimestampSource::None => (0, 0),
TimestampSource::Prescaler(p) => (p as u8, 1),
TimestampSource::FromTIM3 => (0, 2),
};
#[cfg(not(stm32h7))]
let (tcp, tss) = match select {
TimestampSource::None => (0, stm32_metapac::can::vals::Tss::ZERO),
TimestampSource::Prescaler(p) => (p as u8, stm32_metapac::can::vals::Tss::INCREMENT),
TimestampSource::FromTIM3 => (0, stm32_metapac::can::vals::Tss::EXTERNAL),
};
self.regs.tscc().write(|w| {
w.set_tcp(tcp);
w.set_tss(tss);
});
//self.control.config.timestamp_source = select;
}
#[cfg(not(stm32h7))]
/// Configures the global filter settings
#[inline]
pub fn set_global_filter(&mut self, filter: GlobalFilter) {
let anfs = match filter.handle_standard_frames {
crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0,
crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1,
crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfs::REJECT,
};
let anfe = match filter.handle_extended_frames {
crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_0,
crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_1,
crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfe::REJECT,
};
self.regs.rxgfc().modify(|w| {
w.set_anfs(anfs);
w.set_anfe(anfe);
w.set_rrfs(filter.reject_remote_standard_frames);
w.set_rrfe(filter.reject_remote_extended_frames);
});
}
#[cfg(stm32h7)]
/// Configures the global filter settings
#[inline]
pub fn set_global_filter(&mut self, filter: GlobalFilter) {
let anfs = match filter.handle_standard_frames {
crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0,
crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1,
crate::can::fd::config::NonMatchingFilter::Reject => 2,
};
let anfe = match filter.handle_extended_frames {
crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0,
crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1,
crate::can::fd::config::NonMatchingFilter::Reject => 2,
};
self.regs.gfc().modify(|w| {
w.set_anfs(anfs);
w.set_anfe(anfe);
w.set_rrfs(filter.reject_remote_standard_frames);
w.set_rrfe(filter.reject_remote_extended_frames);
});
}
}
fn make_id(id: u32, extended: bool) -> embedded_can::Id {
if extended {
embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) })
} else {
embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked((id & 0x000007FF) as u16) })
}
}
fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) {
let (id, id_type) = match header.id() {
embedded_can::Id::Standard(id) => (id.as_raw() as u32, IdType::StandardId),
embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId),
};
// Use FDCAN only for DLC > 8. FDCAN users can revise this if required.
let frame_format = if header.len() > 8 || header.fdcan() {
FrameFormat::Fdcan
} else {
FrameFormat::Standard
};
let brs = header.len() > 8 || header.bit_rate_switching();
mailbox.header.write(|w| {
unsafe { w.id().bits(id) }
.rtr()
.bit(header.len() == 0 && header.rtr())
.xtd()
.set_id_type(id_type)
.set_len(DataLength::new(header.len(), frame_format))
.set_event(Event::NoEvent)
.fdf()
.set_format(frame_format)
.brs()
.bit(brs)
//esi.set_error_indicator(//TODO//)
});
}
fn put_tx_data(mailbox: &mut TxBufferElement, buffer: &[u8]) {
let mut lbuffer = [0_u32; 16];
let len = buffer.len();
let data = unsafe { slice::from_raw_parts_mut(lbuffer.as_mut_ptr() as *mut u8, len) };
data[..len].copy_from_slice(&buffer[..len]);
let data_len = ((len) + 3) / 4;
for (register, byte) in mailbox.data.iter_mut().zip(lbuffer[..data_len].iter()) {
unsafe { register.write(*byte) };
}
}
fn data_from_fifo(buffer: &mut [u8], mailbox: &RxFifoElement, len: usize) {
for (i, register) in mailbox.data.iter().enumerate() {
let register_value = register.read();
let register_bytes = unsafe { slice::from_raw_parts(&register_value as *const u32 as *const u8, 4) };
let num_bytes = (len) - i * 4;
if num_bytes <= 4 {
buffer[i * 4..i * 4 + num_bytes].copy_from_slice(&register_bytes[..num_bytes]);
break;
}
buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes);
}
}
fn data_from_tx_buffer(buffer: &mut [u8], mailbox: &TxBufferElement, len: usize) {
for (i, register) in mailbox.data.iter().enumerate() {
let register_value = register.read();
let register_bytes = unsafe { slice::from_raw_parts(&register_value as *const u32 as *const u8, 4) };
let num_bytes = (len) - i * 4;
if num_bytes <= 4 {
buffer[i * 4..i * 4 + num_bytes].copy_from_slice(&register_bytes[..num_bytes]);
break;
}
buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes);
}
}
impl From<&RxFifoElement> for ClassicFrame {
fn from(mailbox: &RxFifoElement) -> Self {
let header_reg = mailbox.header.read();
let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
let dlc = header_reg.to_data_length().len();
let len = dlc as usize;
let mut buffer: [u8; 64] = [0; 64];
data_from_fifo(&mut buffer, mailbox, len);
let data = ClassicData::new(&buffer[0..len]);
let header = Header::new(id, dlc, header_reg.rtr().bits());
ClassicFrame::new(header, data.unwrap())
}
}
fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> {
let header_reg = mailbox.header.read();
let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
let dlc = header_reg.to_data_length().len();
let len = dlc as usize;
let timestamp = header_reg.txts().bits;
if len > buffer.len() {
return None;
}
data_from_fifo(buffer, mailbox, len);
let header = if header_reg.fdf().bits {
Header::new_fd(id, dlc, header_reg.rtr().bits(), header_reg.brs().bits())
} else {
Header::new(id, dlc, header_reg.rtr().bits())
};
Some((header, timestamp))
}

View File

@ -1,16 +1,15 @@
#[allow(unused_variables)]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use core::task::Poll;
pub mod fd;
use cfg_if::cfg_if;
use embassy_hal_internal::{into_ref, PeripheralRef};
pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader};
pub use fdcan::id::{ExtendedId, Id, StandardId};
use fdcan::message_ram::RegisterBlock;
use fdcan::{self, LastErrorCode};
pub use fdcan::{config, filter};
use fd::config::*;
use fd::filter::*;
use crate::can::fd::peripheral::Registers;
use crate::gpio::sealed::AFType;
use crate::interrupt::typelevel::Interrupt;
use crate::rcc::RccPeripheral;
@ -20,127 +19,14 @@ pub mod enums;
use enums::*;
pub mod util;
/// CAN Frame returned by read
pub struct RxFrame {
/// CAN Header info: frame ID, data length and other meta
pub header: RxFrameInfo,
/// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
pub data: Data,
/// Reception time.
pub mod frame;
use frame::*;
#[cfg(feature = "time")]
pub timestamp: embassy_time::Instant,
}
type Timestamp = embassy_time::Instant;
/// CAN frame used for write
pub struct TxFrame {
/// CAN Header info: frame ID, data length and other meta
pub header: TxFrameHeader,
/// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
pub data: Data,
}
impl TxFrame {
/// Create new TX frame from header and data
pub fn new(header: TxFrameHeader, data: &[u8]) -> Option<Self> {
if data.len() < header.len as usize {
return None;
}
let Some(data) = Data::new(data) else { return None };
Some(TxFrame { header, data })
}
fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option<Self> {
let mut data = [0u8; 64];
for i in 0..data32.len() {
data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes());
}
let Some(data) = Data::new(&data) else { return None };
Some(TxFrame { header, data })
}
/// Access frame data. Slice length will match header.
pub fn data(&self) -> &[u8] {
&self.data.bytes[..(self.header.len as usize)]
}
}
impl RxFrame {
pub(crate) fn new(
header: RxFrameInfo,
data: &[u8],
#[cfg(feature = "time")] timestamp: embassy_time::Instant,
) -> Self {
let data = Data::new(&data).unwrap_or_else(|| Data::empty());
RxFrame {
header,
data,
#[cfg(feature = "time")]
timestamp,
}
}
/// Access frame data. Slice length will match header.
pub fn data(&self) -> &[u8] {
&self.data.bytes[..(self.header.len as usize)]
}
}
/// Payload of a (FD)CAN data frame.
///
/// Contains 0 to 64 Bytes of data.
#[derive(Debug, Copy, Clone)]
pub struct Data {
pub(crate) bytes: [u8; 64],
}
impl Data {
/// Creates a data payload from a raw byte slice.
///
/// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
/// cannot be represented with an FDCAN DLC.
pub fn new(data: &[u8]) -> Option<Self> {
if !Data::is_valid_len(data.len()) {
return None;
}
let mut bytes = [0; 64];
bytes[..data.len()].copy_from_slice(data);
Some(Self { bytes })
}
/// Raw read access to data.
pub fn raw(&self) -> &[u8] {
&self.bytes
}
/// Checks if the length can be encoded in FDCAN DLC field.
pub const fn is_valid_len(len: usize) -> bool {
match len {
0..=8 => true,
12 => true,
16 => true,
20 => true,
24 => true,
32 => true,
48 => true,
64 => true,
_ => false,
}
}
/// Creates an empty data payload containing 0 bytes.
#[inline]
pub const fn empty() -> Self {
Self { bytes: [0; 64] }
}
}
#[cfg(not(feature = "time"))]
type Timestamp = u16;
/// Interrupt handler channel 0.
pub struct IT0InterruptHandler<T: Instance> {
@ -172,7 +58,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
}
if ir.rfn(0) {
regs.ir().write(|w| w.set_rfn(0, true));
let fifonr = 0 as usize;
regs.ir().write(|w| w.set_rfn(fifonr, true));
T::state().rx_waker.wake();
}
@ -192,44 +80,82 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup
unsafe fn on_interrupt() {}
}
impl BusError {
fn try_from(lec: LastErrorCode) -> Option<BusError> {
match lec {
LastErrorCode::AckError => Some(BusError::Acknowledge),
// `0` data bit encodes a dominant state. `1` data bit is recessive.
// Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1
LastErrorCode::Bit0Error => Some(BusError::BitRecessive),
LastErrorCode::Bit1Error => Some(BusError::BitDominant),
LastErrorCode::CRCError => Some(BusError::Crc),
LastErrorCode::FormError => Some(BusError::Form),
LastErrorCode::StuffError => Some(BusError::Stuff),
_ => None,
}
}
}
/// Allows for Transmit Operations
pub trait Transmit {}
/// Allows for Receive Operations
pub trait Receive {}
/// Allows for the FdCan Instance to be released or to enter ConfigMode
pub struct PoweredDownMode;
/// Allows for the configuration for the Instance
pub struct ConfigMode;
/// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without
/// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this
/// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held
/// recessive.
pub struct InternalLoopbackMode;
impl Transmit for InternalLoopbackMode {}
impl Receive for InternalLoopbackMode {}
/// This mode is provided for hardware self-test. To be independent from external stimulation,
/// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a
/// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal
/// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX
/// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the
/// FDCAN_TX transmit pin.
pub struct ExternalLoopbackMode;
impl Transmit for ExternalLoopbackMode {}
impl Receive for ExternalLoopbackMode {}
/// The normal use of the FdCan instance after configurations
pub struct NormalOperationMode;
impl Transmit for NormalOperationMode {}
impl Receive for NormalOperationMode {}
/// In Restricted operation mode the node is able to receive data and remote frames and to give
/// acknowledge to valid frames, but it does not send data frames, remote frames, active error
/// frames, or overload frames. In case of an error condition or overload condition, it does not
/// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize
/// itself to the CAN communication. The error counters for transmit and receive are frozen while
/// error logging (can_errors) is active. TODO: automatically enter in this mode?
pub struct RestrictedOperationMode;
impl Receive for RestrictedOperationMode {}
/// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring),
/// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a
/// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is
/// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is
/// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive
/// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring
/// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission
/// of dominant bits.
pub struct BusMonitoringMode;
impl Receive for BusMonitoringMode {}
/// Test mode must be used for production tests or self test only. The software control for
/// FDCAN_TX pin interferes with all CAN protocol functions. It is not recommended to use test
/// modes for application.
pub struct TestMode;
/// Operating modes trait
pub trait FdcanOperatingMode {}
impl FdcanOperatingMode for fdcan::PoweredDownMode {}
impl FdcanOperatingMode for fdcan::ConfigMode {}
impl FdcanOperatingMode for fdcan::InternalLoopbackMode {}
impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {}
impl FdcanOperatingMode for fdcan::NormalOperationMode {}
impl FdcanOperatingMode for fdcan::RestrictedOperationMode {}
impl FdcanOperatingMode for fdcan::BusMonitoringMode {}
impl FdcanOperatingMode for fdcan::TestMode {}
impl FdcanOperatingMode for PoweredDownMode {}
impl FdcanOperatingMode for ConfigMode {}
impl FdcanOperatingMode for InternalLoopbackMode {}
impl FdcanOperatingMode for ExternalLoopbackMode {}
impl FdcanOperatingMode for NormalOperationMode {}
impl FdcanOperatingMode for RestrictedOperationMode {}
impl FdcanOperatingMode for BusMonitoringMode {}
impl FdcanOperatingMode for TestMode {}
/// FDCAN Instance
pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> {
config: crate::can::fd::config::FdCanConfig,
/// Reference to internals.
pub can: fdcan::FdCan<FdcanInstance<'d, T>, M>,
instance: FdcanInstance<'d, T>,
_mode: PhantomData<M>,
ns_per_timer_tick: u64, // For FDCAN internal timer
}
fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> u64 {
fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
match mode {
// Use timestamp from Rx FIFO to adjust timestamp reported to user
config::FrameTransmissionConfig::ClassicCanOnly => {
crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => {
let freq = T::frequency();
let prescale: u64 =
({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64;
@ -242,17 +168,22 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) ->
}
#[cfg(feature = "time")]
fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant {
fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
let now_embassy = embassy_time::Instant::now();
if ns_per_timer_tick == 0 {
return now_embassy;
}
let now_can = { T::regs().tscv().read().tsc() };
let delta = now_can.overflowing_sub(ts_val).0 as u64;
let cantime = { T::regs().tscv().read().tsc() };
let delta = cantime.overflowing_sub(ts_val).0 as u64;
let ns = ns_per_timer_tick * delta as u64;
now_embassy - embassy_time::Duration::from_nanos(ns)
}
#[cfg(not(feature = "time"))]
fn calc_timestamp<T: Instance>(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
ts_val
}
fn curr_error<T: Instance>() -> Option<BusError> {
let err = { T::regs().psr().read() };
if err.bo() {
@ -269,14 +200,14 @@ fn curr_error<T: Instance>() -> Option<BusError> {
let lec = err.lec().to_bits();
}
}
if let Ok(err) = LastErrorCode::try_from(lec) {
return BusError::try_from(err);
if let Ok(err) = BusError::try_from(lec) {
return Some(err);
}
}
None
}
impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> {
/// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
/// You must call [Fdcan::enable_non_blocking] to use the peripheral.
pub fn new(
@ -286,7 +217,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
_irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
+ interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
+ 'd,
) -> Fdcan<'d, T, fdcan::ConfigMode> {
) -> Fdcan<'d, T, ConfigMode> {
into_ref!(peri, rx, tx);
rx.set_as_af(rx.af_num(), AFType::Input);
@ -294,11 +225,12 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
T::enable_and_reset();
let mut config = crate::can::fd::config::FdCanConfig::default();
T::registers().into_config_mode(config);
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode();
T::configure_msg_ram();
unsafe {
// Enable timestamping
@ -308,6 +240,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
.write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT));
#[cfg(stm32h7)]
T::regs().tscc().write(|w| w.set_tss(0x01));
config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
T::IT0Interrupt::unpend(); // Not unsafe
T::IT0Interrupt::enable();
@ -320,38 +253,104 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
T::regs().txbtie().write(|w| w.0 = 0xffff_ffff);
}
can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg);
can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg);
can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete);
can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true);
can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true);
T::regs().ie().modify(|w| {
w.set_rfne(0, true); // Rx Fifo 0 New Msg
w.set_rfne(1, true); // Rx Fifo 1 New Msg
w.set_tce(true); // Tx Complete
});
T::regs().ile().modify(|w| {
w.set_eint0(true); // Interrupt Line 0
w.set_eint1(true); // Interrupt Line 1
});
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(can.get_config().frame_transmit);
Self { can, ns_per_timer_tick }
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(config.frame_transmit);
Self {
config,
instance: FdcanInstance(peri),
_mode: PhantomData::<ConfigMode>,
ns_per_timer_tick,
}
}
/// Get configuration
pub fn config(&self) -> crate::can::fd::config::FdCanConfig {
return self.config;
}
/// Set configuration
pub fn set_config(&mut self, config: crate::can::fd::config::FdCanConfig) {
self.config = config;
}
/// Configures the bit timings calculated from supplied bitrate.
pub fn set_bitrate(&mut self, bitrate: u32) {
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
self.can.set_nominal_bit_timing(config::NominalBitTiming {
let nbtr = crate::can::fd::config::NominalBitTiming {
sync_jump_width: bit_timing.sync_jump_width,
prescaler: bit_timing.prescaler,
seg1: bit_timing.seg1,
seg2: bit_timing.seg2,
});
};
self.config = self.config.set_nominal_bit_timing(nbtr);
}
/// Configures the bit timings for VBR data calculated from supplied bitrate.
pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) {
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
// Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M
let nbtr = crate::can::fd::config::DataBitTiming {
transceiver_delay_compensation,
sync_jump_width: bit_timing.sync_jump_width,
prescaler: bit_timing.prescaler,
seg1: bit_timing.seg1,
seg2: bit_timing.seg2,
};
self.config.frame_transmit = FrameTransmissionConfig::AllowFdCanAndBRS;
self.config = self.config.set_data_bit_timing(nbtr);
}
/// Set an Standard Address CAN filter into slot 'id'
#[inline]
pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) {
T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
}
/// Set an array of Standard Address CAN filters and overwrite the current set
pub fn set_standard_filters(&mut self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
for (i, f) in filters.iter().enumerate() {
T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
}
}
/// Set an Extended Address CAN filter into slot 'id'
#[inline]
pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
}
/// Set an array of Extended Address CAN filters and overwrite the current set
pub fn set_extended_filters(&mut self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
for (i, f) in filters.iter().enumerate() {
T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
}
}
}
macro_rules! impl_transition {
($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => {
impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> {
impl<'d, T: Instance> Fdcan<'d, T, $from_mode> {
/// Transition from $from_mode:ident mode to $to_mode:ident mode
pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> {
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.can.get_config().frame_transmit);
Fdcan {
can: self.can.$func(),
pub fn $name(self) -> Fdcan<'d, T, $to_mode> {
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
T::registers().$func(self.config);
let ret = Fdcan {
config: self.config,
instance: self.instance,
_mode: PhantomData::<$to_mode>,
ns_per_timer_tick,
}
};
ret
}
}
};
@ -376,38 +375,16 @@ impl_transition!(
impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M>
where
M: fdcan::Transmit,
M: fdcan::Receive,
M: Transmit,
M: Receive,
{
/// Queues the message to be sent but exerts backpressure. If a lower-priority
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
if let Ok(dropped) = self
.can
.transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| {
TxFrame::from_preserved(hdr, data32)
})
{
return Poll::Ready(dropped.flatten());
}
// Couldn't replace any lower priority frames. Need to wait for some mailboxes
// to clear.
Poll::Pending
})
.await
}
/// Flush one of the TX mailboxes.
pub async fn flush(&self, mb: fdcan::Mailbox) {
pub async fn flush(&self, idx: usize) {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
let idx: u8 = mb.into();
if idx > 3 {
panic!("Bad mailbox");
}
let idx = 1 << idx;
if !T::regs().txbrp().read().trp(idx) {
return Poll::Ready(());
@ -418,37 +395,77 @@ where
.await;
}
/// Queues the message to be sent but exerts backpressure. If a lower-priority
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
if let Ok(dropped) = T::registers().write_classic(frame) {
return Poll::Ready(dropped);
}
// Couldn't replace any lower priority frames. Need to wait for some mailboxes
// to clear.
Poll::Pending
})
.await
}
/// Returns the next received message frame
pub async fn read(&mut self) -> Result<RxFrame, BusError> {
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
poll_fn(|cx| {
T::state().err_waker.register(cx.waker());
T::state().rx_waker.register(cx.waker());
let mut buffer: [u8; 64] = [0; 64];
if let Ok(rx) = self.can.receive0(&mut buffer) {
// rx: fdcan::ReceiveOverrun<RxFrameInfo>
// TODO: report overrun?
// for now we just drop it
if let Some((msg, ts)) = T::registers().read_classic(0) {
let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
return Poll::Ready(Ok((msg, ts)));
} else if let Some((msg, ts)) = T::registers().read_classic(1) {
let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
return Poll::Ready(Ok((msg, ts)));
} else if let Some(err) = curr_error::<T>() {
// TODO: this is probably wrong
return Poll::Ready(Err(err));
}
Poll::Pending
})
.await
}
let frame: RxFrame = RxFrame::new(
rx.unwrap(),
&buffer,
#[cfg(feature = "time")]
calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
);
return Poll::Ready(Ok(frame));
} else if let Ok(rx) = self.can.receive1(&mut buffer) {
// rx: fdcan::ReceiveOverrun<RxFrameInfo>
// TODO: report overrun?
// for now we just drop it
/// Queues the message to be sent but exerts backpressure. If a lower-priority
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
let frame: RxFrame = RxFrame::new(
rx.unwrap(),
&buffer,
#[cfg(feature = "time")]
calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
);
return Poll::Ready(Ok(frame));
if let Ok(dropped) = T::registers().write_fd(frame) {
return Poll::Ready(dropped);
}
// Couldn't replace any lower priority frames. Need to wait for some mailboxes
// to clear.
Poll::Pending
})
.await
}
/// Returns the next received message frame
pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
poll_fn(|cx| {
T::state().err_waker.register(cx.waker());
T::state().rx_waker.register(cx.waker());
if let Some((msg, ts)) = T::registers().read_fd(0) {
let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
return Poll::Ready(Ok((msg, ts)));
} else if let Some((msg, ts)) = T::registers().read_fd(1) {
let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
return Poll::Ready(Ok((msg, ts)));
} else if let Some(err) = curr_error::<T>() {
// TODO: this is probably wrong
return Poll::Ready(Err(err));
@ -459,40 +476,67 @@ where
}
/// Split instance into separate Tx(write) and Rx(read) portions
pub fn split<'c>(&'c mut self) -> (FdcanTx<'c, 'd, T, M>, FdcanRx<'c, 'd, T, M>) {
let (mut _control, tx, rx0, rx1) = self.can.split_by_ref();
pub fn split(self) -> (FdcanTx<'d, T, M>, FdcanRx<'d, T, M>) {
(
FdcanTx { _control, tx },
FdcanTx {
_instance: self.instance,
_mode: self._mode,
},
FdcanRx {
rx0,
rx1,
_instance1: PhantomData::<T>,
_instance2: T::regs(),
_mode: self._mode,
ns_per_timer_tick: self.ns_per_timer_tick,
},
)
}
}
/// FDCAN Tx only Instance
pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> {
_control: &'c mut fdcan::FdCanControl<FdcanInstance<'d, T>, M>,
tx: &'c mut fdcan::Tx<FdcanInstance<'d, T>, M>,
/// FDCAN Rx only Instance
#[allow(dead_code)]
pub struct FdcanRx<'d, T: Instance, M: Receive> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: PhantomData<M>,
ns_per_timer_tick: u64, // For FDCAN internal timer
}
impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> {
/// FDCAN Tx only Instance
pub struct FdcanTx<'d, T: Instance, M: Transmit> {
_instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
_mode: PhantomData<M>,
}
impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> {
/// Queues the message to be sent but exerts backpressure. If a lower-priority
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> {
pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
if let Ok(dropped) = self
.tx
.transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| {
TxFrame::from_preserved(hdr, data32)
if let Ok(dropped) = T::registers().write_classic(frame) {
return Poll::Ready(dropped);
}
// Couldn't replace any lower priority frames. Need to wait for some mailboxes
// to clear.
Poll::Pending
})
{
return Poll::Ready(dropped.flatten());
.await
}
/// Queues the message to be sent but exerts backpressure. If a lower-priority
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
if let Ok(dropped) = T::registers().write_fd(frame) {
return Poll::Ready(dropped);
}
// Couldn't replace any lower priority frames. Need to wait for some mailboxes
@ -503,65 +547,47 @@ impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> {
}
}
/// FDCAN Rx only Instance
#[allow(dead_code)]
pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> {
rx0: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo0>,
rx1: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo1>,
ns_per_timer_tick: u64, // For FDCAN internal timer
}
impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> {
impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> {
/// Returns the next received message frame
pub async fn read(&mut self) -> Result<RxFrame, BusError> {
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
poll_fn(|cx| {
T::state().err_waker.register(cx.waker());
T::state().rx_waker.register(cx.waker());
let mut buffer: [u8; 64] = [0; 64];
if let Ok(rx) = self.rx0.receive(&mut buffer) {
// rx: fdcan::ReceiveOverrun<RxFrameInfo>
// TODO: report overrun?
// for now we just drop it
let frame: RxFrame = RxFrame::new(
rx.unwrap(),
&buffer,
#[cfg(feature = "time")]
calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
);
return Poll::Ready(Ok(frame));
} else if let Ok(rx) = self.rx1.receive(&mut buffer) {
// rx: fdcan::ReceiveOverrun<RxFrameInfo>
// TODO: report overrun?
// for now we just drop it
let frame: RxFrame = RxFrame::new(
rx.unwrap(),
&buffer,
#[cfg(feature = "time")]
calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
);
return Poll::Ready(Ok(frame));
if let Some((msg, ts)) = T::registers().read_classic(0) {
let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
return Poll::Ready(Ok((msg, ts)));
} else if let Some((msg, ts)) = T::registers().read_classic(1) {
let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
return Poll::Ready(Ok((msg, ts)));
} else if let Some(err) = curr_error::<T>() {
// TODO: this is probably wrong
return Poll::Ready(Err(err));
}
Poll::Pending
})
.await
}
}
impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> {
type Target = fdcan::FdCan<FdcanInstance<'d, T>, M>;
fn deref(&self) -> &Self::Target {
&self.can
}
}
/// Returns the next received message frame
pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
poll_fn(|cx| {
T::state().err_waker.register(cx.waker());
T::state().rx_waker.register(cx.waker());
impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.can
if let Some((msg, ts)) = T::registers().read_fd(0) {
let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
return Poll::Ready(Ok((msg, ts)));
} else if let Some((msg, ts)) = T::registers().read_fd(1) {
let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
return Poll::Ready(Ok((msg, ts)));
} else if let Some(err) = curr_error::<T>() {
// TODO: this is probably wrong
return Poll::Ready(Err(err));
}
Poll::Pending
})
.await
}
}
@ -585,11 +611,11 @@ pub(crate) mod sealed {
}
pub trait Instance {
const REGISTERS: *mut fdcan::RegisterBlock;
const MSG_RAM: *mut fdcan::message_ram::RegisterBlock;
const MSG_RAM_OFFSET: usize;
fn regs() -> &'static crate::pac::can::Fdcan;
fn registers() -> crate::can::fd::peripheral::Registers;
fn ram() -> &'static crate::pac::fdcanram::Fdcanram;
fn state() -> &'static State;
#[cfg(not(stm32h7))]
@ -599,7 +625,8 @@ pub(crate) mod sealed {
fn configure_msg_ram() {
let r = Self::regs();
use fdcan::message_ram::*;
use crate::can::fd::message_ram::*;
//use fdcan::message_ram::*;
let mut offset_words = Self::MSG_RAM_OFFSET as u16;
// 11-bit filter
@ -677,28 +704,20 @@ pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + '
/// Fdcan Instance struct
pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> {
const MSG_RAM: *mut RegisterBlock = T::MSG_RAM;
}
unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T>
where
FdcanInstance<'d, T>: fdcan::message_ram::Instance,
{
const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS;
}
macro_rules! impl_fdcan {
($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => {
impl sealed::Instance for peripherals::$inst {
const REGISTERS: *mut fdcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = crate::pac::$msg_ram_inst.as_ptr() as *mut _;
const MSG_RAM_OFFSET: usize = $msg_ram_offset;
fn regs() -> &'static crate::pac::can::Fdcan {
&crate::pac::$inst
}
fn registers() -> Registers {
Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst}
}
fn ram() -> &'static crate::pac::fdcanram::Fdcanram {
&crate::pac::$msg_ram_inst
}
fn state() -> &'static sealed::State {
static STATE: sealed::State = sealed::State::new();
&STATE

View File

@ -0,0 +1,370 @@
//! Definition for CAN Frames
use bit_field::BitField;
/// CAN Header, without meta data
#[derive(Debug, Copy, Clone)]
pub struct Header {
id: embedded_can::Id,
len: u8,
flags: u8,
}
impl Header {
const FLAG_RTR: usize = 0; // Remote
const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
const FLAG_BRS: usize = 2; // Bit-rate switching, ignored for Classic CAN
/// Create new CAN Header
pub fn new(id: embedded_can::Id, len: u8, rtr: bool) -> Header {
let mut flags = 0u8;
flags.set_bit(Self::FLAG_RTR, rtr);
Header { id, len, flags }
}
/// Create new CAN FD Header
pub fn new_fd(id: embedded_can::Id, len: u8, rtr: bool, brs: bool) -> Header {
let mut flags = 0u8;
flags.set_bit(Self::FLAG_RTR, rtr);
flags.set_bit(Self::FLAG_FDCAN, true);
flags.set_bit(Self::FLAG_BRS, brs);
Header { id, len, flags }
}
/// Return ID
pub fn id(&self) -> &embedded_can::Id {
&self.id
}
/// Return length as u8
pub fn len(&self) -> u8 {
self.len
}
/// Is remote frame
pub fn rtr(&self) -> bool {
self.flags.get_bit(Self::FLAG_RTR)
}
/// Request/is FDCAN frame
pub fn fdcan(&self) -> bool {
self.flags.get_bit(Self::FLAG_FDCAN)
}
/// Request/is Flexible Data Rate
pub fn bit_rate_switching(&self) -> bool {
self.flags.get_bit(Self::FLAG_BRS)
}
}
/// Payload of a classic CAN data frame.
///
/// Contains 0 to 8 Bytes of data.
#[derive(Debug, Copy, Clone)]
pub struct ClassicData {
pub(crate) bytes: [u8; 8],
}
impl ClassicData {
/// Creates a data payload from a raw byte slice.
///
/// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
/// cannot be represented with an FDCAN DLC.
pub fn new(data: &[u8]) -> Option<Self> {
if !FdData::is_valid_len(data.len()) {
return None;
}
let mut bytes = [0; 8];
bytes[..data.len()].copy_from_slice(data);
Some(Self { bytes })
}
/// Raw read access to data.
pub fn raw(&self) -> &[u8] {
&self.bytes
}
/// Checks if the length can be encoded in FDCAN DLC field.
pub const fn is_valid_len(len: usize) -> bool {
match len {
0..=8 => true,
_ => false,
}
}
/// Creates an empty data payload containing 0 bytes.
#[inline]
pub const fn empty() -> Self {
Self { bytes: [0; 8] }
}
}
/// Frame with up to 8 bytes of data payload as per Classic CAN
#[derive(Debug, Copy, Clone)]
pub struct ClassicFrame {
can_header: Header,
data: ClassicData,
}
impl ClassicFrame {
pub(crate) const MAX_DATA_LEN: usize = 8;
/// Create a new CAN classic Frame
pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame {
ClassicFrame { can_header, data }
}
/// Create new extended frame
pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> {
if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
match ClassicData::new(raw_data) {
Some(data) => Some(ClassicFrame::new(
Header::new(id.into(), raw_data.len() as u8, false),
data,
)),
None => None,
}
} else {
None
}
}
/// Create new standard frame
pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> {
if let Some(id) = embedded_can::StandardId::new(raw_id) {
match ClassicData::new(raw_data) {
Some(data) => Some(ClassicFrame::new(
Header::new(id.into(), raw_data.len() as u8, false),
data,
)),
None => None,
}
} else {
None
}
}
/// Create new remote frame
pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8usize {
Some(ClassicFrame::new(
Header::new(id.into(), len as u8, true),
ClassicData::empty(),
))
} else {
None
}
}
/// Get reference to data
pub fn header(&self) -> &Header {
&self.can_header
}
/// Return ID
pub fn id(&self) -> &embedded_can::Id {
&self.can_header.id
}
/// Get reference to data
pub fn data(&self) -> &[u8] {
&self.data.raw()
}
}
impl embedded_can::Frame for ClassicFrame {
fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
match ClassicData::new(raw_data) {
Some(data) => Some(ClassicFrame::new(
Header::new(id.into(), raw_data.len() as u8, false),
data,
)),
None => None,
}
}
fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 {
Some(ClassicFrame::new(
Header::new(id.into(), len as u8, true),
ClassicData::empty(),
))
} else {
None
}
}
fn is_extended(&self) -> bool {
match self.can_header.id {
embedded_can::Id::Extended(_) => true,
embedded_can::Id::Standard(_) => true,
}
}
fn is_remote_frame(&self) -> bool {
self.can_header.rtr()
}
fn id(&self) -> embedded_can::Id {
self.can_header.id
}
fn dlc(&self) -> usize {
self.can_header.len as usize
}
fn data(&self) -> &[u8] {
&self.data.raw()
}
}
/// Payload of a (FD)CAN data frame.
///
/// Contains 0 to 64 Bytes of data.
#[derive(Debug, Copy, Clone)]
pub struct FdData {
pub(crate) bytes: [u8; 64],
}
impl FdData {
/// Creates a data payload from a raw byte slice.
///
/// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
/// cannot be represented with an FDCAN DLC.
pub fn new(data: &[u8]) -> Option<Self> {
if !FdData::is_valid_len(data.len()) {
return None;
}
let mut bytes = [0; 64];
bytes[..data.len()].copy_from_slice(data);
Some(Self { bytes })
}
/// Raw read access to data.
pub fn raw(&self) -> &[u8] {
&self.bytes
}
/// Checks if the length can be encoded in FDCAN DLC field.
pub const fn is_valid_len(len: usize) -> bool {
match len {
0..=8 => true,
12 => true,
16 => true,
20 => true,
24 => true,
32 => true,
48 => true,
64 => true,
_ => false,
}
}
/// Creates an empty data payload containing 0 bytes.
#[inline]
pub const fn empty() -> Self {
Self { bytes: [0; 64] }
}
}
/// Frame with up to 8 bytes of data payload as per Fd CAN
#[derive(Debug, Copy, Clone)]
pub struct FdFrame {
can_header: Header,
data: FdData,
}
impl FdFrame {
pub(crate) const MAX_DATA_LEN: usize = 64;
/// Create a new CAN classic Frame
pub fn new(can_header: Header, data: FdData) -> FdFrame {
FdFrame { can_header, data }
}
/// Create new extended frame
pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> {
if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
match FdData::new(raw_data) {
Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
None => None,
}
} else {
None
}
}
/// Create new standard frame
pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> {
if let Some(id) = embedded_can::StandardId::new(raw_id) {
match FdData::new(raw_data) {
Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
None => None,
}
} else {
None
}
}
/// Create new remote frame
pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 {
Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty()))
} else {
None
}
}
/// Get reference to data
pub fn header(&self) -> &Header {
&self.can_header
}
/// Return ID
pub fn id(&self) -> &embedded_can::Id {
&self.can_header.id
}
/// Get reference to data
pub fn data(&self) -> &[u8] {
&self.data.raw()
}
}
impl embedded_can::Frame for FdFrame {
fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
match FdData::new(raw_data) {
Some(data) => Some(FdFrame::new(
Header::new_fd(id.into(), raw_data.len() as u8, false, true),
data,
)),
None => None,
}
}
fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 {
Some(FdFrame::new(
Header::new_fd(id.into(), len as u8, true, true),
FdData::empty(),
))
} else {
None
}
}
fn is_extended(&self) -> bool {
match self.can_header.id {
embedded_can::Id::Extended(_) => true,
embedded_can::Id::Standard(_) => true,
}
}
fn is_remote_frame(&self) -> bool {
self.can_header.rtr()
}
fn id(&self) -> embedded_can::Id {
self.can_header.id
}
// Returns length in bytes even for CANFD packets which embedded-can does not really mention.
fn dlc(&self) -> usize {
self.can_header.len as usize
}
fn data(&self) -> &[u8] {
&self.data.raw()
}
}

View File

@ -20,6 +20,7 @@ defmt-rtt = "0.4"
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7.0"
embedded-hal = "0.2.6"
embedded-can = { version = "0.4" }
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.8", default-features = false }

View File

@ -20,32 +20,100 @@ async fn main(_spawner: Spawner) {
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
can.set_extended_filter(
can::fd::filter::ExtendedFilterSlot::_0,
can::fd::filter::ExtendedFilter::accept_all_into_fifo1(),
);
// 250k bps
can.set_bitrate(250_000);
// 1M bps
can.set_fd_data_bitrate(1_000_000, false);
info!("Configured");
//let mut can = can.into_external_loopback_mode();
let mut can = can.into_normal_mode();
//let mut can = can.into_normal_mode();
let mut can = can.into_internal_loopback_mode();
let mut i = 0;
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::TxFrame::new(
can::TxFrameHeader {
len: 1,
frame_format: can::FrameFormat::Standard,
id: can::StandardId::new(0x123).unwrap().into(),
bit_rate_switching: false,
marker: None,
},
&[i],
)
.unwrap();
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {} {:02x} --- {}ms",
rx_frame.header().len(),
rx_frame.data()[0..rx_frame.header().len() as usize],
delta,
)
}
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
if i > 2 {
break;
}
}
// Use the FD API's even if we don't get FD packets.
loop {
let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
info!("Writing frame using FD API");
_ = can.write_fd(&frame).await;
match can.read_fd().await {
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {} {:02x} --- using FD API {}ms",
rx_frame.header().len(),
rx_frame.data()[0..rx_frame.header().len() as usize],
delta,
)
}
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
if i > 4 {
break;
}
}
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {} {:02x} --- {}ms",
rx_frame.header().len(),
rx_frame.data()[0..rx_frame.header().len() as usize],
delta,
)
}
Err(_err) => error!("Error in frame"),
}

View File

@ -16,54 +16,77 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
// configure FDCAN to use PLL1_Q at 64 MHz
config.rcc.pll1 = Some(rcc::Pll {
source: rcc::PllSource::HSI,
prediv: rcc::PllPreDiv::DIV4,
mul: rcc::PllMul::MUL8,
divp: None,
divq: Some(rcc::PllDiv::DIV2),
divr: None,
config.rcc.hse = Some(rcc::Hse {
freq: embassy_stm32::time::Hertz(25_000_000),
mode: rcc::HseMode::Oscillator,
});
config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q;
config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
let peripherals = embassy_stm32::init(config);
//let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
can.can.apply_config(
can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming {
sync_jump_width: 1.try_into().unwrap(),
prescaler: 8.try_into().unwrap(),
seg1: 13.try_into().unwrap(),
seg2: 2.try_into().unwrap(),
}),
);
// 250k bps
can.set_bitrate(250_000);
info!("Configured");
//let mut can = can.into_internal_loopback_mode();
let mut can = can.into_normal_mode();
let mut can = can.into_external_loopback_mode();
//let mut can = can.into_normal_mode();
info!("CAN Configured");
let mut i = 0;
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::TxFrame::new(
can::TxFrameHeader {
len: 1,
frame_format: can::FrameFormat::Standard,
id: can::StandardId::new(0x123).unwrap().into(),
bit_rate_switching: false,
marker: None,
},
&[i],
)
.unwrap();
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {:x} {:x} {:x} {:x} --- NEW {}",
rx_frame.data()[0],
rx_frame.data()[1],
rx_frame.data()[2],
rx_frame.data()[3],
delta,
)
}
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
if i > 3 {
break;
}
}
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {:x} {:x} {:x} {:x} --- NEW {}",
rx_frame.data()[0],
rx_frame.data()[1],
rx_frame.data()[2],
rx_frame.data()[3],
delta,
)
}
Err(_err) => error!("Error in frame"),
}

View File

@ -16,54 +16,77 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
// configure FDCAN to use PLL1_Q at 64 MHz
config.rcc.pll1 = Some(rcc::Pll {
source: rcc::PllSource::HSI,
prediv: rcc::PllPreDiv::DIV4,
mul: rcc::PllMul::MUL8,
divp: None,
divq: Some(rcc::PllDiv::DIV2),
divr: None,
config.rcc.hse = Some(rcc::Hse {
freq: embassy_stm32::time::Hertz(25_000_000),
mode: rcc::HseMode::Oscillator,
});
config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q;
config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
let peripherals = embassy_stm32::init(config);
//let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
can.can.apply_config(
can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming {
sync_jump_width: 1.try_into().unwrap(),
prescaler: 8.try_into().unwrap(),
seg1: 13.try_into().unwrap(),
seg2: 2.try_into().unwrap(),
}),
);
// 250k bps
can.set_bitrate(250_000);
info!("Configured");
//let mut can = can.into_internal_loopback_mode();
let mut can = can.into_normal_mode();
let mut can = can.into_external_loopback_mode();
//let mut can = can.into_normal_mode();
info!("CAN Configured");
let mut i = 0;
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::TxFrame::new(
can::TxFrameHeader {
len: 1,
frame_format: can::FrameFormat::Standard,
id: can::StandardId::new(0x123).unwrap().into(),
bit_rate_switching: false,
marker: None,
},
&[i],
)
.unwrap();
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {:x} {:x} {:x} {:x} --- NEW {}",
rx_frame.data()[0],
rx_frame.data()[1],
rx_frame.data()[2],
rx_frame.data()[3],
delta,
)
}
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
if i > 3 {
break;
}
}
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {:x} {:x} {:x} {:x} --- NEW {}",
rx_frame.data()[0],
rx_frame.data()[1],
rx_frame.data()[2],
rx_frame.data()[3],
delta,
)
}
Err(_err) => error!("Error in frame"),
}

View File

@ -69,6 +69,7 @@ cortex-m-rt = "0.7.0"
embedded-hal = "0.2.6"
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
embedded-hal-async = { version = "1.0" }
embedded-can = { version = "0.4" }
micromath = "2.0.0"
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
rand_core = { version = "0.6", default-features = false }

View File

@ -36,7 +36,7 @@ fn options() -> TestOptions {
c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
TestOptions {
config: c,
max_latency: Duration::from_micros(3800),
max_latency: Duration::from_micros(1200),
second_fifo_working: false,
}
}
@ -53,12 +53,12 @@ fn options() -> TestOptions {
c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
TestOptions {
config: c,
max_latency: Duration::from_micros(5500),
max_latency: Duration::from_micros(1200),
second_fifo_working: false,
}
}
#[cfg(any(feature = "stm32g491re"))]
#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))]
fn options() -> TestOptions {
info!("G4 config");
TestOptions {
@ -80,9 +80,9 @@ async fn main(_spawner: Spawner) {
// 250k bps
can.set_bitrate(250_000);
can.can.set_extended_filter(
can::filter::ExtendedFilterSlot::_0,
can::filter::ExtendedFilter::accept_all_into_fifo1(),
can.set_extended_filter(
can::fd::filter::ExtendedFilterSlot::_0,
can::fd::filter::ExtendedFilter::accept_all_into_fifo1(),
);
let mut can = can.into_internal_loopback_mode();
@ -91,31 +91,21 @@ async fn main(_spawner: Spawner) {
let mut i: u8 = 0;
loop {
let tx_frame = can::TxFrame::new(
can::TxFrameHeader {
len: 1,
frame_format: can::FrameFormat::Standard,
id: can::StandardId::new(0x123).unwrap().into(),
bit_rate_switching: false,
marker: None,
},
&[i],
)
.unwrap();
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame...");
let tx_ts = Instant::now();
can.write(&tx_frame).await;
let envelope = can.read().await.unwrap();
let (frame, timestamp) = can.read().await.unwrap();
info!("Frame received!");
// Check data.
assert!(i == envelope.data()[0], "{} == {}", i, envelope.data()[0]);
assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
info!("loopback time {}", envelope.header.time_stamp);
info!("loopback frame {=u8}", envelope.data()[0]);
let latency = envelope.timestamp.saturating_duration_since(tx_ts);
info!("loopback time {}", timestamp);
info!("loopback frame {=u8}", frame.data()[0]);
let latency = timestamp.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
@ -143,47 +133,26 @@ async fn main(_spawner: Spawner) {
// in each FIFO so make sure we write enough to fill them both up before reading.
for i in 0..3 {
// Try filling up the RX FIFO0 buffers with standard packets
let tx_frame = can::TxFrame::new(
can::TxFrameHeader {
len: 1,
frame_format: can::FrameFormat::Standard,
id: can::StandardId::new(0x123).unwrap().into(),
bit_rate_switching: false,
marker: None,
},
&[i],
)
.unwrap();
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
can.write(&tx_frame).await;
}
for i in 3..max_buffered {
// Try filling up the RX FIFO0 buffers with extended packets
let tx_frame = can::TxFrame::new(
can::TxFrameHeader {
len: 1,
frame_format: can::FrameFormat::Standard,
id: can::ExtendedId::new(0x1232344).unwrap().into(),
bit_rate_switching: false,
marker: None,
},
&[i],
)
.unwrap();
let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
can.write(&tx_frame).await;
}
// Try and receive all 6 packets
for i in 0..max_buffered {
let envelope = can.read().await.unwrap();
match envelope.header.id {
can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
let (frame, _ts) = can.read().await.unwrap();
match frame.id() {
embedded_can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
embedded_can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
}
}
@ -192,48 +161,26 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx) = can.split();
for i in 0..3 {
// Try filling up the RX FIFO0 buffers with standard packets
let tx_frame = can::TxFrame::new(
can::TxFrameHeader {
len: 1,
frame_format: can::FrameFormat::Standard,
id: can::StandardId::new(0x123).unwrap().into(),
bit_rate_switching: false,
marker: None,
},
&[i],
)
.unwrap();
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
tx.write(&tx_frame).await;
}
for i in 3..max_buffered {
// Try filling up the RX FIFO0 buffers with extended packets
let tx_frame = can::TxFrame::new(
can::TxFrameHeader {
len: 1,
frame_format: can::FrameFormat::Standard,
id: can::ExtendedId::new(0x1232344).unwrap().into(),
bit_rate_switching: false,
marker: None,
},
&[i],
)
.unwrap();
let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
tx.write(&tx_frame).await;
}
// Try and receive all 6 packets
for i in 0..max_buffered {
let envelope = rx.read().await.unwrap();
match envelope.header.id {
can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
let (frame, _ts) = rx.read().await.unwrap();
match frame.id() {
embedded_can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
embedded_can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
}
}