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