Merge pull request #2475 from cschuhen/feature/fdcan_r2

Support for FDCAN peripheral as found on newer STM32 micros.
This commit is contained in:
Dario Nieuwenhuis 2024-01-30 23:45:14 +00:00 committed by GitHub
commit fed8635e93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 1783 additions and 579 deletions

View file

@ -80,6 +80,8 @@ 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 }
[dev-dependencies]
critical-section = { version = "1.1", features = ["std"] }
@ -693,373 +695,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ]
stm32f779bi = [ "stm32-metapac/stm32f779bi" ]
stm32f779ii = [ "stm32-metapac/stm32f779ii" ]
stm32f779ni = [ "stm32-metapac/stm32f779ni" ]
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" ]
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" ]
stm32l010c6 = [ "stm32-metapac/stm32l010c6" ]
stm32l010f4 = [ "stm32-metapac/stm32l010f4" ]
stm32l010k4 = [ "stm32-metapac/stm32l010k4" ]
@ -1386,86 +1388,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ]
stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ]
stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ]
stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ]
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" ]
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" ]
stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ]
stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ]
stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ]

View file

@ -449,7 +449,7 @@ fn main() {
// ========
// Generate RccPeripheral impls
let refcounted_peripherals = HashSet::from(["usart", "adc"]);
let refcounted_peripherals = HashSet::from(["usart", "adc", "can"]);
let mut refcount_statics = BTreeSet::new();
for p in METADATA.peripherals {

View file

@ -13,9 +13,12 @@ use crate::gpio::sealed::AFType;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::can::vals::{Ide, Lec};
use crate::rcc::RccPeripheral;
use crate::time::Hertz;
use crate::{interrupt, peripherals, Peripheral};
pub mod enums;
use enums::*;
pub mod util;
/// Contains CAN frame and additional metadata.
///
/// Timestamp is available if `time` feature is enabled.
@ -93,23 +96,6 @@ pub struct Can<'d, T: Instance> {
can: bxcan::Can<BxcanInstance<'d, T>>,
}
/// CAN bus error
#[allow(missing_docs)]
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BusError {
Stuff,
Form,
Acknowledge,
BitRecessive,
BitDominant,
Crc,
Software,
BusOff,
BusPassive,
BusWarning,
}
/// Error returned by `try_read`
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -186,8 +172,15 @@ impl<'d, T: Instance> Can<'d, T> {
/// Set CAN bit rate.
pub fn set_bitrate(&mut self, bitrate: u32) {
let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
let sjw = u8::from(bit_timing.sync_jump_width) as u32;
let seg1 = u8::from(bit_timing.seg1) as u32;
let seg2 = u8::from(bit_timing.seg2) as u32;
let prescaler = u16::from(bit_timing.prescaler) as u32;
self.can
.modify_config()
.set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1))
.leave_disabled();
}
/// Enables the peripheral and synchronizes with the bus.
@ -302,97 +295,6 @@ impl<'d, T: Instance> Can<'d, T> {
}
}
const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> {
const BS1_MAX: u8 = 16;
const BS2_MAX: u8 = 8;
const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
let periph_clock = periph_clock.0;
if can_bitrate < 1000 {
return None;
}
// Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
// CAN in Automation, 2003
//
// According to the source, optimal quanta per bit are:
// Bitrate Optimal Maximum
// 1000 kbps 8 10
// 500 kbps 16 17
// 250 kbps 16 17
// 125 kbps 16 17
let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
// Computing (prescaler * BS):
// BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
// BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
// let:
// BS = 1 + BS1 + BS2 -- Number of time quanta per bit
// PRESCALER_BS = PRESCALER * BS
// ==>
// PRESCALER_BS = PCLK / BITRATE
let prescaler_bs = periph_clock / can_bitrate;
// Searching for such prescaler value so that the number of quanta per bit is highest.
let mut bs1_bs2_sum = max_quanta_per_bit - 1;
while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
if bs1_bs2_sum <= 2 {
return None; // No solution
}
bs1_bs2_sum -= 1;
}
let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
if (prescaler < 1) || (prescaler > 1024) {
return None; // No solution
}
// Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
// We need to find such values so that the sample point is as close as possible to the optimal value,
// which is 87.5%, which is 7/8.
//
// Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
// {{bs2 -> (1 + bs1)/7}}
//
// Hence:
// bs2 = (1 + bs1) / 7
// bs1 = (7 * bs1_bs2_sum - 1) / 8
//
// Sample point location can be computed as follows:
// Sample point location = (1 + bs1) / (1 + bs1 + bs2)
//
// Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
// - With rounding to nearest
// - With rounding to zero
let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
let mut bs2 = bs1_bs2_sum - bs1;
core::assert!(bs1_bs2_sum > bs1);
let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
// Nope, too far; now rounding to zero
bs1 = (7 * bs1_bs2_sum - 1) / 8;
bs2 = bs1_bs2_sum - bs1;
}
// Check is BS1 and BS2 are in range
if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
return None;
}
// Check if final bitrate matches the requested
if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
return None;
}
// One is recommended by DS-015, CANOpen, and DeviceNet
let sjw = 1;
// Pack into BTR register values
Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1))
}
/// Split the CAN driver into transmit and receive halves.
///
/// Useful for doing separate transmit/receive tasks.

View file

@ -0,0 +1,30 @@
//! Enums shared between CAN controller types.
/// Bus error
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BusError {
/// Bit stuffing error - more than 5 equal bits
Stuff,
/// Form error - A fixed format part of a received message has wrong format
Form,
/// The message transmitted by the FDCAN was not acknowledged by another node.
Acknowledge,
/// Bit0Error: During the transmission of a message the device wanted to send a dominant level
/// but the monitored bus value was recessive.
BitRecessive,
/// Bit1Error: During the transmission of a message the device wanted to send a recessive level
/// but the monitored bus value was dominant.
BitDominant,
/// The CRC check sum of a received message was incorrect. The CRC of an
/// incoming message does not match with the CRC calculated from the received data.
Crc,
/// A software error occured
Software,
/// The FDCAN is in Bus_Off state.
BusOff,
/// The FDCAN is in the Error_Passive state.
BusPassive,
/// At least one of error counter has reached the Error_Warning limit of 96.
BusWarning,
}

View file

@ -1,14 +1,577 @@
use crate::peripherals;
use core::future::poll_fn;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use core::task::Poll;
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 crate::gpio::sealed::AFType;
use crate::interrupt::typelevel::Interrupt;
use crate::rcc::RccPeripheral;
use crate::{interrupt, peripherals, Peripheral};
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.
#[cfg(feature = "time")]
pub 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] }
}
}
/// Interrupt handler channel 0.
pub struct IT0InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
// We use IT0 for everything currently
impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> {
unsafe fn on_interrupt() {
let regs = T::regs();
let ir = regs.ir().read();
if ir.tc() {
regs.ir().write(|w| w.set_tc(true));
T::state().tx_waker.wake();
}
if ir.tefn() {
regs.ir().write(|w| w.set_tefn(true));
T::state().tx_waker.wake();
}
if ir.ped() || ir.pea() {
regs.ir().write(|w| {
w.set_ped(true);
w.set_pea(true);
});
}
if ir.rfn(0) {
regs.ir().write(|w| w.set_rfn(0, true));
T::state().rx_waker.wake();
}
if ir.rfn(1) {
regs.ir().write(|w| w.set_rfn(1, true));
T::state().rx_waker.wake();
}
}
}
/// Interrupt handler channel 1.
pub struct IT1InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1InterruptHandler<T> {
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,
}
}
}
/// 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 {}
/// FDCAN Instance
pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> {
/// Reference to internals.
pub can: fdcan::FdCan<FdcanInstance<'d, T>, M>,
ns_per_timer_tick: u64, // For FDCAN internal timer
}
fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> u64 {
match mode {
// Use timestamp from Rx FIFO to adjust timestamp reported to user
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;
1_000_000_000 as u64 / (freq.0 as u64 * prescale)
}
// For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use
// timer3 instead which is too hard to do from this module.
_ => 0,
}
}
#[cfg(feature = "time")]
fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant {
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 ns = ns_per_timer_tick * delta as u64;
now_embassy - embassy_time::Duration::from_nanos(ns)
}
fn curr_error<T: Instance>() -> Option<BusError> {
let err = { T::regs().psr().read() };
if err.bo() {
return Some(BusError::BusOff);
} else if err.ep() {
return Some(BusError::BusPassive);
} else if err.ew() {
return Some(BusError::BusWarning);
} else {
cfg_if! {
if #[cfg(stm32h7)] {
let lec = err.lec();
} else {
let lec = err.lec().to_bits();
}
}
if let Ok(err) = LastErrorCode::try_from(lec) {
return BusError::try_from(err);
}
}
None
}
impl<'d, T: Instance> Fdcan<'d, T, fdcan::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(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
_irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
+ interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
+ 'd,
) -> Fdcan<'d, T, fdcan::ConfigMode> {
into_ref!(peri, rx, tx);
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
T::enable_and_reset();
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
#[cfg(not(stm32h7))]
T::regs()
.tscc()
.write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT));
#[cfg(stm32h7)]
T::regs().tscc().write(|w| w.set_tss(0x01));
T::IT0Interrupt::unpend(); // Not unsafe
T::IT0Interrupt::enable();
T::IT1Interrupt::unpend(); // Not unsafe
T::IT1Interrupt::enable();
// this isn't really documented in the reference manual
// but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire
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);
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(can.get_config().frame_transmit);
Self { can, ns_per_timer_tick }
}
/// 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 {
sync_jump_width: bit_timing.sync_jump_width,
prescaler: bit_timing.prescaler,
seg1: bit_timing.seg1,
seg2: bit_timing.seg2,
});
}
}
macro_rules! impl_transition {
($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => {
impl<'d, T: Instance> Fdcan<'d, T, fdcan::$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(),
ns_per_timer_tick,
}
}
}
};
}
impl_transition!(PoweredDownMode, ConfigMode, into_config_mode, into_config_mode);
impl_transition!(InternalLoopbackMode, ConfigMode, into_config_mode, into_config_mode);
impl_transition!(ConfigMode, NormalOperationMode, into_normal_mode, into_normal);
impl_transition!(
ConfigMode,
ExternalLoopbackMode,
into_external_loopback_mode,
into_external_loopback
);
impl_transition!(
ConfigMode,
InternalLoopbackMode,
into_internal_loopback_mode,
into_internal_loopback
);
impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M>
where
M: fdcan::Transmit,
M: fdcan::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) {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
let idx: u8 = mb.into();
let idx = 1 << idx;
if !T::regs().txbrp().read().trp(idx) {
return Poll::Ready(());
}
Poll::Pending
})
.await;
}
/// Returns the next received message frame
pub async fn read(&mut self) -> Result<RxFrame, 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
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
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 Some(err) = curr_error::<T>() {
// TODO: this is probably wrong
return Poll::Ready(Err(err));
}
Poll::Pending
})
.await
}
/// 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();
(
FdcanTx { _control, tx },
FdcanRx {
rx0,
rx1,
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>,
}
impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, '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> {
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)
})
{
return Poll::Ready(dropped.flatten());
}
// Couldn't replace any lower priority frames. Need to wait for some mailboxes
// to clear.
Poll::Pending
})
.await
}
}
/// 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> {
/// Returns the next received message frame
pub async fn read(&mut self) -> Result<RxFrame, 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));
} 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
}
}
impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.can
}
}
pub(crate) mod sealed {
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use embassy_sync::waitqueue::AtomicWaker;
pub struct State {
pub tx_waker: AtomicWaker,
pub err_waker: AtomicWaker,
pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>,
pub rx_waker: AtomicWaker,
}
impl State {
@ -16,25 +579,122 @@ pub(crate) mod sealed {
Self {
tx_waker: AtomicWaker::new(),
err_waker: AtomicWaker::new(),
rx_queue: Channel::new(),
rx_waker: AtomicWaker::new(),
}
}
}
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 state() -> &'static State;
#[cfg(not(stm32h7))]
fn configure_msg_ram() {}
#[cfg(stm32h7)]
fn configure_msg_ram() {
let r = Self::regs();
use fdcan::message_ram::*;
let mut offset_words = Self::MSG_RAM_OFFSET as u16;
// 11-bit filter
r.sidfc().modify(|w| w.set_flssa(offset_words));
offset_words += STANDARD_FILTER_MAX as u16;
// 29-bit filter
r.xidfc().modify(|w| w.set_flesa(offset_words));
offset_words += 2 * EXTENDED_FILTER_MAX as u16;
// Rx FIFO 0 and 1
for i in 0..=1 {
r.rxfc(i).modify(|w| {
w.set_fsa(offset_words);
w.set_fs(RX_FIFO_MAX);
w.set_fwm(RX_FIFO_MAX);
});
offset_words += 18 * RX_FIFO_MAX as u16;
}
// Rx buffer - see below
// Tx event FIFO
r.txefc().modify(|w| {
w.set_efsa(offset_words);
w.set_efs(TX_EVENT_MAX);
w.set_efwm(TX_EVENT_MAX);
});
offset_words += 2 * TX_EVENT_MAX as u16;
// Tx buffers
r.txbc().modify(|w| {
w.set_tbsa(offset_words);
w.set_tfqs(TX_FIFO_MAX);
});
offset_words += 18 * TX_FIFO_MAX as u16;
// Rx Buffer - not used
r.rxbc().modify(|w| {
w.set_rbsa(offset_words);
});
// TX event FIFO?
// Trigger memory?
// Set the element sizes to 16 bytes
r.rxesc().modify(|w| {
w.set_rbds(0b111);
for i in 0..=1 {
w.set_fds(i, 0b111);
}
});
r.txesc().modify(|w| {
w.set_tbds(0b111);
})
}
}
}
/// Interruptable FDCAN instance.
pub trait InterruptableInstance {}
/// FDCAN instance.
pub trait Instance: sealed::Instance + InterruptableInstance + 'static {}
/// Trait for FDCAN interrupt channel 0
pub trait IT0Instance {
/// Type for FDCAN interrupt channel 0
type IT0Interrupt: crate::interrupt::typelevel::Interrupt;
}
foreach_peripheral!(
(can, $inst:ident) => {
/// Trait for FDCAN interrupt channel 1
pub trait IT1Instance {
/// Type for FDCAN interrupt channel 1
type IT1Interrupt: crate::interrupt::typelevel::Interrupt;
}
/// InterruptableInstance trait
pub trait InterruptableInstance: IT0Instance + IT1Instance {}
/// Instance trait
pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
/// 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
}
@ -47,8 +707,40 @@ foreach_peripheral!(
impl Instance for peripherals::$inst {}
foreach_interrupt!(
($inst,can,FDCAN,IT0,$irq:ident) => {
impl IT0Instance for peripherals::$inst {
type IT0Interrupt = crate::interrupt::typelevel::$irq;
}
};
($inst,can,FDCAN,IT1,$irq:ident) => {
impl IT1Instance for peripherals::$inst {
type IT1Interrupt = crate::interrupt::typelevel::$irq;
}
};
);
impl InterruptableInstance for peripherals::$inst {}
};
($inst:ident, $msg_ram_inst:ident) => {
impl_fdcan!($inst, $msg_ram_inst, 0);
};
}
#[cfg(not(stm32h7))]
foreach_peripheral!(
(can, FDCAN) => { impl_fdcan!(FDCAN, FDCANRAM); };
(can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM1); };
(can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM2); };
(can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM3); };
);
#[cfg(stm32h7)]
foreach_peripheral!(
(can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM, 0x0000); };
(can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM, 0x0C00); };
(can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM, 0x1800); };
);
pin_trait!(RxPin, Instance);

View file

@ -0,0 +1,117 @@
//! Utility functions shared between CAN controller types.
use core::num::{NonZeroU16, NonZeroU8};
/// Shared struct to represent bit timings used by calc_can_timings.
#[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,
}
/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency
pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> {
const BS1_MAX: u8 = 16;
const BS2_MAX: u8 = 8;
const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
let periph_clock = periph_clock.0;
if can_bitrate < 1000 {
return None;
}
// Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
// CAN in Automation, 2003
//
// According to the source, optimal quanta per bit are:
// Bitrate Optimal Maximum
// 1000 kbps 8 10
// 500 kbps 16 17
// 250 kbps 16 17
// 125 kbps 16 17
let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
// Computing (prescaler * BS):
// BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
// BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
// let:
// BS = 1 + BS1 + BS2 -- Number of time quanta per bit
// PRESCALER_BS = PRESCALER * BS
// ==>
// PRESCALER_BS = PCLK / BITRATE
let prescaler_bs = periph_clock / can_bitrate;
// Searching for such prescaler value so that the number of quanta per bit is highest.
let mut bs1_bs2_sum = max_quanta_per_bit - 1;
while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
if bs1_bs2_sum <= 2 {
return None; // No solution
}
bs1_bs2_sum -= 1;
}
let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
if (prescaler < 1) || (prescaler > 1024) {
return None; // No solution
}
// Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
// We need to find such values so that the sample point is as close as possible to the optimal value,
// which is 87.5%, which is 7/8.
//
// Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
// {{bs2 -> (1 + bs1)/7}}
//
// Hence:
// bs2 = (1 + bs1) / 7
// bs1 = (7 * bs1_bs2_sum - 1) / 8
//
// Sample point location can be computed as follows:
// Sample point location = (1 + bs1) / (1 + bs1 + bs2)
//
// Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
// - With rounding to nearest
// - With rounding to zero
let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
let mut bs2 = bs1_bs2_sum - bs1;
core::assert!(bs1_bs2_sum > bs1);
let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
// Nope, too far; now rounding to zero
bs1 = (7 * bs1_bs2_sum - 1) / 8;
bs2 = bs1_bs2_sum - bs1;
}
// Check is BS1 and BS2 are in range
if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
return None;
}
// Check if final bitrate matches the requested
if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
return None;
}
// One is recommended by DS-015, CANOpen, and DeviceNet
let sync_jump_width = core::num::NonZeroU8::new(1)?;
let seg1 = core::num::NonZeroU8::new(bs1)?;
let seg2 = core::num::NonZeroU8::new(bs2)?;
let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?;
Some(NominalBitTiming {
sync_jump_width,
prescaler: nz_prescaler,
seg1,
seg2,
})
}

View file

@ -3,8 +3,8 @@ use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
use stm32_metapac::FLASH;
pub use crate::pac::rcc::vals::{
Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ,
Pllr as PllR, Ppre as APBPrescaler,
Adcsel as AdcClockSource, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN,
Pllp as PllP, Pllq as PllQ, Pllr as PllR, Ppre as APBPrescaler,
};
use crate::pac::{PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
@ -87,6 +87,7 @@ pub struct Config {
pub clock_48mhz_src: Option<Clock48MhzSrc>,
pub adc12_clock_source: AdcClockSource,
pub adc345_clock_source: AdcClockSource,
pub fdcan_clock_source: FdCanClockSource,
pub ls: super::LsConfig,
}
@ -104,6 +105,7 @@ impl Default for Config {
clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
adc12_clock_source: Adcsel::DISABLE,
adc345_clock_source: Adcsel::DISABLE,
fdcan_clock_source: FdCanClockSource::PCLK1,
ls: Default::default(),
}
}
@ -282,6 +284,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source));
let adc12_ck = match config.adc12_clock_source {
AdcClockSource::DISABLE => None,

View file

@ -7,8 +7,8 @@ pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
#[cfg(stm32h7)]
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
pub use crate::pac::rcc::vals::{
Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
Pllsrc as PllSource, Sw as Sysclk,
Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv,
Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
};
use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
use crate::pac::{FLASH, PWR, RCC};
@ -212,6 +212,8 @@ pub struct Config {
pub per_clock_source: PerClockSource,
pub adc_clock_source: AdcClockSource,
pub fdcan_clock_source: FdCanClockSource,
pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale,
pub ls: super::LsConfig,
@ -248,6 +250,8 @@ impl Default for Config {
#[cfg(stm32h7)]
adc_clock_source: AdcClockSource::PER,
fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE
timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale0,
ls: Default::default(),
@ -585,7 +589,8 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr5().modify(|w| {
w.set_ckpersel(config.per_clock_source);
w.set_adcdacsel(config.adc_clock_source)
w.set_adcdacsel(config.adc_clock_source);
w.set_fdcan12sel(config.fdcan_clock_source)
});
}

View file

@ -0,0 +1,56 @@
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::peripherals::*;
use embassy_stm32::{bind_interrupts, can, Config};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let config = Config::default();
let peripherals = embassy_stm32::init(config);
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
// 250k bps
can.set_bitrate(250_000);
info!("Configured");
//let mut can = can.into_external_loopback_mode();
let mut can = can.into_normal_mode();
let mut i = 0;
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();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
}
}

View file

@ -0,0 +1,74 @@
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::peripherals::*;
use embassy_stm32::{bind_interrupts, can, rcc, Config};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
});
#[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.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q;
let peripherals = embassy_stm32::init(config);
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(),
}),
);
info!("Configured");
let mut can = can.into_external_loopback_mode();
//let mut can = can.into_normal_mode();
let mut i = 0;
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();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
}
}

View file

@ -0,0 +1,74 @@
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::peripherals::*;
use embassy_stm32::{bind_interrupts, can, rcc, Config};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
});
#[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.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q;
let peripherals = embassy_stm32::init(config);
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(),
}),
);
info!("Configured");
let mut can = can.into_external_loopback_mode();
//let mut can = can.into_normal_mode();
let mut i = 0;
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();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
}
}

View file

@ -14,11 +14,11 @@ stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not
stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"]
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"]
stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"]
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"]
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"]
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"]
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"]
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"]
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]
@ -37,6 +37,7 @@ sdmmc = []
stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"]
chrono = ["embassy-stm32/chrono", "dep:chrono"]
can = []
fdcan = []
ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
embassy-stm32-wpan = []
@ -96,6 +97,11 @@ name = "eth"
path = "src/bin/eth.rs"
required-features = [ "eth",]
[[bin]]
name = "fdcan"
path = "src/bin/fdcan.rs"
required-features = [ "fdcan",]
[[bin]]
name = "gpio"
path = "src/bin/gpio.rs"

View file

@ -0,0 +1,243 @@
#![no_std]
#![no_main]
// required-features: fdcan
#[path = "../common.rs"]
mod common;
use common::*;
use defmt::assert;
use embassy_executor::Spawner;
use embassy_stm32::peripherals::*;
use embassy_stm32::{bind_interrupts, can, Config};
use embassy_time::{Duration, Instant};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
});
struct TestOptions {
config: Config,
max_latency: Duration,
second_fifo_working: bool,
}
#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
fn options() -> TestOptions {
use embassy_stm32::rcc;
info!("H75 config");
let mut c = config();
c.rcc.hse = Some(rcc::Hse {
freq: embassy_stm32::time::Hertz(25_000_000),
mode: rcc::HseMode::Oscillator,
});
c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
TestOptions {
config: c,
max_latency: Duration::from_micros(3800),
second_fifo_working: false,
}
}
#[cfg(any(feature = "stm32h7a3zi"))]
fn options() -> TestOptions {
use embassy_stm32::rcc;
info!("H7a config");
let mut c = config();
c.rcc.hse = Some(rcc::Hse {
freq: embassy_stm32::time::Hertz(25_000_000),
mode: rcc::HseMode::Oscillator,
});
c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
TestOptions {
config: c,
max_latency: Duration::from_micros(5500),
second_fifo_working: false,
}
}
#[cfg(any(feature = "stm32g491re"))]
fn options() -> TestOptions {
info!("G4 config");
TestOptions {
config: config(),
max_latency: Duration::from_micros(500),
second_fifo_working: true,
}
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
//let peripherals = embassy_stm32::init(config());
let options = options();
let peripherals = embassy_stm32::init(options.config);
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
// 250k bps
can.set_bitrate(250_000);
can.can.set_extended_filter(
can::filter::ExtendedFilterSlot::_0,
can::filter::ExtendedFilter::accept_all_into_fifo1(),
);
let mut can = can.into_internal_loopback_mode();
info!("CAN Configured");
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();
info!("Transmitting frame...");
let tx_ts = Instant::now();
can.write(&tx_frame).await;
let envelope = can.read().await.unwrap();
info!("Frame received!");
// Check data.
assert!(i == envelope.data()[0], "{} == {}", i, envelope.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 latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
// Was failing at 150 but we are not getting a real time stamp. I'm not
// sure if there are other delays
assert!(
MIN_LATENCY <= latency && latency <= options.max_latency,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
options.max_latency
);
i += 1;
if i > 10 {
break;
}
}
let max_buffered = if options.second_fifo_working { 6 } else { 3 };
// Below here, check that we can receive from both FIFO0 and FIFO0
// Above we configured FIFO1 for extended ID packets. There are only 3 slots
// 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();
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();
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);
}
can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
}
}
}
// Test again with a split
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();
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();
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);
}
can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
}
}
}
info!("Test OK");
cortex_m::asm::bkpt();
}