From a91a7a8557ae8998de7b08d753e7a55172fb43c8 Mon Sep 17 00:00:00 2001 From: Tomasz bla Fortuna Date: Sun, 14 Jan 2024 09:44:37 +0100 Subject: [PATCH 1/6] Add FDCAN dependency in correct flavor based on selected chip. Author: Torin Cooper-Bennun Change from review. --- embassy-stm32/Cargo.toml | 896 ++++++++++++++++++------------------ examples/stm32g4/Cargo.toml | 2 +- 2 files changed, 450 insertions(+), 448 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 70d4daf09..6c7591f57 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -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" ] diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 895ad3e7c..b87f461b4 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g473re", "memory-x", "unstable-pac", "exti", "fdcan"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } From 03ba45065e529284d41ebca5a8e716633107fc48 Mon Sep 17 00:00:00 2001 From: Tomasz bla Fortuna Date: Sun, 14 Jan 2024 09:47:26 +0100 Subject: [PATCH 2/6] Add FDCAN clock registers to G4 RCC. Author: Adam Morgan Break definitions out of bxcan that can be used innm fdcan. Typo --- embassy-stm32/build.rs | 2 +- embassy-stm32/src/can/bxcan.rs | 124 ++++----------------------------- embassy-stm32/src/can/enums.rs | 30 ++++++++ embassy-stm32/src/can/util.rs | 117 +++++++++++++++++++++++++++++++ embassy-stm32/src/rcc/g4.rs | 7 +- embassy-stm32/src/rcc/h.rs | 8 ++- 6 files changed, 173 insertions(+), 115 deletions(-) create mode 100644 embassy-stm32/src/can/enums.rs create mode 100644 embassy-stm32/src/can/util.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 948ce3aff..414723573 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -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 { diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index cc87b2565..7e00eca6f 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -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>, } -/// 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 { - 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. diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs new file mode 100644 index 000000000..36139a45c --- /dev/null +++ b/embassy-stm32/src/can/enums.rs @@ -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, +} diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs new file mode 100644 index 000000000..fcdbbad62 --- /dev/null +++ b/embassy-stm32/src/can/util.rs @@ -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 { + 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, + }) +} diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index fca364c21..891f0490b 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -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, 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, diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 15b51a398..85e12637e 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -6,6 +6,7 @@ use crate::pac::pwr::vals::Vos; 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::Fdcansel as FdCanClockSource; 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, @@ -212,6 +213,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 +251,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 +590,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_fdcan1sel(config.fdcan_clock_source) }); } From 1de78d049017b7d21946a2e64d94c990f1bf4e7e Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 14 Jan 2024 10:12:49 +0100 Subject: [PATCH 3/6] Initial FDCAN driver implementation. Original author: Torin Cooper-Bennun Cleanup and documentaion by: Tomasz bla Fortuna Corey Schuhen Use new PAC method now that the names are common. Use broken out definitions that can be shared with bxcan Populate Rx struct with an embassy timestamp. Remove use of RefCell. As per review comment. - THis will probably get squashed down. Fix --- embassy-stm32/src/can/fdcan.rs | 714 ++++++++++++++++++++++++++++++++- embassy-stm32/src/rcc/h.rs | 7 +- 2 files changed, 706 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 0cc2559cf..faf4af73f 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -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 { + 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 { + 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 { + 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 { + _phantom: PhantomData, +} + +// We use IT0 for everything currently +impl interrupt::typelevel::Handler for IT0InterruptHandler { + 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 { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for IT1InterruptHandler { + unsafe fn on_interrupt() {} +} + +impl BusError { + fn try_from(lec: LastErrorCode) -> Option { + 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, M>, + ns_per_timer_tick: u64, // For FDCAN internal timer +} + +fn calc_ns_per_timer_tick(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(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() -> Option { + 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

+ 'd, + rx: impl Peripheral

> + 'd, + tx: impl Peripheral

> + 'd, + _irqs: impl interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + '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::(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::(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 { + 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 { + 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 + // TODO: report overrun? + // for now we just drop it + + let frame: RxFrame = RxFrame::new( + rx.unwrap(), + &buffer, + #[cfg(feature = "time")] + calc_timestamp::(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 + // TODO: report overrun? + // for now we just drop it + + let frame: RxFrame = RxFrame::new( + rx.unwrap(), + &buffer, + #[cfg(feature = "time")] + calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), + ); + return Poll::Ready(Ok(frame)); + } else if let Some(err) = curr_error::() { + // 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, M>, + tx: &'c mut fdcan::Tx, 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 { + 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, M, fdcan::Fifo0>, + rx1: &'c mut fdcan::Rx, 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 { + 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 + // TODO: report overrun? + // for now we just drop it + let frame: RxFrame = RxFrame::new( + rx.unwrap(), + &buffer, + #[cfg(feature = "time")] + calc_timestamp::(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 + // TODO: report overrun? + // for now we just drop it + let frame: RxFrame = RxFrame::new( + rx.unwrap(), + &buffer, + #[cfg(feature = "time")] + calc_timestamp::(self.ns_per_timer_tick, rx.unwrap().time_stamp), + ); + return Poll::Ready(Ok(frame)); + } else if let Some(err) = curr_error::() { + // 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, 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, + 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); diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 85e12637e..dcaf2dced 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -6,10 +6,9 @@ use crate::pac::pwr::vals::Vos; 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::Fdcansel as FdCanClockSource; 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}; @@ -591,7 +590,7 @@ 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_fdcan1sel(config.fdcan_clock_source) + w.set_fdcan12sel(config.fdcan_clock_source) }); } From 1698f4dbc3b5f4e561c3edd20246af63c22da507 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 25 Jan 2024 17:10:25 +1000 Subject: [PATCH 4/6] Add FDCAN examples for STM32G4, STM32H5 and STM32H7 Fix examples Fix examples Fix examples. --- examples/stm32g4/Cargo.toml | 2 +- examples/stm32g4/src/bin/can.rs | 56 +++++++++++++++++++++++++ examples/stm32h5/src/bin/can.rs | 74 +++++++++++++++++++++++++++++++++ examples/stm32h7/src/bin/can.rs | 74 +++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 examples/stm32g4/src/bin/can.rs create mode 100644 examples/stm32h5/src/bin/can.rs create mode 100644 examples/stm32h7/src/bin/can.rs diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index b87f461b4..895ad3e7c 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g473re", "memory-x", "unstable-pac", "exti", "fdcan"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs new file mode 100644 index 000000000..727921fba --- /dev/null +++ b/examples/stm32g4/src/bin/can.rs @@ -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_IT1 => can::IT1InterruptHandler; +}); + +#[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; + } +} diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs new file mode 100644 index 000000000..2906d1576 --- /dev/null +++ b/examples/stm32h5/src/bin/can.rs @@ -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_IT1 => can::IT1InterruptHandler; +}); + +#[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; + } +} diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs new file mode 100644 index 000000000..2906d1576 --- /dev/null +++ b/examples/stm32h7/src/bin/can.rs @@ -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_IT1 => can::IT1InterruptHandler; +}); + +#[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; + } +} From 6e1047395d56dbbd1aa1a0352bdd3147e3994c5b Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Wed, 17 Jan 2024 21:13:24 +1000 Subject: [PATCH 5/6] HIL test for STM32 FDCAN support. Internal loopback. fdcan: use common.rs for HIL test. Fix tests. Fix tests. Fix tests Add HIL tests for H7 even though they are a bit crippled. CI fixes Bah Test bah --- tests/stm32/Cargo.toml | 16 ++- tests/stm32/src/bin/fdcan.rs | 243 +++++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 tests/stm32/src/bin/fdcan.rs diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bf85f05d2..b8b52c076 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -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"] -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"] +stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] +stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan"] +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" diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs new file mode 100644 index 000000000..7363eaa16 --- /dev/null +++ b/tests/stm32/src/bin/fdcan.rs @@ -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_IT1 => can::IT1InterruptHandler; +}); + +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(); +} From a14dc8413abacc78002a972cd55b1fbf19bac6df Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Wed, 31 Jan 2024 05:43:37 +1000 Subject: [PATCH 6/6] Disable h563 test. --- tests/stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index b8b52c076..cb1bd9a50 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -15,7 +15,7 @@ stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma" 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", "fdcan"] -stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan"] +stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "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"]