aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaleb Garrett <[email protected]>2024-02-04 17:19:15 -0500
committerCaleb Garrett <[email protected]>2024-02-04 17:19:15 -0500
commit059d8a82228c0fa90f7709ce362d7629ca028f13 (patch)
tree2f238a6f97d0da953e98e7f8573fdaff0528f855
parent66f44b95d70547be8e32daac1ab611eec5fbe28a (diff)
parent1f940bf9e868438090ea126eb2267f5e9325fbd4 (diff)
Merge commit '1f940bf9e868438090ea126eb2267f5e9325fbd4' into hash
-rwxr-xr-xci.sh7
-rw-r--r--embassy-net/src/tcp.rs4
-rw-r--r--embassy-nrf/Cargo.toml6
-rw-r--r--embassy-nrf/README.md3
-rw-r--r--embassy-nrf/src/chips/nrf51.rs169
-rw-r--r--embassy-nrf/src/gpio.rs10
-rw-r--r--embassy-nrf/src/lib.rs23
-rw-r--r--embassy-nrf/src/ppi/mod.rs1
-rw-r--r--embassy-nrf/src/ppi/ppi.rs5
-rw-r--r--embassy-nrf/src/rng.rs126
-rw-r--r--embassy-nrf/src/time_driver.rs18
-rw-r--r--embassy-nrf/src/timer.rs20
-rw-r--r--embassy-nrf/src/util.rs1
-rw-r--r--embassy-stm32-wpan/Cargo.toml2
-rw-r--r--embassy-stm32-wpan/build.rs17
-rw-r--r--embassy-stm32-wpan/tl_mbox_extended_wb1.x.in16
-rw-r--r--embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in16
-rw-r--r--embassy-stm32/Cargo.toml900
-rw-r--r--embassy-stm32/build.rs112
-rw-r--r--embassy-stm32/src/adc/f1.rs3
-rw-r--r--embassy-stm32/src/adc/f3.rs2
-rw-r--r--embassy-stm32/src/adc/mod.rs7
-rw-r--r--embassy-stm32/src/adc/v2.rs6
-rw-r--r--embassy-stm32/src/can/bxcan.rs124
-rw-r--r--embassy-stm32/src/can/enums.rs30
-rw-r--r--embassy-stm32/src/can/fdcan.rs714
-rw-r--r--embassy-stm32/src/can/util.rs117
-rw-r--r--embassy-stm32/src/dac/mod.rs23
-rw-r--r--embassy-stm32/src/eth/mod.rs10
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs4
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs2
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs138
-rw-r--r--embassy-stm32/src/hrtim/mod.rs4
-rw-r--r--embassy-stm32/src/hrtim/traits.rs16
-rw-r--r--embassy-stm32/src/i2s.rs9
-rw-r--r--embassy-stm32/src/rcc/c0.rs15
-rw-r--r--embassy-stm32/src/rcc/f.rs59
-rw-r--r--embassy-stm32/src/rcc/f0.rs21
-rw-r--r--embassy-stm32/src/rcc/f1.rs19
-rw-r--r--embassy-stm32/src/rcc/f3.rs22
-rw-r--r--embassy-stm32/src/rcc/g0.rs15
-rw-r--r--embassy-stm32/src/rcc/g4.rs30
-rw-r--r--embassy-stm32/src/rcc/h.rs72
-rw-r--r--embassy-stm32/src/rcc/l.rs75
-rw-r--r--embassy-stm32/src/rcc/mod.rs159
-rw-r--r--embassy-stm32/src/rcc/u5.rs46
-rw-r--r--embassy-stm32/src/rcc/wba.rs213
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs64
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs3
-rw-r--r--embassy-stm32/src/timer/mod.rs40
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs93
-rw-r--r--embassy-stm32/src/usb/usb.rs2
-rw-r--r--embassy-sync/src/priority_channel.rs2
-rw-r--r--embassy-sync/src/ring_buffer.rs22
-rw-r--r--embassy-time/src/lib.rs2
-rw-r--r--embassy-time/src/timer.rs15
-rw-r--r--examples/nrf51/.cargo/config.toml9
-rw-r--r--examples/nrf51/Cargo.toml20
-rw-r--r--examples/nrf51/build.rs35
-rw-r--r--examples/nrf51/memory.x5
-rw-r--r--examples/nrf51/src/bin/blinky.rs20
-rw-r--r--examples/rp/src/bin/debounce.rs80
-rw-r--r--examples/rp/src/bin/i2c_slave.rs6
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs2
-rw-r--r--examples/stm32g4/src/bin/can.rs56
-rw-r--r--examples/stm32h5/src/bin/can.rs74
-rw-r--r--examples/stm32h7/src/bin/can.rs74
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs1
-rw-r--r--examples/stm32h7/src/bin/eth_client_mii.rs142
-rw-r--r--tests/nrf51422/.cargo/config.toml9
-rw-r--r--tests/nrf51422/Cargo.toml22
-rw-r--r--tests/nrf51422/build.rs17
-rw-r--r--tests/nrf51422/memory.x5
-rw-r--r--tests/nrf51422/src/bin/gpio.rs28
-rw-r--r--tests/nrf51422/src/bin/timer.rs24
-rw-r--r--tests/nrf52840/.cargo/config.toml (renamed from tests/nrf/.cargo/config.toml)0
-rw-r--r--tests/nrf52840/Cargo.toml (renamed from tests/nrf/Cargo.toml)0
-rw-r--r--tests/nrf52840/build.rs (renamed from tests/nrf/build.rs)0
-rw-r--r--tests/nrf52840/memory.x (renamed from tests/nrf/memory.x)0
-rw-r--r--tests/nrf52840/src/bin/buffered_uart.rs (renamed from tests/nrf/src/bin/buffered_uart.rs)0
-rw-r--r--tests/nrf52840/src/bin/buffered_uart_full.rs (renamed from tests/nrf/src/bin/buffered_uart_full.rs)0
-rw-r--r--tests/nrf52840/src/bin/buffered_uart_spam.rs (renamed from tests/nrf/src/bin/buffered_uart_spam.rs)0
-rw-r--r--tests/nrf52840/src/bin/ethernet_enc28j60_perf.rs (renamed from tests/nrf/src/bin/ethernet_enc28j60_perf.rs)0
-rw-r--r--tests/nrf52840/src/bin/timer.rs (renamed from tests/nrf/src/bin/timer.rs)1
-rw-r--r--tests/nrf52840/src/bin/wifi_esp_hosted_perf.rs (renamed from tests/nrf/src/bin/wifi_esp_hosted_perf.rs)0
-rw-r--r--tests/rp/src/bin/i2c.rs2
-rw-r--r--tests/stm32/Cargo.toml14
-rw-r--r--tests/stm32/src/bin/fdcan.rs243
88 files changed, 3251 insertions, 1292 deletions
diff --git a/ci.sh b/ci.sh
index 3322c60d1..6a5e6e3f5 100755
--- a/ci.sh
+++ b/ci.sh
@@ -67,6 +67,9 @@ cargo batch \
67 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \ 67 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \
68 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \ 68 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \
69 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \ 69 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \
70 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \
71 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \
72 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \
70 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \ 73 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \
71 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \ 74 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \
72 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \ 75 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \
@@ -148,6 +151,7 @@ cargo batch \
148 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ 151 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
149 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ 152 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
150 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \ 153 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \
154 --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \
151 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ 155 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
152 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ 156 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
153 --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ 157 --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
@@ -211,7 +215,8 @@ cargo batch \
211 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \ 215 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \
212 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \ 216 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \
213 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ 217 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
214 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ 218 --- build --release --manifest-path tests/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
219 --- build --release --manifest-path tests/nrf51422/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/nrf51-dk \
215 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ 220 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
216 $BUILD_EXTRA 221 $BUILD_EXTRA
217 222
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 72b0677b4..c508ff97a 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -342,7 +342,7 @@ impl<'a> TcpSocket<'a> {
342 self.io.with(|s, _| s.may_send()) 342 self.io.with(|s, _| s.may_send())
343 } 343 }
344 344
345 /// return whether the recieve half of the full-duplex connection is open. 345 /// return whether the receive half of the full-duplex connection is open.
346 /// This function returns true if it’s possible to receive data from the remote endpoint. 346 /// This function returns true if it’s possible to receive data from the remote endpoint.
347 /// It will return true while there is data in the receive buffer, and if there isn’t, 347 /// It will return true while there is data in the receive buffer, and if there isn’t,
348 /// as long as the remote endpoint has not closed the connection. 348 /// as long as the remote endpoint has not closed the connection.
@@ -471,7 +471,7 @@ impl<'d> TcpIo<'d> {
471 s.register_recv_waker(cx.waker()); 471 s.register_recv_waker(cx.waker());
472 Poll::Pending 472 Poll::Pending
473 } else { 473 } else {
474 // if we can't receive because the recieve half of the duplex connection is closed then return an error 474 // if we can't receive because the receive half of the duplex connection is closed then return an error
475 Poll::Ready(Err(Error::ConnectionReset)) 475 Poll::Ready(Err(Error::ConnectionReset))
476 } 476 }
477 } else { 477 } else {
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 10f268b51..a682e1227 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -15,6 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/s
15 15
16features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"] 16features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"]
17flavors = [ 17flavors = [
18 { regex_feature = "nrf51", target = "thumbv6m-none-eabi" },
18 { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" }, 19 { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" },
19 { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" }, 20 { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" },
20 { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" }, 21 { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" },
@@ -28,6 +29,7 @@ rustdoc-args = ["--cfg", "docsrs"]
28default = ["rt"] 29default = ["rt"]
29## Cortex-M runtime (enabled by default) 30## Cortex-M runtime (enabled by default)
30rt = [ 31rt = [
32 "nrf51-pac?/rt",
31 "nrf52805-pac?/rt", 33 "nrf52805-pac?/rt",
32 "nrf52810-pac?/rt", 34 "nrf52810-pac?/rt",
33 "nrf52811-pac?/rt", 35 "nrf52811-pac?/rt",
@@ -71,6 +73,8 @@ reset-pin-as-gpio = []
71qspi-multiwrite-flash = [] 73qspi-multiwrite-flash = []
72 74
73#! ### Chip selection features 75#! ### Chip selection features
76## nRF51
77nrf51 = ["nrf51-pac", "_nrf51"]
74## nRF52805 78## nRF52805
75nrf52805 = ["nrf52805-pac", "_nrf52"] 79nrf52805 = ["nrf52805-pac", "_nrf52"]
76## nRF52810 80## nRF52810
@@ -104,6 +108,7 @@ _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
104_nrf5340 = ["_gpio-p1", "_dppi"] 108_nrf5340 = ["_gpio-p1", "_dppi"]
105_nrf9160 = ["nrf9160-pac", "_dppi"] 109_nrf9160 = ["nrf9160-pac", "_dppi"]
106_nrf52 = ["_ppi"] 110_nrf52 = ["_ppi"]
111_nrf51 = ["_ppi"]
107 112
108_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"] 113_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"]
109 114
@@ -144,6 +149,7 @@ embedded-storage-async = "0.4.0"
144cfg-if = "1.0.0" 149cfg-if = "1.0.0"
145document-features = "0.2.7" 150document-features = "0.2.7"
146 151
152nrf51-pac = { version = "0.12.0", optional = true }
147nrf52805-pac = { version = "0.12.0", optional = true } 153nrf52805-pac = { version = "0.12.0", optional = true }
148nrf52810-pac = { version = "0.12.0", optional = true } 154nrf52810-pac = { version = "0.12.0", optional = true }
149nrf52811-pac = { version = "0.12.0", optional = true } 155nrf52811-pac = { version = "0.12.0", optional = true }
diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md
index 50662749d..3df5f1fa5 100644
--- a/embassy-nrf/README.md
+++ b/embassy-nrf/README.md
@@ -14,11 +14,12 @@ For a complete list of available peripherals and features, see the [embassy-nrf
14 14
15The `embassy-nrf` HAL supports most variants of the nRF family: 15The `embassy-nrf` HAL supports most variants of the nRF family:
16 16
17* nRF51 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf51))
17* nRF52 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840)) 18* nRF52 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840))
18* nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340)) 19* nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340))
19* nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160)) 20* nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160))
20 21
21Most peripherals are supported. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf). 22Most peripherals are supported, but can vary between chip families. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf).
22 23
23For MCUs with TrustZone support, both Secure (S) and Non-Secure (NS) modes are supported. Running in Secure mode 24For MCUs with TrustZone support, both Secure (S) and Non-Secure (NS) modes are supported. Running in Secure mode
24allows running Rust code without a SPM or TF-M binary, saving flash space and simplifying development. 25allows running Rust code without a SPM or TF-M binary, saving flash space and simplifying development.
diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs
new file mode 100644
index 000000000..016352fb8
--- /dev/null
+++ b/embassy-nrf/src/chips/nrf51.rs
@@ -0,0 +1,169 @@
1pub use nrf51_pac as pac;
2
3/// The maximum buffer size that the EasyDMA can send/recv in one operation.
4pub const EASY_DMA_SIZE: usize = (1 << 14) - 1;
5
6pub const FLASH_SIZE: usize = 128 * 1024;
7
8embassy_hal_internal::peripherals! {
9 // RTC
10 RTC0,
11 RTC1,
12
13 // WDT
14 WDT,
15
16 // NVMC
17 NVMC,
18
19 // RNG
20 RNG,
21
22 // UARTE
23 UART0,
24
25 // SPI/TWI
26 TWI0,
27 SPI0,
28
29 // ADC
30 ADC,
31
32 // TIMER
33 TIMER0,
34 TIMER1,
35 TIMER2,
36
37 // GPIOTE
38 GPIOTE_CH0,
39 GPIOTE_CH1,
40 GPIOTE_CH2,
41 GPIOTE_CH3,
42
43 // PPI
44 PPI_CH0,
45 PPI_CH1,
46 PPI_CH2,
47 PPI_CH3,
48 PPI_CH4,
49 PPI_CH5,
50 PPI_CH6,
51 PPI_CH7,
52 PPI_CH8,
53 PPI_CH9,
54 PPI_CH10,
55 PPI_CH11,
56 PPI_CH12,
57 PPI_CH13,
58 PPI_CH14,
59 PPI_CH15,
60
61 PPI_GROUP0,
62 PPI_GROUP1,
63 PPI_GROUP2,
64 PPI_GROUP3,
65
66 // GPIO port 0
67 P0_00,
68 P0_01,
69 P0_02,
70 P0_03,
71 P0_04,
72 P0_05,
73 P0_06,
74 P0_07,
75 P0_08,
76 P0_09,
77 P0_10,
78 P0_11,
79 P0_12,
80 P0_13,
81 P0_14,
82 P0_15,
83 P0_16,
84 P0_17,
85 P0_18,
86 P0_19,
87 P0_20,
88 P0_21,
89 P0_22,
90 P0_23,
91 P0_24,
92 P0_25,
93 P0_26,
94 P0_27,
95 P0_28,
96 P0_29,
97 P0_30,
98 P0_31,
99
100 // TEMP
101 TEMP,
102}
103
104impl_timer!(TIMER0, TIMER0, TIMER0);
105impl_timer!(TIMER1, TIMER1, TIMER1);
106impl_timer!(TIMER2, TIMER2, TIMER2);
107
108impl_rng!(RNG, RNG, RNG);
109
110impl_pin!(P0_00, 0, 0);
111impl_pin!(P0_01, 0, 1);
112impl_pin!(P0_02, 0, 2);
113impl_pin!(P0_03, 0, 3);
114impl_pin!(P0_04, 0, 4);
115impl_pin!(P0_05, 0, 5);
116impl_pin!(P0_06, 0, 6);
117impl_pin!(P0_07, 0, 7);
118impl_pin!(P0_08, 0, 8);
119impl_pin!(P0_09, 0, 9);
120impl_pin!(P0_10, 0, 10);
121impl_pin!(P0_11, 0, 11);
122impl_pin!(P0_12, 0, 12);
123impl_pin!(P0_13, 0, 13);
124impl_pin!(P0_14, 0, 14);
125impl_pin!(P0_15, 0, 15);
126impl_pin!(P0_16, 0, 16);
127impl_pin!(P0_17, 0, 17);
128impl_pin!(P0_18, 0, 18);
129impl_pin!(P0_19, 0, 19);
130impl_pin!(P0_20, 0, 20);
131impl_pin!(P0_21, 0, 21);
132impl_pin!(P0_22, 0, 22);
133impl_pin!(P0_23, 0, 23);
134impl_pin!(P0_24, 0, 24);
135impl_pin!(P0_25, 0, 25);
136impl_pin!(P0_26, 0, 26);
137impl_pin!(P0_27, 0, 27);
138impl_pin!(P0_28, 0, 28);
139impl_pin!(P0_29, 0, 29);
140impl_pin!(P0_30, 0, 30);
141impl_pin!(P0_31, 0, 31);
142
143embassy_hal_internal::interrupt_mod!(
144 POWER_CLOCK,
145 RADIO,
146 UART0,
147 SPI0_TWI0,
148 SPI1_TWI1,
149 GPIOTE,
150 ADC,
151 TIMER0,
152 TIMER1,
153 TIMER2,
154 RTC0,
155 TEMP,
156 RNG,
157 ECB,
158 CCM_AAR,
159 WDT,
160 RTC1,
161 QDEC,
162 LPCOMP,
163 SWI0,
164 SWI1,
165 SWI2,
166 SWI3,
167 SWI4,
168 SWI5,
169);
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index 287811e61..b2f987109 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -8,7 +8,13 @@ use cfg_if::cfg_if;
8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; 8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
9 9
10use self::sealed::Pin as _; 10use self::sealed::Pin as _;
11#[cfg(feature = "nrf51")]
12use crate::pac::gpio;
13#[cfg(feature = "nrf51")]
14use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A};
15#[cfg(not(feature = "nrf51"))]
11use crate::pac::p0 as gpio; 16use crate::pac::p0 as gpio;
17#[cfg(not(feature = "nrf51"))]
12use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A}; 18use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A};
13use crate::{pac, Peripheral}; 19use crate::{pac, Peripheral};
14 20
@@ -376,6 +382,9 @@ pub(crate) mod sealed {
376 fn block(&self) -> &gpio::RegisterBlock { 382 fn block(&self) -> &gpio::RegisterBlock {
377 unsafe { 383 unsafe {
378 match self.pin_port() / 32 { 384 match self.pin_port() / 32 {
385 #[cfg(feature = "nrf51")]
386 0 => &*pac::GPIO::ptr(),
387 #[cfg(not(feature = "nrf51"))]
379 0 => &*pac::P0::ptr(), 388 0 => &*pac::P0::ptr(),
380 #[cfg(feature = "_gpio-p1")] 389 #[cfg(feature = "_gpio-p1")]
381 1 => &*pac::P1::ptr(), 390 1 => &*pac::P1::ptr(),
@@ -478,6 +487,7 @@ impl<'a, P: Pin> PselBits for Option<PeripheralRef<'a, P>> {
478 } 487 }
479} 488}
480 489
490#[allow(dead_code)]
481pub(crate) fn deconfigure_pin(psel_bits: u32) { 491pub(crate) fn deconfigure_pin(psel_bits: u32) {
482 if psel_bits & 0x8000_0000 != 0 { 492 if psel_bits & 0x8000_0000 != 0 {
483 return; 493 return;
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index d9c92a76d..358a7cc27 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -40,6 +40,7 @@ pub(crate) mod util;
40#[cfg(feature = "_time-driver")] 40#[cfg(feature = "_time-driver")]
41mod time_driver; 41mod time_driver;
42 42
43#[cfg(not(feature = "nrf51"))]
43pub mod buffered_uarte; 44pub mod buffered_uarte;
44pub mod gpio; 45pub mod gpio;
45#[cfg(feature = "gpiote")] 46#[cfg(feature = "gpiote")]
@@ -58,7 +59,12 @@ pub mod nvmc;
58))] 59))]
59pub mod pdm; 60pub mod pdm;
60pub mod ppi; 61pub mod ppi;
61#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] 62#[cfg(not(any(
63 feature = "nrf51",
64 feature = "nrf52805",
65 feature = "nrf52820",
66 feature = "_nrf5340-net"
67)))]
62pub mod pwm; 68pub mod pwm;
63#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))] 69#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))]
64pub mod qdec; 70pub mod qdec;
@@ -66,15 +72,20 @@ pub mod qdec;
66pub mod qspi; 72pub mod qspi;
67#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))] 73#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
68pub mod rng; 74pub mod rng;
69#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] 75#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
70pub mod saadc; 76pub mod saadc;
77#[cfg(not(feature = "nrf51"))]
71pub mod spim; 78pub mod spim;
79#[cfg(not(feature = "nrf51"))]
72pub mod spis; 80pub mod spis;
73#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 81#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
74pub mod temp; 82pub mod temp;
75pub mod timer; 83pub mod timer;
84#[cfg(not(feature = "nrf51"))]
76pub mod twim; 85pub mod twim;
86#[cfg(not(feature = "nrf51"))]
77pub mod twis; 87pub mod twis;
88#[cfg(not(feature = "nrf51"))]
78pub mod uarte; 89pub mod uarte;
79#[cfg(any( 90#[cfg(any(
80 feature = "_nrf5340-app", 91 feature = "_nrf5340-app",
@@ -87,6 +98,7 @@ pub mod usb;
87pub mod wdt; 98pub mod wdt;
88 99
89// This mod MUST go last, so that it sees all the `impl_foo!` macros 100// This mod MUST go last, so that it sees all the `impl_foo!` macros
101#[cfg_attr(feature = "nrf51", path = "chips/nrf51.rs")]
90#[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")] 102#[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")]
91#[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")] 103#[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")]
92#[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")] 104#[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")]
@@ -324,6 +336,7 @@ mod consts {
324 pub const APPROTECT_DISABLED: u32 = 0x0000_005a; 336 pub const APPROTECT_DISABLED: u32 = 0x0000_005a;
325} 337}
326 338
339#[cfg(not(feature = "nrf51"))]
327#[derive(Debug, Copy, Clone, Eq, PartialEq)] 340#[derive(Debug, Copy, Clone, Eq, PartialEq)]
328#[cfg_attr(feature = "defmt", derive(defmt::Format))] 341#[cfg_attr(feature = "defmt", derive(defmt::Format))]
329enum WriteResult { 342enum WriteResult {
@@ -335,10 +348,12 @@ enum WriteResult {
335 Failed, 348 Failed,
336} 349}
337 350
351#[cfg(not(feature = "nrf51"))]
338unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult { 352unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult {
339 uicr_write_masked(address, value, 0xFFFF_FFFF) 353 uicr_write_masked(address, value, 0xFFFF_FFFF)
340} 354}
341 355
356#[cfg(not(feature = "nrf51"))]
342unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult { 357unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult {
343 let curr_val = address.read_volatile(); 358 let curr_val = address.read_volatile();
344 if curr_val & mask == value & mask { 359 if curr_val & mask == value & mask {
@@ -371,9 +386,11 @@ pub fn init(config: config::Config) -> Peripherals {
371 // before doing anything important. 386 // before doing anything important.
372 let peripherals = Peripherals::take(); 387 let peripherals = Peripherals::take();
373 388
389 #[allow(unused_mut)]
374 let mut needs_reset = false; 390 let mut needs_reset = false;
375 391
376 // Setup debug protection. 392 // Setup debug protection.
393 #[cfg(not(feature = "nrf51"))]
377 match config.debug { 394 match config.debug {
378 config::Debug::Allowed => { 395 config::Debug::Allowed => {
379 #[cfg(feature = "_nrf52")] 396 #[cfg(feature = "_nrf52")]
@@ -489,7 +506,7 @@ pub fn init(config: config::Config) -> Peripherals {
489 } 506 }
490 507
491 // Configure LFCLK. 508 // Configure LFCLK.
492 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 509 #[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf9160")))]
493 match config.lfclk_source { 510 match config.lfclk_source {
494 config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), 511 config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
495 config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), 512 config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index 5b4a64388..f5764b8b7 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -284,6 +284,7 @@ impl ConfigurableChannel for AnyConfigurableChannel {
284 } 284 }
285} 285}
286 286
287#[cfg(not(feature = "nrf51"))]
287macro_rules! impl_ppi_channel { 288macro_rules! impl_ppi_channel {
288 ($type:ident, $number:expr) => { 289 ($type:ident, $number:expr) => {
289 impl crate::ppi::sealed::Channel for peripherals::$type {} 290 impl crate::ppi::sealed::Channel for peripherals::$type {}
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs
index 3e9e9fc81..8ff52ece3 100644
--- a/embassy-nrf/src/ppi/ppi.rs
+++ b/embassy-nrf/src/ppi/ppi.rs
@@ -1,6 +1,6 @@
1use embassy_hal_internal::into_ref; 1use embassy_hal_internal::into_ref;
2 2
3use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task}; 3use super::{Channel, ConfigurableChannel, Event, Ppi, Task};
4use crate::{pac, Peripheral}; 4use crate::{pac, Peripheral};
5 5
6impl<'d> Task<'d> { 6impl<'d> Task<'d> {
@@ -19,7 +19,7 @@ pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
19} 19}
20 20
21#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task 21#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
22impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> { 22impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> {
23 /// Configure PPI channel to trigger `task`. 23 /// Configure PPI channel to trigger `task`.
24 pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self { 24 pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self {
25 into_ref!(ch); 25 into_ref!(ch);
@@ -84,6 +84,7 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for
84 let n = self.ch.number(); 84 let n = self.ch.number();
85 r.ch[n].eep.write(|w| unsafe { w.bits(0) }); 85 r.ch[n].eep.write(|w| unsafe { w.bits(0) });
86 r.ch[n].tep.write(|w| unsafe { w.bits(0) }); 86 r.ch[n].tep.write(|w| unsafe { w.bits(0) });
87 #[cfg(not(feature = "nrf51"))]
87 r.fork[n].tep.write(|w| unsafe { w.bits(0) }); 88 r.fork[n].tep.write(|w| unsafe { w.bits(0) });
88 } 89 }
89} 90}
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index e2803f0d3..40b73231b 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -5,12 +5,10 @@
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::ptr; 7use core::ptr;
8use core::sync::atomic::{AtomicPtr, Ordering};
9use core::task::Poll; 8use core::task::Poll;
10 9
11use embassy_hal_internal::drop::OnDrop; 10use embassy_hal_internal::drop::OnDrop;
12use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::{into_ref, PeripheralRef};
13use embassy_sync::waitqueue::AtomicWaker;
14 12
15use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
16use crate::{interrupt, Peripheral}; 14use crate::{interrupt, Peripheral};
@@ -22,7 +20,6 @@ pub struct InterruptHandler<T: Instance> {
22 20
23impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 21impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
24 unsafe fn on_interrupt() { 22 unsafe fn on_interrupt() {
25 let s = T::state();
26 let r = T::regs(); 23 let r = T::regs();
27 24
28 // Clear the event. 25 // Clear the event.
@@ -30,46 +27,25 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
30 27
31 // Mutate the slice within a critical section, 28 // Mutate the slice within a critical section,
32 // so that the future isn't dropped in between us loading the pointer and actually dereferencing it. 29 // so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
33 let (ptr, end) = critical_section::with(|_| { 30 critical_section::with(|cs| {
34 let ptr = s.ptr.load(Ordering::Relaxed); 31 let mut state = T::state().borrow_mut(cs);
35 // We need to make sure we haven't already filled the whole slice, 32 // We need to make sure we haven't already filled the whole slice,
36 // in case the interrupt fired again before the executor got back to the future. 33 // in case the interrupt fired again before the executor got back to the future.
37 let end = s.end.load(Ordering::Relaxed); 34 if !state.ptr.is_null() && state.ptr != state.end {
38 if !ptr.is_null() && ptr != end {
39 // If the future was dropped, the pointer would have been set to null, 35 // If the future was dropped, the pointer would have been set to null,
40 // so we're still good to mutate the slice. 36 // so we're still good to mutate the slice.
41 // The safety contract of `Rng::new` means that the future can't have been dropped 37 // The safety contract of `Rng::new` means that the future can't have been dropped
42 // without calling its destructor. 38 // without calling its destructor.
43 unsafe { 39 unsafe {
44 *ptr = r.value.read().value().bits(); 40 *state.ptr = r.value.read().value().bits();
41 state.ptr = state.ptr.add(1);
45 } 42 }
46 }
47 (ptr, end)
48 });
49
50 if ptr.is_null() || ptr == end {
51 // If the future was dropped, there's nothing to do.
52 // If `ptr == end`, we were called by mistake, so return.
53 return;
54 }
55 43
56 let new_ptr = unsafe { ptr.add(1) }; 44 if state.ptr == state.end {
57 match s 45 state.waker.wake();
58 .ptr
59 .compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
60 {
61 Ok(_) => {
62 let end = s.end.load(Ordering::Relaxed);
63 // It doesn't matter if `end` was changed under our feet, because then this will just be false.
64 if new_ptr == end {
65 s.waker.wake();
66 } 46 }
67 } 47 }
68 Err(_) => { 48 });
69 // If the future was dropped or finished, there's no point trying to wake it.
70 // It will have already stopped the RNG, so there's no need to do that either.
71 }
72 }
73 } 49 }
74} 50}
75 51
@@ -136,13 +112,14 @@ impl<'d, T: Instance> Rng<'d, T> {
136 return; // Nothing to fill 112 return; // Nothing to fill
137 } 113 }
138 114
139 let s = T::state();
140
141 let range = dest.as_mut_ptr_range(); 115 let range = dest.as_mut_ptr_range();
142 // Even if we've preempted the interrupt, it can't preempt us again, 116 // Even if we've preempted the interrupt, it can't preempt us again,
143 // so we don't need to worry about the order we write these in. 117 // so we don't need to worry about the order we write these in.
144 s.ptr.store(range.start, Ordering::Relaxed); 118 critical_section::with(|cs| {
145 s.end.store(range.end, Ordering::Relaxed); 119 let mut state = T::state().borrow_mut(cs);
120 state.ptr = range.start;
121 state.end = range.end;
122 });
146 123
147 self.enable_irq(); 124 self.enable_irq();
148 self.start(); 125 self.start();
@@ -151,24 +128,24 @@ impl<'d, T: Instance> Rng<'d, T> {
151 self.stop(); 128 self.stop();
152 self.disable_irq(); 129 self.disable_irq();
153 130
154 // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. 131 critical_section::with(|cs| {
155 s.ptr.store(ptr::null_mut(), Ordering::Relaxed); 132 let mut state = T::state().borrow_mut(cs);
156 s.end.store(ptr::null_mut(), Ordering::Relaxed); 133 state.ptr = ptr::null_mut();
134 state.end = ptr::null_mut();
135 });
157 }); 136 });
158 137
159 poll_fn(|cx| { 138 poll_fn(|cx| {
160 s.waker.register(cx.waker()); 139 critical_section::with(|cs| {
161 140 let mut s = T::state().borrow_mut(cs);
162 // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. 141 s.waker.register(cx.waker());
163 let end = s.end.load(Ordering::Relaxed); 142 if s.ptr == s.end {
164 let ptr = s.ptr.load(Ordering::Relaxed); 143 // We're done.
165 144 Poll::Ready(())
166 if ptr == end { 145 } else {
167 // We're done. 146 Poll::Pending
168 Poll::Ready(()) 147 }
169 } else { 148 })
170 Poll::Pending
171 }
172 }) 149 })
173 .await; 150 .await;
174 151
@@ -194,9 +171,11 @@ impl<'d, T: Instance> Rng<'d, T> {
194impl<'d, T: Instance> Drop for Rng<'d, T> { 171impl<'d, T: Instance> Drop for Rng<'d, T> {
195 fn drop(&mut self) { 172 fn drop(&mut self) {
196 self.stop(); 173 self.stop();
197 let s = T::state(); 174 critical_section::with(|cs| {
198 s.ptr.store(ptr::null_mut(), Ordering::Relaxed); 175 let mut state = T::state().borrow_mut(cs);
199 s.end.store(ptr::null_mut(), Ordering::Relaxed); 176 state.ptr = ptr::null_mut();
177 state.end = ptr::null_mut();
178 });
200 } 179 }
201} 180}
202 181
@@ -227,21 +206,48 @@ impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> {
227impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} 206impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {}
228 207
229pub(crate) mod sealed { 208pub(crate) mod sealed {
209 use core::cell::{Ref, RefCell, RefMut};
210
211 use critical_section::{CriticalSection, Mutex};
212 use embassy_sync::waitqueue::WakerRegistration;
213
230 use super::*; 214 use super::*;
231 215
232 /// Peripheral static state 216 /// Peripheral static state
233 pub struct State { 217 pub struct State {
234 pub ptr: AtomicPtr<u8>, 218 inner: Mutex<RefCell<InnerState>>,
235 pub end: AtomicPtr<u8>, 219 }
236 pub waker: AtomicWaker, 220
221 pub struct InnerState {
222 pub ptr: *mut u8,
223 pub end: *mut u8,
224 pub waker: WakerRegistration,
237 } 225 }
238 226
227 unsafe impl Send for InnerState {}
228
239 impl State { 229 impl State {
240 pub const fn new() -> Self { 230 pub const fn new() -> Self {
241 Self { 231 Self {
242 ptr: AtomicPtr::new(ptr::null_mut()), 232 inner: Mutex::new(RefCell::new(InnerState::new())),
243 end: AtomicPtr::new(ptr::null_mut()), 233 }
244 waker: AtomicWaker::new(), 234 }
235
236 pub fn borrow<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, InnerState> {
237 self.inner.borrow(cs).borrow()
238 }
239
240 pub fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> {
241 self.inner.borrow(cs).borrow_mut()
242 }
243 }
244
245 impl InnerState {
246 pub const fn new() -> Self {
247 Self {
248 ptr: ptr::null_mut(),
249 end: ptr::null_mut(),
250 waker: WakerRegistration::new(),
245 } 251 }
246 } 252 }
247 } 253 }
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 042f7c5f7..3407c9504 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -171,7 +171,8 @@ impl RtcDriver {
171 fn next_period(&self) { 171 fn next_period(&self) {
172 critical_section::with(|cs| { 172 critical_section::with(|cs| {
173 let r = rtc(); 173 let r = rtc();
174 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; 174 let period = self.period.load(Ordering::Relaxed) + 1;
175 self.period.store(period, Ordering::Relaxed);
175 let t = (period as u64) << 23; 176 let t = (period as u64) << 23;
176 177
177 for n in 0..ALARM_COUNT { 178 for n in 0..ALARM_COUNT {
@@ -219,18 +220,15 @@ impl Driver for RtcDriver {
219 } 220 }
220 221
221 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 222 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
222 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { 223 critical_section::with(|_| {
223 if x < ALARM_COUNT as u8 { 224 let id = self.alarm_count.load(Ordering::Relaxed);
224 Some(x + 1) 225 if id < ALARM_COUNT as u8 {
226 self.alarm_count.store(id + 1, Ordering::Relaxed);
227 Some(AlarmHandle::new(id))
225 } else { 228 } else {
226 None 229 None
227 } 230 }
228 }); 231 })
229
230 match id {
231 Ok(id) => Some(AlarmHandle::new(id)),
232 Err(_) => None,
233 }
234 } 232 }
235 233
236 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 234 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index 3dbfdac42..3c35baee5 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -111,7 +111,7 @@ impl<'d, T: Instance> Timer<'d, T> {
111 Self::new_inner(timer, true) 111 Self::new_inner(timer, true)
112 } 112 }
113 113
114 fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self { 114 fn new_inner(timer: impl Peripheral<P = T> + 'd, _is_counter: bool) -> Self {
115 into_ref!(timer); 115 into_ref!(timer);
116 116
117 let regs = T::regs(); 117 let regs = T::regs();
@@ -122,12 +122,16 @@ impl<'d, T: Instance> Timer<'d, T> {
122 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. 122 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
123 this.stop(); 123 this.stop();
124 124
125 if is_counter { 125 #[cfg(not(feature = "nrf51"))]
126 if _is_counter {
126 regs.mode.write(|w| w.mode().low_power_counter()); 127 regs.mode.write(|w| w.mode().low_power_counter());
127 } else { 128 } else {
128 regs.mode.write(|w| w.mode().timer()); 129 regs.mode.write(|w| w.mode().timer());
129 } 130 }
130 131
132 #[cfg(feature = "nrf51")]
133 regs.mode.write(|w| w.mode().timer());
134
131 // Make the counter's max value as high as possible. 135 // Make the counter's max value as high as possible.
132 // TODO: is there a reason someone would want to set this lower? 136 // TODO: is there a reason someone would want to set this lower?
133 regs.bitmode.write(|w| w.bitmode()._32bit()); 137 regs.bitmode.write(|w| w.bitmode()._32bit());
@@ -238,7 +242,11 @@ pub struct Cc<'d, T: Instance> {
238impl<'d, T: Instance> Cc<'d, T> { 242impl<'d, T: Instance> Cc<'d, T> {
239 /// Get the current value stored in the register. 243 /// Get the current value stored in the register.
240 pub fn read(&self) -> u32 { 244 pub fn read(&self) -> u32 {
241 T::regs().cc[self.n].read().cc().bits() 245 #[cfg(not(feature = "nrf51"))]
246 return T::regs().cc[self.n].read().cc().bits();
247
248 #[cfg(feature = "nrf51")]
249 return T::regs().cc[self.n].read().bits();
242 } 250 }
243 251
244 /// Set the value stored in the register. 252 /// Set the value stored in the register.
@@ -246,7 +254,11 @@ impl<'d, T: Instance> Cc<'d, T> {
246 /// `event_compare` will fire when the timer's counter reaches this value. 254 /// `event_compare` will fire when the timer's counter reaches this value.
247 pub fn write(&self, value: u32) { 255 pub fn write(&self, value: u32) {
248 // SAFETY: there are no invalid values for the CC register. 256 // SAFETY: there are no invalid values for the CC register.
249 T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }) 257 #[cfg(not(feature = "nrf51"))]
258 T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) });
259
260 #[cfg(feature = "nrf51")]
261 T::regs().cc[self.n].write(|w| unsafe { w.bits(value) });
250 } 262 }
251 263
252 /// Capture the current value of the timer's counter in this register, and return it. 264 /// Capture the current value of the timer's counter in this register, and return it.
diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs
index cd0f59490..b408c517b 100644
--- a/embassy-nrf/src/util.rs
+++ b/embassy-nrf/src/util.rs
@@ -1,3 +1,4 @@
1#![allow(dead_code)]
1use core::mem; 2use core::mem;
2 3
3const SRAM_LOWER: usize = 0x2000_0000; 4const SRAM_LOWER: usize = 0x2000_0000;
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 4f53a400a..360ca5f4b 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -44,6 +44,8 @@ defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embas
44ble = ["dep:stm32wb-hci"] 44ble = ["dep:stm32wb-hci"]
45mac = ["dep:bitflags", "dep:embassy-net-driver" ] 45mac = ["dep:bitflags", "dep:embassy-net-driver" ]
46 46
47extended = []
48
47stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] 49stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
48stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] 50stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
49stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ] 51stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ]
diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs
index 94aac070d..7ab458bf2 100644
--- a/embassy-stm32-wpan/build.rs
+++ b/embassy-stm32-wpan/build.rs
@@ -18,9 +18,22 @@ fn main() {
18 // stm32wb tl_mbox link sections 18 // stm32wb tl_mbox link sections
19 19
20 let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string(); 20 let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string();
21 fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap(); 21 let in_file;
22 if env::var_os("CARGO_FEATURE_EXTENDED").is_some() {
23 if env::vars()
24 .map(|(a, _)| a)
25 .any(|x| x.starts_with("CARGO_FEATURE_STM32WB1"))
26 {
27 in_file = "tl_mbox_extended_wb1.x.in";
28 } else {
29 in_file = "tl_mbox_extended_wbx5.x.in";
30 }
31 } else {
32 in_file = "tl_mbox.x.in";
33 }
34 fs::write(out_file, fs::read_to_string(in_file).unwrap()).unwrap();
22 println!("cargo:rustc-link-search={}", out_dir.display()); 35 println!("cargo:rustc-link-search={}", out_dir.display());
23 println!("cargo:rerun-if-changed=tl_mbox.x.in"); 36 println!("cargo:rerun-if-changed={}", in_file);
24} 37}
25 38
26enum GetOneError { 39enum GetOneError {
diff --git a/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in b/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in
new file mode 100644
index 000000000..4cffdaddd
--- /dev/null
+++ b/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in
@@ -0,0 +1,16 @@
1MEMORY
2{
3 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 4K
4 RAMB_SHARED (xrw) : ORIGIN = 0x20030028, LENGTH = 4K
5}
6
7/*
8 * Scatter the mailbox interface memory sections in shared memory
9 */
10SECTIONS
11{
12 TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
13
14 MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAMB_SHARED
15 MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAMB_SHARED
16}
diff --git a/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in b/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in
new file mode 100644
index 000000000..281d637a9
--- /dev/null
+++ b/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in
@@ -0,0 +1,16 @@
1MEMORY
2{
3 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 2K
4 RAMB_SHARED (xrw) : ORIGIN = 0x20038000, LENGTH = 10K
5}
6
7/*
8 * Scatter the mailbox interface memory sections in shared memory
9 */
10SECTIONS
11{
12 TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
13
14 MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAMB_SHARED
15 MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAMB_SHARED
16}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 00d8a5f63..698febf71 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -68,7 +68,7 @@ rand_core = "0.6.3"
68sdio-host = "0.5.0" 68sdio-host = "0.5.0"
69critical-section = "1.1" 69critical-section = "1.1"
70#stm32-metapac = { version = "15" } 70#stm32-metapac = { version = "15" }
71stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-aa5dbf859fae743306f5d816905f166de824241f" } 71stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15" }
72vcell = "0.1.3" 72vcell = "0.1.3"
73bxcan = "0.7.0" 73bxcan = "0.7.0"
74nb = "1.0.0" 74nb = "1.0.0"
@@ -80,6 +80,8 @@ chrono = { version = "^0.4", default-features = false, optional = true}
80bit_field = "0.10.2" 80bit_field = "0.10.2"
81document-features = "0.2.7" 81document-features = "0.2.7"
82 82
83fdcan = { version = "0.2.0", optional = true }
84
83[dev-dependencies] 85[dev-dependencies]
84critical-section = { version = "1.1", features = ["std"] } 86critical-section = { version = "1.1", features = ["std"] }
85 87
@@ -87,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] }
87proc-macro2 = "1.0.36" 89proc-macro2 = "1.0.36"
88quote = "1.0.15" 90quote = "1.0.15"
89#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 91#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
90stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-aa5dbf859fae743306f5d816905f166de824241f", default-features = false, features = ["metadata"]} 92stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15", default-features = false, features = ["metadata"]}
91 93
92 94
93[features] 95[features]
@@ -693,373 +695,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ]
693stm32f779bi = [ "stm32-metapac/stm32f779bi" ] 695stm32f779bi = [ "stm32-metapac/stm32f779bi" ]
694stm32f779ii = [ "stm32-metapac/stm32f779ii" ] 696stm32f779ii = [ "stm32-metapac/stm32f779ii" ]
695stm32f779ni = [ "stm32-metapac/stm32f779ni" ] 697stm32f779ni = [ "stm32-metapac/stm32f779ni" ]
696stm32g030c6 = [ "stm32-metapac/stm32g030c6" ] 698stm32g030c6 = [ "stm32-metapac/stm32g030c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
697stm32g030c8 = [ "stm32-metapac/stm32g030c8" ] 699stm32g030c8 = [ "stm32-metapac/stm32g030c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
698stm32g030f6 = [ "stm32-metapac/stm32g030f6" ] 700stm32g030f6 = [ "stm32-metapac/stm32g030f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
699stm32g030j6 = [ "stm32-metapac/stm32g030j6" ] 701stm32g030j6 = [ "stm32-metapac/stm32g030j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
700stm32g030k6 = [ "stm32-metapac/stm32g030k6" ] 702stm32g030k6 = [ "stm32-metapac/stm32g030k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
701stm32g030k8 = [ "stm32-metapac/stm32g030k8" ] 703stm32g030k8 = [ "stm32-metapac/stm32g030k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
702stm32g031c4 = [ "stm32-metapac/stm32g031c4" ] 704stm32g031c4 = [ "stm32-metapac/stm32g031c4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
703stm32g031c6 = [ "stm32-metapac/stm32g031c6" ] 705stm32g031c6 = [ "stm32-metapac/stm32g031c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
704stm32g031c8 = [ "stm32-metapac/stm32g031c8" ] 706stm32g031c8 = [ "stm32-metapac/stm32g031c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
705stm32g031f4 = [ "stm32-metapac/stm32g031f4" ] 707stm32g031f4 = [ "stm32-metapac/stm32g031f4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
706stm32g031f6 = [ "stm32-metapac/stm32g031f6" ] 708stm32g031f6 = [ "stm32-metapac/stm32g031f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
707stm32g031f8 = [ "stm32-metapac/stm32g031f8" ] 709stm32g031f8 = [ "stm32-metapac/stm32g031f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
708stm32g031g4 = [ "stm32-metapac/stm32g031g4" ] 710stm32g031g4 = [ "stm32-metapac/stm32g031g4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
709stm32g031g6 = [ "stm32-metapac/stm32g031g6" ] 711stm32g031g6 = [ "stm32-metapac/stm32g031g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
710stm32g031g8 = [ "stm32-metapac/stm32g031g8" ] 712stm32g031g8 = [ "stm32-metapac/stm32g031g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
711stm32g031j4 = [ "stm32-metapac/stm32g031j4" ] 713stm32g031j4 = [ "stm32-metapac/stm32g031j4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
712stm32g031j6 = [ "stm32-metapac/stm32g031j6" ] 714stm32g031j6 = [ "stm32-metapac/stm32g031j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
713stm32g031k4 = [ "stm32-metapac/stm32g031k4" ] 715stm32g031k4 = [ "stm32-metapac/stm32g031k4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
714stm32g031k6 = [ "stm32-metapac/stm32g031k6" ] 716stm32g031k6 = [ "stm32-metapac/stm32g031k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
715stm32g031k8 = [ "stm32-metapac/stm32g031k8" ] 717stm32g031k8 = [ "stm32-metapac/stm32g031k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
716stm32g031y8 = [ "stm32-metapac/stm32g031y8" ] 718stm32g031y8 = [ "stm32-metapac/stm32g031y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
717stm32g041c6 = [ "stm32-metapac/stm32g041c6" ] 719stm32g041c6 = [ "stm32-metapac/stm32g041c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
718stm32g041c8 = [ "stm32-metapac/stm32g041c8" ] 720stm32g041c8 = [ "stm32-metapac/stm32g041c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
719stm32g041f6 = [ "stm32-metapac/stm32g041f6" ] 721stm32g041f6 = [ "stm32-metapac/stm32g041f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
720stm32g041f8 = [ "stm32-metapac/stm32g041f8" ] 722stm32g041f8 = [ "stm32-metapac/stm32g041f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
721stm32g041g6 = [ "stm32-metapac/stm32g041g6" ] 723stm32g041g6 = [ "stm32-metapac/stm32g041g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
722stm32g041g8 = [ "stm32-metapac/stm32g041g8" ] 724stm32g041g8 = [ "stm32-metapac/stm32g041g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
723stm32g041j6 = [ "stm32-metapac/stm32g041j6" ] 725stm32g041j6 = [ "stm32-metapac/stm32g041j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
724stm32g041k6 = [ "stm32-metapac/stm32g041k6" ] 726stm32g041k6 = [ "stm32-metapac/stm32g041k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
725stm32g041k8 = [ "stm32-metapac/stm32g041k8" ] 727stm32g041k8 = [ "stm32-metapac/stm32g041k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
726stm32g041y8 = [ "stm32-metapac/stm32g041y8" ] 728stm32g041y8 = [ "stm32-metapac/stm32g041y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
727stm32g050c6 = [ "stm32-metapac/stm32g050c6" ] 729stm32g050c6 = [ "stm32-metapac/stm32g050c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
728stm32g050c8 = [ "stm32-metapac/stm32g050c8" ] 730stm32g050c8 = [ "stm32-metapac/stm32g050c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
729stm32g050f6 = [ "stm32-metapac/stm32g050f6" ] 731stm32g050f6 = [ "stm32-metapac/stm32g050f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
730stm32g050k6 = [ "stm32-metapac/stm32g050k6" ] 732stm32g050k6 = [ "stm32-metapac/stm32g050k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
731stm32g050k8 = [ "stm32-metapac/stm32g050k8" ] 733stm32g050k8 = [ "stm32-metapac/stm32g050k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
732stm32g051c6 = [ "stm32-metapac/stm32g051c6" ] 734stm32g051c6 = [ "stm32-metapac/stm32g051c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
733stm32g051c8 = [ "stm32-metapac/stm32g051c8" ] 735stm32g051c8 = [ "stm32-metapac/stm32g051c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
734stm32g051f6 = [ "stm32-metapac/stm32g051f6" ] 736stm32g051f6 = [ "stm32-metapac/stm32g051f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
735stm32g051f8 = [ "stm32-metapac/stm32g051f8" ] 737stm32g051f8 = [ "stm32-metapac/stm32g051f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
736stm32g051g6 = [ "stm32-metapac/stm32g051g6" ] 738stm32g051g6 = [ "stm32-metapac/stm32g051g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
737stm32g051g8 = [ "stm32-metapac/stm32g051g8" ] 739stm32g051g8 = [ "stm32-metapac/stm32g051g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
738stm32g051k6 = [ "stm32-metapac/stm32g051k6" ] 740stm32g051k6 = [ "stm32-metapac/stm32g051k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
739stm32g051k8 = [ "stm32-metapac/stm32g051k8" ] 741stm32g051k8 = [ "stm32-metapac/stm32g051k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
740stm32g061c6 = [ "stm32-metapac/stm32g061c6" ] 742stm32g061c6 = [ "stm32-metapac/stm32g061c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
741stm32g061c8 = [ "stm32-metapac/stm32g061c8" ] 743stm32g061c8 = [ "stm32-metapac/stm32g061c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
742stm32g061f6 = [ "stm32-metapac/stm32g061f6" ] 744stm32g061f6 = [ "stm32-metapac/stm32g061f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
743stm32g061f8 = [ "stm32-metapac/stm32g061f8" ] 745stm32g061f8 = [ "stm32-metapac/stm32g061f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
744stm32g061g6 = [ "stm32-metapac/stm32g061g6" ] 746stm32g061g6 = [ "stm32-metapac/stm32g061g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
745stm32g061g8 = [ "stm32-metapac/stm32g061g8" ] 747stm32g061g8 = [ "stm32-metapac/stm32g061g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
746stm32g061k6 = [ "stm32-metapac/stm32g061k6" ] 748stm32g061k6 = [ "stm32-metapac/stm32g061k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
747stm32g061k8 = [ "stm32-metapac/stm32g061k8" ] 749stm32g061k8 = [ "stm32-metapac/stm32g061k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
748stm32g070cb = [ "stm32-metapac/stm32g070cb" ] 750stm32g070cb = [ "stm32-metapac/stm32g070cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
749stm32g070kb = [ "stm32-metapac/stm32g070kb" ] 751stm32g070kb = [ "stm32-metapac/stm32g070kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
750stm32g070rb = [ "stm32-metapac/stm32g070rb" ] 752stm32g070rb = [ "stm32-metapac/stm32g070rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
751stm32g071c6 = [ "stm32-metapac/stm32g071c6" ] 753stm32g071c6 = [ "stm32-metapac/stm32g071c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
752stm32g071c8 = [ "stm32-metapac/stm32g071c8" ] 754stm32g071c8 = [ "stm32-metapac/stm32g071c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
753stm32g071cb = [ "stm32-metapac/stm32g071cb" ] 755stm32g071cb = [ "stm32-metapac/stm32g071cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
754stm32g071eb = [ "stm32-metapac/stm32g071eb" ] 756stm32g071eb = [ "stm32-metapac/stm32g071eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
755stm32g071g6 = [ "stm32-metapac/stm32g071g6" ] 757stm32g071g6 = [ "stm32-metapac/stm32g071g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
756stm32g071g8 = [ "stm32-metapac/stm32g071g8" ] 758stm32g071g8 = [ "stm32-metapac/stm32g071g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
757stm32g071gb = [ "stm32-metapac/stm32g071gb" ] 759stm32g071gb = [ "stm32-metapac/stm32g071gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
758stm32g071k6 = [ "stm32-metapac/stm32g071k6" ] 760stm32g071k6 = [ "stm32-metapac/stm32g071k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
759stm32g071k8 = [ "stm32-metapac/stm32g071k8" ] 761stm32g071k8 = [ "stm32-metapac/stm32g071k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
760stm32g071kb = [ "stm32-metapac/stm32g071kb" ] 762stm32g071kb = [ "stm32-metapac/stm32g071kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
761stm32g071r6 = [ "stm32-metapac/stm32g071r6" ] 763stm32g071r6 = [ "stm32-metapac/stm32g071r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
762stm32g071r8 = [ "stm32-metapac/stm32g071r8" ] 764stm32g071r8 = [ "stm32-metapac/stm32g071r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
763stm32g071rb = [ "stm32-metapac/stm32g071rb" ] 765stm32g071rb = [ "stm32-metapac/stm32g071rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
764stm32g081cb = [ "stm32-metapac/stm32g081cb" ] 766stm32g081cb = [ "stm32-metapac/stm32g081cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
765stm32g081eb = [ "stm32-metapac/stm32g081eb" ] 767stm32g081eb = [ "stm32-metapac/stm32g081eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
766stm32g081gb = [ "stm32-metapac/stm32g081gb" ] 768stm32g081gb = [ "stm32-metapac/stm32g081gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
767stm32g081kb = [ "stm32-metapac/stm32g081kb" ] 769stm32g081kb = [ "stm32-metapac/stm32g081kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
768stm32g081rb = [ "stm32-metapac/stm32g081rb" ] 770stm32g081rb = [ "stm32-metapac/stm32g081rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
769stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce" ] 771stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
770stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke" ] 772stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
771stm32g0b0re = [ "stm32-metapac/stm32g0b0re" ] 773stm32g0b0re = [ "stm32-metapac/stm32g0b0re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
772stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve" ] 774stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
773stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb" ] 775stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
774stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc" ] 776stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
775stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce" ] 777stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
776stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb" ] 778stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
777stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc" ] 779stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
778stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke" ] 780stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
779stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb" ] 781stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
780stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc" ] 782stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
781stm32g0b1me = [ "stm32-metapac/stm32g0b1me" ] 783stm32g0b1me = [ "stm32-metapac/stm32g0b1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
782stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne" ] 784stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
783stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb" ] 785stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
784stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc" ] 786stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
785stm32g0b1re = [ "stm32-metapac/stm32g0b1re" ] 787stm32g0b1re = [ "stm32-metapac/stm32g0b1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
786stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb" ] 788stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
787stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc" ] 789stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
788stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve" ] 790stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
789stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc" ] 791stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
790stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce" ] 792stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
791stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc" ] 793stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
792stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke" ] 794stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
793stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc" ] 795stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
794stm32g0c1me = [ "stm32-metapac/stm32g0c1me" ] 796stm32g0c1me = [ "stm32-metapac/stm32g0c1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
795stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne" ] 797stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
796stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc" ] 798stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
797stm32g0c1re = [ "stm32-metapac/stm32g0c1re" ] 799stm32g0c1re = [ "stm32-metapac/stm32g0c1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
798stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc" ] 800stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
799stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve" ] 801stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
800stm32g431c6 = [ "stm32-metapac/stm32g431c6" ] 802stm32g431c6 = [ "stm32-metapac/stm32g431c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
801stm32g431c8 = [ "stm32-metapac/stm32g431c8" ] 803stm32g431c8 = [ "stm32-metapac/stm32g431c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
802stm32g431cb = [ "stm32-metapac/stm32g431cb" ] 804stm32g431cb = [ "stm32-metapac/stm32g431cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
803stm32g431k6 = [ "stm32-metapac/stm32g431k6" ] 805stm32g431k6 = [ "stm32-metapac/stm32g431k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
804stm32g431k8 = [ "stm32-metapac/stm32g431k8" ] 806stm32g431k8 = [ "stm32-metapac/stm32g431k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
805stm32g431kb = [ "stm32-metapac/stm32g431kb" ] 807stm32g431kb = [ "stm32-metapac/stm32g431kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
806stm32g431m6 = [ "stm32-metapac/stm32g431m6" ] 808stm32g431m6 = [ "stm32-metapac/stm32g431m6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
807stm32g431m8 = [ "stm32-metapac/stm32g431m8" ] 809stm32g431m8 = [ "stm32-metapac/stm32g431m8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
808stm32g431mb = [ "stm32-metapac/stm32g431mb" ] 810stm32g431mb = [ "stm32-metapac/stm32g431mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
809stm32g431r6 = [ "stm32-metapac/stm32g431r6" ] 811stm32g431r6 = [ "stm32-metapac/stm32g431r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
810stm32g431r8 = [ "stm32-metapac/stm32g431r8" ] 812stm32g431r8 = [ "stm32-metapac/stm32g431r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
811stm32g431rb = [ "stm32-metapac/stm32g431rb" ] 813stm32g431rb = [ "stm32-metapac/stm32g431rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
812stm32g431v6 = [ "stm32-metapac/stm32g431v6" ] 814stm32g431v6 = [ "stm32-metapac/stm32g431v6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
813stm32g431v8 = [ "stm32-metapac/stm32g431v8" ] 815stm32g431v8 = [ "stm32-metapac/stm32g431v8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
814stm32g431vb = [ "stm32-metapac/stm32g431vb" ] 816stm32g431vb = [ "stm32-metapac/stm32g431vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
815stm32g441cb = [ "stm32-metapac/stm32g441cb" ] 817stm32g441cb = [ "stm32-metapac/stm32g441cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
816stm32g441kb = [ "stm32-metapac/stm32g441kb" ] 818stm32g441kb = [ "stm32-metapac/stm32g441kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
817stm32g441mb = [ "stm32-metapac/stm32g441mb" ] 819stm32g441mb = [ "stm32-metapac/stm32g441mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
818stm32g441rb = [ "stm32-metapac/stm32g441rb" ] 820stm32g441rb = [ "stm32-metapac/stm32g441rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
819stm32g441vb = [ "stm32-metapac/stm32g441vb" ] 821stm32g441vb = [ "stm32-metapac/stm32g441vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
820stm32g471cc = [ "stm32-metapac/stm32g471cc" ] 822stm32g471cc = [ "stm32-metapac/stm32g471cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
821stm32g471ce = [ "stm32-metapac/stm32g471ce" ] 823stm32g471ce = [ "stm32-metapac/stm32g471ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
822stm32g471mc = [ "stm32-metapac/stm32g471mc" ] 824stm32g471mc = [ "stm32-metapac/stm32g471mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
823stm32g471me = [ "stm32-metapac/stm32g471me" ] 825stm32g471me = [ "stm32-metapac/stm32g471me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
824stm32g471qc = [ "stm32-metapac/stm32g471qc" ] 826stm32g471qc = [ "stm32-metapac/stm32g471qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
825stm32g471qe = [ "stm32-metapac/stm32g471qe" ] 827stm32g471qe = [ "stm32-metapac/stm32g471qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
826stm32g471rc = [ "stm32-metapac/stm32g471rc" ] 828stm32g471rc = [ "stm32-metapac/stm32g471rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
827stm32g471re = [ "stm32-metapac/stm32g471re" ] 829stm32g471re = [ "stm32-metapac/stm32g471re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
828stm32g471vc = [ "stm32-metapac/stm32g471vc" ] 830stm32g471vc = [ "stm32-metapac/stm32g471vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
829stm32g471ve = [ "stm32-metapac/stm32g471ve" ] 831stm32g471ve = [ "stm32-metapac/stm32g471ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
830stm32g473cb = [ "stm32-metapac/stm32g473cb" ] 832stm32g473cb = [ "stm32-metapac/stm32g473cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
831stm32g473cc = [ "stm32-metapac/stm32g473cc" ] 833stm32g473cc = [ "stm32-metapac/stm32g473cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
832stm32g473ce = [ "stm32-metapac/stm32g473ce" ] 834stm32g473ce = [ "stm32-metapac/stm32g473ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
833stm32g473mb = [ "stm32-metapac/stm32g473mb" ] 835stm32g473mb = [ "stm32-metapac/stm32g473mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
834stm32g473mc = [ "stm32-metapac/stm32g473mc" ] 836stm32g473mc = [ "stm32-metapac/stm32g473mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
835stm32g473me = [ "stm32-metapac/stm32g473me" ] 837stm32g473me = [ "stm32-metapac/stm32g473me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
836stm32g473pb = [ "stm32-metapac/stm32g473pb" ] 838stm32g473pb = [ "stm32-metapac/stm32g473pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
837stm32g473pc = [ "stm32-metapac/stm32g473pc" ] 839stm32g473pc = [ "stm32-metapac/stm32g473pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
838stm32g473pe = [ "stm32-metapac/stm32g473pe" ] 840stm32g473pe = [ "stm32-metapac/stm32g473pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
839stm32g473qb = [ "stm32-metapac/stm32g473qb" ] 841stm32g473qb = [ "stm32-metapac/stm32g473qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
840stm32g473qc = [ "stm32-metapac/stm32g473qc" ] 842stm32g473qc = [ "stm32-metapac/stm32g473qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
841stm32g473qe = [ "stm32-metapac/stm32g473qe" ] 843stm32g473qe = [ "stm32-metapac/stm32g473qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
842stm32g473rb = [ "stm32-metapac/stm32g473rb" ] 844stm32g473rb = [ "stm32-metapac/stm32g473rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
843stm32g473rc = [ "stm32-metapac/stm32g473rc" ] 845stm32g473rc = [ "stm32-metapac/stm32g473rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
844stm32g473re = [ "stm32-metapac/stm32g473re" ] 846stm32g473re = [ "stm32-metapac/stm32g473re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
845stm32g473vb = [ "stm32-metapac/stm32g473vb" ] 847stm32g473vb = [ "stm32-metapac/stm32g473vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
846stm32g473vc = [ "stm32-metapac/stm32g473vc" ] 848stm32g473vc = [ "stm32-metapac/stm32g473vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
847stm32g473ve = [ "stm32-metapac/stm32g473ve" ] 849stm32g473ve = [ "stm32-metapac/stm32g473ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
848stm32g474cb = [ "stm32-metapac/stm32g474cb" ] 850stm32g474cb = [ "stm32-metapac/stm32g474cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
849stm32g474cc = [ "stm32-metapac/stm32g474cc" ] 851stm32g474cc = [ "stm32-metapac/stm32g474cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
850stm32g474ce = [ "stm32-metapac/stm32g474ce" ] 852stm32g474ce = [ "stm32-metapac/stm32g474ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
851stm32g474mb = [ "stm32-metapac/stm32g474mb" ] 853stm32g474mb = [ "stm32-metapac/stm32g474mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
852stm32g474mc = [ "stm32-metapac/stm32g474mc" ] 854stm32g474mc = [ "stm32-metapac/stm32g474mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
853stm32g474me = [ "stm32-metapac/stm32g474me" ] 855stm32g474me = [ "stm32-metapac/stm32g474me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
854stm32g474pb = [ "stm32-metapac/stm32g474pb" ] 856stm32g474pb = [ "stm32-metapac/stm32g474pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
855stm32g474pc = [ "stm32-metapac/stm32g474pc" ] 857stm32g474pc = [ "stm32-metapac/stm32g474pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
856stm32g474pe = [ "stm32-metapac/stm32g474pe" ] 858stm32g474pe = [ "stm32-metapac/stm32g474pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
857stm32g474qb = [ "stm32-metapac/stm32g474qb" ] 859stm32g474qb = [ "stm32-metapac/stm32g474qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
858stm32g474qc = [ "stm32-metapac/stm32g474qc" ] 860stm32g474qc = [ "stm32-metapac/stm32g474qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
859stm32g474qe = [ "stm32-metapac/stm32g474qe" ] 861stm32g474qe = [ "stm32-metapac/stm32g474qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
860stm32g474rb = [ "stm32-metapac/stm32g474rb" ] 862stm32g474rb = [ "stm32-metapac/stm32g474rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
861stm32g474rc = [ "stm32-metapac/stm32g474rc" ] 863stm32g474rc = [ "stm32-metapac/stm32g474rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
862stm32g474re = [ "stm32-metapac/stm32g474re" ] 864stm32g474re = [ "stm32-metapac/stm32g474re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
863stm32g474vb = [ "stm32-metapac/stm32g474vb" ] 865stm32g474vb = [ "stm32-metapac/stm32g474vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
864stm32g474vc = [ "stm32-metapac/stm32g474vc" ] 866stm32g474vc = [ "stm32-metapac/stm32g474vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
865stm32g474ve = [ "stm32-metapac/stm32g474ve" ] 867stm32g474ve = [ "stm32-metapac/stm32g474ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
866stm32g483ce = [ "stm32-metapac/stm32g483ce" ] 868stm32g483ce = [ "stm32-metapac/stm32g483ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
867stm32g483me = [ "stm32-metapac/stm32g483me" ] 869stm32g483me = [ "stm32-metapac/stm32g483me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
868stm32g483pe = [ "stm32-metapac/stm32g483pe" ] 870stm32g483pe = [ "stm32-metapac/stm32g483pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
869stm32g483qe = [ "stm32-metapac/stm32g483qe" ] 871stm32g483qe = [ "stm32-metapac/stm32g483qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
870stm32g483re = [ "stm32-metapac/stm32g483re" ] 872stm32g483re = [ "stm32-metapac/stm32g483re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
871stm32g483ve = [ "stm32-metapac/stm32g483ve" ] 873stm32g483ve = [ "stm32-metapac/stm32g483ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
872stm32g484ce = [ "stm32-metapac/stm32g484ce" ] 874stm32g484ce = [ "stm32-metapac/stm32g484ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
873stm32g484me = [ "stm32-metapac/stm32g484me" ] 875stm32g484me = [ "stm32-metapac/stm32g484me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
874stm32g484pe = [ "stm32-metapac/stm32g484pe" ] 876stm32g484pe = [ "stm32-metapac/stm32g484pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
875stm32g484qe = [ "stm32-metapac/stm32g484qe" ] 877stm32g484qe = [ "stm32-metapac/stm32g484qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
876stm32g484re = [ "stm32-metapac/stm32g484re" ] 878stm32g484re = [ "stm32-metapac/stm32g484re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
877stm32g484ve = [ "stm32-metapac/stm32g484ve" ] 879stm32g484ve = [ "stm32-metapac/stm32g484ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
878stm32g491cc = [ "stm32-metapac/stm32g491cc" ] 880stm32g491cc = [ "stm32-metapac/stm32g491cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
879stm32g491ce = [ "stm32-metapac/stm32g491ce" ] 881stm32g491ce = [ "stm32-metapac/stm32g491ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
880stm32g491kc = [ "stm32-metapac/stm32g491kc" ] 882stm32g491kc = [ "stm32-metapac/stm32g491kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
881stm32g491ke = [ "stm32-metapac/stm32g491ke" ] 883stm32g491ke = [ "stm32-metapac/stm32g491ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
882stm32g491mc = [ "stm32-metapac/stm32g491mc" ] 884stm32g491mc = [ "stm32-metapac/stm32g491mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
883stm32g491me = [ "stm32-metapac/stm32g491me" ] 885stm32g491me = [ "stm32-metapac/stm32g491me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
884stm32g491rc = [ "stm32-metapac/stm32g491rc" ] 886stm32g491rc = [ "stm32-metapac/stm32g491rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
885stm32g491re = [ "stm32-metapac/stm32g491re" ] 887stm32g491re = [ "stm32-metapac/stm32g491re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
886stm32g491vc = [ "stm32-metapac/stm32g491vc" ] 888stm32g491vc = [ "stm32-metapac/stm32g491vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
887stm32g491ve = [ "stm32-metapac/stm32g491ve" ] 889stm32g491ve = [ "stm32-metapac/stm32g491ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
888stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce" ] 890stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
889stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ] 891stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
890stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] 892stm32g4a1me = [ "stm32-metapac/stm32g4a1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
891stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] 893stm32g4a1re = [ "stm32-metapac/stm32g4a1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
892stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] 894stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
893stm32h503cb = [ "stm32-metapac/stm32h503cb" ] 895stm32h503cb = [ "stm32-metapac/stm32h503cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
894stm32h503eb = [ "stm32-metapac/stm32h503eb" ] 896stm32h503eb = [ "stm32-metapac/stm32h503eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
895stm32h503kb = [ "stm32-metapac/stm32h503kb" ] 897stm32h503kb = [ "stm32-metapac/stm32h503kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
896stm32h503rb = [ "stm32-metapac/stm32h503rb" ] 898stm32h503rb = [ "stm32-metapac/stm32h503rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
897stm32h562ag = [ "stm32-metapac/stm32h562ag" ] 899stm32h562ag = [ "stm32-metapac/stm32h562ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
898stm32h562ai = [ "stm32-metapac/stm32h562ai" ] 900stm32h562ai = [ "stm32-metapac/stm32h562ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
899stm32h562ig = [ "stm32-metapac/stm32h562ig" ] 901stm32h562ig = [ "stm32-metapac/stm32h562ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
900stm32h562ii = [ "stm32-metapac/stm32h562ii" ] 902stm32h562ii = [ "stm32-metapac/stm32h562ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
901stm32h562rg = [ "stm32-metapac/stm32h562rg" ] 903stm32h562rg = [ "stm32-metapac/stm32h562rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
902stm32h562ri = [ "stm32-metapac/stm32h562ri" ] 904stm32h562ri = [ "stm32-metapac/stm32h562ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
903stm32h562vg = [ "stm32-metapac/stm32h562vg" ] 905stm32h562vg = [ "stm32-metapac/stm32h562vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
904stm32h562vi = [ "stm32-metapac/stm32h562vi" ] 906stm32h562vi = [ "stm32-metapac/stm32h562vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
905stm32h562zg = [ "stm32-metapac/stm32h562zg" ] 907stm32h562zg = [ "stm32-metapac/stm32h562zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
906stm32h562zi = [ "stm32-metapac/stm32h562zi" ] 908stm32h562zi = [ "stm32-metapac/stm32h562zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
907stm32h563ag = [ "stm32-metapac/stm32h563ag" ] 909stm32h563ag = [ "stm32-metapac/stm32h563ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
908stm32h563ai = [ "stm32-metapac/stm32h563ai" ] 910stm32h563ai = [ "stm32-metapac/stm32h563ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
909stm32h563ig = [ "stm32-metapac/stm32h563ig" ] 911stm32h563ig = [ "stm32-metapac/stm32h563ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
910stm32h563ii = [ "stm32-metapac/stm32h563ii" ] 912stm32h563ii = [ "stm32-metapac/stm32h563ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
911stm32h563mi = [ "stm32-metapac/stm32h563mi" ] 913stm32h563mi = [ "stm32-metapac/stm32h563mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
912stm32h563rg = [ "stm32-metapac/stm32h563rg" ] 914stm32h563rg = [ "stm32-metapac/stm32h563rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
913stm32h563ri = [ "stm32-metapac/stm32h563ri" ] 915stm32h563ri = [ "stm32-metapac/stm32h563ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
914stm32h563vg = [ "stm32-metapac/stm32h563vg" ] 916stm32h563vg = [ "stm32-metapac/stm32h563vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
915stm32h563vi = [ "stm32-metapac/stm32h563vi" ] 917stm32h563vi = [ "stm32-metapac/stm32h563vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
916stm32h563zg = [ "stm32-metapac/stm32h563zg" ] 918stm32h563zg = [ "stm32-metapac/stm32h563zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
917stm32h563zi = [ "stm32-metapac/stm32h563zi" ] 919stm32h563zi = [ "stm32-metapac/stm32h563zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
918stm32h573ai = [ "stm32-metapac/stm32h573ai" ] 920stm32h573ai = [ "stm32-metapac/stm32h573ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
919stm32h573ii = [ "stm32-metapac/stm32h573ii" ] 921stm32h573ii = [ "stm32-metapac/stm32h573ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
920stm32h573mi = [ "stm32-metapac/stm32h573mi" ] 922stm32h573mi = [ "stm32-metapac/stm32h573mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
921stm32h573ri = [ "stm32-metapac/stm32h573ri" ] 923stm32h573ri = [ "stm32-metapac/stm32h573ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
922stm32h573vi = [ "stm32-metapac/stm32h573vi" ] 924stm32h573vi = [ "stm32-metapac/stm32h573vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
923stm32h573zi = [ "stm32-metapac/stm32h573zi" ] 925stm32h573zi = [ "stm32-metapac/stm32h573zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
924stm32h723ve = [ "stm32-metapac/stm32h723ve" ] 926stm32h723ve = [ "stm32-metapac/stm32h723ve", "dep:fdcan", "fdcan/fdcan_h7" ]
925stm32h723vg = [ "stm32-metapac/stm32h723vg" ] 927stm32h723vg = [ "stm32-metapac/stm32h723vg", "dep:fdcan", "fdcan/fdcan_h7" ]
926stm32h723ze = [ "stm32-metapac/stm32h723ze" ] 928stm32h723ze = [ "stm32-metapac/stm32h723ze", "dep:fdcan", "fdcan/fdcan_h7" ]
927stm32h723zg = [ "stm32-metapac/stm32h723zg" ] 929stm32h723zg = [ "stm32-metapac/stm32h723zg", "dep:fdcan", "fdcan/fdcan_h7" ]
928stm32h725ae = [ "stm32-metapac/stm32h725ae" ] 930stm32h725ae = [ "stm32-metapac/stm32h725ae", "dep:fdcan", "fdcan/fdcan_h7" ]
929stm32h725ag = [ "stm32-metapac/stm32h725ag" ] 931stm32h725ag = [ "stm32-metapac/stm32h725ag", "dep:fdcan", "fdcan/fdcan_h7" ]
930stm32h725ie = [ "stm32-metapac/stm32h725ie" ] 932stm32h725ie = [ "stm32-metapac/stm32h725ie", "dep:fdcan", "fdcan/fdcan_h7" ]
931stm32h725ig = [ "stm32-metapac/stm32h725ig" ] 933stm32h725ig = [ "stm32-metapac/stm32h725ig", "dep:fdcan", "fdcan/fdcan_h7" ]
932stm32h725re = [ "stm32-metapac/stm32h725re" ] 934stm32h725re = [ "stm32-metapac/stm32h725re", "dep:fdcan", "fdcan/fdcan_h7" ]
933stm32h725rg = [ "stm32-metapac/stm32h725rg" ] 935stm32h725rg = [ "stm32-metapac/stm32h725rg", "dep:fdcan", "fdcan/fdcan_h7" ]
934stm32h725ve = [ "stm32-metapac/stm32h725ve" ] 936stm32h725ve = [ "stm32-metapac/stm32h725ve", "dep:fdcan", "fdcan/fdcan_h7" ]
935stm32h725vg = [ "stm32-metapac/stm32h725vg" ] 937stm32h725vg = [ "stm32-metapac/stm32h725vg", "dep:fdcan", "fdcan/fdcan_h7" ]
936stm32h725ze = [ "stm32-metapac/stm32h725ze" ] 938stm32h725ze = [ "stm32-metapac/stm32h725ze", "dep:fdcan", "fdcan/fdcan_h7" ]
937stm32h725zg = [ "stm32-metapac/stm32h725zg" ] 939stm32h725zg = [ "stm32-metapac/stm32h725zg", "dep:fdcan", "fdcan/fdcan_h7" ]
938stm32h730ab = [ "stm32-metapac/stm32h730ab" ] 940stm32h730ab = [ "stm32-metapac/stm32h730ab", "dep:fdcan", "fdcan/fdcan_h7" ]
939stm32h730ib = [ "stm32-metapac/stm32h730ib" ] 941stm32h730ib = [ "stm32-metapac/stm32h730ib", "dep:fdcan", "fdcan/fdcan_h7" ]
940stm32h730vb = [ "stm32-metapac/stm32h730vb" ] 942stm32h730vb = [ "stm32-metapac/stm32h730vb", "dep:fdcan", "fdcan/fdcan_h7" ]
941stm32h730zb = [ "stm32-metapac/stm32h730zb" ] 943stm32h730zb = [ "stm32-metapac/stm32h730zb", "dep:fdcan", "fdcan/fdcan_h7" ]
942stm32h733vg = [ "stm32-metapac/stm32h733vg" ] 944stm32h733vg = [ "stm32-metapac/stm32h733vg", "dep:fdcan", "fdcan/fdcan_h7" ]
943stm32h733zg = [ "stm32-metapac/stm32h733zg" ] 945stm32h733zg = [ "stm32-metapac/stm32h733zg", "dep:fdcan", "fdcan/fdcan_h7" ]
944stm32h735ag = [ "stm32-metapac/stm32h735ag" ] 946stm32h735ag = [ "stm32-metapac/stm32h735ag", "dep:fdcan", "fdcan/fdcan_h7" ]
945stm32h735ig = [ "stm32-metapac/stm32h735ig" ] 947stm32h735ig = [ "stm32-metapac/stm32h735ig", "dep:fdcan", "fdcan/fdcan_h7" ]
946stm32h735rg = [ "stm32-metapac/stm32h735rg" ] 948stm32h735rg = [ "stm32-metapac/stm32h735rg", "dep:fdcan", "fdcan/fdcan_h7" ]
947stm32h735vg = [ "stm32-metapac/stm32h735vg" ] 949stm32h735vg = [ "stm32-metapac/stm32h735vg", "dep:fdcan", "fdcan/fdcan_h7" ]
948stm32h735zg = [ "stm32-metapac/stm32h735zg" ] 950stm32h735zg = [ "stm32-metapac/stm32h735zg", "dep:fdcan", "fdcan/fdcan_h7" ]
949stm32h742ag = [ "stm32-metapac/stm32h742ag" ] 951stm32h742ag = [ "stm32-metapac/stm32h742ag", "dep:fdcan", "fdcan/fdcan_h7" ]
950stm32h742ai = [ "stm32-metapac/stm32h742ai" ] 952stm32h742ai = [ "stm32-metapac/stm32h742ai", "dep:fdcan", "fdcan/fdcan_h7" ]
951stm32h742bg = [ "stm32-metapac/stm32h742bg" ] 953stm32h742bg = [ "stm32-metapac/stm32h742bg", "dep:fdcan", "fdcan/fdcan_h7" ]
952stm32h742bi = [ "stm32-metapac/stm32h742bi" ] 954stm32h742bi = [ "stm32-metapac/stm32h742bi", "dep:fdcan", "fdcan/fdcan_h7" ]
953stm32h742ig = [ "stm32-metapac/stm32h742ig" ] 955stm32h742ig = [ "stm32-metapac/stm32h742ig", "dep:fdcan", "fdcan/fdcan_h7" ]
954stm32h742ii = [ "stm32-metapac/stm32h742ii" ] 956stm32h742ii = [ "stm32-metapac/stm32h742ii", "dep:fdcan", "fdcan/fdcan_h7" ]
955stm32h742vg = [ "stm32-metapac/stm32h742vg" ] 957stm32h742vg = [ "stm32-metapac/stm32h742vg", "dep:fdcan", "fdcan/fdcan_h7" ]
956stm32h742vi = [ "stm32-metapac/stm32h742vi" ] 958stm32h742vi = [ "stm32-metapac/stm32h742vi", "dep:fdcan", "fdcan/fdcan_h7" ]
957stm32h742xg = [ "stm32-metapac/stm32h742xg" ] 959stm32h742xg = [ "stm32-metapac/stm32h742xg", "dep:fdcan", "fdcan/fdcan_h7" ]
958stm32h742xi = [ "stm32-metapac/stm32h742xi" ] 960stm32h742xi = [ "stm32-metapac/stm32h742xi", "dep:fdcan", "fdcan/fdcan_h7" ]
959stm32h742zg = [ "stm32-metapac/stm32h742zg" ] 961stm32h742zg = [ "stm32-metapac/stm32h742zg", "dep:fdcan", "fdcan/fdcan_h7" ]
960stm32h742zi = [ "stm32-metapac/stm32h742zi" ] 962stm32h742zi = [ "stm32-metapac/stm32h742zi", "dep:fdcan", "fdcan/fdcan_h7" ]
961stm32h743ag = [ "stm32-metapac/stm32h743ag" ] 963stm32h743ag = [ "stm32-metapac/stm32h743ag", "dep:fdcan", "fdcan/fdcan_h7" ]
962stm32h743ai = [ "stm32-metapac/stm32h743ai" ] 964stm32h743ai = [ "stm32-metapac/stm32h743ai", "dep:fdcan", "fdcan/fdcan_h7" ]
963stm32h743bg = [ "stm32-metapac/stm32h743bg" ] 965stm32h743bg = [ "stm32-metapac/stm32h743bg", "dep:fdcan", "fdcan/fdcan_h7" ]
964stm32h743bi = [ "stm32-metapac/stm32h743bi" ] 966stm32h743bi = [ "stm32-metapac/stm32h743bi", "dep:fdcan", "fdcan/fdcan_h7" ]
965stm32h743ig = [ "stm32-metapac/stm32h743ig" ] 967stm32h743ig = [ "stm32-metapac/stm32h743ig", "dep:fdcan", "fdcan/fdcan_h7" ]
966stm32h743ii = [ "stm32-metapac/stm32h743ii" ] 968stm32h743ii = [ "stm32-metapac/stm32h743ii", "dep:fdcan", "fdcan/fdcan_h7" ]
967stm32h743vg = [ "stm32-metapac/stm32h743vg" ] 969stm32h743vg = [ "stm32-metapac/stm32h743vg", "dep:fdcan", "fdcan/fdcan_h7" ]
968stm32h743vi = [ "stm32-metapac/stm32h743vi" ] 970stm32h743vi = [ "stm32-metapac/stm32h743vi", "dep:fdcan", "fdcan/fdcan_h7" ]
969stm32h743xg = [ "stm32-metapac/stm32h743xg" ] 971stm32h743xg = [ "stm32-metapac/stm32h743xg", "dep:fdcan", "fdcan/fdcan_h7" ]
970stm32h743xi = [ "stm32-metapac/stm32h743xi" ] 972stm32h743xi = [ "stm32-metapac/stm32h743xi", "dep:fdcan", "fdcan/fdcan_h7" ]
971stm32h743zg = [ "stm32-metapac/stm32h743zg" ] 973stm32h743zg = [ "stm32-metapac/stm32h743zg", "dep:fdcan", "fdcan/fdcan_h7" ]
972stm32h743zi = [ "stm32-metapac/stm32h743zi" ] 974stm32h743zi = [ "stm32-metapac/stm32h743zi", "dep:fdcan", "fdcan/fdcan_h7" ]
973stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ] 975stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
974stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ] 976stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
975stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ] 977stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
976stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ] 978stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
977stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ] 979stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
978stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ] 980stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
979stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ] 981stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
980stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ] 982stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
981stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ] 983stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
982stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ] 984stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
983stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ] 985stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
984stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ] 986stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
985stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ] 987stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
986stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ] 988stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
987stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ] 989stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
988stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ] 990stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
989stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ] 991stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
990stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ] 992stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
991stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ] 993stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
992stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ] 994stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
993stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ] 995stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
994stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ] 996stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
995stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ] 997stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
996stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ] 998stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
997stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ] 999stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
998stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ] 1000stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
999stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ] 1001stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1000stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ] 1002stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1001stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ] 1003stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1002stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ] 1004stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1003stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ] 1005stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1004stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ] 1006stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1005stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ] 1007stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1006stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ] 1008stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1007stm32h750ib = [ "stm32-metapac/stm32h750ib" ] 1009stm32h750ib = [ "stm32-metapac/stm32h750ib", "dep:fdcan", "fdcan/fdcan_h7" ]
1008stm32h750vb = [ "stm32-metapac/stm32h750vb" ] 1010stm32h750vb = [ "stm32-metapac/stm32h750vb", "dep:fdcan", "fdcan/fdcan_h7" ]
1009stm32h750xb = [ "stm32-metapac/stm32h750xb" ] 1011stm32h750xb = [ "stm32-metapac/stm32h750xb", "dep:fdcan", "fdcan/fdcan_h7" ]
1010stm32h750zb = [ "stm32-metapac/stm32h750zb" ] 1012stm32h750zb = [ "stm32-metapac/stm32h750zb", "dep:fdcan", "fdcan/fdcan_h7" ]
1011stm32h753ai = [ "stm32-metapac/stm32h753ai" ] 1013stm32h753ai = [ "stm32-metapac/stm32h753ai", "dep:fdcan", "fdcan/fdcan_h7" ]
1012stm32h753bi = [ "stm32-metapac/stm32h753bi" ] 1014stm32h753bi = [ "stm32-metapac/stm32h753bi", "dep:fdcan", "fdcan/fdcan_h7" ]
1013stm32h753ii = [ "stm32-metapac/stm32h753ii" ] 1015stm32h753ii = [ "stm32-metapac/stm32h753ii", "dep:fdcan", "fdcan/fdcan_h7" ]
1014stm32h753vi = [ "stm32-metapac/stm32h753vi" ] 1016stm32h753vi = [ "stm32-metapac/stm32h753vi", "dep:fdcan", "fdcan/fdcan_h7" ]
1015stm32h753xi = [ "stm32-metapac/stm32h753xi" ] 1017stm32h753xi = [ "stm32-metapac/stm32h753xi", "dep:fdcan", "fdcan/fdcan_h7" ]
1016stm32h753zi = [ "stm32-metapac/stm32h753zi" ] 1018stm32h753zi = [ "stm32-metapac/stm32h753zi", "dep:fdcan", "fdcan/fdcan_h7" ]
1017stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ] 1019stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1018stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ] 1020stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1019stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ] 1021stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1020stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ] 1022stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1021stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ] 1023stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1022stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ] 1024stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1023stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ] 1025stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1024stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ] 1026stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1025stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ] 1027stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1026stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ] 1028stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1027stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ] 1029stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1028stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ] 1030stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1029stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ] 1031stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1030stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ] 1032stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1031stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ] 1033stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1032stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ] 1034stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1033stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ] 1035stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
1034stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ] 1036stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
1035stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] 1037stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag", "dep:fdcan", "fdcan/fdcan_h7" ]
1036stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] 1038stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai", "dep:fdcan", "fdcan/fdcan_h7" ]
1037stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] 1039stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig", "dep:fdcan", "fdcan/fdcan_h7" ]
1038stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii" ] 1040stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii", "dep:fdcan", "fdcan/fdcan_h7" ]
1039stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg" ] 1041stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg", "dep:fdcan", "fdcan/fdcan_h7" ]
1040stm32h7a3li = [ "stm32-metapac/stm32h7a3li" ] 1042stm32h7a3li = [ "stm32-metapac/stm32h7a3li", "dep:fdcan", "fdcan/fdcan_h7" ]
1041stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng" ] 1043stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng", "dep:fdcan", "fdcan/fdcan_h7" ]
1042stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni" ] 1044stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni", "dep:fdcan", "fdcan/fdcan_h7" ]
1043stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi" ] 1045stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi", "dep:fdcan", "fdcan/fdcan_h7" ]
1044stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg" ] 1046stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg", "dep:fdcan", "fdcan/fdcan_h7" ]
1045stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri" ] 1047stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri", "dep:fdcan", "fdcan/fdcan_h7" ]
1046stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg" ] 1048stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg", "dep:fdcan", "fdcan/fdcan_h7" ]
1047stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi" ] 1049stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi", "dep:fdcan", "fdcan/fdcan_h7" ]
1048stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg" ] 1050stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg", "dep:fdcan", "fdcan/fdcan_h7" ]
1049stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi" ] 1051stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi", "dep:fdcan", "fdcan/fdcan_h7" ]
1050stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab" ] 1052stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab", "dep:fdcan", "fdcan/fdcan_h7" ]
1051stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib" ] 1053stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib", "dep:fdcan", "fdcan/fdcan_h7" ]
1052stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb" ] 1054stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb", "dep:fdcan", "fdcan/fdcan_h7" ]
1053stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb" ] 1055stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb", "dep:fdcan", "fdcan/fdcan_h7" ]
1054stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb" ] 1056stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb", "dep:fdcan", "fdcan/fdcan_h7" ]
1055stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai" ] 1057stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai", "dep:fdcan", "fdcan/fdcan_h7" ]
1056stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii" ] 1058stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii", "dep:fdcan", "fdcan/fdcan_h7" ]
1057stm32h7b3li = [ "stm32-metapac/stm32h7b3li" ] 1059stm32h7b3li = [ "stm32-metapac/stm32h7b3li", "dep:fdcan", "fdcan/fdcan_h7" ]
1058stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni" ] 1060stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni", "dep:fdcan", "fdcan/fdcan_h7" ]
1059stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ] 1061stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi", "dep:fdcan", "fdcan/fdcan_h7" ]
1060stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ] 1062stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri", "dep:fdcan", "fdcan/fdcan_h7" ]
1061stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ] 1063stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi", "dep:fdcan", "fdcan/fdcan_h7" ]
1062stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ] 1064stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi", "dep:fdcan", "fdcan/fdcan_h7" ]
1063stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] 1065stm32l010c6 = [ "stm32-metapac/stm32l010c6" ]
1064stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] 1066stm32l010f4 = [ "stm32-metapac/stm32l010f4" ]
1065stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] 1067stm32l010k4 = [ "stm32-metapac/stm32l010k4" ]
@@ -1386,86 +1388,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ]
1386stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] 1388stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ]
1387stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] 1389stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ]
1388stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] 1390stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ]
1389stm32l552cc = [ "stm32-metapac/stm32l552cc" ] 1391stm32l552cc = [ "stm32-metapac/stm32l552cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1390stm32l552ce = [ "stm32-metapac/stm32l552ce" ] 1392stm32l552ce = [ "stm32-metapac/stm32l552ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1391stm32l552me = [ "stm32-metapac/stm32l552me" ] 1393stm32l552me = [ "stm32-metapac/stm32l552me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1392stm32l552qc = [ "stm32-metapac/stm32l552qc" ] 1394stm32l552qc = [ "stm32-metapac/stm32l552qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1393stm32l552qe = [ "stm32-metapac/stm32l552qe" ] 1395stm32l552qe = [ "stm32-metapac/stm32l552qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1394stm32l552rc = [ "stm32-metapac/stm32l552rc" ] 1396stm32l552rc = [ "stm32-metapac/stm32l552rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1395stm32l552re = [ "stm32-metapac/stm32l552re" ] 1397stm32l552re = [ "stm32-metapac/stm32l552re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1396stm32l552vc = [ "stm32-metapac/stm32l552vc" ] 1398stm32l552vc = [ "stm32-metapac/stm32l552vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1397stm32l552ve = [ "stm32-metapac/stm32l552ve" ] 1399stm32l552ve = [ "stm32-metapac/stm32l552ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1398stm32l552zc = [ "stm32-metapac/stm32l552zc" ] 1400stm32l552zc = [ "stm32-metapac/stm32l552zc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1399stm32l552ze = [ "stm32-metapac/stm32l552ze" ] 1401stm32l552ze = [ "stm32-metapac/stm32l552ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1400stm32l562ce = [ "stm32-metapac/stm32l562ce" ] 1402stm32l562ce = [ "stm32-metapac/stm32l562ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1401stm32l562me = [ "stm32-metapac/stm32l562me" ] 1403stm32l562me = [ "stm32-metapac/stm32l562me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1402stm32l562qe = [ "stm32-metapac/stm32l562qe" ] 1404stm32l562qe = [ "stm32-metapac/stm32l562qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1403stm32l562re = [ "stm32-metapac/stm32l562re" ] 1405stm32l562re = [ "stm32-metapac/stm32l562re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1404stm32l562ve = [ "stm32-metapac/stm32l562ve" ] 1406stm32l562ve = [ "stm32-metapac/stm32l562ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1405stm32l562ze = [ "stm32-metapac/stm32l562ze" ] 1407stm32l562ze = [ "stm32-metapac/stm32l562ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1406stm32u535cb = [ "stm32-metapac/stm32u535cb" ] 1408stm32u535cb = [ "stm32-metapac/stm32u535cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1407stm32u535cc = [ "stm32-metapac/stm32u535cc" ] 1409stm32u535cc = [ "stm32-metapac/stm32u535cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1408stm32u535ce = [ "stm32-metapac/stm32u535ce" ] 1410stm32u535ce = [ "stm32-metapac/stm32u535ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1409stm32u535je = [ "stm32-metapac/stm32u535je" ] 1411stm32u535je = [ "stm32-metapac/stm32u535je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1410stm32u535nc = [ "stm32-metapac/stm32u535nc" ] 1412stm32u535nc = [ "stm32-metapac/stm32u535nc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1411stm32u535ne = [ "stm32-metapac/stm32u535ne" ] 1413stm32u535ne = [ "stm32-metapac/stm32u535ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1412stm32u535rb = [ "stm32-metapac/stm32u535rb" ] 1414stm32u535rb = [ "stm32-metapac/stm32u535rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1413stm32u535rc = [ "stm32-metapac/stm32u535rc" ] 1415stm32u535rc = [ "stm32-metapac/stm32u535rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1414stm32u535re = [ "stm32-metapac/stm32u535re" ] 1416stm32u535re = [ "stm32-metapac/stm32u535re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1415stm32u535vc = [ "stm32-metapac/stm32u535vc" ] 1417stm32u535vc = [ "stm32-metapac/stm32u535vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1416stm32u535ve = [ "stm32-metapac/stm32u535ve" ] 1418stm32u535ve = [ "stm32-metapac/stm32u535ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1417stm32u545ce = [ "stm32-metapac/stm32u545ce" ] 1419stm32u545ce = [ "stm32-metapac/stm32u545ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1418stm32u545je = [ "stm32-metapac/stm32u545je" ] 1420stm32u545je = [ "stm32-metapac/stm32u545je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1419stm32u545ne = [ "stm32-metapac/stm32u545ne" ] 1421stm32u545ne = [ "stm32-metapac/stm32u545ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1420stm32u545re = [ "stm32-metapac/stm32u545re" ] 1422stm32u545re = [ "stm32-metapac/stm32u545re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1421stm32u545ve = [ "stm32-metapac/stm32u545ve" ] 1423stm32u545ve = [ "stm32-metapac/stm32u545ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1422stm32u575ag = [ "stm32-metapac/stm32u575ag" ] 1424stm32u575ag = [ "stm32-metapac/stm32u575ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1423stm32u575ai = [ "stm32-metapac/stm32u575ai" ] 1425stm32u575ai = [ "stm32-metapac/stm32u575ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1424stm32u575cg = [ "stm32-metapac/stm32u575cg" ] 1426stm32u575cg = [ "stm32-metapac/stm32u575cg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1425stm32u575ci = [ "stm32-metapac/stm32u575ci" ] 1427stm32u575ci = [ "stm32-metapac/stm32u575ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1426stm32u575og = [ "stm32-metapac/stm32u575og" ] 1428stm32u575og = [ "stm32-metapac/stm32u575og", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1427stm32u575oi = [ "stm32-metapac/stm32u575oi" ] 1429stm32u575oi = [ "stm32-metapac/stm32u575oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1428stm32u575qg = [ "stm32-metapac/stm32u575qg" ] 1430stm32u575qg = [ "stm32-metapac/stm32u575qg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1429stm32u575qi = [ "stm32-metapac/stm32u575qi" ] 1431stm32u575qi = [ "stm32-metapac/stm32u575qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1430stm32u575rg = [ "stm32-metapac/stm32u575rg" ] 1432stm32u575rg = [ "stm32-metapac/stm32u575rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1431stm32u575ri = [ "stm32-metapac/stm32u575ri" ] 1433stm32u575ri = [ "stm32-metapac/stm32u575ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1432stm32u575vg = [ "stm32-metapac/stm32u575vg" ] 1434stm32u575vg = [ "stm32-metapac/stm32u575vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1433stm32u575vi = [ "stm32-metapac/stm32u575vi" ] 1435stm32u575vi = [ "stm32-metapac/stm32u575vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1434stm32u575zg = [ "stm32-metapac/stm32u575zg" ] 1436stm32u575zg = [ "stm32-metapac/stm32u575zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1435stm32u575zi = [ "stm32-metapac/stm32u575zi" ] 1437stm32u575zi = [ "stm32-metapac/stm32u575zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1436stm32u585ai = [ "stm32-metapac/stm32u585ai" ] 1438stm32u585ai = [ "stm32-metapac/stm32u585ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1437stm32u585ci = [ "stm32-metapac/stm32u585ci" ] 1439stm32u585ci = [ "stm32-metapac/stm32u585ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1438stm32u585oi = [ "stm32-metapac/stm32u585oi" ] 1440stm32u585oi = [ "stm32-metapac/stm32u585oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1439stm32u585qi = [ "stm32-metapac/stm32u585qi" ] 1441stm32u585qi = [ "stm32-metapac/stm32u585qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1440stm32u585ri = [ "stm32-metapac/stm32u585ri" ] 1442stm32u585ri = [ "stm32-metapac/stm32u585ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1441stm32u585vi = [ "stm32-metapac/stm32u585vi" ] 1443stm32u585vi = [ "stm32-metapac/stm32u585vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1442stm32u585zi = [ "stm32-metapac/stm32u585zi" ] 1444stm32u585zi = [ "stm32-metapac/stm32u585zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1443stm32u595ai = [ "stm32-metapac/stm32u595ai" ] 1445stm32u595ai = [ "stm32-metapac/stm32u595ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1444stm32u595aj = [ "stm32-metapac/stm32u595aj" ] 1446stm32u595aj = [ "stm32-metapac/stm32u595aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1445stm32u595qi = [ "stm32-metapac/stm32u595qi" ] 1447stm32u595qi = [ "stm32-metapac/stm32u595qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1446stm32u595qj = [ "stm32-metapac/stm32u595qj" ] 1448stm32u595qj = [ "stm32-metapac/stm32u595qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1447stm32u595ri = [ "stm32-metapac/stm32u595ri" ] 1449stm32u595ri = [ "stm32-metapac/stm32u595ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1448stm32u595rj = [ "stm32-metapac/stm32u595rj" ] 1450stm32u595rj = [ "stm32-metapac/stm32u595rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1449stm32u595vi = [ "stm32-metapac/stm32u595vi" ] 1451stm32u595vi = [ "stm32-metapac/stm32u595vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1450stm32u595vj = [ "stm32-metapac/stm32u595vj" ] 1452stm32u595vj = [ "stm32-metapac/stm32u595vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1451stm32u595zi = [ "stm32-metapac/stm32u595zi" ] 1453stm32u595zi = [ "stm32-metapac/stm32u595zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1452stm32u595zj = [ "stm32-metapac/stm32u595zj" ] 1454stm32u595zj = [ "stm32-metapac/stm32u595zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1453stm32u599bj = [ "stm32-metapac/stm32u599bj" ] 1455stm32u599bj = [ "stm32-metapac/stm32u599bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1454stm32u599ni = [ "stm32-metapac/stm32u599ni" ] 1456stm32u599ni = [ "stm32-metapac/stm32u599ni", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1455stm32u599nj = [ "stm32-metapac/stm32u599nj" ] 1457stm32u599nj = [ "stm32-metapac/stm32u599nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1456stm32u599vi = [ "stm32-metapac/stm32u599vi" ] 1458stm32u599vi = [ "stm32-metapac/stm32u599vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1457stm32u599vj = [ "stm32-metapac/stm32u599vj" ] 1459stm32u599vj = [ "stm32-metapac/stm32u599vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1458stm32u599zi = [ "stm32-metapac/stm32u599zi" ] 1460stm32u599zi = [ "stm32-metapac/stm32u599zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1459stm32u599zj = [ "stm32-metapac/stm32u599zj" ] 1461stm32u599zj = [ "stm32-metapac/stm32u599zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1460stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] 1462stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1461stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] 1463stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1462stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] 1464stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1463stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] 1465stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1464stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ] 1466stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1465stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ] 1467stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1466stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ] 1468stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1467stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ] 1469stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1468stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ] 1470stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
1469stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] 1471stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ]
1470stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] 1472stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ]
1471stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] 1473stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 1a68dfc9d..35023bf1f 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -449,9 +449,20 @@ fn main() {
449 // ======== 449 // ========
450 // Generate RccPeripheral impls 450 // Generate RccPeripheral impls
451 451
452 let refcounted_peripherals = HashSet::from(["usart", "adc"]); 452 // count how many times each xxENR field is used, to enable refcounting if used more than once.
453 let mut rcc_field_count: HashMap<_, usize> = HashMap::new();
454 for p in METADATA.peripherals {
455 if let Some(rcc) = &p.rcc {
456 let en = rcc.enable.as_ref().unwrap();
457 *rcc_field_count.entry((en.register, en.field)).or_insert(0) += 1;
458 }
459 }
460
461 let force_refcount = HashSet::from(["usart"]);
453 let mut refcount_statics = BTreeSet::new(); 462 let mut refcount_statics = BTreeSet::new();
454 463
464 let mut clock_names = BTreeSet::new();
465
455 for p in METADATA.peripherals { 466 for p in METADATA.peripherals {
456 if !singletons.contains(&p.name.to_string()) { 467 if !singletons.contains(&p.name.to_string()) {
457 continue; 468 continue;
@@ -483,11 +494,12 @@ fn main() {
483 494
484 let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; 495 let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
485 let pname = format_ident!("{}", p.name); 496 let pname = format_ident!("{}", p.name);
486 let clk = format_ident!("{}", rcc.clock);
487 let en_reg = format_ident!("{}", en.register); 497 let en_reg = format_ident!("{}", en.register);
488 let set_en_field = format_ident!("set_{}", en.field); 498 let set_en_field = format_ident!("set_{}", en.field);
489 499
490 let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) { 500 let refcount =
501 force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
502 let (before_enable, before_disable) = if refcount {
491 let refcount_static = 503 let refcount_static =
492 format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); 504 format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
493 505
@@ -511,14 +523,7 @@ fn main() {
511 (TokenStream::new(), TokenStream::new()) 523 (TokenStream::new(), TokenStream::new())
512 }; 524 };
513 525
514 let mux_supported = HashSet::from(["c0", "h5", "h50", "h7", "h7ab", "h7rm0433", "g0", "g4", "l4"])
515 .contains(rcc_registers.version);
516 let mux_for = |mux: Option<&'static PeripheralRccRegister>| { 526 let mux_for = |mux: Option<&'static PeripheralRccRegister>| {
517 // restrict mux implementation to supported versions
518 if !mux_supported {
519 return None;
520 }
521
522 let mux = mux?; 527 let mux = mux?;
523 let fieldset = rcc_enum_map.get(mux.register)?; 528 let fieldset = rcc_enum_map.get(mux.register)?;
524 let enumm = fieldset.get(mux.field)?; 529 let enumm = fieldset.get(mux.field)?;
@@ -539,15 +544,9 @@ fn main() {
539 .map(|v| { 544 .map(|v| {
540 let variant_name = format_ident!("{}", v.name); 545 let variant_name = format_ident!("{}", v.name);
541 let clock_name = format_ident!("{}", v.name.to_ascii_lowercase()); 546 let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
542 547 clock_names.insert(v.name.to_ascii_lowercase());
543 if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" { 548 quote! {
544 quote! { 549 #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
545 #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name },
546 }
547 } else {
548 quote! {
549 #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
550 }
551 } 550 }
552 }) 551 })
553 .collect(); 552 .collect();
@@ -558,19 +557,21 @@ fn main() {
558 #[allow(unreachable_patterns)] 557 #[allow(unreachable_patterns)]
559 match crate::pac::RCC.#fieldset_name().read().#field_name() { 558 match crate::pac::RCC.#fieldset_name().read().#field_name() {
560 #match_arms 559 #match_arms
561
562 _ => unreachable!(), 560 _ => unreachable!(),
563 } 561 }
564 } 562 }
565 } 563 }
566 None => quote! { 564 None => {
567 unsafe { crate::rcc::get_freqs().#clk } 565 let clock_name = format_ident!("{}", rcc.clock);
568 }, 566 clock_names.insert(rcc.clock.to_string());
567 quote! {
568 unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }
569 }
570 }
569 }; 571 };
570 572
571 /* 573 /*
572 A refcount leak can result if the same field is shared by peripherals with different stop modes 574 A refcount leak can result if the same field is shared by peripherals with different stop modes
573
574 This condition should be checked in stm32-data 575 This condition should be checked in stm32-data
575 */ 576 */
576 let stop_refcount = match rcc.stop_mode { 577 let stop_refcount = match rcc.stop_mode {
@@ -617,6 +618,39 @@ fn main() {
617 } 618 }
618 } 619 }
619 620
621 // Generate RCC
622 clock_names.insert("sys".to_string());
623 clock_names.insert("rtc".to_string());
624 let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect();
625 g.extend(quote! {
626 #[derive(Clone, Copy, Debug)]
627 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
628 pub struct Clocks {
629 #(
630 pub #clock_idents: Option<crate::time::Hertz>,
631 )*
632 }
633 });
634
635 let clocks_macro = quote!(
636 macro_rules! set_clocks {
637 ($($(#[$m:meta])* $k:ident: $v:expr,)*) => {
638 {
639 #[allow(unused)]
640 struct Temp {
641 $($(#[$m])* $k: Option<crate::time::Hertz>,)*
642 }
643 let all = Temp {
644 $($(#[$m])* $k: $v,)*
645 };
646 crate::rcc::set_freqs(crate::rcc::Clocks {
647 #( #clock_idents: all.#clock_idents, )*
648 });
649 }
650 };
651 }
652 );
653
620 let refcount_mod: TokenStream = refcount_statics 654 let refcount_mod: TokenStream = refcount_statics
621 .iter() 655 .iter()
622 .map(|refcount_static| { 656 .map(|refcount_static| {
@@ -735,13 +769,20 @@ fn main() {
735 (("can", "TX"), quote!(crate::can::TxPin)), 769 (("can", "TX"), quote!(crate::can::TxPin)),
736 (("can", "RX"), quote!(crate::can::RxPin)), 770 (("can", "RX"), quote!(crate::can::RxPin)),
737 (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), 771 (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)),
772 (("eth", "RX_CLK"), quote!(crate::eth::RXClkPin)),
773 (("eth", "TX_CLK"), quote!(crate::eth::TXClkPin)),
738 (("eth", "MDIO"), quote!(crate::eth::MDIOPin)), 774 (("eth", "MDIO"), quote!(crate::eth::MDIOPin)),
739 (("eth", "MDC"), quote!(crate::eth::MDCPin)), 775 (("eth", "MDC"), quote!(crate::eth::MDCPin)),
740 (("eth", "CRS_DV"), quote!(crate::eth::CRSPin)), 776 (("eth", "CRS_DV"), quote!(crate::eth::CRSPin)),
777 (("eth", "RX_DV"), quote!(crate::eth::RXDVPin)),
741 (("eth", "RXD0"), quote!(crate::eth::RXD0Pin)), 778 (("eth", "RXD0"), quote!(crate::eth::RXD0Pin)),
742 (("eth", "RXD1"), quote!(crate::eth::RXD1Pin)), 779 (("eth", "RXD1"), quote!(crate::eth::RXD1Pin)),
780 (("eth", "RXD2"), quote!(crate::eth::RXD2Pin)),
781 (("eth", "RXD3"), quote!(crate::eth::RXD3Pin)),
743 (("eth", "TXD0"), quote!(crate::eth::TXD0Pin)), 782 (("eth", "TXD0"), quote!(crate::eth::TXD0Pin)),
744 (("eth", "TXD1"), quote!(crate::eth::TXD1Pin)), 783 (("eth", "TXD1"), quote!(crate::eth::TXD1Pin)),
784 (("eth", "TXD2"), quote!(crate::eth::TXD2Pin)),
785 (("eth", "TXD3"), quote!(crate::eth::TXD3Pin)),
745 (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)), 786 (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)),
746 (("fmc", "A0"), quote!(crate::fmc::A0Pin)), 787 (("fmc", "A0"), quote!(crate::fmc::A0Pin)),
747 (("fmc", "A1"), quote!(crate::fmc::A1Pin)), 788 (("fmc", "A1"), quote!(crate::fmc::A1Pin)),
@@ -942,9 +983,9 @@ fn main() {
942 } else if pin.signal.starts_with("INN") { 983 } else if pin.signal.starts_with("INN") {
943 // TODO handle in the future when embassy supports differential measurements 984 // TODO handle in the future when embassy supports differential measurements
944 None 985 None
945 } else if pin.signal.starts_with("IN") && pin.signal.ends_with("b") { 986 } else if pin.signal.starts_with("IN") && pin.signal.ends_with('b') {
946 // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63 987 // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63
947 let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix("b").unwrap(); 988 let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix('b').unwrap();
948 Some(32u8 + signal.parse::<u8>().unwrap()) 989 Some(32u8 + signal.parse::<u8>().unwrap())
949 } else if pin.signal.starts_with("IN") { 990 } else if pin.signal.starts_with("IN") {
950 Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap()) 991 Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap())
@@ -1016,6 +1057,10 @@ fn main() {
1016 (("dac", "CH2"), quote!(crate::dac::DacDma2)), 1057 (("dac", "CH2"), quote!(crate::dac::DacDma2)),
1017 (("timer", "UP"), quote!(crate::timer::UpDma)), 1058 (("timer", "UP"), quote!(crate::timer::UpDma)),
1018 (("hash", "IN"), quote!(crate::hash::Dma)), 1059 (("hash", "IN"), quote!(crate::hash::Dma)),
1060 (("timer", "CH1"), quote!(crate::timer::Ch1Dma)),
1061 (("timer", "CH2"), quote!(crate::timer::Ch2Dma)),
1062 (("timer", "CH3"), quote!(crate::timer::Ch3Dma)),
1063 (("timer", "CH4"), quote!(crate::timer::Ch4Dma)),
1019 ] 1064 ]
1020 .into(); 1065 .into();
1021 1066
@@ -1031,16 +1076,6 @@ fn main() {
1031 } 1076 }
1032 1077
1033 if let Some(tr) = signals.get(&(regs.kind, ch.signal)) { 1078 if let Some(tr) = signals.get(&(regs.kind, ch.signal)) {
1034 // TIM6 of stm32f334 is special, DMA channel for TIM6 depending on SYSCFG state
1035 if chip_name.starts_with("stm32f334") && p.name == "TIM6" {
1036 continue;
1037 }
1038
1039 // TIM6 of stm32f378 is special, DMA channel for TIM6 depending on SYSCFG state
1040 if chip_name.starts_with("stm32f378") && p.name == "TIM6" {
1041 continue;
1042 }
1043
1044 let peri = format_ident!("{}", p.name); 1079 let peri = format_ident!("{}", p.name);
1045 1080
1046 let channel = if let Some(channel) = &ch.channel { 1081 let channel = if let Some(channel) = &ch.channel {
@@ -1199,7 +1234,7 @@ fn main() {
1199 ADC3 and higher are assigned to the adc34 clock in the table 1234 ADC3 and higher are assigned to the adc34 clock in the table
1200 The adc3_common cfg directive is added if ADC3_COMMON exists 1235 The adc3_common cfg directive is added if ADC3_COMMON exists
1201 */ 1236 */
1202 let has_adc3 = METADATA.peripherals.iter().find(|p| p.name == "ADC3_COMMON").is_some(); 1237 let has_adc3 = METADATA.peripherals.iter().any(|p| p.name == "ADC3_COMMON");
1203 let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]); 1238 let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]);
1204 1239
1205 for m in METADATA 1240 for m in METADATA
@@ -1338,7 +1373,7 @@ fn main() {
1338 } 1373 }
1339 } 1374 }
1340 1375
1341 let mut m = String::new(); 1376 let mut m = clocks_macro.to_string();
1342 1377
1343 // DO NOT ADD more macros like these. 1378 // DO NOT ADD more macros like these.
1344 // These turned to be a bad idea! 1379 // These turned to be a bad idea!
@@ -1383,6 +1418,7 @@ fn main() {
1383 1418
1384 // ======= 1419 // =======
1385 // ADC3_COMMON is present 1420 // ADC3_COMMON is present
1421 #[allow(clippy::print_literal)]
1386 if has_adc3 { 1422 if has_adc3 {
1387 println!("cargo:rustc-cfg={}", "adc3_common"); 1423 println!("cargo:rustc-cfg={}", "adc3_common");
1388 } 1424 }
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index fb27bb87b..c896d8e3a 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -6,7 +6,6 @@ use embassy_hal_internal::into_ref;
6use embedded_hal_02::blocking::delay::DelayUs; 6use embedded_hal_02::blocking::delay::DelayUs;
7 7
8use crate::adc::{Adc, AdcPin, Instance, SampleTime}; 8use crate::adc::{Adc, AdcPin, Instance, SampleTime};
9use crate::rcc::get_freqs;
10use crate::time::Hertz; 9use crate::time::Hertz;
11use crate::{interrupt, Peripheral}; 10use crate::{interrupt, Peripheral};
12 11
@@ -80,7 +79,7 @@ impl<'d, T: Instance> Adc<'d, T> {
80 } 79 }
81 80
82 fn freq() -> Hertz { 81 fn freq() -> Hertz {
83 unsafe { get_freqs() }.adc.unwrap() 82 T::frequency()
84 } 83 }
85 84
86 pub fn sample_time_for_us(&self, us: u32) -> SampleTime { 85 pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 6f59c230f..6606a2b9c 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -102,7 +102,7 @@ impl<'d, T: Instance> Adc<'d, T> {
102 } 102 }
103 103
104 fn freq() -> Hertz { 104 fn freq() -> Hertz {
105 <T as crate::adc::sealed::Instance>::frequency() 105 <T as crate::rcc::sealed::RccPeripheral>::frequency()
106 } 106 }
107 107
108 pub fn sample_time_for_us(&self, us: u32) -> SampleTime { 108 pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index e4dd35c34..d21c3053f 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -61,8 +61,6 @@ pub(crate) mod sealed {
61 fn regs() -> crate::pac::adc::Adc; 61 fn regs() -> crate::pac::adc::Adc;
62 #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 62 #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
63 fn common_regs() -> crate::pac::adccommon::AdcCommon; 63 fn common_regs() -> crate::pac::adccommon::AdcCommon;
64 #[cfg(adc_f3)]
65 fn frequency() -> crate::time::Hertz;
66 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 64 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
67 fn state() -> &'static State; 65 fn state() -> &'static State;
68 } 66 }
@@ -103,11 +101,6 @@ foreach_adc!(
103 return crate::pac::$common_inst 101 return crate::pac::$common_inst
104 } 102 }
105 103
106 #[cfg(adc_f3)]
107 fn frequency() -> crate::time::Hertz {
108 unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
109 }
110
111 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 104 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
112 fn state() -> &'static sealed::State { 105 fn state() -> &'static sealed::State {
113 static STATE: sealed::State = sealed::State::new(); 106 static STATE: sealed::State = sealed::State::new();
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 4622b40a9..b37ac5a5d 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -34,7 +34,7 @@ impl AdcPin<ADC1> for Temperature {}
34impl super::sealed::AdcPin<ADC1> for Temperature { 34impl super::sealed::AdcPin<ADC1> for Temperature {
35 fn channel(&self) -> u8 { 35 fn channel(&self) -> u8 {
36 cfg_if::cfg_if! { 36 cfg_if::cfg_if! {
37 if #[cfg(any(stm32f40, stm32f41))] { 37 if #[cfg(any(stm32f2, stm32f40, stm32f41))] {
38 16 38 16
39 } else { 39 } else {
40 18 40 18
@@ -67,7 +67,11 @@ enum Prescaler {
67 67
68impl Prescaler { 68impl Prescaler {
69 fn from_pclk2(freq: Hertz) -> Self { 69 fn from_pclk2(freq: Hertz) -> Self {
70 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V).
71 #[cfg(stm32f2)]
72 const MAX_FREQUENCY: Hertz = Hertz(30_000_000);
70 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. 73 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
74 #[cfg(not(stm32f2))]
71 const MAX_FREQUENCY: Hertz = Hertz(36_000_000); 75 const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
72 let raw_div = freq.0 / MAX_FREQUENCY.0; 76 let raw_div = freq.0 / MAX_FREQUENCY.0;
73 match raw_div { 77 match raw_div {
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;
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::can::vals::{Ide, Lec}; 14use crate::pac::can::vals::{Ide, Lec};
15use crate::rcc::RccPeripheral; 15use crate::rcc::RccPeripheral;
16use crate::time::Hertz;
17use crate::{interrupt, peripherals, Peripheral}; 16use crate::{interrupt, peripherals, Peripheral};
18 17
18pub mod enums;
19use enums::*;
20pub 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))]
100pub 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))]
6pub 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 @@
1use crate::peripherals; 1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::ops::{Deref, DerefMut};
4use core::task::Poll;
5
6use cfg_if::cfg_if;
7use embassy_hal_internal::{into_ref, PeripheralRef};
8pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader};
9pub use fdcan::id::{ExtendedId, Id, StandardId};
10use fdcan::message_ram::RegisterBlock;
11use fdcan::{self, LastErrorCode};
12pub use fdcan::{config, filter};
13
14use crate::gpio::sealed::AFType;
15use crate::interrupt::typelevel::Interrupt;
16use crate::rcc::RccPeripheral;
17use crate::{interrupt, peripherals, Peripheral};
18
19pub mod enums;
20use enums::*;
21pub mod util;
22
23/// CAN Frame returned by read
24pub 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
35pub struct TxFrame {
36 /// CAN Header info: frame ID, data length and other meta
37 pub header: TxFrameHeader,
38 /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
39 pub data: Data,
40}
41
42impl TxFrame {
43 /// Create new TX frame from header and data
44 pub fn new(header: TxFrameHeader, data: &[u8]) -> Option<Self> {
45 if data.len() < header.len as usize {
46 return None;
47 }
48
49 let Some(data) = Data::new(data) else { return None };
50
51 Some(TxFrame { header, data })
52 }
53
54 fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option<Self> {
55 let mut data = [0u8; 64];
56
57 for i in 0..data32.len() {
58 data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes());
59 }
60
61 let Some(data) = Data::new(&data) else { return None };
62
63 Some(TxFrame { header, data })
64 }
65
66 /// Access frame data. Slice length will match header.
67 pub fn data(&self) -> &[u8] {
68 &self.data.bytes[..(self.header.len as usize)]
69 }
70}
71
72impl RxFrame {
73 pub(crate) fn new(
74 header: RxFrameInfo,
75 data: &[u8],
76 #[cfg(feature = "time")] timestamp: embassy_time::Instant,
77 ) -> Self {
78 let data = Data::new(&data).unwrap_or_else(|| Data::empty());
79
80 RxFrame {
81 header,
82 data,
83 #[cfg(feature = "time")]
84 timestamp,
85 }
86 }
87
88 /// Access frame data. Slice length will match header.
89 pub fn data(&self) -> &[u8] {
90 &self.data.bytes[..(self.header.len as usize)]
91 }
92}
93
94/// Payload of a (FD)CAN data frame.
95///
96/// Contains 0 to 64 Bytes of data.
97#[derive(Debug, Copy, Clone)]
98pub struct Data {
99 pub(crate) bytes: [u8; 64],
100}
101
102impl Data {
103 /// Creates a data payload from a raw byte slice.
104 ///
105 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
106 /// cannot be represented with an FDCAN DLC.
107 pub fn new(data: &[u8]) -> Option<Self> {
108 if !Data::is_valid_len(data.len()) {
109 return None;
110 }
111
112 let mut bytes = [0; 64];
113 bytes[..data.len()].copy_from_slice(data);
114
115 Some(Self { bytes })
116 }
117
118 /// Raw read access to data.
119 pub fn raw(&self) -> &[u8] {
120 &self.bytes
121 }
122
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.
146pub struct IT0InterruptHandler<T: Instance> {
147 _phantom: PhantomData<T>,
148}
149
150// We use IT0 for everything currently
151impl<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.
187pub struct IT1InterruptHandler<T: Instance> {
188 _phantom: PhantomData<T>,
189}
190
191impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1InterruptHandler<T> {
192 unsafe fn on_interrupt() {}
193}
194
195impl 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
212pub trait FdcanOperatingMode {}
213impl FdcanOperatingMode for fdcan::PoweredDownMode {}
214impl FdcanOperatingMode for fdcan::ConfigMode {}
215impl FdcanOperatingMode for fdcan::InternalLoopbackMode {}
216impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {}
217impl FdcanOperatingMode for fdcan::NormalOperationMode {}
218impl FdcanOperatingMode for fdcan::RestrictedOperationMode {}
219impl FdcanOperatingMode for fdcan::BusMonitoringMode {}
220impl FdcanOperatingMode for fdcan::TestMode {}
221
222/// FDCAN Instance
223pub 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
229fn 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")]
245fn 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
256fn 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
279impl<'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
345macro_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
360impl_transition!(PoweredDownMode, ConfigMode, into_config_mode, into_config_mode);
361impl_transition!(InternalLoopbackMode, ConfigMode, into_config_mode, into_config_mode);
362
363impl_transition!(ConfigMode, NormalOperationMode, into_normal_mode, into_normal);
364impl_transition!(
365 ConfigMode,
366 ExternalLoopbackMode,
367 into_external_loopback_mode,
368 into_external_loopback
369);
370impl_transition!(
371 ConfigMode,
372 InternalLoopbackMode,
373 into_internal_loopback_mode,
374 into_internal_loopback
375);
376
377impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M>
378where
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
476pub 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
481impl<'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)]
508pub 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
514impl<'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}
554impl<'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
562impl<'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
3pub(crate) mod sealed { 568pub(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
31pub trait InterruptableInstance {} 662pub trait IT0Instance {
32/// FDCAN instance. 663 /// Type for FDCAN interrupt channel 0
33pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} 664 type IT0Interrupt: crate::interrupt::typelevel::Interrupt;
665}
34 666
35foreach_peripheral!( 667/// Trait for FDCAN interrupt channel 1
36 (can, $inst:ident) => { 668pub trait IT1Instance {
669 /// Type for FDCAN interrupt channel 1
670 type IT1Interrupt: crate::interrupt::typelevel::Interrupt;
671}
672
673/// InterruptableInstance trait
674pub trait InterruptableInstance: IT0Instance + IT1Instance {}
675/// Instance trait
676pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
677/// Fdcan Instance struct
678pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
679
680unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> {
681 const MSG_RAM: *mut RegisterBlock = T::MSG_RAM;
682}
683
684unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T>
685where
686 FdcanInstance<'d, T>: fdcan::message_ram::Instance,
687{
688 const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS;
689}
690
691macro_rules! impl_fdcan {
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))]
732foreach_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)]
740foreach_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
54pin_trait!(RxPin, Instance); 746pin_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
3use core::num::{NonZeroU16, NonZeroU8};
4
5/// Shared struct to represent bit timings used by calc_can_timings.
6#[derive(Clone, Copy, Debug)]
7pub 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
20pub 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/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 31dedf06e..60f9404c2 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -504,29 +504,6 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
504 504
505foreach_peripheral!( 505foreach_peripheral!(
506 (dac, $inst:ident) => { 506 (dac, $inst:ident) => {
507 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
508 #[cfg(any(rcc_h7, rcc_h7rm0433))]
509 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
510 fn frequency() -> crate::time::Hertz {
511 critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 })
512 }
513
514 fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
515 // TODO: Increment refcount?
516 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
517 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
518 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
519 }
520
521 fn disable_with_cs(_cs: critical_section::CriticalSection) {
522 // TODO: Decrement refcount?
523 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
524 }
525 }
526
527 #[cfg(any(rcc_h7, rcc_h7rm0433))]
528 impl crate::rcc::RccPeripheral for peripherals::$inst {}
529
530 impl crate::dac::sealed::Instance for peripherals::$inst { 507 impl crate::dac::sealed::Instance for peripherals::$inst {
531 fn regs() -> &'static crate::pac::dac::Dac { 508 fn regs() -> &'static crate::pac::dac::Dac {
532 &crate::pac::$inst 509 &crate::pac::$inst
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 448405507..71fe09c3f 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -13,6 +13,7 @@ use embassy_net_driver::{Capabilities, HardwareAddress, LinkState};
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14 14
15pub use self::_version::{InterruptHandler, *}; 15pub use self::_version::{InterruptHandler, *};
16use crate::rcc::RccPeripheral;
16 17
17#[allow(unused)] 18#[allow(unused)]
18const MTU: usize = 1514; 19const MTU: usize = 1514;
@@ -183,7 +184,7 @@ pub(crate) mod sealed {
183} 184}
184 185
185/// Ethernet instance. 186/// Ethernet instance.
186pub trait Instance: sealed::Instance + Send + 'static {} 187pub trait Instance: sealed::Instance + RccPeripheral + Send + 'static {}
187 188
188impl sealed::Instance for crate::peripherals::ETH { 189impl sealed::Instance for crate::peripherals::ETH {
189 fn regs() -> crate::pac::eth::Eth { 190 fn regs() -> crate::pac::eth::Eth {
@@ -192,12 +193,19 @@ impl sealed::Instance for crate::peripherals::ETH {
192} 193}
193impl Instance for crate::peripherals::ETH {} 194impl Instance for crate::peripherals::ETH {}
194 195
196pin_trait!(RXClkPin, Instance);
197pin_trait!(TXClkPin, Instance);
195pin_trait!(RefClkPin, Instance); 198pin_trait!(RefClkPin, Instance);
196pin_trait!(MDIOPin, Instance); 199pin_trait!(MDIOPin, Instance);
197pin_trait!(MDCPin, Instance); 200pin_trait!(MDCPin, Instance);
201pin_trait!(RXDVPin, Instance);
198pin_trait!(CRSPin, Instance); 202pin_trait!(CRSPin, Instance);
199pin_trait!(RXD0Pin, Instance); 203pin_trait!(RXD0Pin, Instance);
200pin_trait!(RXD1Pin, Instance); 204pin_trait!(RXD1Pin, Instance);
205pin_trait!(RXD2Pin, Instance);
206pin_trait!(RXD3Pin, Instance);
201pin_trait!(TXD0Pin, Instance); 207pin_trait!(TXD0Pin, Instance);
202pin_trait!(TXD1Pin, Instance); 208pin_trait!(TXD1Pin, Instance);
209pin_trait!(TXD2Pin, Instance);
210pin_trait!(TXD3Pin, Instance);
203pin_trait!(TXEnPin, Instance); 211pin_trait!(TXEnPin, Instance);
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 2ce5b3927..e5b7b0452 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -20,6 +20,7 @@ use crate::pac::AFIO;
20#[cfg(any(eth_v1b, eth_v1c))] 20#[cfg(any(eth_v1b, eth_v1c))]
21use crate::pac::SYSCFG; 21use crate::pac::SYSCFG;
22use crate::pac::{ETH, RCC}; 22use crate::pac::{ETH, RCC};
23use crate::rcc::sealed::RccPeripheral;
23use crate::{interrupt, Peripheral}; 24use crate::{interrupt, Peripheral};
24 25
25/// Interrupt handler. 26/// Interrupt handler.
@@ -191,8 +192,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
191 192
192 // TODO MTU size setting not found for v1 ethernet, check if correct 193 // TODO MTU size setting not found for v1 ethernet, check if correct
193 194
194 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 195 let hclk = <T as RccPeripheral>::frequency();
195 let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
196 let hclk_mhz = hclk.0 / 1_000_000; 196 let hclk_mhz = hclk.0 / 1_000_000;
197 197
198 // Set the MDC clock frequency in the range 1MHz - 2.5MHz 198 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index 01ea8e574..645bfdb14 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -129,7 +129,7 @@ impl<'a> TDesRing<'a> {
129 129
130/// Receive Descriptor representation 130/// Receive Descriptor representation
131/// 131///
132/// * rdes0: recieve buffer address 132/// * rdes0: receive buffer address
133/// * rdes1: 133/// * rdes1:
134/// * rdes2: 134/// * rdes2:
135/// * rdes3: OWN and Status 135/// * rdes3: OWN and Status
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 59745cba0..8d69561d4 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -11,6 +11,7 @@ use crate::gpio::sealed::{AFType, Pin as _};
11use crate::gpio::{AnyPin, Speed}; 11use crate::gpio::{AnyPin, Speed};
12use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
13use crate::pac::ETH; 13use crate::pac::ETH;
14use crate::rcc::sealed::RccPeripheral;
14use crate::{interrupt, Peripheral}; 15use crate::{interrupt, Peripheral};
15 16
16/// Interrupt handler. 17/// Interrupt handler.
@@ -39,12 +40,18 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
39 _peri: PeripheralRef<'d, T>, 40 _peri: PeripheralRef<'d, T>,
40 pub(crate) tx: TDesRing<'d>, 41 pub(crate) tx: TDesRing<'d>,
41 pub(crate) rx: RDesRing<'d>, 42 pub(crate) rx: RDesRing<'d>,
42 pins: [PeripheralRef<'d, AnyPin>; 9], 43 pins: Pins<'d>,
43 pub(crate) phy: P, 44 pub(crate) phy: P,
44 pub(crate) station_management: EthernetStationManagement<T>, 45 pub(crate) station_management: EthernetStationManagement<T>,
45 pub(crate) mac_addr: [u8; 6], 46 pub(crate) mac_addr: [u8; 6],
46} 47}
47 48
49/// Pins of ethernet driver.
50enum Pins<'d> {
51 Rmii([PeripheralRef<'d, AnyPin>; 9]),
52 Mii([PeripheralRef<'d, AnyPin>; 14]),
53}
54
48macro_rules! config_pins { 55macro_rules! config_pins {
49 ($($pin:ident),*) => { 56 ($($pin:ident),*) => {
50 critical_section::with(|_| { 57 critical_section::with(|_| {
@@ -57,11 +64,11 @@ macro_rules! config_pins {
57} 64}
58 65
59impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { 66impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
60 /// Create a new Ethernet driver. 67 /// Create a new RMII ethernet driver using 9 pins.
61 pub fn new<const TX: usize, const RX: usize>( 68 pub fn new<const TX: usize, const RX: usize>(
62 queue: &'d mut PacketQueue<TX, RX>, 69 queue: &'d mut PacketQueue<TX, RX>,
63 peri: impl Peripheral<P = T> + 'd, 70 peri: impl Peripheral<P = T> + 'd,
64 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 71 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
65 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 72 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
66 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 73 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
67 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 74 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
@@ -74,8 +81,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
74 phy: P, 81 phy: P,
75 mac_addr: [u8; 6], 82 mac_addr: [u8; 6],
76 ) -> Self { 83 ) -> Self {
77 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
78
79 // Enable the necessary Clocks 84 // Enable the necessary Clocks
80 #[cfg(not(rcc_h5))] 85 #[cfg(not(rcc_h5))]
81 critical_section::with(|_| { 86 critical_section::with(|_| {
@@ -85,7 +90,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
85 w.set_eth1rxen(true); 90 w.set_eth1rxen(true);
86 }); 91 });
87 92
88 // RMII
89 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); 93 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
90 }); 94 });
91 95
@@ -99,14 +103,110 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
99 w.set_ethrxen(true); 103 w.set_ethrxen(true);
100 }); 104 });
101 105
102 // RMII
103 crate::pac::SYSCFG 106 crate::pac::SYSCFG
104 .pmcr() 107 .pmcr()
105 .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); 108 .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
106 }); 109 });
107 110
111 into_ref!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
108 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 112 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
109 113
114 let pins = Pins::Rmii([
115 ref_clk.map_into(),
116 mdio.map_into(),
117 mdc.map_into(),
118 crs.map_into(),
119 rx_d0.map_into(),
120 rx_d1.map_into(),
121 tx_d0.map_into(),
122 tx_d1.map_into(),
123 tx_en.map_into(),
124 ]);
125
126 Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
127 }
128
129 /// Create a new MII ethernet driver using 14 pins.
130 pub fn new_mii<const TX: usize, const RX: usize>(
131 queue: &'d mut PacketQueue<TX, RX>,
132 peri: impl Peripheral<P = T> + 'd,
133 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
134 rx_clk: impl Peripheral<P = impl RXClkPin<T>> + 'd,
135 tx_clk: impl Peripheral<P = impl TXClkPin<T>> + 'd,
136 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
137 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
138 rxdv: impl Peripheral<P = impl RXDVPin<T>> + 'd,
139 rx_d0: impl Peripheral<P = impl RXD0Pin<T>> + 'd,
140 rx_d1: impl Peripheral<P = impl RXD1Pin<T>> + 'd,
141 rx_d2: impl Peripheral<P = impl RXD2Pin<T>> + 'd,
142 rx_d3: impl Peripheral<P = impl RXD3Pin<T>> + 'd,
143 tx_d0: impl Peripheral<P = impl TXD0Pin<T>> + 'd,
144 tx_d1: impl Peripheral<P = impl TXD1Pin<T>> + 'd,
145 tx_d2: impl Peripheral<P = impl TXD2Pin<T>> + 'd,
146 tx_d3: impl Peripheral<P = impl TXD3Pin<T>> + 'd,
147 tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
148 phy: P,
149 mac_addr: [u8; 6],
150 ) -> Self {
151 // Enable necessary clocks.
152 #[cfg(not(rcc_h5))]
153 critical_section::with(|_| {
154 crate::pac::RCC.ahb1enr().modify(|w| {
155 w.set_eth1macen(true);
156 w.set_eth1txen(true);
157 w.set_eth1rxen(true);
158 });
159
160 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b000));
161 });
162
163 #[cfg(rcc_h5)]
164 critical_section::with(|_| {
165 crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
166
167 crate::pac::RCC.ahb1enr().modify(|w| {
168 w.set_ethen(true);
169 w.set_ethtxen(true);
170 w.set_ethrxen(true);
171 });
172
173 // TODO: This is for RMII - what would MII need here?
174 crate::pac::SYSCFG
175 .pmcr()
176 .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
177 });
178
179 into_ref!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
180 config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
181
182 let pins = Pins::Mii([
183 rx_clk.map_into(),
184 tx_clk.map_into(),
185 mdio.map_into(),
186 mdc.map_into(),
187 rxdv.map_into(),
188 rx_d0.map_into(),
189 rx_d1.map_into(),
190 rx_d2.map_into(),
191 rx_d3.map_into(),
192 tx_d0.map_into(),
193 tx_d1.map_into(),
194 tx_d2.map_into(),
195 tx_d3.map_into(),
196 tx_en.map_into(),
197 ]);
198
199 Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
200 }
201
202 fn new_inner<const TX: usize, const RX: usize>(
203 queue: &'d mut PacketQueue<TX, RX>,
204 peri: impl Peripheral<P = T> + 'd,
205 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
206 pins: Pins<'d>,
207 phy: P,
208 mac_addr: [u8; 6],
209 ) -> Self {
110 let dma = ETH.ethernet_dma(); 210 let dma = ETH.ethernet_dma();
111 let mac = ETH.ethernet_mac(); 211 let mac = ETH.ethernet_mac();
112 let mtl = ETH.ethernet_mtl(); 212 let mtl = ETH.ethernet_mtl();
@@ -165,8 +265,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
165 w.set_rbsz(RX_BUFFER_SIZE as u16); 265 w.set_rbsz(RX_BUFFER_SIZE as u16);
166 }); 266 });
167 267
168 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 268 let hclk = <T as RccPeripheral>::frequency();
169 let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
170 let hclk_mhz = hclk.0 / 1_000_000; 269 let hclk_mhz = hclk.0 / 1_000_000;
171 270
172 // Set the MDC clock frequency in the range 1MHz - 2.5MHz 271 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
@@ -182,24 +281,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
182 } 281 }
183 }; 282 };
184 283
185 let pins = [
186 ref_clk.map_into(),
187 mdio.map_into(),
188 mdc.map_into(),
189 crs.map_into(),
190 rx_d0.map_into(),
191 rx_d1.map_into(),
192 tx_d0.map_into(),
193 tx_d1.map_into(),
194 tx_en.map_into(),
195 ];
196
197 let mut this = Self { 284 let mut this = Self {
198 _peri: peri, 285 _peri: peri.into_ref(),
199 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 286 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
200 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 287 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
201 pins, 288 pins,
202 phy: phy, 289 phy,
203 station_management: EthernetStationManagement { 290 station_management: EthernetStationManagement {
204 peri: PhantomData, 291 peri: PhantomData,
205 clock_range: clock_range, 292 clock_range: clock_range,
@@ -302,7 +389,10 @@ impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
302 dma.dmacrx_cr().modify(|w| w.set_sr(false)); 389 dma.dmacrx_cr().modify(|w| w.set_sr(false));
303 390
304 critical_section::with(|_| { 391 critical_section::with(|_| {
305 for pin in self.pins.iter_mut() { 392 for pin in match self.pins {
393 Pins::Rmii(ref mut pins) => pins.iter_mut(),
394 Pins::Mii(ref mut pins) => pins.iter_mut(),
395 } {
306 pin.set_as_disconnected(); 396 pin.set_as_disconnected();
307 } 397 }
308 }) 398 })
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index faefaabbc..3ec646fc3 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -10,8 +10,6 @@ pub use traits::Instance;
10#[allow(unused_imports)] 10#[allow(unused_imports)]
11use crate::gpio::sealed::{AFType, Pin}; 11use crate::gpio::sealed::{AFType, Pin};
12use crate::gpio::AnyPin; 12use crate::gpio::AnyPin;
13#[cfg(stm32f334)]
14use crate::rcc::get_freqs;
15use crate::time::Hertz; 13use crate::time::Hertz;
16use crate::Peripheral; 14use crate::Peripheral;
17 15
@@ -182,7 +180,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
182 T::enable_and_reset(); 180 T::enable_and_reset();
183 181
184 #[cfg(stm32f334)] 182 #[cfg(stm32f334)]
185 if unsafe { get_freqs() }.hrtim.is_some() { 183 if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P {
186 // Enable and and stabilize the DLL 184 // Enable and and stabilize the DLL
187 T::regs().dllcr().modify(|w| { 185 T::regs().dllcr().modify(|w| {
188 w.set_cal(true); 186 w.set_cal(true);
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs
index cfd31c47c..dcc2b9ef4 100644
--- a/embassy-stm32/src/hrtim/traits.rs
+++ b/embassy-stm32/src/hrtim/traits.rs
@@ -80,10 +80,12 @@ pub(crate) mod sealed {
80 80
81 fn set_master_frequency(frequency: Hertz) { 81 fn set_master_frequency(frequency: Hertz) {
82 let f = frequency.0; 82 let f = frequency.0;
83 #[cfg(not(stm32f334))] 83
84 // TODO: wire up HRTIM to the RCC mux infra.
85 //#[cfg(stm32f334)]
86 //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
87 //#[cfg(not(stm32f334))]
84 let timer_f = Self::frequency().0; 88 let timer_f = Self::frequency().0;
85 #[cfg(stm32f334)]
86 let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
87 89
88 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); 90 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
89 let psc = if Self::regs().isr().read().dllrdy() { 91 let psc = if Self::regs().isr().read().dllrdy() {
@@ -103,10 +105,12 @@ pub(crate) mod sealed {
103 105
104 fn set_channel_frequency(channel: usize, frequency: Hertz) { 106 fn set_channel_frequency(channel: usize, frequency: Hertz) {
105 let f = frequency.0; 107 let f = frequency.0;
106 #[cfg(not(stm32f334))] 108
109 // TODO: wire up HRTIM to the RCC mux infra.
110 //#[cfg(stm32f334)]
111 //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
112 //#[cfg(not(stm32f334))]
107 let timer_f = Self::frequency().0; 113 let timer_f = Self::frequency().0;
108 #[cfg(stm32f334)]
109 let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
110 114
111 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); 115 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
112 let psc = if Self::regs().isr().read().dllrdy() { 116 let psc = if Self::regs().isr().read().dllrdy() {
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 1f85c0bc5..e9065dce6 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -4,7 +4,6 @@ use embassy_hal_internal::into_ref;
4use crate::gpio::sealed::{AFType, Pin as _}; 4use crate::gpio::sealed::{AFType, Pin as _};
5use crate::gpio::AnyPin; 5use crate::gpio::AnyPin;
6use crate::pac::spi::vals; 6use crate::pac::spi::vals;
7use crate::rcc::get_freqs;
8use crate::spi::{Config as SpiConfig, *}; 7use crate::spi::{Config as SpiConfig, *};
9use crate::time::Hertz; 8use crate::time::Hertz;
10use crate::{Peripheral, PeripheralRef}; 9use crate::{Peripheral, PeripheralRef};
@@ -193,10 +192,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
193 spi_cfg.frequency = freq; 192 spi_cfg.frequency = freq;
194 let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg); 193 let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
195 194
196 #[cfg(all(rcc_f4, not(stm32f410)))] 195 // TODO move i2s to the new mux infra.
197 let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap(); 196 //#[cfg(all(rcc_f4, not(stm32f410)))]
198 197 //let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
199 #[cfg(stm32f410)] 198 //#[cfg(stm32f410)]
200 let pclk = T::frequency(); 199 let pclk = T::frequency();
201 200
202 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); 201 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 68f029ca0..ca1222185 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -2,7 +2,6 @@ use crate::pac::flash::vals::Latency;
2use crate::pac::rcc::vals::Sw; 2use crate::pac::rcc::vals::Sw;
3pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler}; 3pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler};
4use crate::pac::{FLASH, RCC}; 4use crate::pac::{FLASH, RCC};
5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz; 5use crate::time::Hertz;
7 6
8/// HSI speed 7/// HSI speed
@@ -133,13 +132,13 @@ pub(crate) unsafe fn init(config: Config) {
133 } 132 }
134 }; 133 };
135 134
136 set_freqs(Clocks { 135 set_clocks!(
137 hsi: None, 136 hsi: None,
138 lse: None, 137 lse: None,
139 sys: sys_clk, 138 sys: Some(sys_clk),
140 hclk1: ahb_freq, 139 hclk1: Some(ahb_freq),
141 pclk1: apb_freq, 140 pclk1: Some(apb_freq),
142 pclk1_tim: apb_tim_freq, 141 pclk1_tim: Some(apb_tim_freq),
143 rtc, 142 rtc: rtc,
144 }); 143 );
145} 144}
diff --git a/embassy-stm32/src/rcc/f.rs b/embassy-stm32/src/rcc/f.rs
index 36d9f178f..e306d478d 100644
--- a/embassy-stm32/src/rcc/f.rs
+++ b/embassy-stm32/src/rcc/f.rs
@@ -7,7 +7,6 @@ pub use crate::pac::rcc::vals::{
7#[cfg(any(stm32f4, stm32f7))] 7#[cfg(any(stm32f4, stm32f7))]
8use crate::pac::PWR; 8use crate::pac::PWR;
9use crate::pac::{FLASH, RCC}; 9use crate::pac::{FLASH, RCC};
10use crate::rcc::{set_freqs, Clocks};
11use crate::time::Hertz; 10use crate::time::Hertz;
12 11
13// TODO: on some F4s, PLLM is shared between all PLLs. Enforce that. 12// TODO: on some F4s, PLLM is shared between all PLLs. Enforce that.
@@ -183,9 +182,9 @@ pub(crate) unsafe fn init(config: Config) {
183 }; 182 };
184 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); 183 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
185 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] 184 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
186 let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); 185 let plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input);
187 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] 186 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
188 let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); 187 let pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input);
189 188
190 // Configure sysclk 189 // Configure sysclk
191 let sys = match config.sys { 190 let sys = match config.sys {
@@ -257,27 +256,41 @@ pub(crate) unsafe fn init(config: Config) {
257 }); 256 });
258 while RCC.cfgr().read().sws() != config.sys {} 257 while RCC.cfgr().read().sws() != config.sys {}
259 258
260 set_freqs(Clocks { 259 set_clocks!(
261 sys, 260 hsi: hsi,
262 hclk1: hclk, 261 hse: hse,
263 hclk2: hclk, 262 lse: None, // TODO
264 hclk3: hclk, 263 lsi: None, // TODO
265 pclk1, 264 sys: Some(sys),
266 pclk2, 265 hclk1: Some(hclk),
267 pclk1_tim, 266 hclk2: Some(hclk),
268 pclk2_tim, 267 hclk3: Some(hclk),
269 rtc, 268 pclk1: Some(pclk1),
269 pclk2: Some(pclk2),
270 pclk1_tim: Some(pclk1_tim),
271 pclk2_tim: Some(pclk2_tim),
272 rtc: rtc,
270 pll1_q: pll.q, 273 pll1_q: pll.q,
271 #[cfg(all(rcc_f4, not(stm32f410)))] 274
272 plli2s1_q: _plli2s.q, 275 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
273 #[cfg(all(rcc_f4, not(stm32f410)))] 276 plli2s1_p: plli2s.p,
274 plli2s1_r: _plli2s.r, 277 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
275 278 plli2s1_q: plli2s.q,
276 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] 279 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
277 pllsai1_q: _pllsai.q, 280 plli2s1_r: plli2s.r,
278 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] 281
279 pllsai1_r: _pllsai.r, 282 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
280 }); 283 pllsai1_p: pllsai.p,
284 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
285 pllsai1_q: pllsai.q,
286 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
287 pllsai1_r: pllsai.r,
288
289 clk48: pll.q,
290
291 hsi_hse: None,
292 afif: None,
293 );
281} 294}
282 295
283struct PllInput { 296struct PllInput {
diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs
index feaa2f4c0..a6b627887 100644
--- a/embassy-stm32/src/rcc/f0.rs
+++ b/embassy-stm32/src/rcc/f0.rs
@@ -1,6 +1,5 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2 2
3use super::{set_freqs, Clocks};
4use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; 3use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
5use crate::pac::{FLASH, RCC}; 4use crate::pac::{FLASH, RCC};
6use crate::time::Hertz; 5use crate::time::Hertz;
@@ -160,13 +159,15 @@ pub(crate) unsafe fn init(config: Config) {
160 159
161 let rtc = config.ls.init(); 160 let rtc = config.ls.init();
162 161
163 set_freqs(Clocks { 162 set_clocks!(
164 sys: Hertz(real_sysclk), 163 hsi: None,
165 pclk1: Hertz(pclk), 164 lse: None,
166 pclk2: Hertz(pclk), 165 sys: Some(Hertz(real_sysclk)),
167 pclk1_tim: Hertz(pclk * timer_mul), 166 pclk1: Some(Hertz(pclk)),
168 pclk2_tim: Hertz(pclk * timer_mul), 167 pclk2: Some(Hertz(pclk)),
169 hclk1: Hertz(hclk), 168 pclk1_tim: Some(Hertz(pclk * timer_mul)),
170 rtc, 169 pclk2_tim: Some(Hertz(pclk * timer_mul)),
171 }); 170 hclk1: Some(Hertz(hclk)),
171 rtc: rtc,
172 );
172} 173}
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
index 169551e45..7f0adab27 100644
--- a/embassy-stm32/src/rcc/f1.rs
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -1,6 +1,5 @@
1use core::convert::TryFrom; 1use core::convert::TryFrom;
2 2
3use super::{set_freqs, Clocks};
4use crate::pac::flash::vals::Latency; 3use crate::pac::flash::vals::Latency;
5use crate::pac::rcc::vals::*; 4use crate::pac::rcc::vals::*;
6use crate::pac::{FLASH, RCC}; 5use crate::pac::{FLASH, RCC};
@@ -179,14 +178,14 @@ pub(crate) unsafe fn init(config: Config) {
179 178
180 let rtc = config.ls.init(); 179 let rtc = config.ls.init();
181 180
182 set_freqs(Clocks { 181 set_clocks!(
183 sys: Hertz(real_sysclk), 182 sys: Some(Hertz(real_sysclk)),
184 pclk1: Hertz(pclk1), 183 pclk1: Some(Hertz(pclk1)),
185 pclk2: Hertz(pclk2), 184 pclk2: Some(Hertz(pclk2)),
186 pclk1_tim: Hertz(pclk1 * timer_mul1), 185 pclk1_tim: Some(Hertz(pclk1 * timer_mul1)),
187 pclk2_tim: Hertz(pclk2 * timer_mul2), 186 pclk2_tim: Some(Hertz(pclk2 * timer_mul2)),
188 hclk1: Hertz(hclk), 187 hclk1: Some(Hertz(hclk)),
189 adc: Some(Hertz(adcclk)), 188 adc: Some(Hertz(adcclk)),
190 rtc, 189 rtc: rtc,
191 }); 190 );
192} 191}
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs
index bf035fd25..25866e446 100644
--- a/embassy-stm32/src/rcc/f3.rs
+++ b/embassy-stm32/src/rcc/f3.rs
@@ -4,7 +4,6 @@ use crate::pac::flash::vals::Latency;
4pub use crate::pac::rcc::vals::Adcpres; 4pub use crate::pac::rcc::vals::Adcpres;
5use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; 5use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
6use crate::pac::{FLASH, RCC}; 6use crate::pac::{FLASH, RCC};
7use crate::rcc::{set_freqs, Clocks};
8use crate::time::Hertz; 7use crate::time::Hertz;
9 8
10/// HSI speed 9/// HSI speed
@@ -279,13 +278,16 @@ pub(crate) unsafe fn init(config: Config) {
279 278
280 let rtc = config.ls.init(); 279 let rtc = config.ls.init();
281 280
282 set_freqs(Clocks { 281 set_clocks!(
283 sys: sysclk, 282 hsi: None,
284 pclk1: pclk1, 283 lse: None,
285 pclk2: pclk2, 284 pll1_p: None,
286 pclk1_tim: pclk1 * timer_mul1, 285 sys: Some(sysclk),
287 pclk2_tim: pclk2 * timer_mul2, 286 pclk1: Some(pclk1),
288 hclk1: hclk, 287 pclk2: Some(pclk2),
288 pclk1_tim: Some(pclk1 * timer_mul1),
289 pclk2_tim: Some(pclk2 * timer_mul2),
290 hclk1: Some(hclk),
289 #[cfg(rcc_f3)] 291 #[cfg(rcc_f3)]
290 adc: adc, 292 adc: adc,
291 #[cfg(all(rcc_f3, adc3_common))] 293 #[cfg(all(rcc_f3, adc3_common))]
@@ -294,8 +296,8 @@ pub(crate) unsafe fn init(config: Config) {
294 adc34: None, 296 adc34: None,
295 #[cfg(stm32f334)] 297 #[cfg(stm32f334)]
296 hrtim: hrtim, 298 hrtim: hrtim,
297 rtc, 299 rtc: rtc,
298 }); 300 );
299} 301}
300 302
301#[inline] 303#[inline]
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index b38fe1dcc..e3cd46fb9 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -4,7 +4,6 @@ pub use crate::pac::rcc::vals::{
4 Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler, 4 Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler,
5}; 5};
6use crate::pac::{FLASH, PWR, RCC}; 6use crate::pac::{FLASH, PWR, RCC};
7use crate::rcc::{set_freqs, Clocks};
8use crate::time::Hertz; 7use crate::time::Hertz;
9 8
10/// HSI speed 9/// HSI speed
@@ -352,11 +351,11 @@ pub(crate) unsafe fn init(config: Config) {
352 #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))] 351 #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))]
353 let hsi48_freq: Option<Hertz> = None; 352 let hsi48_freq: Option<Hertz> = None;
354 353
355 set_freqs(Clocks { 354 set_clocks!(
356 sys: sys_clk, 355 sys: Some(sys_clk),
357 hclk1: ahb_freq, 356 hclk1: Some(ahb_freq),
358 pclk1: apb_freq, 357 pclk1: Some(apb_freq),
359 pclk1_tim: apb_tim_freq, 358 pclk1_tim: Some(apb_tim_freq),
360 hsi: hsi_freq, 359 hsi: hsi_freq,
361 hsi48: hsi48_freq, 360 hsi48: hsi48_freq,
362 hsi_div_8: hsi_div_8_freq, 361 hsi_div_8: hsi_div_8_freq,
@@ -365,6 +364,6 @@ pub(crate) unsafe fn init(config: Config) {
365 lsi: lsi_freq, 364 lsi: lsi_freq,
366 pll1_q: pll1_q_freq, 365 pll1_q: pll1_q_freq,
367 pll1_p: pll1_p_freq, 366 pll1_p: pll1_p_freq,
368 rtc, 367 rtc: rtc,
369 }); 368 );
370} 369}
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index fca364c21..3e20bf6af 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -3,11 +3,10 @@ use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
3use stm32_metapac::FLASH; 3use stm32_metapac::FLASH;
4 4
5pub use crate::pac::rcc::vals::{ 5pub 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};
9use crate::pac::{PWR, RCC}; 9use crate::pac::{PWR, RCC};
10use crate::rcc::{set_freqs, Clocks};
11use crate::time::Hertz; 10use crate::time::Hertz;
12 11
13/// HSI speed 12/// HSI speed
@@ -87,6 +86,7 @@ pub struct Config {
87 pub clock_48mhz_src: Option<Clock48MhzSrc>, 86 pub clock_48mhz_src: Option<Clock48MhzSrc>,
88 pub adc12_clock_source: AdcClockSource, 87 pub adc12_clock_source: AdcClockSource,
89 pub adc345_clock_source: AdcClockSource, 88 pub adc345_clock_source: AdcClockSource,
89 pub fdcan_clock_source: FdCanClockSource,
90 90
91 pub ls: super::LsConfig, 91 pub ls: super::LsConfig,
92} 92}
@@ -104,6 +104,7 @@ impl Default for Config {
104 clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())), 104 clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
105 adc12_clock_source: Adcsel::DISABLE, 105 adc12_clock_source: Adcsel::DISABLE,
106 adc345_clock_source: Adcsel::DISABLE, 106 adc345_clock_source: Adcsel::DISABLE,
107 fdcan_clock_source: FdCanClockSource::PCLK1,
107 ls: Default::default(), 108 ls: Default::default(),
108 } 109 }
109 } 110 }
@@ -282,6 +283,7 @@ pub(crate) unsafe fn init(config: Config) {
282 283
283 RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); 284 RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
284 RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); 285 RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
286 RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source));
285 287
286 let adc12_ck = match config.adc12_clock_source { 288 let adc12_ck = match config.adc12_clock_source {
287 AdcClockSource::DISABLE => None, 289 AdcClockSource::DISABLE => None,
@@ -304,20 +306,20 @@ pub(crate) unsafe fn init(config: Config) {
304 306
305 let rtc = config.ls.init(); 307 let rtc = config.ls.init();
306 308
307 set_freqs(Clocks { 309 set_clocks!(
308 sys: sys_clk, 310 sys: Some(sys_clk),
309 hclk1: ahb_freq, 311 hclk1: Some(ahb_freq),
310 hclk2: ahb_freq, 312 hclk2: Some(ahb_freq),
311 hclk3: ahb_freq, 313 hclk3: Some(ahb_freq),
312 pclk1: apb1_freq, 314 pclk1: Some(apb1_freq),
313 pclk1_tim: apb1_tim_freq, 315 pclk1_tim: Some(apb1_tim_freq),
314 pclk2: apb2_freq, 316 pclk2: Some(apb2_freq),
315 pclk2_tim: apb2_tim_freq, 317 pclk2_tim: Some(apb2_tim_freq),
316 adc: adc12_ck, 318 adc: adc12_ck,
317 adc34: adc345_ck, 319 adc34: adc345_ck,
318 pll1_p: None, 320 pll1_p: None,
319 pll1_q: None, // TODO 321 pll1_q: None, // TODO
320 hse: None, // TODO 322 hse: None, // TODO
321 rtc, 323 rtc: rtc,
322 }); 324 );
323} 325}
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 15b51a398..9ac2115f0 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -7,12 +7,11 @@ pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
7#[cfg(stm32h7)] 7#[cfg(stm32h7)]
8pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; 8pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
9pub use crate::pac::rcc::vals::{ 9pub 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};
13use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; 13use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
14use crate::pac::{FLASH, PWR, RCC}; 14use crate::pac::{FLASH, PWR, RCC};
15use crate::rcc::{set_freqs, Clocks};
16use crate::time::Hertz; 15use crate::time::Hertz;
17 16
18/// HSI speed 17/// HSI speed
@@ -212,6 +211,8 @@ pub struct Config {
212 211
213 pub per_clock_source: PerClockSource, 212 pub per_clock_source: PerClockSource,
214 pub adc_clock_source: AdcClockSource, 213 pub adc_clock_source: AdcClockSource,
214 pub fdcan_clock_source: FdCanClockSource,
215
215 pub timer_prescaler: TimerPrescaler, 216 pub timer_prescaler: TimerPrescaler,
216 pub voltage_scale: VoltageScale, 217 pub voltage_scale: VoltageScale,
217 pub ls: super::LsConfig, 218 pub ls: super::LsConfig,
@@ -248,6 +249,8 @@ impl Default for Config {
248 #[cfg(stm32h7)] 249 #[cfg(stm32h7)]
249 adc_clock_source: AdcClockSource::PER, 250 adc_clock_source: AdcClockSource::PER,
250 251
252 fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE
253
251 timer_prescaler: TimerPrescaler::DefaultX2, 254 timer_prescaler: TimerPrescaler::DefaultX2,
252 voltage_scale: VoltageScale::Scale0, 255 voltage_scale: VoltageScale::Scale0,
253 ls: Default::default(), 256 ls: Default::default(),
@@ -426,7 +429,7 @@ pub(crate) unsafe fn init(config: Config) {
426 }; 429 };
427 430
428 // Configure HSI48. 431 // Configure HSI48.
429 let _hsi48 = config.hsi48.map(super::init_hsi48); 432 let hsi48 = config.hsi48.map(super::init_hsi48);
430 433
431 // Configure CSI. 434 // Configure CSI.
432 RCC.cr().modify(|w| w.set_csion(config.csi)); 435 RCC.cr().modify(|w| w.set_csion(config.csi));
@@ -585,7 +588,8 @@ pub(crate) unsafe fn init(config: Config) {
585 588
586 RCC.ccipr5().modify(|w| { 589 RCC.ccipr5().modify(|w| {
587 w.set_ckpersel(config.per_clock_source); 590 w.set_ckpersel(config.per_clock_source);
588 w.set_adcdacsel(config.adc_clock_source) 591 w.set_adcdacsel(config.adc_clock_source);
592 w.set_fdcan12sel(config.fdcan_clock_source)
589 }); 593 });
590 } 594 }
591 595
@@ -609,45 +613,33 @@ pub(crate) unsafe fn init(config: Config) {
609 while !pac::SYSCFG.cccsr().read().ready() {} 613 while !pac::SYSCFG.cccsr().read().ready() {}
610 } 614 }
611 615
612 set_freqs(Clocks { 616 set_clocks!(
613 sys, 617 sys: Some(sys),
614 hclk1: hclk, 618 hclk1: Some(hclk),
615 hclk2: hclk, 619 hclk2: Some(hclk),
616 hclk3: hclk, 620 hclk3: Some(hclk),
617 hclk4: hclk, 621 hclk4: Some(hclk),
618 pclk1: apb1, 622 pclk1: Some(apb1),
619 pclk2: apb2, 623 pclk2: Some(apb2),
620 pclk3: apb3, 624 pclk3: Some(apb3),
621 #[cfg(stm32h7)] 625 #[cfg(stm32h7)]
622 pclk4: apb4, 626 pclk4: Some(apb4),
623 #[cfg(stm32h5)] 627 pclk1_tim: Some(apb1_tim),
624 pclk4: Hertz(1), 628 pclk2_tim: Some(apb2_tim),
625 pclk1_tim: apb1_tim, 629 adc: adc,
626 pclk2_tim: apb2_tim, 630 rtc: rtc,
627 adc, 631
628 rtc, 632 hsi: hsi,
629 633 hsi48: hsi48,
630 #[cfg(any(stm32h5, stm32h7))] 634 csi: csi,
631 hsi: None, 635 hse: hse,
632 #[cfg(stm32h5)]
633 hsi48: None,
634 #[cfg(stm32h5)]
635 lsi: None,
636 #[cfg(any(stm32h5, stm32h7))]
637 csi: None,
638 636
639 #[cfg(any(stm32h5, stm32h7))]
640 lse: None, 637 lse: None,
641 #[cfg(any(stm32h5, stm32h7))] 638 lsi: None,
642 hse: None,
643 639
644 #[cfg(any(stm32h5, stm32h7))]
645 pll1_q: pll1.q, 640 pll1_q: pll1.q,
646 #[cfg(any(stm32h5, stm32h7))]
647 pll2_p: pll2.p, 641 pll2_p: pll2.p,
648 #[cfg(any(stm32h5, stm32h7))]
649 pll2_q: pll2.q, 642 pll2_q: pll2.q,
650 #[cfg(any(stm32h5, stm32h7))]
651 pll2_r: pll2.r, 643 pll2_r: pll2.r,
652 #[cfg(any(rcc_h5, stm32h7))] 644 #[cfg(any(rcc_h5, stm32h7))]
653 pll3_p: pll3.p, 645 pll3_p: pll3.p,
@@ -665,12 +657,8 @@ pub(crate) unsafe fn init(config: Config) {
665 657
666 #[cfg(stm32h5)] 658 #[cfg(stm32h5)]
667 audioclk: None, 659 audioclk: None,
668 #[cfg(any(stm32h5, stm32h7))]
669 per: None, 660 per: None,
670 661 );
671 #[cfg(stm32h7)]
672 rcc_pclk_d3: None,
673 });
674} 662}
675 663
676struct PllInput { 664struct PllInput {
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 257fd83fe..ab1681dd4 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -9,7 +9,6 @@ pub use crate::pac::rcc::vals::Clk48sel as Clk48Src;
9pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; 9pub use crate::pac::rcc::vals::Hsepre as HsePrescaler;
10pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as ClockSrc}; 10pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as ClockSrc};
11use crate::pac::{FLASH, RCC}; 11use crate::pac::{FLASH, RCC};
12use crate::rcc::{set_freqs, Clocks};
13use crate::time::Hertz; 12use crate::time::Hertz;
14 13
15/// HSI speed 14/// HSI speed
@@ -262,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) {
262 #[cfg(any(stm32l4, stm32l5, stm32wb))] 261 #[cfg(any(stm32l4, stm32l5, stm32wb))]
263 let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input); 262 let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input);
264 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] 263 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
265 let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input); 264 let pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input);
266 265
267 let sys_clk = match config.mux { 266 let sys_clk = match config.mux {
268 ClockSrc::HSE => hse.unwrap(), 267 ClockSrc::HSE => hse.unwrap(),
@@ -274,12 +273,12 @@ pub(crate) unsafe fn init(config: Config) {
274 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] 273 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
275 RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src)); 274 RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src));
276 #[cfg(any(rcc_l0_v2))] 275 #[cfg(any(rcc_l0_v2))]
277 let _clk48 = match config.clk48_src { 276 let clk48 = match config.clk48_src {
278 Clk48Src::HSI48 => _hsi48, 277 Clk48Src::HSI48 => _hsi48,
279 Clk48Src::PLL1_VCO_DIV_2 => pll.clk48, 278 Clk48Src::PLL1_VCO_DIV_2 => pll.clk48,
280 }; 279 };
281 #[cfg(any(stm32l4, stm32l5, stm32wb))] 280 #[cfg(any(stm32l4, stm32l5, stm32wb))]
282 let _clk48 = match config.clk48_src { 281 let clk48 = match config.clk48_src {
283 Clk48Src::HSI48 => _hsi48, 282 Clk48Src::HSI48 => _hsi48,
284 Clk48Src::MSI => msi, 283 Clk48Src::MSI => msi,
285 Clk48Src::PLLSAI1_Q => pllsai1.q, 284 Clk48Src::PLLSAI1_Q => pllsai1.q,
@@ -376,37 +375,53 @@ pub(crate) unsafe fn init(config: Config) {
376 while !RCC.extcfgr().read().c2hpref() {} 375 while !RCC.extcfgr().read().c2hpref() {}
377 } 376 }
378 377
379 set_freqs(Clocks { 378 set_clocks!(
380 sys: sys_clk, 379 sys: Some(sys_clk),
381 hclk1, 380 hclk1: Some(hclk1),
382 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 381 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
383 hclk2, 382 hclk2: Some(hclk2),
384 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 383 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
385 hclk3, 384 hclk3: Some(hclk3),
386 pclk1, 385 pclk1: Some(pclk1),
387 pclk2, 386 pclk2: Some(pclk2),
388 pclk1_tim, 387 pclk1_tim: Some(pclk1_tim),
389 pclk2_tim, 388 pclk2_tim: Some(pclk2_tim),
390 #[cfg(stm32wl)] 389 #[cfg(stm32wl)]
391 pclk3: hclk3, 390 pclk3: Some(hclk3),
392 #[cfg(rcc_l4)] 391 hsi: hsi,
393 hsi: None, 392 hse: hse,
394 #[cfg(rcc_l4)] 393 msi: msi,
395 lse: None, 394 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
396 #[cfg(rcc_l4)] 395 clk48: clk48,
397 pllsai1_p: None, 396
398 #[cfg(rcc_l4)] 397 #[cfg(not(any(stm32l0, stm32l1)))]
399 pllsai2_p: None, 398 pll1_p: pll.p,
400 #[cfg(rcc_l4)] 399 #[cfg(not(any(stm32l0, stm32l1)))]
401 pll1_p: None, 400 pll1_q: pll.q,
402 #[cfg(rcc_l4)] 401 pll1_r: pll.r,
403 pll1_q: None, 402
404 #[cfg(rcc_l4)] 403 #[cfg(any(stm32l4, stm32l5, stm32wb))]
404 pllsai1_p: pllsai1.p,
405 #[cfg(any(stm32l4, stm32l5, stm32wb))]
406 pllsai1_q: pllsai1.q,
407 #[cfg(any(stm32l4, stm32l5, stm32wb))]
408 pllsai1_r: pllsai1.r,
409
410 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
411 pllsai2_p: pllsai2.p,
412 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
413 pllsai2_q: pllsai2.q,
414 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
415 pllsai2_r: pllsai2.r,
416
417 rtc: rtc,
418
419 // TODO
405 sai1_extclk: None, 420 sai1_extclk: None,
406 #[cfg(rcc_l4)]
407 sai2_extclk: None, 421 sai2_extclk: None,
408 rtc, 422 lsi: None,
409 }); 423 lse: None,
424 );
410} 425}
411 426
412#[cfg(any(stm32l0, stm32l1))] 427#[cfg(any(stm32l0, stm32l1))]
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 240ffc6d2..280da7ae3 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -5,8 +5,6 @@
5 5
6use core::mem::MaybeUninit; 6use core::mem::MaybeUninit;
7 7
8use crate::time::Hertz;
9
10mod bd; 8mod bd;
11mod mco; 9mod mco;
12pub use bd::*; 10pub use bd::*;
@@ -32,162 +30,7 @@ mod _version;
32 30
33pub use _version::*; 31pub use _version::*;
34 32
35// Model Clock Configuration 33pub use crate::_generated::Clocks;
36//
37// pub struct Clocks {
38// hse: Option<Hertz>,
39// hsi: bool,
40// lse: Option<Hertz>,
41// lsi: bool,
42// rtc: RtcSource,
43// }
44
45#[derive(Clone, Copy, Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub struct Clocks {
48 pub sys: Hertz,
49
50 // APB
51 pub pclk1: Hertz,
52 pub pclk1_tim: Hertz,
53 #[cfg(not(any(rcc_c0, rcc_g0)))]
54 pub pclk2: Hertz,
55 #[cfg(not(any(rcc_c0, rcc_g0)))]
56 pub pclk2_tim: Hertz,
57 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))]
58 pub pclk3: Hertz,
59 #[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab, stm32h5))]
60 pub pclk4: Hertz,
61 #[cfg(any(rcc_wba))]
62 pub pclk7: Hertz,
63
64 // AHB
65 pub hclk1: Hertz,
66 #[cfg(any(
67 rcc_l4,
68 rcc_l4plus,
69 rcc_l5,
70 rcc_f2,
71 rcc_f4,
72 rcc_f410,
73 rcc_f7,
74 rcc_h5,
75 rcc_h50,
76 rcc_h7,
77 rcc_h7rm0433,
78 rcc_h7ab,
79 rcc_g4,
80 rcc_u5,
81 rcc_wb,
82 rcc_wba,
83 rcc_wl5,
84 rcc_wle
85 ))]
86 pub hclk2: Hertz,
87 #[cfg(any(
88 rcc_l4,
89 rcc_l4plus,
90 rcc_l5,
91 rcc_f2,
92 rcc_f4,
93 rcc_f410,
94 rcc_f7,
95 rcc_h5,
96 rcc_h50,
97 rcc_h7,
98 rcc_h7rm0433,
99 rcc_h7ab,
100 rcc_u5,
101 rcc_g4,
102 rcc_wb,
103 rcc_wl5,
104 rcc_wle
105 ))]
106 pub hclk3: Hertz,
107 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))]
108 pub hclk4: Hertz,
109
110 #[cfg(all(rcc_f4, not(stm32f410)))]
111 pub plli2s1_q: Option<Hertz>,
112 #[cfg(all(rcc_f4, not(stm32f410)))]
113 pub plli2s1_r: Option<Hertz>,
114
115 #[cfg(rcc_l4)]
116 pub pllsai1_p: Option<Hertz>,
117 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
118 pub pllsai1_q: Option<Hertz>,
119 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
120 pub pllsai1_r: Option<Hertz>,
121 #[cfg(rcc_l4)]
122 pub pllsai2_p: Option<Hertz>,
123
124 #[cfg(any(stm32g0, stm32g4, rcc_l4))]
125 pub pll1_p: Option<Hertz>,
126 #[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g0, stm32g4))]
127 pub pll1_q: Option<Hertz>,
128 #[cfg(any(stm32h5, stm32h7))]
129 pub pll2_p: Option<Hertz>,
130 #[cfg(any(stm32h5, stm32h7))]
131 pub pll2_q: Option<Hertz>,
132 #[cfg(any(stm32h5, stm32h7))]
133 pub pll2_r: Option<Hertz>,
134 #[cfg(any(stm32h5, stm32h7))]
135 pub pll3_p: Option<Hertz>,
136 #[cfg(any(stm32h5, stm32h7))]
137 pub pll3_q: Option<Hertz>,
138 #[cfg(any(stm32h5, stm32h7))]
139 pub pll3_r: Option<Hertz>,
140
141 #[cfg(any(
142 rcc_f1,
143 rcc_f100,
144 rcc_f1cl,
145 rcc_h5,
146 rcc_h50,
147 rcc_h7,
148 rcc_h7rm0433,
149 rcc_h7ab,
150 rcc_f3,
151 rcc_g4
152 ))]
153 pub adc: Option<Hertz>,
154
155 #[cfg(any(rcc_f3, rcc_g4))]
156 pub adc34: Option<Hertz>,
157
158 #[cfg(stm32f334)]
159 pub hrtim: Option<Hertz>,
160
161 pub rtc: Option<Hertz>,
162
163 #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))]
164 pub hsi: Option<Hertz>,
165 #[cfg(any(stm32h5, stm32g0))]
166 pub hsi48: Option<Hertz>,
167 #[cfg(stm32g0)]
168 pub hsi_div_8: Option<Hertz>,
169 #[cfg(any(stm32g0, stm32h5))]
170 pub lsi: Option<Hertz>,
171 #[cfg(any(stm32h5, stm32h7))]
172 pub csi: Option<Hertz>,
173
174 #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))]
175 pub lse: Option<Hertz>,
176 #[cfg(any(stm32h5, stm32h7, stm32g0, stm32g4))]
177 pub hse: Option<Hertz>,
178
179 #[cfg(stm32h5)]
180 pub audioclk: Option<Hertz>,
181 #[cfg(any(stm32h5, stm32h7))]
182 pub per: Option<Hertz>,
183
184 #[cfg(stm32h7)]
185 pub rcc_pclk_d3: Option<Hertz>,
186 #[cfg(rcc_l4)]
187 pub sai1_extclk: Option<Hertz>,
188 #[cfg(rcc_l4)]
189 pub sai2_extclk: Option<Hertz>,
190}
191 34
192#[cfg(feature = "low-power")] 35#[cfg(feature = "low-power")]
193/// Must be written within a critical section 36/// Must be written within a critical section
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index dff08dc9b..9cec6c96c 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -1,7 +1,6 @@
1pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; 1pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler};
2use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; 2use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw};
3use crate::pac::{FLASH, PWR, RCC}; 3use crate::pac::{FLASH, PWR, RCC};
4use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz; 4use crate::time::Hertz;
6 5
7/// HSI speed 6/// HSI speed
@@ -338,7 +337,7 @@ pub(crate) unsafe fn init(config: Config) {
338 } 337 }
339 }; 338 };
340 339
341 let _hsi48 = config.hsi48.map(super::init_hsi48); 340 let hsi48 = config.hsi48.map(super::init_hsi48);
342 341
343 // The clock source is ready 342 // The clock source is ready
344 // Calculate and set the flash wait states 343 // Calculate and set the flash wait states
@@ -448,18 +447,37 @@ pub(crate) unsafe fn init(config: Config) {
448 447
449 let rtc = config.ls.init(); 448 let rtc = config.ls.init();
450 449
451 set_freqs(Clocks { 450 set_clocks!(
452 sys: sys_clk, 451 sys: Some(sys_clk),
453 hclk1: ahb_freq, 452 hclk1: Some(ahb_freq),
454 hclk2: ahb_freq, 453 hclk2: Some(ahb_freq),
455 hclk3: ahb_freq, 454 hclk3: Some(ahb_freq),
456 pclk1: apb1_freq, 455 pclk1: Some(apb1_freq),
457 pclk2: apb2_freq, 456 pclk2: Some(apb2_freq),
458 pclk3: apb3_freq, 457 pclk3: Some(apb3_freq),
459 pclk1_tim: apb1_tim_freq, 458 pclk1_tim: Some(apb1_tim_freq),
460 pclk2_tim: apb2_tim_freq, 459 pclk2_tim: Some(apb2_tim_freq),
461 rtc, 460 hsi48: hsi48,
462 }); 461 rtc: rtc,
462
463 // TODO
464 hse: None,
465 hsi: None,
466 audioclk: None,
467 hsi48_div_2: None,
468 lse: None,
469 lsi: None,
470 msik: None,
471 pll1_p: None,
472 pll1_q: None,
473 pll1_r: None,
474 pll2_p: None,
475 pll2_q: None,
476 pll2_r: None,
477 pll3_p: None,
478 pll3_q: None,
479 pll3_r: None,
480 );
463} 481}
464 482
465fn msirange_to_hertz(range: Msirange) -> Hertz { 483fn msirange_to_hertz(range: Msirange) -> Hertz {
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index c0cd91507..47ce4783c 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -1,88 +1,118 @@
1use stm32_metapac::rcc::vals::{Pllsrc, Sw}; 1pub use crate::pac::pwr::vals::Vos as VoltageScale;
2 2use crate::pac::rcc::regs::Cfgr1;
3pub use crate::pac::rcc::vals::{
4 Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as ClockSrc,
5};
3use crate::pac::{FLASH, RCC}; 6use crate::pac::{FLASH, RCC};
4use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz; 7use crate::time::Hertz;
6 8
7/// HSI speed 9/// HSI speed
8pub const HSI_FREQ: Hertz = Hertz(16_000_000); 10pub const HSI_FREQ: Hertz = Hertz(16_000_000);
11// HSE speed
12pub const HSE_FREQ: Hertz = Hertz(32_000_000);
9 13
10pub use crate::pac::pwr::vals::Vos as VoltageScale; 14#[derive(Clone, Copy, Eq, PartialEq)]
11pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; 15pub struct Hse {
12 16 pub prescaler: HsePrescaler,
13#[derive(Copy, Clone)]
14pub enum ClockSrc {
15 HSE(Hertz),
16 HSI,
17}
18
19#[derive(Clone, Copy, Debug)]
20pub enum PllSource {
21 HSE(Hertz),
22 HSI,
23}
24
25impl Into<Pllsrc> for PllSource {
26 fn into(self) -> Pllsrc {
27 match self {
28 PllSource::HSE(..) => Pllsrc::HSE,
29 PllSource::HSI => Pllsrc::HSI,
30 }
31 }
32}
33
34impl Into<Sw> for ClockSrc {
35 fn into(self) -> Sw {
36 match self {
37 ClockSrc::HSE(..) => Sw::HSE,
38 ClockSrc::HSI => Sw::HSI,
39 }
40 }
41} 17}
42 18
19/// Clocks configuration
43pub struct Config { 20pub struct Config {
21 // base clock sources
22 pub hsi: bool,
23 pub hse: Option<Hse>,
24
25 // sysclk, buses.
44 pub mux: ClockSrc, 26 pub mux: ClockSrc,
45 pub ahb_pre: AHBPrescaler, 27 pub ahb_pre: AHBPrescaler,
46 pub apb1_pre: APBPrescaler, 28 pub apb1_pre: APBPrescaler,
47 pub apb2_pre: APBPrescaler, 29 pub apb2_pre: APBPrescaler,
48 pub apb7_pre: APBPrescaler, 30 pub apb7_pre: APBPrescaler,
31
32 // low speed LSI/LSE/RTC
49 pub ls: super::LsConfig, 33 pub ls: super::LsConfig,
34
35 pub adc_clock_source: AdcClockSource,
36
37 pub voltage_scale: VoltageScale,
50} 38}
51 39
52impl Default for Config { 40impl Default for Config {
53 fn default() -> Self { 41 #[inline]
54 Self { 42 fn default() -> Config {
43 Config {
44 hse: None,
45 hsi: true,
55 mux: ClockSrc::HSI, 46 mux: ClockSrc::HSI,
56 ahb_pre: AHBPrescaler::DIV1, 47 ahb_pre: AHBPrescaler::DIV1,
57 apb1_pre: APBPrescaler::DIV1, 48 apb1_pre: APBPrescaler::DIV1,
58 apb2_pre: APBPrescaler::DIV1, 49 apb2_pre: APBPrescaler::DIV1,
59 apb7_pre: APBPrescaler::DIV1, 50 apb7_pre: APBPrescaler::DIV1,
60 ls: Default::default(), 51 ls: Default::default(),
52 adc_clock_source: AdcClockSource::HCLK1,
53 voltage_scale: VoltageScale::RANGE2,
61 } 54 }
62 } 55 }
63} 56}
64 57
58fn hsi_enable() {
59 RCC.cr().modify(|w| w.set_hsion(true));
60 while !RCC.cr().read().hsirdy() {}
61}
62
65pub(crate) unsafe fn init(config: Config) { 63pub(crate) unsafe fn init(config: Config) {
66 let sys_clk = match config.mux { 64 // Switch to HSI to prevent problems with PLL configuration.
67 ClockSrc::HSE(freq) => { 65 if !RCC.cr().read().hsion() {
68 RCC.cr().write(|w| w.set_hseon(true)); 66 hsi_enable()
69 while !RCC.cr().read().hserdy() {} 67 }
68 if RCC.cfgr1().read().sws() != ClockSrc::HSI {
69 // Set HSI as a clock source, reset prescalers.
70 RCC.cfgr1().write_value(Cfgr1::default());
71 // Wait for clock switch status bits to change.
72 while RCC.cfgr1().read().sws() != ClockSrc::HSI {}
73 }
70 74
71 freq 75 // Set voltage scale
72 } 76 crate::pac::PWR.vosr().write(|w| w.set_vos(config.voltage_scale));
73 ClockSrc::HSI => { 77 while !crate::pac::PWR.vosr().read().vosrdy() {}
74 RCC.cr().write(|w| w.set_hsion(true));
75 while !RCC.cr().read().hsirdy() {}
76 78
77 HSI_FREQ 79 let rtc = config.ls.init();
78 } 80
81 let hsi = config.hsi.then(|| {
82 hsi_enable();
83
84 HSI_FREQ
85 });
86
87 let hse = config.hse.map(|hse| {
88 RCC.cr().write(|w| {
89 w.set_hseon(true);
90 w.set_hsepre(hse.prescaler);
91 });
92 while !RCC.cr().read().hserdy() {}
93
94 HSE_FREQ
95 });
96
97 let sys_clk = match config.mux {
98 ClockSrc::HSE => hse.unwrap(),
99 ClockSrc::HSI => hsi.unwrap(),
100 ClockSrc::_RESERVED_1 => unreachable!(),
101 ClockSrc::PLL1_R => todo!(),
79 }; 102 };
80 103
81 // TODO make configurable 104 assert!(sys_clk.0 <= 100_000_000);
82 let power_vos = VoltageScale::RANGE1;
83 105
84 // states and programming delay 106 let hclk1 = sys_clk / config.ahb_pre;
85 let wait_states = match power_vos { 107 let hclk2 = hclk1;
108 let hclk4 = hclk1;
109 // TODO: hclk5
110 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
111 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
112 let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre);
113
114 // Set flash wait states
115 let flash_latency = match config.voltage_scale {
86 VoltageScale::RANGE1 => match sys_clk.0 { 116 VoltageScale::RANGE1 => match sys_clk.0 {
87 ..=32_000_000 => 0, 117 ..=32_000_000 => 0,
88 ..=64_000_000 => 1, 118 ..=64_000_000 => 1,
@@ -97,13 +127,24 @@ pub(crate) unsafe fn init(config: Config) {
97 }, 127 },
98 }; 128 };
99 129
100 FLASH.acr().modify(|w| { 130 FLASH.acr().modify(|w| w.set_latency(flash_latency));
101 w.set_latency(wait_states); 131 while FLASH.acr().read().latency() != flash_latency {}
102 }); 132
133 // Set sram wait states
134 let _sram_latency = match config.voltage_scale {
135 VoltageScale::RANGE1 => 0,
136 VoltageScale::RANGE2 => match sys_clk.0 {
137 ..=12_000_000 => 0,
138 ..=16_000_000 => 1,
139 _ => 2,
140 },
141 };
142 // TODO: Set the SRAM wait states
103 143
104 RCC.cfgr1().modify(|w| { 144 RCC.cfgr1().modify(|w| {
105 w.set_sw(config.mux.into()); 145 w.set_sw(config.mux);
106 }); 146 });
147 while RCC.cfgr1().read().sws() != config.mux {}
107 148
108 RCC.cfgr2().modify(|w| { 149 RCC.cfgr2().modify(|w| {
109 w.set_hpre(config.ahb_pre); 150 w.set_hpre(config.ahb_pre);
@@ -111,45 +152,25 @@ pub(crate) unsafe fn init(config: Config) {
111 w.set_ppre2(config.apb2_pre); 152 w.set_ppre2(config.apb2_pre);
112 }); 153 });
113 154
114 RCC.cfgr3().modify(|w| { 155 RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source));
115 w.set_ppre7(config.apb7_pre); 156
116 }); 157 set_clocks!(
117 158 sys: Some(sys_clk),
118 let ahb_freq = sys_clk / config.ahb_pre; 159 hclk1: Some(hclk1),
119 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 160 hclk2: Some(hclk2),
120 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 161 hclk4: Some(hclk4),
121 pre => { 162 pclk1: Some(pclk1),
122 let freq = ahb_freq / pre; 163 pclk2: Some(pclk2),
123 (freq, freq * 2u32) 164 pclk7: Some(pclk7),
124 } 165 pclk1_tim: Some(pclk1_tim),
125 }; 166 pclk2_tim: Some(pclk2_tim),
126 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 167 rtc: rtc,
127 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 168 hse: hse,
128 pre => { 169 hsi: hsi,
129 let freq = ahb_freq / pre; 170
130 (freq, freq * 2u32) 171 // TODO
131 } 172 lse: None,
132 }; 173 lsi: None,
133 let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre { 174 pll1_q: None,
134 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 175 );
135 pre => {
136 let freq = ahb_freq / pre;
137 (freq, freq * 2u32)
138 }
139 };
140
141 let rtc = config.ls.init();
142
143 set_freqs(Clocks {
144 sys: sys_clk,
145 hclk1: ahb_freq,
146 hclk2: ahb_freq,
147 hclk4: ahb_freq,
148 pclk1: apb1_freq,
149 pclk2: apb2_freq,
150 pclk7: apb7_freq,
151 pclk1_tim: apb1_tim_freq,
152 pclk2_tim: apb2_tim_freq,
153 rtc,
154 });
155} 176}
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index debe26c88..61589a215 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -670,7 +670,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
670 _ => panic!("Invalid Bus Width"), 670 _ => panic!("Invalid Bus Width"),
671 }; 671 };
672 672
673 let ker_ck = T::kernel_clk(); 673 let ker_ck = T::frequency();
674 let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; 674 let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?;
675 675
676 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 676 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
@@ -1023,7 +1023,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1023 /// specified frequency. 1023 /// specified frequency.
1024 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { 1024 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
1025 let regs = T::regs(); 1025 let regs = T::regs();
1026 let ker_ck = T::kernel_clk(); 1026 let ker_ck = T::frequency();
1027 1027
1028 let bus_width = match self.d3.is_some() { 1028 let bus_width = match self.d3.is_some() {
1029 true => BusWidth::Four, 1029 true => BusWidth::Four,
@@ -1429,7 +1429,6 @@ pub(crate) mod sealed {
1429 1429
1430 fn regs() -> RegBlock; 1430 fn regs() -> RegBlock;
1431 fn state() -> &'static AtomicWaker; 1431 fn state() -> &'static AtomicWaker;
1432 fn kernel_clk() -> Hertz;
1433 } 1432 }
1434 1433
1435 pub trait Pins<T: Instance> {} 1434 pub trait Pins<T: Instance> {}
@@ -1461,61 +1460,6 @@ pub trait SdmmcDma<T: Instance> {}
1461#[cfg(sdmmc_v2)] 1460#[cfg(sdmmc_v2)]
1462impl<T: Instance> SdmmcDma<T> for NoDma {} 1461impl<T: Instance> SdmmcDma<T> for NoDma {}
1463 1462
1464cfg_if::cfg_if! {
1465 // TODO, these could not be implemented, because required clocks are not exposed in RCC:
1466 // - H7 uses pll1_q_ck or pll2_r_ck depending on SDMMCSEL
1467 // - L1 uses pll48
1468 // - L4 uses clk48(pll48)
1469 // - L4+, L5, U5 uses clk48(pll48) or PLLSAI3CLK(PLLP) depending on SDMMCSEL
1470 if #[cfg(stm32f1)] {
1471 // F1 uses AHB1(HCLK), which is correct in PAC
1472 macro_rules! kernel_clk {
1473 ($inst:ident) => {
1474 <peripherals::$inst as crate::rcc::sealed::RccPeripheral>::frequency()
1475 }
1476 }
1477 } else if #[cfg(any(stm32f2, stm32f4))] {
1478 // F2, F4 always use pll48
1479 macro_rules! kernel_clk {
1480 ($inst:ident) => {
1481 critical_section::with(|_| unsafe {
1482 unwrap!(crate::rcc::get_freqs().pll1_q)
1483 })
1484 }
1485 }
1486 } else if #[cfg(stm32f7)] {
1487 macro_rules! kernel_clk {
1488 (SDMMC1) => {
1489 critical_section::with(|_| unsafe {
1490 let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc1sel();
1491 if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYS {
1492 crate::rcc::get_freqs().sys
1493 } else {
1494 unwrap!(crate::rcc::get_freqs().pll1_q)
1495 }
1496 })
1497 };
1498 (SDMMC2) => {
1499 critical_section::with(|_| unsafe {
1500 let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc2sel();
1501 if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYS {
1502 crate::rcc::get_freqs().sys
1503 } else {
1504 unwrap!(crate::rcc::get_freqs().pll1_q)
1505 }
1506 })
1507 };
1508 }
1509 } else {
1510 // Use default peripheral clock and hope it works
1511 macro_rules! kernel_clk {
1512 ($inst:ident) => {
1513 <peripherals::$inst as crate::rcc::sealed::RccPeripheral>::frequency()
1514 }
1515 }
1516 }
1517}
1518
1519foreach_peripheral!( 1463foreach_peripheral!(
1520 (sdmmc, $inst:ident) => { 1464 (sdmmc, $inst:ident) => {
1521 impl sealed::Instance for peripherals::$inst { 1465 impl sealed::Instance for peripherals::$inst {
@@ -1529,10 +1473,6 @@ foreach_peripheral!(
1529 static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new(); 1473 static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new();
1530 &WAKER 1474 &WAKER
1531 } 1475 }
1532
1533 fn kernel_clk() -> Hertz {
1534 kernel_clk!($inst)
1535 }
1536 } 1476 }
1537 1477
1538 impl Instance for peripherals::$inst {} 1478 impl Instance for peripherals::$inst {}
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 71d7110b5..eddce0404 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -54,6 +54,7 @@ pub struct ComplementaryPwm<'d, T> {
54 54
55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
56 /// Create a new complementary PWM driver. 56 /// Create a new complementary PWM driver.
57 #[allow(clippy::too_many_arguments)]
57 pub fn new( 58 pub fn new(
58 tim: impl Peripheral<P = T> + 'd, 59 tim: impl Peripheral<P = T> + 'd,
59 _ch1: Option<PwmPin<'d, T, Ch1>>, 60 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -165,7 +166,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C
165 } 166 }
166 167
167 fn get_period(&self) -> Self::Time { 168 fn get_period(&self) -> Self::Time {
168 self.inner.get_frequency().into() 169 self.inner.get_frequency()
169 } 170 }
170 171
171 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 172 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index d07fd2776..210bf7153 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -311,6 +311,26 @@ pub(crate) mod sealed {
311 .ccmr_output(channel_index / 2) 311 .ccmr_output(channel_index / 2)
312 .modify(|w| w.set_ocpe(channel_index % 2, preload)); 312 .modify(|w| w.set_ocpe(channel_index % 2, preload));
313 } 313 }
314
315 /// Get capture compare DMA selection
316 fn get_cc_dma_selection(&self) -> super::vals::Ccds {
317 Self::regs_gp16().cr2().read().ccds()
318 }
319
320 /// Set capture compare DMA selection
321 fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) {
322 Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
323 }
324
325 /// Get capture compare DMA enable state
326 fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
327 Self::regs_gp16().dier().read().ccde(channel.index())
328 }
329
330 /// Set capture compare DMA enable state
331 fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) {
332 Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
333 }
314 } 334 }
315 335
316 /// Capture/Compare 16-bit timer instance with complementary pin support. 336 /// Capture/Compare 16-bit timer instance with complementary pin support.
@@ -450,20 +470,17 @@ pub enum CountingMode {
450impl CountingMode { 470impl CountingMode {
451 /// Return whether this mode is edge-aligned (up or down). 471 /// Return whether this mode is edge-aligned (up or down).
452 pub fn is_edge_aligned(&self) -> bool { 472 pub fn is_edge_aligned(&self) -> bool {
453 match self { 473 matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
454 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
455 _ => false,
456 }
457 } 474 }
458 475
459 /// Return whether this mode is center-aligned. 476 /// Return whether this mode is center-aligned.
460 pub fn is_center_aligned(&self) -> bool { 477 pub fn is_center_aligned(&self) -> bool {
461 match self { 478 matches!(
479 self,
462 CountingMode::CenterAlignedDownInterrupts 480 CountingMode::CenterAlignedDownInterrupts
463 | CountingMode::CenterAlignedUpInterrupts 481 | CountingMode::CenterAlignedUpInterrupts
464 | CountingMode::CenterAlignedBothInterrupts => true, 482 | CountingMode::CenterAlignedBothInterrupts
465 _ => false, 483 )
466 }
467 } 484 }
468} 485}
469 486
@@ -705,3 +722,8 @@ foreach_interrupt! {
705 722
706// Update Event trigger DMA for every timer 723// Update Event trigger DMA for every timer
707dma_trait!(UpDma, Basic16bitInstance); 724dma_trait!(UpDma, Basic16bitInstance);
725
726dma_trait!(Ch1Dma, CaptureCompare16bitInstance);
727dma_trait!(Ch2Dma, CaptureCompare16bitInstance);
728dma_trait!(Ch3Dma, CaptureCompare16bitInstance);
729dma_trait!(Ch4Dma, CaptureCompare16bitInstance);
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 83a3e9291..0b4c1225f 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -160,7 +160,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
160 /// 160 ///
161 /// Note: 161 /// Note:
162 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 162 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
163 pub async fn gen_waveform( 163 pub async fn waveform_up(
164 &mut self, 164 &mut self,
165 dma: impl Peripheral<P = impl super::UpDma<T>>, 165 dma: impl Peripheral<P = impl super::UpDma<T>>,
166 channel: Channel, 166 channel: Channel,
@@ -226,6 +226,95 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
226 } 226 }
227} 227}
228 228
229macro_rules! impl_waveform_chx {
230 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
231 impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
232 /// Generate a sequence of PWM waveform
233 ///
234 /// Note:
235 /// you will need to provide corresponding TIMx_CHy DMA channel to use this method.
236 pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) {
237 use super::vals::Ccds;
238
239 assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
240
241 into_ref!(dma);
242
243 #[allow(clippy::let_unit_value)] // eg. stm32f334
244 let req = dma.request();
245
246 let cc_channel = super::Channel::$cc_ch;
247
248 let original_duty_state = self.get_duty(cc_channel);
249 let original_enable_state = self.is_enabled(cc_channel);
250 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE;
251 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
252
253 // redirect CC DMA request onto Update Event
254 if !original_cc_dma_on_update {
255 self.inner.set_cc_dma_selection(Ccds::ONUPDATE)
256 }
257
258 if !original_cc_dma_enabled {
259 self.inner.set_cc_dma_enable_state(cc_channel, true);
260 }
261
262 if !original_enable_state {
263 self.enable(cc_channel);
264 }
265
266 unsafe {
267 #[cfg(not(any(bdma, gpdma)))]
268 use crate::dma::{Burst, FifoThreshold};
269 use crate::dma::{Transfer, TransferOptions};
270
271 let dma_transfer_option = TransferOptions {
272 #[cfg(not(any(bdma, gpdma)))]
273 fifo_threshold: Some(FifoThreshold::Full),
274 #[cfg(not(any(bdma, gpdma)))]
275 mburst: Burst::Incr8,
276 ..Default::default()
277 };
278
279 Transfer::new_write(
280 &mut dma,
281 req,
282 duty,
283 T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _,
284 dma_transfer_option,
285 )
286 .await
287 };
288
289 // restore output compare state
290 if !original_enable_state {
291 self.disable(cc_channel);
292 }
293
294 self.set_duty(cc_channel, original_duty_state);
295
296 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
297 // this can almost always trigger a DMA FIFO error.
298 //
299 // optional TODO:
300 // clean FEIF after disable UDE
301 if !original_cc_dma_enabled {
302 self.inner.set_cc_dma_enable_state(cc_channel, false);
303 }
304
305 if !original_cc_dma_on_update {
306 self.inner.set_cc_dma_selection(Ccds::ONCOMPARE)
307 }
308 }
309 }
310 };
311}
312
313impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1);
314impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
315impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
316impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
317
229impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { 318impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> {
230 type Channel = Channel; 319 type Channel = Channel;
231 type Time = Hertz; 320 type Time = Hertz;
@@ -240,7 +329,7 @@ impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d,
240 } 329 }
241 330
242 fn get_period(&self) -> Self::Time { 331 fn get_period(&self) -> Self::Time {
243 self.inner.get_frequency().into() 332 self.inner.get_frequency()
244 } 333 }
245 334
246 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 335 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index f39915906..34d6b52fd 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -280,7 +280,7 @@ impl<'d, T: Instance> Driver<'d, T> {
280 #[cfg(time)] 280 #[cfg(time)]
281 embassy_time::block_for(embassy_time::Duration::from_millis(100)); 281 embassy_time::block_for(embassy_time::Duration::from_millis(100));
282 #[cfg(not(time))] 282 #[cfg(not(time))]
283 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10); 283 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10);
284 284
285 #[cfg(not(usb_v4))] 285 #[cfg(not(usb_v4))]
286 regs.btable().write(|w| w.set_btable(0)); 286 regs.btable().write(|w| w.set_btable(0));
diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs
index bd75c0135..e77678c24 100644
--- a/embassy-sync/src/priority_channel.rs
+++ b/embassy-sync/src/priority_channel.rs
@@ -325,7 +325,7 @@ where
325/// 325///
326/// Sent data may be reordered based on their priorty within the channel. 326/// Sent data may be reordered based on their priorty within the channel.
327/// For example, in a [`Max`](heapless::binary_heap::Max) [`PriorityChannel`] 327/// For example, in a [`Max`](heapless::binary_heap::Max) [`PriorityChannel`]
328/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be recieved as `[3, 2, 1]`. 328/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be received as `[3, 2, 1]`.
329pub struct PriorityChannel<M, T, K, const N: usize> 329pub struct PriorityChannel<M, T, K, const N: usize>
330where 330where
331 T: Ord, 331 T: Ord,
diff --git a/embassy-sync/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs
index d95ffa7c9..81e60c42b 100644
--- a/embassy-sync/src/ring_buffer.rs
+++ b/embassy-sync/src/ring_buffer.rs
@@ -3,7 +3,7 @@ use core::ops::Range;
3pub struct RingBuffer<const N: usize> { 3pub struct RingBuffer<const N: usize> {
4 start: usize, 4 start: usize,
5 end: usize, 5 end: usize,
6 empty: bool, 6 full: bool,
7} 7}
8 8
9impl<const N: usize> RingBuffer<N> { 9impl<const N: usize> RingBuffer<N> {
@@ -11,13 +11,13 @@ impl<const N: usize> RingBuffer<N> {
11 Self { 11 Self {
12 start: 0, 12 start: 0,
13 end: 0, 13 end: 0,
14 empty: true, 14 full: false,
15 } 15 }
16 } 16 }
17 17
18 pub fn push_buf(&mut self) -> Range<usize> { 18 pub fn push_buf(&mut self) -> Range<usize> {
19 if self.start == self.end && !self.empty { 19 if self.is_full() {
20 trace!(" ringbuf: push_buf empty"); 20 trace!(" ringbuf: push_buf full");
21 return 0..0; 21 return 0..0;
22 } 22 }
23 23
@@ -38,11 +38,11 @@ impl<const N: usize> RingBuffer<N> {
38 } 38 }
39 39
40 self.end = self.wrap(self.end + n); 40 self.end = self.wrap(self.end + n);
41 self.empty = false; 41 self.full = self.start == self.end;
42 } 42 }
43 43
44 pub fn pop_buf(&mut self) -> Range<usize> { 44 pub fn pop_buf(&mut self) -> Range<usize> {
45 if self.empty { 45 if self.is_empty() {
46 trace!(" ringbuf: pop_buf empty"); 46 trace!(" ringbuf: pop_buf empty");
47 return 0..0; 47 return 0..0;
48 } 48 }
@@ -64,20 +64,20 @@ impl<const N: usize> RingBuffer<N> {
64 } 64 }
65 65
66 self.start = self.wrap(self.start + n); 66 self.start = self.wrap(self.start + n);
67 self.empty = self.start == self.end; 67 self.full = false;
68 } 68 }
69 69
70 pub fn is_full(&self) -> bool { 70 pub fn is_full(&self) -> bool {
71 self.start == self.end && !self.empty 71 self.full
72 } 72 }
73 73
74 pub fn is_empty(&self) -> bool { 74 pub fn is_empty(&self) -> bool {
75 self.empty 75 self.start == self.end && !self.full
76 } 76 }
77 77
78 #[allow(unused)] 78 #[allow(unused)]
79 pub fn len(&self) -> usize { 79 pub fn len(&self) -> usize {
80 if self.empty { 80 if self.is_empty() {
81 0 81 0
82 } else if self.start < self.end { 82 } else if self.start < self.end {
83 self.end - self.start 83 self.end - self.start
@@ -89,7 +89,7 @@ impl<const N: usize> RingBuffer<N> {
89 pub fn clear(&mut self) { 89 pub fn clear(&mut self) {
90 self.start = 0; 90 self.start = 0;
91 self.end = 0; 91 self.end = 0;
92 self.empty = true; 92 self.full = false;
93 } 93 }
94 94
95 fn wrap(&self, n: usize) -> usize { 95 fn wrap(&self, n: usize) -> usize {
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs
index d27eb92f6..3c8575ee9 100644
--- a/embassy-time/src/lib.rs
+++ b/embassy-time/src/lib.rs
@@ -32,7 +32,7 @@ pub use delay::{block_for, Delay};
32pub use duration::Duration; 32pub use duration::Duration;
33pub use embassy_time_driver::TICK_HZ; 33pub use embassy_time_driver::TICK_HZ;
34pub use instant::Instant; 34pub use instant::Instant;
35pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; 35pub use timer::{with_deadline, with_timeout, Ticker, TimeoutError, Timer};
36 36
37const fn gcd(a: u64, b: u64) -> u64 { 37const fn gcd(a: u64, b: u64) -> u64 {
38 if b == 0 { 38 if b == 0 {
diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs
index 565a65cb8..daa4c1699 100644
--- a/embassy-time/src/timer.rs
+++ b/embassy-time/src/timer.rs
@@ -8,7 +8,7 @@ use futures_util::{pin_mut, Stream};
8 8
9use crate::{Duration, Instant}; 9use crate::{Duration, Instant};
10 10
11/// Error returned by [`with_timeout`] on timeout. 11/// Error returned by [`with_timeout`] and [`with_deadline`] on timeout.
12#[derive(Debug, Clone, PartialEq, Eq)] 12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))] 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14pub struct TimeoutError; 14pub struct TimeoutError;
@@ -26,6 +26,19 @@ pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Out
26 } 26 }
27} 27}
28 28
29/// Runs a given future with a deadline time.
30///
31/// If the future completes before the deadline, its output is returned. Otherwise, on timeout,
32/// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned.
33pub async fn with_deadline<F: Future>(at: Instant, fut: F) -> Result<F::Output, TimeoutError> {
34 let timeout_fut = Timer::at(at);
35 pin_mut!(fut);
36 match select(fut, timeout_fut).await {
37 Either::Left((r, _)) => Ok(r),
38 Either::Right(_) => Err(TimeoutError),
39 }
40}
41
29/// A future that completes at a specified [Instant](struct.Instant.html). 42/// A future that completes at a specified [Instant](struct.Instant.html).
30#[must_use = "futures do nothing unless you `.await` or poll them"] 43#[must_use = "futures do nothing unless you `.await` or poll them"]
31pub struct Timer { 44pub struct Timer {
diff --git a/examples/nrf51/.cargo/config.toml b/examples/nrf51/.cargo/config.toml
new file mode 100644
index 000000000..1671f5db1
--- /dev/null
+++ b/examples/nrf51/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF51422_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip nRF51422_xxAA"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml
new file mode 100644
index 000000000..d1e919a33
--- /dev/null
+++ b/examples/nrf51/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2edition = "2021"
3name = "embassy-nrf51-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
11
12defmt = "0.3"
13defmt-rtt = "0.4"
14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7"
17panic-probe = { version = "0.3", features = ["print-defmt"] }
18
19[profile.release]
20debug = 2
diff --git a/examples/nrf51/build.rs b/examples/nrf51/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf51/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/nrf51/memory.x b/examples/nrf51/memory.x
new file mode 100644
index 000000000..98b3c792f
--- /dev/null
+++ b/examples/nrf51/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 128K
4 RAM : ORIGIN = 0x20000000, LENGTH = 16K
5}
diff --git a/examples/nrf51/src/bin/blinky.rs b/examples/nrf51/src/bin/blinky.rs
new file mode 100644
index 000000000..7c12ffcbc
--- /dev/null
+++ b/examples/nrf51/src/bin/blinky.rs
@@ -0,0 +1,20 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::gpio::{Level, Output, OutputDrive};
6use embassy_time::Timer;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_nrf::init(Default::default());
12 let mut led = Output::new(p.P0_21, Level::Low, OutputDrive::Standard);
13
14 loop {
15 led.set_high();
16 Timer::after_millis(300).await;
17 led.set_low();
18 Timer::after_millis(300).await;
19 }
20}
diff --git a/examples/rp/src/bin/debounce.rs b/examples/rp/src/bin/debounce.rs
new file mode 100644
index 000000000..0077f19fc
--- /dev/null
+++ b/examples/rp/src/bin/debounce.rs
@@ -0,0 +1,80 @@
1//! This example shows the ease of debouncing a button with async rust.
2//! Hook up a button or switch between pin 9 and ground.
3
4#![no_std]
5#![no_main]
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_rp::gpio::{Input, Level, Pull};
10use embassy_time::{with_deadline, Duration, Instant, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13pub struct Debouncer<'a> {
14 input: Input<'a>,
15 debounce: Duration,
16}
17
18impl<'a> Debouncer<'a> {
19 pub fn new(input: Input<'a>, debounce: Duration) -> Self {
20 Self { input, debounce }
21 }
22
23 pub async fn debounce(&mut self) -> Level {
24 loop {
25 let l1 = self.input.get_level();
26
27 self.input.wait_for_any_edge().await;
28
29 Timer::after(self.debounce).await;
30
31 let l2 = self.input.get_level();
32 if l1 != l2 {
33 break l2;
34 }
35 }
36 }
37}
38
39#[embassy_executor::main]
40async fn main(_spawner: Spawner) {
41 let p = embassy_rp::init(Default::default());
42 let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20));
43
44 info!("Debounce Demo");
45
46 loop {
47 // button pressed
48 btn.debounce().await;
49 let start = Instant::now();
50 info!("Button Press");
51
52 match with_deadline(start + Duration::from_secs(1), btn.debounce()).await {
53 // Button Released < 1s
54 Ok(_) => {
55 info!("Button pressed for: {}ms", start.elapsed().as_millis());
56 continue;
57 }
58 // button held for > 1s
59 Err(_) => {
60 info!("Button Held");
61 }
62 }
63
64 match with_deadline(start + Duration::from_secs(5), btn.debounce()).await {
65 // Button released <5s
66 Ok(_) => {
67 info!("Button pressed for: {}ms", start.elapsed().as_millis());
68 continue;
69 }
70 // button held for > >5s
71 Err(_) => {
72 info!("Button Long Held");
73 }
74 }
75
76 // wait for button release before handling another press
77 btn.debounce().await;
78 info!("Button pressed for: {}ms", start.elapsed().as_millis());
79 }
80}
diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs
index 479f9a16a..ac470d2be 100644
--- a/examples/rp/src/bin/i2c_slave.rs
+++ b/examples/rp/src/bin/i2c_slave.rs
@@ -26,7 +26,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
26 loop { 26 loop {
27 let mut buf = [0u8; 128]; 27 let mut buf = [0u8; 128];
28 match dev.listen(&mut buf).await { 28 match dev.listen(&mut buf).await {
29 Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device recieved general call write: {}", buf[..len]), 29 Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device received general call write: {}", buf[..len]),
30 Ok(i2c_slave::Command::Read) => loop { 30 Ok(i2c_slave::Command::Read) => loop {
31 match dev.respond_to_read(&[state]).await { 31 match dev.respond_to_read(&[state]).await {
32 Ok(x) => match x { 32 Ok(x) => match x {
@@ -40,9 +40,9 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
40 Err(e) => error!("error while responding {}", e), 40 Err(e) => error!("error while responding {}", e),
41 } 41 }
42 }, 42 },
43 Ok(i2c_slave::Command::Write(len)) => info!("Device recieved write: {}", buf[..len]), 43 Ok(i2c_slave::Command::Write(len)) => info!("Device received write: {}", buf[..len]),
44 Ok(i2c_slave::Command::WriteRead(len)) => { 44 Ok(i2c_slave::Command::WriteRead(len)) => {
45 info!("device recieved write read: {:x}", buf[..len]); 45 info!("device received write read: {:x}", buf[..len]);
46 match buf[0] { 46 match buf[0] {
47 // Set the state 47 // Set the state
48 0xC2 => { 48 0xC2 => {
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs
index 239709253..6122cea2d 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm.rs
@@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) {
91 loop { 91 loop {
92 for &color in color_list { 92 for &color in color_list {
93 // with &mut, we can easily reuse same DMA channel multiple times 93 // with &mut, we can easily reuse same DMA channel multiple times
94 ws2812_pwm.gen_waveform(&mut dp.DMA1_CH2, pwm_channel, color).await; 94 ws2812_pwm.waveform_up(&mut dp.DMA1_CH2, pwm_channel, color).await;
95 // ws2812 need at least 50 us low level input to confirm the input data and change it's state 95 // ws2812 need at least 50 us low level input to confirm the input data and change it's state
96 Timer::after_micros(50).await; 96 Timer::after_micros(50).await;
97 // wait until ticker tick 97 // wait until ticker tick
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]
3use defmt::*;
4use embassy_executor::Spawner;
5use embassy_stm32::peripherals::*;
6use embassy_stm32::{bind_interrupts, can, Config};
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _};
9
10bind_interrupts!(struct Irqs {
11 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
12 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
13});
14
15#[embassy_executor::main]
16async 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
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::peripherals::*;
7use embassy_stm32::{bind_interrupts, can, rcc, Config};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
13 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
14});
15
16#[embassy_executor::main]
17async 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
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::peripherals::*;
7use embassy_stm32::{bind_interrupts, can, rcc, Config};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
13 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
14});
15
16#[embassy_executor::main]
17async 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/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index dcc6e36e2..aeb169e19 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -65,6 +65,7 @@ async fn main(spawner: Spawner) -> ! {
65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
66 66
67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); 67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
68
68 let device = Ethernet::new( 69 let device = Ethernet::new(
69 PACKETS.init(PacketQueue::<16, 16>::new()), 70 PACKETS.init(PacketQueue::<16, 16>::new()),
70 p.ETH, 71 p.ETH,
diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs
new file mode 100644
index 000000000..de6ea522a
--- /dev/null
+++ b/examples/stm32h7/src/bin/eth_client_mii.rs
@@ -0,0 +1,142 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_net::tcp::client::{TcpClient, TcpClientState};
7use embassy_net::{Stack, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH;
11use embassy_stm32::rng::Rng;
12use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
13use embassy_time::Timer;
14use embedded_io_async::Write;
15use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect};
16use rand_core::RngCore;
17use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 ETH => eth::InterruptHandler;
22 RNG => rng::InterruptHandler<peripherals::RNG>;
23});
24
25type Device = Ethernet<'static, ETH, GenericSMI>;
26
27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! {
29 stack.run().await
30}
31
32#[embassy_executor::main]
33async fn main(spawner: Spawner) -> ! {
34 let mut config = Config::default();
35 {
36 use embassy_stm32::rcc::*;
37 config.rcc.hsi = Some(HSIPrescaler::DIV1);
38 config.rcc.csi = true;
39 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
40 config.rcc.pll1 = Some(Pll {
41 source: PllSource::HSI,
42 prediv: PllPreDiv::DIV4,
43 mul: PllMul::MUL50,
44 divp: Some(PllDiv::DIV2),
45 divq: None,
46 divr: None,
47 });
48 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
49 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
50 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
51 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
53 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
54 config.rcc.voltage_scale = VoltageScale::Scale1;
55 }
56 let p = embassy_stm32::init(config);
57 info!("Hello World!");
58
59 // Generate random seed.
60 let mut rng = Rng::new(p.RNG, Irqs);
61 let mut seed = [0; 8];
62 rng.fill_bytes(&mut seed);
63 let seed = u64::from_le_bytes(seed);
64
65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
66
67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
68
69 let device = Ethernet::new_mii(
70 PACKETS.init(PacketQueue::<16, 16>::new()),
71 p.ETH,
72 Irqs,
73 p.PA1,
74 p.PC3,
75 p.PA2,
76 p.PC1,
77 p.PA7,
78 p.PC4,
79 p.PC5,
80 p.PB0,
81 p.PB1,
82 p.PG13,
83 p.PG12,
84 p.PC2,
85 p.PE2,
86 p.PG11,
87 GenericSMI::new(1),
88 mac_addr,
89 );
90 info!("Device created");
91
92 let config = embassy_net::Config::dhcpv4(Default::default());
93 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
94 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
95 // dns_servers: Vec::new(),
96 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
97 //});
98
99 // Init network stack
100 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
102 let stack = &*STACK.init(Stack::new(
103 device,
104 config,
105 RESOURCES.init(StackResources::<3>::new()),
106 seed,
107 ));
108
109 // Launch network task
110 unwrap!(spawner.spawn(net_task(stack)));
111
112 // Ensure DHCP configuration is up before trying connect
113 stack.wait_config_up().await;
114
115 info!("Network task initialized");
116
117 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
118 let client = TcpClient::new(&stack, &state);
119
120 loop {
121 // You need to start a server on the host machine, for example: `nc -l 8000`
122 let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 100, 1), 8000));
123
124 info!("connecting...");
125 let r = client.connect(addr).await;
126 if let Err(e) = r {
127 info!("connect error: {:?}", e);
128 Timer::after_secs(1).await;
129 continue;
130 }
131 let mut connection = r.unwrap();
132 info!("connected!");
133 loop {
134 let r = connection.write_all(b"Hello\n").await;
135 if let Err(e) = r {
136 info!("write error: {:?}", e);
137 break;
138 }
139 Timer::after_secs(1).await;
140 }
141 }
142}
diff --git a/tests/nrf51422/.cargo/config.toml b/tests/nrf51422/.cargo/config.toml
new file mode 100644
index 000000000..634805633
--- /dev/null
+++ b/tests/nrf51422/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "teleprobe local run --chip nRF51422_xxAA --elf"
3runner = "teleprobe client run"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace,embassy_hal_internal=debug"
diff --git a/tests/nrf51422/Cargo.toml b/tests/nrf51422/Cargo.toml
new file mode 100644
index 000000000..2cab20ac0
--- /dev/null
+++ b/tests/nrf51422/Cargo.toml
@@ -0,0 +1,22 @@
1[package]
2edition = "2021"
3name = "embassy-nrf51-tests"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8teleprobe-meta = "1"
9
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt", ] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-128", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time"] }
14embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
15embedded-hal-async = { version = "1.0" }
16
17defmt = "0.3"
18defmt-rtt = "0.4"
19
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0"
22panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/tests/nrf51422/build.rs b/tests/nrf51422/build.rs
new file mode 100644
index 000000000..13ebbe4ee
--- /dev/null
+++ b/tests/nrf51422/build.rs
@@ -0,0 +1,17 @@
1use std::error::Error;
2use std::path::PathBuf;
3use std::{env, fs};
4
5fn main() -> Result<(), Box<dyn Error>> {
6 let out = PathBuf::from(env::var("OUT_DIR").unwrap());
7 fs::write(out.join("memory.x"), include_bytes!("memory.x")).unwrap();
8 println!("cargo:rustc-link-search={}", out.display());
9 println!("cargo:rerun-if-changed=memory.x");
10
11 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink.x");
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
14 println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
15
16 Ok(())
17}
diff --git a/tests/nrf51422/memory.x b/tests/nrf51422/memory.x
new file mode 100644
index 000000000..a5881e66f
--- /dev/null
+++ b/tests/nrf51422/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 128K
4 RAM : ORIGIN = 0x20000000, LENGTH = 16K
5}
diff --git a/tests/nrf51422/src/bin/gpio.rs b/tests/nrf51422/src/bin/gpio.rs
new file mode 100644
index 000000000..6d5a87d0a
--- /dev/null
+++ b/tests/nrf51422/src/bin/gpio.rs
@@ -0,0 +1,28 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"nrf51-dk");
4
5use defmt::{assert, info};
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14
15 let input = Input::new(p.P0_13, Pull::Up);
16 let mut output = Output::new(p.P0_14, Level::Low, OutputDrive::Standard);
17
18 output.set_low();
19 Timer::after_millis(10).await;
20 assert!(input.is_low());
21
22 output.set_high();
23 Timer::after_millis(10).await;
24 assert!(input.is_high());
25
26 info!("Test OK");
27 cortex_m::asm::bkpt();
28}
diff --git a/tests/nrf51422/src/bin/timer.rs b/tests/nrf51422/src/bin/timer.rs
new file mode 100644
index 000000000..cf9ea41a8
--- /dev/null
+++ b/tests/nrf51422/src/bin/timer.rs
@@ -0,0 +1,24 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"nrf51-dk");
4
5use defmt::{assert, info};
6use embassy_executor::Spawner;
7use embassy_time::{Instant, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let _p = embassy_nrf::init(Default::default());
13 info!("Hello World!");
14
15 let start = Instant::now();
16 Timer::after_millis(100).await;
17 let end = Instant::now();
18 let ms = (end - start).as_millis();
19 info!("slept for {} ms", ms);
20 assert!(ms >= 99);
21
22 info!("Test OK");
23 cortex_m::asm::bkpt();
24}
diff --git a/tests/nrf/.cargo/config.toml b/tests/nrf52840/.cargo/config.toml
index 9d6b0313a..9d6b0313a 100644
--- a/tests/nrf/.cargo/config.toml
+++ b/tests/nrf52840/.cargo/config.toml
diff --git a/tests/nrf/Cargo.toml b/tests/nrf52840/Cargo.toml
index 84ca99f1f..84ca99f1f 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf52840/Cargo.toml
diff --git a/tests/nrf/build.rs b/tests/nrf52840/build.rs
index 71c82a70f..71c82a70f 100644
--- a/tests/nrf/build.rs
+++ b/tests/nrf52840/build.rs
diff --git a/tests/nrf/memory.x b/tests/nrf52840/memory.x
index 58900a7bd..58900a7bd 100644
--- a/tests/nrf/memory.x
+++ b/tests/nrf52840/memory.x
diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf52840/src/bin/buffered_uart.rs
index 354d787b4..354d787b4 100644
--- a/tests/nrf/src/bin/buffered_uart.rs
+++ b/tests/nrf52840/src/bin/buffered_uart.rs
diff --git a/tests/nrf/src/bin/buffered_uart_full.rs b/tests/nrf52840/src/bin/buffered_uart_full.rs
index e59c75ba9..e59c75ba9 100644
--- a/tests/nrf/src/bin/buffered_uart_full.rs
+++ b/tests/nrf52840/src/bin/buffered_uart_full.rs
diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf52840/src/bin/buffered_uart_spam.rs
index 400c0df99..400c0df99 100644
--- a/tests/nrf/src/bin/buffered_uart_spam.rs
+++ b/tests/nrf52840/src/bin/buffered_uart_spam.rs
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf52840/src/bin/ethernet_enc28j60_perf.rs
index 33c2f4235..33c2f4235 100644
--- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
+++ b/tests/nrf52840/src/bin/ethernet_enc28j60_perf.rs
diff --git a/tests/nrf/src/bin/timer.rs b/tests/nrf52840/src/bin/timer.rs
index 2a147e7ba..117947a94 100644
--- a/tests/nrf/src/bin/timer.rs
+++ b/tests/nrf52840/src/bin/timer.rs
@@ -18,7 +18,6 @@ async fn main(_spawner: Spawner) {
18 let ms = (end - start).as_millis(); 18 let ms = (end - start).as_millis();
19 info!("slept for {} ms", ms); 19 info!("slept for {} ms", ms);
20 assert!(ms >= 99); 20 assert!(ms >= 99);
21 assert!(ms < 110);
22 21
23 info!("Test OK"); 22 info!("Test OK");
24 cortex_m::asm::bkpt(); 23 cortex_m::asm::bkpt();
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf52840/src/bin/wifi_esp_hosted_perf.rs
index b83edddc4..b83edddc4 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf52840/src/bin/wifi_esp_hosted_perf.rs
diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs
index 77d628cf6..a0aed1a42 100644
--- a/tests/rp/src/bin/i2c.rs
+++ b/tests/rp/src/bin/i2c.rs
@@ -80,7 +80,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
80 _ => panic!("Invalid write length {}", len), 80 _ => panic!("Invalid write length {}", len),
81 }, 81 },
82 Ok(i2c_slave::Command::WriteRead(len)) => { 82 Ok(i2c_slave::Command::WriteRead(len)) => {
83 info!("device recieved write read: {:x}", buf[..len]); 83 info!("device received write read: {:x}", buf[..len]);
84 match buf[0] { 84 match buf[0] {
85 0xC2 => { 85 0xC2 => {
86 let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4]; 86 let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4];
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
14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] 14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] 15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] 16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"] 17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"]
18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] 18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"]
19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"] 19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"]
20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"] 20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"]
21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"] 21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] 22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
23stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] 23stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] 24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]
@@ -37,6 +37,7 @@ sdmmc = []
37stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] 37stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"]
38chrono = ["embassy-stm32/chrono", "dep:chrono"] 38chrono = ["embassy-stm32/chrono", "dep:chrono"]
39can = [] 39can = []
40fdcan = []
40ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] 41ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
41mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] 42mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
42embassy-stm32-wpan = [] 43embassy-stm32-wpan = []
@@ -97,6 +98,11 @@ path = "src/bin/eth.rs"
97required-features = [ "eth",] 98required-features = [ "eth",]
98 99
99[[bin]] 100[[bin]]
101name = "fdcan"
102path = "src/bin/fdcan.rs"
103required-features = [ "fdcan",]
104
105[[bin]]
100name = "gpio" 106name = "gpio"
101path = "src/bin/gpio.rs" 107path = "src/bin/gpio.rs"
102required-features = [] 108required-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"]
7mod common;
8use common::*;
9use defmt::assert;
10use embassy_executor::Spawner;
11use embassy_stm32::peripherals::*;
12use embassy_stm32::{bind_interrupts, can, Config};
13use embassy_time::{Duration, Instant};
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
18 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
19});
20
21struct TestOptions {
22 config: Config,
23 max_latency: Duration,
24 second_fifo_working: bool,
25}
26
27#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
28fn 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"))]
45fn 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"))]
62fn 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]
72async 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}