diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-01-30 23:45:14 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-01-30 23:45:14 +0000 |
| commit | fed8635e93f6965eff20de73a16ac92a1f672a73 (patch) | |
| tree | f7a2d4436636994b7038dd1d7dc24d0caf9a958e | |
| parent | dcce40c8a2eefb956ffadbfcc3db6c27cde55dab (diff) | |
| parent | a14dc8413abacc78002a972cd55b1fbf19bac6df (diff) | |
Merge pull request #2475 from cschuhen/feature/fdcan_r2
Support for FDCAN peripheral as found on newer STM32 micros.
| -rw-r--r-- | embassy-stm32/Cargo.toml | 896 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 124 | ||||
| -rw-r--r-- | embassy-stm32/src/can/enums.rs | 30 | ||||
| -rw-r--r-- | embassy-stm32/src/can/fdcan.rs | 714 | ||||
| -rw-r--r-- | embassy-stm32/src/can/util.rs | 117 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/g4.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h.rs | 11 | ||||
| -rw-r--r-- | examples/stm32g4/src/bin/can.rs | 56 | ||||
| -rw-r--r-- | examples/stm32h5/src/bin/can.rs | 74 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/can.rs | 74 | ||||
| -rw-r--r-- | tests/stm32/Cargo.toml | 14 | ||||
| -rw-r--r-- | tests/stm32/src/bin/fdcan.rs | 243 |
13 files changed, 1783 insertions, 579 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 70d4daf09..6c7591f57 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -80,6 +80,8 @@ chrono = { version = "^0.4", default-features = false, optional = true} | |||
| 80 | bit_field = "0.10.2" | 80 | bit_field = "0.10.2" |
| 81 | document-features = "0.2.7" | 81 | document-features = "0.2.7" |
| 82 | 82 | ||
| 83 | fdcan = { version = "0.2.0", optional = true } | ||
| 84 | |||
| 83 | [dev-dependencies] | 85 | [dev-dependencies] |
| 84 | critical-section = { version = "1.1", features = ["std"] } | 86 | critical-section = { version = "1.1", features = ["std"] } |
| 85 | 87 | ||
| @@ -693,373 +695,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ] | |||
| 693 | stm32f779bi = [ "stm32-metapac/stm32f779bi" ] | 695 | stm32f779bi = [ "stm32-metapac/stm32f779bi" ] |
| 694 | stm32f779ii = [ "stm32-metapac/stm32f779ii" ] | 696 | stm32f779ii = [ "stm32-metapac/stm32f779ii" ] |
| 695 | stm32f779ni = [ "stm32-metapac/stm32f779ni" ] | 697 | stm32f779ni = [ "stm32-metapac/stm32f779ni" ] |
| 696 | stm32g030c6 = [ "stm32-metapac/stm32g030c6" ] | 698 | stm32g030c6 = [ "stm32-metapac/stm32g030c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 697 | stm32g030c8 = [ "stm32-metapac/stm32g030c8" ] | 699 | stm32g030c8 = [ "stm32-metapac/stm32g030c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 698 | stm32g030f6 = [ "stm32-metapac/stm32g030f6" ] | 700 | stm32g030f6 = [ "stm32-metapac/stm32g030f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 699 | stm32g030j6 = [ "stm32-metapac/stm32g030j6" ] | 701 | stm32g030j6 = [ "stm32-metapac/stm32g030j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 700 | stm32g030k6 = [ "stm32-metapac/stm32g030k6" ] | 702 | stm32g030k6 = [ "stm32-metapac/stm32g030k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 701 | stm32g030k8 = [ "stm32-metapac/stm32g030k8" ] | 703 | stm32g030k8 = [ "stm32-metapac/stm32g030k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 702 | stm32g031c4 = [ "stm32-metapac/stm32g031c4" ] | 704 | stm32g031c4 = [ "stm32-metapac/stm32g031c4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 703 | stm32g031c6 = [ "stm32-metapac/stm32g031c6" ] | 705 | stm32g031c6 = [ "stm32-metapac/stm32g031c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 704 | stm32g031c8 = [ "stm32-metapac/stm32g031c8" ] | 706 | stm32g031c8 = [ "stm32-metapac/stm32g031c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 705 | stm32g031f4 = [ "stm32-metapac/stm32g031f4" ] | 707 | stm32g031f4 = [ "stm32-metapac/stm32g031f4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 706 | stm32g031f6 = [ "stm32-metapac/stm32g031f6" ] | 708 | stm32g031f6 = [ "stm32-metapac/stm32g031f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 707 | stm32g031f8 = [ "stm32-metapac/stm32g031f8" ] | 709 | stm32g031f8 = [ "stm32-metapac/stm32g031f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 708 | stm32g031g4 = [ "stm32-metapac/stm32g031g4" ] | 710 | stm32g031g4 = [ "stm32-metapac/stm32g031g4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 709 | stm32g031g6 = [ "stm32-metapac/stm32g031g6" ] | 711 | stm32g031g6 = [ "stm32-metapac/stm32g031g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 710 | stm32g031g8 = [ "stm32-metapac/stm32g031g8" ] | 712 | stm32g031g8 = [ "stm32-metapac/stm32g031g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 711 | stm32g031j4 = [ "stm32-metapac/stm32g031j4" ] | 713 | stm32g031j4 = [ "stm32-metapac/stm32g031j4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 712 | stm32g031j6 = [ "stm32-metapac/stm32g031j6" ] | 714 | stm32g031j6 = [ "stm32-metapac/stm32g031j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 713 | stm32g031k4 = [ "stm32-metapac/stm32g031k4" ] | 715 | stm32g031k4 = [ "stm32-metapac/stm32g031k4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 714 | stm32g031k6 = [ "stm32-metapac/stm32g031k6" ] | 716 | stm32g031k6 = [ "stm32-metapac/stm32g031k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 715 | stm32g031k8 = [ "stm32-metapac/stm32g031k8" ] | 717 | stm32g031k8 = [ "stm32-metapac/stm32g031k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 716 | stm32g031y8 = [ "stm32-metapac/stm32g031y8" ] | 718 | stm32g031y8 = [ "stm32-metapac/stm32g031y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 717 | stm32g041c6 = [ "stm32-metapac/stm32g041c6" ] | 719 | stm32g041c6 = [ "stm32-metapac/stm32g041c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 718 | stm32g041c8 = [ "stm32-metapac/stm32g041c8" ] | 720 | stm32g041c8 = [ "stm32-metapac/stm32g041c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 719 | stm32g041f6 = [ "stm32-metapac/stm32g041f6" ] | 721 | stm32g041f6 = [ "stm32-metapac/stm32g041f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 720 | stm32g041f8 = [ "stm32-metapac/stm32g041f8" ] | 722 | stm32g041f8 = [ "stm32-metapac/stm32g041f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 721 | stm32g041g6 = [ "stm32-metapac/stm32g041g6" ] | 723 | stm32g041g6 = [ "stm32-metapac/stm32g041g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 722 | stm32g041g8 = [ "stm32-metapac/stm32g041g8" ] | 724 | stm32g041g8 = [ "stm32-metapac/stm32g041g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 723 | stm32g041j6 = [ "stm32-metapac/stm32g041j6" ] | 725 | stm32g041j6 = [ "stm32-metapac/stm32g041j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 724 | stm32g041k6 = [ "stm32-metapac/stm32g041k6" ] | 726 | stm32g041k6 = [ "stm32-metapac/stm32g041k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 725 | stm32g041k8 = [ "stm32-metapac/stm32g041k8" ] | 727 | stm32g041k8 = [ "stm32-metapac/stm32g041k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 726 | stm32g041y8 = [ "stm32-metapac/stm32g041y8" ] | 728 | stm32g041y8 = [ "stm32-metapac/stm32g041y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 727 | stm32g050c6 = [ "stm32-metapac/stm32g050c6" ] | 729 | stm32g050c6 = [ "stm32-metapac/stm32g050c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 728 | stm32g050c8 = [ "stm32-metapac/stm32g050c8" ] | 730 | stm32g050c8 = [ "stm32-metapac/stm32g050c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 729 | stm32g050f6 = [ "stm32-metapac/stm32g050f6" ] | 731 | stm32g050f6 = [ "stm32-metapac/stm32g050f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 730 | stm32g050k6 = [ "stm32-metapac/stm32g050k6" ] | 732 | stm32g050k6 = [ "stm32-metapac/stm32g050k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 731 | stm32g050k8 = [ "stm32-metapac/stm32g050k8" ] | 733 | stm32g050k8 = [ "stm32-metapac/stm32g050k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 732 | stm32g051c6 = [ "stm32-metapac/stm32g051c6" ] | 734 | stm32g051c6 = [ "stm32-metapac/stm32g051c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 733 | stm32g051c8 = [ "stm32-metapac/stm32g051c8" ] | 735 | stm32g051c8 = [ "stm32-metapac/stm32g051c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 734 | stm32g051f6 = [ "stm32-metapac/stm32g051f6" ] | 736 | stm32g051f6 = [ "stm32-metapac/stm32g051f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 735 | stm32g051f8 = [ "stm32-metapac/stm32g051f8" ] | 737 | stm32g051f8 = [ "stm32-metapac/stm32g051f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 736 | stm32g051g6 = [ "stm32-metapac/stm32g051g6" ] | 738 | stm32g051g6 = [ "stm32-metapac/stm32g051g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 737 | stm32g051g8 = [ "stm32-metapac/stm32g051g8" ] | 739 | stm32g051g8 = [ "stm32-metapac/stm32g051g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 738 | stm32g051k6 = [ "stm32-metapac/stm32g051k6" ] | 740 | stm32g051k6 = [ "stm32-metapac/stm32g051k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 739 | stm32g051k8 = [ "stm32-metapac/stm32g051k8" ] | 741 | stm32g051k8 = [ "stm32-metapac/stm32g051k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 740 | stm32g061c6 = [ "stm32-metapac/stm32g061c6" ] | 742 | stm32g061c6 = [ "stm32-metapac/stm32g061c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 741 | stm32g061c8 = [ "stm32-metapac/stm32g061c8" ] | 743 | stm32g061c8 = [ "stm32-metapac/stm32g061c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 742 | stm32g061f6 = [ "stm32-metapac/stm32g061f6" ] | 744 | stm32g061f6 = [ "stm32-metapac/stm32g061f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 743 | stm32g061f8 = [ "stm32-metapac/stm32g061f8" ] | 745 | stm32g061f8 = [ "stm32-metapac/stm32g061f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 744 | stm32g061g6 = [ "stm32-metapac/stm32g061g6" ] | 746 | stm32g061g6 = [ "stm32-metapac/stm32g061g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 745 | stm32g061g8 = [ "stm32-metapac/stm32g061g8" ] | 747 | stm32g061g8 = [ "stm32-metapac/stm32g061g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 746 | stm32g061k6 = [ "stm32-metapac/stm32g061k6" ] | 748 | stm32g061k6 = [ "stm32-metapac/stm32g061k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 747 | stm32g061k8 = [ "stm32-metapac/stm32g061k8" ] | 749 | stm32g061k8 = [ "stm32-metapac/stm32g061k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 748 | stm32g070cb = [ "stm32-metapac/stm32g070cb" ] | 750 | stm32g070cb = [ "stm32-metapac/stm32g070cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 749 | stm32g070kb = [ "stm32-metapac/stm32g070kb" ] | 751 | stm32g070kb = [ "stm32-metapac/stm32g070kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 750 | stm32g070rb = [ "stm32-metapac/stm32g070rb" ] | 752 | stm32g070rb = [ "stm32-metapac/stm32g070rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 751 | stm32g071c6 = [ "stm32-metapac/stm32g071c6" ] | 753 | stm32g071c6 = [ "stm32-metapac/stm32g071c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 752 | stm32g071c8 = [ "stm32-metapac/stm32g071c8" ] | 754 | stm32g071c8 = [ "stm32-metapac/stm32g071c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 753 | stm32g071cb = [ "stm32-metapac/stm32g071cb" ] | 755 | stm32g071cb = [ "stm32-metapac/stm32g071cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 754 | stm32g071eb = [ "stm32-metapac/stm32g071eb" ] | 756 | stm32g071eb = [ "stm32-metapac/stm32g071eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 755 | stm32g071g6 = [ "stm32-metapac/stm32g071g6" ] | 757 | stm32g071g6 = [ "stm32-metapac/stm32g071g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 756 | stm32g071g8 = [ "stm32-metapac/stm32g071g8" ] | 758 | stm32g071g8 = [ "stm32-metapac/stm32g071g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 757 | stm32g071gb = [ "stm32-metapac/stm32g071gb" ] | 759 | stm32g071gb = [ "stm32-metapac/stm32g071gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 758 | stm32g071k6 = [ "stm32-metapac/stm32g071k6" ] | 760 | stm32g071k6 = [ "stm32-metapac/stm32g071k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 759 | stm32g071k8 = [ "stm32-metapac/stm32g071k8" ] | 761 | stm32g071k8 = [ "stm32-metapac/stm32g071k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 760 | stm32g071kb = [ "stm32-metapac/stm32g071kb" ] | 762 | stm32g071kb = [ "stm32-metapac/stm32g071kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 761 | stm32g071r6 = [ "stm32-metapac/stm32g071r6" ] | 763 | stm32g071r6 = [ "stm32-metapac/stm32g071r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 762 | stm32g071r8 = [ "stm32-metapac/stm32g071r8" ] | 764 | stm32g071r8 = [ "stm32-metapac/stm32g071r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 763 | stm32g071rb = [ "stm32-metapac/stm32g071rb" ] | 765 | stm32g071rb = [ "stm32-metapac/stm32g071rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 764 | stm32g081cb = [ "stm32-metapac/stm32g081cb" ] | 766 | stm32g081cb = [ "stm32-metapac/stm32g081cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 765 | stm32g081eb = [ "stm32-metapac/stm32g081eb" ] | 767 | stm32g081eb = [ "stm32-metapac/stm32g081eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 766 | stm32g081gb = [ "stm32-metapac/stm32g081gb" ] | 768 | stm32g081gb = [ "stm32-metapac/stm32g081gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 767 | stm32g081kb = [ "stm32-metapac/stm32g081kb" ] | 769 | stm32g081kb = [ "stm32-metapac/stm32g081kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 768 | stm32g081rb = [ "stm32-metapac/stm32g081rb" ] | 770 | stm32g081rb = [ "stm32-metapac/stm32g081rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 769 | stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce" ] | 771 | stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 770 | stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke" ] | 772 | stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 771 | stm32g0b0re = [ "stm32-metapac/stm32g0b0re" ] | 773 | stm32g0b0re = [ "stm32-metapac/stm32g0b0re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 772 | stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve" ] | 774 | stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 773 | stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb" ] | 775 | stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 774 | stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc" ] | 776 | stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 775 | stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce" ] | 777 | stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 776 | stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb" ] | 778 | stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 777 | stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc" ] | 779 | stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 778 | stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke" ] | 780 | stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 779 | stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb" ] | 781 | stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 780 | stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc" ] | 782 | stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 781 | stm32g0b1me = [ "stm32-metapac/stm32g0b1me" ] | 783 | stm32g0b1me = [ "stm32-metapac/stm32g0b1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 782 | stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne" ] | 784 | stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 783 | stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb" ] | 785 | stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 784 | stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc" ] | 786 | stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 785 | stm32g0b1re = [ "stm32-metapac/stm32g0b1re" ] | 787 | stm32g0b1re = [ "stm32-metapac/stm32g0b1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 786 | stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb" ] | 788 | stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 787 | stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc" ] | 789 | stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 788 | stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve" ] | 790 | stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 789 | stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc" ] | 791 | stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 790 | stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce" ] | 792 | stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 791 | stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc" ] | 793 | stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 792 | stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke" ] | 794 | stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 793 | stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc" ] | 795 | stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 794 | stm32g0c1me = [ "stm32-metapac/stm32g0c1me" ] | 796 | stm32g0c1me = [ "stm32-metapac/stm32g0c1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 795 | stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne" ] | 797 | stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 796 | stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc" ] | 798 | stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 797 | stm32g0c1re = [ "stm32-metapac/stm32g0c1re" ] | 799 | stm32g0c1re = [ "stm32-metapac/stm32g0c1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 798 | stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc" ] | 800 | stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 799 | stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve" ] | 801 | stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 800 | stm32g431c6 = [ "stm32-metapac/stm32g431c6" ] | 802 | stm32g431c6 = [ "stm32-metapac/stm32g431c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 801 | stm32g431c8 = [ "stm32-metapac/stm32g431c8" ] | 803 | stm32g431c8 = [ "stm32-metapac/stm32g431c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 802 | stm32g431cb = [ "stm32-metapac/stm32g431cb" ] | 804 | stm32g431cb = [ "stm32-metapac/stm32g431cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 803 | stm32g431k6 = [ "stm32-metapac/stm32g431k6" ] | 805 | stm32g431k6 = [ "stm32-metapac/stm32g431k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 804 | stm32g431k8 = [ "stm32-metapac/stm32g431k8" ] | 806 | stm32g431k8 = [ "stm32-metapac/stm32g431k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 805 | stm32g431kb = [ "stm32-metapac/stm32g431kb" ] | 807 | stm32g431kb = [ "stm32-metapac/stm32g431kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 806 | stm32g431m6 = [ "stm32-metapac/stm32g431m6" ] | 808 | stm32g431m6 = [ "stm32-metapac/stm32g431m6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 807 | stm32g431m8 = [ "stm32-metapac/stm32g431m8" ] | 809 | stm32g431m8 = [ "stm32-metapac/stm32g431m8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 808 | stm32g431mb = [ "stm32-metapac/stm32g431mb" ] | 810 | stm32g431mb = [ "stm32-metapac/stm32g431mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 809 | stm32g431r6 = [ "stm32-metapac/stm32g431r6" ] | 811 | stm32g431r6 = [ "stm32-metapac/stm32g431r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 810 | stm32g431r8 = [ "stm32-metapac/stm32g431r8" ] | 812 | stm32g431r8 = [ "stm32-metapac/stm32g431r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 811 | stm32g431rb = [ "stm32-metapac/stm32g431rb" ] | 813 | stm32g431rb = [ "stm32-metapac/stm32g431rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 812 | stm32g431v6 = [ "stm32-metapac/stm32g431v6" ] | 814 | stm32g431v6 = [ "stm32-metapac/stm32g431v6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 813 | stm32g431v8 = [ "stm32-metapac/stm32g431v8" ] | 815 | stm32g431v8 = [ "stm32-metapac/stm32g431v8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 814 | stm32g431vb = [ "stm32-metapac/stm32g431vb" ] | 816 | stm32g431vb = [ "stm32-metapac/stm32g431vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 815 | stm32g441cb = [ "stm32-metapac/stm32g441cb" ] | 817 | stm32g441cb = [ "stm32-metapac/stm32g441cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 816 | stm32g441kb = [ "stm32-metapac/stm32g441kb" ] | 818 | stm32g441kb = [ "stm32-metapac/stm32g441kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 817 | stm32g441mb = [ "stm32-metapac/stm32g441mb" ] | 819 | stm32g441mb = [ "stm32-metapac/stm32g441mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 818 | stm32g441rb = [ "stm32-metapac/stm32g441rb" ] | 820 | stm32g441rb = [ "stm32-metapac/stm32g441rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 819 | stm32g441vb = [ "stm32-metapac/stm32g441vb" ] | 821 | stm32g441vb = [ "stm32-metapac/stm32g441vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 820 | stm32g471cc = [ "stm32-metapac/stm32g471cc" ] | 822 | stm32g471cc = [ "stm32-metapac/stm32g471cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 821 | stm32g471ce = [ "stm32-metapac/stm32g471ce" ] | 823 | stm32g471ce = [ "stm32-metapac/stm32g471ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 822 | stm32g471mc = [ "stm32-metapac/stm32g471mc" ] | 824 | stm32g471mc = [ "stm32-metapac/stm32g471mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 823 | stm32g471me = [ "stm32-metapac/stm32g471me" ] | 825 | stm32g471me = [ "stm32-metapac/stm32g471me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 824 | stm32g471qc = [ "stm32-metapac/stm32g471qc" ] | 826 | stm32g471qc = [ "stm32-metapac/stm32g471qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 825 | stm32g471qe = [ "stm32-metapac/stm32g471qe" ] | 827 | stm32g471qe = [ "stm32-metapac/stm32g471qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 826 | stm32g471rc = [ "stm32-metapac/stm32g471rc" ] | 828 | stm32g471rc = [ "stm32-metapac/stm32g471rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 827 | stm32g471re = [ "stm32-metapac/stm32g471re" ] | 829 | stm32g471re = [ "stm32-metapac/stm32g471re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 828 | stm32g471vc = [ "stm32-metapac/stm32g471vc" ] | 830 | stm32g471vc = [ "stm32-metapac/stm32g471vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 829 | stm32g471ve = [ "stm32-metapac/stm32g471ve" ] | 831 | stm32g471ve = [ "stm32-metapac/stm32g471ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 830 | stm32g473cb = [ "stm32-metapac/stm32g473cb" ] | 832 | stm32g473cb = [ "stm32-metapac/stm32g473cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 831 | stm32g473cc = [ "stm32-metapac/stm32g473cc" ] | 833 | stm32g473cc = [ "stm32-metapac/stm32g473cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 832 | stm32g473ce = [ "stm32-metapac/stm32g473ce" ] | 834 | stm32g473ce = [ "stm32-metapac/stm32g473ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 833 | stm32g473mb = [ "stm32-metapac/stm32g473mb" ] | 835 | stm32g473mb = [ "stm32-metapac/stm32g473mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 834 | stm32g473mc = [ "stm32-metapac/stm32g473mc" ] | 836 | stm32g473mc = [ "stm32-metapac/stm32g473mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 835 | stm32g473me = [ "stm32-metapac/stm32g473me" ] | 837 | stm32g473me = [ "stm32-metapac/stm32g473me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 836 | stm32g473pb = [ "stm32-metapac/stm32g473pb" ] | 838 | stm32g473pb = [ "stm32-metapac/stm32g473pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 837 | stm32g473pc = [ "stm32-metapac/stm32g473pc" ] | 839 | stm32g473pc = [ "stm32-metapac/stm32g473pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 838 | stm32g473pe = [ "stm32-metapac/stm32g473pe" ] | 840 | stm32g473pe = [ "stm32-metapac/stm32g473pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 839 | stm32g473qb = [ "stm32-metapac/stm32g473qb" ] | 841 | stm32g473qb = [ "stm32-metapac/stm32g473qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 840 | stm32g473qc = [ "stm32-metapac/stm32g473qc" ] | 842 | stm32g473qc = [ "stm32-metapac/stm32g473qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 841 | stm32g473qe = [ "stm32-metapac/stm32g473qe" ] | 843 | stm32g473qe = [ "stm32-metapac/stm32g473qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 842 | stm32g473rb = [ "stm32-metapac/stm32g473rb" ] | 844 | stm32g473rb = [ "stm32-metapac/stm32g473rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 843 | stm32g473rc = [ "stm32-metapac/stm32g473rc" ] | 845 | stm32g473rc = [ "stm32-metapac/stm32g473rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 844 | stm32g473re = [ "stm32-metapac/stm32g473re" ] | 846 | stm32g473re = [ "stm32-metapac/stm32g473re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 845 | stm32g473vb = [ "stm32-metapac/stm32g473vb" ] | 847 | stm32g473vb = [ "stm32-metapac/stm32g473vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 846 | stm32g473vc = [ "stm32-metapac/stm32g473vc" ] | 848 | stm32g473vc = [ "stm32-metapac/stm32g473vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 847 | stm32g473ve = [ "stm32-metapac/stm32g473ve" ] | 849 | stm32g473ve = [ "stm32-metapac/stm32g473ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 848 | stm32g474cb = [ "stm32-metapac/stm32g474cb" ] | 850 | stm32g474cb = [ "stm32-metapac/stm32g474cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 849 | stm32g474cc = [ "stm32-metapac/stm32g474cc" ] | 851 | stm32g474cc = [ "stm32-metapac/stm32g474cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 850 | stm32g474ce = [ "stm32-metapac/stm32g474ce" ] | 852 | stm32g474ce = [ "stm32-metapac/stm32g474ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 851 | stm32g474mb = [ "stm32-metapac/stm32g474mb" ] | 853 | stm32g474mb = [ "stm32-metapac/stm32g474mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 852 | stm32g474mc = [ "stm32-metapac/stm32g474mc" ] | 854 | stm32g474mc = [ "stm32-metapac/stm32g474mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 853 | stm32g474me = [ "stm32-metapac/stm32g474me" ] | 855 | stm32g474me = [ "stm32-metapac/stm32g474me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 854 | stm32g474pb = [ "stm32-metapac/stm32g474pb" ] | 856 | stm32g474pb = [ "stm32-metapac/stm32g474pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 855 | stm32g474pc = [ "stm32-metapac/stm32g474pc" ] | 857 | stm32g474pc = [ "stm32-metapac/stm32g474pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 856 | stm32g474pe = [ "stm32-metapac/stm32g474pe" ] | 858 | stm32g474pe = [ "stm32-metapac/stm32g474pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 857 | stm32g474qb = [ "stm32-metapac/stm32g474qb" ] | 859 | stm32g474qb = [ "stm32-metapac/stm32g474qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 858 | stm32g474qc = [ "stm32-metapac/stm32g474qc" ] | 860 | stm32g474qc = [ "stm32-metapac/stm32g474qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 859 | stm32g474qe = [ "stm32-metapac/stm32g474qe" ] | 861 | stm32g474qe = [ "stm32-metapac/stm32g474qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 860 | stm32g474rb = [ "stm32-metapac/stm32g474rb" ] | 862 | stm32g474rb = [ "stm32-metapac/stm32g474rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 861 | stm32g474rc = [ "stm32-metapac/stm32g474rc" ] | 863 | stm32g474rc = [ "stm32-metapac/stm32g474rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 862 | stm32g474re = [ "stm32-metapac/stm32g474re" ] | 864 | stm32g474re = [ "stm32-metapac/stm32g474re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 863 | stm32g474vb = [ "stm32-metapac/stm32g474vb" ] | 865 | stm32g474vb = [ "stm32-metapac/stm32g474vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 864 | stm32g474vc = [ "stm32-metapac/stm32g474vc" ] | 866 | stm32g474vc = [ "stm32-metapac/stm32g474vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 865 | stm32g474ve = [ "stm32-metapac/stm32g474ve" ] | 867 | stm32g474ve = [ "stm32-metapac/stm32g474ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 866 | stm32g483ce = [ "stm32-metapac/stm32g483ce" ] | 868 | stm32g483ce = [ "stm32-metapac/stm32g483ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 867 | stm32g483me = [ "stm32-metapac/stm32g483me" ] | 869 | stm32g483me = [ "stm32-metapac/stm32g483me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 868 | stm32g483pe = [ "stm32-metapac/stm32g483pe" ] | 870 | stm32g483pe = [ "stm32-metapac/stm32g483pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 869 | stm32g483qe = [ "stm32-metapac/stm32g483qe" ] | 871 | stm32g483qe = [ "stm32-metapac/stm32g483qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 870 | stm32g483re = [ "stm32-metapac/stm32g483re" ] | 872 | stm32g483re = [ "stm32-metapac/stm32g483re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 871 | stm32g483ve = [ "stm32-metapac/stm32g483ve" ] | 873 | stm32g483ve = [ "stm32-metapac/stm32g483ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 872 | stm32g484ce = [ "stm32-metapac/stm32g484ce" ] | 874 | stm32g484ce = [ "stm32-metapac/stm32g484ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 873 | stm32g484me = [ "stm32-metapac/stm32g484me" ] | 875 | stm32g484me = [ "stm32-metapac/stm32g484me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 874 | stm32g484pe = [ "stm32-metapac/stm32g484pe" ] | 876 | stm32g484pe = [ "stm32-metapac/stm32g484pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 875 | stm32g484qe = [ "stm32-metapac/stm32g484qe" ] | 877 | stm32g484qe = [ "stm32-metapac/stm32g484qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 876 | stm32g484re = [ "stm32-metapac/stm32g484re" ] | 878 | stm32g484re = [ "stm32-metapac/stm32g484re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 877 | stm32g484ve = [ "stm32-metapac/stm32g484ve" ] | 879 | stm32g484ve = [ "stm32-metapac/stm32g484ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 878 | stm32g491cc = [ "stm32-metapac/stm32g491cc" ] | 880 | stm32g491cc = [ "stm32-metapac/stm32g491cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 879 | stm32g491ce = [ "stm32-metapac/stm32g491ce" ] | 881 | stm32g491ce = [ "stm32-metapac/stm32g491ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 880 | stm32g491kc = [ "stm32-metapac/stm32g491kc" ] | 882 | stm32g491kc = [ "stm32-metapac/stm32g491kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 881 | stm32g491ke = [ "stm32-metapac/stm32g491ke" ] | 883 | stm32g491ke = [ "stm32-metapac/stm32g491ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 882 | stm32g491mc = [ "stm32-metapac/stm32g491mc" ] | 884 | stm32g491mc = [ "stm32-metapac/stm32g491mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 883 | stm32g491me = [ "stm32-metapac/stm32g491me" ] | 885 | stm32g491me = [ "stm32-metapac/stm32g491me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 884 | stm32g491rc = [ "stm32-metapac/stm32g491rc" ] | 886 | stm32g491rc = [ "stm32-metapac/stm32g491rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 885 | stm32g491re = [ "stm32-metapac/stm32g491re" ] | 887 | stm32g491re = [ "stm32-metapac/stm32g491re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 886 | stm32g491vc = [ "stm32-metapac/stm32g491vc" ] | 888 | stm32g491vc = [ "stm32-metapac/stm32g491vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 887 | stm32g491ve = [ "stm32-metapac/stm32g491ve" ] | 889 | stm32g491ve = [ "stm32-metapac/stm32g491ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 888 | stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce" ] | 890 | stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 889 | stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ] | 891 | stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 890 | stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] | 892 | stm32g4a1me = [ "stm32-metapac/stm32g4a1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 891 | stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] | 893 | stm32g4a1re = [ "stm32-metapac/stm32g4a1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 892 | stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] | 894 | stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 893 | stm32h503cb = [ "stm32-metapac/stm32h503cb" ] | 895 | stm32h503cb = [ "stm32-metapac/stm32h503cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 894 | stm32h503eb = [ "stm32-metapac/stm32h503eb" ] | 896 | stm32h503eb = [ "stm32-metapac/stm32h503eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 895 | stm32h503kb = [ "stm32-metapac/stm32h503kb" ] | 897 | stm32h503kb = [ "stm32-metapac/stm32h503kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 896 | stm32h503rb = [ "stm32-metapac/stm32h503rb" ] | 898 | stm32h503rb = [ "stm32-metapac/stm32h503rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 897 | stm32h562ag = [ "stm32-metapac/stm32h562ag" ] | 899 | stm32h562ag = [ "stm32-metapac/stm32h562ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 898 | stm32h562ai = [ "stm32-metapac/stm32h562ai" ] | 900 | stm32h562ai = [ "stm32-metapac/stm32h562ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 899 | stm32h562ig = [ "stm32-metapac/stm32h562ig" ] | 901 | stm32h562ig = [ "stm32-metapac/stm32h562ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 900 | stm32h562ii = [ "stm32-metapac/stm32h562ii" ] | 902 | stm32h562ii = [ "stm32-metapac/stm32h562ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 901 | stm32h562rg = [ "stm32-metapac/stm32h562rg" ] | 903 | stm32h562rg = [ "stm32-metapac/stm32h562rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 902 | stm32h562ri = [ "stm32-metapac/stm32h562ri" ] | 904 | stm32h562ri = [ "stm32-metapac/stm32h562ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 903 | stm32h562vg = [ "stm32-metapac/stm32h562vg" ] | 905 | stm32h562vg = [ "stm32-metapac/stm32h562vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 904 | stm32h562vi = [ "stm32-metapac/stm32h562vi" ] | 906 | stm32h562vi = [ "stm32-metapac/stm32h562vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 905 | stm32h562zg = [ "stm32-metapac/stm32h562zg" ] | 907 | stm32h562zg = [ "stm32-metapac/stm32h562zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 906 | stm32h562zi = [ "stm32-metapac/stm32h562zi" ] | 908 | stm32h562zi = [ "stm32-metapac/stm32h562zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 907 | stm32h563ag = [ "stm32-metapac/stm32h563ag" ] | 909 | stm32h563ag = [ "stm32-metapac/stm32h563ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 908 | stm32h563ai = [ "stm32-metapac/stm32h563ai" ] | 910 | stm32h563ai = [ "stm32-metapac/stm32h563ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 909 | stm32h563ig = [ "stm32-metapac/stm32h563ig" ] | 911 | stm32h563ig = [ "stm32-metapac/stm32h563ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 910 | stm32h563ii = [ "stm32-metapac/stm32h563ii" ] | 912 | stm32h563ii = [ "stm32-metapac/stm32h563ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 911 | stm32h563mi = [ "stm32-metapac/stm32h563mi" ] | 913 | stm32h563mi = [ "stm32-metapac/stm32h563mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 912 | stm32h563rg = [ "stm32-metapac/stm32h563rg" ] | 914 | stm32h563rg = [ "stm32-metapac/stm32h563rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 913 | stm32h563ri = [ "stm32-metapac/stm32h563ri" ] | 915 | stm32h563ri = [ "stm32-metapac/stm32h563ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 914 | stm32h563vg = [ "stm32-metapac/stm32h563vg" ] | 916 | stm32h563vg = [ "stm32-metapac/stm32h563vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 915 | stm32h563vi = [ "stm32-metapac/stm32h563vi" ] | 917 | stm32h563vi = [ "stm32-metapac/stm32h563vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 916 | stm32h563zg = [ "stm32-metapac/stm32h563zg" ] | 918 | stm32h563zg = [ "stm32-metapac/stm32h563zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 917 | stm32h563zi = [ "stm32-metapac/stm32h563zi" ] | 919 | stm32h563zi = [ "stm32-metapac/stm32h563zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 918 | stm32h573ai = [ "stm32-metapac/stm32h573ai" ] | 920 | stm32h573ai = [ "stm32-metapac/stm32h573ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 919 | stm32h573ii = [ "stm32-metapac/stm32h573ii" ] | 921 | stm32h573ii = [ "stm32-metapac/stm32h573ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 920 | stm32h573mi = [ "stm32-metapac/stm32h573mi" ] | 922 | stm32h573mi = [ "stm32-metapac/stm32h573mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 921 | stm32h573ri = [ "stm32-metapac/stm32h573ri" ] | 923 | stm32h573ri = [ "stm32-metapac/stm32h573ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 922 | stm32h573vi = [ "stm32-metapac/stm32h573vi" ] | 924 | stm32h573vi = [ "stm32-metapac/stm32h573vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 923 | stm32h573zi = [ "stm32-metapac/stm32h573zi" ] | 925 | stm32h573zi = [ "stm32-metapac/stm32h573zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 924 | stm32h723ve = [ "stm32-metapac/stm32h723ve" ] | 926 | stm32h723ve = [ "stm32-metapac/stm32h723ve", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 925 | stm32h723vg = [ "stm32-metapac/stm32h723vg" ] | 927 | stm32h723vg = [ "stm32-metapac/stm32h723vg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 926 | stm32h723ze = [ "stm32-metapac/stm32h723ze" ] | 928 | stm32h723ze = [ "stm32-metapac/stm32h723ze", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 927 | stm32h723zg = [ "stm32-metapac/stm32h723zg" ] | 929 | stm32h723zg = [ "stm32-metapac/stm32h723zg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 928 | stm32h725ae = [ "stm32-metapac/stm32h725ae" ] | 930 | stm32h725ae = [ "stm32-metapac/stm32h725ae", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 929 | stm32h725ag = [ "stm32-metapac/stm32h725ag" ] | 931 | stm32h725ag = [ "stm32-metapac/stm32h725ag", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 930 | stm32h725ie = [ "stm32-metapac/stm32h725ie" ] | 932 | stm32h725ie = [ "stm32-metapac/stm32h725ie", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 931 | stm32h725ig = [ "stm32-metapac/stm32h725ig" ] | 933 | stm32h725ig = [ "stm32-metapac/stm32h725ig", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 932 | stm32h725re = [ "stm32-metapac/stm32h725re" ] | 934 | stm32h725re = [ "stm32-metapac/stm32h725re", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 933 | stm32h725rg = [ "stm32-metapac/stm32h725rg" ] | 935 | stm32h725rg = [ "stm32-metapac/stm32h725rg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 934 | stm32h725ve = [ "stm32-metapac/stm32h725ve" ] | 936 | stm32h725ve = [ "stm32-metapac/stm32h725ve", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 935 | stm32h725vg = [ "stm32-metapac/stm32h725vg" ] | 937 | stm32h725vg = [ "stm32-metapac/stm32h725vg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 936 | stm32h725ze = [ "stm32-metapac/stm32h725ze" ] | 938 | stm32h725ze = [ "stm32-metapac/stm32h725ze", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 937 | stm32h725zg = [ "stm32-metapac/stm32h725zg" ] | 939 | stm32h725zg = [ "stm32-metapac/stm32h725zg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 938 | stm32h730ab = [ "stm32-metapac/stm32h730ab" ] | 940 | stm32h730ab = [ "stm32-metapac/stm32h730ab", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 939 | stm32h730ib = [ "stm32-metapac/stm32h730ib" ] | 941 | stm32h730ib = [ "stm32-metapac/stm32h730ib", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 940 | stm32h730vb = [ "stm32-metapac/stm32h730vb" ] | 942 | stm32h730vb = [ "stm32-metapac/stm32h730vb", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 941 | stm32h730zb = [ "stm32-metapac/stm32h730zb" ] | 943 | stm32h730zb = [ "stm32-metapac/stm32h730zb", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 942 | stm32h733vg = [ "stm32-metapac/stm32h733vg" ] | 944 | stm32h733vg = [ "stm32-metapac/stm32h733vg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 943 | stm32h733zg = [ "stm32-metapac/stm32h733zg" ] | 945 | stm32h733zg = [ "stm32-metapac/stm32h733zg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 944 | stm32h735ag = [ "stm32-metapac/stm32h735ag" ] | 946 | stm32h735ag = [ "stm32-metapac/stm32h735ag", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 945 | stm32h735ig = [ "stm32-metapac/stm32h735ig" ] | 947 | stm32h735ig = [ "stm32-metapac/stm32h735ig", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 946 | stm32h735rg = [ "stm32-metapac/stm32h735rg" ] | 948 | stm32h735rg = [ "stm32-metapac/stm32h735rg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 947 | stm32h735vg = [ "stm32-metapac/stm32h735vg" ] | 949 | stm32h735vg = [ "stm32-metapac/stm32h735vg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 948 | stm32h735zg = [ "stm32-metapac/stm32h735zg" ] | 950 | stm32h735zg = [ "stm32-metapac/stm32h735zg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 949 | stm32h742ag = [ "stm32-metapac/stm32h742ag" ] | 951 | stm32h742ag = [ "stm32-metapac/stm32h742ag", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 950 | stm32h742ai = [ "stm32-metapac/stm32h742ai" ] | 952 | stm32h742ai = [ "stm32-metapac/stm32h742ai", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 951 | stm32h742bg = [ "stm32-metapac/stm32h742bg" ] | 953 | stm32h742bg = [ "stm32-metapac/stm32h742bg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 952 | stm32h742bi = [ "stm32-metapac/stm32h742bi" ] | 954 | stm32h742bi = [ "stm32-metapac/stm32h742bi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 953 | stm32h742ig = [ "stm32-metapac/stm32h742ig" ] | 955 | stm32h742ig = [ "stm32-metapac/stm32h742ig", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 954 | stm32h742ii = [ "stm32-metapac/stm32h742ii" ] | 956 | stm32h742ii = [ "stm32-metapac/stm32h742ii", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 955 | stm32h742vg = [ "stm32-metapac/stm32h742vg" ] | 957 | stm32h742vg = [ "stm32-metapac/stm32h742vg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 956 | stm32h742vi = [ "stm32-metapac/stm32h742vi" ] | 958 | stm32h742vi = [ "stm32-metapac/stm32h742vi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 957 | stm32h742xg = [ "stm32-metapac/stm32h742xg" ] | 959 | stm32h742xg = [ "stm32-metapac/stm32h742xg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 958 | stm32h742xi = [ "stm32-metapac/stm32h742xi" ] | 960 | stm32h742xi = [ "stm32-metapac/stm32h742xi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 959 | stm32h742zg = [ "stm32-metapac/stm32h742zg" ] | 961 | stm32h742zg = [ "stm32-metapac/stm32h742zg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 960 | stm32h742zi = [ "stm32-metapac/stm32h742zi" ] | 962 | stm32h742zi = [ "stm32-metapac/stm32h742zi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 961 | stm32h743ag = [ "stm32-metapac/stm32h743ag" ] | 963 | stm32h743ag = [ "stm32-metapac/stm32h743ag", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 962 | stm32h743ai = [ "stm32-metapac/stm32h743ai" ] | 964 | stm32h743ai = [ "stm32-metapac/stm32h743ai", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 963 | stm32h743bg = [ "stm32-metapac/stm32h743bg" ] | 965 | stm32h743bg = [ "stm32-metapac/stm32h743bg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 964 | stm32h743bi = [ "stm32-metapac/stm32h743bi" ] | 966 | stm32h743bi = [ "stm32-metapac/stm32h743bi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 965 | stm32h743ig = [ "stm32-metapac/stm32h743ig" ] | 967 | stm32h743ig = [ "stm32-metapac/stm32h743ig", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 966 | stm32h743ii = [ "stm32-metapac/stm32h743ii" ] | 968 | stm32h743ii = [ "stm32-metapac/stm32h743ii", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 967 | stm32h743vg = [ "stm32-metapac/stm32h743vg" ] | 969 | stm32h743vg = [ "stm32-metapac/stm32h743vg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 968 | stm32h743vi = [ "stm32-metapac/stm32h743vi" ] | 970 | stm32h743vi = [ "stm32-metapac/stm32h743vi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 969 | stm32h743xg = [ "stm32-metapac/stm32h743xg" ] | 971 | stm32h743xg = [ "stm32-metapac/stm32h743xg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 970 | stm32h743xi = [ "stm32-metapac/stm32h743xi" ] | 972 | stm32h743xi = [ "stm32-metapac/stm32h743xi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 971 | stm32h743zg = [ "stm32-metapac/stm32h743zg" ] | 973 | stm32h743zg = [ "stm32-metapac/stm32h743zg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 972 | stm32h743zi = [ "stm32-metapac/stm32h743zi" ] | 974 | stm32h743zi = [ "stm32-metapac/stm32h743zi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 973 | stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ] | 975 | stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 974 | stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ] | 976 | stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 975 | stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ] | 977 | stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 976 | stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ] | 978 | stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 977 | stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ] | 979 | stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 978 | stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ] | 980 | stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 979 | stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ] | 981 | stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 980 | stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ] | 982 | stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 981 | stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ] | 983 | stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 982 | stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ] | 984 | stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 983 | stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ] | 985 | stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 984 | stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ] | 986 | stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 985 | stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ] | 987 | stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 986 | stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ] | 988 | stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 987 | stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ] | 989 | stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 988 | stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ] | 990 | stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 989 | stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ] | 991 | stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 990 | stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ] | 992 | stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 991 | stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ] | 993 | stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 992 | stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ] | 994 | stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 993 | stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ] | 995 | stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 994 | stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ] | 996 | stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 995 | stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ] | 997 | stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 996 | stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ] | 998 | stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 997 | stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ] | 999 | stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 998 | stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ] | 1000 | stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 999 | stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ] | 1001 | stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1000 | stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ] | 1002 | stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1001 | stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ] | 1003 | stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1002 | stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ] | 1004 | stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1003 | stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ] | 1005 | stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1004 | stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ] | 1006 | stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1005 | stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ] | 1007 | stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1006 | stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ] | 1008 | stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1007 | stm32h750ib = [ "stm32-metapac/stm32h750ib" ] | 1009 | stm32h750ib = [ "stm32-metapac/stm32h750ib", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1008 | stm32h750vb = [ "stm32-metapac/stm32h750vb" ] | 1010 | stm32h750vb = [ "stm32-metapac/stm32h750vb", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1009 | stm32h750xb = [ "stm32-metapac/stm32h750xb" ] | 1011 | stm32h750xb = [ "stm32-metapac/stm32h750xb", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1010 | stm32h750zb = [ "stm32-metapac/stm32h750zb" ] | 1012 | stm32h750zb = [ "stm32-metapac/stm32h750zb", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1011 | stm32h753ai = [ "stm32-metapac/stm32h753ai" ] | 1013 | stm32h753ai = [ "stm32-metapac/stm32h753ai", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1012 | stm32h753bi = [ "stm32-metapac/stm32h753bi" ] | 1014 | stm32h753bi = [ "stm32-metapac/stm32h753bi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1013 | stm32h753ii = [ "stm32-metapac/stm32h753ii" ] | 1015 | stm32h753ii = [ "stm32-metapac/stm32h753ii", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1014 | stm32h753vi = [ "stm32-metapac/stm32h753vi" ] | 1016 | stm32h753vi = [ "stm32-metapac/stm32h753vi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1015 | stm32h753xi = [ "stm32-metapac/stm32h753xi" ] | 1017 | stm32h753xi = [ "stm32-metapac/stm32h753xi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1016 | stm32h753zi = [ "stm32-metapac/stm32h753zi" ] | 1018 | stm32h753zi = [ "stm32-metapac/stm32h753zi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1017 | stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ] | 1019 | stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1018 | stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ] | 1020 | stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1019 | stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ] | 1021 | stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1020 | stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ] | 1022 | stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1021 | stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ] | 1023 | stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1022 | stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ] | 1024 | stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1023 | stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ] | 1025 | stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1024 | stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ] | 1026 | stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1025 | stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ] | 1027 | stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1026 | stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ] | 1028 | stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1027 | stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ] | 1029 | stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1028 | stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ] | 1030 | stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1029 | stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ] | 1031 | stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1030 | stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ] | 1032 | stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1031 | stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ] | 1033 | stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1032 | stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ] | 1034 | stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1033 | stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ] | 1035 | stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1034 | stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ] | 1036 | stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1035 | stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] | 1037 | stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1036 | stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] | 1038 | stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1037 | stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] | 1039 | stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1038 | stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii" ] | 1040 | stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1039 | stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg" ] | 1041 | stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1040 | stm32h7a3li = [ "stm32-metapac/stm32h7a3li" ] | 1042 | stm32h7a3li = [ "stm32-metapac/stm32h7a3li", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1041 | stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng" ] | 1043 | stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1042 | stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni" ] | 1044 | stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1043 | stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi" ] | 1045 | stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1044 | stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg" ] | 1046 | stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1045 | stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri" ] | 1047 | stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1046 | stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg" ] | 1048 | stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1047 | stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi" ] | 1049 | stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1048 | stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg" ] | 1050 | stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1049 | stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi" ] | 1051 | stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1050 | stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab" ] | 1052 | stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1051 | stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib" ] | 1053 | stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1052 | stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb" ] | 1054 | stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1053 | stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb" ] | 1055 | stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1054 | stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb" ] | 1056 | stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1055 | stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai" ] | 1057 | stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1056 | stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii" ] | 1058 | stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1057 | stm32h7b3li = [ "stm32-metapac/stm32h7b3li" ] | 1059 | stm32h7b3li = [ "stm32-metapac/stm32h7b3li", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1058 | stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni" ] | 1060 | stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1059 | stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ] | 1061 | stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1060 | stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ] | 1062 | stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1061 | stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ] | 1063 | stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1062 | stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ] | 1064 | stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi", "dep:fdcan", "fdcan/fdcan_h7" ] |
| 1063 | stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] | 1065 | stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] |
| 1064 | stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] | 1066 | stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] |
| 1065 | stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] | 1067 | stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] |
| @@ -1386,86 +1388,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ] | |||
| 1386 | stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] | 1388 | stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] |
| 1387 | stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] | 1389 | stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] |
| 1388 | stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] | 1390 | stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] |
| 1389 | stm32l552cc = [ "stm32-metapac/stm32l552cc" ] | 1391 | stm32l552cc = [ "stm32-metapac/stm32l552cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1390 | stm32l552ce = [ "stm32-metapac/stm32l552ce" ] | 1392 | stm32l552ce = [ "stm32-metapac/stm32l552ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1391 | stm32l552me = [ "stm32-metapac/stm32l552me" ] | 1393 | stm32l552me = [ "stm32-metapac/stm32l552me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1392 | stm32l552qc = [ "stm32-metapac/stm32l552qc" ] | 1394 | stm32l552qc = [ "stm32-metapac/stm32l552qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1393 | stm32l552qe = [ "stm32-metapac/stm32l552qe" ] | 1395 | stm32l552qe = [ "stm32-metapac/stm32l552qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1394 | stm32l552rc = [ "stm32-metapac/stm32l552rc" ] | 1396 | stm32l552rc = [ "stm32-metapac/stm32l552rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1395 | stm32l552re = [ "stm32-metapac/stm32l552re" ] | 1397 | stm32l552re = [ "stm32-metapac/stm32l552re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1396 | stm32l552vc = [ "stm32-metapac/stm32l552vc" ] | 1398 | stm32l552vc = [ "stm32-metapac/stm32l552vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1397 | stm32l552ve = [ "stm32-metapac/stm32l552ve" ] | 1399 | stm32l552ve = [ "stm32-metapac/stm32l552ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1398 | stm32l552zc = [ "stm32-metapac/stm32l552zc" ] | 1400 | stm32l552zc = [ "stm32-metapac/stm32l552zc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1399 | stm32l552ze = [ "stm32-metapac/stm32l552ze" ] | 1401 | stm32l552ze = [ "stm32-metapac/stm32l552ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1400 | stm32l562ce = [ "stm32-metapac/stm32l562ce" ] | 1402 | stm32l562ce = [ "stm32-metapac/stm32l562ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1401 | stm32l562me = [ "stm32-metapac/stm32l562me" ] | 1403 | stm32l562me = [ "stm32-metapac/stm32l562me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1402 | stm32l562qe = [ "stm32-metapac/stm32l562qe" ] | 1404 | stm32l562qe = [ "stm32-metapac/stm32l562qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1403 | stm32l562re = [ "stm32-metapac/stm32l562re" ] | 1405 | stm32l562re = [ "stm32-metapac/stm32l562re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1404 | stm32l562ve = [ "stm32-metapac/stm32l562ve" ] | 1406 | stm32l562ve = [ "stm32-metapac/stm32l562ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1405 | stm32l562ze = [ "stm32-metapac/stm32l562ze" ] | 1407 | stm32l562ze = [ "stm32-metapac/stm32l562ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1406 | stm32u535cb = [ "stm32-metapac/stm32u535cb" ] | 1408 | stm32u535cb = [ "stm32-metapac/stm32u535cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1407 | stm32u535cc = [ "stm32-metapac/stm32u535cc" ] | 1409 | stm32u535cc = [ "stm32-metapac/stm32u535cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1408 | stm32u535ce = [ "stm32-metapac/stm32u535ce" ] | 1410 | stm32u535ce = [ "stm32-metapac/stm32u535ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1409 | stm32u535je = [ "stm32-metapac/stm32u535je" ] | 1411 | stm32u535je = [ "stm32-metapac/stm32u535je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1410 | stm32u535nc = [ "stm32-metapac/stm32u535nc" ] | 1412 | stm32u535nc = [ "stm32-metapac/stm32u535nc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1411 | stm32u535ne = [ "stm32-metapac/stm32u535ne" ] | 1413 | stm32u535ne = [ "stm32-metapac/stm32u535ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1412 | stm32u535rb = [ "stm32-metapac/stm32u535rb" ] | 1414 | stm32u535rb = [ "stm32-metapac/stm32u535rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1413 | stm32u535rc = [ "stm32-metapac/stm32u535rc" ] | 1415 | stm32u535rc = [ "stm32-metapac/stm32u535rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1414 | stm32u535re = [ "stm32-metapac/stm32u535re" ] | 1416 | stm32u535re = [ "stm32-metapac/stm32u535re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1415 | stm32u535vc = [ "stm32-metapac/stm32u535vc" ] | 1417 | stm32u535vc = [ "stm32-metapac/stm32u535vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1416 | stm32u535ve = [ "stm32-metapac/stm32u535ve" ] | 1418 | stm32u535ve = [ "stm32-metapac/stm32u535ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1417 | stm32u545ce = [ "stm32-metapac/stm32u545ce" ] | 1419 | stm32u545ce = [ "stm32-metapac/stm32u545ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1418 | stm32u545je = [ "stm32-metapac/stm32u545je" ] | 1420 | stm32u545je = [ "stm32-metapac/stm32u545je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1419 | stm32u545ne = [ "stm32-metapac/stm32u545ne" ] | 1421 | stm32u545ne = [ "stm32-metapac/stm32u545ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1420 | stm32u545re = [ "stm32-metapac/stm32u545re" ] | 1422 | stm32u545re = [ "stm32-metapac/stm32u545re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1421 | stm32u545ve = [ "stm32-metapac/stm32u545ve" ] | 1423 | stm32u545ve = [ "stm32-metapac/stm32u545ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1422 | stm32u575ag = [ "stm32-metapac/stm32u575ag" ] | 1424 | stm32u575ag = [ "stm32-metapac/stm32u575ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1423 | stm32u575ai = [ "stm32-metapac/stm32u575ai" ] | 1425 | stm32u575ai = [ "stm32-metapac/stm32u575ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1424 | stm32u575cg = [ "stm32-metapac/stm32u575cg" ] | 1426 | stm32u575cg = [ "stm32-metapac/stm32u575cg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1425 | stm32u575ci = [ "stm32-metapac/stm32u575ci" ] | 1427 | stm32u575ci = [ "stm32-metapac/stm32u575ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1426 | stm32u575og = [ "stm32-metapac/stm32u575og" ] | 1428 | stm32u575og = [ "stm32-metapac/stm32u575og", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1427 | stm32u575oi = [ "stm32-metapac/stm32u575oi" ] | 1429 | stm32u575oi = [ "stm32-metapac/stm32u575oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1428 | stm32u575qg = [ "stm32-metapac/stm32u575qg" ] | 1430 | stm32u575qg = [ "stm32-metapac/stm32u575qg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1429 | stm32u575qi = [ "stm32-metapac/stm32u575qi" ] | 1431 | stm32u575qi = [ "stm32-metapac/stm32u575qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1430 | stm32u575rg = [ "stm32-metapac/stm32u575rg" ] | 1432 | stm32u575rg = [ "stm32-metapac/stm32u575rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1431 | stm32u575ri = [ "stm32-metapac/stm32u575ri" ] | 1433 | stm32u575ri = [ "stm32-metapac/stm32u575ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1432 | stm32u575vg = [ "stm32-metapac/stm32u575vg" ] | 1434 | stm32u575vg = [ "stm32-metapac/stm32u575vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1433 | stm32u575vi = [ "stm32-metapac/stm32u575vi" ] | 1435 | stm32u575vi = [ "stm32-metapac/stm32u575vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1434 | stm32u575zg = [ "stm32-metapac/stm32u575zg" ] | 1436 | stm32u575zg = [ "stm32-metapac/stm32u575zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1435 | stm32u575zi = [ "stm32-metapac/stm32u575zi" ] | 1437 | stm32u575zi = [ "stm32-metapac/stm32u575zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1436 | stm32u585ai = [ "stm32-metapac/stm32u585ai" ] | 1438 | stm32u585ai = [ "stm32-metapac/stm32u585ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1437 | stm32u585ci = [ "stm32-metapac/stm32u585ci" ] | 1439 | stm32u585ci = [ "stm32-metapac/stm32u585ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1438 | stm32u585oi = [ "stm32-metapac/stm32u585oi" ] | 1440 | stm32u585oi = [ "stm32-metapac/stm32u585oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1439 | stm32u585qi = [ "stm32-metapac/stm32u585qi" ] | 1441 | stm32u585qi = [ "stm32-metapac/stm32u585qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1440 | stm32u585ri = [ "stm32-metapac/stm32u585ri" ] | 1442 | stm32u585ri = [ "stm32-metapac/stm32u585ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1441 | stm32u585vi = [ "stm32-metapac/stm32u585vi" ] | 1443 | stm32u585vi = [ "stm32-metapac/stm32u585vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1442 | stm32u585zi = [ "stm32-metapac/stm32u585zi" ] | 1444 | stm32u585zi = [ "stm32-metapac/stm32u585zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1443 | stm32u595ai = [ "stm32-metapac/stm32u595ai" ] | 1445 | stm32u595ai = [ "stm32-metapac/stm32u595ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1444 | stm32u595aj = [ "stm32-metapac/stm32u595aj" ] | 1446 | stm32u595aj = [ "stm32-metapac/stm32u595aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1445 | stm32u595qi = [ "stm32-metapac/stm32u595qi" ] | 1447 | stm32u595qi = [ "stm32-metapac/stm32u595qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1446 | stm32u595qj = [ "stm32-metapac/stm32u595qj" ] | 1448 | stm32u595qj = [ "stm32-metapac/stm32u595qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1447 | stm32u595ri = [ "stm32-metapac/stm32u595ri" ] | 1449 | stm32u595ri = [ "stm32-metapac/stm32u595ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1448 | stm32u595rj = [ "stm32-metapac/stm32u595rj" ] | 1450 | stm32u595rj = [ "stm32-metapac/stm32u595rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1449 | stm32u595vi = [ "stm32-metapac/stm32u595vi" ] | 1451 | stm32u595vi = [ "stm32-metapac/stm32u595vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1450 | stm32u595vj = [ "stm32-metapac/stm32u595vj" ] | 1452 | stm32u595vj = [ "stm32-metapac/stm32u595vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1451 | stm32u595zi = [ "stm32-metapac/stm32u595zi" ] | 1453 | stm32u595zi = [ "stm32-metapac/stm32u595zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1452 | stm32u595zj = [ "stm32-metapac/stm32u595zj" ] | 1454 | stm32u595zj = [ "stm32-metapac/stm32u595zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1453 | stm32u599bj = [ "stm32-metapac/stm32u599bj" ] | 1455 | stm32u599bj = [ "stm32-metapac/stm32u599bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1454 | stm32u599ni = [ "stm32-metapac/stm32u599ni" ] | 1456 | stm32u599ni = [ "stm32-metapac/stm32u599ni", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1455 | stm32u599nj = [ "stm32-metapac/stm32u599nj" ] | 1457 | stm32u599nj = [ "stm32-metapac/stm32u599nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1456 | stm32u599vi = [ "stm32-metapac/stm32u599vi" ] | 1458 | stm32u599vi = [ "stm32-metapac/stm32u599vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1457 | stm32u599vj = [ "stm32-metapac/stm32u599vj" ] | 1459 | stm32u599vj = [ "stm32-metapac/stm32u599vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1458 | stm32u599zi = [ "stm32-metapac/stm32u599zi" ] | 1460 | stm32u599zi = [ "stm32-metapac/stm32u599zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1459 | stm32u599zj = [ "stm32-metapac/stm32u599zj" ] | 1461 | stm32u599zj = [ "stm32-metapac/stm32u599zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1460 | stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] | 1462 | stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1461 | stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] | 1463 | stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1462 | stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] | 1464 | stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1463 | stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] | 1465 | stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1464 | stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ] | 1466 | stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1465 | stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ] | 1467 | stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1466 | stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ] | 1468 | stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1467 | stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ] | 1469 | stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1468 | stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ] | 1470 | stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] |
| 1469 | stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] | 1471 | stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] |
| 1470 | stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] | 1472 | stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] |
| 1471 | stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] | 1473 | stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 948ce3aff..414723573 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -449,7 +449,7 @@ fn main() { | |||
| 449 | // ======== | 449 | // ======== |
| 450 | // Generate RccPeripheral impls | 450 | // Generate RccPeripheral impls |
| 451 | 451 | ||
| 452 | let refcounted_peripherals = HashSet::from(["usart", "adc"]); | 452 | let refcounted_peripherals = HashSet::from(["usart", "adc", "can"]); |
| 453 | let mut refcount_statics = BTreeSet::new(); | 453 | let mut refcount_statics = BTreeSet::new(); |
| 454 | 454 | ||
| 455 | for p in METADATA.peripherals { | 455 | for p in METADATA.peripherals { |
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index cc87b2565..7e00eca6f 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -13,9 +13,12 @@ use crate::gpio::sealed::AFType; | |||
| 13 | use crate::interrupt::typelevel::Interrupt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 14 | use crate::pac::can::vals::{Ide, Lec}; | 14 | use crate::pac::can::vals::{Ide, Lec}; |
| 15 | use crate::rcc::RccPeripheral; | 15 | use crate::rcc::RccPeripheral; |
| 16 | use crate::time::Hertz; | ||
| 17 | use crate::{interrupt, peripherals, Peripheral}; | 16 | use crate::{interrupt, peripherals, Peripheral}; |
| 18 | 17 | ||
| 18 | pub mod enums; | ||
| 19 | use enums::*; | ||
| 20 | pub mod util; | ||
| 21 | |||
| 19 | /// Contains CAN frame and additional metadata. | 22 | /// Contains CAN frame and additional metadata. |
| 20 | /// | 23 | /// |
| 21 | /// Timestamp is available if `time` feature is enabled. | 24 | /// Timestamp is available if `time` feature is enabled. |
| @@ -93,23 +96,6 @@ pub struct Can<'d, T: Instance> { | |||
| 93 | can: bxcan::Can<BxcanInstance<'d, T>>, | 96 | can: bxcan::Can<BxcanInstance<'d, T>>, |
| 94 | } | 97 | } |
| 95 | 98 | ||
| 96 | /// CAN bus error | ||
| 97 | #[allow(missing_docs)] | ||
| 98 | #[derive(Debug)] | ||
| 99 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 100 | pub enum BusError { | ||
| 101 | Stuff, | ||
| 102 | Form, | ||
| 103 | Acknowledge, | ||
| 104 | BitRecessive, | ||
| 105 | BitDominant, | ||
| 106 | Crc, | ||
| 107 | Software, | ||
| 108 | BusOff, | ||
| 109 | BusPassive, | ||
| 110 | BusWarning, | ||
| 111 | } | ||
| 112 | |||
| 113 | /// Error returned by `try_read` | 99 | /// Error returned by `try_read` |
| 114 | #[derive(Debug)] | 100 | #[derive(Debug)] |
| 115 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 101 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -186,8 +172,15 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 186 | 172 | ||
| 187 | /// Set CAN bit rate. | 173 | /// Set CAN bit rate. |
| 188 | pub fn set_bitrate(&mut self, bitrate: u32) { | 174 | pub fn set_bitrate(&mut self, bitrate: u32) { |
| 189 | let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); | 175 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); |
| 190 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); | 176 | let sjw = u8::from(bit_timing.sync_jump_width) as u32; |
| 177 | let seg1 = u8::from(bit_timing.seg1) as u32; | ||
| 178 | let seg2 = u8::from(bit_timing.seg2) as u32; | ||
| 179 | let prescaler = u16::from(bit_timing.prescaler) as u32; | ||
| 180 | self.can | ||
| 181 | .modify_config() | ||
| 182 | .set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1)) | ||
| 183 | .leave_disabled(); | ||
| 191 | } | 184 | } |
| 192 | 185 | ||
| 193 | /// Enables the peripheral and synchronizes with the bus. | 186 | /// Enables the peripheral and synchronizes with the bus. |
| @@ -302,97 +295,6 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 302 | } | 295 | } |
| 303 | } | 296 | } |
| 304 | 297 | ||
| 305 | const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { | ||
| 306 | const BS1_MAX: u8 = 16; | ||
| 307 | const BS2_MAX: u8 = 8; | ||
| 308 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; | ||
| 309 | |||
| 310 | let periph_clock = periph_clock.0; | ||
| 311 | |||
| 312 | if can_bitrate < 1000 { | ||
| 313 | return None; | ||
| 314 | } | ||
| 315 | |||
| 316 | // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG | ||
| 317 | // CAN in Automation, 2003 | ||
| 318 | // | ||
| 319 | // According to the source, optimal quanta per bit are: | ||
| 320 | // Bitrate Optimal Maximum | ||
| 321 | // 1000 kbps 8 10 | ||
| 322 | // 500 kbps 16 17 | ||
| 323 | // 250 kbps 16 17 | ||
| 324 | // 125 kbps 16 17 | ||
| 325 | let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 }; | ||
| 326 | |||
| 327 | // Computing (prescaler * BS): | ||
| 328 | // BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual | ||
| 329 | // BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified | ||
| 330 | // let: | ||
| 331 | // BS = 1 + BS1 + BS2 -- Number of time quanta per bit | ||
| 332 | // PRESCALER_BS = PRESCALER * BS | ||
| 333 | // ==> | ||
| 334 | // PRESCALER_BS = PCLK / BITRATE | ||
| 335 | let prescaler_bs = periph_clock / can_bitrate; | ||
| 336 | |||
| 337 | // Searching for such prescaler value so that the number of quanta per bit is highest. | ||
| 338 | let mut bs1_bs2_sum = max_quanta_per_bit - 1; | ||
| 339 | while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { | ||
| 340 | if bs1_bs2_sum <= 2 { | ||
| 341 | return None; // No solution | ||
| 342 | } | ||
| 343 | bs1_bs2_sum -= 1; | ||
| 344 | } | ||
| 345 | |||
| 346 | let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; | ||
| 347 | if (prescaler < 1) || (prescaler > 1024) { | ||
| 348 | return None; // No solution | ||
| 349 | } | ||
| 350 | |||
| 351 | // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. | ||
| 352 | // We need to find such values so that the sample point is as close as possible to the optimal value, | ||
| 353 | // which is 87.5%, which is 7/8. | ||
| 354 | // | ||
| 355 | // Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *) | ||
| 356 | // {{bs2 -> (1 + bs1)/7}} | ||
| 357 | // | ||
| 358 | // Hence: | ||
| 359 | // bs2 = (1 + bs1) / 7 | ||
| 360 | // bs1 = (7 * bs1_bs2_sum - 1) / 8 | ||
| 361 | // | ||
| 362 | // Sample point location can be computed as follows: | ||
| 363 | // Sample point location = (1 + bs1) / (1 + bs1 + bs2) | ||
| 364 | // | ||
| 365 | // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one: | ||
| 366 | // - With rounding to nearest | ||
| 367 | // - With rounding to zero | ||
| 368 | let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first | ||
| 369 | let mut bs2 = bs1_bs2_sum - bs1; | ||
| 370 | core::assert!(bs1_bs2_sum > bs1); | ||
| 371 | |||
| 372 | let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16; | ||
| 373 | if sample_point_permill > MAX_SAMPLE_POINT_PERMILL { | ||
| 374 | // Nope, too far; now rounding to zero | ||
| 375 | bs1 = (7 * bs1_bs2_sum - 1) / 8; | ||
| 376 | bs2 = bs1_bs2_sum - bs1; | ||
| 377 | } | ||
| 378 | |||
| 379 | // Check is BS1 and BS2 are in range | ||
| 380 | if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { | ||
| 381 | return None; | ||
| 382 | } | ||
| 383 | |||
| 384 | // Check if final bitrate matches the requested | ||
| 385 | if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { | ||
| 386 | return None; | ||
| 387 | } | ||
| 388 | |||
| 389 | // One is recommended by DS-015, CANOpen, and DeviceNet | ||
| 390 | let sjw = 1; | ||
| 391 | |||
| 392 | // Pack into BTR register values | ||
| 393 | Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) | ||
| 394 | } | ||
| 395 | |||
| 396 | /// Split the CAN driver into transmit and receive halves. | 298 | /// Split the CAN driver into transmit and receive halves. |
| 397 | /// | 299 | /// |
| 398 | /// Useful for doing separate transmit/receive tasks. | 300 | /// Useful for doing separate transmit/receive tasks. |
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs new file mode 100644 index 000000000..36139a45c --- /dev/null +++ b/embassy-stm32/src/can/enums.rs | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | //! Enums shared between CAN controller types. | ||
| 2 | |||
| 3 | /// Bus error | ||
| 4 | #[derive(Debug)] | ||
| 5 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 6 | pub enum BusError { | ||
| 7 | /// Bit stuffing error - more than 5 equal bits | ||
| 8 | Stuff, | ||
| 9 | /// Form error - A fixed format part of a received message has wrong format | ||
| 10 | Form, | ||
| 11 | /// The message transmitted by the FDCAN was not acknowledged by another node. | ||
| 12 | Acknowledge, | ||
| 13 | /// Bit0Error: During the transmission of a message the device wanted to send a dominant level | ||
| 14 | /// but the monitored bus value was recessive. | ||
| 15 | BitRecessive, | ||
| 16 | /// Bit1Error: During the transmission of a message the device wanted to send a recessive level | ||
| 17 | /// but the monitored bus value was dominant. | ||
| 18 | BitDominant, | ||
| 19 | /// The CRC check sum of a received message was incorrect. The CRC of an | ||
| 20 | /// incoming message does not match with the CRC calculated from the received data. | ||
| 21 | Crc, | ||
| 22 | /// A software error occured | ||
| 23 | Software, | ||
| 24 | /// The FDCAN is in Bus_Off state. | ||
| 25 | BusOff, | ||
| 26 | /// The FDCAN is in the Error_Passive state. | ||
| 27 | BusPassive, | ||
| 28 | /// At least one of error counter has reached the Error_Warning limit of 96. | ||
| 29 | BusWarning, | ||
| 30 | } | ||
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 0cc2559cf..faf4af73f 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -1,14 +1,577 @@ | |||
| 1 | use crate::peripherals; | 1 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::ops::{Deref, DerefMut}; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use cfg_if::cfg_if; | ||
| 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 8 | pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader}; | ||
| 9 | pub use fdcan::id::{ExtendedId, Id, StandardId}; | ||
| 10 | use fdcan::message_ram::RegisterBlock; | ||
| 11 | use fdcan::{self, LastErrorCode}; | ||
| 12 | pub use fdcan::{config, filter}; | ||
| 13 | |||
| 14 | use crate::gpio::sealed::AFType; | ||
| 15 | use crate::interrupt::typelevel::Interrupt; | ||
| 16 | use crate::rcc::RccPeripheral; | ||
| 17 | use crate::{interrupt, peripherals, Peripheral}; | ||
| 18 | |||
| 19 | pub mod enums; | ||
| 20 | use enums::*; | ||
| 21 | pub mod util; | ||
| 22 | |||
| 23 | /// CAN Frame returned by read | ||
| 24 | pub struct RxFrame { | ||
| 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 | ||
| 35 | pub 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 | |||
| 42 | impl 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 | |||
| 72 | impl 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)] | ||
| 98 | pub struct Data { | ||
| 99 | pub(crate) bytes: [u8; 64], | ||
| 100 | } | ||
| 101 | |||
| 102 | impl 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 | |||
| 123 | /// Checks if the length can be encoded in FDCAN DLC field. | ||
| 124 | pub const fn is_valid_len(len: usize) -> bool { | ||
| 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 | |||
| 138 | /// Creates an empty data payload containing 0 bytes. | ||
| 139 | #[inline] | ||
| 140 | pub const fn empty() -> Self { | ||
| 141 | Self { bytes: [0; 64] } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | /// Interrupt handler channel 0. | ||
| 146 | pub struct IT0InterruptHandler<T: Instance> { | ||
| 147 | _phantom: PhantomData<T>, | ||
| 148 | } | ||
| 149 | |||
| 150 | // We use IT0 for everything currently | ||
| 151 | impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> { | ||
| 152 | unsafe fn on_interrupt() { | ||
| 153 | let regs = T::regs(); | ||
| 154 | |||
| 155 | let ir = regs.ir().read(); | ||
| 156 | |||
| 157 | if ir.tc() { | ||
| 158 | regs.ir().write(|w| w.set_tc(true)); | ||
| 159 | T::state().tx_waker.wake(); | ||
| 160 | } | ||
| 161 | |||
| 162 | if ir.tefn() { | ||
| 163 | regs.ir().write(|w| w.set_tefn(true)); | ||
| 164 | T::state().tx_waker.wake(); | ||
| 165 | } | ||
| 166 | |||
| 167 | if ir.ped() || ir.pea() { | ||
| 168 | regs.ir().write(|w| { | ||
| 169 | w.set_ped(true); | ||
| 170 | w.set_pea(true); | ||
| 171 | }); | ||
| 172 | } | ||
| 173 | |||
| 174 | if ir.rfn(0) { | ||
| 175 | regs.ir().write(|w| w.set_rfn(0, true)); | ||
| 176 | T::state().rx_waker.wake(); | ||
| 177 | } | ||
| 178 | |||
| 179 | if ir.rfn(1) { | ||
| 180 | regs.ir().write(|w| w.set_rfn(1, true)); | ||
| 181 | T::state().rx_waker.wake(); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | /// Interrupt handler channel 1. | ||
| 187 | pub struct IT1InterruptHandler<T: Instance> { | ||
| 188 | _phantom: PhantomData<T>, | ||
| 189 | } | ||
| 190 | |||
| 191 | impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1InterruptHandler<T> { | ||
| 192 | unsafe fn on_interrupt() {} | ||
| 193 | } | ||
| 194 | |||
| 195 | impl BusError { | ||
| 196 | fn try_from(lec: LastErrorCode) -> Option<BusError> { | ||
| 197 | match lec { | ||
| 198 | LastErrorCode::AckError => Some(BusError::Acknowledge), | ||
| 199 | // `0` data bit encodes a dominant state. `1` data bit is recessive. | ||
| 200 | // Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1 | ||
| 201 | LastErrorCode::Bit0Error => Some(BusError::BitRecessive), | ||
| 202 | LastErrorCode::Bit1Error => Some(BusError::BitDominant), | ||
| 203 | LastErrorCode::CRCError => Some(BusError::Crc), | ||
| 204 | LastErrorCode::FormError => Some(BusError::Form), | ||
| 205 | LastErrorCode::StuffError => Some(BusError::Stuff), | ||
| 206 | _ => None, | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | /// Operating modes trait | ||
| 212 | pub trait FdcanOperatingMode {} | ||
| 213 | impl FdcanOperatingMode for fdcan::PoweredDownMode {} | ||
| 214 | impl FdcanOperatingMode for fdcan::ConfigMode {} | ||
| 215 | impl FdcanOperatingMode for fdcan::InternalLoopbackMode {} | ||
| 216 | impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {} | ||
| 217 | impl FdcanOperatingMode for fdcan::NormalOperationMode {} | ||
| 218 | impl FdcanOperatingMode for fdcan::RestrictedOperationMode {} | ||
| 219 | impl FdcanOperatingMode for fdcan::BusMonitoringMode {} | ||
| 220 | impl FdcanOperatingMode for fdcan::TestMode {} | ||
| 221 | |||
| 222 | /// FDCAN Instance | ||
| 223 | pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { | ||
| 224 | /// Reference to internals. | ||
| 225 | pub can: fdcan::FdCan<FdcanInstance<'d, T>, M>, | ||
| 226 | ns_per_timer_tick: u64, // For FDCAN internal timer | ||
| 227 | } | ||
| 228 | |||
| 229 | fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> u64 { | ||
| 230 | match mode { | ||
| 231 | // Use timestamp from Rx FIFO to adjust timestamp reported to user | ||
| 232 | config::FrameTransmissionConfig::ClassicCanOnly => { | ||
| 233 | let freq = T::frequency(); | ||
| 234 | let prescale: u64 = | ||
| 235 | ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; | ||
| 236 | 1_000_000_000 as u64 / (freq.0 as u64 * prescale) | ||
| 237 | } | ||
| 238 | // For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use | ||
| 239 | // timer3 instead which is too hard to do from this module. | ||
| 240 | _ => 0, | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | #[cfg(feature = "time")] | ||
| 245 | fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant { | ||
| 246 | let now_embassy = embassy_time::Instant::now(); | ||
| 247 | if ns_per_timer_tick == 0 { | ||
| 248 | return now_embassy; | ||
| 249 | } | ||
| 250 | let now_can = { T::regs().tscv().read().tsc() }; | ||
| 251 | let delta = now_can.overflowing_sub(ts_val).0 as u64; | ||
| 252 | let ns = ns_per_timer_tick * delta as u64; | ||
| 253 | now_embassy - embassy_time::Duration::from_nanos(ns) | ||
| 254 | } | ||
| 255 | |||
| 256 | fn curr_error<T: Instance>() -> Option<BusError> { | ||
| 257 | let err = { T::regs().psr().read() }; | ||
| 258 | if err.bo() { | ||
| 259 | return Some(BusError::BusOff); | ||
| 260 | } else if err.ep() { | ||
| 261 | return Some(BusError::BusPassive); | ||
| 262 | } else if err.ew() { | ||
| 263 | return Some(BusError::BusWarning); | ||
| 264 | } else { | ||
| 265 | cfg_if! { | ||
| 266 | if #[cfg(stm32h7)] { | ||
| 267 | let lec = err.lec(); | ||
| 268 | } else { | ||
| 269 | let lec = err.lec().to_bits(); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | if let Ok(err) = LastErrorCode::try_from(lec) { | ||
| 273 | return BusError::try_from(err); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | None | ||
| 277 | } | ||
| 278 | |||
| 279 | impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | ||
| 280 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. | ||
| 281 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. | ||
| 282 | pub fn new( | ||
| 283 | peri: impl Peripheral<P = T> + 'd, | ||
| 284 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 285 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 286 | _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> | ||
| 287 | + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> | ||
| 288 | + 'd, | ||
| 289 | ) -> Fdcan<'d, T, fdcan::ConfigMode> { | ||
| 290 | into_ref!(peri, rx, tx); | ||
| 291 | |||
| 292 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 293 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 294 | |||
| 295 | T::enable_and_reset(); | ||
| 296 | |||
| 297 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 298 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 299 | |||
| 300 | let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode(); | ||
| 301 | |||
| 302 | T::configure_msg_ram(); | ||
| 303 | unsafe { | ||
| 304 | // Enable timestamping | ||
| 305 | #[cfg(not(stm32h7))] | ||
| 306 | T::regs() | ||
| 307 | .tscc() | ||
| 308 | .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); | ||
| 309 | #[cfg(stm32h7)] | ||
| 310 | T::regs().tscc().write(|w| w.set_tss(0x01)); | ||
| 311 | |||
| 312 | T::IT0Interrupt::unpend(); // Not unsafe | ||
| 313 | T::IT0Interrupt::enable(); | ||
| 314 | |||
| 315 | T::IT1Interrupt::unpend(); // Not unsafe | ||
| 316 | T::IT1Interrupt::enable(); | ||
| 317 | |||
| 318 | // this isn't really documented in the reference manual | ||
| 319 | // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire | ||
| 320 | T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); | ||
| 321 | } | ||
| 322 | |||
| 323 | can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); | ||
| 324 | can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg); | ||
| 325 | can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete); | ||
| 326 | can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); | ||
| 327 | can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true); | ||
| 328 | |||
| 329 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(can.get_config().frame_transmit); | ||
| 330 | Self { can, ns_per_timer_tick } | ||
| 331 | } | ||
| 332 | |||
| 333 | /// Configures the bit timings calculated from supplied bitrate. | ||
| 334 | pub fn set_bitrate(&mut self, bitrate: u32) { | ||
| 335 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | ||
| 336 | self.can.set_nominal_bit_timing(config::NominalBitTiming { | ||
| 337 | sync_jump_width: bit_timing.sync_jump_width, | ||
| 338 | prescaler: bit_timing.prescaler, | ||
| 339 | seg1: bit_timing.seg1, | ||
| 340 | seg2: bit_timing.seg2, | ||
| 341 | }); | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | macro_rules! impl_transition { | ||
| 346 | ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => { | ||
| 347 | impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> { | ||
| 348 | /// Transition from $from_mode:ident mode to $to_mode:ident mode | ||
| 349 | pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> { | ||
| 350 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.can.get_config().frame_transmit); | ||
| 351 | Fdcan { | ||
| 352 | can: self.can.$func(), | ||
| 353 | ns_per_timer_tick, | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | }; | ||
| 358 | } | ||
| 359 | |||
| 360 | impl_transition!(PoweredDownMode, ConfigMode, into_config_mode, into_config_mode); | ||
| 361 | impl_transition!(InternalLoopbackMode, ConfigMode, into_config_mode, into_config_mode); | ||
| 362 | |||
| 363 | impl_transition!(ConfigMode, NormalOperationMode, into_normal_mode, into_normal); | ||
| 364 | impl_transition!( | ||
| 365 | ConfigMode, | ||
| 366 | ExternalLoopbackMode, | ||
| 367 | into_external_loopback_mode, | ||
| 368 | into_external_loopback | ||
| 369 | ); | ||
| 370 | impl_transition!( | ||
| 371 | ConfigMode, | ||
| 372 | InternalLoopbackMode, | ||
| 373 | into_internal_loopback_mode, | ||
| 374 | into_internal_loopback | ||
| 375 | ); | ||
| 376 | |||
| 377 | impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M> | ||
| 378 | where | ||
| 379 | M: fdcan::Transmit, | ||
| 380 | M: fdcan::Receive, | ||
| 381 | { | ||
| 382 | /// 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 | ||
| 384 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 385 | /// transmitted, then tries again. | ||
| 386 | pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> { | ||
| 387 | poll_fn(|cx| { | ||
| 388 | T::state().tx_waker.register(cx.waker()); | ||
| 389 | if let Ok(dropped) = self | ||
| 390 | .can | ||
| 391 | .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { | ||
| 392 | TxFrame::from_preserved(hdr, data32) | ||
| 393 | }) | ||
| 394 | { | ||
| 395 | return Poll::Ready(dropped.flatten()); | ||
| 396 | } | ||
| 397 | |||
| 398 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 399 | // to clear. | ||
| 400 | Poll::Pending | ||
| 401 | }) | ||
| 402 | .await | ||
| 403 | } | ||
| 404 | |||
| 405 | /// Flush one of the TX mailboxes. | ||
| 406 | pub async fn flush(&self, mb: fdcan::Mailbox) { | ||
| 407 | poll_fn(|cx| { | ||
| 408 | T::state().tx_waker.register(cx.waker()); | ||
| 409 | |||
| 410 | let idx: u8 = mb.into(); | ||
| 411 | let idx = 1 << idx; | ||
| 412 | if !T::regs().txbrp().read().trp(idx) { | ||
| 413 | return Poll::Ready(()); | ||
| 414 | } | ||
| 415 | |||
| 416 | Poll::Pending | ||
| 417 | }) | ||
| 418 | .await; | ||
| 419 | } | ||
| 420 | |||
| 421 | /// Returns the next received message frame | ||
| 422 | pub async fn read(&mut self) -> Result<RxFrame, BusError> { | ||
| 423 | poll_fn(|cx| { | ||
| 424 | T::state().err_waker.register(cx.waker()); | ||
| 425 | T::state().rx_waker.register(cx.waker()); | ||
| 426 | |||
| 427 | let mut buffer: [u8; 64] = [0; 64]; | ||
| 428 | if let Ok(rx) = self.can.receive0(&mut buffer) { | ||
| 429 | // rx: fdcan::ReceiveOverrun<RxFrameInfo> | ||
| 430 | // TODO: report overrun? | ||
| 431 | // for now we just drop it | ||
| 432 | |||
| 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>() { | ||
| 453 | // TODO: this is probably wrong | ||
| 454 | return Poll::Ready(Err(err)); | ||
| 455 | } | ||
| 456 | Poll::Pending | ||
| 457 | }) | ||
| 458 | .await | ||
| 459 | } | ||
| 460 | |||
| 461 | /// 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>) { | ||
| 463 | let (mut _control, tx, rx0, rx1) = self.can.split_by_ref(); | ||
| 464 | ( | ||
| 465 | FdcanTx { _control, tx }, | ||
| 466 | FdcanRx { | ||
| 467 | rx0, | ||
| 468 | rx1, | ||
| 469 | ns_per_timer_tick: self.ns_per_timer_tick, | ||
| 470 | }, | ||
| 471 | ) | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | /// FDCAN Tx only Instance | ||
| 476 | pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> { | ||
| 477 | _control: &'c mut fdcan::FdCanControl<FdcanInstance<'d, T>, M>, | ||
| 478 | tx: &'c mut fdcan::Tx<FdcanInstance<'d, T>, M>, | ||
| 479 | } | ||
| 480 | |||
| 481 | impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> { | ||
| 482 | /// 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 | ||
| 484 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 485 | /// transmitted, then tries again. | ||
| 486 | pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> { | ||
| 487 | poll_fn(|cx| { | ||
| 488 | T::state().tx_waker.register(cx.waker()); | ||
| 489 | if let Ok(dropped) = self | ||
| 490 | .tx | ||
| 491 | .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { | ||
| 492 | TxFrame::from_preserved(hdr, data32) | ||
| 493 | }) | ||
| 494 | { | ||
| 495 | return Poll::Ready(dropped.flatten()); | ||
| 496 | } | ||
| 497 | |||
| 498 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 499 | // to clear. | ||
| 500 | Poll::Pending | ||
| 501 | }) | ||
| 502 | .await | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | /// FDCAN Rx only Instance | ||
| 507 | #[allow(dead_code)] | ||
| 508 | pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> { | ||
| 509 | rx0: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo0>, | ||
| 510 | rx1: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo1>, | ||
| 511 | ns_per_timer_tick: u64, // For FDCAN internal timer | ||
| 512 | } | ||
| 513 | |||
| 514 | impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> { | ||
| 515 | /// Returns the next received message frame | ||
| 516 | pub async fn read(&mut self) -> Result<RxFrame, BusError> { | ||
| 517 | poll_fn(|cx| { | ||
| 518 | T::state().err_waker.register(cx.waker()); | ||
| 519 | T::state().rx_waker.register(cx.waker()); | ||
| 520 | |||
| 521 | let mut buffer: [u8; 64] = [0; 64]; | ||
| 522 | if let Ok(rx) = self.rx0.receive(&mut buffer) { | ||
| 523 | // rx: fdcan::ReceiveOverrun<RxFrameInfo> | ||
| 524 | // TODO: report overrun? | ||
| 525 | // for now we just drop it | ||
| 526 | let frame: RxFrame = RxFrame::new( | ||
| 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>() { | ||
| 545 | // TODO: this is probably wrong | ||
| 546 | return Poll::Ready(Err(err)); | ||
| 547 | } | ||
| 548 | |||
| 549 | Poll::Pending | ||
| 550 | }) | ||
| 551 | .await | ||
| 552 | } | ||
| 553 | } | ||
| 554 | impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> { | ||
| 555 | type Target = fdcan::FdCan<FdcanInstance<'d, T>, M>; | ||
| 556 | |||
| 557 | fn deref(&self) -> &Self::Target { | ||
| 558 | &self.can | ||
| 559 | } | ||
| 560 | } | ||
| 561 | |||
| 562 | impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> { | ||
| 563 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 564 | &mut self.can | ||
| 565 | } | ||
| 566 | } | ||
| 2 | 567 | ||
| 3 | pub(crate) mod sealed { | 568 | pub(crate) mod sealed { |
| 4 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 5 | use embassy_sync::channel::Channel; | ||
| 6 | use embassy_sync::waitqueue::AtomicWaker; | 569 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | 570 | ||
| 8 | pub struct State { | 571 | pub struct State { |
| 9 | pub tx_waker: AtomicWaker, | 572 | pub tx_waker: AtomicWaker, |
| 10 | pub err_waker: AtomicWaker, | 573 | pub err_waker: AtomicWaker, |
| 11 | pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>, | 574 | pub rx_waker: AtomicWaker, |
| 12 | } | 575 | } |
| 13 | 576 | ||
| 14 | impl State { | 577 | impl State { |
| @@ -16,25 +579,122 @@ pub(crate) mod sealed { | |||
| 16 | Self { | 579 | Self { |
| 17 | tx_waker: AtomicWaker::new(), | 580 | tx_waker: AtomicWaker::new(), |
| 18 | err_waker: AtomicWaker::new(), | 581 | err_waker: AtomicWaker::new(), |
| 19 | rx_queue: Channel::new(), | 582 | rx_waker: AtomicWaker::new(), |
| 20 | } | 583 | } |
| 21 | } | 584 | } |
| 22 | } | 585 | } |
| 23 | 586 | ||
| 24 | pub trait Instance { | 587 | pub trait Instance { |
| 588 | const REGISTERS: *mut fdcan::RegisterBlock; | ||
| 589 | const MSG_RAM: *mut fdcan::message_ram::RegisterBlock; | ||
| 590 | const MSG_RAM_OFFSET: usize; | ||
| 591 | |||
| 25 | fn regs() -> &'static crate::pac::can::Fdcan; | 592 | fn regs() -> &'static crate::pac::can::Fdcan; |
| 26 | fn state() -> &'static State; | 593 | fn state() -> &'static State; |
| 594 | |||
| 595 | #[cfg(not(stm32h7))] | ||
| 596 | fn configure_msg_ram() {} | ||
| 597 | |||
| 598 | #[cfg(stm32h7)] | ||
| 599 | fn configure_msg_ram() { | ||
| 600 | let r = Self::regs(); | ||
| 601 | |||
| 602 | use fdcan::message_ram::*; | ||
| 603 | let mut offset_words = Self::MSG_RAM_OFFSET as u16; | ||
| 604 | |||
| 605 | // 11-bit filter | ||
| 606 | r.sidfc().modify(|w| w.set_flssa(offset_words)); | ||
| 607 | offset_words += STANDARD_FILTER_MAX as u16; | ||
| 608 | |||
| 609 | // 29-bit filter | ||
| 610 | r.xidfc().modify(|w| w.set_flesa(offset_words)); | ||
| 611 | offset_words += 2 * EXTENDED_FILTER_MAX as u16; | ||
| 612 | |||
| 613 | // Rx FIFO 0 and 1 | ||
| 614 | for i in 0..=1 { | ||
| 615 | r.rxfc(i).modify(|w| { | ||
| 616 | w.set_fsa(offset_words); | ||
| 617 | w.set_fs(RX_FIFO_MAX); | ||
| 618 | w.set_fwm(RX_FIFO_MAX); | ||
| 619 | }); | ||
| 620 | offset_words += 18 * RX_FIFO_MAX as u16; | ||
| 621 | } | ||
| 622 | |||
| 623 | // Rx buffer - see below | ||
| 624 | // Tx event FIFO | ||
| 625 | r.txefc().modify(|w| { | ||
| 626 | w.set_efsa(offset_words); | ||
| 627 | w.set_efs(TX_EVENT_MAX); | ||
| 628 | w.set_efwm(TX_EVENT_MAX); | ||
| 629 | }); | ||
| 630 | offset_words += 2 * TX_EVENT_MAX as u16; | ||
| 631 | |||
| 632 | // Tx buffers | ||
| 633 | r.txbc().modify(|w| { | ||
| 634 | w.set_tbsa(offset_words); | ||
| 635 | w.set_tfqs(TX_FIFO_MAX); | ||
| 636 | }); | ||
| 637 | offset_words += 18 * TX_FIFO_MAX as u16; | ||
| 638 | |||
| 639 | // Rx Buffer - not used | ||
| 640 | r.rxbc().modify(|w| { | ||
| 641 | w.set_rbsa(offset_words); | ||
| 642 | }); | ||
| 643 | |||
| 644 | // TX event FIFO? | ||
| 645 | // Trigger memory? | ||
| 646 | |||
| 647 | // Set the element sizes to 16 bytes | ||
| 648 | r.rxesc().modify(|w| { | ||
| 649 | w.set_rbds(0b111); | ||
| 650 | for i in 0..=1 { | ||
| 651 | w.set_fds(i, 0b111); | ||
| 652 | } | ||
| 653 | }); | ||
| 654 | r.txesc().modify(|w| { | ||
| 655 | w.set_tbds(0b111); | ||
| 656 | }) | ||
| 657 | } | ||
| 27 | } | 658 | } |
| 28 | } | 659 | } |
| 29 | 660 | ||
| 30 | /// Interruptable FDCAN instance. | 661 | /// Trait for FDCAN interrupt channel 0 |
| 31 | pub trait InterruptableInstance {} | 662 | pub trait IT0Instance { |
| 32 | /// FDCAN instance. | 663 | /// Type for FDCAN interrupt channel 0 |
| 33 | pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} | 664 | type IT0Interrupt: crate::interrupt::typelevel::Interrupt; |
| 665 | } | ||
| 34 | 666 | ||
| 35 | foreach_peripheral!( | 667 | /// Trait for FDCAN interrupt channel 1 |
| 36 | (can, $inst:ident) => { | 668 | pub trait IT1Instance { |
| 669 | /// Type for FDCAN interrupt channel 1 | ||
| 670 | type IT1Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 671 | } | ||
| 672 | |||
| 673 | /// InterruptableInstance trait | ||
| 674 | pub trait InterruptableInstance: IT0Instance + IT1Instance {} | ||
| 675 | /// Instance trait | ||
| 676 | pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {} | ||
| 677 | /// Fdcan Instance struct | ||
| 678 | pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); | ||
| 679 | |||
| 680 | unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> { | ||
| 681 | const MSG_RAM: *mut RegisterBlock = T::MSG_RAM; | ||
| 682 | } | ||
| 683 | |||
| 684 | unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T> | ||
| 685 | where | ||
| 686 | FdcanInstance<'d, T>: fdcan::message_ram::Instance, | ||
| 687 | { | ||
| 688 | const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS; | ||
| 689 | } | ||
| 690 | |||
| 691 | macro_rules! impl_fdcan { | ||
| 692 | ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { | ||
| 37 | impl sealed::Instance for peripherals::$inst { | 693 | 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; | ||
| 697 | |||
| 38 | fn regs() -> &'static crate::pac::can::Fdcan { | 698 | fn regs() -> &'static crate::pac::can::Fdcan { |
| 39 | &crate::pac::$inst | 699 | &crate::pac::$inst |
| 40 | } | 700 | } |
| @@ -47,8 +707,40 @@ foreach_peripheral!( | |||
| 47 | 707 | ||
| 48 | impl Instance for peripherals::$inst {} | 708 | impl Instance for peripherals::$inst {} |
| 49 | 709 | ||
| 710 | foreach_interrupt!( | ||
| 711 | ($inst,can,FDCAN,IT0,$irq:ident) => { | ||
| 712 | impl IT0Instance for peripherals::$inst { | ||
| 713 | type IT0Interrupt = crate::interrupt::typelevel::$irq; | ||
| 714 | } | ||
| 715 | }; | ||
| 716 | ($inst,can,FDCAN,IT1,$irq:ident) => { | ||
| 717 | impl IT1Instance for peripherals::$inst { | ||
| 718 | type IT1Interrupt = crate::interrupt::typelevel::$irq; | ||
| 719 | } | ||
| 720 | }; | ||
| 721 | ); | ||
| 722 | |||
| 50 | impl InterruptableInstance for peripherals::$inst {} | 723 | impl InterruptableInstance for peripherals::$inst {} |
| 51 | }; | 724 | }; |
| 725 | |||
| 726 | ($inst:ident, $msg_ram_inst:ident) => { | ||
| 727 | impl_fdcan!($inst, $msg_ram_inst, 0); | ||
| 728 | }; | ||
| 729 | } | ||
| 730 | |||
| 731 | #[cfg(not(stm32h7))] | ||
| 732 | foreach_peripheral!( | ||
| 733 | (can, FDCAN) => { impl_fdcan!(FDCAN, FDCANRAM); }; | ||
| 734 | (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM1); }; | ||
| 735 | (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM2); }; | ||
| 736 | (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM3); }; | ||
| 737 | ); | ||
| 738 | |||
| 739 | #[cfg(stm32h7)] | ||
| 740 | foreach_peripheral!( | ||
| 741 | (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM, 0x0000); }; | ||
| 742 | (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM, 0x0C00); }; | ||
| 743 | (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM, 0x1800); }; | ||
| 52 | ); | 744 | ); |
| 53 | 745 | ||
| 54 | pin_trait!(RxPin, Instance); | 746 | pin_trait!(RxPin, Instance); |
diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs new file mode 100644 index 000000000..fcdbbad62 --- /dev/null +++ b/embassy-stm32/src/can/util.rs | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | //! Utility functions shared between CAN controller types. | ||
| 2 | |||
| 3 | use core::num::{NonZeroU16, NonZeroU8}; | ||
| 4 | |||
| 5 | /// Shared struct to represent bit timings used by calc_can_timings. | ||
| 6 | #[derive(Clone, Copy, Debug)] | ||
| 7 | pub struct NominalBitTiming { | ||
| 8 | /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit | ||
| 9 | /// time is built up from a multiple of this quanta. Valid values are 1 to 512. | ||
| 10 | pub prescaler: NonZeroU16, | ||
| 11 | /// Valid values are 1 to 128. | ||
| 12 | pub seg1: NonZeroU8, | ||
| 13 | /// Valid values are 1 to 255. | ||
| 14 | pub seg2: NonZeroU8, | ||
| 15 | /// Valid values are 1 to 128. | ||
| 16 | pub sync_jump_width: NonZeroU8, | ||
| 17 | } | ||
| 18 | |||
| 19 | /// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency | ||
| 20 | pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> { | ||
| 21 | const BS1_MAX: u8 = 16; | ||
| 22 | const BS2_MAX: u8 = 8; | ||
| 23 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; | ||
| 24 | |||
| 25 | let periph_clock = periph_clock.0; | ||
| 26 | |||
| 27 | if can_bitrate < 1000 { | ||
| 28 | return None; | ||
| 29 | } | ||
| 30 | |||
| 31 | // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG | ||
| 32 | // CAN in Automation, 2003 | ||
| 33 | // | ||
| 34 | // According to the source, optimal quanta per bit are: | ||
| 35 | // Bitrate Optimal Maximum | ||
| 36 | // 1000 kbps 8 10 | ||
| 37 | // 500 kbps 16 17 | ||
| 38 | // 250 kbps 16 17 | ||
| 39 | // 125 kbps 16 17 | ||
| 40 | let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 }; | ||
| 41 | |||
| 42 | // Computing (prescaler * BS): | ||
| 43 | // BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual | ||
| 44 | // BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified | ||
| 45 | // let: | ||
| 46 | // BS = 1 + BS1 + BS2 -- Number of time quanta per bit | ||
| 47 | // PRESCALER_BS = PRESCALER * BS | ||
| 48 | // ==> | ||
| 49 | // PRESCALER_BS = PCLK / BITRATE | ||
| 50 | let prescaler_bs = periph_clock / can_bitrate; | ||
| 51 | |||
| 52 | // Searching for such prescaler value so that the number of quanta per bit is highest. | ||
| 53 | let mut bs1_bs2_sum = max_quanta_per_bit - 1; | ||
| 54 | while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { | ||
| 55 | if bs1_bs2_sum <= 2 { | ||
| 56 | return None; // No solution | ||
| 57 | } | ||
| 58 | bs1_bs2_sum -= 1; | ||
| 59 | } | ||
| 60 | |||
| 61 | let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; | ||
| 62 | if (prescaler < 1) || (prescaler > 1024) { | ||
| 63 | return None; // No solution | ||
| 64 | } | ||
| 65 | |||
| 66 | // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. | ||
| 67 | // We need to find such values so that the sample point is as close as possible to the optimal value, | ||
| 68 | // which is 87.5%, which is 7/8. | ||
| 69 | // | ||
| 70 | // Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *) | ||
| 71 | // {{bs2 -> (1 + bs1)/7}} | ||
| 72 | // | ||
| 73 | // Hence: | ||
| 74 | // bs2 = (1 + bs1) / 7 | ||
| 75 | // bs1 = (7 * bs1_bs2_sum - 1) / 8 | ||
| 76 | // | ||
| 77 | // Sample point location can be computed as follows: | ||
| 78 | // Sample point location = (1 + bs1) / (1 + bs1 + bs2) | ||
| 79 | // | ||
| 80 | // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one: | ||
| 81 | // - With rounding to nearest | ||
| 82 | // - With rounding to zero | ||
| 83 | let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first | ||
| 84 | let mut bs2 = bs1_bs2_sum - bs1; | ||
| 85 | core::assert!(bs1_bs2_sum > bs1); | ||
| 86 | |||
| 87 | let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16; | ||
| 88 | if sample_point_permill > MAX_SAMPLE_POINT_PERMILL { | ||
| 89 | // Nope, too far; now rounding to zero | ||
| 90 | bs1 = (7 * bs1_bs2_sum - 1) / 8; | ||
| 91 | bs2 = bs1_bs2_sum - bs1; | ||
| 92 | } | ||
| 93 | |||
| 94 | // Check is BS1 and BS2 are in range | ||
| 95 | if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { | ||
| 96 | return None; | ||
| 97 | } | ||
| 98 | |||
| 99 | // Check if final bitrate matches the requested | ||
| 100 | if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { | ||
| 101 | return None; | ||
| 102 | } | ||
| 103 | |||
| 104 | // One is recommended by DS-015, CANOpen, and DeviceNet | ||
| 105 | let sync_jump_width = core::num::NonZeroU8::new(1)?; | ||
| 106 | |||
| 107 | let seg1 = core::num::NonZeroU8::new(bs1)?; | ||
| 108 | let seg2 = core::num::NonZeroU8::new(bs2)?; | ||
| 109 | let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?; | ||
| 110 | |||
| 111 | Some(NominalBitTiming { | ||
| 112 | sync_jump_width, | ||
| 113 | prescaler: nz_prescaler, | ||
| 114 | seg1, | ||
| 115 | seg2, | ||
| 116 | }) | ||
| 117 | } | ||
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index fca364c21..891f0490b 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs | |||
| @@ -3,8 +3,8 @@ use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw}; | |||
| 3 | use stm32_metapac::FLASH; | 3 | use stm32_metapac::FLASH; |
| 4 | 4 | ||
| 5 | pub use crate::pac::rcc::vals::{ | 5 | pub use crate::pac::rcc::vals::{ |
| 6 | Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ, | 6 | Adcsel as AdcClockSource, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, |
| 7 | Pllr as PllR, Ppre as APBPrescaler, | 7 | Pllp as PllP, Pllq as PllQ, Pllr as PllR, Ppre as APBPrescaler, |
| 8 | }; | 8 | }; |
| 9 | use crate::pac::{PWR, RCC}; | 9 | use crate::pac::{PWR, RCC}; |
| 10 | use crate::rcc::{set_freqs, Clocks}; | 10 | use crate::rcc::{set_freqs, Clocks}; |
| @@ -87,6 +87,7 @@ pub struct Config { | |||
| 87 | pub clock_48mhz_src: Option<Clock48MhzSrc>, | 87 | pub clock_48mhz_src: Option<Clock48MhzSrc>, |
| 88 | pub adc12_clock_source: AdcClockSource, | 88 | pub adc12_clock_source: AdcClockSource, |
| 89 | pub adc345_clock_source: AdcClockSource, | 89 | pub adc345_clock_source: AdcClockSource, |
| 90 | pub fdcan_clock_source: FdCanClockSource, | ||
| 90 | 91 | ||
| 91 | pub ls: super::LsConfig, | 92 | pub ls: super::LsConfig, |
| 92 | } | 93 | } |
| @@ -104,6 +105,7 @@ impl Default for Config { | |||
| 104 | clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())), | 105 | clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())), |
| 105 | adc12_clock_source: Adcsel::DISABLE, | 106 | adc12_clock_source: Adcsel::DISABLE, |
| 106 | adc345_clock_source: Adcsel::DISABLE, | 107 | adc345_clock_source: Adcsel::DISABLE, |
| 108 | fdcan_clock_source: FdCanClockSource::PCLK1, | ||
| 107 | ls: Default::default(), | 109 | ls: Default::default(), |
| 108 | } | 110 | } |
| 109 | } | 111 | } |
| @@ -282,6 +284,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 282 | 284 | ||
| 283 | RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); | 285 | RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); |
| 284 | RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); | 286 | RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); |
| 287 | RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source)); | ||
| 285 | 288 | ||
| 286 | let adc12_ck = match config.adc12_clock_source { | 289 | let adc12_ck = match config.adc12_clock_source { |
| 287 | AdcClockSource::DISABLE => None, | 290 | AdcClockSource::DISABLE => None, |
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 15b51a398..dcaf2dced 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs | |||
| @@ -7,8 +7,8 @@ pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; | |||
| 7 | #[cfg(stm32h7)] | 7 | #[cfg(stm32h7)] |
| 8 | pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; | 8 | pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; |
| 9 | pub use crate::pac::rcc::vals::{ | 9 | pub use crate::pac::rcc::vals::{ |
| 10 | Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, | 10 | Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, |
| 11 | Pllsrc as PllSource, Sw as Sysclk, | 11 | Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, |
| 12 | }; | 12 | }; |
| 13 | use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; | 13 | use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; |
| 14 | use crate::pac::{FLASH, PWR, RCC}; | 14 | use crate::pac::{FLASH, PWR, RCC}; |
| @@ -212,6 +212,8 @@ pub struct Config { | |||
| 212 | 212 | ||
| 213 | pub per_clock_source: PerClockSource, | 213 | pub per_clock_source: PerClockSource, |
| 214 | pub adc_clock_source: AdcClockSource, | 214 | pub adc_clock_source: AdcClockSource, |
| 215 | pub fdcan_clock_source: FdCanClockSource, | ||
| 216 | |||
| 215 | pub timer_prescaler: TimerPrescaler, | 217 | pub timer_prescaler: TimerPrescaler, |
| 216 | pub voltage_scale: VoltageScale, | 218 | pub voltage_scale: VoltageScale, |
| 217 | pub ls: super::LsConfig, | 219 | pub ls: super::LsConfig, |
| @@ -248,6 +250,8 @@ impl Default for Config { | |||
| 248 | #[cfg(stm32h7)] | 250 | #[cfg(stm32h7)] |
| 249 | adc_clock_source: AdcClockSource::PER, | 251 | adc_clock_source: AdcClockSource::PER, |
| 250 | 252 | ||
| 253 | fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE | ||
| 254 | |||
| 251 | timer_prescaler: TimerPrescaler::DefaultX2, | 255 | timer_prescaler: TimerPrescaler::DefaultX2, |
| 252 | voltage_scale: VoltageScale::Scale0, | 256 | voltage_scale: VoltageScale::Scale0, |
| 253 | ls: Default::default(), | 257 | ls: Default::default(), |
| @@ -585,7 +589,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 585 | 589 | ||
| 586 | RCC.ccipr5().modify(|w| { | 590 | RCC.ccipr5().modify(|w| { |
| 587 | w.set_ckpersel(config.per_clock_source); | 591 | w.set_ckpersel(config.per_clock_source); |
| 588 | w.set_adcdacsel(config.adc_clock_source) | 592 | w.set_adcdacsel(config.adc_clock_source); |
| 593 | w.set_fdcan12sel(config.fdcan_clock_source) | ||
| 589 | }); | 594 | }); |
| 590 | } | 595 | } |
| 591 | 596 | ||
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs new file mode 100644 index 000000000..727921fba --- /dev/null +++ b/examples/stm32g4/src/bin/can.rs | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | use defmt::*; | ||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_stm32::peripherals::*; | ||
| 6 | use embassy_stm32::{bind_interrupts, can, Config}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | bind_interrupts!(struct Irqs { | ||
| 11 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; | ||
| 12 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | ||
| 13 | }); | ||
| 14 | |||
| 15 | #[embassy_executor::main] | ||
| 16 | async fn main(_spawner: Spawner) { | ||
| 17 | let config = Config::default(); | ||
| 18 | |||
| 19 | let peripherals = embassy_stm32::init(config); | ||
| 20 | |||
| 21 | let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | ||
| 22 | |||
| 23 | // 250k bps | ||
| 24 | can.set_bitrate(250_000); | ||
| 25 | |||
| 26 | info!("Configured"); | ||
| 27 | |||
| 28 | //let mut can = can.into_external_loopback_mode(); | ||
| 29 | let mut can = can.into_normal_mode(); | ||
| 30 | |||
| 31 | let mut i = 0; | ||
| 32 | loop { | ||
| 33 | let frame = can::TxFrame::new( | ||
| 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"); | ||
| 45 | _ = can.write(&frame).await; | ||
| 46 | |||
| 47 | match can.read().await { | ||
| 48 | Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), | ||
| 49 | Err(_err) => error!("Error in frame"), | ||
| 50 | } | ||
| 51 | |||
| 52 | Timer::after_millis(250).await; | ||
| 53 | |||
| 54 | i += 1; | ||
| 55 | } | ||
| 56 | } | ||
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs new file mode 100644 index 000000000..2906d1576 --- /dev/null +++ b/examples/stm32h5/src/bin/can.rs | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::peripherals::*; | ||
| 7 | use embassy_stm32::{bind_interrupts, can, rcc, Config}; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; | ||
| 13 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut config = Config::default(); | ||
| 19 | |||
| 20 | // configure FDCAN to use PLL1_Q at 64 MHz | ||
| 21 | config.rcc.pll1 = Some(rcc::Pll { | ||
| 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 | }); | ||
| 29 | config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; | ||
| 30 | |||
| 31 | let peripherals = embassy_stm32::init(config); | ||
| 32 | |||
| 33 | let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | ||
| 34 | |||
| 35 | can.can.apply_config( | ||
| 36 | can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { | ||
| 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 | |||
| 44 | info!("Configured"); | ||
| 45 | |||
| 46 | let mut can = can.into_external_loopback_mode(); | ||
| 47 | //let mut can = can.into_normal_mode(); | ||
| 48 | |||
| 49 | let mut i = 0; | ||
| 50 | loop { | ||
| 51 | let frame = can::TxFrame::new( | ||
| 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"); | ||
| 63 | _ = can.write(&frame).await; | ||
| 64 | |||
| 65 | match can.read().await { | ||
| 66 | Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), | ||
| 67 | Err(_err) => error!("Error in frame"), | ||
| 68 | } | ||
| 69 | |||
| 70 | Timer::after_millis(250).await; | ||
| 71 | |||
| 72 | i += 1; | ||
| 73 | } | ||
| 74 | } | ||
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs new file mode 100644 index 000000000..2906d1576 --- /dev/null +++ b/examples/stm32h7/src/bin/can.rs | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::peripherals::*; | ||
| 7 | use embassy_stm32::{bind_interrupts, can, rcc, Config}; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; | ||
| 13 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut config = Config::default(); | ||
| 19 | |||
| 20 | // configure FDCAN to use PLL1_Q at 64 MHz | ||
| 21 | config.rcc.pll1 = Some(rcc::Pll { | ||
| 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 | }); | ||
| 29 | config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; | ||
| 30 | |||
| 31 | let peripherals = embassy_stm32::init(config); | ||
| 32 | |||
| 33 | let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | ||
| 34 | |||
| 35 | can.can.apply_config( | ||
| 36 | can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { | ||
| 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 | |||
| 44 | info!("Configured"); | ||
| 45 | |||
| 46 | let mut can = can.into_external_loopback_mode(); | ||
| 47 | //let mut can = can.into_normal_mode(); | ||
| 48 | |||
| 49 | let mut i = 0; | ||
| 50 | loop { | ||
| 51 | let frame = can::TxFrame::new( | ||
| 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"); | ||
| 63 | _ = can.write(&frame).await; | ||
| 64 | |||
| 65 | match can.read().await { | ||
| 66 | Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), | ||
| 67 | Err(_err) => error!("Error in frame"), | ||
| 68 | } | ||
| 69 | |||
| 70 | Timer::after_millis(250).await; | ||
| 71 | |||
| 72 | i += 1; | ||
| 73 | } | ||
| 74 | } | ||
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bf85f05d2..cb1bd9a50 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -14,11 +14,11 @@ stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not | |||
| 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] | 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] |
| 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] | 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] |
| 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] | 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] |
| 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"] | 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] |
| 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] | 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] |
| 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"] | 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"] |
| 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"] | 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"] |
| 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"] | 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] |
| 22 | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] | 22 | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] |
| 23 | stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] | 23 | stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] |
| 24 | stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] | 24 | stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] |
| @@ -37,6 +37,7 @@ sdmmc = [] | |||
| 37 | stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] | 37 | stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] |
| 38 | chrono = ["embassy-stm32/chrono", "dep:chrono"] | 38 | chrono = ["embassy-stm32/chrono", "dep:chrono"] |
| 39 | can = [] | 39 | can = [] |
| 40 | fdcan = [] | ||
| 40 | ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] | 41 | ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] |
| 41 | mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] | 42 | mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] |
| 42 | embassy-stm32-wpan = [] | 43 | embassy-stm32-wpan = [] |
| @@ -97,6 +98,11 @@ path = "src/bin/eth.rs" | |||
| 97 | required-features = [ "eth",] | 98 | required-features = [ "eth",] |
| 98 | 99 | ||
| 99 | [[bin]] | 100 | [[bin]] |
| 101 | name = "fdcan" | ||
| 102 | path = "src/bin/fdcan.rs" | ||
| 103 | required-features = [ "fdcan",] | ||
| 104 | |||
| 105 | [[bin]] | ||
| 100 | name = "gpio" | 106 | name = "gpio" |
| 101 | path = "src/bin/gpio.rs" | 107 | path = "src/bin/gpio.rs" |
| 102 | required-features = [] | 108 | required-features = [] |
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs new file mode 100644 index 000000000..7363eaa16 --- /dev/null +++ b/tests/stm32/src/bin/fdcan.rs | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | // required-features: fdcan | ||
| 5 | |||
| 6 | #[path = "../common.rs"] | ||
| 7 | mod common; | ||
| 8 | use common::*; | ||
| 9 | use defmt::assert; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_stm32::peripherals::*; | ||
| 12 | use embassy_stm32::{bind_interrupts, can, Config}; | ||
| 13 | use embassy_time::{Duration, Instant}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | bind_interrupts!(struct Irqs { | ||
| 17 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; | ||
| 18 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | ||
| 19 | }); | ||
| 20 | |||
| 21 | struct TestOptions { | ||
| 22 | config: Config, | ||
| 23 | max_latency: Duration, | ||
| 24 | second_fifo_working: bool, | ||
| 25 | } | ||
| 26 | |||
| 27 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] | ||
| 28 | fn options() -> TestOptions { | ||
| 29 | use embassy_stm32::rcc; | ||
| 30 | info!("H75 config"); | ||
| 31 | let mut c = config(); | ||
| 32 | c.rcc.hse = Some(rcc::Hse { | ||
| 33 | freq: embassy_stm32::time::Hertz(25_000_000), | ||
| 34 | mode: rcc::HseMode::Oscillator, | ||
| 35 | }); | ||
| 36 | c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; | ||
| 37 | TestOptions { | ||
| 38 | config: c, | ||
| 39 | max_latency: Duration::from_micros(3800), | ||
| 40 | second_fifo_working: false, | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | #[cfg(any(feature = "stm32h7a3zi"))] | ||
| 45 | fn options() -> TestOptions { | ||
| 46 | use embassy_stm32::rcc; | ||
| 47 | info!("H7a config"); | ||
| 48 | let mut c = config(); | ||
| 49 | c.rcc.hse = Some(rcc::Hse { | ||
| 50 | freq: embassy_stm32::time::Hertz(25_000_000), | ||
| 51 | mode: rcc::HseMode::Oscillator, | ||
| 52 | }); | ||
| 53 | c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; | ||
| 54 | TestOptions { | ||
| 55 | config: c, | ||
| 56 | max_latency: Duration::from_micros(5500), | ||
| 57 | second_fifo_working: false, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | #[cfg(any(feature = "stm32g491re"))] | ||
| 62 | fn options() -> TestOptions { | ||
| 63 | info!("G4 config"); | ||
| 64 | TestOptions { | ||
| 65 | config: config(), | ||
| 66 | max_latency: Duration::from_micros(500), | ||
| 67 | second_fifo_working: true, | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | #[embassy_executor::main] | ||
| 72 | async fn main(_spawner: Spawner) { | ||
| 73 | //let peripherals = embassy_stm32::init(config()); | ||
| 74 | |||
| 75 | let options = options(); | ||
| 76 | let peripherals = embassy_stm32::init(options.config); | ||
| 77 | |||
| 78 | let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); | ||
| 79 | |||
| 80 | // 250k bps | ||
| 81 | can.set_bitrate(250_000); | ||
| 82 | |||
| 83 | can.can.set_extended_filter( | ||
| 84 | can::filter::ExtendedFilterSlot::_0, | ||
| 85 | can::filter::ExtendedFilter::accept_all_into_fifo1(), | ||
| 86 | ); | ||
| 87 | |||
| 88 | let mut can = can.into_internal_loopback_mode(); | ||
| 89 | |||
| 90 | info!("CAN Configured"); | ||
| 91 | |||
| 92 | let mut i: u8 = 0; | ||
| 93 | loop { | ||
| 94 | let tx_frame = can::TxFrame::new( | ||
| 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 | |||
| 106 | info!("Transmitting frame..."); | ||
| 107 | let tx_ts = Instant::now(); | ||
| 108 | can.write(&tx_frame).await; | ||
| 109 | |||
| 110 | let envelope = can.read().await.unwrap(); | ||
| 111 | info!("Frame received!"); | ||
| 112 | |||
| 113 | // Check data. | ||
| 114 | assert!(i == envelope.data()[0], "{} == {}", i, envelope.data()[0]); | ||
| 115 | |||
| 116 | info!("loopback time {}", envelope.header.time_stamp); | ||
| 117 | info!("loopback frame {=u8}", envelope.data()[0]); | ||
| 118 | let latency = envelope.timestamp.saturating_duration_since(tx_ts); | ||
| 119 | info!("loopback latency {} us", latency.as_micros()); | ||
| 120 | |||
| 121 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 122 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 123 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 124 | // sure if there are other delays | ||
| 125 | assert!( | ||
| 126 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 127 | "{} <= {} <= {}", | ||
| 128 | MIN_LATENCY, | ||
| 129 | latency, | ||
| 130 | options.max_latency | ||
| 131 | ); | ||
| 132 | |||
| 133 | i += 1; | ||
| 134 | if i > 10 { | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | let max_buffered = if options.second_fifo_working { 6 } else { 3 }; | ||
| 140 | |||
| 141 | // Below here, check that we can receive from both FIFO0 and FIFO0 | ||
| 142 | // Above we configured FIFO1 for extended ID packets. There are only 3 slots | ||
| 143 | // in each FIFO so make sure we write enough to fill them both up before reading. | ||
| 144 | for i in 0..3 { | ||
| 145 | // Try filling up the RX FIFO0 buffers with standard packets | ||
| 146 | let tx_frame = can::TxFrame::new( | ||
| 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); | ||
| 158 | can.write(&tx_frame).await; | ||
| 159 | } | ||
| 160 | for i in 3..max_buffered { | ||
| 161 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 162 | let tx_frame = can::TxFrame::new( | ||
| 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); | ||
| 175 | can.write(&tx_frame).await; | ||
| 176 | } | ||
| 177 | |||
| 178 | // Try and receive all 6 packets | ||
| 179 | for i in 0..max_buffered { | ||
| 180 | let envelope = can.read().await.unwrap(); | ||
| 181 | match envelope.header.id { | ||
| 182 | can::Id::Extended(id) => { | ||
| 183 | info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); | ||
| 184 | } | ||
| 185 | can::Id::Standard(id) => { | ||
| 186 | info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | // Test again with a split | ||
| 192 | let (mut tx, mut rx) = can.split(); | ||
| 193 | for i in 0..3 { | ||
| 194 | // Try filling up the RX FIFO0 buffers with standard packets | ||
| 195 | let tx_frame = can::TxFrame::new( | ||
| 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); | ||
| 208 | tx.write(&tx_frame).await; | ||
| 209 | } | ||
| 210 | for i in 3..max_buffered { | ||
| 211 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 212 | let tx_frame = can::TxFrame::new( | ||
| 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); | ||
| 225 | tx.write(&tx_frame).await; | ||
| 226 | } | ||
| 227 | |||
| 228 | // Try and receive all 6 packets | ||
| 229 | for i in 0..max_buffered { | ||
| 230 | let envelope = rx.read().await.unwrap(); | ||
| 231 | match envelope.header.id { | ||
| 232 | can::Id::Extended(id) => { | ||
| 233 | info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); | ||
| 234 | } | ||
| 235 | can::Id::Standard(id) => { | ||
| 236 | info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | info!("Test OK"); | ||
| 242 | cortex_m::asm::bkpt(); | ||
| 243 | } | ||
