aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorey Schuhen <[email protected]>2024-02-03 09:44:00 +1000
committerCorey Schuhen <[email protected]>2024-02-17 18:25:58 +1000
commit70b3c4374d57ab638e0cb76013b725e1ea229546 (patch)
tree0c0f13b68c6e67d1f2ae49fafb62e5c38754c8c6
parent377e58e408f830f79171a470ba602b7d8bc525e4 (diff)
Port FDCAN HAL to use PAC directly instead of fdcan crate.
- Provide separate FDCAN capable and Classic CAN API's - Don't use fdcan crate dep anymore - Provide embedded-can traits.
-rw-r--r--embassy-stm32/Cargo.toml901
-rw-r--r--embassy-stm32/src/can/enums.rs17
-rw-r--r--embassy-stm32/src/can/fd/config.rs438
-rw-r--r--embassy-stm32/src/can/fd/filter.rs379
-rw-r--r--embassy-stm32/src/can/fd/message_ram/common.rs134
-rw-r--r--embassy-stm32/src/can/fd/message_ram/enums.rs233
-rw-r--r--embassy-stm32/src/can/fd/message_ram/extended_filter.rs136
-rw-r--r--embassy-stm32/src/can/fd/message_ram/generic.rs168
-rw-r--r--embassy-stm32/src/can/fd/message_ram/mod.rs170
-rw-r--r--embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs122
-rw-r--r--embassy-stm32/src/can/fd/message_ram/standard_filter.rs136
-rw-r--r--embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs433
-rw-r--r--embassy-stm32/src/can/fd/message_ram/txevent_element.rs138
-rw-r--r--embassy-stm32/src/can/fd/mod.rs6
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs776
-rw-r--r--embassy-stm32/src/can/fdcan.rs611
-rw-r--r--embassy-stm32/src/can/frame.rs370
-rw-r--r--examples/stm32g4/Cargo.toml1
-rw-r--r--examples/stm32g4/src/bin/can.rs96
-rw-r--r--examples/stm32h5/src/bin/can.rs89
-rw-r--r--examples/stm32h7/src/bin/can.rs89
-rw-r--r--tests/stm32/Cargo.toml1
-rw-r--r--tests/stm32/src/bin/fdcan.rs109
23 files changed, 4648 insertions, 905 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 389ed0041..d585d2cd6 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -55,10 +55,12 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["un
55embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 55embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
56embedded-hal-async = { version = "1.0" } 56embedded-hal-async = { version = "1.0" }
57embedded-hal-nb = { version = "1.0" } 57embedded-hal-nb = { version = "1.0" }
58embedded-can = "0.4"
58 59
59embedded-storage = "0.3.1" 60embedded-storage = "0.3.1"
60embedded-storage-async = { version = "0.4.1" } 61embedded-storage-async = { version = "0.4.1" }
61 62
63
62defmt = { version = "0.3", optional = true } 64defmt = { version = "0.3", optional = true }
63log = { version = "0.4.14", optional = true } 65log = { version = "0.4.14", optional = true }
64cortex-m-rt = ">=0.6.15,<0.8" 66cortex-m-rt = ">=0.6.15,<0.8"
@@ -80,7 +82,10 @@ chrono = { version = "^0.4", default-features = false, optional = true}
80bit_field = "0.10.2" 82bit_field = "0.10.2"
81document-features = "0.2.7" 83document-features = "0.2.7"
82 84
83fdcan = { version = "0.2.0", optional = true } 85static_assertions = { version = "1.1" }
86volatile-register = { version = "0.2.1" }
87
88
84 89
85[dev-dependencies] 90[dev-dependencies]
86critical-section = { version = "1.1", features = ["std"] } 91critical-section = { version = "1.1", features = ["std"] }
@@ -695,373 +700,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ]
695stm32f779bi = [ "stm32-metapac/stm32f779bi" ] 700stm32f779bi = [ "stm32-metapac/stm32f779bi" ]
696stm32f779ii = [ "stm32-metapac/stm32f779ii" ] 701stm32f779ii = [ "stm32-metapac/stm32f779ii" ]
697stm32f779ni = [ "stm32-metapac/stm32f779ni" ] 702stm32f779ni = [ "stm32-metapac/stm32f779ni" ]
698stm32g030c6 = [ "stm32-metapac/stm32g030c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 703stm32g030c6 = [ "stm32-metapac/stm32g030c6" ]
699stm32g030c8 = [ "stm32-metapac/stm32g030c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 704stm32g030c8 = [ "stm32-metapac/stm32g030c8" ]
700stm32g030f6 = [ "stm32-metapac/stm32g030f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 705stm32g030f6 = [ "stm32-metapac/stm32g030f6" ]
701stm32g030j6 = [ "stm32-metapac/stm32g030j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 706stm32g030j6 = [ "stm32-metapac/stm32g030j6" ]
702stm32g030k6 = [ "stm32-metapac/stm32g030k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 707stm32g030k6 = [ "stm32-metapac/stm32g030k6" ]
703stm32g030k8 = [ "stm32-metapac/stm32g030k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 708stm32g030k8 = [ "stm32-metapac/stm32g030k8" ]
704stm32g031c4 = [ "stm32-metapac/stm32g031c4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 709stm32g031c4 = [ "stm32-metapac/stm32g031c4" ]
705stm32g031c6 = [ "stm32-metapac/stm32g031c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 710stm32g031c6 = [ "stm32-metapac/stm32g031c6" ]
706stm32g031c8 = [ "stm32-metapac/stm32g031c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 711stm32g031c8 = [ "stm32-metapac/stm32g031c8" ]
707stm32g031f4 = [ "stm32-metapac/stm32g031f4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 712stm32g031f4 = [ "stm32-metapac/stm32g031f4" ]
708stm32g031f6 = [ "stm32-metapac/stm32g031f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 713stm32g031f6 = [ "stm32-metapac/stm32g031f6" ]
709stm32g031f8 = [ "stm32-metapac/stm32g031f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 714stm32g031f8 = [ "stm32-metapac/stm32g031f8" ]
710stm32g031g4 = [ "stm32-metapac/stm32g031g4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 715stm32g031g4 = [ "stm32-metapac/stm32g031g4" ]
711stm32g031g6 = [ "stm32-metapac/stm32g031g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 716stm32g031g6 = [ "stm32-metapac/stm32g031g6" ]
712stm32g031g8 = [ "stm32-metapac/stm32g031g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 717stm32g031g8 = [ "stm32-metapac/stm32g031g8" ]
713stm32g031j4 = [ "stm32-metapac/stm32g031j4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 718stm32g031j4 = [ "stm32-metapac/stm32g031j4" ]
714stm32g031j6 = [ "stm32-metapac/stm32g031j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 719stm32g031j6 = [ "stm32-metapac/stm32g031j6" ]
715stm32g031k4 = [ "stm32-metapac/stm32g031k4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 720stm32g031k4 = [ "stm32-metapac/stm32g031k4" ]
716stm32g031k6 = [ "stm32-metapac/stm32g031k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 721stm32g031k6 = [ "stm32-metapac/stm32g031k6" ]
717stm32g031k8 = [ "stm32-metapac/stm32g031k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 722stm32g031k8 = [ "stm32-metapac/stm32g031k8" ]
718stm32g031y8 = [ "stm32-metapac/stm32g031y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 723stm32g031y8 = [ "stm32-metapac/stm32g031y8" ]
719stm32g041c6 = [ "stm32-metapac/stm32g041c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 724stm32g041c6 = [ "stm32-metapac/stm32g041c6" ]
720stm32g041c8 = [ "stm32-metapac/stm32g041c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 725stm32g041c8 = [ "stm32-metapac/stm32g041c8" ]
721stm32g041f6 = [ "stm32-metapac/stm32g041f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 726stm32g041f6 = [ "stm32-metapac/stm32g041f6" ]
722stm32g041f8 = [ "stm32-metapac/stm32g041f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 727stm32g041f8 = [ "stm32-metapac/stm32g041f8" ]
723stm32g041g6 = [ "stm32-metapac/stm32g041g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 728stm32g041g6 = [ "stm32-metapac/stm32g041g6" ]
724stm32g041g8 = [ "stm32-metapac/stm32g041g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 729stm32g041g8 = [ "stm32-metapac/stm32g041g8" ]
725stm32g041j6 = [ "stm32-metapac/stm32g041j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 730stm32g041j6 = [ "stm32-metapac/stm32g041j6" ]
726stm32g041k6 = [ "stm32-metapac/stm32g041k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 731stm32g041k6 = [ "stm32-metapac/stm32g041k6" ]
727stm32g041k8 = [ "stm32-metapac/stm32g041k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 732stm32g041k8 = [ "stm32-metapac/stm32g041k8" ]
728stm32g041y8 = [ "stm32-metapac/stm32g041y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 733stm32g041y8 = [ "stm32-metapac/stm32g041y8" ]
729stm32g050c6 = [ "stm32-metapac/stm32g050c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 734stm32g050c6 = [ "stm32-metapac/stm32g050c6" ]
730stm32g050c8 = [ "stm32-metapac/stm32g050c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 735stm32g050c8 = [ "stm32-metapac/stm32g050c8" ]
731stm32g050f6 = [ "stm32-metapac/stm32g050f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 736stm32g050f6 = [ "stm32-metapac/stm32g050f6" ]
732stm32g050k6 = [ "stm32-metapac/stm32g050k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 737stm32g050k6 = [ "stm32-metapac/stm32g050k6" ]
733stm32g050k8 = [ "stm32-metapac/stm32g050k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 738stm32g050k8 = [ "stm32-metapac/stm32g050k8" ]
734stm32g051c6 = [ "stm32-metapac/stm32g051c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 739stm32g051c6 = [ "stm32-metapac/stm32g051c6" ]
735stm32g051c8 = [ "stm32-metapac/stm32g051c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 740stm32g051c8 = [ "stm32-metapac/stm32g051c8" ]
736stm32g051f6 = [ "stm32-metapac/stm32g051f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 741stm32g051f6 = [ "stm32-metapac/stm32g051f6" ]
737stm32g051f8 = [ "stm32-metapac/stm32g051f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 742stm32g051f8 = [ "stm32-metapac/stm32g051f8" ]
738stm32g051g6 = [ "stm32-metapac/stm32g051g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 743stm32g051g6 = [ "stm32-metapac/stm32g051g6" ]
739stm32g051g8 = [ "stm32-metapac/stm32g051g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 744stm32g051g8 = [ "stm32-metapac/stm32g051g8" ]
740stm32g051k6 = [ "stm32-metapac/stm32g051k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 745stm32g051k6 = [ "stm32-metapac/stm32g051k6" ]
741stm32g051k8 = [ "stm32-metapac/stm32g051k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 746stm32g051k8 = [ "stm32-metapac/stm32g051k8" ]
742stm32g061c6 = [ "stm32-metapac/stm32g061c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 747stm32g061c6 = [ "stm32-metapac/stm32g061c6" ]
743stm32g061c8 = [ "stm32-metapac/stm32g061c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 748stm32g061c8 = [ "stm32-metapac/stm32g061c8" ]
744stm32g061f6 = [ "stm32-metapac/stm32g061f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 749stm32g061f6 = [ "stm32-metapac/stm32g061f6" ]
745stm32g061f8 = [ "stm32-metapac/stm32g061f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 750stm32g061f8 = [ "stm32-metapac/stm32g061f8" ]
746stm32g061g6 = [ "stm32-metapac/stm32g061g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 751stm32g061g6 = [ "stm32-metapac/stm32g061g6" ]
747stm32g061g8 = [ "stm32-metapac/stm32g061g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 752stm32g061g8 = [ "stm32-metapac/stm32g061g8" ]
748stm32g061k6 = [ "stm32-metapac/stm32g061k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 753stm32g061k6 = [ "stm32-metapac/stm32g061k6" ]
749stm32g061k8 = [ "stm32-metapac/stm32g061k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 754stm32g061k8 = [ "stm32-metapac/stm32g061k8" ]
750stm32g070cb = [ "stm32-metapac/stm32g070cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 755stm32g070cb = [ "stm32-metapac/stm32g070cb" ]
751stm32g070kb = [ "stm32-metapac/stm32g070kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 756stm32g070kb = [ "stm32-metapac/stm32g070kb" ]
752stm32g070rb = [ "stm32-metapac/stm32g070rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 757stm32g070rb = [ "stm32-metapac/stm32g070rb" ]
753stm32g071c6 = [ "stm32-metapac/stm32g071c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 758stm32g071c6 = [ "stm32-metapac/stm32g071c6" ]
754stm32g071c8 = [ "stm32-metapac/stm32g071c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 759stm32g071c8 = [ "stm32-metapac/stm32g071c8" ]
755stm32g071cb = [ "stm32-metapac/stm32g071cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 760stm32g071cb = [ "stm32-metapac/stm32g071cb" ]
756stm32g071eb = [ "stm32-metapac/stm32g071eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 761stm32g071eb = [ "stm32-metapac/stm32g071eb" ]
757stm32g071g6 = [ "stm32-metapac/stm32g071g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 762stm32g071g6 = [ "stm32-metapac/stm32g071g6" ]
758stm32g071g8 = [ "stm32-metapac/stm32g071g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 763stm32g071g8 = [ "stm32-metapac/stm32g071g8" ]
759stm32g071gb = [ "stm32-metapac/stm32g071gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 764stm32g071gb = [ "stm32-metapac/stm32g071gb" ]
760stm32g071k6 = [ "stm32-metapac/stm32g071k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 765stm32g071k6 = [ "stm32-metapac/stm32g071k6" ]
761stm32g071k8 = [ "stm32-metapac/stm32g071k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 766stm32g071k8 = [ "stm32-metapac/stm32g071k8" ]
762stm32g071kb = [ "stm32-metapac/stm32g071kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 767stm32g071kb = [ "stm32-metapac/stm32g071kb" ]
763stm32g071r6 = [ "stm32-metapac/stm32g071r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 768stm32g071r6 = [ "stm32-metapac/stm32g071r6" ]
764stm32g071r8 = [ "stm32-metapac/stm32g071r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 769stm32g071r8 = [ "stm32-metapac/stm32g071r8" ]
765stm32g071rb = [ "stm32-metapac/stm32g071rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 770stm32g071rb = [ "stm32-metapac/stm32g071rb" ]
766stm32g081cb = [ "stm32-metapac/stm32g081cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 771stm32g081cb = [ "stm32-metapac/stm32g081cb" ]
767stm32g081eb = [ "stm32-metapac/stm32g081eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 772stm32g081eb = [ "stm32-metapac/stm32g081eb" ]
768stm32g081gb = [ "stm32-metapac/stm32g081gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 773stm32g081gb = [ "stm32-metapac/stm32g081gb" ]
769stm32g081kb = [ "stm32-metapac/stm32g081kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 774stm32g081kb = [ "stm32-metapac/stm32g081kb" ]
770stm32g081rb = [ "stm32-metapac/stm32g081rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 775stm32g081rb = [ "stm32-metapac/stm32g081rb" ]
771stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 776stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce" ]
772stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 777stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke" ]
773stm32g0b0re = [ "stm32-metapac/stm32g0b0re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 778stm32g0b0re = [ "stm32-metapac/stm32g0b0re" ]
774stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 779stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve" ]
775stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 780stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb" ]
776stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 781stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc" ]
777stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 782stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce" ]
778stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 783stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb" ]
779stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 784stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc" ]
780stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 785stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke" ]
781stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 786stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb" ]
782stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 787stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc" ]
783stm32g0b1me = [ "stm32-metapac/stm32g0b1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 788stm32g0b1me = [ "stm32-metapac/stm32g0b1me" ]
784stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 789stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne" ]
785stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 790stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb" ]
786stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 791stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc" ]
787stm32g0b1re = [ "stm32-metapac/stm32g0b1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 792stm32g0b1re = [ "stm32-metapac/stm32g0b1re" ]
788stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 793stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb" ]
789stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 794stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc" ]
790stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 795stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve" ]
791stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 796stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc" ]
792stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 797stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce" ]
793stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 798stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc" ]
794stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 799stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke" ]
795stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 800stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc" ]
796stm32g0c1me = [ "stm32-metapac/stm32g0c1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 801stm32g0c1me = [ "stm32-metapac/stm32g0c1me" ]
797stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 802stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne" ]
798stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 803stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc" ]
799stm32g0c1re = [ "stm32-metapac/stm32g0c1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 804stm32g0c1re = [ "stm32-metapac/stm32g0c1re" ]
800stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 805stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc" ]
801stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 806stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve" ]
802stm32g431c6 = [ "stm32-metapac/stm32g431c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 807stm32g431c6 = [ "stm32-metapac/stm32g431c6" ]
803stm32g431c8 = [ "stm32-metapac/stm32g431c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 808stm32g431c8 = [ "stm32-metapac/stm32g431c8" ]
804stm32g431cb = [ "stm32-metapac/stm32g431cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 809stm32g431cb = [ "stm32-metapac/stm32g431cb" ]
805stm32g431k6 = [ "stm32-metapac/stm32g431k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 810stm32g431k6 = [ "stm32-metapac/stm32g431k6" ]
806stm32g431k8 = [ "stm32-metapac/stm32g431k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 811stm32g431k8 = [ "stm32-metapac/stm32g431k8" ]
807stm32g431kb = [ "stm32-metapac/stm32g431kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 812stm32g431kb = [ "stm32-metapac/stm32g431kb" ]
808stm32g431m6 = [ "stm32-metapac/stm32g431m6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 813stm32g431m6 = [ "stm32-metapac/stm32g431m6" ]
809stm32g431m8 = [ "stm32-metapac/stm32g431m8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 814stm32g431m8 = [ "stm32-metapac/stm32g431m8" ]
810stm32g431mb = [ "stm32-metapac/stm32g431mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 815stm32g431mb = [ "stm32-metapac/stm32g431mb" ]
811stm32g431r6 = [ "stm32-metapac/stm32g431r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 816stm32g431r6 = [ "stm32-metapac/stm32g431r6" ]
812stm32g431r8 = [ "stm32-metapac/stm32g431r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 817stm32g431r8 = [ "stm32-metapac/stm32g431r8" ]
813stm32g431rb = [ "stm32-metapac/stm32g431rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 818stm32g431rb = [ "stm32-metapac/stm32g431rb" ]
814stm32g431v6 = [ "stm32-metapac/stm32g431v6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 819stm32g431v6 = [ "stm32-metapac/stm32g431v6" ]
815stm32g431v8 = [ "stm32-metapac/stm32g431v8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 820stm32g431v8 = [ "stm32-metapac/stm32g431v8" ]
816stm32g431vb = [ "stm32-metapac/stm32g431vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 821stm32g431vb = [ "stm32-metapac/stm32g431vb" ]
817stm32g441cb = [ "stm32-metapac/stm32g441cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 822stm32g441cb = [ "stm32-metapac/stm32g441cb" ]
818stm32g441kb = [ "stm32-metapac/stm32g441kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 823stm32g441kb = [ "stm32-metapac/stm32g441kb" ]
819stm32g441mb = [ "stm32-metapac/stm32g441mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 824stm32g441mb = [ "stm32-metapac/stm32g441mb" ]
820stm32g441rb = [ "stm32-metapac/stm32g441rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 825stm32g441rb = [ "stm32-metapac/stm32g441rb" ]
821stm32g441vb = [ "stm32-metapac/stm32g441vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 826stm32g441vb = [ "stm32-metapac/stm32g441vb" ]
822stm32g471cc = [ "stm32-metapac/stm32g471cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 827stm32g471cc = [ "stm32-metapac/stm32g471cc" ]
823stm32g471ce = [ "stm32-metapac/stm32g471ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 828stm32g471ce = [ "stm32-metapac/stm32g471ce" ]
824stm32g471mc = [ "stm32-metapac/stm32g471mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 829stm32g471mc = [ "stm32-metapac/stm32g471mc" ]
825stm32g471me = [ "stm32-metapac/stm32g471me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 830stm32g471me = [ "stm32-metapac/stm32g471me" ]
826stm32g471qc = [ "stm32-metapac/stm32g471qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 831stm32g471qc = [ "stm32-metapac/stm32g471qc" ]
827stm32g471qe = [ "stm32-metapac/stm32g471qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 832stm32g471qe = [ "stm32-metapac/stm32g471qe" ]
828stm32g471rc = [ "stm32-metapac/stm32g471rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 833stm32g471rc = [ "stm32-metapac/stm32g471rc" ]
829stm32g471re = [ "stm32-metapac/stm32g471re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 834stm32g471re = [ "stm32-metapac/stm32g471re" ]
830stm32g471vc = [ "stm32-metapac/stm32g471vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 835stm32g471vc = [ "stm32-metapac/stm32g471vc" ]
831stm32g471ve = [ "stm32-metapac/stm32g471ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 836stm32g471ve = [ "stm32-metapac/stm32g471ve" ]
832stm32g473cb = [ "stm32-metapac/stm32g473cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 837stm32g473cb = [ "stm32-metapac/stm32g473cb" ]
833stm32g473cc = [ "stm32-metapac/stm32g473cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 838stm32g473cc = [ "stm32-metapac/stm32g473cc" ]
834stm32g473ce = [ "stm32-metapac/stm32g473ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 839stm32g473ce = [ "stm32-metapac/stm32g473ce" ]
835stm32g473mb = [ "stm32-metapac/stm32g473mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 840stm32g473mb = [ "stm32-metapac/stm32g473mb" ]
836stm32g473mc = [ "stm32-metapac/stm32g473mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 841stm32g473mc = [ "stm32-metapac/stm32g473mc" ]
837stm32g473me = [ "stm32-metapac/stm32g473me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 842stm32g473me = [ "stm32-metapac/stm32g473me" ]
838stm32g473pb = [ "stm32-metapac/stm32g473pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 843stm32g473pb = [ "stm32-metapac/stm32g473pb" ]
839stm32g473pc = [ "stm32-metapac/stm32g473pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 844stm32g473pc = [ "stm32-metapac/stm32g473pc" ]
840stm32g473pe = [ "stm32-metapac/stm32g473pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 845stm32g473pe = [ "stm32-metapac/stm32g473pe" ]
841stm32g473qb = [ "stm32-metapac/stm32g473qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 846stm32g473qb = [ "stm32-metapac/stm32g473qb" ]
842stm32g473qc = [ "stm32-metapac/stm32g473qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 847stm32g473qc = [ "stm32-metapac/stm32g473qc" ]
843stm32g473qe = [ "stm32-metapac/stm32g473qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 848stm32g473qe = [ "stm32-metapac/stm32g473qe" ]
844stm32g473rb = [ "stm32-metapac/stm32g473rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 849stm32g473rb = [ "stm32-metapac/stm32g473rb" ]
845stm32g473rc = [ "stm32-metapac/stm32g473rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 850stm32g473rc = [ "stm32-metapac/stm32g473rc" ]
846stm32g473re = [ "stm32-metapac/stm32g473re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 851stm32g473re = [ "stm32-metapac/stm32g473re" ]
847stm32g473vb = [ "stm32-metapac/stm32g473vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 852stm32g473vb = [ "stm32-metapac/stm32g473vb" ]
848stm32g473vc = [ "stm32-metapac/stm32g473vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 853stm32g473vc = [ "stm32-metapac/stm32g473vc" ]
849stm32g473ve = [ "stm32-metapac/stm32g473ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 854stm32g473ve = [ "stm32-metapac/stm32g473ve" ]
850stm32g474cb = [ "stm32-metapac/stm32g474cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 855stm32g474cb = [ "stm32-metapac/stm32g474cb" ]
851stm32g474cc = [ "stm32-metapac/stm32g474cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 856stm32g474cc = [ "stm32-metapac/stm32g474cc" ]
852stm32g474ce = [ "stm32-metapac/stm32g474ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 857stm32g474ce = [ "stm32-metapac/stm32g474ce" ]
853stm32g474mb = [ "stm32-metapac/stm32g474mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 858stm32g474mb = [ "stm32-metapac/stm32g474mb" ]
854stm32g474mc = [ "stm32-metapac/stm32g474mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 859stm32g474mc = [ "stm32-metapac/stm32g474mc" ]
855stm32g474me = [ "stm32-metapac/stm32g474me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 860stm32g474me = [ "stm32-metapac/stm32g474me" ]
856stm32g474pb = [ "stm32-metapac/stm32g474pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 861stm32g474pb = [ "stm32-metapac/stm32g474pb" ]
857stm32g474pc = [ "stm32-metapac/stm32g474pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 862stm32g474pc = [ "stm32-metapac/stm32g474pc" ]
858stm32g474pe = [ "stm32-metapac/stm32g474pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 863stm32g474pe = [ "stm32-metapac/stm32g474pe" ]
859stm32g474qb = [ "stm32-metapac/stm32g474qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 864stm32g474qb = [ "stm32-metapac/stm32g474qb" ]
860stm32g474qc = [ "stm32-metapac/stm32g474qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 865stm32g474qc = [ "stm32-metapac/stm32g474qc" ]
861stm32g474qe = [ "stm32-metapac/stm32g474qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 866stm32g474qe = [ "stm32-metapac/stm32g474qe" ]
862stm32g474rb = [ "stm32-metapac/stm32g474rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 867stm32g474rb = [ "stm32-metapac/stm32g474rb" ]
863stm32g474rc = [ "stm32-metapac/stm32g474rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 868stm32g474rc = [ "stm32-metapac/stm32g474rc" ]
864stm32g474re = [ "stm32-metapac/stm32g474re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 869stm32g474re = [ "stm32-metapac/stm32g474re" ]
865stm32g474vb = [ "stm32-metapac/stm32g474vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 870stm32g474vb = [ "stm32-metapac/stm32g474vb" ]
866stm32g474vc = [ "stm32-metapac/stm32g474vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 871stm32g474vc = [ "stm32-metapac/stm32g474vc" ]
867stm32g474ve = [ "stm32-metapac/stm32g474ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 872stm32g474ve = [ "stm32-metapac/stm32g474ve" ]
868stm32g483ce = [ "stm32-metapac/stm32g483ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 873stm32g483ce = [ "stm32-metapac/stm32g483ce" ]
869stm32g483me = [ "stm32-metapac/stm32g483me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 874stm32g483me = [ "stm32-metapac/stm32g483me" ]
870stm32g483pe = [ "stm32-metapac/stm32g483pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 875stm32g483pe = [ "stm32-metapac/stm32g483pe" ]
871stm32g483qe = [ "stm32-metapac/stm32g483qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 876stm32g483qe = [ "stm32-metapac/stm32g483qe" ]
872stm32g483re = [ "stm32-metapac/stm32g483re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 877stm32g483re = [ "stm32-metapac/stm32g483re" ]
873stm32g483ve = [ "stm32-metapac/stm32g483ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 878stm32g483ve = [ "stm32-metapac/stm32g483ve" ]
874stm32g484ce = [ "stm32-metapac/stm32g484ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 879stm32g484ce = [ "stm32-metapac/stm32g484ce" ]
875stm32g484me = [ "stm32-metapac/stm32g484me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 880stm32g484me = [ "stm32-metapac/stm32g484me" ]
876stm32g484pe = [ "stm32-metapac/stm32g484pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 881stm32g484pe = [ "stm32-metapac/stm32g484pe" ]
877stm32g484qe = [ "stm32-metapac/stm32g484qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 882stm32g484qe = [ "stm32-metapac/stm32g484qe" ]
878stm32g484re = [ "stm32-metapac/stm32g484re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 883stm32g484re = [ "stm32-metapac/stm32g484re" ]
879stm32g484ve = [ "stm32-metapac/stm32g484ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 884stm32g484ve = [ "stm32-metapac/stm32g484ve" ]
880stm32g491cc = [ "stm32-metapac/stm32g491cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 885stm32g491cc = [ "stm32-metapac/stm32g491cc" ]
881stm32g491ce = [ "stm32-metapac/stm32g491ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 886stm32g491ce = [ "stm32-metapac/stm32g491ce" ]
882stm32g491kc = [ "stm32-metapac/stm32g491kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 887stm32g491kc = [ "stm32-metapac/stm32g491kc" ]
883stm32g491ke = [ "stm32-metapac/stm32g491ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 888stm32g491ke = [ "stm32-metapac/stm32g491ke" ]
884stm32g491mc = [ "stm32-metapac/stm32g491mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 889stm32g491mc = [ "stm32-metapac/stm32g491mc" ]
885stm32g491me = [ "stm32-metapac/stm32g491me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 890stm32g491me = [ "stm32-metapac/stm32g491me" ]
886stm32g491rc = [ "stm32-metapac/stm32g491rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 891stm32g491rc = [ "stm32-metapac/stm32g491rc" ]
887stm32g491re = [ "stm32-metapac/stm32g491re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 892stm32g491re = [ "stm32-metapac/stm32g491re" ]
888stm32g491vc = [ "stm32-metapac/stm32g491vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 893stm32g491vc = [ "stm32-metapac/stm32g491vc" ]
889stm32g491ve = [ "stm32-metapac/stm32g491ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 894stm32g491ve = [ "stm32-metapac/stm32g491ve" ]
890stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 895stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce" ]
891stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 896stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ]
892stm32g4a1me = [ "stm32-metapac/stm32g4a1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 897stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ]
893stm32g4a1re = [ "stm32-metapac/stm32g4a1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 898stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ]
894stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 899stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ]
895stm32h503cb = [ "stm32-metapac/stm32h503cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 900stm32h503cb = [ "stm32-metapac/stm32h503cb" ]
896stm32h503eb = [ "stm32-metapac/stm32h503eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 901stm32h503eb = [ "stm32-metapac/stm32h503eb" ]
897stm32h503kb = [ "stm32-metapac/stm32h503kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 902stm32h503kb = [ "stm32-metapac/stm32h503kb" ]
898stm32h503rb = [ "stm32-metapac/stm32h503rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 903stm32h503rb = [ "stm32-metapac/stm32h503rb" ]
899stm32h562ag = [ "stm32-metapac/stm32h562ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 904stm32h562ag = [ "stm32-metapac/stm32h562ag" ]
900stm32h562ai = [ "stm32-metapac/stm32h562ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 905stm32h562ai = [ "stm32-metapac/stm32h562ai" ]
901stm32h562ig = [ "stm32-metapac/stm32h562ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 906stm32h562ig = [ "stm32-metapac/stm32h562ig" ]
902stm32h562ii = [ "stm32-metapac/stm32h562ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 907stm32h562ii = [ "stm32-metapac/stm32h562ii" ]
903stm32h562rg = [ "stm32-metapac/stm32h562rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 908stm32h562rg = [ "stm32-metapac/stm32h562rg" ]
904stm32h562ri = [ "stm32-metapac/stm32h562ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 909stm32h562ri = [ "stm32-metapac/stm32h562ri" ]
905stm32h562vg = [ "stm32-metapac/stm32h562vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 910stm32h562vg = [ "stm32-metapac/stm32h562vg" ]
906stm32h562vi = [ "stm32-metapac/stm32h562vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 911stm32h562vi = [ "stm32-metapac/stm32h562vi" ]
907stm32h562zg = [ "stm32-metapac/stm32h562zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 912stm32h562zg = [ "stm32-metapac/stm32h562zg" ]
908stm32h562zi = [ "stm32-metapac/stm32h562zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 913stm32h562zi = [ "stm32-metapac/stm32h562zi" ]
909stm32h563ag = [ "stm32-metapac/stm32h563ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 914stm32h563ag = [ "stm32-metapac/stm32h563ag" ]
910stm32h563ai = [ "stm32-metapac/stm32h563ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 915stm32h563ai = [ "stm32-metapac/stm32h563ai" ]
911stm32h563ig = [ "stm32-metapac/stm32h563ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 916stm32h563ig = [ "stm32-metapac/stm32h563ig" ]
912stm32h563ii = [ "stm32-metapac/stm32h563ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 917stm32h563ii = [ "stm32-metapac/stm32h563ii" ]
913stm32h563mi = [ "stm32-metapac/stm32h563mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 918stm32h563mi = [ "stm32-metapac/stm32h563mi" ]
914stm32h563rg = [ "stm32-metapac/stm32h563rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 919stm32h563rg = [ "stm32-metapac/stm32h563rg" ]
915stm32h563ri = [ "stm32-metapac/stm32h563ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 920stm32h563ri = [ "stm32-metapac/stm32h563ri" ]
916stm32h563vg = [ "stm32-metapac/stm32h563vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 921stm32h563vg = [ "stm32-metapac/stm32h563vg" ]
917stm32h563vi = [ "stm32-metapac/stm32h563vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 922stm32h563vi = [ "stm32-metapac/stm32h563vi" ]
918stm32h563zg = [ "stm32-metapac/stm32h563zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 923stm32h563zg = [ "stm32-metapac/stm32h563zg" ]
919stm32h563zi = [ "stm32-metapac/stm32h563zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 924stm32h563zi = [ "stm32-metapac/stm32h563zi" ]
920stm32h573ai = [ "stm32-metapac/stm32h573ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 925stm32h573ai = [ "stm32-metapac/stm32h573ai" ]
921stm32h573ii = [ "stm32-metapac/stm32h573ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 926stm32h573ii = [ "stm32-metapac/stm32h573ii" ]
922stm32h573mi = [ "stm32-metapac/stm32h573mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 927stm32h573mi = [ "stm32-metapac/stm32h573mi" ]
923stm32h573ri = [ "stm32-metapac/stm32h573ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 928stm32h573ri = [ "stm32-metapac/stm32h573ri" ]
924stm32h573vi = [ "stm32-metapac/stm32h573vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 929stm32h573vi = [ "stm32-metapac/stm32h573vi" ]
925stm32h573zi = [ "stm32-metapac/stm32h573zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 930stm32h573zi = [ "stm32-metapac/stm32h573zi" ]
926stm32h723ve = [ "stm32-metapac/stm32h723ve", "dep:fdcan", "fdcan/fdcan_h7" ] 931stm32h723ve = [ "stm32-metapac/stm32h723ve" ]
927stm32h723vg = [ "stm32-metapac/stm32h723vg", "dep:fdcan", "fdcan/fdcan_h7" ] 932stm32h723vg = [ "stm32-metapac/stm32h723vg" ]
928stm32h723ze = [ "stm32-metapac/stm32h723ze", "dep:fdcan", "fdcan/fdcan_h7" ] 933stm32h723ze = [ "stm32-metapac/stm32h723ze" ]
929stm32h723zg = [ "stm32-metapac/stm32h723zg", "dep:fdcan", "fdcan/fdcan_h7" ] 934stm32h723zg = [ "stm32-metapac/stm32h723zg" ]
930stm32h725ae = [ "stm32-metapac/stm32h725ae", "dep:fdcan", "fdcan/fdcan_h7" ] 935stm32h725ae = [ "stm32-metapac/stm32h725ae" ]
931stm32h725ag = [ "stm32-metapac/stm32h725ag", "dep:fdcan", "fdcan/fdcan_h7" ] 936stm32h725ag = [ "stm32-metapac/stm32h725ag" ]
932stm32h725ie = [ "stm32-metapac/stm32h725ie", "dep:fdcan", "fdcan/fdcan_h7" ] 937stm32h725ie = [ "stm32-metapac/stm32h725ie" ]
933stm32h725ig = [ "stm32-metapac/stm32h725ig", "dep:fdcan", "fdcan/fdcan_h7" ] 938stm32h725ig = [ "stm32-metapac/stm32h725ig" ]
934stm32h725re = [ "stm32-metapac/stm32h725re", "dep:fdcan", "fdcan/fdcan_h7" ] 939stm32h725re = [ "stm32-metapac/stm32h725re" ]
935stm32h725rg = [ "stm32-metapac/stm32h725rg", "dep:fdcan", "fdcan/fdcan_h7" ] 940stm32h725rg = [ "stm32-metapac/stm32h725rg" ]
936stm32h725ve = [ "stm32-metapac/stm32h725ve", "dep:fdcan", "fdcan/fdcan_h7" ] 941stm32h725ve = [ "stm32-metapac/stm32h725ve" ]
937stm32h725vg = [ "stm32-metapac/stm32h725vg", "dep:fdcan", "fdcan/fdcan_h7" ] 942stm32h725vg = [ "stm32-metapac/stm32h725vg" ]
938stm32h725ze = [ "stm32-metapac/stm32h725ze", "dep:fdcan", "fdcan/fdcan_h7" ] 943stm32h725ze = [ "stm32-metapac/stm32h725ze" ]
939stm32h725zg = [ "stm32-metapac/stm32h725zg", "dep:fdcan", "fdcan/fdcan_h7" ] 944stm32h725zg = [ "stm32-metapac/stm32h725zg" ]
940stm32h730ab = [ "stm32-metapac/stm32h730ab", "dep:fdcan", "fdcan/fdcan_h7" ] 945stm32h730ab = [ "stm32-metapac/stm32h730ab" ]
941stm32h730ib = [ "stm32-metapac/stm32h730ib", "dep:fdcan", "fdcan/fdcan_h7" ] 946stm32h730ib = [ "stm32-metapac/stm32h730ib" ]
942stm32h730vb = [ "stm32-metapac/stm32h730vb", "dep:fdcan", "fdcan/fdcan_h7" ] 947stm32h730vb = [ "stm32-metapac/stm32h730vb" ]
943stm32h730zb = [ "stm32-metapac/stm32h730zb", "dep:fdcan", "fdcan/fdcan_h7" ] 948stm32h730zb = [ "stm32-metapac/stm32h730zb" ]
944stm32h733vg = [ "stm32-metapac/stm32h733vg", "dep:fdcan", "fdcan/fdcan_h7" ] 949stm32h733vg = [ "stm32-metapac/stm32h733vg" ]
945stm32h733zg = [ "stm32-metapac/stm32h733zg", "dep:fdcan", "fdcan/fdcan_h7" ] 950stm32h733zg = [ "stm32-metapac/stm32h733zg" ]
946stm32h735ag = [ "stm32-metapac/stm32h735ag", "dep:fdcan", "fdcan/fdcan_h7" ] 951stm32h735ag = [ "stm32-metapac/stm32h735ag" ]
947stm32h735ig = [ "stm32-metapac/stm32h735ig", "dep:fdcan", "fdcan/fdcan_h7" ] 952stm32h735ig = [ "stm32-metapac/stm32h735ig" ]
948stm32h735rg = [ "stm32-metapac/stm32h735rg", "dep:fdcan", "fdcan/fdcan_h7" ] 953stm32h735rg = [ "stm32-metapac/stm32h735rg" ]
949stm32h735vg = [ "stm32-metapac/stm32h735vg", "dep:fdcan", "fdcan/fdcan_h7" ] 954stm32h735vg = [ "stm32-metapac/stm32h735vg" ]
950stm32h735zg = [ "stm32-metapac/stm32h735zg", "dep:fdcan", "fdcan/fdcan_h7" ] 955stm32h735zg = [ "stm32-metapac/stm32h735zg" ]
951stm32h742ag = [ "stm32-metapac/stm32h742ag", "dep:fdcan", "fdcan/fdcan_h7" ] 956stm32h742ag = [ "stm32-metapac/stm32h742ag" ]
952stm32h742ai = [ "stm32-metapac/stm32h742ai", "dep:fdcan", "fdcan/fdcan_h7" ] 957stm32h742ai = [ "stm32-metapac/stm32h742ai" ]
953stm32h742bg = [ "stm32-metapac/stm32h742bg", "dep:fdcan", "fdcan/fdcan_h7" ] 958stm32h742bg = [ "stm32-metapac/stm32h742bg" ]
954stm32h742bi = [ "stm32-metapac/stm32h742bi", "dep:fdcan", "fdcan/fdcan_h7" ] 959stm32h742bi = [ "stm32-metapac/stm32h742bi" ]
955stm32h742ig = [ "stm32-metapac/stm32h742ig", "dep:fdcan", "fdcan/fdcan_h7" ] 960stm32h742ig = [ "stm32-metapac/stm32h742ig" ]
956stm32h742ii = [ "stm32-metapac/stm32h742ii", "dep:fdcan", "fdcan/fdcan_h7" ] 961stm32h742ii = [ "stm32-metapac/stm32h742ii" ]
957stm32h742vg = [ "stm32-metapac/stm32h742vg", "dep:fdcan", "fdcan/fdcan_h7" ] 962stm32h742vg = [ "stm32-metapac/stm32h742vg" ]
958stm32h742vi = [ "stm32-metapac/stm32h742vi", "dep:fdcan", "fdcan/fdcan_h7" ] 963stm32h742vi = [ "stm32-metapac/stm32h742vi" ]
959stm32h742xg = [ "stm32-metapac/stm32h742xg", "dep:fdcan", "fdcan/fdcan_h7" ] 964stm32h742xg = [ "stm32-metapac/stm32h742xg" ]
960stm32h742xi = [ "stm32-metapac/stm32h742xi", "dep:fdcan", "fdcan/fdcan_h7" ] 965stm32h742xi = [ "stm32-metapac/stm32h742xi" ]
961stm32h742zg = [ "stm32-metapac/stm32h742zg", "dep:fdcan", "fdcan/fdcan_h7" ] 966stm32h742zg = [ "stm32-metapac/stm32h742zg" ]
962stm32h742zi = [ "stm32-metapac/stm32h742zi", "dep:fdcan", "fdcan/fdcan_h7" ] 967stm32h742zi = [ "stm32-metapac/stm32h742zi" ]
963stm32h743ag = [ "stm32-metapac/stm32h743ag", "dep:fdcan", "fdcan/fdcan_h7" ] 968stm32h743ag = [ "stm32-metapac/stm32h743ag" ]
964stm32h743ai = [ "stm32-metapac/stm32h743ai", "dep:fdcan", "fdcan/fdcan_h7" ] 969stm32h743ai = [ "stm32-metapac/stm32h743ai" ]
965stm32h743bg = [ "stm32-metapac/stm32h743bg", "dep:fdcan", "fdcan/fdcan_h7" ] 970stm32h743bg = [ "stm32-metapac/stm32h743bg" ]
966stm32h743bi = [ "stm32-metapac/stm32h743bi", "dep:fdcan", "fdcan/fdcan_h7" ] 971stm32h743bi = [ "stm32-metapac/stm32h743bi" ]
967stm32h743ig = [ "stm32-metapac/stm32h743ig", "dep:fdcan", "fdcan/fdcan_h7" ] 972stm32h743ig = [ "stm32-metapac/stm32h743ig" ]
968stm32h743ii = [ "stm32-metapac/stm32h743ii", "dep:fdcan", "fdcan/fdcan_h7" ] 973stm32h743ii = [ "stm32-metapac/stm32h743ii" ]
969stm32h743vg = [ "stm32-metapac/stm32h743vg", "dep:fdcan", "fdcan/fdcan_h7" ] 974stm32h743vg = [ "stm32-metapac/stm32h743vg" ]
970stm32h743vi = [ "stm32-metapac/stm32h743vi", "dep:fdcan", "fdcan/fdcan_h7" ] 975stm32h743vi = [ "stm32-metapac/stm32h743vi" ]
971stm32h743xg = [ "stm32-metapac/stm32h743xg", "dep:fdcan", "fdcan/fdcan_h7" ] 976stm32h743xg = [ "stm32-metapac/stm32h743xg" ]
972stm32h743xi = [ "stm32-metapac/stm32h743xi", "dep:fdcan", "fdcan/fdcan_h7" ] 977stm32h743xi = [ "stm32-metapac/stm32h743xi" ]
973stm32h743zg = [ "stm32-metapac/stm32h743zg", "dep:fdcan", "fdcan/fdcan_h7" ] 978stm32h743zg = [ "stm32-metapac/stm32h743zg" ]
974stm32h743zi = [ "stm32-metapac/stm32h743zi", "dep:fdcan", "fdcan/fdcan_h7" ] 979stm32h743zi = [ "stm32-metapac/stm32h743zi" ]
975stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 980stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ]
976stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 981stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ]
977stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 982stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ]
978stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 983stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ]
979stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 984stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ]
980stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 985stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ]
981stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 986stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ]
982stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 987stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ]
983stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 988stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ]
984stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 989stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ]
985stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 990stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ]
986stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 991stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ]
987stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 992stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ]
988stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 993stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ]
989stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 994stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ]
990stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 995stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ]
991stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 996stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ]
992stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 997stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ]
993stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 998stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ]
994stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 999stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ]
995stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1000stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ]
996stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1001stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ]
997stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1002stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ]
998stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1003stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ]
999stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1004stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ]
1000stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1005stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ]
1001stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1006stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ]
1002stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1007stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ]
1003stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1008stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ]
1004stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1009stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ]
1005stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1010stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ]
1006stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1011stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ]
1007stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1012stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ]
1008stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1013stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ]
1009stm32h750ib = [ "stm32-metapac/stm32h750ib", "dep:fdcan", "fdcan/fdcan_h7" ] 1014stm32h750ib = [ "stm32-metapac/stm32h750ib" ]
1010stm32h750vb = [ "stm32-metapac/stm32h750vb", "dep:fdcan", "fdcan/fdcan_h7" ] 1015stm32h750vb = [ "stm32-metapac/stm32h750vb" ]
1011stm32h750xb = [ "stm32-metapac/stm32h750xb", "dep:fdcan", "fdcan/fdcan_h7" ] 1016stm32h750xb = [ "stm32-metapac/stm32h750xb" ]
1012stm32h750zb = [ "stm32-metapac/stm32h750zb", "dep:fdcan", "fdcan/fdcan_h7" ] 1017stm32h750zb = [ "stm32-metapac/stm32h750zb" ]
1013stm32h753ai = [ "stm32-metapac/stm32h753ai", "dep:fdcan", "fdcan/fdcan_h7" ] 1018stm32h753ai = [ "stm32-metapac/stm32h753ai" ]
1014stm32h753bi = [ "stm32-metapac/stm32h753bi", "dep:fdcan", "fdcan/fdcan_h7" ] 1019stm32h753bi = [ "stm32-metapac/stm32h753bi" ]
1015stm32h753ii = [ "stm32-metapac/stm32h753ii", "dep:fdcan", "fdcan/fdcan_h7" ] 1020stm32h753ii = [ "stm32-metapac/stm32h753ii" ]
1016stm32h753vi = [ "stm32-metapac/stm32h753vi", "dep:fdcan", "fdcan/fdcan_h7" ] 1021stm32h753vi = [ "stm32-metapac/stm32h753vi" ]
1017stm32h753xi = [ "stm32-metapac/stm32h753xi", "dep:fdcan", "fdcan/fdcan_h7" ] 1022stm32h753xi = [ "stm32-metapac/stm32h753xi" ]
1018stm32h753zi = [ "stm32-metapac/stm32h753zi", "dep:fdcan", "fdcan/fdcan_h7" ] 1023stm32h753zi = [ "stm32-metapac/stm32h753zi" ]
1019stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1024stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ]
1020stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1025stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ]
1021stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1026stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ]
1022stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1027stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ]
1023stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1028stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ]
1024stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1029stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ]
1025stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1030stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ]
1026stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1031stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ]
1027stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1032stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ]
1028stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1033stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ]
1029stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1034stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ]
1030stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1035stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ]
1031stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1036stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ]
1032stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1037stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ]
1033stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1038stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ]
1034stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1039stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ]
1035stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] 1040stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ]
1036stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] 1041stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ]
1037stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag", "dep:fdcan", "fdcan/fdcan_h7" ] 1042stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ]
1038stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai", "dep:fdcan", "fdcan/fdcan_h7" ] 1043stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ]
1039stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig", "dep:fdcan", "fdcan/fdcan_h7" ] 1044stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ]
1040stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii", "dep:fdcan", "fdcan/fdcan_h7" ] 1045stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii" ]
1041stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg", "dep:fdcan", "fdcan/fdcan_h7" ] 1046stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg" ]
1042stm32h7a3li = [ "stm32-metapac/stm32h7a3li", "dep:fdcan", "fdcan/fdcan_h7" ] 1047stm32h7a3li = [ "stm32-metapac/stm32h7a3li" ]
1043stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng", "dep:fdcan", "fdcan/fdcan_h7" ] 1048stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng" ]
1044stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni", "dep:fdcan", "fdcan/fdcan_h7" ] 1049stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni" ]
1045stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi", "dep:fdcan", "fdcan/fdcan_h7" ] 1050stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi" ]
1046stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg", "dep:fdcan", "fdcan/fdcan_h7" ] 1051stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg" ]
1047stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri", "dep:fdcan", "fdcan/fdcan_h7" ] 1052stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri" ]
1048stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg", "dep:fdcan", "fdcan/fdcan_h7" ] 1053stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg" ]
1049stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi", "dep:fdcan", "fdcan/fdcan_h7" ] 1054stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi" ]
1050stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg", "dep:fdcan", "fdcan/fdcan_h7" ] 1055stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg" ]
1051stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi", "dep:fdcan", "fdcan/fdcan_h7" ] 1056stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi" ]
1052stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab", "dep:fdcan", "fdcan/fdcan_h7" ] 1057stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab" ]
1053stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib", "dep:fdcan", "fdcan/fdcan_h7" ] 1058stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib" ]
1054stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb", "dep:fdcan", "fdcan/fdcan_h7" ] 1059stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb" ]
1055stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb", "dep:fdcan", "fdcan/fdcan_h7" ] 1060stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb" ]
1056stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb", "dep:fdcan", "fdcan/fdcan_h7" ] 1061stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb" ]
1057stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai", "dep:fdcan", "fdcan/fdcan_h7" ] 1062stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai" ]
1058stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii", "dep:fdcan", "fdcan/fdcan_h7" ] 1063stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii" ]
1059stm32h7b3li = [ "stm32-metapac/stm32h7b3li", "dep:fdcan", "fdcan/fdcan_h7" ] 1064stm32h7b3li = [ "stm32-metapac/stm32h7b3li" ]
1060stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni", "dep:fdcan", "fdcan/fdcan_h7" ] 1065stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni" ]
1061stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi", "dep:fdcan", "fdcan/fdcan_h7" ] 1066stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ]
1062stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri", "dep:fdcan", "fdcan/fdcan_h7" ] 1067stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ]
1063stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi", "dep:fdcan", "fdcan/fdcan_h7" ] 1068stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ]
1064stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi", "dep:fdcan", "fdcan/fdcan_h7" ] 1069stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ]
1065stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] 1070stm32l010c6 = [ "stm32-metapac/stm32l010c6" ]
1066stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] 1071stm32l010f4 = [ "stm32-metapac/stm32l010f4" ]
1067stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] 1072stm32l010k4 = [ "stm32-metapac/stm32l010k4" ]
@@ -1388,86 +1393,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ]
1388stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] 1393stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ]
1389stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] 1394stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ]
1390stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] 1395stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ]
1391stm32l552cc = [ "stm32-metapac/stm32l552cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1396stm32l552cc = [ "stm32-metapac/stm32l552cc" ]
1392stm32l552ce = [ "stm32-metapac/stm32l552ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1397stm32l552ce = [ "stm32-metapac/stm32l552ce" ]
1393stm32l552me = [ "stm32-metapac/stm32l552me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1398stm32l552me = [ "stm32-metapac/stm32l552me" ]
1394stm32l552qc = [ "stm32-metapac/stm32l552qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1399stm32l552qc = [ "stm32-metapac/stm32l552qc" ]
1395stm32l552qe = [ "stm32-metapac/stm32l552qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1400stm32l552qe = [ "stm32-metapac/stm32l552qe" ]
1396stm32l552rc = [ "stm32-metapac/stm32l552rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1401stm32l552rc = [ "stm32-metapac/stm32l552rc" ]
1397stm32l552re = [ "stm32-metapac/stm32l552re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1402stm32l552re = [ "stm32-metapac/stm32l552re" ]
1398stm32l552vc = [ "stm32-metapac/stm32l552vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1403stm32l552vc = [ "stm32-metapac/stm32l552vc" ]
1399stm32l552ve = [ "stm32-metapac/stm32l552ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1404stm32l552ve = [ "stm32-metapac/stm32l552ve" ]
1400stm32l552zc = [ "stm32-metapac/stm32l552zc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1405stm32l552zc = [ "stm32-metapac/stm32l552zc" ]
1401stm32l552ze = [ "stm32-metapac/stm32l552ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1406stm32l552ze = [ "stm32-metapac/stm32l552ze" ]
1402stm32l562ce = [ "stm32-metapac/stm32l562ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1407stm32l562ce = [ "stm32-metapac/stm32l562ce" ]
1403stm32l562me = [ "stm32-metapac/stm32l562me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1408stm32l562me = [ "stm32-metapac/stm32l562me" ]
1404stm32l562qe = [ "stm32-metapac/stm32l562qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1409stm32l562qe = [ "stm32-metapac/stm32l562qe" ]
1405stm32l562re = [ "stm32-metapac/stm32l562re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1410stm32l562re = [ "stm32-metapac/stm32l562re" ]
1406stm32l562ve = [ "stm32-metapac/stm32l562ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1411stm32l562ve = [ "stm32-metapac/stm32l562ve" ]
1407stm32l562ze = [ "stm32-metapac/stm32l562ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1412stm32l562ze = [ "stm32-metapac/stm32l562ze" ]
1408stm32u535cb = [ "stm32-metapac/stm32u535cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1413stm32u535cb = [ "stm32-metapac/stm32u535cb" ]
1409stm32u535cc = [ "stm32-metapac/stm32u535cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1414stm32u535cc = [ "stm32-metapac/stm32u535cc" ]
1410stm32u535ce = [ "stm32-metapac/stm32u535ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1415stm32u535ce = [ "stm32-metapac/stm32u535ce" ]
1411stm32u535je = [ "stm32-metapac/stm32u535je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1416stm32u535je = [ "stm32-metapac/stm32u535je" ]
1412stm32u535nc = [ "stm32-metapac/stm32u535nc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1417stm32u535nc = [ "stm32-metapac/stm32u535nc" ]
1413stm32u535ne = [ "stm32-metapac/stm32u535ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1418stm32u535ne = [ "stm32-metapac/stm32u535ne" ]
1414stm32u535rb = [ "stm32-metapac/stm32u535rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1419stm32u535rb = [ "stm32-metapac/stm32u535rb" ]
1415stm32u535rc = [ "stm32-metapac/stm32u535rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1420stm32u535rc = [ "stm32-metapac/stm32u535rc" ]
1416stm32u535re = [ "stm32-metapac/stm32u535re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1421stm32u535re = [ "stm32-metapac/stm32u535re" ]
1417stm32u535vc = [ "stm32-metapac/stm32u535vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1422stm32u535vc = [ "stm32-metapac/stm32u535vc" ]
1418stm32u535ve = [ "stm32-metapac/stm32u535ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1423stm32u535ve = [ "stm32-metapac/stm32u535ve" ]
1419stm32u545ce = [ "stm32-metapac/stm32u545ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1424stm32u545ce = [ "stm32-metapac/stm32u545ce" ]
1420stm32u545je = [ "stm32-metapac/stm32u545je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1425stm32u545je = [ "stm32-metapac/stm32u545je" ]
1421stm32u545ne = [ "stm32-metapac/stm32u545ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1426stm32u545ne = [ "stm32-metapac/stm32u545ne" ]
1422stm32u545re = [ "stm32-metapac/stm32u545re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1427stm32u545re = [ "stm32-metapac/stm32u545re" ]
1423stm32u545ve = [ "stm32-metapac/stm32u545ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1428stm32u545ve = [ "stm32-metapac/stm32u545ve" ]
1424stm32u575ag = [ "stm32-metapac/stm32u575ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1429stm32u575ag = [ "stm32-metapac/stm32u575ag" ]
1425stm32u575ai = [ "stm32-metapac/stm32u575ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1430stm32u575ai = [ "stm32-metapac/stm32u575ai" ]
1426stm32u575cg = [ "stm32-metapac/stm32u575cg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1431stm32u575cg = [ "stm32-metapac/stm32u575cg" ]
1427stm32u575ci = [ "stm32-metapac/stm32u575ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1432stm32u575ci = [ "stm32-metapac/stm32u575ci" ]
1428stm32u575og = [ "stm32-metapac/stm32u575og", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1433stm32u575og = [ "stm32-metapac/stm32u575og" ]
1429stm32u575oi = [ "stm32-metapac/stm32u575oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1434stm32u575oi = [ "stm32-metapac/stm32u575oi" ]
1430stm32u575qg = [ "stm32-metapac/stm32u575qg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1435stm32u575qg = [ "stm32-metapac/stm32u575qg" ]
1431stm32u575qi = [ "stm32-metapac/stm32u575qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1436stm32u575qi = [ "stm32-metapac/stm32u575qi" ]
1432stm32u575rg = [ "stm32-metapac/stm32u575rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1437stm32u575rg = [ "stm32-metapac/stm32u575rg" ]
1433stm32u575ri = [ "stm32-metapac/stm32u575ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1438stm32u575ri = [ "stm32-metapac/stm32u575ri" ]
1434stm32u575vg = [ "stm32-metapac/stm32u575vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1439stm32u575vg = [ "stm32-metapac/stm32u575vg" ]
1435stm32u575vi = [ "stm32-metapac/stm32u575vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1440stm32u575vi = [ "stm32-metapac/stm32u575vi" ]
1436stm32u575zg = [ "stm32-metapac/stm32u575zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1441stm32u575zg = [ "stm32-metapac/stm32u575zg" ]
1437stm32u575zi = [ "stm32-metapac/stm32u575zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1442stm32u575zi = [ "stm32-metapac/stm32u575zi" ]
1438stm32u585ai = [ "stm32-metapac/stm32u585ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1443stm32u585ai = [ "stm32-metapac/stm32u585ai" ]
1439stm32u585ci = [ "stm32-metapac/stm32u585ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1444stm32u585ci = [ "stm32-metapac/stm32u585ci" ]
1440stm32u585oi = [ "stm32-metapac/stm32u585oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1445stm32u585oi = [ "stm32-metapac/stm32u585oi" ]
1441stm32u585qi = [ "stm32-metapac/stm32u585qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1446stm32u585qi = [ "stm32-metapac/stm32u585qi" ]
1442stm32u585ri = [ "stm32-metapac/stm32u585ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1447stm32u585ri = [ "stm32-metapac/stm32u585ri" ]
1443stm32u585vi = [ "stm32-metapac/stm32u585vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1448stm32u585vi = [ "stm32-metapac/stm32u585vi" ]
1444stm32u585zi = [ "stm32-metapac/stm32u585zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1449stm32u585zi = [ "stm32-metapac/stm32u585zi" ]
1445stm32u595ai = [ "stm32-metapac/stm32u595ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1450stm32u595ai = [ "stm32-metapac/stm32u595ai" ]
1446stm32u595aj = [ "stm32-metapac/stm32u595aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1451stm32u595aj = [ "stm32-metapac/stm32u595aj" ]
1447stm32u595qi = [ "stm32-metapac/stm32u595qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1452stm32u595qi = [ "stm32-metapac/stm32u595qi" ]
1448stm32u595qj = [ "stm32-metapac/stm32u595qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1453stm32u595qj = [ "stm32-metapac/stm32u595qj" ]
1449stm32u595ri = [ "stm32-metapac/stm32u595ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1454stm32u595ri = [ "stm32-metapac/stm32u595ri" ]
1450stm32u595rj = [ "stm32-metapac/stm32u595rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1455stm32u595rj = [ "stm32-metapac/stm32u595rj" ]
1451stm32u595vi = [ "stm32-metapac/stm32u595vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1456stm32u595vi = [ "stm32-metapac/stm32u595vi" ]
1452stm32u595vj = [ "stm32-metapac/stm32u595vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1457stm32u595vj = [ "stm32-metapac/stm32u595vj" ]
1453stm32u595zi = [ "stm32-metapac/stm32u595zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1458stm32u595zi = [ "stm32-metapac/stm32u595zi" ]
1454stm32u595zj = [ "stm32-metapac/stm32u595zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1459stm32u595zj = [ "stm32-metapac/stm32u595zj" ]
1455stm32u599bj = [ "stm32-metapac/stm32u599bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1460stm32u599bj = [ "stm32-metapac/stm32u599bj" ]
1456stm32u599ni = [ "stm32-metapac/stm32u599ni", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1461stm32u599ni = [ "stm32-metapac/stm32u599ni" ]
1457stm32u599nj = [ "stm32-metapac/stm32u599nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1462stm32u599nj = [ "stm32-metapac/stm32u599nj" ]
1458stm32u599vi = [ "stm32-metapac/stm32u599vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1463stm32u599vi = [ "stm32-metapac/stm32u599vi" ]
1459stm32u599vj = [ "stm32-metapac/stm32u599vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1464stm32u599vj = [ "stm32-metapac/stm32u599vj" ]
1460stm32u599zi = [ "stm32-metapac/stm32u599zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1465stm32u599zi = [ "stm32-metapac/stm32u599zi" ]
1461stm32u599zj = [ "stm32-metapac/stm32u599zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1466stm32u599zj = [ "stm32-metapac/stm32u599zj" ]
1462stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1467stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ]
1463stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1468stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ]
1464stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1469stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ]
1465stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1470stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ]
1466stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1471stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ]
1467stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1472stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ]
1468stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1473stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ]
1469stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1474stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ]
1470stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] 1475stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ]
1471stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] 1476stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ]
1472stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] 1477stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ]
1473stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] 1478stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ]
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs
index 36139a45c..135010011 100644
--- a/embassy-stm32/src/can/enums.rs
+++ b/embassy-stm32/src/can/enums.rs
@@ -1,4 +1,5 @@
1//! Enums shared between CAN controller types. 1//! Enums shared between CAN controller types.
2use core::convert::TryFrom;
2 3
3/// Bus error 4/// Bus error
4#[derive(Debug)] 5#[derive(Debug)]
@@ -28,3 +29,19 @@ pub enum BusError {
28 /// At least one of error counter has reached the Error_Warning limit of 96. 29 /// At least one of error counter has reached the Error_Warning limit of 96.
29 BusWarning, 30 BusWarning,
30} 31}
32impl TryFrom<u8> for BusError {
33 type Error = ();
34 fn try_from(value: u8) -> Result<Self, Self::Error> {
35 match value {
36 //0b000 => None,
37 0b001 => Ok(Self::Stuff),
38 0b010 => Ok(Self::Form),
39 0b011 => Ok(Self::Acknowledge),
40 0b100 => Ok(Self::BitRecessive),
41 0b101 => Ok(Self::BitDominant),
42 0b110 => Ok(Self::Crc),
43 //0b111 => Ok(Self::NoError),
44 _ => Err(()),
45 }
46 }
47}
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
new file mode 100644
index 000000000..38b409121
--- /dev/null
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -0,0 +1,438 @@
1//! Configuration for FDCAN Module
2//! Note: This file is copied and modified from fdcan crate by Richard Meadows
3
4use core::num::{NonZeroU16, NonZeroU8};
5
6/// Configures the bit timings.
7///
8/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
9/// parameters as follows:
10///
11/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
12/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
13/// - *Sample Point*: Should normally be left at the default value of 87.5%.
14/// - *SJW*: Should normally be left at the default value of 1.
15///
16/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
17/// parameter to this method.
18#[derive(Clone, Copy, Debug)]
19pub struct NominalBitTiming {
20 /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit
21 /// time is built up from a multiple of this quanta. Valid values are 1 to 512.
22 pub prescaler: NonZeroU16,
23 /// Valid values are 1 to 128.
24 pub seg1: NonZeroU8,
25 /// Valid values are 1 to 255.
26 pub seg2: NonZeroU8,
27 /// Valid values are 1 to 128.
28 pub sync_jump_width: NonZeroU8,
29}
30impl NominalBitTiming {
31 #[inline]
32 pub(crate) fn nbrp(&self) -> u16 {
33 u16::from(self.prescaler) & 0x1FF
34 }
35 #[inline]
36 pub(crate) fn ntseg1(&self) -> u8 {
37 u8::from(self.seg1)
38 }
39 #[inline]
40 pub(crate) fn ntseg2(&self) -> u8 {
41 u8::from(self.seg2) & 0x7F
42 }
43 #[inline]
44 pub(crate) fn nsjw(&self) -> u8 {
45 u8::from(self.sync_jump_width) & 0x7F
46 }
47}
48
49impl Default for NominalBitTiming {
50 #[inline]
51 fn default() -> Self {
52 // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a NBTP
53 // register value of 0x0600_0A03
54 Self {
55 prescaler: NonZeroU16::new(1).unwrap(),
56 seg1: NonZeroU8::new(11).unwrap(),
57 seg2: NonZeroU8::new(4).unwrap(),
58 sync_jump_width: NonZeroU8::new(4).unwrap(),
59 }
60 }
61}
62
63/// Configures the data bit timings for the FdCan Variable Bitrates.
64/// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
65#[derive(Clone, Copy, Debug)]
66pub struct DataBitTiming {
67 /// Tranceiver Delay Compensation
68 pub transceiver_delay_compensation: bool,
69 /// The value by which the oscillator frequency is divided to generate the bit time quanta. The bit
70 /// time is built up from a multiple of this quanta. Valid values for the Baud Rate Prescaler are 1
71 /// to 31.
72 pub prescaler: NonZeroU16,
73 /// Valid values are 1 to 31.
74 pub seg1: NonZeroU8,
75 /// Valid values are 1 to 15.
76 pub seg2: NonZeroU8,
77 /// Must always be smaller than DTSEG2, valid values are 1 to 15.
78 pub sync_jump_width: NonZeroU8,
79}
80impl DataBitTiming {
81 // #[inline]
82 // fn tdc(&self) -> u8 {
83 // let tsd = self.transceiver_delay_compensation as u8;
84 // //TODO: stm32g4 does not export the TDC field
85 // todo!()
86 // }
87 #[inline]
88 pub(crate) fn dbrp(&self) -> u8 {
89 (u16::from(self.prescaler) & 0x001F) as u8
90 }
91 #[inline]
92 pub(crate) fn dtseg1(&self) -> u8 {
93 u8::from(self.seg1) & 0x1F
94 }
95 #[inline]
96 pub(crate) fn dtseg2(&self) -> u8 {
97 u8::from(self.seg2) & 0x0F
98 }
99 #[inline]
100 pub(crate) fn dsjw(&self) -> u8 {
101 u8::from(self.sync_jump_width) & 0x0F
102 }
103}
104
105impl Default for DataBitTiming {
106 #[inline]
107 fn default() -> Self {
108 // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a DBTP
109 // register value of 0x0000_0A33
110 Self {
111 transceiver_delay_compensation: false,
112 prescaler: NonZeroU16::new(1).unwrap(),
113 seg1: NonZeroU8::new(11).unwrap(),
114 seg2: NonZeroU8::new(4).unwrap(),
115 sync_jump_width: NonZeroU8::new(4).unwrap(),
116 }
117 }
118}
119
120/// Configures which modes to use
121/// Individual headers can contain a desire to be send via FdCan
122/// or use Bit rate switching. But if this general setting does not allow
123/// that, only classic CAN is used instead.
124#[derive(Clone, Copy, Debug)]
125pub enum FrameTransmissionConfig {
126 /// Only allow Classic CAN message Frames
127 ClassicCanOnly,
128 /// Allow (non-brs) FdCAN Message Frames
129 AllowFdCan,
130 /// Allow FdCAN Message Frames and allow Bit Rate Switching
131 AllowFdCanAndBRS,
132}
133
134///
135#[derive(Clone, Copy, Debug)]
136pub enum ClockDivider {
137 /// Divide by 1
138 _1 = 0b0000,
139 /// Divide by 2
140 _2 = 0b0001,
141 /// Divide by 4
142 _4 = 0b0010,
143 /// Divide by 6
144 _6 = 0b0011,
145 /// Divide by 8
146 _8 = 0b0100,
147 /// Divide by 10
148 _10 = 0b0101,
149 /// Divide by 12
150 _12 = 0b0110,
151 /// Divide by 14
152 _14 = 0b0111,
153 /// Divide by 16
154 _16 = 0b1000,
155 /// Divide by 18
156 _18 = 0b1001,
157 /// Divide by 20
158 _20 = 0b1010,
159 /// Divide by 22
160 _22 = 0b1011,
161 /// Divide by 24
162 _24 = 0b1100,
163 /// Divide by 26
164 _26 = 0b1101,
165 /// Divide by 28
166 _28 = 0b1110,
167 /// Divide by 30
168 _30 = 0b1111,
169}
170
171/// Prescaler of the Timestamp counter
172#[derive(Clone, Copy, Debug)]
173pub enum TimestampPrescaler {
174 /// 1
175 _1 = 1,
176 /// 2
177 _2 = 2,
178 /// 3
179 _3 = 3,
180 /// 4
181 _4 = 4,
182 /// 5
183 _5 = 5,
184 /// 6
185 _6 = 6,
186 /// 7
187 _7 = 7,
188 /// 8
189 _8 = 8,
190 /// 9
191 _9 = 9,
192 /// 10
193 _10 = 10,
194 /// 11
195 _11 = 11,
196 /// 12
197 _12 = 12,
198 /// 13
199 _13 = 13,
200 /// 14
201 _14 = 14,
202 /// 15
203 _15 = 15,
204 /// 16
205 _16 = 16,
206}
207
208/// Selects the source of the Timestamp counter
209#[derive(Clone, Copy, Debug)]
210pub enum TimestampSource {
211 /// The Timestamp counter is disabled
212 None,
213 /// Using the FdCan input clock as the Timstamp counter's source,
214 /// and using a specific prescaler
215 Prescaler(TimestampPrescaler),
216 /// Using TIM3 as a source
217 FromTIM3,
218}
219
220/// How to handle frames in the global filter
221#[derive(Clone, Copy, Debug)]
222pub enum NonMatchingFilter {
223 /// Frames will go to Fifo0 when they do no match any specific filter
224 IntoRxFifo0 = 0b00,
225 /// Frames will go to Fifo1 when they do no match any specific filter
226 IntoRxFifo1 = 0b01,
227 /// Frames will be rejected when they do not match any specific filter
228 Reject = 0b11,
229}
230
231/// How to handle frames which do not match a specific filter
232#[derive(Clone, Copy, Debug)]
233pub struct GlobalFilter {
234 /// How to handle non-matching standard frames
235 pub handle_standard_frames: NonMatchingFilter,
236
237 /// How to handle non-matching extended frames
238 pub handle_extended_frames: NonMatchingFilter,
239
240 /// How to handle remote standard frames
241 pub reject_remote_standard_frames: bool,
242
243 /// How to handle remote extended frames
244 pub reject_remote_extended_frames: bool,
245}
246impl GlobalFilter {
247 /// Reject all non-matching and remote frames
248 pub const fn reject_all() -> Self {
249 Self {
250 handle_standard_frames: NonMatchingFilter::Reject,
251 handle_extended_frames: NonMatchingFilter::Reject,
252 reject_remote_standard_frames: true,
253 reject_remote_extended_frames: true,
254 }
255 }
256
257 /// How to handle non-matching standard frames
258 pub const fn set_handle_standard_frames(mut self, filter: NonMatchingFilter) -> Self {
259 self.handle_standard_frames = filter;
260 self
261 }
262 /// How to handle non-matching exteded frames
263 pub const fn set_handle_extended_frames(mut self, filter: NonMatchingFilter) -> Self {
264 self.handle_extended_frames = filter;
265 self
266 }
267 /// How to handle remote standard frames
268 pub const fn set_reject_remote_standard_frames(mut self, filter: bool) -> Self {
269 self.reject_remote_standard_frames = filter;
270 self
271 }
272 /// How to handle remote extended frames
273 pub const fn set_reject_remote_extended_frames(mut self, filter: bool) -> Self {
274 self.reject_remote_extended_frames = filter;
275 self
276 }
277}
278impl Default for GlobalFilter {
279 #[inline]
280 fn default() -> Self {
281 Self {
282 handle_standard_frames: NonMatchingFilter::IntoRxFifo0,
283 handle_extended_frames: NonMatchingFilter::IntoRxFifo0,
284 reject_remote_standard_frames: false,
285 reject_remote_extended_frames: false,
286 }
287 }
288}
289
290/// FdCan Config Struct
291#[derive(Clone, Copy, Debug)]
292pub struct FdCanConfig {
293 /// Nominal Bit Timings
294 pub nbtr: NominalBitTiming,
295 /// (Variable) Data Bit Timings
296 pub dbtr: DataBitTiming,
297 /// Enables or disables automatic retransmission of messages
298 ///
299 /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
300 /// util it can be sent. Otherwise, it will try only once to send each frame.
301 ///
302 /// Automatic retransmission is enabled by default.
303 pub automatic_retransmit: bool,
304 /// Enabled or disables the pausing between transmissions
305 ///
306 /// This feature looses up burst transmissions coming from a single node and it protects against
307 /// "babbling idiot" scenarios where the application program erroneously requests too many
308 /// transmissions.
309 pub transmit_pause: bool,
310 /// Enabled or disables the pausing between transmissions
311 ///
312 /// This feature looses up burst transmissions coming from a single node and it protects against
313 /// "babbling idiot" scenarios where the application program erroneously requests too many
314 /// transmissions.
315 pub frame_transmit: FrameTransmissionConfig,
316 /// Non Isoe Mode
317 /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
318 /// FD Specification V1.0.
319 pub non_iso_mode: bool,
320 /// Edge Filtering: Two consecutive dominant tq required to detect an edge for hard synchronization
321 pub edge_filtering: bool,
322 /// Enables protocol exception handling
323 pub protocol_exception_handling: bool,
324 /// Sets the general clock divider for this FdCAN instance
325 pub clock_divider: ClockDivider,
326 /// Sets the timestamp source
327 pub timestamp_source: TimestampSource,
328 /// Configures the Global Filter
329 pub global_filter: GlobalFilter,
330}
331
332impl FdCanConfig {
333 /// Configures the bit timings.
334 #[inline]
335 pub const fn set_nominal_bit_timing(mut self, btr: NominalBitTiming) -> Self {
336 self.nbtr = btr;
337 self
338 }
339
340 /// Configures the bit timings.
341 #[inline]
342 pub const fn set_data_bit_timing(mut self, btr: DataBitTiming) -> Self {
343 self.dbtr = btr;
344 self
345 }
346
347 /// Enables or disables automatic retransmission of messages
348 ///
349 /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
350 /// util it can be sent. Otherwise, it will try only once to send each frame.
351 ///
352 /// Automatic retransmission is enabled by default.
353 #[inline]
354 pub const fn set_automatic_retransmit(mut self, enabled: bool) -> Self {
355 self.automatic_retransmit = enabled;
356 self
357 }
358
359 /// Enabled or disables the pausing between transmissions
360 ///
361 /// This feature looses up burst transmissions coming from a single node and it protects against
362 /// "babbling idiot" scenarios where the application program erroneously requests too many
363 /// transmissions.
364 #[inline]
365 pub const fn set_transmit_pause(mut self, enabled: bool) -> Self {
366 self.transmit_pause = enabled;
367 self
368 }
369
370 /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
371 /// FD Specification V1.0.
372 #[inline]
373 pub const fn set_non_iso_mode(mut self, enabled: bool) -> Self {
374 self.non_iso_mode = enabled;
375 self
376 }
377
378 /// Two consecutive dominant tq required to detect an edge for hard synchronization
379 #[inline]
380 pub const fn set_edge_filtering(mut self, enabled: bool) -> Self {
381 self.edge_filtering = enabled;
382 self
383 }
384
385 /// Sets the allowed transmission types for messages.
386 #[inline]
387 pub const fn set_frame_transmit(mut self, fts: FrameTransmissionConfig) -> Self {
388 self.frame_transmit = fts;
389 self
390 }
391
392 /// Enables protocol exception handling
393 #[inline]
394 pub const fn set_protocol_exception_handling(mut self, peh: bool) -> Self {
395 self.protocol_exception_handling = peh;
396 self
397 }
398
399 /// Sets the general clock divider for this FdCAN instance
400 #[inline]
401 pub const fn set_clock_divider(mut self, div: ClockDivider) -> Self {
402 self.clock_divider = div;
403 self
404 }
405
406 /// Sets the timestamp source
407 #[inline]
408 pub const fn set_timestamp_source(mut self, tss: TimestampSource) -> Self {
409 self.timestamp_source = tss;
410 self
411 }
412
413 /// Sets the global filter settings
414 #[inline]
415 pub const fn set_global_filter(mut self, filter: GlobalFilter) -> Self {
416 self.global_filter = filter;
417 self
418 }
419}
420
421impl Default for FdCanConfig {
422 #[inline]
423 fn default() -> Self {
424 Self {
425 nbtr: NominalBitTiming::default(),
426 dbtr: DataBitTiming::default(),
427 automatic_retransmit: true,
428 transmit_pause: false,
429 frame_transmit: FrameTransmissionConfig::ClassicCanOnly,
430 non_iso_mode: false,
431 edge_filtering: false,
432 protocol_exception_handling: true,
433 clock_divider: ClockDivider::_1,
434 timestamp_source: TimestampSource::None,
435 global_filter: GlobalFilter::default(),
436 }
437 }
438}
diff --git a/embassy-stm32/src/can/fd/filter.rs b/embassy-stm32/src/can/fd/filter.rs
new file mode 100644
index 000000000..3e2129e6e
--- /dev/null
+++ b/embassy-stm32/src/can/fd/filter.rs
@@ -0,0 +1,379 @@
1//! Definition of Filter structs for FDCAN Module
2//! Note: This file is copied and modified from fdcan crate by Richard Meadows
3
4use embedded_can::{ExtendedId, StandardId};
5
6use crate::can::fd::message_ram;
7pub use crate::can::fd::message_ram::{EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX};
8
9/// A Standard Filter
10pub type StandardFilter = Filter<StandardId, u16>;
11/// An Extended Filter
12pub type ExtendedFilter = Filter<ExtendedId, u32>;
13
14impl Default for StandardFilter {
15 fn default() -> Self {
16 StandardFilter::disable()
17 }
18}
19impl Default for ExtendedFilter {
20 fn default() -> Self {
21 ExtendedFilter::disable()
22 }
23}
24
25impl StandardFilter {
26 /// Accept all messages in FIFO 0
27 pub fn accept_all_into_fifo0() -> StandardFilter {
28 StandardFilter {
29 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
30 action: Action::StoreInFifo0,
31 }
32 }
33
34 /// Accept all messages in FIFO 1
35 pub fn accept_all_into_fifo1() -> StandardFilter {
36 StandardFilter {
37 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
38 action: Action::StoreInFifo1,
39 }
40 }
41
42 /// Reject all messages
43 pub fn reject_all() -> StandardFilter {
44 StandardFilter {
45 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
46 action: Action::Reject,
47 }
48 }
49
50 /// Disable the filter
51 pub fn disable() -> StandardFilter {
52 StandardFilter {
53 filter: FilterType::Disabled,
54 action: Action::Disable,
55 }
56 }
57}
58
59impl ExtendedFilter {
60 /// Accept all messages in FIFO 0
61 pub fn accept_all_into_fifo0() -> ExtendedFilter {
62 ExtendedFilter {
63 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
64 action: Action::StoreInFifo0,
65 }
66 }
67
68 /// Accept all messages in FIFO 1
69 pub fn accept_all_into_fifo1() -> ExtendedFilter {
70 ExtendedFilter {
71 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
72 action: Action::StoreInFifo1,
73 }
74 }
75
76 /// Reject all messages
77 pub fn reject_all() -> ExtendedFilter {
78 ExtendedFilter {
79 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
80 action: Action::Reject,
81 }
82 }
83
84 /// Disable the filter
85 pub fn disable() -> ExtendedFilter {
86 ExtendedFilter {
87 filter: FilterType::Disabled,
88 action: Action::Disable,
89 }
90 }
91}
92
93/// Filter Type
94#[derive(Clone, Copy, Debug)]
95pub enum FilterType<ID, UNIT>
96where
97 ID: Copy + Clone + core::fmt::Debug,
98 UNIT: Copy + Clone + core::fmt::Debug,
99{
100 /// Match with a range between two messages
101 Range {
102 /// First Id of the range
103 from: ID,
104 /// Last Id of the range
105 to: ID,
106 },
107 /// Match with a bitmask
108 BitMask {
109 /// Filter of the bitmask
110 filter: UNIT,
111 /// Mask of the bitmask
112 mask: UNIT,
113 },
114 /// Match with a single ID
115 DedicatedSingle(ID),
116 /// Match with one of two ID's
117 DedicatedDual(ID, ID),
118 /// Filter is disabled
119 Disabled,
120}
121impl<ID, UNIT> From<FilterType<ID, UNIT>> for message_ram::enums::FilterType
122where
123 ID: Copy + Clone + core::fmt::Debug,
124 UNIT: Copy + Clone + core::fmt::Debug,
125{
126 fn from(f: FilterType<ID, UNIT>) -> Self {
127 match f {
128 FilterType::Range { to: _, from: _ } => Self::RangeFilter,
129 FilterType::BitMask { filter: _, mask: _ } => Self::ClassicFilter,
130 FilterType::DedicatedSingle(_) => Self::DualIdFilter,
131 FilterType::DedicatedDual(_, _) => Self::DualIdFilter,
132 FilterType::Disabled => Self::FilterDisabled,
133 }
134 }
135}
136
137/// Filter Action
138#[derive(Clone, Copy, Debug)]
139pub enum Action {
140 /// No Action
141 Disable = 0b000,
142 /// Store an matching message in FIFO 0
143 StoreInFifo0 = 0b001,
144 /// Store an matching message in FIFO 1
145 StoreInFifo1 = 0b010,
146 /// Reject an matching message
147 Reject = 0b011,
148 /// Flag a matching message (But not store?!?)
149 FlagHighPrio = 0b100,
150 /// Flag a matching message as a High Priority message and store it in FIFO 0
151 FlagHighPrioAndStoreInFifo0 = 0b101,
152 /// Flag a matching message as a High Priority message and store it in FIFO 1
153 FlagHighPrioAndStoreInFifo1 = 0b110,
154}
155impl From<Action> for message_ram::enums::FilterElementConfig {
156 fn from(a: Action) -> Self {
157 match a {
158 Action::Disable => Self::DisableFilterElement,
159 Action::StoreInFifo0 => Self::StoreInFifo0,
160 Action::StoreInFifo1 => Self::StoreInFifo1,
161 Action::Reject => Self::Reject,
162 Action::FlagHighPrio => Self::SetPriority,
163 Action::FlagHighPrioAndStoreInFifo0 => Self::SetPriorityAndStoreInFifo0,
164 Action::FlagHighPrioAndStoreInFifo1 => Self::SetPriorityAndStoreInFifo1,
165 }
166 }
167}
168
169/// Filter
170#[derive(Clone, Copy, Debug)]
171pub struct Filter<ID, UNIT>
172where
173 ID: Copy + Clone + core::fmt::Debug,
174 UNIT: Copy + Clone + core::fmt::Debug,
175{
176 /// How to match an incoming message
177 pub filter: FilterType<ID, UNIT>,
178 /// What to do with a matching message
179 pub action: Action,
180}
181
182/// Standard Filter Slot
183#[derive(Debug, Copy, Clone, Eq, PartialEq)]
184pub enum StandardFilterSlot {
185 /// 0
186 _0 = 0,
187 /// 1
188 _1 = 1,
189 /// 2
190 _2 = 2,
191 /// 3
192 _3 = 3,
193 /// 4
194 _4 = 4,
195 /// 5
196 _5 = 5,
197 /// 6
198 _6 = 6,
199 /// 7
200 _7 = 7,
201 /// 8
202 _8 = 8,
203 /// 9
204 _9 = 9,
205 /// 10
206 _10 = 10,
207 /// 11
208 _11 = 11,
209 /// 12
210 _12 = 12,
211 /// 13
212 _13 = 13,
213 /// 14
214 _14 = 14,
215 /// 15
216 _15 = 15,
217 /// 16
218 _16 = 16,
219 /// 17
220 _17 = 17,
221 /// 18
222 _18 = 18,
223 /// 19
224 _19 = 19,
225 /// 20
226 _20 = 20,
227 /// 21
228 _21 = 21,
229 /// 22
230 _22 = 22,
231 /// 23
232 _23 = 23,
233 /// 24
234 _24 = 24,
235 /// 25
236 _25 = 25,
237 /// 26
238 _26 = 26,
239 /// 27
240 _27 = 27,
241}
242impl From<u8> for StandardFilterSlot {
243 fn from(u: u8) -> Self {
244 match u {
245 0 => StandardFilterSlot::_0,
246 1 => StandardFilterSlot::_1,
247 2 => StandardFilterSlot::_2,
248 3 => StandardFilterSlot::_3,
249 4 => StandardFilterSlot::_4,
250 5 => StandardFilterSlot::_5,
251 6 => StandardFilterSlot::_6,
252 7 => StandardFilterSlot::_7,
253 8 => StandardFilterSlot::_8,
254 9 => StandardFilterSlot::_9,
255 10 => StandardFilterSlot::_10,
256 11 => StandardFilterSlot::_11,
257 12 => StandardFilterSlot::_12,
258 13 => StandardFilterSlot::_13,
259 14 => StandardFilterSlot::_14,
260 15 => StandardFilterSlot::_15,
261 16 => StandardFilterSlot::_16,
262 17 => StandardFilterSlot::_17,
263 18 => StandardFilterSlot::_18,
264 19 => StandardFilterSlot::_19,
265 20 => StandardFilterSlot::_20,
266 21 => StandardFilterSlot::_21,
267 22 => StandardFilterSlot::_22,
268 23 => StandardFilterSlot::_23,
269 24 => StandardFilterSlot::_24,
270 25 => StandardFilterSlot::_25,
271 26 => StandardFilterSlot::_26,
272 27 => StandardFilterSlot::_27,
273 _ => panic!("Standard Filter Slot Too High!"),
274 }
275 }
276}
277
278/// Extended Filter Slot
279#[derive(Debug, Copy, Clone, Eq, PartialEq)]
280pub enum ExtendedFilterSlot {
281 /// 0
282 _0 = 0,
283 /// 1
284 _1 = 1,
285 /// 2
286 _2 = 2,
287 /// 3
288 _3 = 3,
289 /// 4
290 _4 = 4,
291 /// 5
292 _5 = 5,
293 /// 6
294 _6 = 6,
295 /// 7
296 _7 = 7,
297}
298impl From<u8> for ExtendedFilterSlot {
299 fn from(u: u8) -> Self {
300 match u {
301 0 => ExtendedFilterSlot::_0,
302 1 => ExtendedFilterSlot::_1,
303 2 => ExtendedFilterSlot::_2,
304 3 => ExtendedFilterSlot::_3,
305 4 => ExtendedFilterSlot::_4,
306 5 => ExtendedFilterSlot::_5,
307 6 => ExtendedFilterSlot::_6,
308 7 => ExtendedFilterSlot::_7,
309 _ => panic!("Extended Filter Slot Too High!"), // Should be unreachable
310 }
311 }
312}
313
314/// Enum over both Standard and Extended Filter ID's
315#[derive(Debug, Copy, Clone, Eq, PartialEq)]
316pub enum FilterId {
317 /// Standard Filter Slots
318 Standard(StandardFilterSlot),
319 /// Extended Filter Slots
320 Extended(ExtendedFilterSlot),
321}
322
323pub(crate) trait ActivateFilter<ID, UNIT>
324where
325 ID: Copy + Clone + core::fmt::Debug,
326 UNIT: Copy + Clone + core::fmt::Debug,
327{
328 fn activate(&mut self, f: Filter<ID, UNIT>);
329 // fn read(&self) -> Filter<ID, UNIT>;
330}
331
332impl ActivateFilter<StandardId, u16> for message_ram::StandardFilter {
333 fn activate(&mut self, f: Filter<StandardId, u16>) {
334 let sft = f.filter.into();
335
336 let (sfid1, sfid2) = match f.filter {
337 FilterType::Range { to, from } => (to.as_raw(), from.as_raw()),
338 FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()),
339 FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()),
340 FilterType::BitMask { filter, mask } => (filter, mask),
341 FilterType::Disabled => (0x0, 0x0),
342 };
343 let sfec = f.action.into();
344 self.write(|w| {
345 unsafe { w.sfid1().bits(sfid1).sfid2().bits(sfid2) }
346 .sft()
347 .set_filter_type(sft)
348 .sfec()
349 .set_filter_element_config(sfec)
350 });
351 }
352 // fn read(&self) -> Filter<StandardId, u16> {
353 // todo!()
354 // }
355}
356impl ActivateFilter<ExtendedId, u32> for message_ram::ExtendedFilter {
357 fn activate(&mut self, f: Filter<ExtendedId, u32>) {
358 let eft = f.filter.into();
359
360 let (efid1, efid2) = match f.filter {
361 FilterType::Range { to, from } => (to.as_raw(), from.as_raw()),
362 FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()),
363 FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()),
364 FilterType::BitMask { filter, mask } => (filter, mask),
365 FilterType::Disabled => (0x0, 0x0),
366 };
367 let efec = f.action.into();
368 self.write(|w| {
369 unsafe { w.efid1().bits(efid1).efid2().bits(efid2) }
370 .eft()
371 .set_filter_type(eft)
372 .efec()
373 .set_filter_element_config(efec)
374 });
375 }
376 // fn read(&self) -> Filter<ExtendedId, u32> {
377 // todo!()
378 // }
379}
diff --git a/embassy-stm32/src/can/fd/message_ram/common.rs b/embassy-stm32/src/can/fd/message_ram/common.rs
new file mode 100644
index 000000000..a67d68fa0
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/common.rs
@@ -0,0 +1,134 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#![allow(unused)]
5
6use super::enums::{
7 BitRateSwitching, ErrorStateIndicator, FilterElementConfig, FilterType, FrameFormat, IdType,
8 RemoteTransmissionRequest,
9};
10use super::generic;
11
12#[doc = "Reader of field `ID`"]
13pub type ID_R = generic::R<u32, u32>;
14
15#[doc = "Reader of field `RTR`"]
16pub type RTR_R = generic::R<bool, RemoteTransmissionRequest>;
17impl RTR_R {
18 pub fn rtr(&self) -> RemoteTransmissionRequest {
19 match self.bits {
20 false => RemoteTransmissionRequest::TransmitDataFrame,
21 true => RemoteTransmissionRequest::TransmitRemoteFrame,
22 }
23 }
24 pub fn is_transmit_remote_frame(&self) -> bool {
25 *self == RemoteTransmissionRequest::TransmitRemoteFrame
26 }
27 pub fn is_transmit_data_frame(&self) -> bool {
28 *self == RemoteTransmissionRequest::TransmitDataFrame
29 }
30}
31
32#[doc = "Reader of field `XTD`"]
33pub type XTD_R = generic::R<bool, IdType>;
34impl XTD_R {
35 pub fn id_type(&self) -> IdType {
36 match self.bits() {
37 false => IdType::StandardId,
38 true => IdType::ExtendedId,
39 }
40 }
41 pub fn is_standard_id(&self) -> bool {
42 *self == IdType::StandardId
43 }
44 pub fn is_exteded_id(&self) -> bool {
45 *self == IdType::ExtendedId
46 }
47}
48
49#[doc = "Reader of field `ESI`"]
50pub type ESI_R = generic::R<bool, ErrorStateIndicator>;
51impl ESI_R {
52 pub fn error_state(&self) -> ErrorStateIndicator {
53 match self.bits() {
54 false => ErrorStateIndicator::ErrorActive,
55 true => ErrorStateIndicator::ErrorPassive,
56 }
57 }
58 pub fn is_error_active(&self) -> bool {
59 *self == ErrorStateIndicator::ErrorActive
60 }
61 pub fn is_error_passive(&self) -> bool {
62 *self == ErrorStateIndicator::ErrorPassive
63 }
64}
65
66#[doc = "Reader of field `DLC`"]
67pub type DLC_R = generic::R<u8, u8>;
68
69#[doc = "Reader of field `BRS`"]
70pub type BRS_R = generic::R<bool, BitRateSwitching>;
71impl BRS_R {
72 pub fn bit_rate_switching(&self) -> BitRateSwitching {
73 match self.bits() {
74 true => BitRateSwitching::WithBRS,
75 false => BitRateSwitching::WithoutBRS,
76 }
77 }
78 pub fn is_with_brs(&self) -> bool {
79 *self == BitRateSwitching::WithBRS
80 }
81 pub fn is_without_brs(&self) -> bool {
82 *self == BitRateSwitching::WithoutBRS
83 }
84}
85
86#[doc = "Reader of field `FDF`"]
87pub type FDF_R = generic::R<bool, FrameFormat>;
88impl FDF_R {
89 pub fn frame_format(&self) -> FrameFormat {
90 match self.bits() {
91 false => FrameFormat::Standard,
92 true => FrameFormat::Fdcan,
93 }
94 }
95 pub fn is_standard_format(&self) -> bool {
96 *self == FrameFormat::Standard
97 }
98 pub fn is_fdcan_format(&self) -> bool {
99 *self == FrameFormat::Fdcan
100 }
101}
102
103#[doc = "Reader of field `(X|S)FT`"]
104pub type ESFT_R = generic::R<u8, FilterType>;
105impl ESFT_R {
106 #[doc = r"Gets the Filtertype"]
107 #[inline(always)]
108 pub fn to_filter_type(&self) -> FilterType {
109 match self.bits() {
110 0b00 => FilterType::RangeFilter,
111 0b01 => FilterType::DualIdFilter,
112 0b10 => FilterType::ClassicFilter,
113 0b11 => FilterType::FilterDisabled,
114 _ => unreachable!(),
115 }
116 }
117}
118
119#[doc = "Reader of field `(E|S)FEC`"]
120pub type ESFEC_R = generic::R<u8, FilterElementConfig>;
121impl ESFEC_R {
122 pub fn to_filter_element_config(&self) -> FilterElementConfig {
123 match self.bits() {
124 0b000 => FilterElementConfig::DisableFilterElement,
125 0b001 => FilterElementConfig::StoreInFifo0,
126 0b010 => FilterElementConfig::StoreInFifo1,
127 0b011 => FilterElementConfig::Reject,
128 0b100 => FilterElementConfig::SetPriority,
129 0b101 => FilterElementConfig::SetPriorityAndStoreInFifo0,
130 0b110 => FilterElementConfig::SetPriorityAndStoreInFifo1,
131 _ => unimplemented!(),
132 }
133 }
134}
diff --git a/embassy-stm32/src/can/fd/message_ram/enums.rs b/embassy-stm32/src/can/fd/message_ram/enums.rs
new file mode 100644
index 000000000..78285bf81
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/enums.rs
@@ -0,0 +1,233 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3/// Datalength is the message length generalised over
4/// the Standard (Classic) and FDCAN message types
5
6#[derive(Clone, Copy, Debug, PartialEq)]
7pub enum DataLength {
8 Standard(u8),
9 Fdcan(u8),
10}
11impl DataLength {
12 /// Creates a DataLength type
13 ///
14 /// Uses the byte length and Type of frame as input
15 pub fn new(len: u8, ff: FrameFormat) -> DataLength {
16 match ff {
17 FrameFormat::Standard => match len {
18 0..=8 => DataLength::Standard(len),
19 _ => panic!("DataLength > 8"),
20 },
21 FrameFormat::Fdcan => match len {
22 0..=64 => DataLength::Fdcan(len),
23 _ => panic!("DataLength > 64"),
24 },
25 }
26 }
27 /// Specialised function to create standard frames
28 pub fn new_standard(len: u8) -> DataLength {
29 Self::new(len, FrameFormat::Standard)
30 }
31 /// Specialised function to create FDCAN frames
32 pub fn new_fdcan(len: u8) -> DataLength {
33 Self::new(len, FrameFormat::Fdcan)
34 }
35
36 /// returns the length in bytes
37 pub fn len(&self) -> u8 {
38 match self {
39 DataLength::Standard(l) | DataLength::Fdcan(l) => *l,
40 }
41 }
42
43 pub(crate) fn dlc(&self) -> u8 {
44 match self {
45 DataLength::Standard(l) => *l,
46 // See RM0433 Rev 7 Table 475. DLC coding
47 DataLength::Fdcan(l) => match l {
48 0..=8 => *l,
49 9..=12 => 9,
50 13..=16 => 10,
51 17..=20 => 11,
52 21..=24 => 12,
53 25..=32 => 13,
54 33..=48 => 14,
55 49..=64 => 15,
56 _ => panic!("DataLength > 64"),
57 },
58 }
59 }
60}
61impl From<DataLength> for FrameFormat {
62 fn from(dl: DataLength) -> FrameFormat {
63 match dl {
64 DataLength::Standard(_) => FrameFormat::Standard,
65 DataLength::Fdcan(_) => FrameFormat::Fdcan,
66 }
67 }
68}
69
70/// Wheter or not to generate an Tx Event
71#[derive(Clone, Copy, Debug, PartialEq)]
72pub enum Event {
73 /// Do not generate an Tx Event
74 NoEvent,
75 /// Generate an Tx Event with a specified ID
76 Event(u8),
77}
78
79impl From<Event> for EventControl {
80 fn from(e: Event) -> Self {
81 match e {
82 Event::NoEvent => EventControl::DoNotStore,
83 Event::Event(_) => EventControl::Store,
84 }
85 }
86}
87
88impl From<Option<u8>> for Event {
89 fn from(mm: Option<u8>) -> Self {
90 match mm {
91 None => Event::NoEvent,
92 Some(mm) => Event::Event(mm),
93 }
94 }
95}
96
97impl From<Event> for Option<u8> {
98 fn from(e: Event) -> Option<u8> {
99 match e {
100 Event::NoEvent => None,
101 Event::Event(mm) => Some(mm),
102 }
103 }
104}
105
106/// TODO
107#[derive(Clone, Copy, Debug, PartialEq)]
108pub enum ErrorStateIndicator {
109 /// TODO
110 ErrorActive = 0,
111 /// TODO
112 ErrorPassive = 1,
113}
114impl From<ErrorStateIndicator> for bool {
115 #[inline(always)]
116 fn from(e: ErrorStateIndicator) -> Self {
117 e as u8 != 0
118 }
119}
120
121/// Type of frame, standard (classic) or FdCAN
122#[derive(Clone, Copy, Debug, PartialEq)]
123pub enum FrameFormat {
124 Standard = 0,
125 Fdcan = 1,
126}
127impl From<FrameFormat> for bool {
128 #[inline(always)]
129 fn from(e: FrameFormat) -> Self {
130 e as u8 != 0
131 }
132}
133
134/// Type of Id, Standard or Extended
135#[derive(Clone, Copy, Debug, PartialEq)]
136pub enum IdType {
137 /// Standard ID
138 StandardId = 0,
139 /// Extended ID
140 ExtendedId = 1,
141}
142impl From<IdType> for bool {
143 #[inline(always)]
144 fn from(e: IdType) -> Self {
145 e as u8 != 0
146 }
147}
148
149/// Whether the frame contains data or requests data
150#[derive(Clone, Copy, Debug, PartialEq)]
151pub enum RemoteTransmissionRequest {
152 /// Frame contains data
153 TransmitDataFrame = 0,
154 /// frame does not contain data
155 TransmitRemoteFrame = 1,
156}
157impl From<RemoteTransmissionRequest> for bool {
158 #[inline(always)]
159 fn from(e: RemoteTransmissionRequest) -> Self {
160 e as u8 != 0
161 }
162}
163
164/// Whether BitRateSwitching should be or was enabled
165#[derive(Clone, Copy, Debug, PartialEq)]
166pub enum BitRateSwitching {
167 /// disable bit rate switching
168 WithoutBRS = 0,
169 /// enable bit rate switching
170 WithBRS = 1,
171}
172impl From<BitRateSwitching> for bool {
173 #[inline(always)]
174 fn from(e: BitRateSwitching) -> Self {
175 e as u8 != 0
176 }
177}
178
179/// Whether to store transmit Events
180#[derive(Clone, Copy, Debug, PartialEq)]
181pub enum EventControl {
182 /// do not store an tx event
183 DoNotStore,
184 /// store transmit events
185 Store,
186}
187impl From<EventControl> for bool {
188 #[inline(always)]
189 fn from(e: EventControl) -> Self {
190 e as u8 != 0
191 }
192}
193
194/// If an received message matched any filters
195#[derive(Clone, Copy, Debug, PartialEq)]
196pub enum FilterFrameMatch {
197 /// This did match filter <id>
198 DidMatch(u8),
199 /// This received frame did not match any specific filters
200 DidNotMatch,
201}
202
203/// Type of filter to be used
204#[derive(Clone, Copy, Debug, PartialEq)]
205pub enum FilterType {
206 /// Filter uses the range between two id's
207 RangeFilter = 0b00,
208 /// The filter matches on two specific id's (or one ID checked twice)
209 DualIdFilter = 0b01,
210 /// Filter is using a bitmask
211 ClassicFilter = 0b10,
212 /// Filter is disabled
213 FilterDisabled = 0b11,
214}
215
216#[derive(Clone, Copy, Debug, PartialEq)]
217pub enum FilterElementConfig {
218 /// Filter is disabled
219 DisableFilterElement = 0b000,
220 /// Store a matching message in FIFO 0
221 StoreInFifo0 = 0b001,
222 /// Store a matching message in FIFO 1
223 StoreInFifo1 = 0b010,
224 /// Reject a matching message
225 Reject = 0b011,
226 /// Flag that a priority message has been received, *But do note store!*??
227 SetPriority = 0b100,
228 /// Flag and store message in FIFO 0
229 SetPriorityAndStoreInFifo0 = 0b101,
230 /// Flag and store message in FIFO 1
231 SetPriorityAndStoreInFifo1 = 0b110,
232 //_Unused = 0b111,
233}
diff --git a/embassy-stm32/src/can/fd/message_ram/extended_filter.rs b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs
new file mode 100644
index 000000000..453e9056e
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs
@@ -0,0 +1,136 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{ESFEC_R, ESFT_R};
8use super::enums::{FilterElementConfig, FilterType};
9use super::generic;
10
11#[doc = "Reader of register ExtendedFilter"]
12pub(crate) type R = generic::R<super::ExtendedFilterType, super::ExtendedFilter>;
13#[doc = "Writer for register ExtendedFilter"]
14pub(crate) type W = generic::W<super::ExtendedFilterType, super::ExtendedFilter>;
15#[doc = "Register ExtendedFilter `reset()`'s"]
16impl generic::ResetValue for super::ExtendedFilter {
17 type Type = super::ExtendedFilterType;
18 #[inline(always)]
19 fn reset_value() -> Self::Type {
20 // Sets filter element to Disabled
21 [0x0, 0x0]
22 }
23}
24
25#[doc = "Reader of field `EFID2`"]
26pub(crate) type EFID2_R = generic::R<u32, u32>;
27#[doc = "Write proxy for field `EFID2`"]
28pub(crate) struct EFID2_W<'a> {
29 w: &'a mut W,
30}
31impl<'a> EFID2_W<'a> {
32 #[doc = r"Writes raw bits to the field"]
33 #[inline(always)]
34 pub unsafe fn bits(self, value: u32) -> &'a mut W {
35 self.w.bits[1] = (self.w.bits[1] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
36 self.w
37 }
38}
39
40#[doc = "Reader of field `EFID1`"]
41pub(crate) type EFID1_R = generic::R<u32, u32>;
42#[doc = "Write proxy for field `EFID1`"]
43pub(crate) struct EFID1_W<'a> {
44 w: &'a mut W,
45}
46impl<'a> EFID1_W<'a> {
47 #[doc = r"Writes raw bits to the field"]
48 #[inline(always)]
49 pub unsafe fn bits(self, value: u32) -> &'a mut W {
50 self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
51 self.w
52 }
53}
54
55#[doc = "Write proxy for field `EFEC`"]
56pub(crate) struct EFEC_W<'a> {
57 w: &'a mut W,
58}
59impl<'a> EFEC_W<'a> {
60 #[doc = r"Writes raw bits to the field"]
61 #[inline(always)]
62 pub unsafe fn bits(self, value: u8) -> &'a mut W {
63 self.w.bits[0] = (self.w.bits[0] & !(0x07 << 29)) | (((value as u32) & 0x07) << 29);
64 self.w
65 }
66 #[doc = r"Sets the field according to FilterElementConfig"]
67 #[inline(always)]
68 pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W {
69 //SAFETY: FilterElementConfig only be valid options
70 unsafe { self.bits(fec as u8) }
71 }
72}
73
74#[doc = "Write proxy for field `EFT`"]
75pub(crate) struct EFT_W<'a> {
76 w: &'a mut W,
77}
78impl<'a> EFT_W<'a> {
79 #[doc = r"Sets the field according the FilterType"]
80 #[inline(always)]
81 pub fn set_filter_type(self, filter: FilterType) -> &'a mut W {
82 //SAFETY: FilterType only be valid options
83 unsafe { self.bits(filter as u8) }
84 }
85 #[doc = r"Writes raw bits to the field"]
86 #[inline(always)]
87 pub unsafe fn bits(self, value: u8) -> &'a mut W {
88 self.w.bits[1] = (self.w.bits[1] & !(0x03 << 30)) | (((value as u32) & 0x03) << 30);
89 self.w
90 }
91}
92
93impl R {
94 #[doc = "Byte 0 - Bits 0:28 - EFID1"]
95 #[inline(always)]
96 pub fn sfid1(&self) -> EFID1_R {
97 EFID1_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
98 }
99 #[doc = "Byte 0 - Bits 29:31 - EFEC"]
100 #[inline(always)]
101 pub fn efec(&self) -> ESFEC_R {
102 ESFEC_R::new(((self.bits[0] >> 29) & 0x07) as u8)
103 }
104 #[doc = "Byte 1 - Bits 0:28 - EFID2"]
105 #[inline(always)]
106 pub fn sfid2(&self) -> EFID2_R {
107 EFID2_R::new(((self.bits[1]) & 0x1FFFFFFF) as u32)
108 }
109 #[doc = "Byte 1 - Bits 30:31 - EFT"]
110 #[inline(always)]
111 pub fn eft(&self) -> ESFT_R {
112 ESFT_R::new(((self.bits[1] >> 30) & 0x03) as u8)
113 }
114}
115impl W {
116 #[doc = "Byte 0 - Bits 0:28 - EFID1"]
117 #[inline(always)]
118 pub fn efid1(&mut self) -> EFID1_W {
119 EFID1_W { w: self }
120 }
121 #[doc = "Byte 0 - Bits 29:31 - EFEC"]
122 #[inline(always)]
123 pub fn efec(&mut self) -> EFEC_W {
124 EFEC_W { w: self }
125 }
126 #[doc = "Byte 1 - Bits 0:28 - EFID2"]
127 #[inline(always)]
128 pub fn efid2(&mut self) -> EFID2_W {
129 EFID2_W { w: self }
130 }
131 #[doc = "Byte 1 - Bits 30:31 - EFT"]
132 #[inline(always)]
133 pub fn eft(&mut self) -> EFT_W {
134 EFT_W { w: self }
135 }
136}
diff --git a/embassy-stm32/src/can/fd/message_ram/generic.rs b/embassy-stm32/src/can/fd/message_ram/generic.rs
new file mode 100644
index 000000000..1a5e121b4
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/generic.rs
@@ -0,0 +1,168 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3use core::marker;
4
5///This trait shows that register has `read` method
6///
7///Registers marked with `Writable` can be also `modify`'ed
8pub trait Readable {}
9
10///This trait shows that register has `write`, `write_with_zero` and `reset` method
11///
12///Registers marked with `Readable` can be also `modify`'ed
13pub trait Writable {}
14
15///Reset value of the register
16///
17///This value is initial value for `write` method.
18///It can be also directly writed to register by `reset` method.
19pub trait ResetValue {
20 ///Register size
21 type Type;
22 ///Reset value of the register
23 fn reset_value() -> Self::Type;
24}
25
26///This structure provides volatile access to register
27pub struct Reg<U, REG> {
28 register: vcell::VolatileCell<U>,
29 _marker: marker::PhantomData<REG>,
30}
31
32unsafe impl<U: Send, REG> Send for Reg<U, REG> {}
33
34impl<U, REG> Reg<U, REG>
35where
36 Self: Readable,
37 U: Copy,
38{
39 ///Reads the contents of `Readable` register
40 ///
41 ///You can read the contents of a register in such way:
42 ///```ignore
43 ///let bits = periph.reg.read().bits();
44 ///```
45 ///or get the content of a particular field of a register.
46 ///```ignore
47 ///let reader = periph.reg.read();
48 ///let bits = reader.field1().bits();
49 ///let flag = reader.field2().bit_is_set();
50 ///```
51 #[inline(always)]
52 pub fn read(&self) -> R<U, Self> {
53 R {
54 bits: self.register.get(),
55 _reg: marker::PhantomData,
56 }
57 }
58}
59
60impl<U, REG> Reg<U, REG>
61where
62 Self: ResetValue<Type = U> + Writable,
63 U: Copy,
64{
65 ///Writes the reset value to `Writable` register
66 ///
67 ///Resets the register to its initial state
68 #[inline(always)]
69 pub fn reset(&self) {
70 self.register.set(Self::reset_value())
71 }
72}
73
74impl<U, REG> Reg<U, REG>
75where
76 Self: ResetValue<Type = U> + Writable,
77 U: Copy,
78{
79 ///Writes bits to `Writable` register
80 ///
81 ///You can write raw bits into a register:
82 ///```ignore
83 ///periph.reg.write(|w| unsafe { w.bits(rawbits) });
84 ///```
85 ///or write only the fields you need:
86 ///```ignore
87 ///periph.reg.write(|w| w
88 /// .field1().bits(newfield1bits)
89 /// .field2().set_bit()
90 /// .field3().variant(VARIANT)
91 ///);
92 ///```
93 ///Other fields will have reset value.
94 #[inline(always)]
95 pub fn write<F>(&self, f: F)
96 where
97 F: FnOnce(&mut W<U, Self>) -> &mut W<U, Self>,
98 {
99 self.register.set(
100 f(&mut W {
101 bits: Self::reset_value(),
102 _reg: marker::PhantomData,
103 })
104 .bits,
105 );
106 }
107}
108
109///Register/field reader
110///
111///Result of the [`read`](Reg::read) method of a register.
112///Also it can be used in the [`modify`](Reg::read) method
113pub struct R<U, T> {
114 pub(crate) bits: U,
115 _reg: marker::PhantomData<T>,
116}
117
118impl<U, T> R<U, T>
119where
120 U: Copy,
121{
122 ///Create new instance of reader
123 #[inline(always)]
124 pub(crate) fn new(bits: U) -> Self {
125 Self {
126 bits,
127 _reg: marker::PhantomData,
128 }
129 }
130 ///Read raw bits from register/field
131 #[inline(always)]
132 pub fn bits(&self) -> U {
133 self.bits
134 }
135}
136
137impl<U, T, FI> PartialEq<FI> for R<U, T>
138where
139 U: PartialEq,
140 FI: Copy + Into<U>,
141{
142 #[inline(always)]
143 fn eq(&self, other: &FI) -> bool {
144 self.bits.eq(&(*other).into())
145 }
146}
147
148impl<FI> R<bool, FI> {
149 ///Value of the field as raw bits
150 #[inline(always)]
151 pub fn bit(&self) -> bool {
152 self.bits
153 }
154 ///Returns `true` if the bit is clear (0)
155 #[inline(always)]
156 pub fn bit_is_clear(&self) -> bool {
157 !self.bit()
158 }
159}
160
161///Register writer
162///
163///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register
164pub struct W<U, REG> {
165 ///Writable bits
166 pub(crate) bits: U,
167 _reg: marker::PhantomData<REG>,
168}
diff --git a/embassy-stm32/src/can/fd/message_ram/mod.rs b/embassy-stm32/src/can/fd/message_ram/mod.rs
new file mode 100644
index 000000000..830edf3bb
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/mod.rs
@@ -0,0 +1,170 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3use volatile_register::RW;
4
5pub(crate) mod common;
6pub(crate) mod enums;
7pub(crate) mod generic;
8
9/// Number of Receive Fifos configured by this module
10pub const RX_FIFOS_MAX: u8 = 2;
11/// Number of Receive Messages per RxFifo configured by this module
12pub const RX_FIFO_MAX: u8 = 3;
13/// Number of Transmit Messages configured by this module
14pub const TX_FIFO_MAX: u8 = 3;
15/// Number of Transmit Events configured by this module
16pub const TX_EVENT_MAX: u8 = 3;
17/// Number of Standard Filters configured by this module
18pub const STANDARD_FILTER_MAX: u8 = 28;
19/// Number of Extended Filters configured by this module
20pub const EXTENDED_FILTER_MAX: u8 = 8;
21
22/// MessageRam Overlay
23#[repr(C)]
24pub struct RegisterBlock {
25 pub(crate) filters: Filters,
26 pub(crate) receive: [Receive; RX_FIFOS_MAX as usize],
27 pub(crate) transmit: Transmit,
28}
29impl RegisterBlock {
30 pub fn reset(&mut self) {
31 self.filters.reset();
32 self.receive[0].reset();
33 self.receive[1].reset();
34 self.transmit.reset();
35 }
36}
37
38#[repr(C)]
39pub(crate) struct Filters {
40 pub(crate) flssa: [StandardFilter; STANDARD_FILTER_MAX as usize],
41 pub(crate) flesa: [ExtendedFilter; EXTENDED_FILTER_MAX as usize],
42}
43impl Filters {
44 pub fn reset(&mut self) {
45 for sf in &mut self.flssa {
46 sf.reset();
47 }
48 for ef in &mut self.flesa {
49 ef.reset();
50 }
51 }
52}
53
54#[repr(C)]
55pub(crate) struct Receive {
56 pub(crate) fxsa: [RxFifoElement; RX_FIFO_MAX as usize],
57}
58impl Receive {
59 pub fn reset(&mut self) {
60 for fe in &mut self.fxsa {
61 fe.reset();
62 }
63 }
64}
65
66#[repr(C)]
67pub(crate) struct Transmit {
68 pub(crate) efsa: [TxEventElement; TX_EVENT_MAX as usize],
69 pub(crate) tbsa: [TxBufferElement; TX_FIFO_MAX as usize],
70}
71impl Transmit {
72 pub fn reset(&mut self) {
73 for ee in &mut self.efsa {
74 ee.reset();
75 }
76 for be in &mut self.tbsa {
77 be.reset();
78 }
79 }
80}
81
82pub(crate) mod standard_filter;
83pub(crate) type StandardFilterType = u32;
84pub(crate) type StandardFilter = generic::Reg<StandardFilterType, _StandardFilter>;
85pub(crate) struct _StandardFilter;
86impl generic::Readable for StandardFilter {}
87impl generic::Writable for StandardFilter {}
88
89pub(crate) mod extended_filter;
90pub(crate) type ExtendedFilterType = [u32; 2];
91pub(crate) type ExtendedFilter = generic::Reg<ExtendedFilterType, _ExtendedFilter>;
92pub(crate) struct _ExtendedFilter;
93impl generic::Readable for ExtendedFilter {}
94impl generic::Writable for ExtendedFilter {}
95
96pub(crate) mod txevent_element;
97pub(crate) type TxEventElementType = [u32; 2];
98pub(crate) type TxEventElement = generic::Reg<TxEventElementType, _TxEventElement>;
99pub(crate) struct _TxEventElement;
100impl generic::Readable for TxEventElement {}
101impl generic::Writable for TxEventElement {}
102
103pub(crate) mod rxfifo_element;
104#[repr(C)]
105pub(crate) struct RxFifoElement {
106 pub(crate) header: RxFifoElementHeader,
107 pub(crate) data: [RW<u32>; 16],
108}
109impl RxFifoElement {
110 pub(crate) fn reset(&mut self) {
111 self.header.reset();
112 for byte in self.data.iter_mut() {
113 unsafe { byte.write(0) };
114 }
115 }
116}
117pub(crate) type RxFifoElementHeaderType = [u32; 2];
118pub(crate) type RxFifoElementHeader = generic::Reg<RxFifoElementHeaderType, _RxFifoElement>;
119pub(crate) struct _RxFifoElement;
120impl generic::Readable for RxFifoElementHeader {}
121impl generic::Writable for RxFifoElementHeader {}
122
123pub(crate) mod txbuffer_element;
124#[repr(C)]
125pub(crate) struct TxBufferElement {
126 pub(crate) header: TxBufferElementHeader,
127 pub(crate) data: [RW<u32>; 16],
128}
129impl TxBufferElement {
130 pub(crate) fn reset(&mut self) {
131 self.header.reset();
132 for byte in self.data.iter_mut() {
133 unsafe { byte.write(0) };
134 }
135 }
136}
137pub(crate) type TxBufferElementHeader = generic::Reg<TxBufferElementHeaderType, _TxBufferElement>;
138pub(crate) type TxBufferElementHeaderType = [u32; 2];
139pub(crate) struct _TxBufferElement;
140impl generic::Readable for TxBufferElementHeader {}
141impl generic::Writable for TxBufferElementHeader {}
142
143/// FdCan Message RAM instance.
144///
145/// # Safety
146///
147/// It is only safe to implement this trait, when:
148///
149/// * The implementing type has ownership of the Message RAM, preventing any
150/// other accesses to the register block.
151/// * `MSG_RAM` is a pointer to the Message RAM block and can be safely accessed
152/// for as long as ownership or a borrow of the implementing type is present.
153pub unsafe trait Instance {
154 const MSG_RAM: *mut RegisterBlock;
155 fn msg_ram(&self) -> &RegisterBlock {
156 unsafe { &*Self::MSG_RAM }
157 }
158 fn msg_ram_mut(&mut self) -> &mut RegisterBlock {
159 unsafe { &mut *Self::MSG_RAM }
160 }
161}
162
163// Ensure the RegisterBlock is the same size as on pg 1957 of RM0440.
164static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]);
165static_assertions::assert_eq_size!(Receive, [u32; 54]);
166static_assertions::assert_eq_size!(Transmit, [u32; 6 + 54]);
167static_assertions::assert_eq_size!(
168 RegisterBlock,
169 [u32; 28 /*Standard Filters*/ +16 /*Extended Filters*/ +54 /*RxFifo0*/ +54 /*RxFifo1*/ +6 /*TxEvent*/ +54 /*TxFifo */]
170);
diff --git a/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs b/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs
new file mode 100644
index 000000000..48fc3a091
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs
@@ -0,0 +1,122 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R};
8use super::enums::{DataLength, FilterFrameMatch, FrameFormat};
9use super::generic;
10
11#[doc = "Reader of register RxFifoElement"]
12pub(crate) type R = generic::R<super::RxFifoElementHeaderType, super::RxFifoElementHeader>;
13// #[doc = "Writer for register ExtendedFilter"]
14// pub(crate) type W = generic::W<super::RxFifoElementHeaderType, super::RxFifoElementHeader>;
15#[doc = "Register ExtendedFilter `reset()`'s"]
16impl generic::ResetValue for super::RxFifoElementHeader {
17 type Type = super::RxFifoElementHeaderType;
18 #[inline(always)]
19 fn reset_value() -> Self::Type {
20 [0x0, 0x0]
21 }
22}
23
24#[doc = "Reader of field `RXTS`"]
25pub(crate) type RXTS_R = generic::R<u16, u16>;
26
27#[doc = "Reader of field `FIDX`"]
28pub(crate) type FIDX_R = generic::R<u8, u8>;
29
30pub(crate) struct _ANMF;
31#[doc = "Reader of field `ANMF`"]
32pub(crate) type ANMF_R = generic::R<bool, _ANMF>;
33impl ANMF_R {
34 pub fn is_matching_frame(&self) -> bool {
35 self.bit_is_clear()
36 }
37}
38
39impl R {
40 #[doc = "Byte 0 - Bits 0:28 - ID"]
41 #[inline(always)]
42 pub fn id(&self) -> ID_R {
43 ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
44 }
45 #[doc = "Byte 0 - Bit 29 - RTR"]
46 #[inline(always)]
47 pub fn rtr(&self) -> RTR_R {
48 RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
49 }
50 #[doc = "Byte 0 - Bit 30 - XTD"]
51 #[inline(always)]
52 pub fn xtd(&self) -> XTD_R {
53 XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
54 }
55 #[doc = "Byte 0 - Bit 30 - ESI"]
56 #[inline(always)]
57 pub fn esi(&self) -> ESI_R {
58 ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
59 }
60 #[doc = "Byte 1 - Bits 0:15 - RXTS"]
61 #[inline(always)]
62 pub fn txts(&self) -> RXTS_R {
63 RXTS_R::new(((self.bits[1]) & 0xFFFF) as u16)
64 }
65 #[doc = "Byte 1 - Bits 16:19 - DLC"]
66 #[inline(always)]
67 pub fn dlc(&self) -> DLC_R {
68 DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
69 }
70 #[doc = "Byte 1 - Bits 20 - BRS"]
71 #[inline(always)]
72 pub fn brs(&self) -> BRS_R {
73 BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
74 }
75 #[doc = "Byte 1 - Bits 20 - FDF"]
76 #[inline(always)]
77 pub fn fdf(&self) -> FDF_R {
78 FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0)
79 }
80 #[doc = "Byte 1 - Bits 24:30 - FIDX"]
81 #[inline(always)]
82 pub fn fidx(&self) -> FIDX_R {
83 FIDX_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
84 }
85 #[doc = "Byte 1 - Bits 31 - ANMF"]
86 #[inline(always)]
87 pub fn anmf(&self) -> ANMF_R {
88 ANMF_R::new(((self.bits[1] >> 31) & 0x01) != 0)
89 }
90 pub fn to_data_length(&self) -> DataLength {
91 let dlc = self.dlc().bits();
92 let ff = self.fdf().frame_format();
93 let len = if ff == FrameFormat::Fdcan {
94 // See RM0433 Rev 7 Table 475. DLC coding
95 match dlc {
96 0..=8 => dlc,
97 9 => 12,
98 10 => 16,
99 11 => 20,
100 12 => 24,
101 13 => 32,
102 14 => 48,
103 15 => 64,
104 _ => panic!("DLC > 15"),
105 }
106 } else {
107 match dlc {
108 0..=8 => dlc,
109 9..=15 => 8,
110 _ => panic!("DLC > 15"),
111 }
112 };
113 DataLength::new(len, ff)
114 }
115 pub fn to_filter_match(&self) -> FilterFrameMatch {
116 if self.anmf().is_matching_frame() {
117 FilterFrameMatch::DidMatch(self.fidx().bits())
118 } else {
119 FilterFrameMatch::DidNotMatch
120 }
121 }
122}
diff --git a/embassy-stm32/src/can/fd/message_ram/standard_filter.rs b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs
new file mode 100644
index 000000000..3a3bbcf12
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs
@@ -0,0 +1,136 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{ESFEC_R, ESFT_R};
8use super::enums::{FilterElementConfig, FilterType};
9use super::generic;
10
11#[doc = "Reader of register StandardFilter"]
12pub(crate) type R = generic::R<super::StandardFilterType, super::StandardFilter>;
13#[doc = "Writer for register StandardFilter"]
14pub(crate) type W = generic::W<super::StandardFilterType, super::StandardFilter>;
15#[doc = "Register StandardFilter `reset()`'s with value 0xC0000"]
16impl generic::ResetValue for super::StandardFilter {
17 type Type = super::StandardFilterType;
18 #[inline(always)]
19 fn reset_value() -> Self::Type {
20 // Sets filter element to Disabled
21 0xC000
22 }
23}
24
25#[doc = "Reader of field `SFID2`"]
26pub(crate) type SFID2_R = generic::R<u16, u16>;
27#[doc = "Write proxy for field `SFID2`"]
28pub(crate) struct SFID2_W<'a> {
29 w: &'a mut W,
30}
31impl<'a> SFID2_W<'a> {
32 #[doc = r"Writes raw bits to the field"]
33 #[inline(always)]
34 pub unsafe fn bits(self, value: u16) -> &'a mut W {
35 self.w.bits = (self.w.bits & !(0x07ff)) | ((value as u32) & 0x07ff);
36 self.w
37 }
38}
39
40#[doc = "Reader of field `SFID1`"]
41pub(crate) type SFID1_R = generic::R<u16, u16>;
42#[doc = "Write proxy for field `SFID1`"]
43pub(crate) struct SFID1_W<'a> {
44 w: &'a mut W,
45}
46impl<'a> SFID1_W<'a> {
47 #[doc = r"Writes raw bits to the field"]
48 #[inline(always)]
49 pub unsafe fn bits(self, value: u16) -> &'a mut W {
50 self.w.bits = (self.w.bits & !(0x07ff << 16)) | (((value as u32) & 0x07ff) << 16);
51 self.w
52 }
53}
54
55#[doc = "Write proxy for field `SFEC`"]
56pub(crate) struct SFEC_W<'a> {
57 w: &'a mut W,
58}
59impl<'a> SFEC_W<'a> {
60 #[doc = r"Writes raw bits to the field"]
61 #[inline(always)]
62 pub unsafe fn bits(self, value: u8) -> &'a mut W {
63 self.w.bits = (self.w.bits & !(0x07 << 27)) | (((value as u32) & 0x07) << 27);
64 self.w
65 }
66 #[doc = r"Sets the field according to FilterElementConfig"]
67 #[inline(always)]
68 pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W {
69 //SAFETY: FilterElementConfig only be valid options
70 unsafe { self.bits(fec as u8) }
71 }
72}
73
74#[doc = "Write proxy for field `SFT`"]
75pub(crate) struct SFT_W<'a> {
76 w: &'a mut W,
77}
78impl<'a> SFT_W<'a> {
79 #[doc = r"Sets the field according the FilterType"]
80 #[inline(always)]
81 pub fn set_filter_type(self, filter: FilterType) -> &'a mut W {
82 //SAFETY: FilterType only be valid options
83 unsafe { self.bits(filter as u8) }
84 }
85 #[doc = r"Writes raw bits to the field"]
86 #[inline(always)]
87 pub unsafe fn bits(self, value: u8) -> &'a mut W {
88 self.w.bits = (self.w.bits & !(0x03 << 30)) | (((value as u32) & 0x03) << 30);
89 self.w
90 }
91}
92
93impl R {
94 #[doc = "Bits 0:10 - SFID2"]
95 #[inline(always)]
96 pub fn sfid2(&self) -> SFID2_R {
97 SFID2_R::new((self.bits & 0x07ff) as u16)
98 }
99 #[doc = "Bits 16:26 - SFID1"]
100 #[inline(always)]
101 pub fn sfid1(&self) -> SFID1_R {
102 SFID1_R::new(((self.bits >> 16) & 0x07ff) as u16)
103 }
104 #[doc = "Bits 27:29 - SFEC"]
105 #[inline(always)]
106 pub fn sfec(&self) -> ESFEC_R {
107 ESFEC_R::new(((self.bits >> 27) & 0x07) as u8)
108 }
109 #[doc = "Bits 30:31 - SFT"]
110 #[inline(always)]
111 pub fn sft(&self) -> ESFT_R {
112 ESFT_R::new(((self.bits >> 30) & 0x03) as u8)
113 }
114}
115impl W {
116 #[doc = "Bits 0:10 - SFID2"]
117 #[inline(always)]
118 pub fn sfid2(&mut self) -> SFID2_W {
119 SFID2_W { w: self }
120 }
121 #[doc = "Bits 16:26 - SFID1"]
122 #[inline(always)]
123 pub fn sfid1(&mut self) -> SFID1_W {
124 SFID1_W { w: self }
125 }
126 #[doc = "Bits 27:29 - SFEC"]
127 #[inline(always)]
128 pub fn sfec(&mut self) -> SFEC_W {
129 SFEC_W { w: self }
130 }
131 #[doc = "Bits 30:31 - SFT"]
132 #[inline(always)]
133 pub fn sft(&mut self) -> SFT_W {
134 SFT_W { w: self }
135 }
136}
diff --git a/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs
new file mode 100644
index 000000000..455406a1c
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs
@@ -0,0 +1,433 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R};
8use super::enums::{
9 BitRateSwitching, DataLength, ErrorStateIndicator, Event, EventControl, FrameFormat, IdType,
10 RemoteTransmissionRequest,
11};
12use super::generic;
13
14#[doc = "Reader of register TxBufferElement"]
15pub(crate) type R = generic::R<super::TxBufferElementHeaderType, super::TxBufferElementHeader>;
16#[doc = "Writer for register TxBufferElement"]
17pub(crate) type W = generic::W<super::TxBufferElementHeaderType, super::TxBufferElementHeader>;
18impl generic::ResetValue for super::TxBufferElementHeader {
19 type Type = super::TxBufferElementHeaderType;
20
21 #[allow(dead_code)]
22 #[inline(always)]
23 fn reset_value() -> Self::Type {
24 [0; 2]
25 }
26}
27
28#[doc = "Write proxy for field `ESI`"]
29pub(crate) struct ESI_W<'a> {
30 w: &'a mut W,
31}
32impl<'a> ESI_W<'a> {
33 #[doc = r"Writes `variant` to the field"]
34 #[inline(always)]
35 #[allow(dead_code)]
36 pub fn set_error_indicator(self, esi: ErrorStateIndicator) -> &'a mut W {
37 self.bit(esi as u8 != 0)
38 }
39
40 #[doc = r"Sets the field bit"]
41 #[inline(always)]
42 #[allow(dead_code)]
43 pub fn set_bit(self) -> &'a mut W {
44 self.bit(true)
45 }
46 #[doc = r"Clears the field bit"]
47 #[inline(always)]
48 #[allow(dead_code)]
49 pub fn clear_bit(self) -> &'a mut W {
50 self.bit(false)
51 }
52 #[doc = r"Writes raw bits to the field"]
53 #[inline(always)]
54 #[allow(dead_code)]
55 pub fn bit(self, value: bool) -> &'a mut W {
56 self.w.bits[0] = (self.w.bits[0] & !(0x01 << 31)) | (((value as u32) & 0x01) << 31);
57 self.w
58 }
59}
60
61#[doc = "Write proxy for field `XTD`"]
62pub(crate) struct XTD_W<'a> {
63 w: &'a mut W,
64}
65impl<'a> XTD_W<'a> {
66 #[doc = r"Writes `variant` to the field"]
67 #[inline(always)]
68 #[allow(dead_code)]
69 pub fn set_id_type(self, idt: IdType) -> &'a mut W {
70 self.bit(idt as u8 != 0)
71 }
72
73 #[doc = r"Sets the field bit"]
74 #[inline(always)]
75 #[allow(dead_code)]
76 pub fn set_bit(self) -> &'a mut W {
77 self.bit(true)
78 }
79 #[doc = r"Clears the field bit"]
80 #[inline(always)]
81 #[allow(dead_code)]
82 pub fn clear_bit(self) -> &'a mut W {
83 self.bit(false)
84 }
85 #[doc = r"Writes raw bits to the field"]
86 #[inline(always)]
87 #[allow(dead_code)]
88 pub fn bit(self, value: bool) -> &'a mut W {
89 self.w.bits[0] = (self.w.bits[0] & !(0x01 << 30)) | (((value as u32) & 0x01) << 30);
90 self.w
91 }
92}
93
94#[doc = "Write proxy for field `RTR`"]
95pub(crate) struct RTR_W<'a> {
96 w: &'a mut W,
97}
98impl<'a> RTR_W<'a> {
99 #[doc = r"Writes `variant` to the field"]
100 #[inline(always)]
101 #[allow(dead_code)]
102 pub fn set_rtr(self, rtr: RemoteTransmissionRequest) -> &'a mut W {
103 self.bit(rtr as u8 != 0)
104 }
105
106 #[doc = r"Sets the field bit"]
107 #[inline(always)]
108 #[allow(dead_code)]
109 pub fn set_bit(self) -> &'a mut W {
110 self.bit(true)
111 }
112 #[doc = r"Clears the field bit"]
113 #[inline(always)]
114 #[allow(dead_code)]
115 pub fn clear_bit(self) -> &'a mut W {
116 self.bit(false)
117 }
118 #[doc = r"Writes raw bits to the field"]
119 #[inline(always)]
120 #[allow(dead_code)]
121 pub fn bit(self, value: bool) -> &'a mut W {
122 self.w.bits[0] = (self.w.bits[0] & !(0x01 << 29)) | (((value as u32) & 0x01) << 29);
123 self.w
124 }
125}
126
127#[doc = "Write proxy for field `ID`"]
128pub(crate) struct ID_W<'a> {
129 w: &'a mut W,
130}
131impl<'a> ID_W<'a> {
132 #[doc = r"Writes raw bits to the field"]
133 #[inline(always)]
134 #[allow(dead_code)]
135 pub unsafe fn bits(self, value: u32) -> &'a mut W {
136 self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
137 self.w
138 }
139}
140
141#[doc = "Write proxy for field `DLC`"]
142pub(crate) struct DLC_W<'a> {
143 w: &'a mut W,
144}
145impl<'a> DLC_W<'a> {
146 #[doc = r"Writes raw bits to the field"]
147 #[inline(always)]
148 #[allow(dead_code)]
149 pub unsafe fn bits(self, value: u8) -> &'a mut W {
150 self.w.bits[1] = (self.w.bits[1] & !(0x0F << 16)) | (((value as u32) & 0x0F) << 16);
151 self.w
152 }
153}
154
155#[doc = "Write proxy for field `BRS`"]
156pub(crate) struct BRS_W<'a> {
157 w: &'a mut W,
158}
159impl<'a> BRS_W<'a> {
160 #[doc = r"Writes `variant` to the field"]
161 #[inline(always)]
162 #[allow(dead_code)]
163 pub fn set_brs(self, brs: BitRateSwitching) -> &'a mut W {
164 self.bit(brs as u8 != 0)
165 }
166
167 #[doc = r"Sets the field bit"]
168 #[inline(always)]
169 #[allow(dead_code)]
170 pub fn set_bit(self) -> &'a mut W {
171 self.bit(true)
172 }
173 #[doc = r"Clears the field bit"]
174 #[inline(always)]
175 #[allow(dead_code)]
176 pub fn clear_bit(self) -> &'a mut W {
177 self.bit(false)
178 }
179 #[doc = r"Writes raw bits to the field"]
180 #[inline(always)]
181 #[allow(dead_code)]
182 pub fn bit(self, value: bool) -> &'a mut W {
183 self.w.bits[1] = (self.w.bits[1] & !(0x01 << 20)) | (((value as u32) & 0x01) << 20);
184 self.w
185 }
186}
187
188#[doc = "Write proxy for field `FDF`"]
189pub(crate) struct FDF_W<'a> {
190 w: &'a mut W,
191}
192impl<'a> FDF_W<'a> {
193 #[doc = r"Writes `variant` to the field"]
194 #[inline(always)]
195 #[allow(dead_code)]
196 pub fn set_format(self, fdf: FrameFormat) -> &'a mut W {
197 self.bit(fdf as u8 != 0)
198 }
199
200 #[doc = r"Sets the field bit"]
201 #[inline(always)]
202 #[allow(dead_code)]
203 pub fn set_bit(self) -> &'a mut W {
204 self.bit(true)
205 }
206 #[doc = r"Clears the field bit"]
207 #[inline(always)]
208 #[allow(dead_code)]
209 pub fn clear_bit(self) -> &'a mut W {
210 self.bit(false)
211 }
212 #[doc = r"Writes raw bits to the field"]
213 #[inline(always)]
214 #[allow(dead_code)]
215 pub fn bit(self, value: bool) -> &'a mut W {
216 self.w.bits[1] = (self.w.bits[1] & !(0x01 << 21)) | (((value as u32) & 0x01) << 21);
217 self.w
218 }
219}
220
221#[doc = "Reader of field `EFC`"]
222pub(crate) type EFC_R = generic::R<bool, EventControl>;
223impl EFC_R {
224 pub fn to_event_control(&self) -> EventControl {
225 match self.bit() {
226 false => EventControl::DoNotStore,
227 true => EventControl::Store,
228 }
229 }
230}
231#[doc = "Write proxy for field `EFC`"]
232pub(crate) struct EFC_W<'a> {
233 w: &'a mut W,
234}
235impl<'a> EFC_W<'a> {
236 #[doc = r"Writes `variant` to the field"]
237 #[inline(always)]
238 #[allow(dead_code)]
239 pub fn set_event_control(self, efc: EventControl) -> &'a mut W {
240 self.bit(match efc {
241 EventControl::DoNotStore => false,
242 EventControl::Store => true,
243 })
244 }
245
246 #[doc = r"Sets the field bit"]
247 #[inline(always)]
248 #[allow(dead_code)]
249 pub fn set_bit(self) -> &'a mut W {
250 self.bit(true)
251 }
252 #[doc = r"Clears the field bit"]
253 #[inline(always)]
254 #[allow(dead_code)]
255 pub fn clear_bit(self) -> &'a mut W {
256 self.bit(false)
257 }
258 #[doc = r"Writes raw bits to the field"]
259 #[inline(always)]
260 #[allow(dead_code)]
261 pub fn bit(self, value: bool) -> &'a mut W {
262 self.w.bits[1] = (self.w.bits[1] & !(0x01 << 23)) | (((value as u32) & 0x01) << 23);
263 self.w
264 }
265}
266
267struct Marker(u8);
268impl From<Event> for Marker {
269 fn from(e: Event) -> Marker {
270 match e {
271 Event::NoEvent => Marker(0),
272 Event::Event(mm) => Marker(mm),
273 }
274 }
275}
276
277#[doc = "Reader of field `MM`"]
278pub(crate) type MM_R = generic::R<u8, u8>;
279#[doc = "Write proxy for field `MM`"]
280pub(crate) struct MM_W<'a> {
281 w: &'a mut W,
282}
283impl<'a> MM_W<'a> {
284 #[doc = r"Writes raw bits to the field"]
285 #[inline(always)]
286 pub unsafe fn bits(self, value: u8) -> &'a mut W {
287 self.w.bits[1] = (self.w.bits[1] & !(0x7F << 24)) | (((value as u32) & 0x7F) << 24);
288 self.w
289 }
290
291 fn set_message_marker(self, mm: Marker) -> &'a mut W {
292 unsafe { self.bits(mm.0) }
293 }
294}
295
296impl R {
297 #[doc = "Byte 0 - Bits 0:28 - ID"]
298 #[inline(always)]
299 pub fn id(&self) -> ID_R {
300 ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
301 }
302 #[doc = "Byte 0 - Bit 29 - RTR"]
303 #[inline(always)]
304 pub fn rtr(&self) -> RTR_R {
305 RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
306 }
307 #[doc = "Byte 0 - Bit 30 - XTD"]
308 #[inline(always)]
309 pub fn xtd(&self) -> XTD_R {
310 XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
311 }
312 #[doc = "Byte 0 - Bit 30 - ESI"]
313 #[inline(always)]
314 pub fn esi(&self) -> ESI_R {
315 ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
316 }
317 #[doc = "Byte 1 - Bits 16:19 - DLC"]
318 #[inline(always)]
319 pub fn dlc(&self) -> DLC_R {
320 DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
321 }
322 #[doc = "Byte 1 - Bits 20 - BRS"]
323 #[inline(always)]
324 pub fn brs(&self) -> BRS_R {
325 BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
326 }
327 #[doc = "Byte 1 - Bits 20 - FDF"]
328 #[inline(always)]
329 pub fn fdf(&self) -> FDF_R {
330 FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0)
331 }
332 #[doc = "Byte 1 - Bits 23 - EFC"]
333 #[inline(always)]
334 pub fn efc(&self) -> EFC_R {
335 EFC_R::new(((self.bits[1] >> 23) & 0x01) != 0)
336 }
337 #[doc = "Byte 1 - Bits 24:31 - MM"]
338 #[inline(always)]
339 pub fn mm(&self) -> MM_R {
340 MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
341 }
342 pub fn to_data_length(&self) -> DataLength {
343 let dlc = self.dlc().bits();
344 let ff = self.fdf().frame_format();
345 let len = if ff == FrameFormat::Fdcan {
346 // See RM0433 Rev 7 Table 475. DLC coding
347 match dlc {
348 0..=8 => dlc,
349 9 => 12,
350 10 => 16,
351 11 => 20,
352 12 => 24,
353 13 => 32,
354 14 => 48,
355 15 => 64,
356 _ => panic!("DLC > 15"),
357 }
358 } else {
359 match dlc {
360 0..=8 => dlc,
361 9..=15 => 8,
362 _ => panic!("DLC > 15"),
363 }
364 };
365 DataLength::new(len, ff)
366 }
367 pub fn to_event(&self) -> Event {
368 let mm = self.mm().bits();
369 let efc = self.efc().to_event_control();
370 match efc {
371 EventControl::DoNotStore => Event::NoEvent,
372 EventControl::Store => Event::Event(mm),
373 }
374 }
375}
376impl W {
377 #[doc = "Byte 0 - Bits 0:28 - ID"]
378 #[inline(always)]
379 pub fn id(&mut self) -> ID_W {
380 ID_W { w: self }
381 }
382 #[doc = "Byte 0 - Bit 29 - RTR"]
383 #[inline(always)]
384 pub fn rtr(&mut self) -> RTR_W {
385 RTR_W { w: self }
386 }
387 #[doc = "Byte 0 - Bit 30 - XTD"]
388 #[inline(always)]
389 pub fn xtd(&mut self) -> XTD_W {
390 XTD_W { w: self }
391 }
392 #[doc = "Byte 0 - Bit 31 - ESI"]
393 #[inline(always)]
394 pub fn esi(&mut self) -> ESI_W {
395 ESI_W { w: self }
396 }
397 #[doc = "Byte 1 - Bit 16:19 - DLC"]
398 #[inline(always)]
399 pub fn dlc(&mut self) -> DLC_W {
400 DLC_W { w: self }
401 }
402 #[doc = "Byte 1 - Bit 20 - BRS"]
403 #[inline(always)]
404 pub fn brs(&mut self) -> BRS_W {
405 BRS_W { w: self }
406 }
407 #[doc = "Byte 1 - Bit 21 - FDF"]
408 #[inline(always)]
409 pub fn fdf(&mut self) -> FDF_W {
410 FDF_W { w: self }
411 }
412 #[doc = "Byte 1 - Bit 23 - EFC"]
413 #[inline(always)]
414 pub fn efc(&mut self) -> EFC_W {
415 EFC_W { w: self }
416 }
417 #[doc = "Byte 1 - Bit 24:31 - MM"]
418 #[inline(always)]
419 pub fn mm(&mut self) -> MM_W {
420 MM_W { w: self }
421 }
422 #[doc = "Convenience function for setting the data length and frame format"]
423 #[inline(always)]
424 pub fn set_len(&mut self, dl: impl Into<DataLength>) -> &mut Self {
425 let dl: DataLength = dl.into();
426 self.fdf().set_format(dl.into());
427 unsafe { self.dlc().bits(dl.dlc()) }
428 }
429 pub fn set_event(&mut self, event: Event) -> &mut Self {
430 self.mm().set_message_marker(event.into());
431 self.efc().set_event_control(event.into())
432 }
433}
diff --git a/embassy-stm32/src/can/fd/message_ram/txevent_element.rs b/embassy-stm32/src/can/fd/message_ram/txevent_element.rs
new file mode 100644
index 000000000..817a4449f
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/txevent_element.rs
@@ -0,0 +1,138 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{BRS_R, DLC_R, ESI_R, RTR_R, XTD_R};
8use super::generic;
9
10#[doc = "Reader of register TxEventElement"]
11pub(crate) type R = generic::R<super::TxEventElementType, super::TxEventElement>;
12// #[doc = "Writer for register TxEventElement"]
13// pub(crate) type W = generic::W<super::TxEventElementType, super::TxEventElement>;
14#[doc = "Register TxEventElement `reset()`'s"]
15impl generic::ResetValue for super::TxEventElement {
16 type Type = super::TxEventElementType;
17 #[inline(always)]
18 fn reset_value() -> Self::Type {
19 [0, 0]
20 }
21}
22
23#[doc = "Reader of field `ID`"]
24pub(crate) type ID_R = generic::R<u32, u32>;
25
26#[doc = "Reader of field `TXTS`"]
27pub(crate) type TXTS_R = generic::R<u16, u16>;
28
29#[derive(Clone, Copy, Debug, PartialEq)]
30pub(crate) enum DataLengthFormat {
31 StandardLength = 0,
32 FDCANLength = 1,
33}
34impl From<DataLengthFormat> for bool {
35 #[inline(always)]
36 fn from(dlf: DataLengthFormat) -> Self {
37 dlf as u8 != 0
38 }
39}
40
41#[doc = "Reader of field `EDL`"]
42pub(crate) type EDL_R = generic::R<bool, DataLengthFormat>;
43impl EDL_R {
44 pub fn data_length_format(&self) -> DataLengthFormat {
45 match self.bits() {
46 false => DataLengthFormat::StandardLength,
47 true => DataLengthFormat::FDCANLength,
48 }
49 }
50 pub fn is_standard_length(&self) -> bool {
51 *self == DataLengthFormat::StandardLength
52 }
53 pub fn is_fdcan_length(&self) -> bool {
54 *self == DataLengthFormat::FDCANLength
55 }
56}
57
58#[derive(Clone, Copy, Debug, PartialEq)]
59pub(crate) enum EventType {
60 //_Reserved = 0b00,
61 TxEvent = 0b01,
62 TxDespiteAbort = 0b10,
63 //_Reserved = 0b10,
64}
65
66#[doc = "Reader of field `EFC`"]
67pub(crate) type EFC_R = generic::R<u8, EventType>;
68impl EFC_R {
69 pub fn event_type(&self) -> EventType {
70 match self.bits() {
71 0b01 => EventType::TxEvent,
72 0b10 => EventType::TxDespiteAbort,
73 _ => unimplemented!(),
74 }
75 }
76 pub fn is_tx_event(&self) -> bool {
77 self.event_type() == EventType::TxEvent
78 }
79 pub fn is_despite_abort(&self) -> bool {
80 self.event_type() == EventType::TxDespiteAbort
81 }
82}
83
84#[doc = "Reader of field `MM`"]
85pub(crate) type MM_R = generic::R<u8, u8>;
86
87impl R {
88 #[doc = "Byte 0 - Bits 0:28 - ID"]
89 #[inline(always)]
90 pub fn id(&self) -> ID_R {
91 ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
92 }
93 #[doc = "Byte 0 - Bit 29 - RTR"]
94 #[inline(always)]
95 pub fn rtr(&self) -> RTR_R {
96 RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
97 }
98 #[doc = "Byte 0 - Bit 30 - XTD"]
99 #[inline(always)]
100 pub fn xtd(&self) -> XTD_R {
101 XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
102 }
103 #[doc = "Byte 0 - Bit 30 - ESI"]
104 #[inline(always)]
105 pub fn esi(&self) -> ESI_R {
106 ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
107 }
108 #[doc = "Byte 1 - Bits 0:15 - TXTS"]
109 #[inline(always)]
110 pub fn txts(&self) -> TXTS_R {
111 TXTS_R::new(((self.bits[1]) & 0xFFFF) as u16)
112 }
113 #[doc = "Byte 1 - Bits 16:19 - DLC"]
114 #[inline(always)]
115 pub fn dlc(&self) -> DLC_R {
116 DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
117 }
118 #[doc = "Byte 1 - Bits 20 - BRS"]
119 #[inline(always)]
120 pub fn brs(&self) -> BRS_R {
121 BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
122 }
123 #[doc = "Byte 1 - Bits 21 - EDL"]
124 #[inline(always)]
125 pub fn edl(&self) -> EDL_R {
126 EDL_R::new(((self.bits[1] >> 21) & 0x01) != 0)
127 }
128 #[doc = "Byte 1 - Bits 22:23 - EFC"]
129 #[inline(always)]
130 pub fn efc(&self) -> EFC_R {
131 EFC_R::new(((self.bits[1] >> 22) & 0x03) as u8)
132 }
133 #[doc = "Byte 1 - Bits 24:31 - MM"]
134 #[inline(always)]
135 pub fn mm(&self) -> MM_R {
136 MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
137 }
138}
diff --git a/embassy-stm32/src/can/fd/mod.rs b/embassy-stm32/src/can/fd/mod.rs
new file mode 100644
index 000000000..0008fd3a8
--- /dev/null
+++ b/embassy-stm32/src/can/fd/mod.rs
@@ -0,0 +1,6 @@
1//! Module containing that which is speciffic to fdcan hardware variant
2
3pub mod config;
4pub mod filter;
5pub(crate) mod message_ram;
6pub(crate) mod peripheral;
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
new file mode 100644
index 000000000..6f390abb4
--- /dev/null
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -0,0 +1,776 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3use core::convert::Infallible;
4use core::slice;
5
6use crate::can::fd::config::*;
7use crate::can::fd::message_ram::enums::*;
8use crate::can::fd::message_ram::{RegisterBlock, RxFifoElement, TxBufferElement};
9use crate::can::frame::*;
10
11/// Loopback Mode
12#[derive(Clone, Copy, Debug)]
13enum LoopbackMode {
14 None,
15 Internal,
16 External,
17}
18
19pub struct Registers {
20 pub regs: &'static crate::pac::can::Fdcan,
21 pub msgram: &'static crate::pac::fdcanram::Fdcanram,
22}
23
24impl Registers {
25 fn tx_buffer_element(&self, bufidx: usize) -> &mut TxBufferElement {
26 &mut self.msg_ram_mut().transmit.tbsa[bufidx]
27 }
28 pub fn msg_ram_mut(&self) -> &mut RegisterBlock {
29 let ptr = self.msgram.as_ptr() as *mut RegisterBlock;
30 unsafe { &mut (*ptr) }
31 }
32
33 fn rx_fifo_element(&self, fifonr: usize, bufnum: usize) -> &mut RxFifoElement {
34 &mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum]
35 }
36
37 pub fn read_classic(&self, fifonr: usize) -> Option<(ClassicFrame, u16)> {
38 // Fill level - do we have a msg?
39 if self.regs.rxfs(fifonr).read().ffl() < 1 {
40 return None;
41 }
42
43 let read_idx = self.regs.rxfs(fifonr).read().fgi();
44 let mailbox = self.rx_fifo_element(fifonr, read_idx as usize);
45
46 let mut buffer: [u8; 8] = [0; 8];
47 let maybe_header = extract_frame(mailbox, &mut buffer);
48
49 // Clear FIFO, reduces count and increments read buf
50 self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx));
51
52 match maybe_header {
53 Some((header, ts)) => {
54 let data = ClassicData::new(&buffer[0..header.len() as usize]);
55 Some((ClassicFrame::new(header, data.unwrap()), ts))
56 }
57 None => None,
58 }
59 }
60
61 pub fn read_fd(&self, fifonr: usize) -> Option<(FdFrame, u16)> {
62 // Fill level - do we have a msg?
63 if self.regs.rxfs(fifonr).read().ffl() < 1 {
64 return None;
65 }
66
67 let read_idx = self.regs.rxfs(fifonr).read().fgi();
68 let mailbox = self.rx_fifo_element(fifonr, read_idx as usize);
69
70 let mut buffer: [u8; 64] = [0; 64];
71 let maybe_header = extract_frame(mailbox, &mut buffer);
72
73 // Clear FIFO, reduces count and increments read buf
74 self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx));
75
76 match maybe_header {
77 Some((header, ts)) => {
78 let data = FdData::new(&buffer[0..header.len() as usize]);
79 Some((FdFrame::new(header, data.unwrap()), ts))
80 }
81 None => None,
82 }
83 }
84
85 pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) {
86 // Fill level - do we have a msg?
87 //if self.regs.rxfs(fifonr).read().ffl() < 1 { return None; }
88
89 //let read_idx = self.regs.rxfs(fifonr).read().fgi();
90
91 let mailbox = self.tx_buffer_element(bufidx);
92
93 mailbox.reset();
94 put_tx_header(mailbox, header);
95 put_tx_data(mailbox, &buffer[..header.len() as usize]);
96
97 // Set <idx as Mailbox> as ready to transmit
98 self.regs.txbar().modify(|w| w.set_ar(bufidx, true));
99 }
100
101 /// Returns if the tx queue is able to accept new messages without having to cancel an existing one
102 #[inline]
103 pub fn tx_queue_is_full(&self) -> bool {
104 self.regs.txfqs().read().tfqf()
105 }
106
107 #[inline]
108 pub fn has_pending_frame(&self, idx: usize) -> bool {
109 self.regs.txbrp().read().trp(idx)
110 }
111
112 /// Returns `Ok` when the mailbox is free or if it contains pending frame with a
113 /// lower priority (higher ID) than the identifier `id`.
114 #[inline]
115 pub fn is_available(&self, bufidx: usize, id: &embedded_can::Id) -> bool {
116 if self.has_pending_frame(bufidx) {
117 let mailbox = self.tx_buffer_element(bufidx);
118
119 let header_reg = mailbox.header.read();
120 let old_id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
121
122 *id > old_id
123 } else {
124 true
125 }
126 }
127
128 /// Attempts to abort the sending of a frame that is pending in a mailbox.
129 ///
130 /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
131 /// aborted, this function has no effect and returns `false`.
132 ///
133 /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
134 /// returns `true`.
135 #[inline]
136 pub fn abort(&self, bufidx: usize) -> bool {
137 let can = self.regs;
138
139 // Check if there is a request pending to abort
140 if self.has_pending_frame(bufidx) {
141 // Abort Request
142 can.txbcr().write(|w| w.set_cr(bufidx, true));
143
144 // Wait for the abort request to be finished.
145 loop {
146 if can.txbcf().read().cf(bufidx) {
147 // Return false when a transmission has occured
148 break can.txbto().read().to(bufidx) == false;
149 }
150 }
151 } else {
152 false
153 }
154 }
155
156 #[inline]
157 //fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R>
158 pub fn abort_pending_mailbox(&self, bufidx: usize) -> Option<ClassicFrame>
159//where
160 // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
161 {
162 if self.abort(bufidx) {
163 let mailbox = self.tx_buffer_element(bufidx);
164
165 let header_reg = mailbox.header.read();
166 let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
167
168 let len = match header_reg.to_data_length() {
169 DataLength::Fdcan(len) => len,
170 DataLength::Standard(len) => len,
171 };
172 if len as usize > ClassicFrame::MAX_DATA_LEN {
173 return None;
174 }
175
176 //let tx_ram = self.tx_msg_ram();
177 let mut data = [0u8; 64];
178 data_from_tx_buffer(&mut data, mailbox, len as usize);
179
180 let cd = ClassicData::new(&data).unwrap();
181 Some(ClassicFrame::new(Header::new(id, len, header_reg.rtr().bit()), cd))
182 } else {
183 // Abort request failed because the frame was already sent (or being sent) on
184 // the bus. All mailboxes are now free. This can happen for small prescaler
185 // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
186 // has preempted the execution.
187 None
188 }
189 }
190
191 #[inline]
192 //fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R>
193 pub fn abort_pending_fd_mailbox(&self, bufidx: usize) -> Option<FdFrame>
194//where
195 // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
196 {
197 if self.abort(bufidx) {
198 let mailbox = self.tx_buffer_element(bufidx);
199
200 let header_reg = mailbox.header.read();
201 let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
202
203 let len = match header_reg.to_data_length() {
204 DataLength::Fdcan(len) => len,
205 DataLength::Standard(len) => len,
206 };
207 if len as usize > FdFrame::MAX_DATA_LEN {
208 return None;
209 }
210
211 //let tx_ram = self.tx_msg_ram();
212 let mut data = [0u8; 64];
213 data_from_tx_buffer(&mut data, mailbox, len as usize);
214
215 let cd = FdData::new(&data).unwrap();
216
217 let header = if header_reg.fdf().frame_format() == FrameFormat::Fdcan {
218 Header::new_fd(id, len, header_reg.rtr().bit(), header_reg.brs().bit())
219 } else {
220 Header::new(id, len, header_reg.rtr().bit())
221 };
222
223 Some(FdFrame::new(header, cd))
224 } else {
225 // Abort request failed because the frame was already sent (or being sent) on
226 // the bus. All mailboxes are now free. This can happen for small prescaler
227 // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
228 // has preempted the execution.
229 None
230 }
231 }
232
233 /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can
234 /// be preserved.
235 //pub fn transmit_preserve<PTX, P>(
236 pub fn write_classic(&self, frame: &ClassicFrame) -> nb::Result<Option<ClassicFrame>, Infallible> {
237 let queue_is_full = self.tx_queue_is_full();
238
239 let id = frame.header().id();
240
241 // If the queue is full,
242 // Discard the first slot with a lower priority message
243 let (idx, pending_frame) = if queue_is_full {
244 if self.is_available(0, id) {
245 (0, self.abort_pending_mailbox(0))
246 } else if self.is_available(1, id) {
247 (1, self.abort_pending_mailbox(1))
248 } else if self.is_available(2, id) {
249 (2, self.abort_pending_mailbox(2))
250 } else {
251 // For now we bail when there is no lower priority slot available
252 // Can this lead to priority inversion?
253 return Err(nb::Error::WouldBlock);
254 }
255 } else {
256 // Read the Write Pointer
257 let idx = self.regs.txfqs().read().tfqpi();
258
259 (idx, None)
260 };
261
262 self.put_tx_frame(idx as usize, frame.header(), frame.data());
263
264 Ok(pending_frame)
265 }
266
267 /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can
268 /// be preserved.
269 //pub fn transmit_preserve<PTX, P>(
270 pub fn write_fd(&self, frame: &FdFrame) -> nb::Result<Option<FdFrame>, Infallible> {
271 let queue_is_full = self.tx_queue_is_full();
272
273 let id = frame.header().id();
274
275 // If the queue is full,
276 // Discard the first slot with a lower priority message
277 let (idx, pending_frame) = if queue_is_full {
278 if self.is_available(0, id) {
279 (0, self.abort_pending_fd_mailbox(0))
280 } else if self.is_available(1, id) {
281 (1, self.abort_pending_fd_mailbox(1))
282 } else if self.is_available(2, id) {
283 (2, self.abort_pending_fd_mailbox(2))
284 } else {
285 // For now we bail when there is no lower priority slot available
286 // Can this lead to priority inversion?
287 return Err(nb::Error::WouldBlock);
288 }
289 } else {
290 // Read the Write Pointer
291 let idx = self.regs.txfqs().read().tfqpi();
292
293 (idx, None)
294 };
295
296 self.put_tx_frame(idx as usize, frame.header(), frame.data());
297
298 Ok(pending_frame)
299 }
300
301 #[inline]
302 fn reset_msg_ram(&mut self) {
303 self.msg_ram_mut().reset();
304 }
305
306 #[inline]
307 fn enter_init_mode(&mut self) {
308 self.regs.cccr().modify(|w| w.set_init(true));
309 while false == self.regs.cccr().read().init() {}
310 self.regs.cccr().modify(|w| w.set_cce(true));
311 }
312
313 /// Enables or disables loopback mode: Internally connects the TX and RX
314 /// signals together.
315 #[inline]
316 fn set_loopback_mode(&mut self, mode: LoopbackMode) {
317 let (test, mon, lbck) = match mode {
318 LoopbackMode::None => (false, false, false),
319 LoopbackMode::Internal => (true, true, true),
320 LoopbackMode::External => (true, false, true),
321 };
322
323 self.set_test_mode(test);
324 self.set_bus_monitoring_mode(mon);
325
326 self.regs.test().modify(|w| w.set_lbck(lbck));
327 }
328
329 /// Enables or disables silent mode: Disconnects the TX signal from the pin.
330 #[inline]
331 fn set_bus_monitoring_mode(&mut self, enabled: bool) {
332 self.regs.cccr().modify(|w| w.set_mon(enabled));
333 }
334
335 #[inline]
336 fn set_restricted_operations(&mut self, enabled: bool) {
337 self.regs.cccr().modify(|w| w.set_asm(enabled));
338 }
339
340 #[inline]
341 fn set_normal_operations(&mut self, _enabled: bool) {
342 self.set_loopback_mode(LoopbackMode::None);
343 }
344
345 #[inline]
346 fn set_test_mode(&mut self, enabled: bool) {
347 self.regs.cccr().modify(|w| w.set_test(enabled));
348 }
349
350 #[inline]
351 fn set_power_down_mode(&mut self, enabled: bool) {
352 self.regs.cccr().modify(|w| w.set_csr(enabled));
353 while self.regs.cccr().read().csa() != enabled {}
354 }
355
356 /// Moves out of PoweredDownMode and into ConfigMode
357 #[inline]
358 pub fn into_config_mode(mut self, _config: FdCanConfig) {
359 self.set_power_down_mode(false);
360 self.enter_init_mode();
361
362 self.reset_msg_ram();
363
364 // check the FDCAN core matches our expections
365 assert!(
366 self.regs.crel().read().rel() == 3,
367 "Expected FDCAN core major release 3"
368 );
369 assert!(
370 self.regs.endn().read().etv() == 0x87654321_u32,
371 "Error reading endianness test value from FDCAN core"
372 );
373
374 // Framework specific settings are set here
375
376 // set TxBuffer to Queue Mode
377 self.regs.txbc().write(|w| w.set_tfqm(true));
378
379 // set standard filters list size to 28
380 // set extended filters list size to 8
381 // REQUIRED: we use the memory map as if these settings are set
382 // instead of re-calculating them.
383 #[cfg(not(stm32h7))]
384 {
385 self.regs.rxgfc().modify(|w| {
386 w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX);
387 w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX);
388 });
389 }
390 #[cfg(stm32h7)]
391 {
392 self.regs
393 .sidfc()
394 .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX));
395 self.regs
396 .xidfc()
397 .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX));
398 }
399
400 /*
401 for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX {
402 self.set_standard_filter((fid as u8).into(), StandardFilter::disable());
403 }
404 for fid in 0..Ecrate::can::message_ram::XTENDED_FILTER_MAX {
405 self.set_extended_filter(fid.into(), ExtendedFilter::disable());
406 }
407 */
408 }
409
410 /// Disables the CAN interface and returns back the raw peripheral it was created from.
411 #[inline]
412 pub fn free(mut self) {
413 //self.disable_interrupts(Interrupts::all());
414
415 //TODO check this!
416 self.enter_init_mode();
417 self.set_power_down_mode(true);
418 //self.control.instance
419 }
420
421 /// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
422 #[inline]
423 pub fn apply_config(&mut self, config: FdCanConfig) {
424 self.set_data_bit_timing(config.dbtr);
425 self.set_nominal_bit_timing(config.nbtr);
426 self.set_automatic_retransmit(config.automatic_retransmit);
427 self.set_transmit_pause(config.transmit_pause);
428 self.set_frame_transmit(config.frame_transmit);
429 //self.set_interrupt_line_config(config.interrupt_line_config);
430 self.set_non_iso_mode(config.non_iso_mode);
431 self.set_edge_filtering(config.edge_filtering);
432 self.set_protocol_exception_handling(config.protocol_exception_handling);
433 self.set_global_filter(config.global_filter);
434 }
435
436 #[inline]
437 fn leave_init_mode(&mut self, config: FdCanConfig) {
438 self.apply_config(config);
439
440 self.regs.cccr().modify(|w| w.set_cce(false));
441 self.regs.cccr().modify(|w| w.set_init(false));
442 while self.regs.cccr().read().init() == true {}
443 }
444
445 /// Moves out of ConfigMode and into InternalLoopbackMode
446 #[inline]
447 pub fn into_internal_loopback(mut self, config: FdCanConfig) {
448 self.set_loopback_mode(LoopbackMode::Internal);
449 self.leave_init_mode(config);
450 }
451
452 /// Moves out of ConfigMode and into ExternalLoopbackMode
453 #[inline]
454 pub fn into_external_loopback(mut self, config: FdCanConfig) {
455 self.set_loopback_mode(LoopbackMode::External);
456 self.leave_init_mode(config);
457 }
458
459 /// Moves out of ConfigMode and into RestrictedOperationMode
460 #[inline]
461 pub fn into_restricted(mut self, config: FdCanConfig) {
462 self.set_restricted_operations(true);
463 self.leave_init_mode(config);
464 }
465
466 /// Moves out of ConfigMode and into NormalOperationMode
467 #[inline]
468 pub fn into_normal(mut self, config: FdCanConfig) {
469 self.set_normal_operations(true);
470 self.leave_init_mode(config);
471 }
472
473 /// Moves out of ConfigMode and into BusMonitoringMode
474 #[inline]
475 pub fn into_bus_monitoring(mut self, config: FdCanConfig) {
476 self.set_bus_monitoring_mode(true);
477 self.leave_init_mode(config);
478 }
479
480 /// Moves out of ConfigMode and into Testmode
481 #[inline]
482 pub fn into_test_mode(mut self, config: FdCanConfig) {
483 self.set_test_mode(true);
484 self.leave_init_mode(config);
485 }
486
487 /// Moves out of ConfigMode and into PoweredDownmode
488 #[inline]
489 pub fn into_powered_down(mut self, config: FdCanConfig) {
490 self.set_power_down_mode(true);
491 self.leave_init_mode(config);
492 }
493
494 /// Configures the bit timings.
495 ///
496 /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
497 /// parameters as follows:
498 ///
499 /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
500 /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
501 /// - *Sample Point*: Should normally be left at the default value of 87.5%.
502 /// - *SJW*: Should normally be left at the default value of 1.
503 ///
504 /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
505 /// parameter to this method.
506 #[inline]
507 pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) {
508 //self.control.config.nbtr = btr;
509
510 self.regs.nbtp().write(|w| {
511 w.set_nbrp(btr.nbrp() - 1);
512 w.set_ntseg1(btr.ntseg1() - 1);
513 w.set_ntseg2(btr.ntseg2() - 1);
514 w.set_nsjw(btr.nsjw() - 1);
515 });
516 }
517
518 /// Configures the data bit timings for the FdCan Variable Bitrates.
519 /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
520 #[inline]
521 pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) {
522 //self.control.config.dbtr = btr;
523
524 self.regs.dbtp().write(|w| {
525 w.set_dbrp(btr.dbrp() - 1);
526 w.set_dtseg1(btr.dtseg1() - 1);
527 w.set_dtseg2(btr.dtseg2() - 1);
528 w.set_dsjw(btr.dsjw() - 1);
529 });
530 }
531
532 /// Enables or disables automatic retransmission of messages
533 ///
534 /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
535 /// util it can be sent. Otherwise, it will try only once to send each frame.
536 ///
537 /// Automatic retransmission is enabled by default.
538 #[inline]
539 pub fn set_automatic_retransmit(&mut self, enabled: bool) {
540 self.regs.cccr().modify(|w| w.set_dar(!enabled));
541 //self.control.config.automatic_retransmit = enabled;
542 }
543
544 /// Configures the transmit pause feature. See
545 /// [`FdCanConfig::set_transmit_pause`]
546 #[inline]
547 pub fn set_transmit_pause(&mut self, enabled: bool) {
548 self.regs.cccr().modify(|w| w.set_txp(!enabled));
549 //self.control.config.transmit_pause = enabled;
550 }
551
552 /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`]
553 #[inline]
554 pub fn set_non_iso_mode(&mut self, enabled: bool) {
555 self.regs.cccr().modify(|w| w.set_niso(enabled));
556 //self.control.config.non_iso_mode = enabled;
557 }
558
559 /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`]
560 #[inline]
561 pub fn set_edge_filtering(&mut self, enabled: bool) {
562 self.regs.cccr().modify(|w| w.set_efbi(enabled));
563 //self.control.config.edge_filtering = enabled;
564 }
565
566 /// Configures frame transmission mode. See
567 /// [`FdCanConfig::set_frame_transmit`]
568 #[inline]
569 pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) {
570 let (fdoe, brse) = match fts {
571 FrameTransmissionConfig::ClassicCanOnly => (false, false),
572 FrameTransmissionConfig::AllowFdCan => (true, false),
573 FrameTransmissionConfig::AllowFdCanAndBRS => (true, true),
574 };
575
576 self.regs.cccr().modify(|w| {
577 w.set_fdoe(fdoe);
578 #[cfg(stm32h7)]
579 w.set_bse(brse);
580 #[cfg(not(stm32h7))]
581 w.set_brse(brse);
582 });
583
584 //self.control.config.frame_transmit = fts;
585 }
586
587 /// Sets the protocol exception handling on/off
588 #[inline]
589 pub fn set_protocol_exception_handling(&mut self, enabled: bool) {
590 self.regs.cccr().modify(|w| w.set_pxhd(!enabled));
591
592 //self.control.config.protocol_exception_handling = enabled;
593 }
594
595 /// Configures and resets the timestamp counter
596 #[inline]
597 pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) {
598 #[cfg(stm32h7)]
599 let (tcp, tss) = match select {
600 TimestampSource::None => (0, 0),
601 TimestampSource::Prescaler(p) => (p as u8, 1),
602 TimestampSource::FromTIM3 => (0, 2),
603 };
604
605 #[cfg(not(stm32h7))]
606 let (tcp, tss) = match select {
607 TimestampSource::None => (0, stm32_metapac::can::vals::Tss::ZERO),
608 TimestampSource::Prescaler(p) => (p as u8, stm32_metapac::can::vals::Tss::INCREMENT),
609 TimestampSource::FromTIM3 => (0, stm32_metapac::can::vals::Tss::EXTERNAL),
610 };
611
612 self.regs.tscc().write(|w| {
613 w.set_tcp(tcp);
614 w.set_tss(tss);
615 });
616
617 //self.control.config.timestamp_source = select;
618 }
619
620 #[cfg(not(stm32h7))]
621 /// Configures the global filter settings
622 #[inline]
623 pub fn set_global_filter(&mut self, filter: GlobalFilter) {
624 let anfs = match filter.handle_standard_frames {
625 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0,
626 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1,
627 crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfs::REJECT,
628 };
629 let anfe = match filter.handle_extended_frames {
630 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_0,
631 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_1,
632 crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfe::REJECT,
633 };
634
635 self.regs.rxgfc().modify(|w| {
636 w.set_anfs(anfs);
637 w.set_anfe(anfe);
638 w.set_rrfs(filter.reject_remote_standard_frames);
639 w.set_rrfe(filter.reject_remote_extended_frames);
640 });
641 }
642
643 #[cfg(stm32h7)]
644 /// Configures the global filter settings
645 #[inline]
646 pub fn set_global_filter(&mut self, filter: GlobalFilter) {
647 let anfs = match filter.handle_standard_frames {
648 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0,
649 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1,
650 crate::can::fd::config::NonMatchingFilter::Reject => 2,
651 };
652
653 let anfe = match filter.handle_extended_frames {
654 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0,
655 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1,
656 crate::can::fd::config::NonMatchingFilter::Reject => 2,
657 };
658
659 self.regs.gfc().modify(|w| {
660 w.set_anfs(anfs);
661 w.set_anfe(anfe);
662 w.set_rrfs(filter.reject_remote_standard_frames);
663 w.set_rrfe(filter.reject_remote_extended_frames);
664 });
665 }
666}
667
668fn make_id(id: u32, extended: bool) -> embedded_can::Id {
669 if extended {
670 embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) })
671 } else {
672 embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked((id & 0x000007FF) as u16) })
673 }
674}
675
676fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) {
677 let (id, id_type) = match header.id() {
678 embedded_can::Id::Standard(id) => (id.as_raw() as u32, IdType::StandardId),
679 embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId),
680 };
681
682 // Use FDCAN only for DLC > 8. FDCAN users can revise this if required.
683 let frame_format = if header.len() > 8 || header.fdcan() {
684 FrameFormat::Fdcan
685 } else {
686 FrameFormat::Standard
687 };
688 let brs = header.len() > 8 || header.bit_rate_switching();
689
690 mailbox.header.write(|w| {
691 unsafe { w.id().bits(id) }
692 .rtr()
693 .bit(header.len() == 0 && header.rtr())
694 .xtd()
695 .set_id_type(id_type)
696 .set_len(DataLength::new(header.len(), frame_format))
697 .set_event(Event::NoEvent)
698 .fdf()
699 .set_format(frame_format)
700 .brs()
701 .bit(brs)
702 //esi.set_error_indicator(//TODO//)
703 });
704}
705
706fn put_tx_data(mailbox: &mut TxBufferElement, buffer: &[u8]) {
707 let mut lbuffer = [0_u32; 16];
708 let len = buffer.len();
709 let data = unsafe { slice::from_raw_parts_mut(lbuffer.as_mut_ptr() as *mut u8, len) };
710 data[..len].copy_from_slice(&buffer[..len]);
711 let data_len = ((len) + 3) / 4;
712 for (register, byte) in mailbox.data.iter_mut().zip(lbuffer[..data_len].iter()) {
713 unsafe { register.write(*byte) };
714 }
715}
716
717fn data_from_fifo(buffer: &mut [u8], mailbox: &RxFifoElement, len: usize) {
718 for (i, register) in mailbox.data.iter().enumerate() {
719 let register_value = register.read();
720 let register_bytes = unsafe { slice::from_raw_parts(&register_value as *const u32 as *const u8, 4) };
721 let num_bytes = (len) - i * 4;
722 if num_bytes <= 4 {
723 buffer[i * 4..i * 4 + num_bytes].copy_from_slice(&register_bytes[..num_bytes]);
724 break;
725 }
726 buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes);
727 }
728}
729
730fn data_from_tx_buffer(buffer: &mut [u8], mailbox: &TxBufferElement, len: usize) {
731 for (i, register) in mailbox.data.iter().enumerate() {
732 let register_value = register.read();
733 let register_bytes = unsafe { slice::from_raw_parts(&register_value as *const u32 as *const u8, 4) };
734 let num_bytes = (len) - i * 4;
735 if num_bytes <= 4 {
736 buffer[i * 4..i * 4 + num_bytes].copy_from_slice(&register_bytes[..num_bytes]);
737 break;
738 }
739 buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes);
740 }
741}
742
743impl From<&RxFifoElement> for ClassicFrame {
744 fn from(mailbox: &RxFifoElement) -> Self {
745 let header_reg = mailbox.header.read();
746
747 let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
748 let dlc = header_reg.to_data_length().len();
749 let len = dlc as usize;
750
751 let mut buffer: [u8; 64] = [0; 64];
752 data_from_fifo(&mut buffer, mailbox, len);
753 let data = ClassicData::new(&buffer[0..len]);
754 let header = Header::new(id, dlc, header_reg.rtr().bits());
755 ClassicFrame::new(header, data.unwrap())
756 }
757}
758
759fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> {
760 let header_reg = mailbox.header.read();
761
762 let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
763 let dlc = header_reg.to_data_length().len();
764 let len = dlc as usize;
765 let timestamp = header_reg.txts().bits;
766 if len > buffer.len() {
767 return None;
768 }
769 data_from_fifo(buffer, mailbox, len);
770 let header = if header_reg.fdf().bits {
771 Header::new_fd(id, dlc, header_reg.rtr().bits(), header_reg.brs().bits())
772 } else {
773 Header::new(id, dlc, header_reg.rtr().bits())
774 };
775 Some((header, timestamp))
776}
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index faf4af73f..b94e42707 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -1,16 +1,15 @@
1#[allow(unused_variables)]
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::ops::{Deref, DerefMut};
4use core::task::Poll; 4use core::task::Poll;
5 5
6pub mod fd;
6use cfg_if::cfg_if; 7use cfg_if::cfg_if;
7use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
8pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader}; 9use fd::config::*;
9pub use fdcan::id::{ExtendedId, Id, StandardId}; 10use fd::filter::*;
10use fdcan::message_ram::RegisterBlock;
11use fdcan::{self, LastErrorCode};
12pub use fdcan::{config, filter};
13 11
12use crate::can::fd::peripheral::Registers;
14use crate::gpio::sealed::AFType; 13use crate::gpio::sealed::AFType;
15use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
16use crate::rcc::RccPeripheral; 15use crate::rcc::RccPeripheral;
@@ -20,127 +19,14 @@ pub mod enums;
20use enums::*; 19use enums::*;
21pub mod util; 20pub mod util;
22 21
23/// CAN Frame returned by read 22pub mod frame;
24pub struct RxFrame { 23use frame::*;
25 /// CAN Header info: frame ID, data length and other meta
26 pub header: RxFrameInfo,
27 /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
28 pub data: Data,
29 /// Reception time.
30 #[cfg(feature = "time")]
31 pub timestamp: embassy_time::Instant,
32}
33
34/// CAN frame used for write
35pub struct TxFrame {
36 /// CAN Header info: frame ID, data length and other meta
37 pub header: TxFrameHeader,
38 /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
39 pub data: Data,
40}
41
42impl TxFrame {
43 /// Create new TX frame from header and data
44 pub fn new(header: TxFrameHeader, data: &[u8]) -> Option<Self> {
45 if data.len() < header.len as usize {
46 return None;
47 }
48
49 let Some(data) = Data::new(data) else { return None };
50
51 Some(TxFrame { header, data })
52 }
53
54 fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option<Self> {
55 let mut data = [0u8; 64];
56
57 for i in 0..data32.len() {
58 data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes());
59 }
60
61 let Some(data) = Data::new(&data) else { return None };
62
63 Some(TxFrame { header, data })
64 }
65
66 /// Access frame data. Slice length will match header.
67 pub fn data(&self) -> &[u8] {
68 &self.data.bytes[..(self.header.len as usize)]
69 }
70}
71
72impl RxFrame {
73 pub(crate) fn new(
74 header: RxFrameInfo,
75 data: &[u8],
76 #[cfg(feature = "time")] timestamp: embassy_time::Instant,
77 ) -> Self {
78 let data = Data::new(&data).unwrap_or_else(|| Data::empty());
79
80 RxFrame {
81 header,
82 data,
83 #[cfg(feature = "time")]
84 timestamp,
85 }
86 }
87
88 /// Access frame data. Slice length will match header.
89 pub fn data(&self) -> &[u8] {
90 &self.data.bytes[..(self.header.len as usize)]
91 }
92}
93
94/// Payload of a (FD)CAN data frame.
95///
96/// Contains 0 to 64 Bytes of data.
97#[derive(Debug, Copy, Clone)]
98pub struct Data {
99 pub(crate) bytes: [u8; 64],
100}
101
102impl Data {
103 /// Creates a data payload from a raw byte slice.
104 ///
105 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
106 /// cannot be represented with an FDCAN DLC.
107 pub fn new(data: &[u8]) -> Option<Self> {
108 if !Data::is_valid_len(data.len()) {
109 return None;
110 }
111
112 let mut bytes = [0; 64];
113 bytes[..data.len()].copy_from_slice(data);
114
115 Some(Self { bytes })
116 }
117
118 /// Raw read access to data.
119 pub fn raw(&self) -> &[u8] {
120 &self.bytes
121 }
122 24
123 /// Checks if the length can be encoded in FDCAN DLC field. 25#[cfg(feature = "time")]
124 pub const fn is_valid_len(len: usize) -> bool { 26type Timestamp = embassy_time::Instant;
125 match len {
126 0..=8 => true,
127 12 => true,
128 16 => true,
129 20 => true,
130 24 => true,
131 32 => true,
132 48 => true,
133 64 => true,
134 _ => false,
135 }
136 }
137 27
138 /// Creates an empty data payload containing 0 bytes. 28#[cfg(not(feature = "time"))]
139 #[inline] 29type Timestamp = u16;
140 pub const fn empty() -> Self {
141 Self { bytes: [0; 64] }
142 }
143}
144 30
145/// Interrupt handler channel 0. 31/// Interrupt handler channel 0.
146pub struct IT0InterruptHandler<T: Instance> { 32pub struct IT0InterruptHandler<T: Instance> {
@@ -172,7 +58,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
172 } 58 }
173 59
174 if ir.rfn(0) { 60 if ir.rfn(0) {
175 regs.ir().write(|w| w.set_rfn(0, true)); 61 let fifonr = 0 as usize;
62 regs.ir().write(|w| w.set_rfn(fifonr, true));
63
176 T::state().rx_waker.wake(); 64 T::state().rx_waker.wake();
177 } 65 }
178 66
@@ -192,44 +80,82 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup
192 unsafe fn on_interrupt() {} 80 unsafe fn on_interrupt() {}
193} 81}
194 82
195impl BusError { 83/// Allows for Transmit Operations
196 fn try_from(lec: LastErrorCode) -> Option<BusError> { 84pub trait Transmit {}
197 match lec { 85/// Allows for Receive Operations
198 LastErrorCode::AckError => Some(BusError::Acknowledge), 86pub trait Receive {}
199 // `0` data bit encodes a dominant state. `1` data bit is recessive. 87
200 // Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1 88/// Allows for the FdCan Instance to be released or to enter ConfigMode
201 LastErrorCode::Bit0Error => Some(BusError::BitRecessive), 89pub struct PoweredDownMode;
202 LastErrorCode::Bit1Error => Some(BusError::BitDominant), 90/// Allows for the configuration for the Instance
203 LastErrorCode::CRCError => Some(BusError::Crc), 91pub struct ConfigMode;
204 LastErrorCode::FormError => Some(BusError::Form), 92/// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without
205 LastErrorCode::StuffError => Some(BusError::Stuff), 93/// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this
206 _ => None, 94/// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held
207 } 95/// recessive.
208 } 96pub struct InternalLoopbackMode;
209} 97impl Transmit for InternalLoopbackMode {}
98impl Receive for InternalLoopbackMode {}
99/// This mode is provided for hardware self-test. To be independent from external stimulation,
100/// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a
101/// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal
102/// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX
103/// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the
104/// FDCAN_TX transmit pin.
105pub struct ExternalLoopbackMode;
106impl Transmit for ExternalLoopbackMode {}
107impl Receive for ExternalLoopbackMode {}
108/// The normal use of the FdCan instance after configurations
109pub struct NormalOperationMode;
110impl Transmit for NormalOperationMode {}
111impl Receive for NormalOperationMode {}
112/// In Restricted operation mode the node is able to receive data and remote frames and to give
113/// acknowledge to valid frames, but it does not send data frames, remote frames, active error
114/// frames, or overload frames. In case of an error condition or overload condition, it does not
115/// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize
116/// itself to the CAN communication. The error counters for transmit and receive are frozen while
117/// error logging (can_errors) is active. TODO: automatically enter in this mode?
118pub struct RestrictedOperationMode;
119impl Receive for RestrictedOperationMode {}
120/// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring),
121/// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a
122/// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is
123/// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is
124/// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive
125/// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring
126/// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission
127/// of dominant bits.
128pub struct BusMonitoringMode;
129impl Receive for BusMonitoringMode {}
130/// Test mode must be used for production tests or self test only. The software control for
131/// FDCAN_TX pin interferes with all CAN protocol functions. It is not recommended to use test
132/// modes for application.
133pub struct TestMode;
210 134
211/// Operating modes trait 135/// Operating modes trait
212pub trait FdcanOperatingMode {} 136pub trait FdcanOperatingMode {}
213impl FdcanOperatingMode for fdcan::PoweredDownMode {} 137impl FdcanOperatingMode for PoweredDownMode {}
214impl FdcanOperatingMode for fdcan::ConfigMode {} 138impl FdcanOperatingMode for ConfigMode {}
215impl FdcanOperatingMode for fdcan::InternalLoopbackMode {} 139impl FdcanOperatingMode for InternalLoopbackMode {}
216impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {} 140impl FdcanOperatingMode for ExternalLoopbackMode {}
217impl FdcanOperatingMode for fdcan::NormalOperationMode {} 141impl FdcanOperatingMode for NormalOperationMode {}
218impl FdcanOperatingMode for fdcan::RestrictedOperationMode {} 142impl FdcanOperatingMode for RestrictedOperationMode {}
219impl FdcanOperatingMode for fdcan::BusMonitoringMode {} 143impl FdcanOperatingMode for BusMonitoringMode {}
220impl FdcanOperatingMode for fdcan::TestMode {} 144impl FdcanOperatingMode for TestMode {}
221 145
222/// FDCAN Instance 146/// FDCAN Instance
223pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { 147pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> {
148 config: crate::can::fd::config::FdCanConfig,
224 /// Reference to internals. 149 /// Reference to internals.
225 pub can: fdcan::FdCan<FdcanInstance<'d, T>, M>, 150 instance: FdcanInstance<'d, T>,
151 _mode: PhantomData<M>,
226 ns_per_timer_tick: u64, // For FDCAN internal timer 152 ns_per_timer_tick: u64, // For FDCAN internal timer
227} 153}
228 154
229fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> u64 { 155fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
230 match mode { 156 match mode {
231 // Use timestamp from Rx FIFO to adjust timestamp reported to user 157 // Use timestamp from Rx FIFO to adjust timestamp reported to user
232 config::FrameTransmissionConfig::ClassicCanOnly => { 158 crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => {
233 let freq = T::frequency(); 159 let freq = T::frequency();
234 let prescale: u64 = 160 let prescale: u64 =
235 ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; 161 ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64;
@@ -242,17 +168,22 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) ->
242} 168}
243 169
244#[cfg(feature = "time")] 170#[cfg(feature = "time")]
245fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant { 171fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
246 let now_embassy = embassy_time::Instant::now(); 172 let now_embassy = embassy_time::Instant::now();
247 if ns_per_timer_tick == 0 { 173 if ns_per_timer_tick == 0 {
248 return now_embassy; 174 return now_embassy;
249 } 175 }
250 let now_can = { T::regs().tscv().read().tsc() }; 176 let cantime = { T::regs().tscv().read().tsc() };
251 let delta = now_can.overflowing_sub(ts_val).0 as u64; 177 let delta = cantime.overflowing_sub(ts_val).0 as u64;
252 let ns = ns_per_timer_tick * delta as u64; 178 let ns = ns_per_timer_tick * delta as u64;
253 now_embassy - embassy_time::Duration::from_nanos(ns) 179 now_embassy - embassy_time::Duration::from_nanos(ns)
254} 180}
255 181
182#[cfg(not(feature = "time"))]
183fn calc_timestamp<T: Instance>(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
184 ts_val
185}
186
256fn curr_error<T: Instance>() -> Option<BusError> { 187fn curr_error<T: Instance>() -> Option<BusError> {
257 let err = { T::regs().psr().read() }; 188 let err = { T::regs().psr().read() };
258 if err.bo() { 189 if err.bo() {
@@ -269,14 +200,14 @@ fn curr_error<T: Instance>() -> Option<BusError> {
269 let lec = err.lec().to_bits(); 200 let lec = err.lec().to_bits();
270 } 201 }
271 } 202 }
272 if let Ok(err) = LastErrorCode::try_from(lec) { 203 if let Ok(err) = BusError::try_from(lec) {
273 return BusError::try_from(err); 204 return Some(err);
274 } 205 }
275 } 206 }
276 None 207 None
277} 208}
278 209
279impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { 210impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> {
280 /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. 211 /// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
281 /// You must call [Fdcan::enable_non_blocking] to use the peripheral. 212 /// You must call [Fdcan::enable_non_blocking] to use the peripheral.
282 pub fn new( 213 pub fn new(
@@ -286,7 +217,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
286 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> 217 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
287 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> 218 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
288 + 'd, 219 + 'd,
289 ) -> Fdcan<'d, T, fdcan::ConfigMode> { 220 ) -> Fdcan<'d, T, ConfigMode> {
290 into_ref!(peri, rx, tx); 221 into_ref!(peri, rx, tx);
291 222
292 rx.set_as_af(rx.af_num(), AFType::Input); 223 rx.set_as_af(rx.af_num(), AFType::Input);
@@ -294,11 +225,12 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
294 225
295 T::enable_and_reset(); 226 T::enable_and_reset();
296 227
228 let mut config = crate::can::fd::config::FdCanConfig::default();
229 T::registers().into_config_mode(config);
230
297 rx.set_as_af(rx.af_num(), AFType::Input); 231 rx.set_as_af(rx.af_num(), AFType::Input);
298 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 232 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
299 233
300 let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode();
301
302 T::configure_msg_ram(); 234 T::configure_msg_ram();
303 unsafe { 235 unsafe {
304 // Enable timestamping 236 // Enable timestamping
@@ -308,6 +240,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
308 .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); 240 .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT));
309 #[cfg(stm32h7)] 241 #[cfg(stm32h7)]
310 T::regs().tscc().write(|w| w.set_tss(0x01)); 242 T::regs().tscc().write(|w| w.set_tss(0x01));
243 config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
311 244
312 T::IT0Interrupt::unpend(); // Not unsafe 245 T::IT0Interrupt::unpend(); // Not unsafe
313 T::IT0Interrupt::enable(); 246 T::IT0Interrupt::enable();
@@ -320,38 +253,104 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
320 T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); 253 T::regs().txbtie().write(|w| w.0 = 0xffff_ffff);
321 } 254 }
322 255
323 can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); 256 T::regs().ie().modify(|w| {
324 can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg); 257 w.set_rfne(0, true); // Rx Fifo 0 New Msg
325 can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete); 258 w.set_rfne(1, true); // Rx Fifo 1 New Msg
326 can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); 259 w.set_tce(true); // Tx Complete
327 can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true); 260 });
261 T::regs().ile().modify(|w| {
262 w.set_eint0(true); // Interrupt Line 0
263 w.set_eint1(true); // Interrupt Line 1
264 });
265
266 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(config.frame_transmit);
267 Self {
268 config,
269 instance: FdcanInstance(peri),
270 _mode: PhantomData::<ConfigMode>,
271 ns_per_timer_tick,
272 }
273 }
274
275 /// Get configuration
276 pub fn config(&self) -> crate::can::fd::config::FdCanConfig {
277 return self.config;
278 }
328 279
329 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(can.get_config().frame_transmit); 280 /// Set configuration
330 Self { can, ns_per_timer_tick } 281 pub fn set_config(&mut self, config: crate::can::fd::config::FdCanConfig) {
282 self.config = config;
331 } 283 }
332 284
333 /// Configures the bit timings calculated from supplied bitrate. 285 /// Configures the bit timings calculated from supplied bitrate.
334 pub fn set_bitrate(&mut self, bitrate: u32) { 286 pub fn set_bitrate(&mut self, bitrate: u32) {
335 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); 287 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
336 self.can.set_nominal_bit_timing(config::NominalBitTiming { 288
289 let nbtr = crate::can::fd::config::NominalBitTiming {
337 sync_jump_width: bit_timing.sync_jump_width, 290 sync_jump_width: bit_timing.sync_jump_width,
338 prescaler: bit_timing.prescaler, 291 prescaler: bit_timing.prescaler,
339 seg1: bit_timing.seg1, 292 seg1: bit_timing.seg1,
340 seg2: bit_timing.seg2, 293 seg2: bit_timing.seg2,
341 }); 294 };
295 self.config = self.config.set_nominal_bit_timing(nbtr);
296 }
297
298 /// Configures the bit timings for VBR data calculated from supplied bitrate.
299 pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) {
300 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
301 // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M
302 let nbtr = crate::can::fd::config::DataBitTiming {
303 transceiver_delay_compensation,
304 sync_jump_width: bit_timing.sync_jump_width,
305 prescaler: bit_timing.prescaler,
306 seg1: bit_timing.seg1,
307 seg2: bit_timing.seg2,
308 };
309 self.config.frame_transmit = FrameTransmissionConfig::AllowFdCanAndBRS;
310 self.config = self.config.set_data_bit_timing(nbtr);
311 }
312
313 /// Set an Standard Address CAN filter into slot 'id'
314 #[inline]
315 pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) {
316 T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
317 }
318
319 /// Set an array of Standard Address CAN filters and overwrite the current set
320 pub fn set_standard_filters(&mut self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
321 for (i, f) in filters.iter().enumerate() {
322 T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
323 }
324 }
325
326 /// Set an Extended Address CAN filter into slot 'id'
327 #[inline]
328 pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
329 T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
330 }
331
332 /// Set an array of Extended Address CAN filters and overwrite the current set
333 pub fn set_extended_filters(&mut self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
334 for (i, f) in filters.iter().enumerate() {
335 T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
336 }
342 } 337 }
343} 338}
344 339
345macro_rules! impl_transition { 340macro_rules! impl_transition {
346 ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => { 341 ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => {
347 impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> { 342 impl<'d, T: Instance> Fdcan<'d, T, $from_mode> {
348 /// Transition from $from_mode:ident mode to $to_mode:ident mode 343 /// Transition from $from_mode:ident mode to $to_mode:ident mode
349 pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> { 344 pub fn $name(self) -> Fdcan<'d, T, $to_mode> {
350 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.can.get_config().frame_transmit); 345 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
351 Fdcan { 346 T::registers().$func(self.config);
352 can: self.can.$func(), 347 let ret = Fdcan {
348 config: self.config,
349 instance: self.instance,
350 _mode: PhantomData::<$to_mode>,
353 ns_per_timer_tick, 351 ns_per_timer_tick,
354 } 352 };
353 ret
355 } 354 }
356 } 355 }
357 }; 356 };
@@ -376,23 +375,36 @@ impl_transition!(
376 375
377impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M> 376impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M>
378where 377where
379 M: fdcan::Transmit, 378 M: Transmit,
380 M: fdcan::Receive, 379 M: Receive,
381{ 380{
381 /// Flush one of the TX mailboxes.
382 pub async fn flush(&self, idx: usize) {
383 poll_fn(|cx| {
384 T::state().tx_waker.register(cx.waker());
385 if idx > 3 {
386 panic!("Bad mailbox");
387 }
388 let idx = 1 << idx;
389 if !T::regs().txbrp().read().trp(idx) {
390 return Poll::Ready(());
391 }
392
393 Poll::Pending
394 })
395 .await;
396 }
397
382 /// Queues the message to be sent but exerts backpressure. If a lower-priority 398 /// Queues the message to be sent but exerts backpressure. If a lower-priority
383 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 399 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
384 /// can be replaced, this call asynchronously waits for a frame to be successfully 400 /// can be replaced, this call asynchronously waits for a frame to be successfully
385 /// transmitted, then tries again. 401 /// transmitted, then tries again.
386 pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> { 402 pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
387 poll_fn(|cx| { 403 poll_fn(|cx| {
388 T::state().tx_waker.register(cx.waker()); 404 T::state().tx_waker.register(cx.waker());
389 if let Ok(dropped) = self 405
390 .can 406 if let Ok(dropped) = T::registers().write_classic(frame) {
391 .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { 407 return Poll::Ready(dropped);
392 TxFrame::from_preserved(hdr, data32)
393 })
394 {
395 return Poll::Ready(dropped.flatten());
396 } 408 }
397 409
398 // Couldn't replace any lower priority frames. Need to wait for some mailboxes 410 // Couldn't replace any lower priority frames. Need to wait for some mailboxes
@@ -402,53 +414,58 @@ where
402 .await 414 .await
403 } 415 }
404 416
405 /// Flush one of the TX mailboxes. 417 /// Returns the next received message frame
406 pub async fn flush(&self, mb: fdcan::Mailbox) { 418 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
419 poll_fn(|cx| {
420 T::state().err_waker.register(cx.waker());
421 T::state().rx_waker.register(cx.waker());
422
423 if let Some((msg, ts)) = T::registers().read_classic(0) {
424 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
425 return Poll::Ready(Ok((msg, ts)));
426 } else if let Some((msg, ts)) = T::registers().read_classic(1) {
427 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
428 return Poll::Ready(Ok((msg, ts)));
429 } else if let Some(err) = curr_error::<T>() {
430 // TODO: this is probably wrong
431 return Poll::Ready(Err(err));
432 }
433 Poll::Pending
434 })
435 .await
436 }
437
438 /// Queues the message to be sent but exerts backpressure. If a lower-priority
439 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
440 /// can be replaced, this call asynchronously waits for a frame to be successfully
441 /// transmitted, then tries again.
442 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
407 poll_fn(|cx| { 443 poll_fn(|cx| {
408 T::state().tx_waker.register(cx.waker()); 444 T::state().tx_waker.register(cx.waker());
409 445
410 let idx: u8 = mb.into(); 446 if let Ok(dropped) = T::registers().write_fd(frame) {
411 let idx = 1 << idx; 447 return Poll::Ready(dropped);
412 if !T::regs().txbrp().read().trp(idx) {
413 return Poll::Ready(());
414 } 448 }
415 449
450 // Couldn't replace any lower priority frames. Need to wait for some mailboxes
451 // to clear.
416 Poll::Pending 452 Poll::Pending
417 }) 453 })
418 .await; 454 .await
419 } 455 }
420 456
421 /// Returns the next received message frame 457 /// Returns the next received message frame
422 pub async fn read(&mut self) -> Result<RxFrame, BusError> { 458 pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
423 poll_fn(|cx| { 459 poll_fn(|cx| {
424 T::state().err_waker.register(cx.waker()); 460 T::state().err_waker.register(cx.waker());
425 T::state().rx_waker.register(cx.waker()); 461 T::state().rx_waker.register(cx.waker());
426 462
427 let mut buffer: [u8; 64] = [0; 64]; 463 if let Some((msg, ts)) = T::registers().read_fd(0) {
428 if let Ok(rx) = self.can.receive0(&mut buffer) { 464 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
429 // rx: fdcan::ReceiveOverrun<RxFrameInfo> 465 return Poll::Ready(Ok((msg, ts)));
430 // TODO: report overrun? 466 } else if let Some((msg, ts)) = T::registers().read_fd(1) {
431 // for now we just drop it 467 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
432 468 return Poll::Ready(Ok((msg, ts)));
433 let frame: RxFrame = RxFrame::new(
434 rx.unwrap(),
435 &buffer,
436 #[cfg(feature = "time")]
437 calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
438 );
439 return Poll::Ready(Ok(frame));
440 } else if let Ok(rx) = self.can.receive1(&mut buffer) {
441 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
442 // TODO: report overrun?
443 // for now we just drop it
444
445 let frame: RxFrame = RxFrame::new(
446 rx.unwrap(),
447 &buffer,
448 #[cfg(feature = "time")]
449 calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
450 );
451 return Poll::Ready(Ok(frame));
452 } else if let Some(err) = curr_error::<T>() { 469 } else if let Some(err) = curr_error::<T>() {
453 // TODO: this is probably wrong 470 // TODO: this is probably wrong
454 return Poll::Ready(Err(err)); 471 return Poll::Ready(Err(err));
@@ -459,40 +476,48 @@ where
459 } 476 }
460 477
461 /// Split instance into separate Tx(write) and Rx(read) portions 478 /// Split instance into separate Tx(write) and Rx(read) portions
462 pub fn split<'c>(&'c mut self) -> (FdcanTx<'c, 'd, T, M>, FdcanRx<'c, 'd, T, M>) { 479 pub fn split(self) -> (FdcanTx<'d, T, M>, FdcanRx<'d, T, M>) {
463 let (mut _control, tx, rx0, rx1) = self.can.split_by_ref();
464 ( 480 (
465 FdcanTx { _control, tx }, 481 FdcanTx {
482 _instance: self.instance,
483 _mode: self._mode,
484 },
466 FdcanRx { 485 FdcanRx {
467 rx0, 486 _instance1: PhantomData::<T>,
468 rx1, 487 _instance2: T::regs(),
488 _mode: self._mode,
469 ns_per_timer_tick: self.ns_per_timer_tick, 489 ns_per_timer_tick: self.ns_per_timer_tick,
470 }, 490 },
471 ) 491 )
472 } 492 }
473} 493}
474 494
495/// FDCAN Rx only Instance
496#[allow(dead_code)]
497pub struct FdcanRx<'d, T: Instance, M: Receive> {
498 _instance1: PhantomData<T>,
499 _instance2: &'d crate::pac::can::Fdcan,
500 _mode: PhantomData<M>,
501 ns_per_timer_tick: u64, // For FDCAN internal timer
502}
503
475/// FDCAN Tx only Instance 504/// FDCAN Tx only Instance
476pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> { 505pub struct FdcanTx<'d, T: Instance, M: Transmit> {
477 _control: &'c mut fdcan::FdCanControl<FdcanInstance<'d, T>, M>, 506 _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
478 tx: &'c mut fdcan::Tx<FdcanInstance<'d, T>, M>, 507 _mode: PhantomData<M>,
479} 508}
480 509
481impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> { 510impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> {
482 /// Queues the message to be sent but exerts backpressure. If a lower-priority 511 /// Queues the message to be sent but exerts backpressure. If a lower-priority
483 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 512 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
484 /// can be replaced, this call asynchronously waits for a frame to be successfully 513 /// can be replaced, this call asynchronously waits for a frame to be successfully
485 /// transmitted, then tries again. 514 /// transmitted, then tries again.
486 pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> { 515 pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
487 poll_fn(|cx| { 516 poll_fn(|cx| {
488 T::state().tx_waker.register(cx.waker()); 517 T::state().tx_waker.register(cx.waker());
489 if let Ok(dropped) = self 518
490 .tx 519 if let Ok(dropped) = T::registers().write_classic(frame) {
491 .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { 520 return Poll::Ready(dropped);
492 TxFrame::from_preserved(hdr, data32)
493 })
494 {
495 return Poll::Ready(dropped.flatten());
496 } 521 }
497 522
498 // Couldn't replace any lower priority frames. Need to wait for some mailboxes 523 // Couldn't replace any lower priority frames. Need to wait for some mailboxes
@@ -501,67 +526,68 @@ impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> {
501 }) 526 })
502 .await 527 .await
503 } 528 }
504}
505 529
506/// FDCAN Rx only Instance 530 /// Queues the message to be sent but exerts backpressure. If a lower-priority
507#[allow(dead_code)] 531 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
508pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> { 532 /// can be replaced, this call asynchronously waits for a frame to be successfully
509 rx0: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo0>, 533 /// transmitted, then tries again.
510 rx1: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo1>, 534 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
511 ns_per_timer_tick: u64, // For FDCAN internal timer 535 poll_fn(|cx| {
536 T::state().tx_waker.register(cx.waker());
537
538 if let Ok(dropped) = T::registers().write_fd(frame) {
539 return Poll::Ready(dropped);
540 }
541
542 // Couldn't replace any lower priority frames. Need to wait for some mailboxes
543 // to clear.
544 Poll::Pending
545 })
546 .await
547 }
512} 548}
513 549
514impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> { 550impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> {
515 /// Returns the next received message frame 551 /// Returns the next received message frame
516 pub async fn read(&mut self) -> Result<RxFrame, BusError> { 552 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
517 poll_fn(|cx| { 553 poll_fn(|cx| {
518 T::state().err_waker.register(cx.waker()); 554 T::state().err_waker.register(cx.waker());
519 T::state().rx_waker.register(cx.waker()); 555 T::state().rx_waker.register(cx.waker());
520 556
521 let mut buffer: [u8; 64] = [0; 64]; 557 if let Some((msg, ts)) = T::registers().read_classic(0) {
522 if let Ok(rx) = self.rx0.receive(&mut buffer) { 558 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
523 // rx: fdcan::ReceiveOverrun<RxFrameInfo> 559 return Poll::Ready(Ok((msg, ts)));
524 // TODO: report overrun? 560 } else if let Some((msg, ts)) = T::registers().read_classic(1) {
525 // for now we just drop it 561 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
526 let frame: RxFrame = RxFrame::new( 562 return Poll::Ready(Ok((msg, ts)));
527 rx.unwrap(),
528 &buffer,
529 #[cfg(feature = "time")]
530 calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
531 );
532 return Poll::Ready(Ok(frame));
533 } else if let Ok(rx) = self.rx1.receive(&mut buffer) {
534 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
535 // TODO: report overrun?
536 // for now we just drop it
537 let frame: RxFrame = RxFrame::new(
538 rx.unwrap(),
539 &buffer,
540 #[cfg(feature = "time")]
541 calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
542 );
543 return Poll::Ready(Ok(frame));
544 } else if let Some(err) = curr_error::<T>() { 563 } else if let Some(err) = curr_error::<T>() {
545 // TODO: this is probably wrong 564 // TODO: this is probably wrong
546 return Poll::Ready(Err(err)); 565 return Poll::Ready(Err(err));
547 } 566 }
548
549 Poll::Pending 567 Poll::Pending
550 }) 568 })
551 .await 569 .await
552 } 570 }
553}
554impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> {
555 type Target = fdcan::FdCan<FdcanInstance<'d, T>, M>;
556 571
557 fn deref(&self) -> &Self::Target { 572 /// Returns the next received message frame
558 &self.can 573 pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
559 } 574 poll_fn(|cx| {
560} 575 T::state().err_waker.register(cx.waker());
576 T::state().rx_waker.register(cx.waker());
561 577
562impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> { 578 if let Some((msg, ts)) = T::registers().read_fd(0) {
563 fn deref_mut(&mut self) -> &mut Self::Target { 579 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
564 &mut self.can 580 return Poll::Ready(Ok((msg, ts)));
581 } else if let Some((msg, ts)) = T::registers().read_fd(1) {
582 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts);
583 return Poll::Ready(Ok((msg, ts)));
584 } else if let Some(err) = curr_error::<T>() {
585 // TODO: this is probably wrong
586 return Poll::Ready(Err(err));
587 }
588 Poll::Pending
589 })
590 .await
565 } 591 }
566} 592}
567 593
@@ -585,11 +611,11 @@ pub(crate) mod sealed {
585 } 611 }
586 612
587 pub trait Instance { 613 pub trait Instance {
588 const REGISTERS: *mut fdcan::RegisterBlock;
589 const MSG_RAM: *mut fdcan::message_ram::RegisterBlock;
590 const MSG_RAM_OFFSET: usize; 614 const MSG_RAM_OFFSET: usize;
591 615
592 fn regs() -> &'static crate::pac::can::Fdcan; 616 fn regs() -> &'static crate::pac::can::Fdcan;
617 fn registers() -> crate::can::fd::peripheral::Registers;
618 fn ram() -> &'static crate::pac::fdcanram::Fdcanram;
593 fn state() -> &'static State; 619 fn state() -> &'static State;
594 620
595 #[cfg(not(stm32h7))] 621 #[cfg(not(stm32h7))]
@@ -599,7 +625,8 @@ pub(crate) mod sealed {
599 fn configure_msg_ram() { 625 fn configure_msg_ram() {
600 let r = Self::regs(); 626 let r = Self::regs();
601 627
602 use fdcan::message_ram::*; 628 use crate::can::fd::message_ram::*;
629 //use fdcan::message_ram::*;
603 let mut offset_words = Self::MSG_RAM_OFFSET as u16; 630 let mut offset_words = Self::MSG_RAM_OFFSET as u16;
604 631
605 // 11-bit filter 632 // 11-bit filter
@@ -677,28 +704,20 @@ pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + '
677/// Fdcan Instance struct 704/// Fdcan Instance struct
678pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); 705pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
679 706
680unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> {
681 const MSG_RAM: *mut RegisterBlock = T::MSG_RAM;
682}
683
684unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T>
685where
686 FdcanInstance<'d, T>: fdcan::message_ram::Instance,
687{
688 const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS;
689}
690
691macro_rules! impl_fdcan { 707macro_rules! impl_fdcan {
692 ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { 708 ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => {
693 impl sealed::Instance for peripherals::$inst { 709 impl sealed::Instance for peripherals::$inst {
694 const REGISTERS: *mut fdcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
695 const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = crate::pac::$msg_ram_inst.as_ptr() as *mut _;
696 const MSG_RAM_OFFSET: usize = $msg_ram_offset; 710 const MSG_RAM_OFFSET: usize = $msg_ram_offset;
697 711
698 fn regs() -> &'static crate::pac::can::Fdcan { 712 fn regs() -> &'static crate::pac::can::Fdcan {
699 &crate::pac::$inst 713 &crate::pac::$inst
700 } 714 }
701 715 fn registers() -> Registers {
716 Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst}
717 }
718 fn ram() -> &'static crate::pac::fdcanram::Fdcanram {
719 &crate::pac::$msg_ram_inst
720 }
702 fn state() -> &'static sealed::State { 721 fn state() -> &'static sealed::State {
703 static STATE: sealed::State = sealed::State::new(); 722 static STATE: sealed::State = sealed::State::new();
704 &STATE 723 &STATE
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
new file mode 100644
index 000000000..725a9b1ab
--- /dev/null
+++ b/embassy-stm32/src/can/frame.rs
@@ -0,0 +1,370 @@
1//! Definition for CAN Frames
2use bit_field::BitField;
3
4/// CAN Header, without meta data
5#[derive(Debug, Copy, Clone)]
6pub struct Header {
7 id: embedded_can::Id,
8 len: u8,
9 flags: u8,
10}
11
12impl Header {
13 const FLAG_RTR: usize = 0; // Remote
14 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
15 const FLAG_BRS: usize = 2; // Bit-rate switching, ignored for Classic CAN
16
17 /// Create new CAN Header
18 pub fn new(id: embedded_can::Id, len: u8, rtr: bool) -> Header {
19 let mut flags = 0u8;
20 flags.set_bit(Self::FLAG_RTR, rtr);
21 Header { id, len, flags }
22 }
23
24 /// Create new CAN FD Header
25 pub fn new_fd(id: embedded_can::Id, len: u8, rtr: bool, brs: bool) -> Header {
26 let mut flags = 0u8;
27 flags.set_bit(Self::FLAG_RTR, rtr);
28 flags.set_bit(Self::FLAG_FDCAN, true);
29 flags.set_bit(Self::FLAG_BRS, brs);
30 Header { id, len, flags }
31 }
32
33 /// Return ID
34 pub fn id(&self) -> &embedded_can::Id {
35 &self.id
36 }
37
38 /// Return length as u8
39 pub fn len(&self) -> u8 {
40 self.len
41 }
42
43 /// Is remote frame
44 pub fn rtr(&self) -> bool {
45 self.flags.get_bit(Self::FLAG_RTR)
46 }
47
48 /// Request/is FDCAN frame
49 pub fn fdcan(&self) -> bool {
50 self.flags.get_bit(Self::FLAG_FDCAN)
51 }
52
53 /// Request/is Flexible Data Rate
54 pub fn bit_rate_switching(&self) -> bool {
55 self.flags.get_bit(Self::FLAG_BRS)
56 }
57}
58
59/// Payload of a classic CAN data frame.
60///
61/// Contains 0 to 8 Bytes of data.
62#[derive(Debug, Copy, Clone)]
63pub struct ClassicData {
64 pub(crate) bytes: [u8; 8],
65}
66
67impl ClassicData {
68 /// Creates a data payload from a raw byte slice.
69 ///
70 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
71 /// cannot be represented with an FDCAN DLC.
72 pub fn new(data: &[u8]) -> Option<Self> {
73 if !FdData::is_valid_len(data.len()) {
74 return None;
75 }
76
77 let mut bytes = [0; 8];
78 bytes[..data.len()].copy_from_slice(data);
79
80 Some(Self { bytes })
81 }
82
83 /// Raw read access to data.
84 pub fn raw(&self) -> &[u8] {
85 &self.bytes
86 }
87
88 /// Checks if the length can be encoded in FDCAN DLC field.
89 pub const fn is_valid_len(len: usize) -> bool {
90 match len {
91 0..=8 => true,
92 _ => false,
93 }
94 }
95
96 /// Creates an empty data payload containing 0 bytes.
97 #[inline]
98 pub const fn empty() -> Self {
99 Self { bytes: [0; 8] }
100 }
101}
102
103/// Frame with up to 8 bytes of data payload as per Classic CAN
104#[derive(Debug, Copy, Clone)]
105pub struct ClassicFrame {
106 can_header: Header,
107 data: ClassicData,
108}
109
110impl ClassicFrame {
111 pub(crate) const MAX_DATA_LEN: usize = 8;
112
113 /// Create a new CAN classic Frame
114 pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame {
115 ClassicFrame { can_header, data }
116 }
117
118 /// Create new extended frame
119 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> {
120 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
121 match ClassicData::new(raw_data) {
122 Some(data) => Some(ClassicFrame::new(
123 Header::new(id.into(), raw_data.len() as u8, false),
124 data,
125 )),
126 None => None,
127 }
128 } else {
129 None
130 }
131 }
132
133 /// Create new standard frame
134 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> {
135 if let Some(id) = embedded_can::StandardId::new(raw_id) {
136 match ClassicData::new(raw_data) {
137 Some(data) => Some(ClassicFrame::new(
138 Header::new(id.into(), raw_data.len() as u8, false),
139 data,
140 )),
141 None => None,
142 }
143 } else {
144 None
145 }
146 }
147
148 /// Create new remote frame
149 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
150 if len <= 8usize {
151 Some(ClassicFrame::new(
152 Header::new(id.into(), len as u8, true),
153 ClassicData::empty(),
154 ))
155 } else {
156 None
157 }
158 }
159
160 /// Get reference to data
161 pub fn header(&self) -> &Header {
162 &self.can_header
163 }
164
165 /// Return ID
166 pub fn id(&self) -> &embedded_can::Id {
167 &self.can_header.id
168 }
169
170 /// Get reference to data
171 pub fn data(&self) -> &[u8] {
172 &self.data.raw()
173 }
174}
175
176impl embedded_can::Frame for ClassicFrame {
177 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
178 match ClassicData::new(raw_data) {
179 Some(data) => Some(ClassicFrame::new(
180 Header::new(id.into(), raw_data.len() as u8, false),
181 data,
182 )),
183 None => None,
184 }
185 }
186 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
187 if len <= 8 {
188 Some(ClassicFrame::new(
189 Header::new(id.into(), len as u8, true),
190 ClassicData::empty(),
191 ))
192 } else {
193 None
194 }
195 }
196 fn is_extended(&self) -> bool {
197 match self.can_header.id {
198 embedded_can::Id::Extended(_) => true,
199 embedded_can::Id::Standard(_) => true,
200 }
201 }
202 fn is_remote_frame(&self) -> bool {
203 self.can_header.rtr()
204 }
205 fn id(&self) -> embedded_can::Id {
206 self.can_header.id
207 }
208 fn dlc(&self) -> usize {
209 self.can_header.len as usize
210 }
211 fn data(&self) -> &[u8] {
212 &self.data.raw()
213 }
214}
215
216/// Payload of a (FD)CAN data frame.
217///
218/// Contains 0 to 64 Bytes of data.
219#[derive(Debug, Copy, Clone)]
220pub struct FdData {
221 pub(crate) bytes: [u8; 64],
222}
223
224impl FdData {
225 /// Creates a data payload from a raw byte slice.
226 ///
227 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
228 /// cannot be represented with an FDCAN DLC.
229 pub fn new(data: &[u8]) -> Option<Self> {
230 if !FdData::is_valid_len(data.len()) {
231 return None;
232 }
233
234 let mut bytes = [0; 64];
235 bytes[..data.len()].copy_from_slice(data);
236
237 Some(Self { bytes })
238 }
239
240 /// Raw read access to data.
241 pub fn raw(&self) -> &[u8] {
242 &self.bytes
243 }
244
245 /// Checks if the length can be encoded in FDCAN DLC field.
246 pub const fn is_valid_len(len: usize) -> bool {
247 match len {
248 0..=8 => true,
249 12 => true,
250 16 => true,
251 20 => true,
252 24 => true,
253 32 => true,
254 48 => true,
255 64 => true,
256 _ => false,
257 }
258 }
259
260 /// Creates an empty data payload containing 0 bytes.
261 #[inline]
262 pub const fn empty() -> Self {
263 Self { bytes: [0; 64] }
264 }
265}
266
267/// Frame with up to 8 bytes of data payload as per Fd CAN
268#[derive(Debug, Copy, Clone)]
269pub struct FdFrame {
270 can_header: Header,
271 data: FdData,
272}
273
274impl FdFrame {
275 pub(crate) const MAX_DATA_LEN: usize = 64;
276
277 /// Create a new CAN classic Frame
278 pub fn new(can_header: Header, data: FdData) -> FdFrame {
279 FdFrame { can_header, data }
280 }
281
282 /// Create new extended frame
283 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> {
284 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
285 match FdData::new(raw_data) {
286 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
287 None => None,
288 }
289 } else {
290 None
291 }
292 }
293
294 /// Create new standard frame
295 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> {
296 if let Some(id) = embedded_can::StandardId::new(raw_id) {
297 match FdData::new(raw_data) {
298 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
299 None => None,
300 }
301 } else {
302 None
303 }
304 }
305
306 /// Create new remote frame
307 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
308 if len <= 8 {
309 Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty()))
310 } else {
311 None
312 }
313 }
314
315 /// Get reference to data
316 pub fn header(&self) -> &Header {
317 &self.can_header
318 }
319
320 /// Return ID
321 pub fn id(&self) -> &embedded_can::Id {
322 &self.can_header.id
323 }
324
325 /// Get reference to data
326 pub fn data(&self) -> &[u8] {
327 &self.data.raw()
328 }
329}
330
331impl embedded_can::Frame for FdFrame {
332 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
333 match FdData::new(raw_data) {
334 Some(data) => Some(FdFrame::new(
335 Header::new_fd(id.into(), raw_data.len() as u8, false, true),
336 data,
337 )),
338 None => None,
339 }
340 }
341 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
342 if len <= 8 {
343 Some(FdFrame::new(
344 Header::new_fd(id.into(), len as u8, true, true),
345 FdData::empty(),
346 ))
347 } else {
348 None
349 }
350 }
351 fn is_extended(&self) -> bool {
352 match self.can_header.id {
353 embedded_can::Id::Extended(_) => true,
354 embedded_can::Id::Standard(_) => true,
355 }
356 }
357 fn is_remote_frame(&self) -> bool {
358 self.can_header.rtr()
359 }
360 fn id(&self) -> embedded_can::Id {
361 self.can_header.id
362 }
363 // Returns length in bytes even for CANFD packets which embedded-can does not really mention.
364 fn dlc(&self) -> usize {
365 self.can_header.len as usize
366 }
367 fn data(&self) -> &[u8] {
368 &self.data.raw()
369 }
370}
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 895ad3e7c..fdb325f06 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -20,6 +20,7 @@ defmt-rtt = "0.4"
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
22embedded-hal = "0.2.6" 22embedded-hal = "0.2.6"
23embedded-can = { version = "0.4" }
23panic-probe = { version = "0.3", features = ["print-defmt"] } 24panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 25futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.8", default-features = false } 26heapless = { version = "0.8", default-features = false }
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index 727921fba..5ff4f0ef0 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -20,32 +20,100 @@ async fn main(_spawner: Spawner) {
20 20
21 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 21 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
22 22
23 can.set_extended_filter(
24 can::fd::filter::ExtendedFilterSlot::_0,
25 can::fd::filter::ExtendedFilter::accept_all_into_fifo1(),
26 );
27
23 // 250k bps 28 // 250k bps
24 can.set_bitrate(250_000); 29 can.set_bitrate(250_000);
25 30
31 // 1M bps
32 can.set_fd_data_bitrate(1_000_000, false);
33
26 info!("Configured"); 34 info!("Configured");
27 35
28 //let mut can = can.into_external_loopback_mode(); 36 //let mut can = can.into_normal_mode();
29 let mut can = can.into_normal_mode(); 37 let mut can = can.into_internal_loopback_mode();
30 38
31 let mut i = 0; 39 let mut i = 0;
40 let mut last_read_ts = embassy_time::Instant::now();
41
32 loop { 42 loop {
33 let frame = can::TxFrame::new( 43 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
34 can::TxFrameHeader {
35 len: 1,
36 frame_format: can::FrameFormat::Standard,
37 id: can::StandardId::new(0x123).unwrap().into(),
38 bit_rate_switching: false,
39 marker: None,
40 },
41 &[i],
42 )
43 .unwrap();
44 info!("Writing frame"); 44 info!("Writing frame");
45
45 _ = can.write(&frame).await; 46 _ = can.write(&frame).await;
46 47
47 match can.read().await { 48 match can.read().await {
48 Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), 49 Ok((rx_frame, ts)) => {
50 let delta = (ts - last_read_ts).as_millis();
51 last_read_ts = ts;
52 info!(
53 "Rx: {} {:02x} --- {}ms",
54 rx_frame.header().len(),
55 rx_frame.data()[0..rx_frame.header().len() as usize],
56 delta,
57 )
58 }
59 Err(_err) => error!("Error in frame"),
60 }
61
62 Timer::after_millis(250).await;
63
64 i += 1;
65 if i > 2 {
66 break;
67 }
68 }
69
70 // Use the FD API's even if we don't get FD packets.
71 loop {
72 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
73 info!("Writing frame using FD API");
74
75 _ = can.write_fd(&frame).await;
76
77 match can.read_fd().await {
78 Ok((rx_frame, ts)) => {
79 let delta = (ts - last_read_ts).as_millis();
80 last_read_ts = ts;
81 info!(
82 "Rx: {} {:02x} --- using FD API {}ms",
83 rx_frame.header().len(),
84 rx_frame.data()[0..rx_frame.header().len() as usize],
85 delta,
86 )
87 }
88 Err(_err) => error!("Error in frame"),
89 }
90
91 Timer::after_millis(250).await;
92
93 i += 1;
94 if i > 4 {
95 break;
96 }
97 }
98
99 let (mut tx, mut rx) = can.split();
100 // With split
101 loop {
102 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
103 info!("Writing frame");
104 _ = tx.write(&frame).await;
105
106 match rx.read().await {
107 Ok((rx_frame, ts)) => {
108 let delta = (ts - last_read_ts).as_millis();
109 last_read_ts = ts;
110 info!(
111 "Rx: {} {:02x} --- {}ms",
112 rx_frame.header().len(),
113 rx_frame.data()[0..rx_frame.header().len() as usize],
114 delta,
115 )
116 }
49 Err(_err) => error!("Error in frame"), 117 Err(_err) => error!("Error in frame"),
50 } 118 }
51 119
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs
index 2906d1576..4b29a0d21 100644
--- a/examples/stm32h5/src/bin/can.rs
+++ b/examples/stm32h5/src/bin/can.rs
@@ -16,54 +16,77 @@ bind_interrupts!(struct Irqs {
16#[embassy_executor::main] 16#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
18 let mut config = Config::default(); 18 let mut config = Config::default();
19 19 config.rcc.hse = Some(rcc::Hse {
20 // configure FDCAN to use PLL1_Q at 64 MHz 20 freq: embassy_stm32::time::Hertz(25_000_000),
21 config.rcc.pll1 = Some(rcc::Pll { 21 mode: rcc::HseMode::Oscillator,
22 source: rcc::PllSource::HSI,
23 prediv: rcc::PllPreDiv::DIV4,
24 mul: rcc::PllMul::MUL8,
25 divp: None,
26 divq: Some(rcc::PllDiv::DIV2),
27 divr: None,
28 }); 22 });
29 config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; 23 config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
30 24
31 let peripherals = embassy_stm32::init(config); 25 let peripherals = embassy_stm32::init(config);
32 26
27 //let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
33 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 28 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
34 29
35 can.can.apply_config( 30 // 250k bps
36 can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { 31 can.set_bitrate(250_000);
37 sync_jump_width: 1.try_into().unwrap(),
38 prescaler: 8.try_into().unwrap(),
39 seg1: 13.try_into().unwrap(),
40 seg2: 2.try_into().unwrap(),
41 }),
42 );
43 32
44 info!("Configured"); 33 //let mut can = can.into_internal_loopback_mode();
34 let mut can = can.into_normal_mode();
45 35
46 let mut can = can.into_external_loopback_mode(); 36 info!("CAN Configured");
47 //let mut can = can.into_normal_mode();
48 37
49 let mut i = 0; 38 let mut i = 0;
39 let mut last_read_ts = embassy_time::Instant::now();
40
50 loop { 41 loop {
51 let frame = can::TxFrame::new( 42 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
52 can::TxFrameHeader {
53 len: 1,
54 frame_format: can::FrameFormat::Standard,
55 id: can::StandardId::new(0x123).unwrap().into(),
56 bit_rate_switching: false,
57 marker: None,
58 },
59 &[i],
60 )
61 .unwrap();
62 info!("Writing frame"); 43 info!("Writing frame");
63 _ = can.write(&frame).await; 44 _ = can.write(&frame).await;
64 45
65 match can.read().await { 46 match can.read().await {
66 Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), 47 Ok((rx_frame, ts)) => {
48 let delta = (ts - last_read_ts).as_millis();
49 last_read_ts = ts;
50 info!(
51 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
52 rx_frame.data()[0],
53 rx_frame.data()[1],
54 rx_frame.data()[2],
55 rx_frame.data()[3],
56 delta,
57 )
58 }
59 Err(_err) => error!("Error in frame"),
60 }
61
62 Timer::after_millis(250).await;
63
64 i += 1;
65 if i > 3 {
66 break;
67 }
68 }
69
70 let (mut tx, mut rx) = can.split();
71 // With split
72 loop {
73 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
74 info!("Writing frame");
75 _ = tx.write(&frame).await;
76
77 match rx.read().await {
78 Ok((rx_frame, ts)) => {
79 let delta = (ts - last_read_ts).as_millis();
80 last_read_ts = ts;
81 info!(
82 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
83 rx_frame.data()[0],
84 rx_frame.data()[1],
85 rx_frame.data()[2],
86 rx_frame.data()[3],
87 delta,
88 )
89 }
67 Err(_err) => error!("Error in frame"), 90 Err(_err) => error!("Error in frame"),
68 } 91 }
69 92
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs
index 2906d1576..4b29a0d21 100644
--- a/examples/stm32h7/src/bin/can.rs
+++ b/examples/stm32h7/src/bin/can.rs
@@ -16,54 +16,77 @@ bind_interrupts!(struct Irqs {
16#[embassy_executor::main] 16#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
18 let mut config = Config::default(); 18 let mut config = Config::default();
19 19 config.rcc.hse = Some(rcc::Hse {
20 // configure FDCAN to use PLL1_Q at 64 MHz 20 freq: embassy_stm32::time::Hertz(25_000_000),
21 config.rcc.pll1 = Some(rcc::Pll { 21 mode: rcc::HseMode::Oscillator,
22 source: rcc::PllSource::HSI,
23 prediv: rcc::PllPreDiv::DIV4,
24 mul: rcc::PllMul::MUL8,
25 divp: None,
26 divq: Some(rcc::PllDiv::DIV2),
27 divr: None,
28 }); 22 });
29 config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; 23 config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
30 24
31 let peripherals = embassy_stm32::init(config); 25 let peripherals = embassy_stm32::init(config);
32 26
27 //let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
33 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 28 let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
34 29
35 can.can.apply_config( 30 // 250k bps
36 can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { 31 can.set_bitrate(250_000);
37 sync_jump_width: 1.try_into().unwrap(),
38 prescaler: 8.try_into().unwrap(),
39 seg1: 13.try_into().unwrap(),
40 seg2: 2.try_into().unwrap(),
41 }),
42 );
43 32
44 info!("Configured"); 33 //let mut can = can.into_internal_loopback_mode();
34 let mut can = can.into_normal_mode();
45 35
46 let mut can = can.into_external_loopback_mode(); 36 info!("CAN Configured");
47 //let mut can = can.into_normal_mode();
48 37
49 let mut i = 0; 38 let mut i = 0;
39 let mut last_read_ts = embassy_time::Instant::now();
40
50 loop { 41 loop {
51 let frame = can::TxFrame::new( 42 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
52 can::TxFrameHeader {
53 len: 1,
54 frame_format: can::FrameFormat::Standard,
55 id: can::StandardId::new(0x123).unwrap().into(),
56 bit_rate_switching: false,
57 marker: None,
58 },
59 &[i],
60 )
61 .unwrap();
62 info!("Writing frame"); 43 info!("Writing frame");
63 _ = can.write(&frame).await; 44 _ = can.write(&frame).await;
64 45
65 match can.read().await { 46 match can.read().await {
66 Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), 47 Ok((rx_frame, ts)) => {
48 let delta = (ts - last_read_ts).as_millis();
49 last_read_ts = ts;
50 info!(
51 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
52 rx_frame.data()[0],
53 rx_frame.data()[1],
54 rx_frame.data()[2],
55 rx_frame.data()[3],
56 delta,
57 )
58 }
59 Err(_err) => error!("Error in frame"),
60 }
61
62 Timer::after_millis(250).await;
63
64 i += 1;
65 if i > 3 {
66 break;
67 }
68 }
69
70 let (mut tx, mut rx) = can.split();
71 // With split
72 loop {
73 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
74 info!("Writing frame");
75 _ = tx.write(&frame).await;
76
77 match rx.read().await {
78 Ok((rx_frame, ts)) => {
79 let delta = (ts - last_read_ts).as_millis();
80 last_read_ts = ts;
81 info!(
82 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
83 rx_frame.data()[0],
84 rx_frame.data()[1],
85 rx_frame.data()[2],
86 rx_frame.data()[3],
87 delta,
88 )
89 }
67 Err(_err) => error!("Error in frame"), 90 Err(_err) => error!("Error in frame"),
68 } 91 }
69 92
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 8554682a4..5b28b5849 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -69,6 +69,7 @@ cortex-m-rt = "0.7.0"
69embedded-hal = "0.2.6" 69embedded-hal = "0.2.6"
70embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 70embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
71embedded-hal-async = { version = "1.0" } 71embedded-hal-async = { version = "1.0" }
72embedded-can = { version = "0.4" }
72micromath = "2.0.0" 73micromath = "2.0.0"
73panic-probe = { version = "0.3.0", features = ["print-defmt"] } 74panic-probe = { version = "0.3.0", features = ["print-defmt"] }
74rand_core = { version = "0.6", default-features = false } 75rand_core = { version = "0.6", default-features = false }
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index 7363eaa16..76c27d091 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -36,7 +36,7 @@ fn options() -> TestOptions {
36 c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; 36 c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
37 TestOptions { 37 TestOptions {
38 config: c, 38 config: c,
39 max_latency: Duration::from_micros(3800), 39 max_latency: Duration::from_micros(1200),
40 second_fifo_working: false, 40 second_fifo_working: false,
41 } 41 }
42} 42}
@@ -53,12 +53,12 @@ fn options() -> TestOptions {
53 c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; 53 c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
54 TestOptions { 54 TestOptions {
55 config: c, 55 config: c,
56 max_latency: Duration::from_micros(5500), 56 max_latency: Duration::from_micros(1200),
57 second_fifo_working: false, 57 second_fifo_working: false,
58 } 58 }
59} 59}
60 60
61#[cfg(any(feature = "stm32g491re"))] 61#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))]
62fn options() -> TestOptions { 62fn options() -> TestOptions {
63 info!("G4 config"); 63 info!("G4 config");
64 TestOptions { 64 TestOptions {
@@ -80,9 +80,9 @@ async fn main(_spawner: Spawner) {
80 // 250k bps 80 // 250k bps
81 can.set_bitrate(250_000); 81 can.set_bitrate(250_000);
82 82
83 can.can.set_extended_filter( 83 can.set_extended_filter(
84 can::filter::ExtendedFilterSlot::_0, 84 can::fd::filter::ExtendedFilterSlot::_0,
85 can::filter::ExtendedFilter::accept_all_into_fifo1(), 85 can::fd::filter::ExtendedFilter::accept_all_into_fifo1(),
86 ); 86 );
87 87
88 let mut can = can.into_internal_loopback_mode(); 88 let mut can = can.into_internal_loopback_mode();
@@ -91,31 +91,21 @@ async fn main(_spawner: Spawner) {
91 91
92 let mut i: u8 = 0; 92 let mut i: u8 = 0;
93 loop { 93 loop {
94 let tx_frame = can::TxFrame::new( 94 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
95 can::TxFrameHeader {
96 len: 1,
97 frame_format: can::FrameFormat::Standard,
98 id: can::StandardId::new(0x123).unwrap().into(),
99 bit_rate_switching: false,
100 marker: None,
101 },
102 &[i],
103 )
104 .unwrap();
105 95
106 info!("Transmitting frame..."); 96 info!("Transmitting frame...");
107 let tx_ts = Instant::now(); 97 let tx_ts = Instant::now();
108 can.write(&tx_frame).await; 98 can.write(&tx_frame).await;
109 99
110 let envelope = can.read().await.unwrap(); 100 let (frame, timestamp) = can.read().await.unwrap();
111 info!("Frame received!"); 101 info!("Frame received!");
112 102
113 // Check data. 103 // Check data.
114 assert!(i == envelope.data()[0], "{} == {}", i, envelope.data()[0]); 104 assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
115 105
116 info!("loopback time {}", envelope.header.time_stamp); 106 info!("loopback time {}", timestamp);
117 info!("loopback frame {=u8}", envelope.data()[0]); 107 info!("loopback frame {=u8}", frame.data()[0]);
118 let latency = envelope.timestamp.saturating_duration_since(tx_ts); 108 let latency = timestamp.saturating_duration_since(tx_ts);
119 info!("loopback latency {} us", latency.as_micros()); 109 info!("loopback latency {} us", latency.as_micros());
120 110
121 // Theoretical minimum latency is 55us, actual is usually ~80us 111 // Theoretical minimum latency is 55us, actual is usually ~80us
@@ -143,47 +133,26 @@ async fn main(_spawner: Spawner) {
143 // in each FIFO so make sure we write enough to fill them both up before reading. 133 // in each FIFO so make sure we write enough to fill them both up before reading.
144 for i in 0..3 { 134 for i in 0..3 {
145 // Try filling up the RX FIFO0 buffers with standard packets 135 // Try filling up the RX FIFO0 buffers with standard packets
146 let tx_frame = can::TxFrame::new( 136 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
147 can::TxFrameHeader {
148 len: 1,
149 frame_format: can::FrameFormat::Standard,
150 id: can::StandardId::new(0x123).unwrap().into(),
151 bit_rate_switching: false,
152 marker: None,
153 },
154 &[i],
155 )
156 .unwrap();
157 info!("Transmitting frame {}", i); 137 info!("Transmitting frame {}", i);
158 can.write(&tx_frame).await; 138 can.write(&tx_frame).await;
159 } 139 }
160 for i in 3..max_buffered { 140 for i in 3..max_buffered {
161 // Try filling up the RX FIFO0 buffers with extended packets 141 // Try filling up the RX FIFO0 buffers with extended packets
162 let tx_frame = can::TxFrame::new( 142 let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
163 can::TxFrameHeader {
164 len: 1,
165 frame_format: can::FrameFormat::Standard,
166 id: can::ExtendedId::new(0x1232344).unwrap().into(),
167 bit_rate_switching: false,
168 marker: None,
169 },
170 &[i],
171 )
172 .unwrap();
173
174 info!("Transmitting frame {}", i); 143 info!("Transmitting frame {}", i);
175 can.write(&tx_frame).await; 144 can.write(&tx_frame).await;
176 } 145 }
177 146
178 // Try and receive all 6 packets 147 // Try and receive all 6 packets
179 for i in 0..max_buffered { 148 for i in 0..max_buffered {
180 let envelope = can.read().await.unwrap(); 149 let (frame, _ts) = can.read().await.unwrap();
181 match envelope.header.id { 150 match frame.id() {
182 can::Id::Extended(id) => { 151 embedded_can::Id::Extended(id) => {
183 info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); 152 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
184 } 153 }
185 can::Id::Standard(id) => { 154 embedded_can::Id::Standard(id) => {
186 info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); 155 info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
187 } 156 }
188 } 157 }
189 } 158 }
@@ -192,48 +161,26 @@ async fn main(_spawner: Spawner) {
192 let (mut tx, mut rx) = can.split(); 161 let (mut tx, mut rx) = can.split();
193 for i in 0..3 { 162 for i in 0..3 {
194 // Try filling up the RX FIFO0 buffers with standard packets 163 // Try filling up the RX FIFO0 buffers with standard packets
195 let tx_frame = can::TxFrame::new( 164 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
196 can::TxFrameHeader {
197 len: 1,
198 frame_format: can::FrameFormat::Standard,
199 id: can::StandardId::new(0x123).unwrap().into(),
200 bit_rate_switching: false,
201 marker: None,
202 },
203 &[i],
204 )
205 .unwrap();
206
207 info!("Transmitting frame {}", i); 165 info!("Transmitting frame {}", i);
208 tx.write(&tx_frame).await; 166 tx.write(&tx_frame).await;
209 } 167 }
210 for i in 3..max_buffered { 168 for i in 3..max_buffered {
211 // Try filling up the RX FIFO0 buffers with extended packets 169 // Try filling up the RX FIFO0 buffers with extended packets
212 let tx_frame = can::TxFrame::new( 170 let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
213 can::TxFrameHeader {
214 len: 1,
215 frame_format: can::FrameFormat::Standard,
216 id: can::ExtendedId::new(0x1232344).unwrap().into(),
217 bit_rate_switching: false,
218 marker: None,
219 },
220 &[i],
221 )
222 .unwrap();
223
224 info!("Transmitting frame {}", i); 171 info!("Transmitting frame {}", i);
225 tx.write(&tx_frame).await; 172 tx.write(&tx_frame).await;
226 } 173 }
227 174
228 // Try and receive all 6 packets 175 // Try and receive all 6 packets
229 for i in 0..max_buffered { 176 for i in 0..max_buffered {
230 let envelope = rx.read().await.unwrap(); 177 let (frame, _ts) = rx.read().await.unwrap();
231 match envelope.header.id { 178 match frame.id() {
232 can::Id::Extended(id) => { 179 embedded_can::Id::Extended(id) => {
233 info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); 180 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
234 } 181 }
235 can::Id::Standard(id) => { 182 embedded_can::Id::Standard(id) => {
236 info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); 183 info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
237 } 184 }
238 } 185 }
239 } 186 }