From 3dfd7f9feb7b8ca8faffb3e40cb727e97b68d36e Mon Sep 17 00:00:00 2001 From: Orange-Murker <23561952+Orange-Murker@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:34:34 +0200 Subject: [PATCH 01/75] Added VOS0 support for stm32h7a3/7b3/7b0 --- src/pwr.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/pwr.rs b/src/pwr.rs index 46cc5b23..677bf061 100644 --- a/src/pwr.rs +++ b/src/pwr.rs @@ -61,7 +61,7 @@ //! | --- | --- | --- //! | stm32h742/743/753/750 | RM0433 | 480MHz [^revv] //! | stm32h745/747/755/757 | RM0399 | 480MHz -//! | stm32h7a3/7b3/7b0 | RM0455 | VOS0 not supported +//! | stm32h7a3/7b3/7b0 | RM0455 | 280MHz //! | stm32h725/735 | RM0468 | 520MHz [^rm0468ecc] //! //! [^revv]: Revision V and later parts only @@ -72,7 +72,10 @@ use crate::rcc::backup::BackupREC; use crate::stm32::PWR; -#[cfg(all(feature = "revision_v", feature = "rm0468"))] +#[cfg(all( + feature = "revision_v", + any(feature = "rm0468", feature = "rm0455") +))] use crate::stm32::SYSCFG; #[cfg(all( feature = "revision_v", @@ -393,7 +396,12 @@ impl Pwr { #[cfg(all( feature = "revision_v", - any(feature = "rm0433", feature = "rm0399", feature = "rm0468") + any( + feature = "rm0433", + feature = "rm0399", + feature = "rm0468", + feature = "rm0455" + ) ))] #[must_use] pub fn vos0(mut self, _: &SYSCFG) -> Self { @@ -524,6 +532,15 @@ impl Pwr { while self.rb.csr1.read().actvosrdy().bit_is_clear() {} } + #[cfg(all(feature = "revision_v", feature = "rm0455"))] + if matches!(self.target_vos, VoltageScale::Scale0) { + // RM0455 section 6.8.6 says that CSR1.ACTVOSRDY must be set, + // before VOS0 can be changed. + while self.rb.csr1.read().actvosrdy().bit_is_clear() {} + vos = VoltageScale::Scale0; + self.voltage_scaling_transition(vos); + } + // Disable backup power domain write protection self.rb.cr1.modify(|_, w| w.dbp().set_bit()); while self.rb.cr1.read().dbp().bit_is_clear() {} From db3745964ad76796be5abd9096c7eedebac5123d Mon Sep 17 00:00:00 2001 From: Orange_Murker <23561952+Orange-Murker@users.noreply.github.com> Date: Thu, 13 Apr 2023 08:57:12 +0200 Subject: [PATCH 02/75] Removed the space before MHz --- src/pwr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pwr.rs b/src/pwr.rs index 14235c93..decc4143 100644 --- a/src/pwr.rs +++ b/src/pwr.rs @@ -61,7 +61,7 @@ //! | --- | --- | --- //! | stm32h742/743/753/750 | RM0433 | 480MHz [^revv] //! | stm32h745/747/755/757 | RM0399 | 480MHz -//! | stm32h7a3/7b3/7b0 | RM0455 | 280 MHz +//! | stm32h7a3/7b3/7b0 | RM0455 | 280MHz //! | stm32h723/725/730/733/735 | RM0468 | 520MHz [^rm0468ecc] //! //! [^revv]: Revision V and later parts only From bedd5aef4f3fb2f70dae36668f464b2c60022c2c Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 16 Apr 2023 12:43:58 +0300 Subject: [PATCH 03/75] fix vscode rust-analazer --- .vscode/settings.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7cfae6d1..5888de33 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,6 @@ "stm32h743v", "defmt" ], - "rust-analyzer.cargo.target": "thumbv7em-none-eabihf", -} \ No newline at end of file + "rust-analyzer.check.allTargets": false, + "rust-analyzer.check.targets": "thumbv7em-none-eabihf", +} From 721cb657a5ff784bba7d89c244a22de079f1255d Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 5 Apr 2022 14:01:48 +0300 Subject: [PATCH 04/75] IntoAF --- CHANGELOG.md | 5 + Cargo.toml | 13 +- src/gpio.rs | 779 +++++++++++++++++++++++++++-------- src/gpio/convert.rs | 32 +- src/gpio/partially_erased.rs | 11 + src/pwm.rs | 2 +- src/qei.rs | 2 +- 7 files changed, 639 insertions(+), 205 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d1f2a2e..a8d47262 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,9 @@ * adc: Remove unnecessary multiple reads of the CR register [#364] * adc: Add DMA TargetAddress implementations [#389] * adc: Poll LDORDY bit before ADC calibration [#386] +* Remove pulling from `Input` mode. Use `internal_regiter(Pull)` instead, + add universal `into_mode::()` pin mode converter, + `AFx` is now alias to `Alternate` [#346] * flash: Rewrite `write_sector` to correctly write data in 256 bit chunks [#371] * flash: Use Ordering fence to prevent inconsistency errors when writing to flash sector [#382] * iwdt: Added HAL implementation. Changed the name of the other implementation to `system_watchdog` [#376] @@ -62,6 +65,7 @@ `Input`. Use `internal_resistor()` method instead, add universal `into_mode::()` pin mode converter, Rename `set_speed()` method to `speed()` `AFx` is now alias to `Alternate` [#347] + * **Breaking**: Use [fugit](https://docs.rs/fugit/0.3.5/fugit/index.html) crate for duration and rate units. `.mhz()` -> `.MHz()`, `.khz()` -> `.kHz()`, `.hz()` -> `.Hz()`. Methods that previously accepted durations (`.ms()`, @@ -335,6 +339,7 @@ [#341]: https://github.com/stm32-rs/stm32h7xx-hal/pull/341 [#344]: https://github.com/stm32-rs/stm32h7xx-hal/pull/344 [#345]: https://github.com/stm32-rs/stm32h7xx-hal/pull/345 +[#346]: https://github.com/stm32-rs/stm32h7xx-hal/pull/346 [#347]: https://github.com/stm32-rs/stm32h7xx-hal/pull/347 [#350]: https://github.com/stm32-rs/stm32h7xx-hal/pull/350 [#354]: https://github.com/stm32-rs/stm32h7xx-hal/pull/354 diff --git a/Cargo.toml b/Cargo.toml index a51868ae..9a1683de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,10 +92,15 @@ features = ["medium-ethernet", "proto-ipv4", "proto-ipv6", "socket-raw"] default = ["rt"] device-selected = [] revision_v = [] -rm0433 = [] # aka. "single core" devices -rm0399 = [] # aka. "dual core" devices -rm0455 = [] # aka. "high memory integration" devices -rm0468 = [] # aka. "high speed" devices +rm0433 = ["gpio-h747"] # aka. "single core" devices +rm0399 = ["gpio-h747"] # TODO: fix gpio # aka. "dual core" devices +rm0455 = ["gpio-h7a2"] # aka. "high memory integration" devices +rm0468 = ["gpio-h72"] # aka. "high speed" devices + +gpio-h72 = [] +gpio-h747 = [] +gpio-h7a2 = [] + dsi = [] cm4 = [] cm7 = [] diff --git a/src/gpio.rs b/src/gpio.rs index 6aefd417..3419e22c 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -185,6 +185,8 @@ mod marker { pub trait Active {} /// Marker trait for all pin modes except alternate pub trait NotAlt {} + /// Marker trait for pins with alternate function `A` mapping + pub trait IntoAf {} } impl marker::Interruptable for Output {} @@ -388,6 +390,28 @@ impl Pin { } } +impl From> + for PartiallyErasedPin +{ + /// Pin-to-partially erased pin conversion using the [`From`] trait. + /// + /// Note that [`From`] is the reciprocal of [`Into`]. + fn from(p: Pin) -> Self { + p.erase_number() + } +} + +impl From> + for ErasedPin +{ + /// Pin-to-erased pin conversion using the [`From`] trait. + /// + /// Note that [`From`] is the reciprocal of [`Into`]. + fn from(p: Pin) -> Self { + p.erase() + } +} + impl Pin { /// Set the output of the pin regardless of its mode. /// Primarily used to set the output value of the pin @@ -496,7 +520,7 @@ where macro_rules! gpio { ($GPIOX:ident, $gpiox:ident, $Rec:ident, $PEPin:ident, $port_id:expr, $PXn:ident, [ - $($PXi:ident: ($pxi:ident, $i:expr $(, $MODE:ty)?),)+ + $($PXi:ident: ($pxi:ident, $i:expr, [$($A:literal),*] $(, $MODE:ty)?),)+ ]) => { #[doc=concat!("Port ", $port_id)] pub mod $gpiox { @@ -542,6 +566,10 @@ macro_rules! gpio { $( #[doc=concat!("P", $port_id, $i, " pin")] pub type $PXi = super::Pin<$port_id, $i, MODE>; + + $( + impl super::marker::IntoAf<$A> for $PXi { } + )* )+ } @@ -550,214 +578,603 @@ macro_rules! gpio { } } +#[cfg(feature = "gpio-h72")] gpio!(GPIOA, gpioa, Gpioa, PA, 'A', PAn, [ - PA0: (pa0, 0), - PA1: (pa1, 1), - PA2: (pa2, 2), - PA3: (pa3, 3), - PA4: (pa4, 4), - PA5: (pa5, 5), - PA6: (pa6, 6), - PA7: (pa7, 7), - PA8: (pa8, 8), - PA9: (pa9, 9), - PA10: (pa10, 10), - PA11: (pa11, 11), - PA12: (pa12, 12), - PA13: (pa13, 13, super::Debugger), // SWDIO, PullUp VeryHigh speed - PA14: (pa14, 14, super::Debugger), // SWCLK, PullDown - PA15: (pa15, 15, super::Debugger), // JTDI, PullUp + PA0: (pa0, 0, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 15]), + PA1: (pa1, 1, [1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 14, 15]), + PA2: (pa2, 2, [1, 2, 3, 4, 6, 7, 8, 11, 12, 14, 15]), + PA3: (pa3, 3, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15]), + PA4: (pa4, 4, [2, 5, 6, 7, 8, 12, 13, 14, 15]), + PA5: (pa5, 5, [1, 3, 5, 8, 10, 12, 13, 14, 15]), + PA6: (pa6, 6, [1, 2, 3, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15]), + PA7: (pa7, 7, [1, 2, 3, 5, 8, 9, 10, 11, 12, 14, 15]), + PA8: (pa8, 8, [0, 1, 3, 4, 6, 7, 10, 11, 12, 13, 14, 15]), + PA9: (pa9, 9, [1, 3, 4, 5, 6, 7, 11, 13, 14, 15]), + PA10: (pa10, 10, [1, 3, 7, 10, 11, 12, 13, 14, 15]), + PA11: (pa11, 11, [1, 3, 5, 6, 7, 9, 14, 15]), + PA12: (pa12, 12, [1, 3, 5, 6, 7, 8, 9, 12, 14, 15]), + PA13: (pa13, 13, [0, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed + PA14: (pa14, 14, [0, 15], super::Debugger), // SWCLK, PullDown + PA15: (pa15, 15, [0, 1, 4, 5, 6, 7, 8, 9, 11, 14, 15], super::Debugger), // JTDI, PullUp ]); +#[cfg(feature = "gpio-h72")] gpio!(GPIOB, gpiob, Gpiob, PB, 'B', PBn, [ - PB0: (pb0, 0), - PB1: (pb1, 1), - PB2: (pb2, 2), - PB3: (pb3, 3, super::Debugger), // SWO, VeryHigh speed - PB4: (pb4, 4, super::Debugger), // JTRST, PullUp - PB5: (pb5, 5), - PB6: (pb6, 6), - PB7: (pb7, 7), - PB8: (pb8, 8), - PB9: (pb9, 9), - PB10: (pb10, 10), - PB11: (pb11, 11), - PB12: (pb12, 12), - PB13: (pb13, 13), - PB14: (pb14, 14), - PB15: (pb15, 15), + PB0: (pb0, 0, [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15]), + PB1: (pb1, 1, [1, 2, 3, 4, 6, 9, 10, 11, 14, 15]), + PB2: (pb2, 2, [0, 1, 2, 4, 6, 7, 8, 9, 10, 11, 13, 15]), + PB3: (pb3, 3, [0, 1, 5, 6, 8, 9, 10, 11, 14, 15], super::Debugger), // SWO, VeryHigh speed + PB4: (pb4, 4, [0, 1, 2, 5, 6, 7, 8, 9, 11, 15], super::Debugger), // JTRST, PullUp + PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB6: (pb6, 6, [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB7: (pb7, 7, [1, 2, 4, 6, 7, 8, 11, 12, 13, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB9: (pb9, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB10: (pb10, 10, [1, 3, 4, 5, 6, 7, 9, 10, 11, 14, 15]), + PB11: (pb11, 11, [1, 3, 4, 6, 7, 10, 11, 14, 15]), + PB12: (pb12, 12, [1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]), + PB13: (pb13, 13, [1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]), + PB14: (pb14, 14, [1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 15]), + PB15: (pb15, 15, [0, 1, 2, 3, 4, 5, 6, 8, 9, 12, 14, 15]), ]); +#[cfg(feature = "gpio-h72")] gpio!(GPIOC, gpioc, Gpioc, PC, 'C', PCn, [ - PC0: (pc0, 0), - PC1: (pc1, 1), - PC2: (pc2, 2), - PC3: (pc3, 3), - PC4: (pc4, 4), - PC5: (pc5, 5), - PC6: (pc6, 6), - PC7: (pc7, 7), - PC8: (pc8, 8), - PC9: (pc9, 9), - PC10: (pc10, 10), - PC11: (pc11, 11), - PC12: (pc12, 12), - PC13: (pc13, 13), - PC14: (pc14, 14), - PC15: (pc15, 15), + PC0: (pc0, 0, [1, 3, 6, 8, 9, 10, 11, 12, 14, 15]), + PC1: (pc1, 1, [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 15]), + PC2: (pc2, 2, [0, 3, 4, 5, 6, 9, 10, 11, 12, 15]), + PC3: (pc3, 3, [0, 3, 4, 5, 9, 10, 11, 12, 15]), + PC4: (pc4, 4, [1, 3, 5, 9, 10, 11, 12, 14, 15]), + PC5: (pc5, 5, [1, 2, 3, 4, 9, 10, 11, 12, 13, 14, 15]), + PC6: (pc6, 6, [2, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15]), + PC7: (pc7, 7, [0, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PC8: (pc8, 8, [0, 2, 3, 7, 8, 9, 10, 11, 12, 13, 15]), + PC9: (pc9, 9, [0, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15]), + PC10: (pc10, 10, [3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PC11: (pc11, 11, [3, 4, 6, 7, 8, 9, 12, 13, 14, 15]), + PC12: (pc12, 12, [0, 1, 2, 4, 5, 6, 7, 8, 12, 13, 14, 15]), + PC13: (pc13, 13, [15]), + PC14: (pc14, 14, [15]), + PC15: (pc15, 15, [15]), ]); +#[cfg(feature = "gpio-h72")] gpio!(GPIOD, gpiod, Gpiod, PD, 'D', PDn, [ - PD0: (pd0, 0), - PD1: (pd1, 1), - PD2: (pd2, 2), - PD3: (pd3, 3), - PD4: (pd4, 4), - PD5: (pd5, 5), - PD6: (pd6, 6), - PD7: (pd7, 7), - PD8: (pd8, 8), - PD9: (pd9, 9), - PD10: (pd10, 10), - PD11: (pd11, 11), - PD12: (pd12, 12), - PD13: (pd13, 13), - PD14: (pd14, 14), - PD15: (pd15, 15), + PD0: (pd0, 0, [3, 8, 9, 11, 12, 14, 15]), + PD1: (pd1, 1, [3, 8, 9, 12, 15]), + PD2: (pd2, 2, [0, 1, 2, 4, 8, 9, 12, 13, 14, 15]), + PD3: (pd3, 3, [3, 5, 7, 12, 13, 14, 15]), + PD4: (pd4, 4, [7, 10, 12, 15]), + PD5: (pd5, 5, [7, 10, 12, 15]), + PD6: (pd6, 6, [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15]), + PD7: (pd7, 7, [3, 5, 6, 7, 9, 10, 11, 12, 15]), + PD8: (pd8, 8, [3, 7, 9, 12, 15]), + PD9: (pd9, 9, [3, 7, 12, 15]), + PD10: (pd10, 10, [3, 7, 12, 14, 15]), + PD11: (pd11, 11, [3, 4, 7, 9, 10, 12, 15]), + PD12: (pd12, 12, [1, 2, 3, 4, 5, 7, 9, 10, 12, 13, 15]), + PD13: (pd13, 13, [1, 2, 4, 5, 9, 10, 11, 12, 13, 15]), + PD14: (pd14, 14, [2, 8, 11, 12, 15]), + PD15: (pd15, 15, [2, 8, 11, 12, 15]), ]); +#[cfg(feature = "gpio-h72")] gpio!(GPIOE, gpioe, Gpioe, PE, 'E', PEn, [ - PE0: (pe0, 0), - PE1: (pe1, 1), - PE2: (pe2, 2), - PE3: (pe3, 3), - PE4: (pe4, 4), - PE5: (pe5, 5), - PE6: (pe6, 6), - PE7: (pe7, 7), - PE8: (pe8, 8), - PE9: (pe9, 9), - PE10: (pe10, 10), - PE11: (pe11, 11), - PE12: (pe12, 12), - PE13: (pe13, 13), - PE14: (pe14, 14), - PE15: (pe15, 15), + PE0: (pe0, 0, [1, 2, 4, 8, 10, 12, 13, 14, 15]), + PE1: (pe1, 1, [1, 8, 12, 13, 14, 15]), + PE2: (pe2, 2, [0, 2, 4, 5, 6, 8, 9, 10, 11, 12, 15]), + PE3: (pe3, 3, [0, 4, 6, 8, 11, 12, 15]), + PE4: (pe4, 4, [0, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14, 15]), + PE5: (pe5, 5, [0, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14, 15]), + PE6: (pe6, 6, [0, 1, 2, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15]), + PE7: (pe7, 7, [1, 3, 7, 10, 12, 15]), + PE8: (pe8, 8, [1, 3, 7, 10, 12, 13, 15]), + PE9: (pe9, 9, [1, 3, 7, 10, 12, 15]), + PE10: (pe10, 10, [1, 3, 7, 10, 12, 15]), + PE11: (pe11, 11, [1, 3, 5, 10, 11, 12, 14, 15]), + PE12: (pe12, 12, [1, 3, 5, 10, 12, 13, 14, 15]), + PE13: (pe13, 13, [1, 3, 5, 10, 12, 13, 14, 15]), + PE14: (pe14, 14, [1, 5, 10, 12, 14, 15]), + PE15: (pe15, 15, [1, 11, 12, 13, 14, 15]), ]); +#[cfg(feature = "gpio-h72")] gpio!(GPIOF, gpiof, Gpiof, PF, 'F', PFn, [ - PF0: (pf0, 0), - PF1: (pf1, 1), - PF2: (pf2, 2), - PF3: (pf3, 3), - PF4: (pf4, 4), - PF5: (pf5, 5), - PF6: (pf6, 6), - PF7: (pf7, 7), - PF8: (pf8, 8), - PF9: (pf9, 9), - PF10: (pf10, 10), - PF11: (pf11, 11), - PF12: (pf12, 12), - PF13: (pf13, 13), - PF14: (pf14, 14), - PF15: (pf15, 15), + PF0: (pf0, 0, [4, 6, 9, 12, 13, 15]), + PF1: (pf1, 1, [4, 6, 9, 12, 13, 15]), + PF2: (pf2, 2, [4, 6, 9, 12, 13, 15]), + PF3: (pf3, 3, [9, 12, 13, 15]), + PF4: (pf4, 4, [9, 12, 15]), + PF5: (pf5, 5, [9, 12, 15]), + PF6: (pf6, 6, [1, 2, 5, 6, 7, 8, 10, 13, 15]), + PF7: (pf7, 7, [1, 2, 5, 6, 7, 8, 10, 13, 15]), + PF8: (pf8, 8, [1, 5, 6, 7, 8, 9, 10, 13, 15]), + PF9: (pf9, 9, [1, 5, 6, 7, 8, 9, 10, 13, 15]), + PF10: (pf10, 10, [1, 2, 4, 9, 10, 13, 14, 15]), + PF11: (pf11, 11, [5, 9, 10, 12, 13, 14, 15]), + PF12: (pf12, 12, [9, 12, 14, 15]), + PF13: (pf13, 13, [3, 4, 12, 14, 15]), + PF14: (pf14, 14, [3, 4, 12, 14, 15]), + PF15: (pf15, 15, [4, 12, 15]), ]); +#[cfg(feature = "gpio-h72")] gpio!(GPIOG, gpiog, Gpiog, PG, 'G', PGn, [ - PG0: (pg0, 0), - PG1: (pg1, 1), - PG2: (pg2, 2), - PG3: (pg3, 3), - PG4: (pg4, 4), - PG5: (pg5, 5), - PG6: (pg6, 6), - PG7: (pg7, 7), - PG8: (pg8, 8), - PG9: (pg9, 9), - PG10: (pg10, 10), - PG11: (pg11, 11), - PG12: (pg12, 12), - PG13: (pg13, 13), - PG14: (pg14, 14), - PG15: (pg15, 15), + PG0: (pg0, 0, [9, 11, 12, 15]), + PG1: (pg1, 1, [9, 11, 12, 15]), + PG2: (pg2, 2, [3, 11, 12, 14, 15]), + PG3: (pg3, 3, [3, 11, 12, 13, 15]), + PG4: (pg4, 4, [1, 11, 12, 15]), + PG5: (pg5, 5, [1, 12, 15]), + PG6: (pg6, 6, [1, 10, 12, 13, 14, 15]), + PG7: (pg7, 7, [6, 7, 9, 12, 13, 14, 15]), + PG8: (pg8, 8, [3, 5, 7, 8, 11, 12, 14, 15]), + PG9: (pg9, 9, [2, 5, 7, 8, 9, 10, 11, 12, 13, 15]), + PG10: (pg10, 10, [2, 3, 5, 9, 10, 11, 12, 13, 14, 15]), + PG11: (pg11, 11, [1, 4, 5, 8, 9, 10, 11, 13, 14, 15]), + PG12: (pg12, 12, [1, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PG13: (pg13, 13, [0, 1, 4, 5, 7, 10, 11, 12, 13, 14, 15]), + PG14: (pg14, 14, [0, 1, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15]), + PG15: (pg15, 15, [7, 9, 11, 12, 13, 15]), ]); +#[cfg(feature = "gpio-h72")] gpio!(GPIOH, gpioh, Gpioh, PH, 'H', PHn, [ - PH0: (ph0, 0), - PH1: (ph1, 1), - PH2: (ph2, 2), - PH3: (ph3, 3), - PH4: (ph4, 4), - PH5: (ph5, 5), - PH6: (ph6, 6), - PH7: (ph7, 7), - PH8: (ph8, 8), - PH9: (ph9, 9), - PH10: (ph10, 10), - PH11: (ph11, 11), - PH12: (ph12, 12), - PH13: (ph13, 13), - PH14: (ph14, 14), - PH15: (ph15, 15), -]); - -#[cfg(not(feature = "rm0468"))] + PH0: (ph0, 0, [15]), + PH1: (ph1, 1, [15]), + PH2: (ph2, 2, [1, 9, 10, 11, 12, 14, 15]), + PH3: (ph3, 3, [9, 10, 11, 12, 14, 15]), + PH4: (ph4, 4, [4, 9, 10, 13, 14, 15]), + PH5: (ph5, 5, [4, 5, 12, 15]), + PH6: (ph6, 6, [2, 4, 5, 11, 12, 13, 15]), + PH7: (ph7, 7, [4, 5, 11, 12, 13, 15]), + PH8: (ph8, 8, [2, 4, 12, 13, 14, 15]), + PH9: (ph9, 9, [2, 4, 12, 13, 14, 15]), + PH10: (ph10, 10, [2, 4, 12, 13, 14, 15]), + PH11: (ph11, 11, [2, 4, 12, 13, 14, 15]), + PH12: (ph12, 12, [2, 4, 12, 13, 14, 15]), + PH13: (ph13, 13, [3, 8, 9, 12, 14, 15]), + PH14: (ph14, 14, [3, 8, 9, 12, 13, 14, 15]), + PH15: (ph15, 15, [3, 12, 13, 14, 15]), +]); + +#[cfg(feature = "gpio-h72")] +gpio!(GPIOJ, gpioj, Gpioj, PJ, 'J', PJn, [ + PJ8: (pj8, 8, [1, 3, 8, 14, 15]), + PJ9: (pj9, 9, [1, 3, 8, 14, 15]), + PJ10: (pj10, 10, [1, 3, 5, 14, 15]), + PJ11: (pj11, 11, [1, 3, 5, 14, 15]), +]); + +#[cfg(feature = "gpio-h72")] +gpio!(GPIOK, gpiok, Gpiok, PK, 'K', PKn, [ + PK0: (pk0, 0, [1, 3, 5, 14, 15]), + PK1: (pk1, 1, [1, 3, 5, 14, 15]), + PK2: (pk2, 2, [1, 3, 10, 11, 14, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOA, gpioa, Gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 2, 3, 4, 7, 8, 9, 10, 11, 15]), + PA1: (pa1, 1, [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15]), + PA2: (pa2, 2, [1, 2, 3, 4, 7, 8, 11, 12, 14, 15]), + PA3: (pa3, 3, [1, 2, 3, 4, 7, 9, 10, 11, 14, 15]), + PA4: (pa4, 4, [2, 5, 6, 7, 8, 12, 13, 14, 15]), + PA5: (pa5, 5, [1, 3, 5, 8, 10, 14, 15]), + PA6: (pa6, 6, [1, 2, 3, 5, 8, 9, 10, 11, 12, 13, 14, 15]), + PA7: (pa7, 7, [1, 2, 3, 5, 8, 9, 11, 12, 15]), + PA8: (pa8, 8, [0, 1, 2, 3, 4, 7, 10, 11, 12, 13, 14, 15]), + PA9: (pa9, 9, [1, 2, 3, 4, 5, 7, 13, 14, 15]), + PA10: (pa10, 10, [1, 2, 3, 7, 10, 11, 12, 13, 14, 15]), + PA11: (pa11, 11, [1, 2, 3, 5, 6, 7, 9, 10, 14, 15]), + PA12: (pa12, 12, [1, 2, 3, 5, 6, 7, 8, 9, 10, 14, 15]), + PA13: (pa13, 13, [0, 15], super::Debugger), + PA14: (pa14, 14, [0, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 2, 4, 5, 6, 7, 8, 11, 13, 15], super::Debugger), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOB, gpiob, Gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [1, 2, 3, 6, 8, 9, 10, 11, 14, 15]), + PB1: (pb1, 1, [1, 2, 3, 6, 9, 10, 11, 14, 15]), + PB2: (pb2, 2, [0, 2, 4, 6, 7, 8, 9, 10, 15]), + PB3: (pb3, 3, [0, 1, 2, 5, 6, 8, 9, 10, 11, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 15], super::Debugger), + PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB6: (pb6, 6, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB7: (pb7, 7, [1, 2, 3, 4, 6, 7, 8, 11, 12, 13, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB9: (pb9, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB10: (pb10, 10, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 14, 15]), + PB11: (pb11, 11, [1, 2, 3, 4, 6, 7, 10, 11, 13, 14, 15]), + PB12: (pb12, 12, [1, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]), + PB13: (pb13, 13, [1, 3, 5, 6, 7, 9, 10, 11, 14, 15]), + PB14: (pb14, 14, [1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 15]), + PB15: (pb15, 15, [0, 1, 2, 3, 4, 5, 6, 8, 9, 12, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOC, gpioc, Gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [3, 6, 8, 10, 12, 14, 15]), + PC1: (pc1, 1, [0, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 15]), + PC2: (pc2, 2, [3, 5, 6, 10, 11, 12, 15]), + PC3: (pc3, 3, [3, 5, 10, 11, 12, 15]), + PC4: (pc4, 4, [3, 5, 9, 11, 12, 15]), + PC5: (pc5, 5, [2, 3, 9, 10, 11, 12, 13, 15]), + PC6: (pc6, 6, [1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15]), + PC7: (pc7, 7, [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PC8: (pc8, 8, [0, 1, 2, 3, 7, 8, 9, 11, 12, 13, 15]), + PC9: (pc9, 9, [0, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15]), + PC10: (pc10, 10, [2, 3, 6, 7, 8, 9, 12, 13, 14, 15]), + PC11: (pc11, 11, [2, 3, 6, 7, 8, 9, 12, 13, 15]), + PC12: (pc12, 12, [0, 2, 6, 7, 8, 12, 13, 15]), + PC13: (pc13, 13, [15]), + PC14: (pc14, 14, [15]), + PC15: (pc15, 15, [15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOD, gpiod, Gpiod, PD, 'D', PDn, [ + PD0: (pd0, 0, [3, 6, 8, 9, 12, 15]), + PD1: (pd1, 1, [3, 6, 8, 9, 12, 15]), + PD2: (pd2, 2, [0, 2, 8, 12, 13, 15]), + PD3: (pd3, 3, [3, 5, 7, 12, 13, 14, 15]), + PD4: (pd4, 4, [2, 6, 7, 12, 15]), + PD5: (pd5, 5, [2, 7, 12, 15]), + PD6: (pd6, 6, [2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15]), + PD7: (pd7, 7, [3, 5, 6, 7, 9, 11, 12, 15]), + PD8: (pd8, 8, [3, 6, 7, 9, 12, 15]), + PD9: (pd9, 9, [3, 6, 7, 12, 15]), + PD10: (pd10, 10, [3, 6, 7, 12, 14, 15]), + PD11: (pd11, 11, [3, 4, 7, 9, 10, 12, 15]), + PD12: (pd12, 12, [1, 2, 3, 4, 7, 9, 10, 12, 15]), + PD13: (pd13, 13, [1, 2, 4, 9, 10, 12, 15]), + PD14: (pd14, 14, [2, 6, 8, 12, 15]), + PD15: (pd15, 15, [2, 6, 8, 12, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOE, gpioe, Gpioe, PE, 'E', PEn, [ + PE0: (pe0, 0, [1, 2, 3, 4, 8, 10, 12, 13, 15]), + PE1: (pe1, 1, [1, 3, 8, 12, 13, 15]), + PE2: (pe2, 2, [0, 2, 5, 6, 8, 9, 10, 11, 12, 15]), + PE3: (pe3, 3, [0, 4, 6, 8, 12, 15]), + PE4: (pe4, 4, [0, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14, 15]), + PE5: (pe5, 5, [0, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14, 15]), + PE6: (pe6, 6, [0, 1, 2, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15]), + PE7: (pe7, 7, [1, 3, 7, 10, 12, 15]), + PE8: (pe8, 8, [1, 3, 7, 10, 12, 13, 15]), + PE9: (pe9, 9, [1, 3, 7, 10, 12, 15]), + PE10: (pe10, 10, [1, 3, 7, 10, 12, 15]), + PE11: (pe11, 11, [1, 3, 5, 10, 12, 14, 15]), + PE12: (pe12, 12, [1, 3, 5, 10, 12, 13, 14, 15]), + PE13: (pe13, 13, [1, 3, 5, 10, 12, 13, 14, 15]), + PE14: (pe14, 14, [1, 5, 10, 12, 14, 15]), + PE15: (pe15, 15, [1, 12, 13, 14, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOF, gpiof, Gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [4, 12, 15]), + PF1: (pf1, 1, [4, 12, 15]), + PF2: (pf2, 2, [4, 12, 15]), + PF3: (pf3, 3, [12, 15]), + PF4: (pf4, 4, [12, 15]), + PF5: (pf5, 5, [12, 15]), + PF6: (pf6, 6, [1, 5, 6, 7, 8, 9, 15]), + PF7: (pf7, 7, [1, 5, 6, 7, 8, 9, 15]), + PF8: (pf8, 8, [1, 5, 6, 7, 8, 9, 10, 15]), + PF9: (pf9, 9, [1, 5, 6, 7, 8, 9, 10, 15]), + PF10: (pf10, 10, [1, 2, 9, 10, 13, 14, 15]), + PF11: (pf11, 11, [5, 10, 12, 13, 15]), + PF12: (pf12, 12, [12, 15]), + PF13: (pf13, 13, [3, 4, 12, 15]), + PF14: (pf14, 14, [3, 4, 12, 15]), + PF15: (pf15, 15, [4, 12, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOG, gpiog, Gpiog, PG, 'G', PGn, [ + PG0: (pg0, 0, [12, 15]), + PG1: (pg1, 1, [12, 15]), + PG2: (pg2, 2, [3, 11, 12, 15]), + PG3: (pg3, 3, [3, 11, 12, 15]), + PG4: (pg4, 4, [1, 11, 12, 15]), + PG5: (pg5, 5, [1, 12, 15]), + PG6: (pg6, 6, [1, 2, 10, 12, 13, 14, 15]), + PG7: (pg7, 7, [2, 6, 7, 12, 13, 14, 15]), + PG8: (pg8, 8, [3, 5, 7, 8, 11, 12, 14, 15]), + PG9: (pg9, 9, [5, 7, 8, 9, 10, 12, 13, 15]), + PG10: (pg10, 10, [2, 5, 9, 10, 12, 13, 14, 15]), + PG11: (pg11, 11, [1, 2, 5, 8, 10, 11, 13, 14, 15]), + PG12: (pg12, 12, [1, 2, 5, 7, 8, 9, 11, 12, 14, 15]), + PG13: (pg13, 13, [0, 1, 2, 5, 7, 11, 12, 14, 15]), + PG14: (pg14, 14, [0, 1, 5, 7, 9, 11, 12, 14, 15]), + PG15: (pg15, 15, [7, 12, 13, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOH, gpioh, Gpioh, PH, 'H', PHn, [ + PH0: (ph0, 0, [15]), + PH1: (ph1, 1, [15]), + PH2: (ph2, 2, [1, 9, 10, 11, 12, 14, 15]), + PH3: (ph3, 3, [9, 10, 11, 12, 14, 15]), + PH4: (ph4, 4, [4, 9, 10, 14, 15]), + PH5: (ph5, 5, [4, 5, 12, 15]), + PH6: (ph6, 6, [2, 4, 5, 11, 12, 13, 15]), + PH7: (ph7, 7, [4, 5, 11, 12, 13, 15]), + PH8: (ph8, 8, [2, 4, 12, 13, 14, 15]), + PH9: (ph9, 9, [2, 4, 12, 13, 14, 15]), + PH10: (ph10, 10, [2, 4, 12, 13, 14, 15]), + PH11: (ph11, 11, [2, 4, 12, 13, 14, 15]), + PH12: (ph12, 12, [2, 4, 12, 13, 14, 15]), + PH13: (ph13, 13, [3, 8, 9, 12, 14, 15]), + PH14: (ph14, 14, [3, 8, 9, 12, 13, 14, 15]), + PH15: (ph15, 15, [3, 12, 13, 14, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOI, gpioi, Gpioi, PI, 'I', PIn, [ + PI0: (pi0, 0, [2, 5, 12, 13, 14, 15]), + PI1: (pi1, 1, [3, 5, 11, 12, 13, 14, 15]), + PI2: (pi2, 2, [3, 5, 12, 13, 14, 15]), + PI3: (pi3, 3, [3, 5, 12, 13, 15]), + PI4: (pi4, 4, [3, 10, 11, 12, 13, 14, 15]), + PI5: (pi5, 5, [3, 10, 12, 13, 14, 15]), + PI6: (pi6, 6, [3, 10, 12, 13, 14, 15]), + PI7: (pi7, 7, [3, 10, 12, 13, 14, 15]), + PI8: (pi8, 8, [15]), + PI9: (pi9, 9, [8, 9, 12, 14, 15]), + PI10: (pi10, 10, [11, 12, 14, 15]), + PI11: (pi11, 11, [9, 10, 15]), + PI12: (pi12, 12, [14, 15]), + PI13: (pi13, 13, [14, 15]), + PI14: (pi14, 14, [14, 15]), + PI15: (pi15, 15, [9, 14, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOJ, gpioj, Gpioj, PJ, 'J', PJn, [ + PJ0: (pj0, 0, [9, 14, 15]), + PJ1: (pj1, 1, [14, 15]), + PJ2: (pj2, 2, [13, 14, 15]), + PJ3: (pj3, 3, [14, 15]), + PJ4: (pj4, 4, [14, 15]), + PJ5: (pj5, 5, [14, 15]), + PJ6: (pj6, 6, [3, 14, 15]), + PJ7: (pj7, 7, [0, 3, 14, 15]), + PJ8: (pj8, 8, [1, 3, 8, 14, 15]), + PJ9: (pj9, 9, [1, 3, 8, 14, 15]), + PJ10: (pj10, 10, [1, 3, 5, 14, 15]), + PJ11: (pj11, 11, [1, 3, 5, 14, 15]), + PJ12: (pj12, 12, [0, 9, 14, 15]), + PJ13: (pj13, 13, [9, 14, 15]), + PJ14: (pj14, 14, [14, 15]), + PJ15: (pj15, 15, [14, 15]), +]); + +#[cfg(feature = "gpio-h747")] +gpio!(GPIOK, gpiok, Gpiok, PK, 'K', PKn, [ + PK0: (pk0, 0, [1, 3, 5, 14, 15]), + PK1: (pk1, 1, [1, 3, 5, 14, 15]), + PK2: (pk2, 2, [1, 3, 10, 11, 14, 15]), + PK3: (pk3, 3, [14, 15]), + PK4: (pk4, 4, [14, 15]), + PK5: (pk5, 5, [14, 15]), + PK6: (pk6, 6, [14, 15]), + PK7: (pk7, 7, [14, 15]), +]); + +#[cfg(feature = "gpio-h7a2")] +gpio!(GPIOA, gpioa, Gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 2, 3, 4, 5, 7, 8, 9, 10, 15]), + PA1: (pa1, 1, [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15]), + PA2: (pa2, 2, [1, 2, 4, 6, 7, 8, 12, 14, 15]), + PA3: (pa3, 3, [1, 2, 3, 4, 5, 7, 9, 10, 14, 15]), + PA4: (pa4, 4, [2, 5, 6, 7, 8, 13, 14, 15]), + PA5: (pa5, 5, [0, 1, 3, 5, 8, 10, 13, 14, 15]), + PA6: (pa6, 6, [1, 2, 3, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15]), + PA7: (pa7, 7, [1, 2, 3, 4, 5, 8, 9, 10, 12, 14, 15]), + PA8: (pa8, 8, [0, 1, 3, 4, 7, 10, 11, 12, 13, 14, 15]), + PA9: (pa9, 9, [1, 3, 4, 5, 7, 13, 14, 15]), + PA10: (pa10, 10, [1, 3, 7, 10, 11, 12, 13, 14, 15]), + PA11: (pa11, 11, [1, 3, 5, 6, 7, 9, 14, 15]), + PA12: (pa12, 12, [1, 3, 5, 6, 7, 8, 9, 14, 15]), + PA13: (pa13, 13, [0, 15], super::Debugger), + PA14: (pa14, 14, [0, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 4, 5, 6, 7, 8, 9, 11, 14, 15], super::Debugger), +]); + +#[cfg(feature = "gpio-h7a2")] +gpio!(GPIOB, gpiob, Gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15]), + PB1: (pb1, 1, [1, 2, 3, 6, 9, 10, 11, 14, 15]), + PB2: (pb2, 2, [0, 2, 4, 6, 7, 9, 10, 15]), + PB3: (pb3, 3, [0, 1, 5, 6, 8, 9, 10, 11, 15], super::Debugger), + PB4: (pb4, 4, [1, 2, 5, 6, 7, 8, 9, 11, 15], super::Debugger), + PB5: (pb5, 5, [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB6: (pb6, 6, [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB7: (pb7, 7, [1, 2, 4, 6, 7, 8, 11, 12, 13, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15]), + PB9: (pb9, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB10: (pb10, 10, [1, 3, 4, 5, 6, 7, 9, 10, 14, 15]), + PB11: (pb11, 11, [1, 3, 4, 6, 7, 10, 14, 15]), + PB12: (pb12, 12, [1, 3, 4, 5, 6, 7, 9, 10, 11, 13, 14, 15]), + PB13: (pb13, 13, [1, 3, 4, 5, 6, 7, 9, 10, 12, 13, 14, 15]), + PB14: (pb14, 14, [1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15]), + PB15: (pb15, 15, [0, 1, 2, 3, 4, 5, 6, 8, 9, 14, 15]), +]); + +#[cfg(feature = "gpio-h7a2")] +gpio!(GPIOC, gpioc, Gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [3, 6, 8, 9, 10, 11, 12, 14, 15]), + PC1: (pc1, 1, [0, 2, 3, 4, 5, 6, 9, 10, 12, 14, 15]), + PC2: (pc2, 2, [0, 3, 5, 6, 9, 10, 11, 12, 15]), + PC3: (pc3, 3, [0, 3, 5, 9, 10, 11, 12, 15]), + PC4: (pc4, 4, [3, 5, 9, 12, 14, 15]), + PC5: (pc5, 5, [2, 3, 4, 9, 10, 12, 13, 14, 15]), + PC6: (pc6, 6, [2, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15]), + PC7: (pc7, 7, [0, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PC8: (pc8, 8, [0, 2, 3, 7, 8, 9, 10, 11, 12, 13, 15]), + PC9: (pc9, 9, [0, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15]), + PC10: (pc10, 10, [3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PC11: (pc11, 11, [3, 4, 6, 7, 8, 9, 12, 13, 14, 15]), + PC12: (pc12, 12, [0, 2, 4, 5, 6, 7, 8, 12, 13, 14, 15]), + PC13: (pc13, 13, [15]), + PC14: (pc14, 14, [15]), + PC15: (pc15, 15, [15]), +]); + +#[cfg(feature = "gpio-h7a2")] +gpio!(GPIOD, gpiod, Gpiod, PD, 'D', PDn, [ + PD0: (pd0, 0, [3, 8, 9, 11, 12, 14, 15]), + PD1: (pd1, 1, [3, 8, 9, 12, 15]), + PD2: (pd2, 2, [0, 2, 4, 8, 9, 12, 13, 14, 15]), + PD3: (pd3, 3, [3, 5, 7, 12, 13, 14, 15]), + PD4: (pd4, 4, [7, 10, 12, 15]), + PD5: (pd5, 5, [7, 10, 12, 15]), + PD6: (pd6, 6, [2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15]), + PD7: (pd7, 7, [3, 5, 6, 7, 9, 10, 11, 12, 15]), + PD8: (pd8, 8, [3, 7, 9, 12, 15]), + PD9: (pd9, 9, [3, 7, 12, 15]), + PD10: (pd10, 10, [3, 4, 7, 12, 14, 15]), + PD11: (pd11, 11, [3, 4, 7, 9, 10, 12, 15]), + PD12: (pd12, 12, [1, 2, 3, 4, 7, 9, 10, 12, 13, 15]), + PD13: (pd13, 13, [1, 2, 4, 9, 10, 11, 12, 13, 15]), + PD14: (pd14, 14, [2, 8, 11, 12, 15]), + PD15: (pd15, 15, [2, 8, 11, 12, 15]), +]); + +#[cfg(feature = "gpio-h7a2")] +gpio!(GPIOE, gpioe, Gpioe, PE, 'E', PEn, [ + PE0: (pe0, 0, [1, 2, 4, 8, 10, 12, 13, 14, 15]), + PE1: (pe1, 1, [1, 8, 12, 13, 14, 15]), + PE2: (pe2, 2, [0, 2, 5, 6, 9, 11, 12, 15]), + PE3: (pe3, 3, [0, 4, 6, 11, 12, 15]), + PE4: (pe4, 4, [0, 2, 3, 4, 5, 6, 12, 13, 14, 15]), + PE5: (pe5, 5, [0, 2, 3, 4, 5, 6, 12, 13, 14, 15]), + PE6: (pe6, 6, [0, 1, 2, 4, 5, 6, 10, 11, 12, 13, 14, 15]), + PE7: (pe7, 7, [1, 3, 7, 10, 12, 15]), + PE8: (pe8, 8, [1, 3, 7, 10, 12, 13, 15]), + PE9: (pe9, 9, [1, 3, 7, 10, 12, 15]), + PE10: (pe10, 10, [1, 3, 7, 10, 12, 15]), + PE11: (pe11, 11, [1, 3, 5, 10, 11, 12, 14, 15]), + PE12: (pe12, 12, [1, 3, 5, 10, 12, 13, 14, 15]), + PE13: (pe13, 13, [1, 3, 5, 10, 12, 13, 14, 15]), + PE14: (pe14, 14, [1, 5, 10, 12, 14, 15]), + PE15: (pe15, 15, [1, 11, 12, 13, 14, 15]), +]); + +#[cfg(feature = "gpio-h7a2")] +gpio!(GPIOF, gpiof, Gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [4, 9, 12, 15]), + PF1: (pf1, 1, [4, 9, 12, 15]), + PF2: (pf2, 2, [4, 9, 12, 15]), + PF3: (pf3, 3, [9, 12, 15]), + PF4: (pf4, 4, [9, 12, 15]), + PF5: (pf5, 5, [9, 12, 15]), + PF6: (pf6, 6, [1, 5, 6, 7, 10, 15]), + PF7: (pf7, 7, [1, 5, 6, 7, 10, 15]), + PF8: (pf8, 8, [1, 5, 6, 7, 9, 10, 15]), + PF9: (pf9, 9, [1, 5, 6, 7, 9, 10, 15]), + PF10: (pf10, 10, [1, 2, 4, 9, 13, 14, 15]), + PF11: (pf11, 11, [5, 9, 10, 12, 13, 15]), + PF12: (pf12, 12, [9, 12, 15]), + PF13: (pf13, 13, [3, 4, 12, 15]), + PF14: (pf14, 14, [3, 4, 12, 15]), + PF15: (pf15, 15, [4, 12, 15]), +]); + +#[cfg(feature = "gpio-h7a2")] +gpio!(GPIOG, gpiog, Gpiog, PG, 'G', PGn, [ + PG0: (pg0, 0, [9, 11, 12, 15]), + PG1: (pg1, 1, [9, 11, 12, 15]), + PG2: (pg2, 2, [3, 11, 12, 15]), + PG3: (pg3, 3, [3, 11, 12, 15]), + PG4: (pg4, 4, [1, 11, 12, 15]), + PG5: (pg5, 5, [1, 12, 15]), + PG6: (pg6, 6, [1, 10, 12, 13, 14, 15]), + PG7: (pg7, 7, [6, 7, 9, 12, 13, 14, 15]), + PG8: (pg8, 8, [3, 5, 7, 8, 12, 14, 15]), + PG9: (pg9, 9, [5, 7, 8, 9, 10, 11, 12, 13, 15]), + PG10: (pg10, 10, [3, 5, 9, 10, 11, 12, 13, 14, 15]), + PG11: (pg11, 11, [1, 5, 8, 9, 10, 11, 13, 14, 15]), + PG12: (pg12, 12, [1, 3, 5, 7, 8, 9, 10, 11, 12, 14, 15]), + PG13: (pg13, 13, [0, 1, 5, 7, 10, 11, 12, 14, 15]), + PG14: (pg14, 14, [0, 1, 5, 7, 9, 10, 11, 12, 14, 15]), + PG15: (pg15, 15, [7, 9, 11, 12, 13, 15]), +]); + +#[cfg(feature = "gpio-h7a2")] +gpio!(GPIOH, gpioh, Gpioh, PH, 'H', PHn, [ + PH0: (ph0, 0, [15]), + PH1: (ph1, 1, [15]), + PH2: (ph2, 2, [1, 9, 10, 12, 14, 15]), + PH3: (ph3, 3, [9, 10, 12, 14, 15]), + PH4: (ph4, 4, [4, 9, 10, 13, 14, 15]), + PH5: (ph5, 5, [4, 5, 12, 15]), + PH6: (ph6, 6, [2, 4, 5, 12, 13, 15]), + PH7: (ph7, 7, [4, 5, 12, 13, 15]), + PH8: (ph8, 8, [2, 4, 12, 13, 14, 15]), + PH9: (ph9, 9, [2, 4, 12, 13, 14, 15]), + PH10: (ph10, 10, [2, 4, 12, 13, 14, 15]), + PH11: (ph11, 11, [2, 4, 12, 13, 14, 15]), + PH12: (ph12, 12, [2, 4, 12, 13, 14, 15]), + PH13: (ph13, 13, [3, 8, 9, 12, 14, 15]), + PH14: (ph14, 14, [3, 8, 9, 12, 13, 14, 15]), + PH15: (ph15, 15, [3, 12, 13, 14, 15]), +]); + +#[cfg(feature = "gpio-h7a2")] gpio!(GPIOI, gpioi, Gpioi, PI, 'I', PIn, [ - PI0: (pi0, 0), - PI1: (pi1, 1), - PI2: (pi2, 2), - PI3: (pi3, 3), - PI4: (pi4, 4), - PI5: (pi5, 5), - PI6: (pi6, 6), - PI7: (pi7, 7), - PI8: (pi8, 8), - PI9: (pi9, 9), - PI10: (pi10, 10), - PI11: (pi11, 11), - PI12: (pi12, 12), - PI13: (pi13, 13), - PI14: (pi14, 14), - PI15: (pi15, 15), + PI0: (pi0, 0, [2, 5, 12, 13, 14, 15]), + PI1: (pi1, 1, [3, 5, 11, 12, 13, 14, 15]), + PI2: (pi2, 2, [3, 5, 12, 13, 14, 15]), + PI3: (pi3, 3, [3, 5, 12, 13, 15]), + PI4: (pi4, 4, [3, 10, 11, 12, 13, 14, 15]), + PI5: (pi5, 5, [3, 10, 12, 13, 14, 15]), + PI6: (pi6, 6, [3, 10, 12, 13, 14, 15]), + PI7: (pi7, 7, [3, 10, 12, 13, 14, 15]), + PI8: (pi8, 8, [15]), + PI9: (pi9, 9, [3, 8, 9, 12, 14, 15]), + PI10: (pi10, 10, [3, 12, 13, 14, 15]), + PI11: (pi11, 11, [3, 9, 10, 13, 15]), + PI12: (pi12, 12, [3, 14, 15]), + PI13: (pi13, 13, [3, 14, 15]), + PI14: (pi14, 14, [3, 14, 15]), + PI15: (pi15, 15, [9, 14, 15]), ]); +#[cfg(feature = "gpio-h7a2")] gpio!(GPIOJ, gpioj, Gpioj, PJ, 'J', PJn, [ - PJ0: (pj0, 0), - PJ1: (pj1, 1), - PJ2: (pj2, 2), - PJ3: (pj3, 3), - PJ4: (pj4, 4), - PJ5: (pj5, 5), - PJ6: (pj6, 6), - PJ7: (pj7, 7), - PJ8: (pj8, 8), - PJ9: (pj9, 9), - PJ10: (pj10, 10), - PJ11: (pj11, 11), - PJ12: (pj12, 12), - PJ13: (pj13, 13), - PJ14: (pj14, 14), - PJ15: (pj15, 15), + PJ0: (pj0, 0, [9, 14, 15]), + PJ1: (pj1, 1, [3, 14, 15]), + PJ2: (pj2, 2, [3, 14, 15]), + PJ3: (pj3, 3, [11, 14, 15]), + PJ4: (pj4, 4, [11, 14, 15]), + PJ5: (pj5, 5, [14, 15]), + PJ6: (pj6, 6, [3, 14, 15]), + PJ7: (pj7, 7, [0, 3, 14, 15]), + PJ8: (pj8, 8, [1, 3, 8, 14, 15]), + PJ9: (pj9, 9, [1, 3, 8, 14, 15]), + PJ10: (pj10, 10, [1, 3, 5, 14, 15]), + PJ11: (pj11, 11, [1, 3, 5, 14, 15]), + PJ12: (pj12, 12, [0, 9, 14, 15]), + PJ13: (pj13, 13, [9, 14, 15]), + PJ14: (pj14, 14, [14, 15]), + PJ15: (pj15, 15, [14, 15]), ]); +#[cfg(feature = "gpio-h7a2")] gpio!(GPIOK, gpiok, Gpiok, PK, 'K', PKn, [ - PK0: (pk0, 0), - PK1: (pk1, 1), - PK2: (pk2, 2), - PK3: (pk3, 3), - PK4: (pk4, 4), - PK5: (pk5, 5), - PK6: (pk6, 6), - PK7: (pk7, 7), - PK8: (pk8, 8), - PK9: (pk9, 9), - PK10: (pk10, 10), - PK11: (pk11, 11), - PK12: (pk12, 12), - PK13: (pk13, 13), - PK14: (pk14, 14), - PK15: (pk15, 15), + PK0: (pk0, 0, [1, 3, 5, 14, 15]), + PK1: (pk1, 1, [1, 3, 5, 14, 15]), + PK2: (pk2, 2, [1, 3, 10, 11, 14, 15]), + PK3: (pk3, 3, [3, 14, 15]), + PK4: (pk4, 4, [3, 14, 15]), + PK5: (pk5, 5, [3, 14, 15]), + PK6: (pk6, 6, [3, 14, 15]), + PK7: (pk7, 7, [14, 15]), ]); struct Gpio; @@ -772,7 +1189,7 @@ impl Gpio

{ 'F' => crate::pac::GPIOF::ptr() as _, 'G' => crate::pac::GPIOG::ptr() as _, 'H' => crate::pac::GPIOH::ptr() as _, - #[cfg(not(feature = "rm0468"))] + #[cfg(not(feature = "gpio-h72"))] 'I' => crate::pac::GPIOI::ptr() as _, 'J' => crate::pac::GPIOJ::ptr() as _, 'K' => crate::pac::GPIOK::ptr() as _, diff --git a/src/gpio/convert.rs b/src/gpio/convert.rs index 8d0dad31..e1dfd665 100644 --- a/src/gpio/convert.rs +++ b/src/gpio/convert.rs @@ -1,12 +1,5 @@ use super::*; -/// Const assert hack -struct Assert; - -impl Assert { - pub const LESS: () = assert!(L < R); -} - impl Pin> { @@ -25,6 +18,7 @@ impl< > From> for Pin> where Alternate: PinMode, + Self: marker::IntoAf, { #[inline(always)] fn from(f: Pin) -> Self { @@ -35,6 +29,8 @@ where impl From>> for Pin> +where + Self: marker::IntoAf, { #[inline(always)] fn from(f: Pin>) -> Self { @@ -137,7 +133,9 @@ macro_rules! af { #[doc=stringify!($A)] #[doc=" mode"] #[deprecated(since = "0.12.0", note = "Use the .into_alternate() method instead")] - pub fn $into_alternate_af(self) -> Pin> { + pub fn $into_alternate_af(self) -> Pin> where + Self: marker::IntoAf<$A>, + { self.into_alternate::<$A>() } )+ @@ -148,11 +146,10 @@ impl Pin { /// Configures the pin to operate alternate mode pub fn into_alternate( self, - ) -> Pin> { - #[allow(path_statements, clippy::no_effect)] - { - Assert::::LESS; - } + ) -> Pin> + where + Self: marker::IntoAf, + { self.into_mode() } @@ -179,11 +176,10 @@ impl Pin { #[allow(path_statements)] pub fn into_alternate_open_drain( self, - ) -> Pin> { - #[allow(path_statements, clippy::no_effect)] - { - Assert::::LESS; - } + ) -> Pin> + where + Self: marker::IntoAf, + { self.into_mode() } diff --git a/src/gpio/partially_erased.rs b/src/gpio/partially_erased.rs index 08c2dcda..90f2ef9a 100644 --- a/src/gpio/partially_erased.rs +++ b/src/gpio/partially_erased.rs @@ -136,3 +136,14 @@ where unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << self.i) == 0 } } } + +impl From> + for ErasedPin +{ + /// Partially erased pin-to-erased pin conversion using the [`From`] trait. + /// + /// Note that [`From`] is the reciprocal of [`Into`]. + fn from(p: PartiallyErasedPin) -> Self { + ErasedPin::new(P as u8 - b'A', p.i) + } +} diff --git a/src/pwm.rs b/src/pwm.rs index c13d282f..4d5833ea 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -886,7 +886,7 @@ pins! { gpio::PB0>, gpio::PB14>, gpio::PH14>, - #[cfg(not(feature = "stm32h7b0"))] + #[cfg(not(any(feature = "stm32h7b0", feature = "rm0468")))] gpio::PJ7>, #[cfg(not(feature = "stm32h7b0"))] gpio::PJ11> diff --git a/src/qei.rs b/src/qei.rs index 305619dc..6f8f27c8 100644 --- a/src/qei.rs +++ b/src/qei.rs @@ -126,7 +126,7 @@ pins! { gpio::PI6>, #[cfg(not(any(feature = "stm32h7b0", feature = "rm0468")))] gpio::PJ6>, - #[cfg(not(feature = "stm32h7b0"))] + #[cfg(not(any(feature = "stm32h7b0", feature = "rm0468")))] gpio::PJ7>, #[cfg(not(feature = "stm32h7b0"))] gpio::PJ10>, From 3ab88f0bff31eee555e810267e663c6ca44d4c1e Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Wed, 17 Aug 2022 16:33:31 +0300 Subject: [PATCH 05/75] usb_serial example --- CHANGELOG.md | 5 +---- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8d47262..e628a179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased * Update `smoltcp` dependency to `0.9.0` * MSRV increased to 1.65.0 +* add `IntoAf` trait to restrict `into_alternate` [#346] ## [v0.14.0] 2023-03-22 @@ -32,9 +33,6 @@ * adc: Remove unnecessary multiple reads of the CR register [#364] * adc: Add DMA TargetAddress implementations [#389] * adc: Poll LDORDY bit before ADC calibration [#386] -* Remove pulling from `Input` mode. Use `internal_regiter(Pull)` instead, - add universal `into_mode::()` pin mode converter, - `AFx` is now alias to `Alternate` [#346] * flash: Rewrite `write_sector` to correctly write data in 256 bit chunks [#371] * flash: Use Ordering fence to prevent inconsistency errors when writing to flash sector [#382] * iwdt: Added HAL implementation. Changed the name of the other implementation to `system_watchdog` [#376] @@ -65,7 +63,6 @@ `Input`. Use `internal_resistor()` method instead, add universal `into_mode::()` pin mode converter, Rename `set_speed()` method to `speed()` `AFx` is now alias to `Alternate` [#347] - * **Breaking**: Use [fugit](https://docs.rs/fugit/0.3.5/fugit/index.html) crate for duration and rate units. `.mhz()` -> `.MHz()`, `.khz()` -> `.kHz()`, `.hz()` -> `.Hz()`. Methods that previously accepted durations (`.ms()`, diff --git a/Cargo.toml b/Cargo.toml index 9a1683de..e1e8b7ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -230,7 +230,7 @@ required-features = ["rt"] [[example]] name = "usb_serial" -required-features = ["usb_hs"] +required-features = ["usb_hs", "gpio-h747"] [[example]] name = "usb_rtic" From 9d7e788172fd910b3608ac50de7899c1b667cebf Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 1 Jul 2023 13:35:10 +0200 Subject: [PATCH 06/75] Expand vos0 example to support rm0455 parts --- Cargo.toml | 2 +- examples/vos0.rs | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a51868ae..da108acb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -153,7 +153,7 @@ required-features = ["rt", "rm0433"] [[example]] name = "vos0" -required-features = ["revision_v", "rm0433"] +required-features = ["revision_v"] [[example]] name = "fmc" diff --git a/examples/vos0.rs b/examples/vos0.rs index 385ba402..a633e31f 100644 --- a/examples/vos0.rs +++ b/examples/vos0.rs @@ -1,3 +1,6 @@ +//! Example that demonstrates the use of VOS0 +//! +//! 7b3/7a3/7b0 support tested on a NUCLEO-H7A3ZI-Q board #![deny(warnings)] #![no_main] #![no_std] @@ -20,12 +23,17 @@ fn main() -> ! { let pwrcfg = example_power!(pwr).vos0(&dp.SYSCFG).freeze(); // Constrain and Freeze clock - // The PllConfigStrategy::Normal strategy uses the medium range VCO which has a maximum of 420 Mhz - // Switching to PllConfigStrategy::Iterative sets the VCO to wide range to allow this clock to reach 480 Mhz + // + // The PllConfigStrategy::Normal strategy uses the medium range VCO which + // has a maximum of 420 MHz. Switching to PllConfigStrategy::Iterative sets + // the VCO to wide range to allow this clock to reach 480 MHz info!("Setup RCC... "); let rcc = dp.RCC.constrain(); + #[cfg(not(feature = "rm0455"))] + let rcc = rcc.sys_ck(480.MHz()); + #[cfg(feature = "rm0455")] // 7b3/7a3/7b0 parts are limited to 280MHz + let rcc = rcc.sys_ck(280.MHz()); let ccdr = rcc - .sys_ck(480.MHz()) .pll1_strategy(rcc::PllConfigStrategy::Iterative) .freeze(pwrcfg, &dp.SYSCFG); @@ -35,11 +43,17 @@ fn main() -> ! { // HCLK info!("hclk = {} MHz", ccdr.clocks.hclk().raw() as f32 / 1e6); + #[cfg(not(feature = "rm0455"))] assert_eq!(ccdr.clocks.hclk().raw(), 240_000_000); + #[cfg(feature = "rm0455")] // 7b3/7a3/7b0 parts + assert_eq!(ccdr.clocks.hclk().raw(), 280_000_000); // SYS_CK info!("sys_ck = {} MHz", ccdr.clocks.sys_ck().raw() as f32 / 1e6); + #[cfg(not(feature = "rm0455"))] assert_eq!(ccdr.clocks.sys_ck().raw(), 480_000_000); + #[cfg(feature = "rm0455")] // 7b3/7a3/7b0 parts + assert_eq!(ccdr.clocks.sys_ck().raw(), 280_000_000); loop { cortex_m::asm::nop() From a6ccc611653683ec0c39e6de4f337b4a0d12c6d9 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 1 Jul 2023 13:57:51 +0200 Subject: [PATCH 07/75] replace bors with merge queue --- .github/bors.toml | 21 --------------------- .github/workflows/ci.yml | 12 +++++++++++- CHANGELOG.md | 1 + 3 files changed, 12 insertions(+), 22 deletions(-) delete mode 100644 .github/bors.toml diff --git a/.github/bors.toml b/.github/bors.toml deleted file mode 100644 index e9d9378a..00000000 --- a/.github/bors.toml +++ /dev/null @@ -1,21 +0,0 @@ -block_labels = ["wip"] -delete_merged_branches = true -status = [ - "Rustfmt", - "ci (1.65.0, stm32h743)", - "ci (1.65.0, stm32h753)", - "ci (1.65.0, stm32h743v)", - "ci (1.65.0, stm32h753v)", - "ci (1.65.0, stm32h747cm7)", - "ci (1.65.0, stm32h7b3)", - "ci (1.65.0, stm32h7b0)", - "ci (1.65.0, stm32h735)", - "ci (stable, stm32h743)", - "ci (stable, stm32h753)", - "ci (stable, stm32h743v)", - "ci (stable, stm32h753v)", - "ci (stable, stm32h747cm7)", - "ci (stable, stm32h7b3)", - "ci (stable, stm32h7b0)", - "ci (stable, stm32h735)", -] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5aebfbc..bd6e85b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,22 @@ on: push: - branches: [ staging, trying, master ] + branches: master pull_request: + merge_group: name: Continuous integration jobs: ci: + name: CI + runs-on: ubuntu-latest + needs: [check] + if: always() + steps: + - name: Done + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' + + check: runs-on: ubuntu-latest strategy: matrix: # All permutations of {rust, mcu} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d1f2a2e..f6e595db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased +* bors bot replaced with GH merge queue * Update `smoltcp` dependency to `0.9.0` * MSRV increased to 1.65.0 From 723c33212f1eea7381eba33cf5e07c378bea2f38 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 1 Jul 2023 13:48:20 +0200 Subject: [PATCH 08/75] Remove unnecessary borrows in unsafe register write expressions --- src/pwr.rs | 6 ++---- src/sai/mod.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/pwr.rs b/src/pwr.rs index decc4143..69d40046 100644 --- a/src/pwr.rs +++ b/src/pwr.rs @@ -510,11 +510,9 @@ impl Pwr { ))] if matches!(self.target_vos, VoltageScale::Scale0) { unsafe { - &(*RCC::ptr()).apb4enr.modify(|_, w| w.syscfgen().enabled()) - }; - unsafe { - &(*SYSCFG::ptr()).pwrcr.modify(|_, w| w.oden().set_bit()) + (*RCC::ptr()).apb4enr.modify(|_, w| w.syscfgen().enabled()) }; + unsafe { (*SYSCFG::ptr()).pwrcr.modify(|_, w| w.oden().set_bit()) }; while d3cr!(self.rb).read().vosrdy().bit_is_clear() {} vos = VoltageScale::Scale0; } diff --git a/src/sai/mod.rs b/src/sai/mod.rs index de5819f2..381ab334 100644 --- a/src/sai/mod.rs +++ b/src/sai/mod.rs @@ -288,7 +288,7 @@ macro_rules! sai_hal { /// e.g. for SAI1 1-3 are valid and 0 is invalid pub fn set_sync_input(&mut self, selection: u8) { assert!(selection < 0b1_00); - unsafe { &self.rb.gcr.modify(|_, w| w.syncout().bits(selection)) }; + unsafe { self.rb.gcr.modify(|_, w| w.syncout().bits(selection)) }; } /// Synchronization output for other SAI blocks From 258e5c8c6a2e81744c731e8e70ed51626995de4e Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 1 Jul 2023 13:55:08 +0200 Subject: [PATCH 09/75] Simplify cfg expressions --- src/pwr.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pwr.rs b/src/pwr.rs index 69d40046..5f9258c6 100644 --- a/src/pwr.rs +++ b/src/pwr.rs @@ -98,7 +98,7 @@ impl PwrExt for PWR { fn constrain(self) -> Pwr { Pwr { rb: self, - #[cfg(any(feature = "smps"))] + #[cfg(feature = "smps")] supply_configuration: SupplyConfiguration::Default, target_vos: VoltageScale::Scale1, backup_regulator: false, @@ -111,7 +111,7 @@ impl PwrExt for PWR { /// Generated by calling `constrain` on the PAC's PWR peripheral. pub struct Pwr { pub(crate) rb: PWR, - #[cfg(any(feature = "smps"))] + #[cfg(feature = "smps")] supply_configuration: SupplyConfiguration, target_vos: VoltageScale, backup_regulator: bool, @@ -157,7 +157,7 @@ impl PowerConfiguration { /// SMPS Supply Configuration - Dual Core parts /// /// Refer to RM0399 Rev 3 Table 32. -#[cfg(any(feature = "smps"))] +#[cfg(feature = "smps")] enum SupplyConfiguration { Default = 0, LDOSupply, @@ -168,7 +168,7 @@ enum SupplyConfiguration { Bypass, } -#[cfg(any(feature = "smps"))] +#[cfg(feature = "smps")] macro_rules! supply_configuration_setter { ($($config:ident: $name:ident, $doc:expr,)*) => { $( @@ -265,7 +265,7 @@ pub(crate) fn current_vos() -> VoltageScale { /// Internal power methods impl Pwr { /// Verify that the lower byte of CR3 reads as written - #[cfg(any(feature = "smps"))] + #[cfg(feature = "smps")] fn verify_supply_configuration(&self) { use SupplyConfiguration::*; let error = "Values in lower byte of PWR.CR3 do not match the \ @@ -367,7 +367,7 @@ impl Pwr { /// Builder methods impl Pwr { - #[cfg(any(feature = "smps"))] + #[cfg(feature = "smps")] supply_configuration_setter! { LDOSupply: ldo, "VCORE power domains supplied from the LDO. \ LDO voltage adjusted by VOS. \ @@ -449,7 +449,7 @@ impl Pwr { w.scuen().set_bit().ldoen().set_bit().bypass().clear_bit() }); - #[cfg(any(feature = "smps"))] + #[cfg(feature = "smps")] self.rb.cr3.modify(|_, w| { use SupplyConfiguration::*; @@ -481,7 +481,7 @@ impl Pwr { }); // Verify supply configuration, panics if these values read // from CR3 do not match those written. - #[cfg(any(feature = "smps"))] + #[cfg(feature = "smps")] self.verify_supply_configuration(); // Validate the supply configuration. If you are stuck here, it is From adbe62d42f1c98e4e871bc469cfe300f12e8db0a Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 1 Jul 2023 13:55:31 +0200 Subject: [PATCH 10/75] Use new default syntax --- src/adc.rs | 8 ++------ src/dma/mdma.rs | 24 ++++++------------------ src/dma/mod.rs | 8 ++------ src/rcc/rec.rs | 8 ++------ 4 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index 5f1310ae..f07391c1 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -89,7 +89,7 @@ pub enum AdcDmaMode { /// Options for the sampling time, each is T + 0.5 ADC clock cycles. // // Refer to RM0433 Rev 7 - Chapter 25.4.13 -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[allow(non_camel_case_types)] pub enum AdcSampleTime { @@ -102,6 +102,7 @@ pub enum AdcSampleTime { /// 16.5 cycles sampling time T_16, /// 32.5 cycles sampling time + #[default] T_32, /// 64.5 cycles sampling time T_64, @@ -111,11 +112,6 @@ pub enum AdcSampleTime { T_810, } -impl Default for AdcSampleTime { - fn default() -> Self { - AdcSampleTime::T_32 - } -} impl AdcSampleTime { /// Returns the number of half clock cycles represented by this sampling time fn clock_cycles_x2(&self) -> u32 { diff --git a/src/dma/mdma.rs b/src/dma/mdma.rs index ca74d979..52d884fb 100644 --- a/src/dma/mdma.rs +++ b/src/dma/mdma.rs @@ -208,11 +208,12 @@ impl MdmaSize { } /// MDMA increment mode -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum MdmaIncrement { Fixed, /// Increment by one source/destination element each element + #[default] Increment, /// Decrement by one source/destination element each element Decrement, @@ -225,11 +226,6 @@ pub enum MdmaIncrement { /// initialisation will panic DecrementWithOffset(MdmaSize), } -impl Default for MdmaIncrement { - fn default() -> Self { - MdmaIncrement::Increment - } -} /// MDMA burst size. This type contains the _register_ value, thus the burst /// size is equal to 2^N where N is the register value. @@ -278,10 +274,11 @@ impl defmt::Format for MdmaBurstSize { } /// MDMA Packing/Alignment mode -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum MdmaPackingAlignment { /// Source data is packed/unpacked into the destination data size + #[default] Packed, /// Source data is extended into the destination data size. Source data /// smaller than the destination is right-aligned and padded with zeros @@ -299,30 +296,21 @@ pub enum MdmaPackingAlignment { /// of the source is written to the destination. TruncateLeft, } -impl Default for MdmaPackingAlignment { - fn default() -> Self { - MdmaPackingAlignment::Packed - } -} /// MDMA trigger mode -#[derive(Debug, Clone, Copy)] +#[derive(Default, Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum MdmaTrigger { /// Each MDMA request triggers a buffer transfer Buffer = 0b00, /// Each MDMA request triggers a block transfer + #[default] Block = 0b01, /// Each MDMA request triggers a repeated block transfer (Not Supported) RepeatedBlock = 0b10, /// Each MDMA request triggers a linked-link transfer (Not Supported) LinkedList = 0b11, } -impl Default for MdmaTrigger { - fn default() -> Self { - MdmaTrigger::Block - } -} /// MDMA interrupts #[derive(Debug, Clone, Copy)] diff --git a/src/dma/mod.rs b/src/dma/mod.rs index a5d47b61..6359792d 100644 --- a/src/dma/mod.rs +++ b/src/dma/mod.rs @@ -272,23 +272,19 @@ pub mod config { /// the same software priority level, the stream with the lower number takes /// priority over the stream with the higher number. For example, Stream 2 /// takes priority over Stream 4. - #[derive(Debug, Clone, Copy)] + #[derive(Default, Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Priority { /// Low priority. Low, /// Medium priority. + #[default] Medium, /// High priority. High, /// Very high priority. VeryHigh, } - impl Default for Priority { - fn default() -> Self { - Priority::Medium - } - } impl Bits for Priority { fn bits(self) -> u8 { diff --git a/src/rcc/rec.rs b/src/rcc/rec.rs index f7de20df..6b2390da 100644 --- a/src/rcc/rec.rs +++ b/src/rcc/rec.rs @@ -92,22 +92,18 @@ pub trait ResetEnable { /// The clock gating state of a peripheral in low-power mode /// /// See RM0433 rev 7. Section 8.5.11 -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Default, Copy, Clone, PartialEq, Eq)] pub enum LowPowerMode { /// Kernel and bus interface clocks are not provided in low-power modes. Off, /// Kernel and bus interface clocks are provided in CSleep mode. + #[default] Enabled, /// Kernel and bus interface clocks are provided in both CSleep and CStop /// modes. Only applies to peripherals in the D3 / SRD. If the peripheral is /// not in the D3 / SRD then this has the same effect as `Enabled`. Autonomous, } -impl Default for LowPowerMode { - fn default() -> Self { - LowPowerMode::Enabled - } -} impl Rcc { /// Returns all the peripherals resets / enables / kernel clocks. From 8b0cf3f4df1f12d92bac3cb527d6c5ea6a66375d Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 1 Jul 2023 14:23:09 +0200 Subject: [PATCH 11/75] Elide unnecessary explicit lifetime --- src/spi.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index 3e17819b..44edc11f 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -1170,9 +1170,7 @@ macro_rules! spi { } /// Internal implementation for blocking::spi::Write - fn transfer_internal_w<'w>(&mut self, - write_words: &'w [$TY], - ) -> Result<(), Error> { + fn transfer_internal_w(&mut self, write_words: &[$TY]) -> Result<(), Error> { use hal::spi::FullDuplex; // both buffers are the same length @@ -1230,9 +1228,7 @@ macro_rules! spi { } /// Internal implementation for blocking::spi::Transfer - fn transfer_internal_rw<'w>(&mut self, - words : &'w mut [$TY] - ) -> Result<(), Error> { + fn transfer_internal_rw(&mut self, words : &mut [$TY]) -> Result<(), Error> { use hal::spi::FullDuplex; if words.is_empty() { From d900ece32f6b44c8ddb5412d301febc69cffcd9b Mon Sep 17 00:00:00 2001 From: paul Date: Sat, 17 Jun 2023 15:12:54 -0700 Subject: [PATCH 12/75] Add additional possibility for WWDG1RSTF to WindowWatchdogReset arm. --- src/rcc/reset_reason.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcc/reset_reason.rs b/src/rcc/reset_reason.rs index c02f9f0d..4a57770b 100644 --- a/src/rcc/reset_reason.rs +++ b/src/rcc/reset_reason.rs @@ -40,7 +40,7 @@ pub fn get_reset_reason(rcc: &mut crate::stm32::RCC) -> ResetReason { (false, false, false, false, false, false, false, false, false, true) => { ResetReason::CpuReset } - (false, true, false, false, false, true, false, false, false, true) => { + (false, true, false, false, false, false, false, false, false, false) | (false, true, false, false, false, true, false, false, false, true) => { ResetReason::WindowWatchdogReset } (false, false, true, false, false, true, false, false, false, true) => { From 1978fe7504db622e29ca3f3bd1acd0847eeb4c92 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 1 Jul 2023 21:35:03 +0200 Subject: [PATCH 13/75] Update smoltcp dependency to 0.10.0 --- Cargo.toml | 4 ++-- examples/ethernet-nucleo-h743zi2.rs | 3 ++- examples/ethernet-rtic-stm32h735g-dk.rs | 16 ++++++++++------ examples/ethernet-rtic-stm32h747i-disco.rs | 16 ++++++++++------ examples/ethernet-stm32h747i-disco.rs | 3 ++- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e1bf6a5d..0e36c2b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ bitflags = { version = "2.0.0" } embedded-storage = "0.3" [dependencies.smoltcp] -version = "0.9.0" +version = "0.10.0" default-features = false features = ["medium-ethernet", "proto-ipv4", "socket-raw"] optional = true @@ -84,7 +84,7 @@ tinybmp = "0.4" embedded-graphics = "0.7" [dev-dependencies.smoltcp] -version = "0.9.0" +version = "0.10.0" default-features = false features = ["medium-ethernet", "proto-ipv4", "proto-ipv6", "socket-raw"] diff --git a/examples/ethernet-nucleo-h743zi2.rs b/examples/ethernet-nucleo-h743zi2.rs index c1dfef5d..29fa24fc 100644 --- a/examples/ethernet-nucleo-h743zi2.rs +++ b/examples/ethernet-nucleo-h743zi2.rs @@ -6,7 +6,8 @@ //! The ethernet ring buffers are placed in SRAM3, where they can be //! accessed by both the core and the Ethernet DMA. //! -//! This demo doesn't use smoltcp - see the stm32h747i-disco-rtic demo +//! This demo does not use smoltcp - see the ethernet-rtic-stm32h747i-disco demo +//! for an example of smoltcp #![deny(warnings)] #![no_main] #![no_std] diff --git a/examples/ethernet-rtic-stm32h735g-dk.rs b/examples/ethernet-rtic-stm32h735g-dk.rs index 16875956..7c27ea19 100644 --- a/examples/ethernet-rtic-stm32h735g-dk.rs +++ b/examples/ethernet-rtic-stm32h735g-dk.rs @@ -50,7 +50,6 @@ pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } static mut STORE: NetStorageStatic = NetStorageStatic { - // Garbage socket_storage: [SocketStorage::EMPTY; 8], }; @@ -64,11 +63,10 @@ impl<'a> Net<'a> { store: &'a mut NetStorageStatic<'a>, mut ethdev: ethernet::EthernetDMA<4, 4>, ethernet_addr: HardwareAddress, + now: Instant, ) -> Self { - let mut config = Config::new(); - config.hardware_addr = Some(ethernet_addr); - - let mut iface = Interface::new(config, &mut ethdev); + let config = Config::new(ethernet_addr); + let mut iface = Interface::new(config, &mut ethdev, now); // Set IP address iface.update_ip_addrs(|addrs| { let _ = addrs.push(IpCidr::new(IpAddress::v4(192, 168, 1, 99), 0)); @@ -189,7 +187,13 @@ mod app { // unsafe: mutable reference to static storage, we only do this once let store = unsafe { &mut STORE }; - let net = Net::new(store, eth_dma, mac_addr.into()); + + // if you use a link_section attribute to relocate STORE to another + // memory it will *NOT* be initialised by the cortex-m + // prelude. Therefore it would need to be initialised here + store.socket_storage = [SocketStorage::EMPTY; 8]; + + let net = Net::new(store, eth_dma, mac_addr.into(), Instant::ZERO); // 1ms tick systick_init(ctx.core.SYST, ccdr.clocks); diff --git a/examples/ethernet-rtic-stm32h747i-disco.rs b/examples/ethernet-rtic-stm32h747i-disco.rs index 2f6ad1b7..1aad659b 100644 --- a/examples/ethernet-rtic-stm32h747i-disco.rs +++ b/examples/ethernet-rtic-stm32h747i-disco.rs @@ -57,7 +57,6 @@ pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } static mut STORE: NetStorageStatic = NetStorageStatic { - // Garbage socket_storage: [SocketStorage::EMPTY; 8], }; @@ -71,11 +70,10 @@ impl<'a> Net<'a> { store: &'a mut NetStorageStatic<'a>, mut ethdev: ethernet::EthernetDMA<4, 4>, ethernet_addr: HardwareAddress, + now: Instant, ) -> Self { - let mut config = Config::new(); - config.hardware_addr = Some(ethernet_addr); - - let mut iface = Interface::new(config, &mut ethdev); + let config = Config::new(ethernet_addr); + let mut iface = Interface::new(config, &mut ethdev, now); // Set IP address iface.update_ip_addrs(|addrs| { let _ = addrs.push(IpCidr::new(IpAddress::v4(192, 168, 1, 99), 0)); @@ -199,7 +197,13 @@ mod app { // unsafe: mutable reference to static storage, we only do this once let store = unsafe { &mut STORE }; - let net = Net::new(store, eth_dma, mac_addr.into()); + + // if you use a link_section attribute to relocate STORE to another + // memory it will *NOT* be initialised by the cortex-m + // prelude. Therefore it would need to be initialised here + store.socket_storage = [SocketStorage::EMPTY; 8]; + + let net = Net::new(store, eth_dma, mac_addr.into(), Instant::ZERO); // 1ms tick systick_init(ctx.core.SYST, ccdr.clocks); diff --git a/examples/ethernet-stm32h747i-disco.rs b/examples/ethernet-stm32h747i-disco.rs index 799d897c..206c4e43 100644 --- a/examples/ethernet-stm32h747i-disco.rs +++ b/examples/ethernet-stm32h747i-disco.rs @@ -5,7 +5,8 @@ //! The ethernet ring buffers are placed in SRAM3, where they can be //! accessed by both the core and the Ethernet DMA. //! -//! This demo doesn't use smoltcp - see the stm32h747i-disco-rtic demo +//! This demo does not use smoltcp - see the ethernet-rtic-stm32h747i-disco demo +//! for an example of smoltcp #![deny(warnings)] #![no_main] #![no_std] From 11c5eba9fd2f0b66dd534d23c6c1365a710e456e Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:04:50 +0200 Subject: [PATCH 14/75] Use MaybeUninit to solve UB in ethernet-rtic examples --- examples/ethernet-rtic-stm32h735g-dk.rs | 29 ++++++++++++++-------- examples/ethernet-rtic-stm32h747i-disco.rs | 29 ++++++++++++++-------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/examples/ethernet-rtic-stm32h735g-dk.rs b/examples/ethernet-rtic-stm32h735g-dk.rs index 7c27ea19..033a8204 100644 --- a/examples/ethernet-rtic-stm32h735g-dk.rs +++ b/examples/ethernet-rtic-stm32h735g-dk.rs @@ -15,6 +15,8 @@ #[allow(unused)] mod utilities; +use core::mem::MaybeUninit; +use core::ptr::addr_of_mut; use core::sync::atomic::AtomicU32; use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage}; @@ -45,13 +47,13 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; #[link_section = ".axisram.eth"] static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); -/// Net storage with static initialisation - another global singleton +// This data will be held by Net through a mutable reference pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } -static mut STORE: NetStorageStatic = NetStorageStatic { - socket_storage: [SocketStorage::EMPTY; 8], -}; +// MaybeUninit allows us write code that is correct even if STORE is not +// initialised by the runtime +static mut STORE: MaybeUninit = MaybeUninit::uninit(); pub struct Net<'a> { iface: Interface, @@ -186,12 +188,19 @@ mod app { unsafe { ethernet::enable_interrupt() }; // unsafe: mutable reference to static storage, we only do this once - let store = unsafe { &mut STORE }; - - // if you use a link_section attribute to relocate STORE to another - // memory it will *NOT* be initialised by the cortex-m - // prelude. Therefore it would need to be initialised here - store.socket_storage = [SocketStorage::EMPTY; 8]; + let store = unsafe { + let store_ptr = STORE.as_mut_ptr(); + + // Initialise the socket_storage field. Using `write` instead of + // assignment via `=` to not call `drop` on the old, uninitialised + // value + addr_of_mut!((*store_ptr).socket_storage) + .write([SocketStorage::EMPTY; 8]); + + // Now that all fields are initialised we can safely use + // assume_init_mut to return a mutable reference to STORE + STORE.assume_init_mut() + }; let net = Net::new(store, eth_dma, mac_addr.into(), Instant::ZERO); diff --git a/examples/ethernet-rtic-stm32h747i-disco.rs b/examples/ethernet-rtic-stm32h747i-disco.rs index 1aad659b..7d6525d7 100644 --- a/examples/ethernet-rtic-stm32h747i-disco.rs +++ b/examples/ethernet-rtic-stm32h747i-disco.rs @@ -22,6 +22,8 @@ #[allow(unused)] mod utilities; +use core::mem::MaybeUninit; +use core::ptr::addr_of_mut; use core::sync::atomic::AtomicU32; use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage}; @@ -52,13 +54,13 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; #[link_section = ".sram3.eth"] static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); -/// Net storage with static initialisation - another global singleton +// This data will be held by Net through a mutable reference pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } -static mut STORE: NetStorageStatic = NetStorageStatic { - socket_storage: [SocketStorage::EMPTY; 8], -}; +// MaybeUninit allows us write code that is correct even if STORE is not +// initialised by the runtime +static mut STORE: MaybeUninit = MaybeUninit::uninit(); pub struct Net<'a> { iface: Interface, @@ -196,12 +198,19 @@ mod app { unsafe { ethernet::enable_interrupt() }; // unsafe: mutable reference to static storage, we only do this once - let store = unsafe { &mut STORE }; - - // if you use a link_section attribute to relocate STORE to another - // memory it will *NOT* be initialised by the cortex-m - // prelude. Therefore it would need to be initialised here - store.socket_storage = [SocketStorage::EMPTY; 8]; + let store = unsafe { + let store_ptr = STORE.as_mut_ptr(); + + // Initialise the socket_storage field. Using `write` instead of + // assignment via `=` to not call `drop` on the old, uninitialised + // value + addr_of_mut!((*store_ptr).socket_storage) + .write([SocketStorage::EMPTY; 8]); + + // Now that all fields are initialised we can safely use + // assume_init_mut to return a mutable reference to STORE + STORE.assume_init_mut() + }; let net = Net::new(store, eth_dma, mac_addr.into(), Instant::ZERO); From 24ebea4ce529ddcf694aed81bdb5d7b26d01c790 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 22 Jul 2023 14:36:42 +0200 Subject: [PATCH 15/75] Bump embedded-sdmmc from 0.4 to 0.5 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0e36c2b0..5aed3c24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ nb = "1.0.0" paste = "1.0.1" bare-metal = "1.0.0" sdio-host = { version = "0.9", optional = true } -embedded-sdmmc = { version = "0.4", optional = true } +embedded-sdmmc = { version = "0.5", optional = true } stm32-fmc = { version = "0.3", optional = true } synopsys-usb-otg = { version = "^0.3.0", features = ["cortex-m"], optional = true } embedded-display-controller = { version = "^0.1.0", optional = true } From 79af0adf3b6f64314e03ddf37354a4b00ac638f8 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 22 Jul 2023 14:37:00 +0200 Subject: [PATCH 16/75] Bump fdcan from 0.1 to 0.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5aed3c24..c31558b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ stm32-fmc = { version = "0.3", optional = true } synopsys-usb-otg = { version = "^0.3.0", features = ["cortex-m"], optional = true } embedded-display-controller = { version = "^0.1.0", optional = true } log = { version = "0.4.14", optional = true} # see also the dev-dependencies section -fdcan = { version = "0.1", optional = true } +fdcan = { version = "0.2", optional = true } bitflags = { version = "2.0.0" } embedded-storage = "0.3" From de1da6c336861949773c9d78e506422625467e7d Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 22 Jul 2023 14:37:10 +0200 Subject: [PATCH 17/75] Bump embedded-graphics from 0.7 to 0.8 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c31558b4..10c29db6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,8 +80,8 @@ panic-semihosting = "0.6" usb-device = "0.2.5" usbd-serial = "0.1.0" numtoa = "0.2.3" -tinybmp = "0.4" -embedded-graphics = "0.7" +tinybmp = "0.5" +embedded-graphics = "0.8" [dev-dependencies.smoltcp] version = "0.10.0" From 4864cde00ba9918c8b5bb49ebf378637e8a2e7a3 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 22 Jul 2023 14:55:24 +0200 Subject: [PATCH 18/75] Update [[example]] targets Reorder [[example]] targets alphabetically Remove some unnessesary required features Tidy documentation in sai_dma_passthru example --- Cargo.toml | 92 ++++++++++++++++++------------------ examples/sai_dma_passthru.rs | 3 +- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 10c29db6..5e00ce4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -148,17 +148,41 @@ debug = true # symbols are nice and they don't increase the size in flash lto = true # better optimizations opt-level = "s" # optimize for binary size +# The following examples do not build for all feature flag combinations. The +# `required-features` field specifies the hal features and/or the hardware +# configuration required by the example. + [[example]] -name = "rtic" -required-features = ["rt"] +name = "can-echo" +required-features = ["can"] [[example]] -name = "rtic_timers" -required-features = ["rt", "rm0433"] +name = "can-fd" +required-features = ["can"] [[example]] -name = "vos0" -required-features = ["revision_v"] +name = "crc" +required-features = ["crc"] + +[[example]] +name = "embedded-graphics" +required-features = ["ltdc", "xspi", "rm0468"] + +[[example]] +name = "ethernet-stm32h747i-disco" +required-features = ["rt", "stm32h747cm7", "ethernet"] + +[[example]] +name = "ethernet-rtic-stm32h747i-disco" +required-features = ["rt", "stm32h747cm7", "ethernet"] + +[[example]] +name = "ethernet-rtic-stm32h735g-dk" +required-features = ["rt", "stm32h735", "ethernet"] + +[[example]] +name = "ethernet-nucleo-h743zi2" +required-features = ["rt", "revision_v", "stm32h743v", "ethernet"] [[example]] name = "fmc" @@ -169,12 +193,12 @@ name = "fmc_nand_flash" required-features = ["fmc"] [[example]] -name = "can-echo" -required-features = ["can"] +name = "octospi" +required-features = ["xspi", "rm0468"] [[example]] -name = "can-fd" -required-features = ["can"] +name = "octospi_hyperram" +required-features = ["xspi", "rm0468"] [[example]] name = "qspi" @@ -189,12 +213,16 @@ name = "qspi_flash_memory" required-features = ["xspi", "rm0433"] [[example]] -name = "octospi" -required-features = ["xspi", "rm0468"] +name = "rtc" +required-features = ["rt", "rtc"] [[example]] -name = "octospi_hyperram" -required-features = ["xspi", "rm0468"] +name = "rtic" +required-features = ["rt"] + +[[example]] +name = "rtic_timers" +required-features = ["rt", "rm0433"] [[example]] name = "sdmmc" @@ -205,24 +233,8 @@ name = "sdmmc_fat" required-features = ["sdmmc", "sdmmc-fatfs"] [[example]] -name = "embedded-graphics" -required-features = ["ltdc", "xspi", "rm0468"] - -[[example]] -name = "ethernet-stm32h747i-disco" -required-features = ["rt", "stm32h747cm7", "ethernet"] - -[[example]] -name = "ethernet-rtic-stm32h747i-disco" -required-features = ["rt", "stm32h747cm7", "ethernet"] - -[[example]] -name = "ethernet-rtic-stm32h735g-dk" -required-features = ["rt", "stm32h735", "ethernet"] - -[[example]] -name = "ethernet-nucleo-h743zi2" -required-features = ["rt", "revision_v", "stm32h743v", "ethernet"] +name = "spi-dma-rtic" +required-features = ["rt"] [[example]] name = "tick_timer" @@ -245,17 +257,5 @@ name = "usb_phy_serial_interrupt" required-features = ["rt", "usb_hs", "rm0433"] [[example]] -name = "rtc" -required-features = ["rt", "rtc"] - -[[example]] -name = "sai_dma_passthru" -required-features = ["rm0433"] - -[[example]] -name = "spi-dma-rtic" -required-features = ["rm0433","rt"] - -[[example]] -name = "crc" -required-features = ["crc", "rt"] +name = "vos0" +required-features = ["revision_v"] diff --git a/examples/sai_dma_passthru.rs b/examples/sai_dma_passthru.rs index 55ac37fd..34bb0fc9 100644 --- a/examples/sai_dma_passthru.rs +++ b/examples/sai_dma_passthru.rs @@ -1,9 +1,8 @@ -//! This example was tested on the original Electro Smith Daisy Seed board with +//! This example was tested on the original Electro Smith Daisy Seed board (STM32H750) with //! AK4556 codec https://www.electro-smith.com/daisy #![allow(unused_macros)] #![deny(warnings)] -// #![deny(unsafe_code)] #![no_main] #![no_std] From a91052c09cfff6882bdbb1313b1c3c84cbf77fa2 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Wed, 26 Jul 2023 08:54:20 +0300 Subject: [PATCH 19/75] rm bitflags --- CHANGELOG.md | 2 ++ Cargo.toml | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 804eb9e7..ce1f7b10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## Unreleased + +* remove unused `bitflags` dependency * bors bot replaced with GH merge queue * Update `smoltcp` dependency to `0.9.0` * MSRV increased to 1.65.0 diff --git a/Cargo.toml b/Cargo.toml index 5e00ce4c..293b17dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,6 @@ synopsys-usb-otg = { version = "^0.3.0", features = ["cortex-m"], optional = tru embedded-display-controller = { version = "^0.1.0", optional = true } log = { version = "0.4.14", optional = true} # see also the dev-dependencies section fdcan = { version = "0.2", optional = true } -bitflags = { version = "2.0.0" } embedded-storage = "0.3" [dependencies.smoltcp] From c221c515027cf408eaa777e14437c10d296aaafc Mon Sep 17 00:00:00 2001 From: James Logan Date: Sat, 5 Aug 2023 15:52:05 -0400 Subject: [PATCH 20/75] Move ethernet DMA reset slightly earlier to eliminate freeze on h723 --- src/ethernet/eth.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ethernet/eth.rs b/src/ethernet/eth.rs index d786dac0..ebe6c485 100644 --- a/src/ethernet/eth.rs +++ b/src/ethernet/eth.rs @@ -455,6 +455,12 @@ pub unsafe fn new_unchecked( // Ensure syscfg is enabled (for PMCR) rcc.apb4enr.modify(|_, w| w.syscfgen().set_bit()); + // Reset ETH_DMA - write 1 and wait for 0. + // On the H723, we have to do this before prec.enable() + // or the DMA will never come out of reset + eth_dma.dmamr.modify(|_, w| w.swr().set_bit()); + while eth_dma.dmamr.read().swr().bit_is_set() {} + // AHB1 ETH1MACEN prec.enable(); @@ -465,6 +471,7 @@ pub unsafe fn new_unchecked( .modify(|_, w| w.eth1txen().set_bit().eth1rxen().set_bit()); syscfg.pmcr.modify(|_, w| w.epis().bits(0b100)); // RMII + } // reset ETH_MAC - write 1 then 0 @@ -472,9 +479,6 @@ pub unsafe fn new_unchecked( //rcc.ahb1rstr.modify(|_, w| w.eth1macrst().clear_bit()); cortex_m::interrupt::free(|_cs| { - // reset ETH_DMA - write 1 and wait for 0 - eth_dma.dmamr.modify(|_, w| w.swr().set_bit()); - while eth_dma.dmamr.read().swr().bit_is_set() {} // 200 MHz eth_mac From 6b21ffce9c21a4d9d2288ddb85f4f0fcf6dd49df Mon Sep 17 00:00:00 2001 From: James Logan Date: Sat, 5 Aug 2023 17:35:09 -0400 Subject: [PATCH 21/75] add example that brings up the ethernet link on the nucleo-h723zg --- examples/ethernet-rtic-nucleo-h723zg.rs | 236 ++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 examples/ethernet-rtic-nucleo-h723zg.rs diff --git a/examples/ethernet-rtic-nucleo-h723zg.rs b/examples/ethernet-rtic-nucleo-h723zg.rs new file mode 100644 index 00000000..c629e482 --- /dev/null +++ b/examples/ethernet-rtic-nucleo-h723zg.rs @@ -0,0 +1,236 @@ +//! Demo for STM32H735G-DK eval board using the Real Time for the Masses +//! (RTIC) framework. +//! +//! This demo responds to pings on 192.168.1.99 (IP address hardcoded below) +//! +//! We use the SysTick timer to create a 1ms timebase for use with smoltcp. +//! +//! The ethernet ring buffers are placed in AXI SRAM, where they can be +//! accessed by both the core and the Ethernet DMA. +//! +//! Run like +//! +//! `cargo flash --example ethernet-rtic-nucleo-h723zg --features=ethernet,stm32h735 --chip=STM32H723ZGTx` +#![deny(warnings)] +#![no_main] +#![no_std] + +#[macro_use] +#[allow(unused)] +mod utilities; + +use core::sync::atomic::AtomicU32; + +use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage}; +use smoltcp::time::Instant; +use smoltcp::wire::{HardwareAddress, IpAddress, IpCidr}; + +use stm32h7xx_hal::{ethernet, rcc::CoreClocks, stm32}; + +/// Configure SYSTICK for 1ms timebase +fn systick_init(mut syst: stm32::SYST, clocks: CoreClocks) { + let c_ck_mhz = clocks.c_ck().to_MHz(); + + let syst_calib = 0x3E8; + + syst.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core); + syst.set_reload((syst_calib * c_ck_mhz) - 1); + syst.enable_interrupt(); + syst.enable_counter(); +} + +/// TIME is an atomic u32 that counts milliseconds. +static TIME: AtomicU32 = AtomicU32::new(0); + +/// Locally administered MAC address +const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; + +/// Ethernet descriptor rings are a global singleton +#[link_section = ".axisram.eth"] +static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); + +/// Net storage with static initialisation - another global singleton +pub struct NetStorageStatic<'a> { + socket_storage: [SocketStorage<'a>; 8], +} +static mut STORE: NetStorageStatic = NetStorageStatic { + // Garbage + socket_storage: [SocketStorage::EMPTY; 8], +}; + +pub struct Net<'a> { + iface: Interface, + ethdev: ethernet::EthernetDMA<4, 4>, + sockets: SocketSet<'a>, +} +impl<'a> Net<'a> { + pub fn new( + store: &'a mut NetStorageStatic<'a>, + mut ethdev: ethernet::EthernetDMA<4, 4>, + ethernet_addr: HardwareAddress, + ) -> Self { + let mut config = Config::new(); + config.hardware_addr = Some(ethernet_addr); + + let mut iface = Interface::new(config, &mut ethdev); + // Set IP address + iface.update_ip_addrs(|addrs| { + let _ = addrs.push(IpCidr::new(IpAddress::v4(192, 168, 1, 99), 0)); + }); + + let sockets = SocketSet::new(&mut store.socket_storage[..]); + + Net::<'a> { + iface, + ethdev, + sockets, + } + } + + /// Polls on the ethernet interface. You should refer to the smoltcp + /// documentation for poll() to understand how to call poll efficiently + pub fn poll(&mut self, now: i64) { + let timestamp = Instant::from_millis(now); + + self.iface + .poll(timestamp, &mut self.ethdev, &mut self.sockets); + } +} + +#[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true)] +mod app { + use stm32h7xx_hal::{ethernet, ethernet::PHY, gpio, prelude::*}; + + use super::*; + use core::sync::atomic::Ordering; + + #[shared] + struct SharedResources {} + #[local] + struct LocalResources { + net: Net<'static>, + lan8742a: ethernet::phy::LAN8742A, + link_led: gpio::gpioe::PE1>, + } + + #[init] + fn init( + mut ctx: init::Context, + ) -> (SharedResources, LocalResources, init::Monotonics) { + utilities::logger::init(); + // Initialise power... + let pwr = ctx.device.PWR.constrain(); + let pwrcfg = pwr.ldo().freeze(); // nucleo-h723zg board doesn't have SMPS + + // Initialise clocks... + let rcc = ctx.device.RCC.constrain(); + let ccdr = rcc + .sys_ck(200.MHz()) + .hclk(200.MHz()) + .freeze(pwrcfg, &ctx.device.SYSCFG); + + // Initialise system... + ctx.core.SCB.invalidate_icache(); + ctx.core.SCB.enable_icache(); + // TODO: ETH DMA coherence issues + // ctx.core.SCB.enable_dcache(&mut ctx.core.CPUID); + ctx.core.DWT.enable_cycle_counter(); + + // Initialise IO... + let gpioa = ctx.device.GPIOA.split(ccdr.peripheral.GPIOA); + let gpioc = ctx.device.GPIOC.split(ccdr.peripheral.GPIOC); + let gpioe = ctx.device.GPIOE.split(ccdr.peripheral.GPIOE); + let gpiob = ctx.device.GPIOB.split(ccdr.peripheral.GPIOB); + let mut link_led = gpioe.pe1.into_push_pull_output(); // USR LED1 + link_led.set_high(); + + let rmii_ref_clk = gpioa.pa1.into_alternate(); + let rmii_mdio = gpioa.pa2.into_alternate(); + let rmii_mdc = gpioc.pc1.into_alternate(); + let rmii_crs_dv = gpioa.pa7.into_alternate(); + let rmii_rxd0 = gpioc.pc4.into_alternate(); + let rmii_rxd1 = gpioc.pc5.into_alternate(); + let rmii_tx_en = gpiob.pb11.into_alternate(); + let rmii_txd0 = gpiob.pb12.into_alternate(); + let rmii_txd1 = gpiob.pb13.into_alternate(); + + // Initialise ethernet... + assert_eq!(ccdr.clocks.hclk().raw(), 200_000_000); // HCLK 200MHz + assert_eq!(ccdr.clocks.pclk1().raw(), 100_000_000); // PCLK 100MHz + assert_eq!(ccdr.clocks.pclk2().raw(), 100_000_000); // PCLK 100MHz + assert_eq!(ccdr.clocks.pclk4().raw(), 100_000_000); // PCLK 100MHz + + let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); + let (eth_dma, eth_mac) = unsafe { + ethernet::new( + ctx.device.ETHERNET_MAC, + ctx.device.ETHERNET_MTL, + ctx.device.ETHERNET_DMA, + ( + rmii_ref_clk, + rmii_mdio, + rmii_mdc, + rmii_crs_dv, + rmii_rxd0, + rmii_rxd1, + rmii_tx_en, + rmii_txd0, + rmii_txd1, + ), + &mut DES_RING, + mac_addr, + ccdr.peripheral.ETH1MAC, + &ccdr.clocks, + ) + }; + + // Initialise ethernet PHY... + let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac); + lan8742a.phy_reset(); + lan8742a.phy_init(); + // The eth_dma should not be used until the PHY reports the link is up + + unsafe { ethernet::enable_interrupt() }; + + // unsafe: mutable reference to static storage, we only do this once + let store = unsafe { &mut STORE }; + let net = Net::new(store, eth_dma, mac_addr.into()); + + // 1ms tick + systick_init(ctx.core.SYST, ccdr.clocks); + + ( + SharedResources {}, + LocalResources { + net, + lan8742a, + link_led, + }, + init::Monotonics(), + ) + } + + #[idle(local = [lan8742a, link_led])] + fn idle(ctx: idle::Context) -> ! { + loop { + // Ethernet + match ctx.local.lan8742a.poll_link() { + true => ctx.local.link_led.set_low(), + _ => ctx.local.link_led.set_high(), + } + } + } + + #[task(binds = ETH, local = [net])] + fn ethernet_event(ctx: ethernet_event::Context) { + unsafe { ethernet::interrupt_handler() } + + let time = TIME.load(Ordering::Relaxed); + ctx.local.net.poll(time as i64); + } + + #[task(binds = SysTick, priority=15)] + fn systick_tick(_: systick_tick::Context) { + TIME.fetch_add(1, Ordering::Relaxed); + } +} From 2c835a2c0804c34083a1bdd9b9e35f6ff205ecc3 Mon Sep 17 00:00:00 2001 From: James Logan Date: Sat, 5 Aug 2023 17:49:55 -0400 Subject: [PATCH 22/75] run cargo fmt --- examples/ethernet-rtic-nucleo-h723zg.rs | 6 +++--- src/ethernet/eth.rs | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/ethernet-rtic-nucleo-h723zg.rs b/examples/ethernet-rtic-nucleo-h723zg.rs index c629e482..5fb05100 100644 --- a/examples/ethernet-rtic-nucleo-h723zg.rs +++ b/examples/ethernet-rtic-nucleo-h723zg.rs @@ -7,9 +7,9 @@ //! //! The ethernet ring buffers are placed in AXI SRAM, where they can be //! accessed by both the core and the Ethernet DMA. -//! +//! //! Run like -//! +//! //! `cargo flash --example ethernet-rtic-nucleo-h723zg --features=ethernet,stm32h735 --chip=STM32H723ZGTx` #![deny(warnings)] #![no_main] @@ -120,7 +120,7 @@ mod app { utilities::logger::init(); // Initialise power... let pwr = ctx.device.PWR.constrain(); - let pwrcfg = pwr.ldo().freeze(); // nucleo-h723zg board doesn't have SMPS + let pwrcfg = pwr.ldo().freeze(); // nucleo-h723zg board doesn't have SMPS // Initialise clocks... let rcc = ctx.device.RCC.constrain(); diff --git a/src/ethernet/eth.rs b/src/ethernet/eth.rs index ebe6c485..dc51ed92 100644 --- a/src/ethernet/eth.rs +++ b/src/ethernet/eth.rs @@ -471,7 +471,6 @@ pub unsafe fn new_unchecked( .modify(|_, w| w.eth1txen().set_bit().eth1rxen().set_bit()); syscfg.pmcr.modify(|_, w| w.epis().bits(0b100)); // RMII - } // reset ETH_MAC - write 1 then 0 @@ -479,7 +478,6 @@ pub unsafe fn new_unchecked( //rcc.ahb1rstr.modify(|_, w| w.eth1macrst().clear_bit()); cortex_m::interrupt::free(|_cs| { - // 200 MHz eth_mac .mac1ustcr From 0acd6361871155b6402500917532112ee4dc5bd0 Mon Sep 17 00:00:00 2001 From: James Logan Date: Sat, 5 Aug 2023 18:02:33 -0400 Subject: [PATCH 23/75] update example docstring --- examples/ethernet-rtic-nucleo-h723zg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ethernet-rtic-nucleo-h723zg.rs b/examples/ethernet-rtic-nucleo-h723zg.rs index 5fb05100..7cbc0384 100644 --- a/examples/ethernet-rtic-nucleo-h723zg.rs +++ b/examples/ethernet-rtic-nucleo-h723zg.rs @@ -1,4 +1,4 @@ -//! Demo for STM32H735G-DK eval board using the Real Time for the Masses +//! Demo for Nucleo-H723ZG eval board using the Real Time for the Masses //! (RTIC) framework. //! //! This demo responds to pings on 192.168.1.99 (IP address hardcoded below) From e8269a3eab1a44797aece957858c7c9643aca924 Mon Sep 17 00:00:00 2001 From: James Logan Date: Sun, 6 Aug 2023 16:12:32 -0400 Subject: [PATCH 24/75] add feature overrides for new example --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index a51868ae..bb13905e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -215,6 +215,10 @@ required-features = ["rt", "stm32h747cm7", "ethernet"] name = "ethernet-rtic-stm32h735g-dk" required-features = ["rt", "stm32h735", "ethernet"] +[[example]] +name = "ethernet-rtic-nucleo-h723zg" +required-features = ["rt", "stm32h735", "ethernet"] + [[example]] name = "ethernet-nucleo-h743zi2" required-features = ["rt", "revision_v", "stm32h743v", "ethernet"] From ff7efaa924a0c9f34e8acf3054d1b54838261863 Mon Sep 17 00:00:00 2001 From: James Logan Date: Mon, 21 Aug 2023 19:20:40 -0400 Subject: [PATCH 25/75] update example for compatibility with smoltcp 0.10.x --- examples/ethernet-rtic-nucleo-h723zg.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/ethernet-rtic-nucleo-h723zg.rs b/examples/ethernet-rtic-nucleo-h723zg.rs index 7cbc0384..d5009a6b 100644 --- a/examples/ethernet-rtic-nucleo-h723zg.rs +++ b/examples/ethernet-rtic-nucleo-h723zg.rs @@ -69,10 +69,9 @@ impl<'a> Net<'a> { mut ethdev: ethernet::EthernetDMA<4, 4>, ethernet_addr: HardwareAddress, ) -> Self { - let mut config = Config::new(); - config.hardware_addr = Some(ethernet_addr); + let config = Config::new(ethernet_addr); - let mut iface = Interface::new(config, &mut ethdev); + let mut iface = Interface::new(config, &mut ethdev, Instant::ZERO); // Set IP address iface.update_ip_addrs(|addrs| { let _ = addrs.push(IpCidr::new(IpAddress::v4(192, 168, 1, 99), 0)); From 5e3e87e99617b1677e8633ccf278caa135693f11 Mon Sep 17 00:00:00 2001 From: Josef Utbult Date: Tue, 22 Aug 2023 18:12:37 +0200 Subject: [PATCH 26/75] Change incorrect link from I2C to I2S in mod.rs --- src/sai/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sai/mod.rs b/src/sai/mod.rs index 381ab334..7bef8f7d 100644 --- a/src/sai/mod.rs +++ b/src/sai/mod.rs @@ -7,7 +7,7 @@ //! ## Examples using the Electro Smith Daisy Seed Board (AK4556 codec) //! //! - [SAI with DMA](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/sai_dma_passthru.rs) -//! - [SAI with I2C](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/sai-i2s-passthru.rs) +//! - [SAI with I2S](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/sai-i2s-passthru.rs) use core::marker::PhantomData; From d2a215e22d69b81c82f5aa23ad914eeb41496124 Mon Sep 17 00:00:00 2001 From: James Logan Date: Tue, 22 Aug 2023 22:55:00 -0400 Subject: [PATCH 27/75] remove defunct comment --- examples/ethernet-rtic-nucleo-h723zg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ethernet-rtic-nucleo-h723zg.rs b/examples/ethernet-rtic-nucleo-h723zg.rs index d5009a6b..fb13fb8d 100644 --- a/examples/ethernet-rtic-nucleo-h723zg.rs +++ b/examples/ethernet-rtic-nucleo-h723zg.rs @@ -53,8 +53,8 @@ static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } + static mut STORE: NetStorageStatic = NetStorageStatic { - // Garbage socket_storage: [SocketStorage::EMPTY; 8], }; From fd567a9dd008c8bad8deb32e6cf73e823b8aac55 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Mon, 11 Sep 2023 22:17:16 +0200 Subject: [PATCH 28/75] Revert "Move ethernet DMA reset slightly earlier to eliminate freeze on h723" This reverts commit c221c515027cf408eaa777e14437c10d296aaafc. --- src/ethernet/eth.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ethernet/eth.rs b/src/ethernet/eth.rs index dc51ed92..d786dac0 100644 --- a/src/ethernet/eth.rs +++ b/src/ethernet/eth.rs @@ -455,12 +455,6 @@ pub unsafe fn new_unchecked( // Ensure syscfg is enabled (for PMCR) rcc.apb4enr.modify(|_, w| w.syscfgen().set_bit()); - // Reset ETH_DMA - write 1 and wait for 0. - // On the H723, we have to do this before prec.enable() - // or the DMA will never come out of reset - eth_dma.dmamr.modify(|_, w| w.swr().set_bit()); - while eth_dma.dmamr.read().swr().bit_is_set() {} - // AHB1 ETH1MACEN prec.enable(); @@ -478,6 +472,10 @@ pub unsafe fn new_unchecked( //rcc.ahb1rstr.modify(|_, w| w.eth1macrst().clear_bit()); cortex_m::interrupt::free(|_cs| { + // reset ETH_DMA - write 1 and wait for 0 + eth_dma.dmamr.modify(|_, w| w.swr().set_bit()); + while eth_dma.dmamr.read().swr().bit_is_set() {} + // 200 MHz eth_mac .mac1ustcr From d9af4a635e71ad5354415b521b7761adf3f7d10b Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Mon, 11 Sep 2023 23:02:09 +0200 Subject: [PATCH 29/75] Replace casts of &T to &mut T with UnsafeCell Specifically we cast *const T to *const UnsafeCell then use the [UnsafeCell::raw_get](https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.raw_get) method --- src/serial.rs | 6 ++++-- src/spi.rs | 7 +++++-- src/xspi/mod.rs | 9 +++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index 845ac499..2eee59e2 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -7,6 +7,7 @@ //! - [Advanced USART Functions](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/serial-advanced.rs) //! - [Inverted Signal Levels](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/serial-inverted-loopback.rs) +use core::cell::UnsafeCell; use core::fmt; use core::marker::PhantomData; use core::ptr; @@ -1114,8 +1115,9 @@ macro_rules! usart { // NOTE(write_volatile) 8-bit write that's not // possible through the svd2rust API unsafe { - ptr::write_volatile( - &(*$USARTX::ptr()).tdr as *const _ as *mut _, byte) + let tdr = &(*$USARTX::ptr()).tdr as *const _ as *const UnsafeCell; + + ptr::write_volatile(UnsafeCell::raw_get(tdr), byte) } Ok(()) } else { diff --git a/src/spi.rs b/src/spi.rs index 44edc11f..3247a0e2 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -62,6 +62,7 @@ //! //! [embedded_hal]: https://docs.rs/embedded-hal/0.2.3/embedded_hal/spi/index.html +use core::cell::UnsafeCell; use core::convert::From; use core::marker::PhantomData; use core::ptr; @@ -1083,8 +1084,9 @@ macro_rules! spi { { // NOTE(write_volatile) see note above unsafe { + let txdr = &self.spi.txdr as *const _ as *const UnsafeCell<$TY>; ptr::write_volatile( - &self.spi.txdr as *const _ as *mut $TY, + UnsafeCell::raw_get(txdr), word, ) } @@ -1112,8 +1114,9 @@ macro_rules! spi { { // NOTE(write_volatile/read_volatile) write/read only 1 word unsafe { + let txdr = &self.spi.txdr as *const _ as *const UnsafeCell<$TY>; ptr::write_volatile( - &self.spi.txdr as *const _ as *mut $TY, + UnsafeCell::raw_get(txdr), word, ); return Ok(ptr::read_volatile( diff --git a/src/xspi/mod.rs b/src/xspi/mod.rs index e536c760..cdcd8a23 100644 --- a/src/xspi/mod.rs +++ b/src/xspi/mod.rs @@ -143,6 +143,7 @@ mod common { stm32, time::Hertz, }; + use core::cell::UnsafeCell; use core::{marker::PhantomData, ptr}; /// Represents operation modes of the XSPI interface. @@ -641,7 +642,9 @@ mod common { // Write data to the FIFO in a byte-wise manner. unsafe { for byte in data { - ptr::write_volatile(&self.rb.dr as *const _ as *mut u8, *byte); + let dr = &self.rb.dr as *const _ as *const UnsafeCell; + + ptr::write_volatile(UnsafeCell::raw_get(dr), *byte); } } @@ -723,7 +726,9 @@ mod common { // Transaction starts here unsafe { for byte in data { - ptr::write_volatile(&self.rb.dr as *const _ as *mut u8, *byte); + let dr = &self.rb.dr as *const _ as *const UnsafeCell; + + ptr::write_volatile(UnsafeCell::raw_get(dr), *byte); } } From 6950bac638dc6fd7f88a178a53d8d3911cd4fa70 Mon Sep 17 00:00:00 2001 From: Petr Horacek Date: Mon, 18 Sep 2023 18:10:13 +0200 Subject: [PATCH 30/75] Fix invalid read test logic in sdmmc example The read check is processing a buffer 10 blocks long. The check then reads data from the SD card 10 times to then report the speed of "Read 10 blocks at X bytes/second". The problem is that it actually reads 10*10 blocks. With this patch, read_blocks is used correctly to populate a continuous buffer. Signed-off-by: Petr Horacek --- CHANGELOG.md | 1 + examples/sdmmc.rs | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce1f7b10..d6db015b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Update `smoltcp` dependency to `0.9.0` * MSRV increased to 1.65.0 * add `IntoAf` trait to restrict `into_alternate` [#346] +* sdmmc: Fix read speed test. ## [v0.14.0] 2023-03-22 diff --git a/examples/sdmmc.rs b/examples/sdmmc.rs index 2bfd68f8..900cc002 100644 --- a/examples/sdmmc.rs +++ b/examples/sdmmc.rs @@ -145,15 +145,13 @@ fn main() -> ! { info!(""); // Read test - let mut buffer = [0u8; 5120]; + let mut buffer = [0u8; 512 * 10]; cp.DWT.enable_cycle_counter(); let start = pac::DWT::cycle_count(); - for i in 0..10 { - // Read 10 blocks - sdmmc.read_blocks(10 * i, &mut buffer).unwrap(); - } + // Read 10 blocks + sdmmc.read_blocks(0, &mut buffer).unwrap(); let end = pac::DWT::cycle_count(); let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32; From 600969f544892af691ce9fa087ba01a3aa4c70ae Mon Sep 17 00:00:00 2001 From: Petr Horacek Date: Mon, 18 Sep 2023 18:43:31 +0200 Subject: [PATCH 31/75] Introduce SDMMC write_blocks `write_block` needs to be called for every 512 bytes long block that is to be written to the SD card. Each of these calls requires the overhead of negotiating the write command. With this patch, `write_blocks` is introduced, mirroring the behavior of `read_block` and `read_blocks`. This new method helped me to improve write speed of the original 9492 kB/s to 66252 kB/s. Signed-off-by: Petr Horacek --- CHANGELOG.md | 2 +- examples/sdmmc.rs | 58 +++++++++++++++---------------------- src/sdmmc.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6db015b..26857c2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ * Update `smoltcp` dependency to `0.9.0` * MSRV increased to 1.65.0 * add `IntoAf` trait to restrict `into_alternate` [#346] -* sdmmc: Fix read speed test. +* sdmmc: Introduce `write_blocks` [#453] ## [v0.14.0] 2023-03-22 diff --git a/examples/sdmmc.rs b/examples/sdmmc.rs index 900cc002..73dd3417 100644 --- a/examples/sdmmc.rs +++ b/examples/sdmmc.rs @@ -144,55 +144,45 @@ fn main() -> ! { info!("----------------------"); info!(""); - // Read test - let mut buffer = [0u8; 512 * 10]; - cp.DWT.enable_cycle_counter(); - let start = pac::DWT::cycle_count(); - - // Read 10 blocks - sdmmc.read_blocks(0, &mut buffer).unwrap(); + // Write single block test + let write_buffer = [0x34; 512]; + let start = pac::DWT::cycle_count(); + sdmmc.write_block(0, &write_buffer).unwrap(); let end = pac::DWT::cycle_count(); let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32; + info!("Wrote single block at {} bytes/s", 512.0 / duration); - info!("Read 10 blocks at {} bytes/s", 5120. / duration); - info!(""); - - let write_buffer = [0x34; 512]; + // Write multiple blocks test + let write_buffer = [0x34; 512 * 16]; let start = pac::DWT::cycle_count(); + sdmmc.write_blocks(0, &write_buffer).unwrap(); + let end = pac::DWT::cycle_count(); + let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32; + info!("Wrote 16 blocks at {} bytes/s", (512.0 * 16.0) / duration); - for i in 0..10 { - if let Err(err) = sdmmc.write_block(i, &write_buffer) { - info!("Failed to write block {}: {:?}", i, err); - } - } - + // Read single block test + let mut buffer = [0u8; 512]; + let start = pac::DWT::cycle_count(); + sdmmc.read_block(0, &mut buffer).unwrap(); let end = pac::DWT::cycle_count(); let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32; + info!("Read single block at {} bytes/s", 512.0 / duration); - info!("Wrote 10 blocks at {} bytes/s", 5120. / duration); - info!(""); + // Read multiple blocks test + let mut buffer = [0u8; 512 * 16]; + let start = pac::DWT::cycle_count(); + sdmmc.read_blocks(0, &mut buffer).unwrap(); + let end = pac::DWT::cycle_count(); + let duration = (end - start) as f32 / ccdr.clocks.c_ck().raw() as f32; + info!("Read 16 blocks at {} bytes/s", (512.0 * 16.0) / duration); info!("Verification test..."); - // Write 10 blocks - for i in 0..10 { - if let Err(err) = sdmmc.write_block(i, &write_buffer) { - info!("Failed to write block {}: {:?}", i, err); - } else { - info!("Wrote block {}", i); - } - - // Read back - sdmmc.read_blocks(0, &mut buffer).unwrap(); - } - - // Check the read for byte in buffer.iter() { assert_eq!(*byte, 0x34); } - info!("Verified 10 blocks"); - info!(""); + info!("Verified all blocks"); info!("Done!"); diff --git a/src/sdmmc.rs b/src/sdmmc.rs index 8027ff87..847e327a 100644 --- a/src/sdmmc.rs +++ b/src/sdmmc.rs @@ -295,6 +295,7 @@ pub enum Error { Crc, DataCrcFail, RxOverFlow, + TxUnderFlow, NoCard, BadClock, InvalidConfiguration, @@ -342,6 +343,8 @@ macro_rules! err_from_datapath_sm { return Err(Error::DataCrcFail); } else if $status.rxoverr().bit() { return Err(Error::RxOverFlow); + } else if $status.txunderr().bit() { + return Err(Error::TxUnderFlow); } else if $status.dtimeout().bit() { return Err(Error::Timeout); } @@ -793,6 +796,77 @@ macro_rules! sdmmc { Err(Error::SoftwareTimeout) } + /// Write multiple blocks to card. The length of the buffer + /// must be multiple of 512. + /// + /// `address` is the block address. + pub fn write_blocks( + &mut self, + address: u32, + buffer: &[u8] + ) -> Result<(), Error> { + let _card = self.card()?; + + assert!(buffer.len() % 512 == 0, + "Buffer length must be a multiple of 512"); + let n_blocks = buffer.len() / 512; + + if !self.cmd16_illegal { + self.cmd(common_cmd::set_block_length(512))?; // CMD16 + } + + // Setup write command + self.start_datapath_transfer(512 * n_blocks as u32, 9, Dir::HostToCard); + self.cmd(common_cmd::write_multiple_blocks(address))?; // CMD25 + + let mut i = 0; + let mut status; + while { + status = self.sdmmc.star.read(); + !(status.txunderr().bit() + || status.dcrcfail().bit() + || status.dtimeout().bit() + || status.dataend().bit()) + } { + if status.txfifohe().bit() { + for _ in 0..8 { + let mut wb = [0u8; 4]; + wb.copy_from_slice(&buffer[i..i + 4]); + let word = u32::from_le_bytes(wb); + self.sdmmc.fifor.write(|w| unsafe { w.bits(word) }); + i += 4; + } + } + + if i >= buffer.len() { + break + } + } + + while { + status = self.sdmmc.star.read(); + !(status.txunderr().bit() + || status.dcrcfail().bit() + || status.dtimeout().bit() + || status.dataend().bit()) + } {} + self.cmd(common_cmd::stop_transmission())?; // CMD12 + + err_from_datapath_sm!(status); + self.clear_static_interrupt_flags(); + + let mut timeout: u32 = 0xFFFF_FFFF; + + // Try to read card status (CMD13) + while timeout > 0 { + if self.card_ready()? { + return Ok(()); + } + timeout -= 1; + } + Err(Error::SoftwareTimeout) + } + /// Query the card status (CMD13, returns R1) /// fn read_status(&self) -> Result, Error> { From 851577048ce5e60f120889519f848c00cebc8489 Mon Sep 17 00:00:00 2001 From: Petr Horacek Date: Tue, 19 Sep 2023 21:15:40 +0200 Subject: [PATCH 32/75] Optimize SDMMC FAT writting speeds With this patch, the FAT write binding would use sdmmc CMD25 to write large blocks of data. Signed-off-by: Petr Horacek --- CHANGELOG.md | 1 + examples/sdmmc_fat.rs | 45 +++++++++++++++++++++++++++++++++++++++++-- src/sdmmc.rs | 37 ++++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26857c2e..0c77ae85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * MSRV increased to 1.65.0 * add `IntoAf` trait to restrict `into_alternate` [#346] * sdmmc: Introduce `write_blocks` [#453] +* sdmmc-fat: Optimize writing speeds [#456] ## [v0.14.0] 2023-03-22 diff --git a/examples/sdmmc_fat.rs b/examples/sdmmc_fat.rs index e75c3c7b..c451de98 100644 --- a/examples/sdmmc_fat.rs +++ b/examples/sdmmc_fat.rs @@ -2,7 +2,7 @@ #![no_std] use { - embedded_sdmmc::{Controller, VolumeIdx}, + embedded_sdmmc::{Controller, Mode, VolumeIdx}, stm32h7xx_hal::sdmmc::{SdCard, Sdmmc}, stm32h7xx_hal::{pac, prelude::*, rcc}, }; @@ -89,14 +89,55 @@ unsafe fn main() -> ! { // See https://github.com/rust-embedded-community/embedded-sdmmc-rs for docs // and more examples + log::info!("Initialize file system manager"); let mut sd_fatfs = Controller::new(sd.sdmmc_block_device(), TimeSource); - let sd_fatfs_volume = sd_fatfs.get_volume(VolumeIdx(0)).unwrap(); + let mut sd_fatfs_volume = sd_fatfs.get_volume(VolumeIdx(0)).unwrap(); let sd_fatfs_root_dir = sd_fatfs.open_root_dir(&sd_fatfs_volume).unwrap(); + + log::info!("List all the directories and their info"); sd_fatfs .iterate_dir(&sd_fatfs_volume, &sd_fatfs_root_dir, |entry| { log::info!("{:?}", entry); }) .unwrap(); + + const WRITE_BUFFER: [u8; 8 * 1024] = [b'B'; 8 * 1024]; + + for (filename, length) in + &[("small.txt", 8), ("big.txt", WRITE_BUFFER.len())] + { + log::info!("Open file {:?}", filename); + let mut file = sd_fatfs + .open_file_in_dir( + &mut sd_fatfs_volume, + &sd_fatfs_root_dir, + filename, + Mode::ReadWriteCreateOrTruncate, + ) + .unwrap(); + + log::info!("Write {:?} characters in it", length); + sd_fatfs + .write(&mut sd_fatfs_volume, &mut file, &WRITE_BUFFER[0..*length]) + .unwrap(); + + log::info!("Read it back and confirm it contains the expected content"); + file.seek_from_start(0).unwrap(); + while !file.eof() { + let mut buffer = [0u8; 1024]; + let num_read = sd_fatfs + .read(&sd_fatfs_volume, &mut file, &mut buffer) + .unwrap(); + for b in &buffer[0..num_read] { + assert_eq!(*b as char, 'B'); + } + } + + sd_fatfs.close_file(&sd_fatfs_volume, file).unwrap(); + } + + log::info!("Test successfully finished"); + sd_fatfs.close_dir(&sd_fatfs_volume, sd_fatfs_root_dir); loop { diff --git a/src/sdmmc.rs b/src/sdmmc.rs index 847e327a..b72e61cd 100644 --- a/src/sdmmc.rs +++ b/src/sdmmc.rs @@ -804,12 +804,23 @@ macro_rules! sdmmc { &mut self, address: u32, buffer: &[u8] + ) -> Result<(), Error> { + self.write_blocks_begin(address, buffer.len())?; + self.write_blocks_feed(buffer); + self.write_blocks_conclude()?; + Ok(()) + } + + fn write_blocks_begin( + &mut self, + address: u32, + buffer_len: usize, ) -> Result<(), Error> { let _card = self.card()?; - assert!(buffer.len() % 512 == 0, + assert!(buffer_len % 512 == 0, "Buffer length must be a multiple of 512"); - let n_blocks = buffer.len() / 512; + let n_blocks = buffer_len / 512; if !self.cmd16_illegal { self.cmd(common_cmd::set_block_length(512))?; // CMD16 @@ -819,6 +830,10 @@ macro_rules! sdmmc { self.start_datapath_transfer(512 * n_blocks as u32, 9, Dir::HostToCard); self.cmd(common_cmd::write_multiple_blocks(address))?; // CMD25 + Ok(()) + } + + fn write_blocks_feed(&mut self, buffer: &[u8]) { let mut i = 0; let mut status; while { @@ -842,6 +857,10 @@ macro_rules! sdmmc { break } } + } + + fn write_blocks_conclude(&mut self) -> Result<(), Error> { + let mut status; while { status = self.sdmmc.star.read(); @@ -850,6 +869,7 @@ macro_rules! sdmmc { || status.dtimeout().bit() || status.dataend().bit()) } {} + self.cmd(common_cmd::stop_transmission())?; // CMD12 err_from_datapath_sm!(status); @@ -1339,10 +1359,17 @@ macro_rules! sdmmc { blocks: &[embedded_sdmmc::Block], start_block_idx: embedded_sdmmc::BlockIdx, ) -> Result<(), Self::Error> { - let start = start_block_idx.0; let mut sdmmc = self.sdmmc.borrow_mut(); - for block_idx in start..(start + blocks.len() as u32) { - sdmmc.write_block(block_idx, &blocks[(block_idx - start) as usize].contents)?; + let start = start_block_idx.0; + if blocks.len() == 1 { + sdmmc.write_block(start, &blocks[0].contents)?; + } else { + let total_length = embedded_sdmmc::Block::LEN * blocks.len(); + sdmmc.write_blocks_begin(start, total_length)?; + for block in blocks.iter() { + sdmmc.write_blocks_feed(&block.contents); + } + sdmmc.write_blocks_conclude()?; } Ok(()) } From a15c64fd2a544095bb53f2603c203dda9cf40b0e Mon Sep 17 00:00:00 2001 From: Edwin Date: Thu, 21 Sep 2023 20:39:16 +0200 Subject: [PATCH 33/75] fix typo in sdmmc.rs --- src/sdmmc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdmmc.rs b/src/sdmmc.rs index b72e61cd..ab2ac674 100644 --- a/src/sdmmc.rs +++ b/src/sdmmc.rs @@ -1333,7 +1333,7 @@ macro_rules! sdmmc { } #[cfg(feature = "sdmmc-fatfs")] - #[cfg_attr(docsrs, doc(cfg(feature = "sdmcc-fatfs")))] + #[cfg_attr(docsrs, doc(cfg(feature = "sdmmc-fatfs")))] impl embedded_sdmmc::BlockDevice for SdmmcBlockDevice> { type Error = Error; From 9c596cd424eac954158b907510b7c2e6fbb1110f Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Mon, 9 Oct 2023 22:55:47 +0200 Subject: [PATCH 34/75] v0.15.0 --- CHANGELOG.md | 31 +++++++++++++++++++++++-------- Cargo.toml | 2 +- README.md | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c77ae85..24540f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,21 @@ # Changelog -## Unreleased - -* remove unused `bitflags` dependency -* bors bot replaced with GH merge queue -* Update `smoltcp` dependency to `0.9.0` -* MSRV increased to 1.65.0 -* add `IntoAf` trait to restrict `into_alternate` [#346] +## [Unreleased] + +## [v0.15.0] 2023-10-09 + +* Remove unused `bitflags` dependency +* Bors bot replaced with GH merge queue +* Update `smoltcp` dependency to `0.10.0` (from `0.8.0`) [#422] [#439] +* Update `embedded-sdmmc` to `0.5` (from `0.4`) [#440] +* Update `fdcan` to `0.2` (from `0.1`) [#440] +* MSRV increased to Rust 1.65.0 [#422] +* Add `IntoAf` trait to restrict `into_alternate` [#346] +* Replace casts of &T to &mut T with `UnsafeCell` [#451] +* pwr: Add VOS0 support for RM0455 parts [#429] * sdmmc: Introduce `write_blocks` [#453] * sdmmc-fat: Optimize writing speeds [#456] +* wwdg: Add additional possibility for WWDG1RSTF [#434] ## [v0.14.0] 2023-03-22 @@ -280,7 +287,8 @@ * Upgrade to stm32-rs v0.9.0 (including svd2rust v0.16) * Started Changelog -[Unreleased]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.14.0...HEAD +[Unreleased]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.15.0...HEAD +[v0.15.0]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.14.0...v0.15.0 [v0.14.0]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.13.1...v0.14.0 [v0.13.1]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.13.0...v0.13.1 [v0.13.0]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.12.2...v0.13.0 @@ -369,4 +377,11 @@ [#418]: https://github.com/stm32-rs/stm32h7xx-hal/pull/418 [#419]: https://github.com/stm32-rs/stm32h7xx-hal/pull/419 [#421]: https://github.com/stm32-rs/stm32h7xx-hal/pull/421 +[#422]: https://github.com/stm32-rs/stm32h7xx-hal/pull/422 [#426]: https://github.com/stm32-rs/stm32h7xx-hal/pull/426 +[#429]: https://github.com/stm32-rs/stm32h7xx-hal/pull/429 +[#434]: https://github.com/stm32-rs/stm32h7xx-hal/pull/434 +[#440]: https://github.com/stm32-rs/stm32h7xx-hal/pull/440 +[#451]: https://github.com/stm32-rs/stm32h7xx-hal/pull/451 +[#453]: https://github.com/stm32-rs/stm32h7xx-hal/pull/453 +[#456]: https://github.com/stm32-rs/stm32h7xx-hal/pull/456 diff --git a/Cargo.toml b/Cargo.toml index 32de7693..050a57eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stm32h7xx-hal" -version = "0.14.0" +version = "0.15.0" authors = ["Andrew Straw ", "Richard Meadows ", "Henrik Böving ", diff --git a/README.md b/README.md index 78d877b5..d7aaae0b 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ target device feature must be specified in the `Cargo.toml` file: [dependencies] cortex-m = "0.7.4" cortex-m-rt = "0.7.1" -stm32h7xx-hal = {version = "0.14.0", features = ["stm32h743v","rt"]} +stm32h7xx-hal = {version = "0.15.0", features = ["stm32h743v","rt"]} ``` If you are unfamiliar with embedded development using Rust, there are From 1b9e46e67bd65410405e1973f383d9e3e87a633e Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sun, 22 Oct 2023 21:37:48 +0200 Subject: [PATCH 35/75] usb: On rm0455/rm0468 parts, pins PA11/PA12 can be in analog mode See pinouts in part datasheets. To use these pins for USB, it's not necessary to switch them to an alternate function: the USB D-/D+ pins are functional when the GPIO state is analog. Tested on a STM32H7A3ZIT6 --- CHANGELOG.md | 4 ++++ examples/usb_rtic.rs | 2 +- src/usb_hs.rs | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24540f58..e3f9c12b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Unreleased] +* Bugfix, usb: On RM0455 and RM0468 parts, PA11/PA12 do not have an alternate function + (AF) for USB. Use `into_analog()` when passing pins to `USB1/2::new` on these parts [#464] + ## [v0.15.0] 2023-10-09 * Remove unused `bitflags` dependency @@ -385,3 +388,4 @@ [#451]: https://github.com/stm32-rs/stm32h7xx-hal/pull/451 [#453]: https://github.com/stm32-rs/stm32h7xx-hal/pull/453 [#456]: https://github.com/stm32-rs/stm32h7xx-hal/pull/456 +[#464]: https://github.com/stm32-rs/stm32h7xx-hal/pull/464 diff --git a/examples/usb_rtic.rs b/examples/usb_rtic.rs index 3e78f8be..19fe6273 100644 --- a/examples/usb_rtic.rs +++ b/examples/usb_rtic.rs @@ -70,7 +70,7 @@ mod app { #[cfg(any(feature = "rm0455", feature = "rm0468"))] let (pin_dm, pin_dp) = { let gpioa = ctx.device.GPIOA.split(ccdr.peripheral.GPIOA); - (gpioa.pa11.into_alternate(), gpioa.pa12.into_alternate()) + (gpioa.pa11, gpioa.pa12) }; let led = ctx.device.GPIOE.split(ccdr.peripheral.GPIOE).pe1; diff --git a/src/usb_hs.rs b/src/usb_hs.rs index 4aa0c959..26354e2f 100644 --- a/src/usb_hs.rs +++ b/src/usb_hs.rs @@ -18,7 +18,7 @@ use crate::rcc; use crate::stm32; -use crate::gpio::{self, Alternate, Speed}; +use crate::gpio::{self, Alternate, Analog, Speed}; use crate::time::Hertz; @@ -50,8 +50,8 @@ impl USB1 { usb_global: stm32::OTG1_HS_GLOBAL, usb_device: stm32::OTG1_HS_DEVICE, usb_pwrclk: stm32::OTG1_HS_PWRCLK, - _pin_dm: gpio::PA11>, - _pin_dp: gpio::PA12>, + _pin_dm: gpio::PA11, + _pin_dp: gpio::PA12, prec: rcc::rec::Usb1Otg, clocks: &rcc::CoreClocks, ) -> Self { From d4520524c0388430e057ab4bd33db41204949f31 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Fri, 3 Nov 2023 21:25:06 +0100 Subject: [PATCH 36/75] v0.15.1 --- CHANGELOG.md | 5 ++++- Cargo.toml | 2 +- README.md | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3f9c12b..d72624ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [v0.15.1] 2023-11-03 + * Bugfix, usb: On RM0455 and RM0468 parts, PA11/PA12 do not have an alternate function (AF) for USB. Use `into_analog()` when passing pins to `USB1/2::new` on these parts [#464] @@ -290,7 +292,8 @@ * Upgrade to stm32-rs v0.9.0 (including svd2rust v0.16) * Started Changelog -[Unreleased]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.15.0...HEAD +[Unreleased]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.15.1...HEAD +[v0.15.1]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.15.0...v0.15.1 [v0.15.0]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.14.0...v0.15.0 [v0.14.0]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.13.1...v0.14.0 [v0.13.1]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.13.0...v0.13.1 diff --git a/Cargo.toml b/Cargo.toml index 050a57eb..9e2370b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stm32h7xx-hal" -version = "0.15.0" +version = "0.15.1" authors = ["Andrew Straw ", "Richard Meadows ", "Henrik Böving ", diff --git a/README.md b/README.md index d7aaae0b..c9535a8f 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ target device feature must be specified in the `Cargo.toml` file: [dependencies] cortex-m = "0.7.4" cortex-m-rt = "0.7.1" -stm32h7xx-hal = {version = "0.15.0", features = ["stm32h743v","rt"]} +stm32h7xx-hal = {version = "0.15.1", features = ["stm32h743v","rt"]} ``` If you are unfamiliar with embedded development using Rust, there are From 725b99d1ca826eb481aa85a29b552e83cc016392 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Fri, 3 Nov 2023 21:58:47 +0100 Subject: [PATCH 37/75] Update usb examples after #464 --- examples/usb_phy_serial_interrupt.rs | 3 +++ examples/usb_serial.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/usb_phy_serial_interrupt.rs b/examples/usb_phy_serial_interrupt.rs index 68d2d83c..dff0fee7 100644 --- a/examples/usb_phy_serial_interrupt.rs +++ b/examples/usb_phy_serial_interrupt.rs @@ -1,4 +1,7 @@ //! CDC-ACM serial port example using an external phy and interrupts +//! +//! This example is for RM0433/RM0399 parts. It has been tested on the Arduino +//! Portenta H7 #![no_std] #![no_main] diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs index 1a08b470..892e15f6 100644 --- a/examples/usb_serial.rs +++ b/examples/usb_serial.rs @@ -59,7 +59,7 @@ fn main() -> ! { #[cfg(any(feature = "rm0455", feature = "rm0468"))] let (pin_dm, pin_dp) = { let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); - (gpioa.pa11.into_alternate(), gpioa.pa12.into_alternate()) + (gpioa.pa11, gpioa.pa12) }; let usb = USB1::new( From f6b4c893505bccf767eed5438ee5572b92c1d92a Mon Sep 17 00:00:00 2001 From: ElouanPetereau Date: Fri, 1 Sep 2023 09:50:18 +0200 Subject: [PATCH 38/75] Expose QSPI control register for the QSPI struct --- src/xspi/qspi.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/xspi/qspi.rs b/src/xspi/qspi.rs index e4b03c95..e6eb3065 100644 --- a/src/xspi/qspi.rs +++ b/src/xspi/qspi.rs @@ -179,6 +179,14 @@ pub trait QspiExt { } impl Qspi { + pub fn change_bank(&mut self, bank: Bank) { + match bank { + Bank::One => self.rb.cr.modify(|_, w| w.fsel().clear_bit()), + Bank::Two => self.rb.cr.modify(|_, w| w.fsel().set_bit()), + Bank::Dual => self.rb.cr.modify(|_, w| w.dfm().set_bit()), + } + } + pub fn qspi_unchecked( regs: stm32::QUADSPI, config: CONFIG, From 1c9d968db798132632564bbbfe0e4b9c731a1620 Mon Sep 17 00:00:00 2001 From: ElouanPetereau Date: Fri, 1 Sep 2023 12:01:51 +0200 Subject: [PATCH 39/75] Add enums and traits for Bank switch --- src/xspi/mod.rs | 41 +++++++++++++++++++++++++- src/xspi/qspi.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 110 insertions(+), 6 deletions(-) diff --git a/src/xspi/mod.rs b/src/xspi/mod.rs index cdcd8a23..5a631c83 100644 --- a/src/xspi/mod.rs +++ b/src/xspi/mod.rs @@ -248,7 +248,7 @@ mod common { Error, } - /// Indicates a specific QUADSPI bank to use + /// Indicates a specific QUADSPI bank to use. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg(any(feature = "rm0433", feature = "rm0399"))] @@ -260,6 +260,45 @@ mod common { // Banks are not supported by the Octospi peripheral (there's two Octospi // peripherals instead) + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg(any(feature = "rm0433", feature = "rm0399"))] + pub enum BankError { + DualModeNotSupported, + } + + #[cfg(any(feature = "rm0433", feature = "rm0399"))] + impl TryFrom for BankSelect { + type Error = BankError; + + fn try_from(value: Bank) -> Result { + match value { + Bank::One => Ok(BankSelect::One), + Bank::Two => Ok(BankSelect::Two), + Bank::Dual => Err(BankError::DualModeNotSupported), + } + } + } + + /// Indicates one of the two existing QUADSPI bank. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg(any(feature = "rm0433", feature = "rm0399"))] + pub enum BankSelect { + One, + Two, + } + + #[cfg(any(feature = "rm0433", feature = "rm0399"))] + impl From for Bank { + fn from(val: BankSelect) -> Self { + match val { + BankSelect::One => Bank::One, + BankSelect::Two => Bank::Two, + } + } + } + /// A structure for specifying the XSPI configuration. /// /// This structure uses builder semantics to generate the configuration. diff --git a/src/xspi/qspi.rs b/src/xspi/qspi.rs index e6eb3065..5912de0e 100644 --- a/src/xspi/qspi.rs +++ b/src/xspi/qspi.rs @@ -8,7 +8,7 @@ use crate::{ stm32, }; -use super::{Bank, Config, Qspi, SamplingEdge}; +use super::{common::BankSelect, Bank, Config, Qspi, SamplingEdge}; /// Used to indicate that an IO pin is not used by the QSPI interface. pub struct NoIo {} @@ -28,6 +28,9 @@ pub trait PinIo1Bank2 {} pub trait PinIo2Bank2 {} pub trait PinIo3Bank2 {} +/// Indicates a set of pins can be used for the QSPI interface on bank 1 and 2. +pub trait PinsBank1And2 {} + pub trait PinSck {} impl PinsBank1 for (SCK, IO0, IO1, IO2, IO3) @@ -50,6 +53,41 @@ where { } +impl< + SCK, + BK1_IO0, + BK1_IO1, + BK1_IO2, + BK1_IO3, + BK2_IO0, + BK2_IO1, + BK2_IO2, + BK2_IO3, + > PinsBank1And2 + for ( + SCK, + BK1_IO0, + BK1_IO1, + BK1_IO2, + BK1_IO3, + BK2_IO0, + BK2_IO1, + BK2_IO2, + BK2_IO3, + ) +where + SCK: PinSck, + BK1_IO0: PinIo0Bank1, + BK1_IO1: PinIo1Bank1, + BK1_IO2: PinIo2Bank1, + BK1_IO3: PinIo3Bank1, + BK2_IO0: PinIo0Bank2, + BK2_IO1: PinIo1Bank2, + BK2_IO2: PinIo2Bank2, + BK2_IO3: PinIo3Bank2, +{ +} + macro_rules! pins { (Bank1: [IO0: [$($IO0:ty),*] IO1: [$($IO1:ty),*] IO2: [$($IO2:ty),*] IO3: [$($IO3:ty),*]]) => { $( @@ -167,6 +205,18 @@ pub trait QspiExt { CONFIG: Into, PINS: PinsBank2; + fn bank_switch( + self, + _pins: PINS, + initial_bank: BankSelect, + config: CONFIG, + clocks: &CoreClocks, + prec: rec::Qspi, + ) -> Qspi + where + CONFIG: Into, + PINS: PinsBank1And2; + fn qspi_unchecked( self, config: CONFIG, @@ -179,11 +229,11 @@ pub trait QspiExt { } impl Qspi { - pub fn change_bank(&mut self, bank: Bank) { + pub fn change_bank(&mut self, bank: BankSelect) { + self.rb.cr.modify(|_, w| w.dfm().clear_bit()); match bank { - Bank::One => self.rb.cr.modify(|_, w| w.fsel().clear_bit()), - Bank::Two => self.rb.cr.modify(|_, w| w.fsel().set_bit()), - Bank::Dual => self.rb.cr.modify(|_, w| w.dfm().set_bit()), + BankSelect::One => self.rb.cr.modify(|_, w| w.fsel().clear_bit()), + BankSelect::Two => self.rb.cr.modify(|_, w| w.fsel().set_bit()), } } @@ -311,6 +361,21 @@ impl QspiExt for stm32::QUADSPI { Qspi::qspi_unchecked(self, config, Bank::Two, clocks, prec) } + fn bank_switch( + self, + _pins: PINS, + initial_bank: BankSelect, + config: CONFIG, + clocks: &CoreClocks, + prec: rec::Qspi, + ) -> Qspi + where + CONFIG: Into, + PINS: PinsBank1And2, + { + Qspi::qspi_unchecked(self, config, initial_bank.into(), clocks, prec) + } + fn qspi_unchecked( self, config: CONFIG, From fd28a83158b67cef5a8a08a560653f7060e4ba0e Mon Sep 17 00:00:00 2001 From: ElouanPetereau Date: Fri, 1 Sep 2023 12:12:32 +0200 Subject: [PATCH 40/75] Expose BankSelect and related error --- src/xspi/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xspi/mod.rs b/src/xspi/mod.rs index 5a631c83..f9a8e376 100644 --- a/src/xspi/mod.rs +++ b/src/xspi/mod.rs @@ -116,8 +116,8 @@ mod qspi; #[cfg(any(feature = "rm0433", feature = "rm0399"))] pub use common::{ - Bank, Xspi as Qspi, XspiError as QspiError, XspiMode as QspiMode, - XspiWord as QspiWord, + Bank, BankError, BankSelect, Xspi as Qspi, XspiError as QspiError, + XspiMode as QspiMode, XspiWord as QspiWord, }; #[cfg(any(feature = "rm0433", feature = "rm0399"))] pub use qspi::QspiExt as XspiExt; From 0665248f7680826649be15fe6f865c18ea0bd383 Mon Sep 17 00:00:00 2001 From: ElouanPetereau Date: Thu, 5 Oct 2023 19:51:42 +0200 Subject: [PATCH 41/75] Rename QUADSPI change_bank and check for business --- src/xspi/qspi.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/xspi/qspi.rs b/src/xspi/qspi.rs index 5912de0e..9934cbc3 100644 --- a/src/xspi/qspi.rs +++ b/src/xspi/qspi.rs @@ -8,7 +8,7 @@ use crate::{ stm32, }; -use super::{common::BankSelect, Bank, Config, Qspi, SamplingEdge}; +use super::{common::BankSelect, Bank, Config, Qspi, QspiError, SamplingEdge}; /// Used to indicate that an IO pin is not used by the QSPI interface. pub struct NoIo {} @@ -229,12 +229,21 @@ pub trait QspiExt { } impl Qspi { - pub fn change_bank(&mut self, bank: BankSelect) { + pub fn change_bank_unchecked( + &mut self, + bank: BankSelect, + ) -> Result<(), QspiError> { + // Ensure that the peripheral is no longer busy before changing FSEL and DFM bits + if self.is_busy().is_err() { + return Err(QspiError::Busy); + }; + self.rb.cr.modify(|_, w| w.dfm().clear_bit()); match bank { BankSelect::One => self.rb.cr.modify(|_, w| w.fsel().clear_bit()), BankSelect::Two => self.rb.cr.modify(|_, w| w.fsel().set_bit()), } + Ok(()) } pub fn qspi_unchecked( From 1605840a2bd8f1675e0e8633f3a2c985f11274ab Mon Sep 17 00:00:00 2001 From: ElouanPetereau Date: Fri, 6 Oct 2023 10:45:06 +0200 Subject: [PATCH 42/75] Add documentation for Quad-SPI --- src/xspi/qspi.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/xspi/qspi.rs b/src/xspi/qspi.rs index 9934cbc3..d54a5ca2 100644 --- a/src/xspi/qspi.rs +++ b/src/xspi/qspi.rs @@ -229,6 +229,8 @@ pub trait QspiExt { } impl Qspi { + /// Switches between single-bank mode on Bank 1 and single-bank mode on Bank 2. + /// Note that it has no effect in dual-flash mode. pub fn change_bank_unchecked( &mut self, bank: BankSelect, @@ -342,6 +344,10 @@ impl Qspi { } impl QspiExt for stm32::QUADSPI { + /// Create and initialize a new QUADSPI peripheral that will use the single-bank mode on the Bank 1 of the flash memory. + /// + /// A list of pins `(sck, io0, io1, io2, io3)` for this QSPI peripheral should be passed as pins. + /// Even if the pins are not used, the function will consume them to avoid accessing to them manually. fn bank1( self, _pins: PINS, @@ -356,6 +362,10 @@ impl QspiExt for stm32::QUADSPI { Qspi::qspi_unchecked(self, config, Bank::One, clocks, prec) } + /// Create and initialize a new QUADSPI peripheral that will use the single-bank mode on the Bank 2 of the flash memory. + /// + /// A list of pins `(sck, io0, io1, io2, io3)` for this QSPI peripheral should be passed as pins. + /// Even if the pins are not used, the function will consume them to avoid accessing to them manually. fn bank2( self, _pins: PINS, @@ -370,6 +380,13 @@ impl QspiExt for stm32::QUADSPI { Qspi::qspi_unchecked(self, config, Bank::Two, clocks, prec) } + /// Create and initialize a new QUADSPI peripheral that can switch between both banks of the flash memory. + /// + /// The Bank to use at initialization is given by the `initial_bank` parameter. + /// A list of pins `(sck, bank1_io0, bank1_io1, bank1_io2, bank1_io3, bank2_io0, bank2_io1, bank2_io2, bank2_io3)` for this QSPI peripheral should be passed as pins. + /// Even if the pins are not used, the function will consume them to avoid accessing to them manually. + /// + /// Note that the peripheral will still be initialized in single-bank mode and the used bank have to be changed using the [`change_bank_unchecked`](../xspi/struct.Qspi.html#method.change_bank_unchecked) method. fn bank_switch( self, _pins: PINS, @@ -385,6 +402,9 @@ impl QspiExt for stm32::QUADSPI { Qspi::qspi_unchecked(self, config, initial_bank.into(), clocks, prec) } + /// Create and initialize a new QUADSPI peripheral without consuming any pins. + /// + /// The given `bank` allow to chose between communication to just one of the two banks (single-bank mode) or to both at the same time (dual-flash mode). fn qspi_unchecked( self, config: CONFIG, From b238769760006b96f04a51346d414affd071f9ea Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 20 Nov 2023 10:47:55 +0100 Subject: [PATCH 43/75] Updating usb crates --- CHANGELOG.md | 1 + Cargo.toml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d72624ef..b5bd57bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Bugfix, usb: On RM0455 and RM0468 parts, PA11/PA12 do not have an alternate function (AF) for USB. Use `into_analog()` when passing pins to `USB1/2::new` on these parts [#464] +* [breaking] `usb-device` updated to v0.3.0 ## [v0.15.0] 2023-10-09 diff --git a/Cargo.toml b/Cargo.toml index 9e2370b4..b3aef94c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ bare-metal = "1.0.0" sdio-host = { version = "0.9", optional = true } embedded-sdmmc = { version = "0.5", optional = true } stm32-fmc = { version = "0.3", optional = true } -synopsys-usb-otg = { version = "^0.3.0", features = ["cortex-m"], optional = true } +synopsys-usb-otg = { version = "0.4", features = ["cortex-m"], optional = true } embedded-display-controller = { version = "^0.1.0", optional = true } log = { version = "0.4.14", optional = true} # see also the dev-dependencies section fdcan = { version = "0.2", optional = true } @@ -76,8 +76,8 @@ cortex-m-log = { version = "0.8.0", features = ["itm", "semihosting", "log-integ cortex-m-semihosting = "0.5.0" panic-itm = { version = "~0.4.1" } panic-semihosting = "0.6" -usb-device = "0.2.5" -usbd-serial = "0.1.0" +usb-device = "0.3" +usbd-serial = "0.2.0" numtoa = "0.2.3" tinybmp = "0.5" embedded-graphics = "0.8" From 26d9ca0e8835fa92564e32f1cfaff65a26e83eec Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 20 Nov 2023 11:25:20 +0100 Subject: [PATCH 44/75] Updating examples --- examples/usb_passthrough.rs | 8 +++++--- examples/usb_phy_serial_interrupt.rs | 10 ++++++---- examples/usb_rtic.rs | 8 +++++--- examples/usb_serial.rs | 8 +++++--- src/usb_hs.rs | 6 +++--- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/examples/usb_passthrough.rs b/examples/usb_passthrough.rs index 0c8dc1cc..e1a4982d 100644 --- a/examples/usb_passthrough.rs +++ b/examples/usb_passthrough.rs @@ -73,9 +73,11 @@ fn main() -> ! { let mut serial1 = usbd_serial::SerialPort::new(&usb1_bus); let mut usb1_dev = UsbDeviceBuilder::new(&usb1_bus, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST PORT 1") + .strings(&[usb_device::device::StringDescriptors::default() + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST PORT 1") + ]).unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); diff --git a/examples/usb_phy_serial_interrupt.rs b/examples/usb_phy_serial_interrupt.rs index dff0fee7..bd314a82 100644 --- a/examples/usb_phy_serial_interrupt.rs +++ b/examples/usb_phy_serial_interrupt.rs @@ -152,11 +152,13 @@ unsafe fn main() -> ! { USB_BUS_ALLOCATOR.as_ref().unwrap(), UsbVidPid(VID, PID), ) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") + .strings(&[usb_device::device::StringDescriptors::default() + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST PORT 1") + ]).unwrap() .device_class(usbd_serial::USB_CLASS_CDC) - .max_packet_size_0(64) + .max_packet_size_0(64).unwrap() .build(); interrupt_free(|cs| { diff --git a/examples/usb_rtic.rs b/examples/usb_rtic.rs index 19fe6273..8263b805 100644 --- a/examples/usb_rtic.rs +++ b/examples/usb_rtic.rs @@ -91,9 +91,11 @@ mod app { .unwrap(); let serial = usbd_serial::SerialPort::new(usb_bus); let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") + .strings(&[usb_device::device::StringDescriptors::default() + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST PORT 1") + ]).unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); let usb = (usb_dev, serial); diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs index 892e15f6..2ddf85c6 100644 --- a/examples/usb_serial.rs +++ b/examples/usb_serial.rs @@ -78,9 +78,11 @@ fn main() -> ! { let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") + .strings(&[usb_device::device::StringDescriptors::default() + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST PORT 1") + ]).unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); diff --git a/src/usb_hs.rs b/src/usb_hs.rs index 26354e2f..e0aa7983 100644 --- a/src/usb_hs.rs +++ b/src/usb_hs.rs @@ -18,7 +18,7 @@ use crate::rcc; use crate::stm32; -use crate::gpio::{self, Alternate, Analog, Speed}; +use crate::gpio::{self, Alternate, Speed}; use crate::time::Hertz; @@ -50,8 +50,8 @@ impl USB1 { usb_global: stm32::OTG1_HS_GLOBAL, usb_device: stm32::OTG1_HS_DEVICE, usb_pwrclk: stm32::OTG1_HS_PWRCLK, - _pin_dm: gpio::PA11, - _pin_dp: gpio::PA12, + _pin_dm: gpio::PA11, + _pin_dp: gpio::PA12, prec: rcc::rec::Usb1Otg, clocks: &rcc::CoreClocks, ) -> Self { From 63cdc5f010f5e5512e5d9af61904c03590f121bf Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 20 Nov 2023 11:28:29 +0100 Subject: [PATCH 45/75] Fixing format --- examples/usb_passthrough.rs | 4 ++-- examples/usb_phy_serial_interrupt.rs | 13 +++++++------ examples/usb_rtic.rs | 4 ++-- examples/usb_serial.rs | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/examples/usb_passthrough.rs b/examples/usb_passthrough.rs index e1a4982d..cb43443d 100644 --- a/examples/usb_passthrough.rs +++ b/examples/usb_passthrough.rs @@ -76,8 +76,8 @@ fn main() -> ! { .strings(&[usb_device::device::StringDescriptors::default() .manufacturer("Fake company") .product("Serial port") - .serial_number("TEST PORT 1") - ]).unwrap() + .serial_number("TEST PORT 1")]) + .unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); diff --git a/examples/usb_phy_serial_interrupt.rs b/examples/usb_phy_serial_interrupt.rs index bd314a82..4ed5d4f4 100644 --- a/examples/usb_phy_serial_interrupt.rs +++ b/examples/usb_phy_serial_interrupt.rs @@ -152,13 +152,14 @@ unsafe fn main() -> ! { USB_BUS_ALLOCATOR.as_ref().unwrap(), UsbVidPid(VID, PID), ) - .strings(&[usb_device::device::StringDescriptors::default() - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST PORT 1") - ]).unwrap() + .strings(&[usb_device::device::StringDescriptors::default() + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST PORT 1")]) + .unwrap() .device_class(usbd_serial::USB_CLASS_CDC) - .max_packet_size_0(64).unwrap() + .max_packet_size_0(64) + .unwrap() .build(); interrupt_free(|cs| { diff --git a/examples/usb_rtic.rs b/examples/usb_rtic.rs index 8263b805..aa1e99b9 100644 --- a/examples/usb_rtic.rs +++ b/examples/usb_rtic.rs @@ -94,8 +94,8 @@ mod app { .strings(&[usb_device::device::StringDescriptors::default() .manufacturer("Fake company") .product("Serial port") - .serial_number("TEST PORT 1") - ]).unwrap() + .serial_number("TEST PORT 1")]) + .unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); let usb = (usb_dev, serial); diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs index 2ddf85c6..951627da 100644 --- a/examples/usb_serial.rs +++ b/examples/usb_serial.rs @@ -81,8 +81,8 @@ fn main() -> ! { .strings(&[usb_device::device::StringDescriptors::default() .manufacturer("Fake company") .product("Serial port") - .serial_number("TEST PORT 1") - ]).unwrap() + .serial_number("TEST PORT 1")]) + .unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); From a5fde4b42355e894a3f6ec5d06c8bd3c92a09a81 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 20 Nov 2023 12:48:38 +0100 Subject: [PATCH 46/75] Fixing passthrough example --- examples/usb_passthrough.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/usb_passthrough.rs b/examples/usb_passthrough.rs index cb43443d..89440baa 100644 --- a/examples/usb_passthrough.rs +++ b/examples/usb_passthrough.rs @@ -86,9 +86,11 @@ fn main() -> ! { let mut serial2 = usbd_serial::SerialPort::new(&usb2_bus); let mut usb2_dev = UsbDeviceBuilder::new(&usb2_bus, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST PORT 2") + .strings(&[usb_device::device::StringDescriptors::default() + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST PORT 1")]) + .unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); From 88f1568fa3e5e7cede72ed688e42209b43bea76c Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:24:07 +0100 Subject: [PATCH 47/75] Update actions/checkout v2 -> v4; actions/cache v2 -> v3 --- .github/workflows/ci.yml | 6 +++--- .github/workflows/clippy.yml | 2 +- .github/workflows/nightly.yml | 6 +++--- .github/workflows/rustfmt.yml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd6e85b3..19a083b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,16 +36,16 @@ jobs: FLAGS: rt,xspi,sdmmc,sdmmc-fatfs,fmc,usb_hs,rtc,ethernet,ltdc,crc,rand,can,defmt steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Cache cargo registry and index - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ~/.cargo/registry ~/.cargo/git key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} - name: Cache cargo build - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: target key: ${{ runner.os }}-target-${{ matrix.rust }}-${{ hashFiles('**/Cargo.toml') }}-memory-${{ hashFiles('**/memory.x') }} diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 632c386c..ff19def2 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -9,7 +9,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: actions-rs/toolchain@v1 with: components: clippy diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 00480fd3..9f22bff1 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -22,16 +22,16 @@ jobs: FLAGS: rt,xspi,sdmmc,sdmmc-fatfs,fmc,usb_hs,rtc,ethernet,ltdc,crc,rand,can steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Cache cargo registry and index - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ~/.cargo/registry ~/.cargo/git key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} - name: Cache cargo build - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: target key: ${{ runner.os }}-target-nightly-${{ hashFiles('**/Cargo.toml') }}-memory-${{ hashFiles('**/memory.x') }} diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml index 544a5987..d674ccb0 100644 --- a/.github/workflows/rustfmt.yml +++ b/.github/workflows/rustfmt.yml @@ -10,7 +10,7 @@ jobs: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: actions-rs/toolchain@v1 with: profile: minimal From 28acb6c24098b2e619169c9da950179c76276c63 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:48:24 +0100 Subject: [PATCH 48/75] Migrate actions-rs/toolchain -> dtolnay/rust-toolchain --- .github/workflows/ci.yml | 17 ++++------------- .github/workflows/clippy.yml | 5 ++--- .github/workflows/nightly.yml | 18 ++++-------------- .github/workflows/rustfmt.yml | 11 +++-------- 4 files changed, 13 insertions(+), 38 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19a083b0..2e9346b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,18 +49,9 @@ jobs: with: path: target key: ${{ runner.os }}-target-${{ matrix.rust }}-${{ hashFiles('**/Cargo.toml') }}-memory-${{ hashFiles('**/memory.x') }} - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: - profile: minimal toolchain: ${{ matrix.rust }} - target: thumbv7em-none-eabihf - override: true - - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --verbose --release --examples --target thumbv7em-none-eabihf --features ${{ matrix.mcu }},${{ env.FLAGS }} - - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --target x86_64-unknown-linux-gnu --features ${{ matrix.mcu }},${{ env.FLAGS }} + targets: thumbv7em-none-eabihf + - run: cargo build --verbose --release --examples --target thumbv7em-none-eabihf --features ${{ matrix.mcu }},${{ env.FLAGS }} + - run: cargo test --lib --target x86_64-unknown-linux-gnu --features ${{ matrix.mcu }},${{ env.FLAGS }} diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index ff19def2..468b6390 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -10,12 +10,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: - components: clippy toolchain: 1.66.0 target: thumbv7em-none-eabihf - override: true + components: clippy - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 9f22bff1..4d991ec7 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -35,18 +35,8 @@ jobs: with: path: target key: ${{ runner.os }}-target-nightly-${{ hashFiles('**/Cargo.toml') }}-memory-${{ hashFiles('**/memory.x') }} - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@nightly with: - profile: minimal - toolchain: nightly - target: thumbv7em-none-eabihf - override: true - - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --verbose --release --examples --target thumbv7em-none-eabihf --features ${{ matrix.mcu }},${{ env.FLAGS }},${{ matrix.logging }} - - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --target x86_64-unknown-linux-gnu --features ${{ matrix.mcu }},${{ env.FLAGS }} + targets: thumbv7em-none-eabihf + - run: cargo build --verbose --release --examples --target thumbv7em-none-eabihf --features ${{ matrix.mcu }},${{ env.FLAGS }},${{ matrix.logging }} + - run: cargo test --lib --target x86_64-unknown-linux-gnu --features ${{ matrix.mcu }},${{ env.FLAGS }} diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml index d674ccb0..d1ff3657 100644 --- a/.github/workflows/rustfmt.yml +++ b/.github/workflows/rustfmt.yml @@ -11,13 +11,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: - profile: minimal toolchain: stable - override: true - - run: rustup component add rustfmt - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check + components: rustfmt + - run: cargo fmt --all -- --check From 82df2cba534ea050acabbafb652ac8dac3674f7b Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:55:04 +0100 Subject: [PATCH 49/75] Migrate actions-rs/clippy-check@v1 -> clechasseur/rs-clippy-check@v3 --- .github/workflows/clippy.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 468b6390..8abbc976 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -15,7 +15,6 @@ jobs: toolchain: 1.66.0 target: thumbv7em-none-eabihf components: clippy - - uses: actions-rs/clippy-check@v1 + - uses: clechasseur/rs-clippy-check@v3 with: - token: ${{ secrets.GITHUB_TOKEN }} args: --examples --target thumbv7em-none-eabihf --features=rt,stm32h743v -- -D warnings From c2a4c0e13c3a511d417295a84d735ec3c71c2dd4 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:55:48 +0100 Subject: [PATCH 50/75] Remove bors badge from README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c9535a8f..9b42e16a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ stm32h7xx-hal ============= [![docs.rs](https://docs.rs/stm32h7xx-hal/badge.svg)](https://docs.rs/stm32h7xx-hal) -[![Bors enabled](https://bors.tech/images/badge_small.svg)](https://app.bors.tech/repositories/12691) [![CI](https://github.com/stm32-rs/stm32h7xx-hal/workflows/Continuous%20integration/badge.svg)](https://github.com/stm32-rs/stm32h7xx-hal/actions) [![Crates.io](https://img.shields.io/crates/v/stm32h7xx-hal.svg)](https://crates.io/crates/stm32h7xx-hal) ![Minimum rustc version](https://img.shields.io/badge/rustc-1.65.0+-yellow.svg) From cd7c125cceceada4a3c70cc7387d187b00f9f7d2 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sun, 26 Nov 2023 21:49:59 +0100 Subject: [PATCH 51/75] Update clippy to 1.74.0 . Tidy clippy lints --- .github/workflows/clippy.yml | 2 +- examples/blinky.rs | 10 ++++------ examples/gpio_with_input.rs | 14 ++++++-------- examples/independent_watchdog.rs | 2 +- examples/system_watchdog.rs | 2 +- src/exti.rs | 6 ++---- src/lib.rs | 8 ++++---- src/prelude.rs | 2 +- 8 files changed, 20 insertions(+), 26 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 8abbc976..0dd9cc7d 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.66.0 + toolchain: 1.74.0 target: thumbv7em-none-eabihf components: clippy - uses: clechasseur/rs-clippy-check@v3 diff --git a/examples/blinky.rs b/examples/blinky.rs index 7e5eff99..4ce8f973 100644 --- a/examples/blinky.rs +++ b/examples/blinky.rs @@ -41,12 +41,10 @@ fn main() -> ! { let mut delay = cp.SYST.delay(ccdr.clocks); loop { - loop { - led.set_high(); - delay.delay_ms(500_u16); + led.set_high(); + delay.delay_ms(500_u16); - led.set_low(); - delay.delay_ms(500_u16); - } + led.set_low(); + delay.delay_ms(500_u16); } } diff --git a/examples/gpio_with_input.rs b/examples/gpio_with_input.rs index 53d5c463..3273d3d3 100644 --- a/examples/gpio_with_input.rs +++ b/examples/gpio_with_input.rs @@ -44,15 +44,13 @@ fn main() -> ! { let mut delay = cp.SYST.delay(ccdr.clocks); loop { - loop { - led.set_high(); - delay.delay_ms(100_u16); + led.set_high(); + delay.delay_ms(100_u16); - led.set_low(); - delay.delay_ms(100_u16); + led.set_low(); + delay.delay_ms(100_u16); - let is_high = led.with_input(|x| x.is_high()); - info!("LED pin high? {}", is_high); - } + let is_high = led.with_input(|x| x.is_high()); + info!("LED pin high? {}", is_high); } } diff --git a/examples/independent_watchdog.rs b/examples/independent_watchdog.rs index 48994409..85120474 100644 --- a/examples/independent_watchdog.rs +++ b/examples/independent_watchdog.rs @@ -36,7 +36,7 @@ fn main() -> ! { let mut watchdog = IndependentWatchdog::new(dp.IWDG2); // RM0468 - #[cfg(all(feature = "rm0468"))] + #[cfg(feature = "rm0468")] let mut watchdog = IndependentWatchdog::new(dp.IWDG1); info!(""); diff --git a/examples/system_watchdog.rs b/examples/system_watchdog.rs index b0e75d48..687910fe 100644 --- a/examples/system_watchdog.rs +++ b/examples/system_watchdog.rs @@ -34,7 +34,7 @@ fn main() -> ! { let mut watchdog = SystemWindowWatchdog::new(dp.WWDG2, &ccdr); // RM0468 - #[cfg(all(feature = "rm0468"))] + #[cfg(feature = "rm0468")] let mut watchdog = SystemWindowWatchdog::new(dp.WWDG1, &ccdr); info!(""); diff --git a/src/exti.rs b/src/exti.rs index 3e9b3d4e..7c90b6f2 100644 --- a/src/exti.rs +++ b/src/exti.rs @@ -257,9 +257,7 @@ impl ExtiExt for EXTI { let line = ev as u8; match line { - 0..=19 | 20 | 21 => { - reg_for_cpu!(self, pr1).read().bits() & (1 << line) != 0 - } + 0..=21 => reg_for_cpu!(self, pr1).read().bits() & (1 << line) != 0, 49 | 51 => { reg_for_cpu!(self, pr2).read().bits() & (1 << (line - 32)) != 0 } @@ -278,7 +276,7 @@ impl ExtiExt for EXTI { unsafe { match line { - 0..=19 | 20 | 21 => { + 0..=21 => { reg_for_cpu!(self, pr1).write(|w| w.bits(1 << line)); let _ = reg_for_cpu!(self, pr1).read(); let _ = reg_for_cpu!(self, pr1).read(); // Delay 2 peripheral clocks diff --git a/src/lib.rs b/src/lib.rs index 054a7f65..636bfe45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,15 +102,15 @@ pub use stm32h7::stm32h743 as stm32; pub use stm32h7::stm32h743v as stm32; // Single core with crypto -#[cfg(any(feature = "stm32h753",))] +#[cfg(feature = "stm32h753")] pub use stm32h7::stm32h753 as stm32; -#[cfg(any(feature = "stm32h753v",))] +#[cfg(feature = "stm32h753v")] pub use stm32h7::stm32h753v as stm32; // Dual core -#[cfg(any(feature = "stm32h747cm7",))] +#[cfg(feature = "stm32h747cm7")] pub use stm32h7::stm32h747cm7 as stm32; -#[cfg(any(feature = "stm32h757cm7",))] +#[cfg(feature = "stm32h757cm7")] pub use stm32h7::stm32h757cm7 as stm32; // TODO(rm0399): soundness of PeripheralREC macro in rcc/rec.rs diff --git a/src/prelude.rs b/src/prelude.rs index d37c7f74..d873702c 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -39,7 +39,7 @@ pub use crate::timer::HalDisabledLpTimer as _stm32h7xx_hal_timer_HalDisabledLpTi pub use crate::timer::HalEnabledLpTimer as _stm32h7xx_hal_timer_HalEnabledLpTimer; pub use crate::timer::HalLpTimer as _stm32h7xx_hal_timer_HalLpTimer; pub use crate::timer::TimerExt as _stm32h7xx_hal_timer_TimerExt; -#[cfg(all(feature = "xspi"))] +#[cfg(feature = "xspi")] #[cfg_attr(docsrs, doc(cfg(feature = "xspi")))] pub use crate::xspi::XspiExt as _stm32h7xx_hal_xspi_XspiExt; pub use fugit::{ExtU32 as _, RateExtU32 as _}; From 7e8664a5a51e31d82f80c9caec23e7b826296100 Mon Sep 17 00:00:00 2001 From: Roman Isaikin Date: Fri, 1 Dec 2023 10:42:22 +0100 Subject: [PATCH 52/75] Implement DSI HAL. --- Cargo.toml | 18 +- ...y-dsi-command-teartest-stm32h747i-disco.rs | 372 +++++++++ .../display-dsi-video-stm32h747i-disco.rs | 352 +++++++++ ...lay-dsi-video-teartest-stm32h747i-disco.rs | 371 +++++++++ examples/embedded-graphics.rs | 129 +--- examples/utilities/display_primitives.rs | 166 ++++ examples/utilities/display_target.rs | 139 ++++ examples/utilities/logger.rs | 4 +- examples/utilities/mod.rs | 10 + examples/utilities/mpu_config.rs | 77 ++ examples/utilities/write.rs | 54 ++ src/delay.rs | 2 +- src/dsi.rs | 707 ++++++++++++++++++ src/lib.rs | 2 + 14 files changed, 2272 insertions(+), 131 deletions(-) create mode 100644 examples/display-dsi-command-teartest-stm32h747i-disco.rs create mode 100644 examples/display-dsi-video-stm32h747i-disco.rs create mode 100644 examples/display-dsi-video-teartest-stm32h747i-disco.rs create mode 100644 examples/utilities/display_primitives.rs create mode 100644 examples/utilities/display_target.rs create mode 100644 examples/utilities/mpu_config.rs create mode 100644 examples/utilities/write.rs create mode 100644 src/dsi.rs diff --git a/Cargo.toml b/Cargo.toml index 9e2370b4..a9436156 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ embedded-display-controller = { version = "^0.1.0", optional = true } log = { version = "0.4.14", optional = true} # see also the dev-dependencies section fdcan = { version = "0.2", optional = true } embedded-storage = "0.3" +embedded-dsi = { path = "../embedded-hal/embedded-dsi", optional = true } [dependencies.smoltcp] version = "0.10.0" @@ -81,6 +82,9 @@ usbd-serial = "0.1.0" numtoa = "0.2.3" tinybmp = "0.5" embedded-graphics = "0.8" +otm8009a = { path = "../otm8009a" } +eg-seven-segment = "0.2.0" +ft6236 = { git = "https://github.com/romixlab/ft6236.git" } [dev-dependencies.smoltcp] version = "0.10.0" @@ -100,7 +104,7 @@ gpio-h72 = [] gpio-h747 = [] gpio-h7a2 = [] -dsi = [] +dsi = ["embedded-dsi", "embedded-display-controller"] cm4 = [] cm7 = [] smps = [] @@ -262,3 +266,15 @@ required-features = ["rt", "usb_hs", "rm0433"] [[example]] name = "vos0" required-features = ["revision_v"] + +[[example]] +name = "display-dsi-video-stm32h747i-disco" +required-features = ["dsi", "ltdc", "fmc"] + +[[example]] +name = "display-dsi-video-teartest-stm32h747i-disco" +required-features = ["dsi", "ltdc", "fmc"] + +[[example]] +name = "display-dsi-command-teartest-stm32h747i-disco" +required-features = ["dsi", "ltdc", "fmc"] diff --git a/examples/display-dsi-command-teartest-stm32h747i-disco.rs b/examples/display-dsi-command-teartest-stm32h747i-disco.rs new file mode 100644 index 00000000..6b642729 --- /dev/null +++ b/examples/display-dsi-command-teartest-stm32h747i-disco.rs @@ -0,0 +1,372 @@ +//! This example uses the embedded-graphics library to draw fast moving objects on +//! an external display. The external display is connected through the DSI link. +//! DSI Adapted command mode is used to refresh the display only when needed. +//! +//! When using the display in Portrait mode, no diagonal tearing line should be visible. +//! +//! While in Landscape mode diagonal line is visible, because display is still refreshed +//! in 480px lines from display's own graphics RAM, while writes are now 800px high. +//! +//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,rm0399,smps,example-smps,log-rtt,rt,rtc" --example display-dsi-command-teartest-stm32h747i-disco +//! +//! Tested on a STM32H747I-DISCO development board with a ST MB1166 Display +//! (supplied together with the development kit). +//! Display Controller: OTM8009A, LCD: KJD KM-040TMP-02, Frida FRD397B2509 + +// #![deny(warnings)] +#![no_main] +#![no_std] + +use core::{mem, slice}; + +#[macro_use] +mod utilities; +use log::info; +use otm8009a::Otm8009AConfig; +use stm32h7xx_hal::dsi::{ColorCoding, DsiChannel, DsiConfig, DsiPllConfig}; + +extern crate cortex_m; +extern crate cortex_m_rt as rt; +use cortex_m_rt::{entry, exception}; + +use crate::utilities::display_target::BufferedDisplay; +use stm32h7xx_hal::gpio::Speed; +use stm32h7xx_hal::ltdc; +use stm32h7xx_hal::stm32::rcc::d1ccipr::FMCSEL_A; +use stm32h7xx_hal::{prelude::*, stm32}; + +use embedded_display_controller::DisplayController; + +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::{Circle, PrimitiveStyleBuilder, Rectangle}; + +use embedded_display_controller::DisplayConfiguration; +use otm8009a::Otm8009A; +use stm32h7xx_hal::dsi::{ + DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, + DsiVideoMode, LaneCount, +}; +use ft6236::{FT6236}; +use crate::utilities::mpu_config::init_mpu; +use crate::utilities::write::write_to::WriteTo; +use core::fmt::Write; +use stm32h7xx_hal::rcc::PllConfigStrategy; +use crate::utilities::display_primitives::{colored_label, display_test}; + +// Remember to use correct display controller orientation, Portrait in this case +pub const WIDTH: usize = 480; +pub const HEIGHT: usize = 800; + +pub const DISPLAY_CONFIGURATION: DisplayConfiguration = DisplayConfiguration { + active_width: WIDTH as _, + active_height: HEIGHT as _, + h_back_porch: 34, + h_front_porch: 34, + v_back_porch: 15, + v_front_porch: 16, + h_sync: 2, + v_sync: 1, + h_sync_pol: false, + v_sync_pol: false, + not_data_enable_pol: false, + pixel_clock_pol: false, +}; + +/// Configure a pin for the FMC controller +macro_rules! fmc_pins { + ($($pin:expr),*) => { + ( + $( + $pin.into_push_pull_output() + .speed(Speed::VeryHigh) + .into_alternate::<12>() + .internal_pull_up(true) + ),* + ) + }; +} + +#[entry] +fn main() -> ! { + utilities::logger::init(); + + let dp = stm32::Peripherals::take().unwrap(); + let mut cp = stm32::CorePeripherals::take().unwrap(); + + // Constrain and Freeze power + info!("Setup PWR..."); + let pwr = dp.PWR.constrain(); + let pwrcfg = example_power!(pwr).vos0(&dp.SYSCFG).freeze(); + + // Constrain and Freeze clock + info!("Setup RCC..."); + let rcc = dp.RCC.constrain(); + + // Important for DSI PLL to configure this correctly. + // Disco board uses an oscillator while Eval - a crystal. + let hse_freq = 25.MHz(); + let rcc = rcc.use_hse(hse_freq).bypass_hse(); + // Any clock should work in adapted command mode, the faster the better. + let ltdc_freq = 42_000.kHz(); + + let ccdr = rcc + .sys_ck(400.MHz()) + // FMC will run at 100MHz, as this clock is further divided by 2 + .pll2_p_ck(200.MHz()) + // .pll2_q_ck(200.MHz()) + .pll2_r_ck(200.MHz()) + .pll2_strategy(PllConfigStrategy::Iterative) + // LTDC + .pll3_p_ck(400.MHz()) + .pll3_q_ck(400.MHz()) + .pll3_r_ck(ltdc_freq) + .pll3_strategy(PllConfigStrategy::Iterative) + .freeze(pwrcfg, &dp.SYSCFG); + + // Get frequency of LTDC pixel clock + info!("pll3_r_ck: {:?}", ccdr.clocks.pll3_r_ck()); + let _pll3_r = ccdr.clocks.pll3_r_ck().expect("pll3 must run!"); + + // Get the delay provider. + let mut delay = cp.SYST.delay(ccdr.clocks); + + // Initialise system... + cp.SCB.invalidate_icache(); + cp.SCB.enable_icache(); + //cp.SCB.enable_dcache(&mut cp.CPUID); // TODO invalidate dcache when writing to the display + cp.DWT.enable_cycle_counter(); + + // Initialise IO... + // let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); + // let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB); + // let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC); + let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD); + let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE); + let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF); + let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG); + let gpioh = dp.GPIOH.split(ccdr.peripheral.GPIOH); + let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI); + let gpioj = dp.GPIOJ.split(ccdr.peripheral.GPIOJ); + + let _syscfg = dp.SYSCFG; + let _exti = dp.EXTI; + + // MPU config for SDRAM write-through + let sdram_size = 32 * 1024 * 1024; + init_mpu(cp.MPU, &mut cp.SCB, sdram_size); + + // pin setup for SDRAM + let sdram_pins = fmc_pins! { + // A0-A11 + gpiof.pf0, gpiof.pf1, gpiof.pf2, gpiof.pf3, + gpiof.pf4, gpiof.pf5, gpiof.pf12, gpiof.pf13, + gpiof.pf14, gpiof.pf15, gpiog.pg0, gpiog.pg1, + // BA0-BA1 + gpiog.pg4, gpiog.pg5, + // D0-D31 + gpiod.pd14, gpiod.pd15, gpiod.pd0, gpiod.pd1, + gpioe.pe7, gpioe.pe8, gpioe.pe9, gpioe.pe10, + gpioe.pe11, gpioe.pe12, gpioe.pe13, gpioe.pe14, + gpioe.pe15, gpiod.pd8, gpiod.pd9, gpiod.pd10, + gpioh.ph8, gpioh.ph9, gpioh.ph10, gpioh.ph11, + gpioh.ph12, gpioh.ph13, gpioh.ph14, gpioh.ph15, + gpioi.pi0, gpioi.pi1, gpioi.pi2, gpioi.pi3, + gpioi.pi6, gpioi.pi7, gpioi.pi9, gpioi.pi10, + // NBL0 - NBL3 + gpioe.pe0, gpioe.pe1, gpioi.pi4, gpioi.pi5, + gpioh.ph7, // SDCKE1 + gpiog.pg8, // SDCLK + gpiog.pg15, // SDNCAS + gpioh.ph6, // SDNE1 (!CS) + gpiof.pf11, // SDRAS + gpioh.ph5 // SDNWE + }; + + let fmc_ccdr = ccdr.peripheral.FMC.kernel_clk_mux(FMCSEL_A::Pll2R); + // TODO: incorrect for disco! + let sdram_chip = stm32_fmc::devices::is42s32800g_6::Is42s32800g {}; + let mut sdram = dp.FMC.sdram( + sdram_pins, + sdram_chip, + // ccdr.peripheral.FMC, + fmc_ccdr, + &ccdr.clocks, + ); + + let (fb1, fb2) = unsafe { + // Initialise controller and SDRAM + let ram_ptr: *mut u32 = sdram.init(&mut delay); + slice::from_raw_parts_mut(ram_ptr, sdram_size / mem::size_of::()) + .fill(0); + + let fb_size = WIDTH * HEIGHT; + let bank_size_words = 8 * 1024 * 1024 / 4; + let fb1 = slice::from_raw_parts_mut(ram_ptr, fb_size); + // Offset the second buffer into another SDRAM bank - this saves a bit of time if DMA2D is used + // to clear the fb while update is ongoing. + let fb2 = + slice::from_raw_parts_mut(ram_ptr.offset(bank_size_words), fb_size); + (fb1, fb2) + }; + + info!("Initialised SDRAM..."); + + // Initialise LCD... + // Display controller reset through dedicated IO + let mut display_reset = gpiog.pg3.into_push_pull_output(); + display_reset.set_low(); + delay.delay_ms(20u32); + display_reset.set_high(); + delay.delay_ms(10u32); + + // Display backlight enable + let mut display_backlight_en = gpioj.pj12.into_push_pull_output(); + display_backlight_en.set_high(); + + // Display controller TE (hw tear effect sync) pin as input + // let _display_te = gpioj.pj2.into_alternate::<13>(); + let _display_te = gpioj.pj2.into_input(); + // display_te.make_interrupt_source(&mut syscfg); + // display_te.trigger_on_edge(&mut exti, Edge::Rising); + // display_te.enable_interrupt(&mut exti); + + let mut ltdc = ltdc::Ltdc::new(dp.LTDC, ccdr.peripheral.LTDC, &ccdr.clocks); + ltdc.init(DISPLAY_CONFIGURATION); + + let layer = ltdc.split(); + let mut disp = BufferedDisplay::new(layer, fb1, fb2, WIDTH, HEIGHT); + + // Fin = 25MHz ->/idf = 5MHz ->*2 = 10MHz ->*ndiv = 1GHz ->/2 = 500MHz ->/odf = 500MHz (500Mbps per lane); pix clk (/8) = 62.5MHz + let dsi_pll_config = unsafe { DsiPllConfig::manual(100, 5, 0, 4) }; + + let dsi_config = DsiConfig { + mode: DsiMode::AdaptedCommand { + tear_effect: None, + }, + lane_count: LaneCount::DoubleLane, + channel: DsiChannel::Ch0, + hse_freq, + ltdc_freq, + interrupts: DsiInterrupts::None, + color_coding_host: ColorCoding::TwentyFourBits, + color_coding_wrapper: ColorCoding::TwentyFourBits, + lp_size: 4, // for OTM8009A + vlp_size: 4, + }; + let mut dsi_host = DsiHost::init( + dsi_pll_config, + DISPLAY_CONFIGURATION, + dsi_config, + dp.DSIHOST, + ccdr.peripheral.DSI, + &ccdr.clocks, + ) + .expect("DSI host failed to init"); + dsi_host.set_command_mode_transmission_kind( + DsiCmdModeTransmissionKind::AllInLowPower, + ); + + // Enable DSI host + dsi_host.start(); + dsi_host.enable_bus_turn_around(); // Must be before read attempts + + dsi_host.configure_phy_timers(DsiPhyTimers { + dataline_hs2lp: 35, + dataline_lp2hs: 35, + clock_hs2lp: 35, + clock_lp2hs: 35, + dataline_max_read_time: 0, + stop_wait_time: 10, + }); + + let otm8009a_config = Otm8009AConfig { + frame_rate: otm8009a::FrameRate::_70Hz, + // NOTE: In Landscape mode diagonal tearing line will be visible when fast changing content is present + mode: otm8009a::Mode::Portrait, + color_map: otm8009a::ColorMap::Rgb, + cols: WIDTH as u16, + rows: HEIGHT as u16, + }; + let mut glass_ctrl = Otm8009A::new(); + glass_ctrl + .init(&mut dsi_host, otm8009a_config, &mut delay) + .unwrap(); + glass_ctrl.enable_te_output(533, &mut dsi_host).unwrap(); + + // Not sure if this is needed + dsi_host.set_command_mode_transmission_kind( + DsiCmdModeTransmissionKind::AllInHighSpeed, + ); + dsi_host.force_rx_low_power(true); + + let mut dsi_refresh_handle = dsi_host.refresh_handle(); + info!("Initialised Display..."); + + let scl = gpiod.pd12.into_alternate_open_drain(); + let sda = gpiod.pd13.into_alternate_open_drain(); + let i2c4 = + dp.I2C4 + .i2c((scl, sda), 100.kHz(), ccdr.peripheral.I2C4, &ccdr.clocks); + let mut touch_ctrl = FT6236::new(i2c4); + // let touch_int = gpiok.pk7 + + let mut x = 0; + let mut y = 0; + let mut frame = 0; + let style_green = PrimitiveStyleBuilder::new() + .fill_color(Rgb888::GREEN) + .build(); + let mut buf = [0u8; 64]; + + loop { + // Draw on a double buffered display + disp.layer(|draw| { + draw.clear(); + + Rectangle::new(Point::new(x, 0), Size::new(100, HEIGHT as u32)) + .into_styled(style_green) + .draw(draw) + .unwrap(); + + Rectangle::new(Point::new(0, y), Size::new(WIDTH as u32, 100)) + .into_styled(style_green) + .draw(draw) + .unwrap(); + + x += 5; + y += 5; + if x >= WIDTH as i32 { + x = 0; + } + if y >= HEIGHT as i32 { + y = 0; + } + + let mut buf = WriteTo::new(&mut buf); + write!(&mut buf, "f: {frame}").unwrap(); + frame += 1; + colored_label(buf.as_str().unwrap(), 50, 20, Rgb888::RED, draw).unwrap(); + + if let Ok(Some(pt)) = touch_ctrl.get_point0() { + info!("Touch: {} {}", pt.y, 480 - pt.x); + Circle::new(Point::new(480 - pt.x as i32 - 25, pt.y as i32 - 25), 50).into_styled(style_green).draw(draw).unwrap(); + } + + display_test(draw).unwrap(); + }); + disp.swap_layer_wait(); + dsi_refresh_handle.refresh_now(); + delay.delay_ms(500u32); + } +} + +#[exception] +unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); +} + +#[exception] +unsafe fn DefaultHandler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); +} \ No newline at end of file diff --git a/examples/display-dsi-video-stm32h747i-disco.rs b/examples/display-dsi-video-stm32h747i-disco.rs new file mode 100644 index 00000000..65ee0471 --- /dev/null +++ b/examples/display-dsi-video-stm32h747i-disco.rs @@ -0,0 +1,352 @@ +//! This example uses the embedded-graphics library to draw text and an image on +//! an external display. The external display is connected through the DSI link. +//! DSI Video mode is used, so the display is constantly refreshed by hardware. +//! +//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,rm0399,smps,example-smps,log-rtt,rt,rtc" --example display-dsi-video-stm32h747i-disco +//! +//! Tested on a STM32H747I-DISCO development board with a ST MB1166 Display +//! (supplied together with the development kit). +//! Display Controller: OTM8009A, LCD: KJD KM-040TMP-02, Frida FRD397B2509 + +#![deny(warnings)] +#![no_main] +#![no_std] + +use core::{mem, slice}; + +#[macro_use] +mod utilities; +use log::info; +use otm8009a::Otm8009AConfig; +use stm32h7xx_hal::dsi::{ColorCoding, DsiChannel, DsiConfig, DsiPllConfig}; + +extern crate cortex_m; +extern crate cortex_m_rt as rt; +use cortex_m_rt::{entry, exception}; + +use crate::utilities::display_target::BufferedDisplay; +use stm32h7xx_hal::gpio::Speed; +use stm32h7xx_hal::ltdc; +use stm32h7xx_hal::stm32::rcc::d1ccipr::FMCSEL_A; +use stm32h7xx_hal::{prelude::*, rtc, stm32}; + +use embedded_display_controller::DisplayController; + +use chrono::{NaiveDateTime, NaiveTime}; +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::{Circle, PrimitiveStyleBuilder}; + +use embedded_display_controller::DisplayConfiguration; +use otm8009a::Otm8009A; +use stm32h7xx_hal::dsi::{ + DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, + DsiVideoMode, LaneCount, +}; +use ft6236::{FT6236}; +use crate::utilities::display_primitives::time_circuit; +use crate::utilities::mpu_config::init_mpu; + +pub const WIDTH: usize = 800; +pub const HEIGHT: usize = 480; + +pub const DISPLAY_CONFIGURATION: DisplayConfiguration = DisplayConfiguration { + active_width: WIDTH as _, + active_height: HEIGHT as _, + h_back_porch: 34, + h_front_porch: 34, + v_back_porch: 15, + v_front_porch: 16, + h_sync: 2, + v_sync: 1, + h_sync_pol: false, + v_sync_pol: false, + not_data_enable_pol: false, + pixel_clock_pol: false, +}; + +/// Configure a pin for the FMC controller +macro_rules! fmc_pins { + ($($pin:expr),*) => { + ( + $( + $pin.into_push_pull_output() + .speed(Speed::VeryHigh) + .into_alternate::<12>() + .internal_pull_up(true) + ),* + ) + }; +} + +#[entry] +fn main() -> ! { + utilities::logger::init(); + + let dp = stm32::Peripherals::take().unwrap(); + let mut cp = stm32::CorePeripherals::take().unwrap(); + + // Constrain and Freeze power + info!("Setup PWR..."); + let pwr = dp.PWR.constrain(); + let mut pwrcfg = example_power!(pwr).vos0(&dp.SYSCFG).freeze(); + let backup = pwrcfg.backup().unwrap(); + + // Constrain and Freeze clock + info!("Setup RCC..."); + let rcc = dp.RCC.constrain(); + + // Important for DSI PLL to configure this correctly. + // Disco board uses an oscillator while Eval - a crystal. + let hse_freq = 25.MHz(); + let rcc = rcc.use_hse(hse_freq).bypass_hse(); + // Precisely crafted clock in video mode + let ltdc_freq = 27_429.kHz(); + + let ccdr = rcc + .sys_ck(400.MHz()) + // Octo SPI + .pll2_p_ck(400.MHz() / 5) + .pll2_q_ck(400.MHz() / 2) + .pll2_r_ck(400.MHz() / 2) + // LTDC + .pll3_p_ck(330.MHz()) + .pll3_q_ck(330.MHz()) + .pll3_r_ck(ltdc_freq) + .freeze(pwrcfg, &dp.SYSCFG); + + // Get frequency of LTDC pixel clock + info!("pll3_r_ck: {:?}", ccdr.clocks.pll3_r_ck()); + let _pll3_r = ccdr.clocks.pll3_r_ck().expect("pll3 must run!"); + + let mut rtc = rtc::Rtc::open_or_init( + dp.RTC, + backup.RTC, + rtc::RtcClock::Lsi, + &ccdr.clocks, + ); + + use chrono::NaiveDate; + let now = NaiveDate::from_ymd_opt(2023, 11, 24) + .unwrap() + .and_hms_opt(12, 54, 0) + .unwrap(); + rtc.set_date_time(now); + + // Get the delay provider. + let mut delay = cp.SYST.delay(ccdr.clocks); + + // Initialise system... + cp.SCB.invalidate_icache(); + cp.SCB.enable_icache(); + //cp.SCB.enable_dcache(&mut cp.CPUID); // TODO invalidate dcache when writing to the display + cp.DWT.enable_cycle_counter(); + + // Initialise IO... + // let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); + // let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB); + // let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC); + let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD); + let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE); + let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF); + let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG); + let gpioh = dp.GPIOH.split(ccdr.peripheral.GPIOH); + let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI); + let gpioj = dp.GPIOJ.split(ccdr.peripheral.GPIOJ); + + let _syscfg = dp.SYSCFG; + let _exti = dp.EXTI; + + // MPU config for SDRAM write-through + let sdram_size = 32 * 1024 * 1024; + init_mpu(cp.MPU, &mut cp.SCB, sdram_size); + + // pin setup for SDRAM + let sdram_pins = fmc_pins! { + // A0-A11 + gpiof.pf0, gpiof.pf1, gpiof.pf2, gpiof.pf3, + gpiof.pf4, gpiof.pf5, gpiof.pf12, gpiof.pf13, + gpiof.pf14, gpiof.pf15, gpiog.pg0, gpiog.pg1, + // BA0-BA1 + gpiog.pg4, gpiog.pg5, + // D0-D31 + gpiod.pd14, gpiod.pd15, gpiod.pd0, gpiod.pd1, + gpioe.pe7, gpioe.pe8, gpioe.pe9, gpioe.pe10, + gpioe.pe11, gpioe.pe12, gpioe.pe13, gpioe.pe14, + gpioe.pe15, gpiod.pd8, gpiod.pd9, gpiod.pd10, + gpioh.ph8, gpioh.ph9, gpioh.ph10, gpioh.ph11, + gpioh.ph12, gpioh.ph13, gpioh.ph14, gpioh.ph15, + gpioi.pi0, gpioi.pi1, gpioi.pi2, gpioi.pi3, + gpioi.pi6, gpioi.pi7, gpioi.pi9, gpioi.pi10, + // NBL0 - NBL3 + gpioe.pe0, gpioe.pe1, gpioi.pi4, gpioi.pi5, + gpioh.ph7, // SDCKE1 + gpiog.pg8, // SDCLK + gpiog.pg15, // SDNCAS + gpioh.ph6, // SDNE1 (!CS) + gpiof.pf11, // SDRAS + gpioh.ph5 // SDNWE + }; + + let fmc_ccdr = ccdr.peripheral.FMC.kernel_clk_mux(FMCSEL_A::Pll2R); + // TODO: incorrect for disco! + let sdram_chip = stm32_fmc::devices::is42s32800g_6::Is42s32800g {}; + let mut sdram = dp.FMC.sdram( + sdram_pins, + sdram_chip, + // ccdr.peripheral.FMC, + fmc_ccdr, + &ccdr.clocks, + ); + + let (fb1, fb2) = unsafe { + // Initialise controller and SDRAM + let ram_ptr: *mut u32 = sdram.init(&mut delay); + slice::from_raw_parts_mut(ram_ptr, sdram_size / mem::size_of::()) + .fill(0); + + let fb_size = WIDTH * HEIGHT; + let bank_size_words = 8 * 1024 * 1024 / 4; + let fb1 = slice::from_raw_parts_mut(ram_ptr, fb_size); + // Offset the second buffer into another SDRAM bank - this saves a bit of time if DMA2D is used + // to clear the fb while update is ongoing. + let fb2 = + slice::from_raw_parts_mut(ram_ptr.offset(bank_size_words), fb_size); + (fb1, fb2) + }; + + info!("Initialised SDRAM..."); + + // Initialise LCD... + // Display controller reset through dedicated IO + let mut display_reset = gpiog.pg3.into_push_pull_output(); + display_reset.set_low(); + delay.delay_ms(20u32); + display_reset.set_high(); + delay.delay_ms(10u32); + + // Display backlight enable + let mut display_backlight_en = gpioj.pj12.into_push_pull_output(); + display_backlight_en.set_high(); + + // Display controller TE (hw tear effect sync) pin as input + // let _display_te = gpioj.pj2.into_alternate::<13>(); + let _display_te = gpioj.pj2.into_input(); + // display_te.make_interrupt_source(&mut syscfg); + // display_te.trigger_on_edge(&mut exti, Edge::Rising); + // display_te.enable_interrupt(&mut exti); + + let mut ltdc = ltdc::Ltdc::new(dp.LTDC, ccdr.peripheral.LTDC, &ccdr.clocks); + ltdc.init(DISPLAY_CONFIGURATION); + + let layer = ltdc.split(); + let mut disp = BufferedDisplay::new(layer, fb1, fb2, WIDTH, HEIGHT); + + // Fin = 25MHz ->/idf = 5MHz ->*2 = 10MHz ->*ndiv = 1GHz ->/2 = 500MHz ->/odf = 500MHz (500Mbps per lane); pix clk (/8) = 62.5MHz + let dsi_pll_config = unsafe { DsiPllConfig::manual(100, 5, 0, 4) }; + + let dsi_config = DsiConfig { + mode: DsiMode::Video { + // mode: DsiVideoMode::NonBurstWithSyncEvents, + mode: DsiVideoMode::Burst, + }, + lane_count: LaneCount::DoubleLane, + channel: DsiChannel::Ch0, + hse_freq, + ltdc_freq, + interrupts: DsiInterrupts::None, + color_coding_host: ColorCoding::TwentyFourBits, + color_coding_wrapper: ColorCoding::TwentyFourBits, + lp_size: 4, // for OTM8009A + vlp_size: 4, + }; + let mut dsi_host = DsiHost::init( + dsi_pll_config, + DISPLAY_CONFIGURATION, + dsi_config, + dp.DSIHOST, + ccdr.peripheral.DSI, + &ccdr.clocks, + ) + .expect("DSI host failed to init"); + dsi_host.set_command_mode_transmission_kind( + DsiCmdModeTransmissionKind::AllInLowPower, + ); + + // Enable DSI host + dsi_host.start(); + dsi_host.enable_bus_turn_around(); // Must be before read attempts + + dsi_host.configure_phy_timers(DsiPhyTimers { + dataline_hs2lp: 35, + dataline_lp2hs: 35, + clock_hs2lp: 35, + clock_lp2hs: 35, + dataline_max_read_time: 0, + stop_wait_time: 10, + }); + + let otm8009a_config = Otm8009AConfig { + frame_rate: otm8009a::FrameRate::_70Hz, + // NOTE: In Landscape mode diagonal tearing line will be visible when fast changing content is present + mode: otm8009a::Mode::Landscape, + color_map: otm8009a::ColorMap::Rgb, + cols: WIDTH as u16, + rows: HEIGHT as u16, + }; + let mut glass_ctrl = Otm8009A::new(); + glass_ctrl + .init(&mut dsi_host, otm8009a_config, &mut delay) + .unwrap(); + glass_ctrl.enable_te_output(533, &mut dsi_host).unwrap(); + + // Not sure if this is needed + dsi_host.set_command_mode_transmission_kind( + DsiCmdModeTransmissionKind::AllInHighSpeed, + ); + dsi_host.force_rx_low_power(true); + + //let mut dsi_refresh_handle = dsi_host.refresh_handle(); + info!("Initialised Display..."); + + let scl = gpiod.pd12.into_alternate_open_drain(); + let sda = gpiod.pd13.into_alternate_open_drain(); + let i2c4 = + dp.I2C4 + .i2c((scl, sda), 100.kHz(), ccdr.peripheral.I2C4, &ccdr.clocks); + let mut touch_ctrl = FT6236::new(i2c4); + // let touch_int = gpiok.pk7 + + let style_green = PrimitiveStyleBuilder::new() + .fill_color(Rgb888::GREEN) + .build(); + + loop { + // Draw on a double buffered display + disp.layer(|draw| { + draw.clear(); + + let tc_x = 54; + time_circuit(NaiveDateTime::new(NaiveDate::from_ymd_opt(1985, 10, 26).unwrap(), NaiveTime::from_hms_opt(01, 21, 0).unwrap()), tc_x, 100, "DESTINATION TIME", Rgb888::CSS_ORANGE_RED, Rgb888::new(102, 27, 0), draw).unwrap(); + let now = rtc.date_time().unwrap(); + time_circuit(now, tc_x, 250, "PRESENT TIME", Rgb888::CSS_LIME_GREEN, Rgb888::new(15, 64, 15), draw).unwrap(); + time_circuit(NaiveDateTime::new(NaiveDate::from_ymd_opt(1985, 10, 26).unwrap(), NaiveTime::from_hms_opt(01, 20, 0).unwrap()), tc_x, 400, "LAST TIME DEPARTED", Rgb888::CSS_ORANGE, Rgb888::new(77, 42, 0), draw).unwrap(); + + if let Ok(Some(pt)) = touch_ctrl.get_point0() { + info!("Touch: {} {}", pt.y, 480 - pt.x); + Circle::new(Point::new(pt.y as i32 - 25, 480 - pt.x as i32 - 25), 50).into_styled(style_green).draw(draw).unwrap(); + } + }); + disp.swap_layer_wait(); + } +} + +#[exception] +unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); +} + +#[exception] +unsafe fn DefaultHandler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); +} \ No newline at end of file diff --git a/examples/display-dsi-video-teartest-stm32h747i-disco.rs b/examples/display-dsi-video-teartest-stm32h747i-disco.rs new file mode 100644 index 00000000..0d249daa --- /dev/null +++ b/examples/display-dsi-video-teartest-stm32h747i-disco.rs @@ -0,0 +1,371 @@ +//! This example uses the embedded-graphics library to draw fast moving objects on +//! an external display. The external display is connected through the DSI link. +//! DSI Video mode is used, so the display is constantly refreshed by hardware. +//! +//! When using the display in Portrait mode, no diagonal tearing line should be visible. +//! +//! While in Landscape mode diagonal line is visible, because display is still refreshed +//! in 480px lines from display's own graphics RAM, while writes are now 800px high. +//! +//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,rm0399,smps,example-smps,log-rtt,rt,rtc" --example display-dsi-video-teartest-stm32h747i-disco +//! +//! Tested on a STM32H747I-DISCO development board with a ST MB1166 Display +//! (supplied together with the development kit). +//! Display Controller: OTM8009A, LCD: KJD KM-040TMP-02, Frida FRD397B2509 + +#![deny(warnings)] +#![no_main] +#![no_std] + +use core::{mem, slice}; + +#[macro_use] +mod utilities; +use log::info; +use otm8009a::Otm8009AConfig; +use stm32h7xx_hal::dsi::{ColorCoding, DsiChannel, DsiConfig, DsiPllConfig}; + +extern crate cortex_m; +extern crate cortex_m_rt as rt; +use cortex_m_rt::{entry, exception}; + +use crate::utilities::display_target::BufferedDisplay; +use stm32h7xx_hal::gpio::Speed; +use stm32h7xx_hal::ltdc; +use stm32h7xx_hal::stm32::rcc::d1ccipr::FMCSEL_A; +use stm32h7xx_hal::{prelude::*, stm32}; + +use embedded_display_controller::DisplayController; + +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::{Circle, PrimitiveStyleBuilder, Rectangle}; + +use embedded_display_controller::DisplayConfiguration; +use otm8009a::Otm8009A; +use stm32h7xx_hal::dsi::{ + DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, + DsiVideoMode, LaneCount, +}; +use ft6236::{FT6236}; +use crate::utilities::mpu_config::init_mpu; +use crate::utilities::write::write_to::WriteTo; +use core::fmt::Write; +use stm32h7xx_hal::rcc::PllConfigStrategy; +use crate::utilities::display_primitives::{colored_label, display_test}; + +// Remember to use correct display controller orientation, Portrait in this case +pub const WIDTH: usize = 480; +pub const HEIGHT: usize = 800; + +pub const DISPLAY_CONFIGURATION: DisplayConfiguration = DisplayConfiguration { + active_width: WIDTH as _, + active_height: HEIGHT as _, + h_back_porch: 34, + h_front_porch: 34, + v_back_porch: 15, + v_front_porch: 16, + h_sync: 2, + v_sync: 1, + h_sync_pol: false, + v_sync_pol: false, + not_data_enable_pol: false, + pixel_clock_pol: false, +}; + +/// Configure a pin for the FMC controller +macro_rules! fmc_pins { + ($($pin:expr),*) => { + ( + $( + $pin.into_push_pull_output() + .speed(Speed::VeryHigh) + .into_alternate::<12>() + .internal_pull_up(true) + ),* + ) + }; +} + +#[entry] +fn main() -> ! { + utilities::logger::init(); + + let dp = stm32::Peripherals::take().unwrap(); + let mut cp = stm32::CorePeripherals::take().unwrap(); + + // Constrain and Freeze power + info!("Setup PWR..."); + let pwr = dp.PWR.constrain(); + let pwrcfg = example_power!(pwr).vos0(&dp.SYSCFG).freeze(); + + // Constrain and Freeze clock + info!("Setup RCC..."); + let rcc = dp.RCC.constrain(); + + // Important for DSI PLL to configure this correctly. + // Disco board uses an oscillator while Eval - a crystal. + let hse_freq = 25.MHz(); + let rcc = rcc.use_hse(hse_freq).bypass_hse(); + // Precisely crafted clock in video mode + let ltdc_freq = 27_429.kHz(); + + let ccdr = rcc + .sys_ck(400.MHz()) + // FMC will run at 100MHz, as this clock is further divided by 2 + .pll2_p_ck(200.MHz()) + // .pll2_q_ck(200.MHz() / 2) + .pll2_r_ck(200.MHz()) + .pll2_strategy(PllConfigStrategy::Iterative) + // LTDC + .pll3_p_ck(330.MHz()) + .pll3_q_ck(330.MHz()) + .pll3_r_ck(ltdc_freq) + .pll3_strategy(PllConfigStrategy::Iterative) + .freeze(pwrcfg, &dp.SYSCFG); + + // Get frequency of LTDC pixel clock + info!("pll3_r_ck: {:?}", ccdr.clocks.pll3_r_ck()); + let _pll3_r = ccdr.clocks.pll3_r_ck().expect("pll3 must run!"); + + // Get the delay provider. + let mut delay = cp.SYST.delay(ccdr.clocks); + + // Initialise system... + cp.SCB.invalidate_icache(); + cp.SCB.enable_icache(); + //cp.SCB.enable_dcache(&mut cp.CPUID); // TODO invalidate dcache when writing to the display + cp.DWT.enable_cycle_counter(); + + // Initialise IO... + // let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); + // let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB); + // let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC); + let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD); + let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE); + let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF); + let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG); + let gpioh = dp.GPIOH.split(ccdr.peripheral.GPIOH); + let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI); + let gpioj = dp.GPIOJ.split(ccdr.peripheral.GPIOJ); + + let _syscfg = dp.SYSCFG; + let _exti = dp.EXTI; + + // MPU config for SDRAM write-through + let sdram_size = 32 * 1024 * 1024; + init_mpu(cp.MPU, &mut cp.SCB, sdram_size); + + // pin setup for SDRAM + let sdram_pins = fmc_pins! { + // A0-A11 + gpiof.pf0, gpiof.pf1, gpiof.pf2, gpiof.pf3, + gpiof.pf4, gpiof.pf5, gpiof.pf12, gpiof.pf13, + gpiof.pf14, gpiof.pf15, gpiog.pg0, gpiog.pg1, + // BA0-BA1 + gpiog.pg4, gpiog.pg5, + // D0-D31 + gpiod.pd14, gpiod.pd15, gpiod.pd0, gpiod.pd1, + gpioe.pe7, gpioe.pe8, gpioe.pe9, gpioe.pe10, + gpioe.pe11, gpioe.pe12, gpioe.pe13, gpioe.pe14, + gpioe.pe15, gpiod.pd8, gpiod.pd9, gpiod.pd10, + gpioh.ph8, gpioh.ph9, gpioh.ph10, gpioh.ph11, + gpioh.ph12, gpioh.ph13, gpioh.ph14, gpioh.ph15, + gpioi.pi0, gpioi.pi1, gpioi.pi2, gpioi.pi3, + gpioi.pi6, gpioi.pi7, gpioi.pi9, gpioi.pi10, + // NBL0 - NBL3 + gpioe.pe0, gpioe.pe1, gpioi.pi4, gpioi.pi5, + gpioh.ph7, // SDCKE1 + gpiog.pg8, // SDCLK + gpiog.pg15, // SDNCAS + gpioh.ph6, // SDNE1 (!CS) + gpiof.pf11, // SDRAS + gpioh.ph5 // SDNWE + }; + + let fmc_ccdr = ccdr.peripheral.FMC.kernel_clk_mux(FMCSEL_A::Pll2R); + // TODO: incorrect for disco! + let sdram_chip = stm32_fmc::devices::is42s32800g_6::Is42s32800g {}; + let mut sdram = dp.FMC.sdram( + sdram_pins, + sdram_chip, + // ccdr.peripheral.FMC, + fmc_ccdr, + &ccdr.clocks, + ); + + let (fb1, fb2) = unsafe { + // Initialise controller and SDRAM + let ram_ptr: *mut u32 = sdram.init(&mut delay); + slice::from_raw_parts_mut(ram_ptr, sdram_size / mem::size_of::()) + .fill(0); + + let fb_size = WIDTH * HEIGHT; + let bank_size_words = 8 * 1024 * 1024 / 4; + let fb1 = slice::from_raw_parts_mut(ram_ptr, fb_size); + // Offset the second buffer into another SDRAM bank - this saves a bit of time if DMA2D is used + // to clear the fb while update is ongoing. + let fb2 = + slice::from_raw_parts_mut(ram_ptr.offset(bank_size_words), fb_size); + (fb1, fb2) + }; + + info!("Initialised SDRAM..."); + + // Initialise LCD... + // Display controller reset through dedicated IO + let mut display_reset = gpiog.pg3.into_push_pull_output(); + display_reset.set_low(); + delay.delay_ms(20u32); + display_reset.set_high(); + delay.delay_ms(10u32); + + // Display backlight enable + let mut display_backlight_en = gpioj.pj12.into_push_pull_output(); + display_backlight_en.set_high(); + + // Display controller TE (hw tear effect sync) pin as input + // let _display_te = gpioj.pj2.into_alternate::<13>(); + let _display_te = gpioj.pj2.into_input(); + // display_te.make_interrupt_source(&mut syscfg); + // display_te.trigger_on_edge(&mut exti, Edge::Rising); + // display_te.enable_interrupt(&mut exti); + + let mut ltdc = ltdc::Ltdc::new(dp.LTDC, ccdr.peripheral.LTDC, &ccdr.clocks); + ltdc.init(DISPLAY_CONFIGURATION); + + let layer = ltdc.split(); + let mut disp = BufferedDisplay::new(layer, fb1, fb2, WIDTH, HEIGHT); + + // Fin = 25MHz ->/idf = 5MHz ->*2 = 10MHz ->*ndiv = 1GHz ->/2 = 500MHz ->/odf = 500MHz (500Mbps per lane); pix clk (/8) = 62.5MHz + let dsi_pll_config = unsafe { DsiPllConfig::manual(100, 5, 0, 4) }; + + let dsi_config = DsiConfig { + mode: DsiMode::Video { + // mode: DsiVideoMode::NonBurstWithSyncEvents, + mode: DsiVideoMode::Burst, + }, + lane_count: LaneCount::DoubleLane, + channel: DsiChannel::Ch0, + hse_freq, + ltdc_freq, + interrupts: DsiInterrupts::None, + color_coding_host: ColorCoding::TwentyFourBits, + color_coding_wrapper: ColorCoding::TwentyFourBits, + lp_size: 4, // for OTM8009A + vlp_size: 4, + }; + let mut dsi_host = DsiHost::init( + dsi_pll_config, + DISPLAY_CONFIGURATION, + dsi_config, + dp.DSIHOST, + ccdr.peripheral.DSI, + &ccdr.clocks, + ) + .expect("DSI host failed to init"); + dsi_host.set_command_mode_transmission_kind( + DsiCmdModeTransmissionKind::AllInLowPower, + ); + + // Enable DSI host + dsi_host.start(); + dsi_host.enable_bus_turn_around(); // Must be before read attempts + + dsi_host.configure_phy_timers(DsiPhyTimers { + dataline_hs2lp: 35, + dataline_lp2hs: 35, + clock_hs2lp: 35, + clock_lp2hs: 35, + dataline_max_read_time: 0, + stop_wait_time: 10, + }); + + let otm8009a_config = Otm8009AConfig { + frame_rate: otm8009a::FrameRate::_70Hz, + // NOTE: In Landscape mode diagonal tearing line will be visible when fast changing content is present + mode: otm8009a::Mode::Portrait, + color_map: otm8009a::ColorMap::Rgb, + cols: WIDTH as u16, + rows: HEIGHT as u16, + }; + let mut glass_ctrl = Otm8009A::new(); + glass_ctrl + .init(&mut dsi_host, otm8009a_config, &mut delay) + .unwrap(); + glass_ctrl.enable_te_output(533, &mut dsi_host).unwrap(); + + // Not sure if this is needed + dsi_host.set_command_mode_transmission_kind( + DsiCmdModeTransmissionKind::AllInHighSpeed, + ); + dsi_host.force_rx_low_power(true); + + //let mut dsi_refresh_handle = dsi_host.refresh_handle(); + info!("Initialised Display..."); + + let scl = gpiod.pd12.into_alternate_open_drain(); + let sda = gpiod.pd13.into_alternate_open_drain(); + let i2c4 = + dp.I2C4 + .i2c((scl, sda), 100.kHz(), ccdr.peripheral.I2C4, &ccdr.clocks); + let mut touch_ctrl = FT6236::new(i2c4); + // let touch_int = gpiok.pk7 + + let mut x = 0; + let mut y = 0; + let mut frame = 0; + let style_green = PrimitiveStyleBuilder::new() + .fill_color(Rgb888::GREEN) + .build(); + let mut buf = [0u8; 64]; + + loop { + // Draw on a double buffered display + disp.layer(|draw| { + draw.clear(); + + Rectangle::new(Point::new(x, 0), Size::new(100, HEIGHT as u32)) + .into_styled(style_green) + .draw(draw) + .unwrap(); + + Rectangle::new(Point::new(0, y), Size::new(WIDTH as u32, 100)) + .into_styled(style_green) + .draw(draw) + .unwrap(); + + x += 5; + y += 5; + if x >= WIDTH as i32 { + x = 0; + } + if y >= HEIGHT as i32 { + y = 0; + } + + let mut buf = WriteTo::new(&mut buf); + write!(&mut buf, "f: {frame}").unwrap(); + frame += 1; + colored_label(buf.as_str().unwrap(), 50, 20, Rgb888::RED, draw).unwrap(); + + if let Ok(Some(pt)) = touch_ctrl.get_point0() { + info!("Touch: {} {}", pt.y, 480 - pt.x); + Circle::new(Point::new(480 - pt.x as i32 - 25, pt.y as i32 - 25), 50).into_styled(style_green).draw(draw).unwrap(); + } + + display_test(draw).unwrap(); + }); + disp.swap_layer_wait(); + } +} + +#[exception] +unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { + panic!("HardFault at {:#?}", ef); +} + +#[exception] +unsafe fn DefaultHandler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); +} \ No newline at end of file diff --git a/examples/embedded-graphics.rs b/examples/embedded-graphics.rs index 0ec5be04..7c37cf01 100644 --- a/examples/embedded-graphics.rs +++ b/examples/embedded-graphics.rs @@ -34,6 +34,7 @@ use embedded_graphics::text::Text; use numtoa::NumToA; use tinybmp::Bmp; +use crate::utilities::display_target::BufferedDisplay; const WIDTH: usize = 480; const HEIGHT: usize = 272; @@ -230,7 +231,7 @@ fn main() -> ! { }); let layer = ltdc.split(); - let mut disp = BufferedDisplay::new(layer, fb1, fb2); + let mut disp = BufferedDisplay::new(layer, fb1, fb2, WIDTH, HEIGHT); lcd_disp_en.set_low(); lcd_disp_ctrl.set_high(); @@ -281,132 +282,6 @@ fn main() -> ! { } } -/// A display with swappable framebuffers -pub struct BufferedDisplay<'a, LY> { - layer: LY, - front_buffer: &'a mut [u32], - back_buffer: &'a mut [u32], -} - -/// An individual display layer, borrowing from `BufferedDisplay` -pub struct DisplayBuffer<'a, 'p>( - /// Underlying buffer - pub &'p mut &'a mut [u32], -); - -impl<'a, LY> BufferedDisplay<'a, LY> -where - LY: embedded_display_controller::DisplayControllerLayer, -{ - pub fn new( - mut layer: LY, - front_buffer: &'a mut [u32], - back_buffer: &'a mut [u32], - ) -> Self { - // Safety: the frame buffer has the right size - unsafe { - layer.enable( - front_buffer.as_ptr() as *const u8, - embedded_display_controller::PixelFormat::ARGB8888, - ); - } - - BufferedDisplay { - layer, - front_buffer, - back_buffer, - } - } - - /// Swaps frame buffers - /// - /// # Safety - /// - /// Does not wait for the swap to actually occur, and hence layer accesses - /// after this may write to the wrong layer. For a safe version, use - /// swap_layer_wait - pub unsafe fn swap_layer(&mut self) { - // Have been filling back buffer - self.layer.swap_framebuffer(self.back_buffer.as_ptr()); - // Swap the back buffer to the front and visa versa - mem::swap(&mut self.back_buffer, &mut self.front_buffer); - } - - /// Swaps frame buffers then waits for the swap to occour on the next - /// vertical blanking period - pub fn swap_layer_wait(&mut self) { - // unsafe: we wait for the swap to occour, so current - // displayed buffer is protected - unsafe { self.swap_layer() }; - while self.layer.is_swap_pending() {} - } - - /// Access to layer via closure - pub fn layer(&mut self, func: F) -> T - where - F: FnOnce(&mut DisplayBuffer) -> T, - { - // Create a layer that lives until the end of this call - let mut layer = DisplayBuffer(&mut self.back_buffer); - func(&mut layer) - } -} - -use embedded_graphics::{ - geometry, - pixelcolor::raw::{RawData, RawU24}, - pixelcolor::Rgb888, - Pixel, -}; - -// Implement DrawTarget for -impl embedded_graphics::draw_target::DrawTarget for DisplayBuffer<'_, '_> { - type Color = Rgb888; - type Error = (); - - /// Draw a pixel - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - for pixel in pixels { - let Pixel(point, color) = pixel; - let raw: RawU24 = color.into(); - let rgb: u32 = 0xFF00_0000u32 | raw.into_inner(); - - if point.x >= 0 - && point.y >= 0 - && point.x < (WIDTH as i32) - && point.y < (HEIGHT as i32) - { - let index = (point.y * (WIDTH as i32)) + point.x; - self.0[index as usize] = rgb; - } else { - // Ignore invalid points - } - } - - Ok(()) - } -} -impl geometry::OriginDimensions for DisplayBuffer<'_, '_> { - /// Return the size of the display - fn size(&self) -> geometry::Size { - geometry::Size::new(HEIGHT as u32, WIDTH as u32) - } -} - -impl DisplayBuffer<'_, '_> { - /// Clears the buffer - pub fn clear(&mut self) { - let pixels = WIDTH * HEIGHT; - - for a in self.0[..pixels as usize].iter_mut() { - *a = 0xFF00_0000u32; // Solid black - } - } -} - #[exception] fn SysTick() { TIME.fetch_add(1, Ordering::Relaxed); diff --git a/examples/utilities/display_primitives.rs b/examples/utilities/display_primitives.rs new file mode 100644 index 00000000..6004ac8c --- /dev/null +++ b/examples/utilities/display_primitives.rs @@ -0,0 +1,166 @@ +#[cfg(feature = "chrono")] +use chrono::{Datelike, NaiveDateTime, Timelike}; +use embedded_graphics::image::Image; +use embedded_graphics::mono_font::{ascii, MonoTextStyle}; +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; +use embedded_graphics::text::Text; + +#[allow(dead_code)] +pub fn colored_label( + text: &str, + x: i32, + y: i32, + color: Rgb888, + target: &mut D, +) -> Result<(), D::Error> + where + D: DrawTarget, +{ + let style_red = PrimitiveStyleBuilder::new().fill_color(color).build(); + Rectangle::new( + Point::new(x, y), + Size::new((text.len() as u32) * 9 + 8, 22), + ) + .into_styled(style_red) + .draw(target)?; + + let text_style = + MonoTextStyle::new(&ascii::FONT_9X18_BOLD, RgbColor::WHITE); + Text::new(text, Point::new(x + 4, y + 18 - 2), text_style).draw(target)?; + Ok(()) +} + +#[allow(dead_code)] +pub fn display_test( + target: &mut D, +) -> Result<(), D::Error> + where + D: DrawTarget, +{ + let style_red = + PrimitiveStyleBuilder::new().fill_color(Rgb888::RED).build(); + let style_green = PrimitiveStyleBuilder::new() + .fill_color(Rgb888::GREEN) + .build(); + let style_blue = PrimitiveStyleBuilder::new() + .fill_color(Rgb888::BLUE) + .build(); + let style_cyan = PrimitiveStyleBuilder::new() + .fill_color(Rgb888::CYAN) + .build(); + + let size = target.bounding_box().size; + Rectangle::new(Point::new(0, 0), Size::new(10, 10)) + .into_styled(style_red) + .draw(target)?; + Rectangle::new(Point::new(size.width as i32 - 10, 0), Size::new(10, 10)) + .into_styled(style_green) + .draw(target)?; + Rectangle::new( + Point::new(0, size.height as i32 - 10), + Size::new(10, 10), + ) + .into_styled(style_blue) + .draw(target)?; + Rectangle::new( + Point::new(size.width as i32 - 10, size.height as i32 - 10), + Size::new(10, 10), + ) + .into_styled(style_cyan) + .draw(target)?; + + let ferris = tinybmp::Bmp::from_slice(include_bytes!("../ferris.bmp")).unwrap(); + let ferris = Image::new(&ferris, Point::new((size.width / 2 - ferris.size().width / 2) as i32, (size.height / 2 - ferris.size().height / 2) as i32)); + ferris.draw(target)?; + Ok(()) +} + +#[cfg(feature = "chrono")] +#[allow(dead_code)] +pub fn seven_segment_style(color: Rgb888) -> eg_seven_segment::SevenSegmentStyle { + eg_seven_segment::SevenSegmentStyleBuilder::new() + .digit_size(Size::new(36, 48)) // digits are 10x20 pixels + .digit_spacing(5) // 5px spacing between digits + .segment_width(5) + .segment_color(color) // active segments are green + .build() +} + +#[cfg(feature = "chrono")] +#[allow(dead_code)] +pub fn date_labels(y: i32, target: &mut D) -> Result<(), D::Error> + where + D: DrawTarget, +{ + let bg_color = Rgb888::RED; + colored_label("MONTH", 86, y, bg_color, target)?; + colored_label("DAY", 240, y, bg_color, target)?; + colored_label("YEAR", 398, y, bg_color, target)?; + colored_label("HOUR", 563, y, bg_color, target)?; + colored_label("MIN", 692, y, bg_color, target)?; + Ok(()) +} + +#[cfg(feature = "chrono")] +#[allow(dead_code)] +pub fn time_circuit(dt: NaiveDateTime, x: i32, y: i32, label: &str, fg: Rgb888, bg: Rgb888, target: &mut D) -> Result<(), D::Error> + where + D: DrawTarget, +{ + let fg_text_style = seven_segment_style(fg); + let bg_text_style = seven_segment_style(bg); + let all_segments = "888 88 8888 88 88"; + Text::new(all_segments, Point::new(x, y), bg_text_style) + .draw(target)?; + let month = match dt.date().month() { + 1 => "JAN", + 2 => "FEB", + 3 => "MAR", + 4 => "APR", + 5 => "MAY", + 6 => "JUN", + 7 => "JUL", + 8 => "AUG", + 9 => "SEP", + 10 => "OCT", + 11 => "NOU", + 12 => "DEC", + _ => unreachable!() + }; + let mut buf = [0u8; 17]; + use crate::utilities::write::write_to::WriteTo; + use core::fmt::Write; + let mut buf = WriteTo::new(&mut buf); + let (is_pm, hour) = dt.time().hour12(); + write!(&mut buf, "{} {:02} {:04} {:02} {:02}", month, dt.date().day(), dt.date().year(), hour, dt.time().minute()).unwrap(); + Text::new(buf.as_str().unwrap(), Point::new(x, y), fg_text_style) + .draw(target)?; + date_labels(y - 75, target)?; + colored_label( + label, + x + 363 - ((label.len() as i32) / 2) * 9, + y + 10, + Rgb888::CSS_DIM_GRAY, + target, + )?; + + let fg_style = PrimitiveStyleBuilder::new() + .fill_color(fg) + .build(); + let bg_style = PrimitiveStyleBuilder::new() + .fill_color(bg) + .build(); + colored_label("AM", 633, y - 65, Rgb888::RED, target)?; + let (am_style, pm_style) = if is_pm { + (bg_style, fg_style) + } else { + (fg_style, bg_style) + }; + use embedded_graphics::primitives::Circle; + Circle::new(Point::new(641, y - 40), 10).into_styled(am_style).draw(target)?; + colored_label("PM", 633, y - 26, Rgb888::RED, target)?; + Circle::new(Point::new(641, y), 10).into_styled(pm_style).draw(target)?; + Ok(()) +} diff --git a/examples/utilities/display_target.rs b/examples/utilities/display_target.rs new file mode 100644 index 00000000..3047bb20 --- /dev/null +++ b/examples/utilities/display_target.rs @@ -0,0 +1,139 @@ +use core::mem; + +/// A display with swappable framebuffers +pub struct BufferedDisplay<'a, LY> { + layer: LY, + front_buffer: &'a mut [u32], + back_buffer: &'a mut [u32], + width: i32, + height: i32, +} + +/// An individual display layer, borrowing from `BufferedDisplay` +pub struct DisplayBuffer<'a, 'p> { + /// Underlying buffer + pub buf: &'p mut &'a mut [u32], + pub width: i32, + pub height: i32, +} + +impl<'a, LY> BufferedDisplay<'a, LY> +where + LY: embedded_display_controller::DisplayControllerLayer, +{ + pub fn new( + mut layer: LY, + front_buffer: &'a mut [u32], + back_buffer: &'a mut [u32], + width: usize, + height: usize, + ) -> Self { + // Safety: the frame buffer has the right size + unsafe { + layer.enable( + front_buffer.as_ptr() as *const u8, + embedded_display_controller::PixelFormat::ARGB8888, + ); + } + + BufferedDisplay { + layer, + front_buffer, + back_buffer, + width: width as i32, + height: height as i32, + } + } + + /// Swaps frame buffers + /// + /// # Safety + /// + /// Does not wait for the swap to actually occur, and hence layer accesses + /// after this may write to the wrong layer. For a safe version, use + /// swap_layer_wait + pub unsafe fn swap_layer(&mut self) { + // Have been filling back buffer + self.layer.swap_framebuffer(self.back_buffer.as_ptr()); + // Swap the back buffer to the front and visa versa + mem::swap(&mut self.back_buffer, &mut self.front_buffer); + } + + /// Swaps frame buffers then waits for the swap to occour on the next + /// vertical blanking period + pub fn swap_layer_wait(&mut self) { + // unsafe: we wait for the swap to occour, so current + // displayed buffer is protected + unsafe { self.swap_layer() }; + while self.layer.is_swap_pending() {} + } + + /// Access to layer via closure + pub fn layer(&mut self, func: F) -> T + where + F: FnOnce(&mut DisplayBuffer) -> T, + { + // Create a layer that lives until the end of this call + let mut layer = DisplayBuffer { + buf: &mut self.back_buffer, + width: self.width, + height: self.height, + }; + func(&mut layer) + } +} + +use embedded_graphics::{ + geometry, + pixelcolor::raw::{RawData, RawU24}, + pixelcolor::Rgb888, + Pixel, +}; + +// Implement DrawTarget for +impl embedded_graphics::draw_target::DrawTarget for DisplayBuffer<'_, '_> { + type Color = Rgb888; + type Error = (); + + /// Draw a pixel + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + for pixel in pixels { + let Pixel(point, color) = pixel; + let raw: RawU24 = color.into(); + let rgb: u32 = 0xFF00_0000u32 | raw.into_inner(); + + if point.x >= 0 + && point.y >= 0 + && point.x < self.width + && point.y < self.height + { + let index = point.y * self.width + point.x; + self.buf[index as usize] = rgb; + } else { + // Ignore invalid points + } + } + + Ok(()) + } +} +impl geometry::OriginDimensions for DisplayBuffer<'_, '_> { + /// Return the size of the display + fn size(&self) -> geometry::Size { + geometry::Size::new(self.width as u32, self.height as u32) + } +} + +impl DisplayBuffer<'_, '_> { + /// Clears the buffer + pub fn clear(&mut self) { + let pixels = self.width * self.height; + + for a in self.buf[..pixels as usize].iter_mut() { + *a = 0xFF00_0000u32; // Solid black + } + } +} diff --git a/examples/utilities/logger.rs b/examples/utilities/logger.rs index 400a9b3f..650dce7c 100644 --- a/examples/utilities/logger.rs +++ b/examples/utilities/logger.rs @@ -43,12 +43,12 @@ cfg_if::cfg_if! { } static LOGGER: Logger = Logger { - level: Level::Info, + level: Level::Debug, }; pub fn init() { rtt_init_print!(); - log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Info)).unwrap(); + log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Debug)).unwrap(); } impl log::Log for Logger { diff --git a/examples/utilities/mod.rs b/examples/utilities/mod.rs index 39e92a33..87f09dbf 100644 --- a/examples/utilities/mod.rs +++ b/examples/utilities/mod.rs @@ -3,3 +3,13 @@ pub mod logger; #[macro_use] mod power; + +#[cfg(feature = "fmc")] +pub mod mpu_config; + +#[cfg(feature = "ltdc")] +pub mod display_target; +#[cfg(feature = "ltdc")] +pub mod write; +#[cfg(feature = "ltdc")] +pub mod display_primitives; \ No newline at end of file diff --git a/examples/utilities/mpu_config.rs b/examples/utilities/mpu_config.rs new file mode 100644 index 00000000..b91afa60 --- /dev/null +++ b/examples/utilities/mpu_config.rs @@ -0,0 +1,77 @@ +use cortex_m::peripheral::{MPU, SCB}; + +pub fn init_mpu(mpu: MPU, scb: &mut SCB, sdram_size: usize) { + // Refer to ARM®v7-M Architecture Reference Manual ARM DDI 0403 + // Version E.b Section B3.5 + const MEMFAULTENA: u32 = 1 << 16; + + unsafe { + /* Make sure outstanding transfers are done */ + cortex_m::asm::dmb(); + + scb.shcsr.modify(|r| r & !MEMFAULTENA); + + /* Disable the MPU and clear the control register*/ + mpu.ctrl.write(0); + } + + const REGION_NUMBER0: u32 = 0x00; + const REGION_BASE_ADDRESS: u32 = 0xD000_0000; + + const REGION_FULL_ACCESS: u32 = 0x03; + const REGION_CACHEABLE: u32 = 0x01; + const REGION_WRITE_BACK: u32 = 0x01; + const REGION_ENABLE: u32 = 0x01; + + assert_eq!( + sdram_size & (sdram_size - 1), + 0, + "SDRAM memory region size must be a power of 2" + ); + assert_eq!( + sdram_size & 0x1F, + 0, + "SDRAM memory region size must be 32 bytes or more" + ); + fn log2minus1(sz: u32) -> u32 { + for i in 5..=31 { + if sz == (1 << i) { + return i - 1; + } + } + panic!("Unknown SDRAM memory region size!"); + } + + //info!("SDRAM Memory Size 0x{:x}", log2minus1(size as u32)); + + // Configure region 0 + // + // Cacheable, outer and inner write-back, no write allocate. So + // reads are cached, but writes always write all the way to SDRAM + unsafe { + mpu.rnr.write(REGION_NUMBER0); + mpu.rbar.write(REGION_BASE_ADDRESS); + mpu.rasr.write( + (REGION_FULL_ACCESS << 24) + | (REGION_CACHEABLE << 17) + | (REGION_WRITE_BACK << 16) + | (log2minus1(sdram_size as u32) << 1) + | REGION_ENABLE, + ); + } + + const MPU_ENABLE: u32 = 0x01; + const MPU_DEFAULT_MMAP_FOR_PRIVILEGED: u32 = 0x04; + + // Enable + unsafe { + mpu.ctrl + .modify(|r| r | MPU_DEFAULT_MMAP_FOR_PRIVILEGED | MPU_ENABLE); + + scb.shcsr.modify(|r| r | MEMFAULTENA); + + // Ensure MPU settings take effect + cortex_m::asm::dsb(); + cortex_m::asm::isb(); + } +} \ No newline at end of file diff --git a/examples/utilities/write.rs b/examples/utilities/write.rs new file mode 100644 index 00000000..7eabc933 --- /dev/null +++ b/examples/utilities/write.rs @@ -0,0 +1,54 @@ +pub mod write_to { + use core::cmp::min; + use core::fmt; + + pub struct WriteTo<'a> { + buffer: &'a mut [u8], + // on write error (i.e. not enough space in buffer) this grows beyond + // `buffer.len()`. + used: usize, + } + + impl<'a> WriteTo<'a> { + #[allow(dead_code)] + pub fn new(buffer: &'a mut [u8]) -> Self { + WriteTo { buffer, used: 0 } + } + + #[allow(dead_code)] + pub fn as_str(self) -> Option<&'a str> { + if self.used <= self.buffer.len() { + // only successful concats of str - must be a valid str. + use core::str::from_utf8_unchecked; + Some(unsafe { from_utf8_unchecked(&self.buffer[..self.used]) }) + } else { + None + } + } + } + + impl<'a> fmt::Write for WriteTo<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + if self.used > self.buffer.len() { + return Err(fmt::Error); + } + let remaining_buf = &mut self.buffer[self.used..]; + let raw_s = s.as_bytes(); + let write_num = min(raw_s.len(), remaining_buf.len()); + remaining_buf[..write_num].copy_from_slice(&raw_s[..write_num]); + self.used += raw_s.len(); + if write_num < raw_s.len() { + Err(fmt::Error) + } else { + Ok(()) + } + } + } + + #[allow(dead_code)] + pub fn show<'a>(buffer: &'a mut [u8], args: fmt::Arguments) -> Result<&'a str, fmt::Error> { + let mut w = WriteTo::new(buffer); + fmt::write(&mut w, args)?; + w.as_str().ok_or(fmt::Error) + } +} \ No newline at end of file diff --git a/src/delay.rs b/src/delay.rs index 42f5b13a..d3bd2087 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -49,7 +49,7 @@ use void::Void; use crate::nb::block; use crate::rcc::CoreClocks; -use crate::time::Hertz; +use crate::time::{Hertz, MicroSeconds}; use fugit::RateExtU32; pub trait DelayExt { diff --git a/src/dsi.rs b/src/dsi.rs new file mode 100644 index 00000000..1a60fc76 --- /dev/null +++ b/src/dsi.rs @@ -0,0 +1,707 @@ +use crate::rcc::CoreClocks; +use crate::{ + device::DSIHOST, + rcc::{rec, ResetEnable}, + time::Hertz, +}; +use core::cmp::{max, min}; +use embedded_display_controller::DisplayConfiguration; +use embedded_dsi::{DsiHostCtrlIo, DsiReadCommand, DsiWriteCommand}; +#[cfg(feature = "log")] +use log::debug; + +const DSI_TIMEOUT_MS: usize = 100; + +pub struct DsiHost { + dsi: DSIHOST, + channel: DsiChannel, + cycles_1ms: u32, +} + +#[derive(Copy, Clone)] +pub enum DsiChannel { + Ch0 = 0b00, + Ch1 = 0b01, + Ch2 = 0b10, + Ch3 = 0b11, +} + +#[derive(Debug)] +pub enum Error { + RegTimeout, + PllTimeout, + BufferIsToBig, + WriteTimeout, + ReadTimeout, + ReadError, + FifoTimeout, + WrongId, +} + +pub enum DsiMode { + Video { mode: DsiVideoMode }, + AdaptedCommand { tear_effect: Option }, +} + +pub enum DsiVideoMode { + NonBurstWithSyncPulses = 0b00, + NonBurstWithSyncEvents = 0b01, + Burst = 0b10, +} + +pub struct TearEffectMode { + pub source: TearEffectSource, + pub auto_refresh: bool, +} + +#[derive(PartialEq, Eq)] +pub enum TearEffectSource { + DsiLink, + ExternalPin, +} + +pub enum DsiInterrupts { + None, + All, +} + +pub enum DsiCmdModeTransmissionKind { + AllInHighSpeed, + AllInLowPower, +} + +pub struct DsiPhyTimers { + pub dataline_hs2lp: u8, + pub dataline_lp2hs: u8, + pub clock_hs2lp: u16, + pub clock_lp2hs: u16, + pub dataline_max_read_time: u16, + pub stop_wait_time: u8, +} + +pub struct DsiRefreshHandle { + dsi: DSIHOST, + // refresh_request: *mut bool, +} +// unsafe impl Send for DsiRefreshHandle {} + +pub enum LaneCount { + SingleLane = 0b00, + DoubleLane = 0b01, +} + +pub struct DsiPllConfig { + ndiv: u8, + idf: u8, + odf: u8, + eckdiv: u8, +} + +impl DsiPllConfig { + pub unsafe fn manual(ndiv: u8, idf: u8, odf: u8, eckdiv: u8) -> Self { + DsiPllConfig { + ndiv, + idf, + odf, + eckdiv, + } + } +} + +#[repr(u8)] +pub enum ColorCoding { + SixteenBitsConfig1 = 0b000, + SixteenBitsConfig2 = 0b001, + SixteenBitsConfig3 = 0b010, + EighteenBitsConfig1 = 0b011, + EighteenBitsConfig2 = 0b100, + TwentyFourBits = 0b101 +} + +pub struct DsiConfig { + pub mode: DsiMode, + pub lane_count: LaneCount, + pub channel: DsiChannel, + pub hse_freq: Hertz, + pub ltdc_freq: Hertz, + pub interrupts: DsiInterrupts, + pub color_coding_host: ColorCoding, + pub color_coding_wrapper: ColorCoding, + pub lp_size: u8, + pub vlp_size: u8, +} + +impl DsiHost { + pub fn init( + pll_config: DsiPllConfig, + display_config: DisplayConfiguration, + dsi_config: DsiConfig, + dsi: DSIHOST, + dsi_rec: rec::Dsi, + clocks: &CoreClocks, + ) -> Result { + // Enable and reset DSI peripheral + dsi_rec.enable().reset(); + //RCC_D1CCIPR: DSI clock from PHY is selected as DSI byte lane clock (default after reset) + let cycles_1ms = clocks.sysclk().raw() / 1_000; + + // Enable regulator + dsi.wrpcr.modify(|_, w| w.regen().set_bit()); + // Wait for it to be ready + block_with_timeout( + || dsi.wisr.read().rrs() == false, + DSI_TIMEOUT_MS, + cycles_1ms, + Error::RegTimeout, + )?; + + // Set PLL division factors + // Fin = 25MHz ->/idf = 5MHz ->*2 = 10MHz ->*ndiv = 1GHz ->/2 = 500MHz ->/odf = 500MHz ->/8 = 62.5MHz + // let ndiv = 125; + // let ndiv = 102; + // let idf = 5; + // let odf = 0b00; + dsi.wrpcr.modify(|_, w| unsafe { + w.ndiv() + .bits(pll_config.ndiv) // allowed: 10 ..= 125 + .idf() + .bits(pll_config.idf) // div1: 0b000, 0b001, div2: 0b010, div3: 0b011 ..= div7 + .odf() + .bits(pll_config.odf) // div1: 0b00, div2: 0b01, div4: 0b10, div8: 0b11 + }); + // Enable PLL + dsi.wrpcr.modify(|_, w| w.pllen().set_bit()); + // Required to wait 400us before checking PLLLS flag + cortex_m::asm::delay(cycles_1ms / 2); + // Wait for the lock + block_with_timeout( + || dsi.wisr.read().pllls() == false, + DSI_TIMEOUT_MS, + cycles_1ms, + Error::PllTimeout, + )?; + + // Clock and digital section enable + dsi.pctlr.modify(|_, w| w.cke().set_bit().den().set_bit()); + + // Clock lane config + dsi.clcr.modify( + |_, w| { + w.dpcc() + .set_bit() // 1: lanes are running in high speed mode + .acr() + .clear_bit() + }, // Automatically stop lanes clock when "time allows" + ); + + // Configure the number of active data lanes + dsi.pconfr + .modify(|_, w| unsafe { w.nl().bits(dsi_config.lane_count as u8) }); // 0b00 - 1 lanes, 0b01 - 2 lanes + + // Set TX escape clock division factor + dsi.ccr + .modify(|_, w| unsafe { w.txeckdiv().bits(pll_config.eckdiv) }); + + // Set the bit period in high speed mode + // Calculate the bit period in high-speed mode in unit of 0.25 ns (UIX4) + // The equation is : UIX4 = IntegerPart( (1000/F_PHY_Mhz) * 4 ) + // Where : F_PHY_Mhz = (NDIV * HSE_Mhz) / (IDF * ODF) + let odf = match pll_config.odf { + 0b00 => 1, + 0b01 => 2, + 0b10 => 4, + 0b11 => 8, + _ => unreachable!(), + }; + let f_phy_hz = ((pll_config.ndiv as u32) * dsi_config.hse_freq.raw()) + / u32::from(pll_config.idf) + / odf; + let f_pix_khz = f_phy_hz / 1_000 / 8; + let uix4 = 4_000_000_000 / f_phy_hz; + #[cfg(feature = "log")] + debug!("f_phy={}kHz, f_pix={}kHz, uix4={}", f_phy_hz / 1_000, f_pix_khz, uix4); + dsi.wpcr0 + .modify(|_, w| unsafe { w.uix4().bits(uix4 as u8) }); + // debug!("f_phy={}, uix4=override=8", f_phy); + // dsi.wpcr0.modify(|_, w| unsafe { w.uix4().bits(8) }); + + match dsi_config.interrupts { + DsiInterrupts::None => { + // Disable all error interrupts for now and reset the error mask + dsi.ier0.write(|w| unsafe { w.bits(0) }); + dsi.ier1.write(|w| unsafe { w.bits(0) }); + } + DsiInterrupts::All => { + // Enable all error interrupts + dsi.ier0.write(|w| unsafe { + w.bits(0b00000000_00011111_11111111_11111111) + }); + dsi.ier1.write(|w| unsafe { w.bits(0b00011111_11111111) }); + + // Enable wrapper interrupts + dsi.wier.write(|w| w.teie().set_bit().erie().set_bit()); + } + } + + match dsi_config.mode { + DsiMode::Video { mode } => { + // Select video mode + dsi.mcr.modify(|_, w| w.cmdm().clear_bit()); // 0 - video mode, 1 - command mode + dsi.wcfgr.modify(|_, w| { + w + // 0 - video mode, 1 - adapted command mode + .dsim() + .clear_bit() + // 0 - DSI Link, 1 - External pin + .tesrc() + .clear_bit() + // 0 - Rising edge, 1 - Falling edge + .tepol() + .clear_bit() + // Refresh mode in DBI mode, 0 - disabled, 1 - automatic refresh enabled + .ar() + .clear_bit() + }); + + // Video mode transmission type, p. 1346 + dsi.vmcr.modify(|_, w| unsafe { + w.vmt() + .bits(mode as u8) // 0b00 - non-burst with sync pulses, 0b01 - non-burst with sync event, 0b1x - burst mode + .lpvsae() + .set_bit() // Enable LP transition in vertical sync period + .lpvbpe() + .set_bit() // Enable LP transition in VBP period + .lpvfpe() + .set_bit() // Enable LP transition in VFP period + .lpvae() + .set_bit() // Enable LP transition in VACT period + .lphbpe() + .set_bit() // Enable LP transition in HBP period + .lphfpe() + .set_bit() // Enable LP transition in HFP period + .lpce() + .set_bit() // 1 = Command transmission in low power mode enabled + .fbtaae() + .clear_bit() // Disable the request for an acknowledge response at the end of a frame + }); + + // Packet size, 14 bits max + // TODO: Might be incorrect for 16 or 18bit + dsi.vpcr.modify(|_, w| unsafe { + w.vpsize().bits(display_config.active_width) + }); + + // TODO: Unhardcode? + // This register configures the number of chunks to be transmitted during a line period (a chunk + // consists of a video packet and a null packet). + // If set to 0 or 1, the video line is transmitted in a single packet. + // If set to 1, the packet is part of a chunk, so a null packet follows it if NPSIZE > 0. Otherwise, + // multiple chunks are used to transmit each video line. + dsi.vccr.modify(|_, w| unsafe { w.numc().bits(1) }); + + // Size of the null packet + dsi.vnpcr.modify(|_, w| unsafe { w.npsize().bits(0) }); + + // Horizontal sync active (HSA) in lane byte clock cycles + let f_ltdc_khz = dsi_config.ltdc_freq.to_kHz(); + let hsa = ((display_config.h_sync as u32) * f_pix_khz / f_ltdc_khz) as u16; + #[cfg(feature = "log")] + debug!("hsa={}", hsa); + dsi.vhsacr.modify(|_, w| unsafe { w.hsa().bits(hsa) }); + + // Horizontal back porch (HBP) in lane byte clock cycles + let hbp = ((display_config.h_back_porch as u32) * f_pix_khz / f_ltdc_khz) as u16; + #[cfg(feature = "log")] + debug!("hbp={}", hbp); + dsi.vhbpcr.modify(|_, w| unsafe { w.hbp().bits(hbp) }); + + // Total line time, HLINE = HSA + HBP + HACT + HFP + let hline = display_config.h_sync + + display_config.h_back_porch + + display_config.active_width + + display_config.h_front_porch; + let hline = ((hline as u32) * f_pix_khz / f_ltdc_khz) as u16; + // let hsync = f_phy * 3 * hline as u32 / 8; + #[cfg(feature = "log")] + debug!("hline={}", hline); + dsi.vlcr.modify(|_, w| unsafe { w.hline().bits(hline) }); + + // Vertical sync active (VSA) + dsi.vvsacr.modify(|_, w| unsafe { + w.vsa().bits(display_config.v_sync) + }); + + // Vertical back porch (VBP) + dsi.vvbpcr.modify(|_, w| unsafe { + w.vbp().bits(display_config.v_back_porch) + }); + + // Vertical front porch (VFP) + dsi.vvfpcr.modify(|_, w| unsafe { + w.vfp().bits(display_config.v_front_porch) + }); + + // Vertical active period + dsi.vvacr.modify(|_, w| unsafe { + w.va().bits(display_config.active_height) + }); + } + DsiMode::AdaptedCommand { tear_effect } => { + // Select command mode + dsi.mcr.modify(|_, w| w.cmdm().set_bit()); // 0 - video mode, 1 - command mode + let (is_external_pin, auto_refresh) = match tear_effect { + Some(te) => ( + te.source == TearEffectSource::ExternalPin, + te.auto_refresh, + ), + None => (false, false), + }; + dsi.wcfgr.modify(|_, w| { + w + // 0 - video mode, 1 - adapted command mode + .dsim() + .set_bit() + // 0 - DSI Link, 1 - External pin + .tesrc() + .bit(is_external_pin) + // 0 - Rising edge, 1 - Falling edge + .tepol() + .clear_bit() + // Refresh mode in DBI mode, 0 - disabled, 1 - automatic refresh enabled + .ar() + .bit(auto_refresh) + // VSync polarity, 0 - LTDC halted on falling edge, 1 - LTDC halted on rising edge + .vspol() + .clear_bit() + }); + + // Maximum allowed size for memory write command + dsi.lccr.modify(|_, w| unsafe { + w.cmdsize().bits(display_config.active_width) + }); + + // Tearing effect acknowledge request + dsi.cmcr.modify(|_, w| w.teare().set_bit()) + } + } + + // Select virtual channel for the LTDC interface traffic + dsi.lvcidr + .modify(|_, w| unsafe { w.vcid().bits(dsi_config.channel as u8) }); + + // Polarity + dsi.lpcr.modify(|_, w| { + w.dep().clear_bit().vsp().clear_bit().hsp().clear_bit() + }); + + // Color coding for the host + let lpe = match dsi_config.color_coding_host { + ColorCoding::EighteenBitsConfig1 => true, + ColorCoding::EighteenBitsConfig2 => true, + _ => false + }; + dsi.lcolcr.modify(|_, w| unsafe { + w.lpe() + .bit(lpe) // loosely packed: 18bits + .colc() + .bits(dsi_config.color_coding_host as u8) // 0: 16bit_1, 1: 16bit_2, 2: 16bit_3, 3: 18bit_1, 4: 18bit_2, 5: 24bit + }); + + // Color coding for the wrapper + dsi.wcfgr.modify(|_, w| unsafe { w.colmux().bits(dsi_config.color_coding_wrapper as u8) }); + + dsi.lpmcr.modify(|_, w| unsafe { + w.lpsize() + .bits(dsi_config.lp_size) // Low power largest packet size + .vlpsize() + .bits(dsi_config.vlp_size) // Low power VACT largest packet size + }); + + Ok(DsiHost { + dsi, + channel: dsi_config.channel, + cycles_1ms, + }) + } + + pub fn set_command_mode_transmission_kind( + &mut self, + kind: DsiCmdModeTransmissionKind, + ) { + let is_low_power = match kind { + DsiCmdModeTransmissionKind::AllInHighSpeed => false, + DsiCmdModeTransmissionKind::AllInLowPower => true, + }; + self.dsi.cmcr.modify(|_, w| { + w.gsw0tx() + .bit(is_low_power) + .gsw1tx() + .bit(is_low_power) + .gsw2tx() + .bit(is_low_power) + .gsr0tx() + .bit(is_low_power) + .gsr1tx() + .bit(is_low_power) + .gsr2tx() + .bit(is_low_power) + .glwtx() + .bit(is_low_power) + .dsw0tx() + .bit(is_low_power) + .dsw1tx() + .bit(is_low_power) + .dsr0tx() + .bit(is_low_power) + .dlwtx() + .bit(is_low_power) + .mrdps() + .bit(is_low_power) + }); + self.dsi.cmcr.modify(|_, w| w.are().clear_bit()); // FIXME: might be incorrect + } + + pub fn configure_phy_timers(&mut self, phy_timers: DsiPhyTimers) { + let max_time = max(phy_timers.clock_lp2hs, phy_timers.clock_hs2lp); + self.dsi.cltcr.modify(|_, w| unsafe { + w.hs2lp_time().bits(max_time).lp2hs_time().bits(max_time) + }); + self.dsi.dltcr.modify(|_, w| unsafe { + w.mrd_time() + .bits(phy_timers.dataline_max_read_time) + .hs2lp_time() + .bits(phy_timers.dataline_hs2lp) + .lp2hs_time() + .bits(phy_timers.dataline_lp2hs) + }); + self.dsi.pconfr.modify(|_, w| unsafe { + w.sw_time().bits(phy_timers.stop_wait_time) + }); + } + + pub fn force_rx_low_power(&mut self, force: bool) { + self.dsi.wpcr1.modify(|_, w| w.flprxlpm().bit(force)); + } + + fn long_write( + &mut self, + cmd: u8, + buf: &[u8], + ghcr_dt: u8, + ) -> Result<(), Error> { + // debug!("{}, long {dcs_cmd:02x}, {buf:02x?}", self.write_idx); + // self.write_idx += 1; + + if buf.len() >= 65_535 { + // TODO: is it correct length? + return Err(Error::BufferIsToBig); + } + + // Put dcs_command and up to 3 bytes of data to GPDR + let mut fifoword = u32::from(cmd); + for (i, byte) in buf.iter().take(3).enumerate() { + fifoword |= (*byte as u32) << (8 + 8 * i); + } + self.dsi.gpdr.write(|w| unsafe { w.bits(fifoword) }); + //debug!("gpdr = {fifoword:08x}"); + + // Put the rest of the data, assuming that GPDR is accumulated in the hardware in some buffer. + if buf.len() > 3 { + let mut iter = buf[3..].chunks_exact(4); + for chunk in &mut iter { + let fifoword: [u8; 4] = chunk.try_into().unwrap(); + let fifoword = u32::from_ne_bytes(fifoword); //.swap_bytes(); + self.dsi.gpdr.write(|w| unsafe { w.bits(fifoword) }); + //debug!("gpdr = {fifoword:08x}"); + } + if !iter.remainder().is_empty() { + let mut fifoword = 0u32; + for (i, byte) in iter.remainder().iter().enumerate() { + fifoword |= (*byte as u32) << (8 * i); + } + self.dsi.gpdr.write(|w| unsafe { w.bits(fifoword) }); + //debug!("gpdr = {fifoword:08x}"); + } + } + + let len = buf.len() + 1; // dcs_cmd + actual data + self.ghcr_write(((len >> 8) & 0xff) as u8, (len & 0xff) as u8, ghcr_dt); + + Ok(()) + } + + fn ghcr_write(&mut self, msb: u8, lsb: u8, dt: u8) { + self.dsi.ghcr.write(|w| unsafe { + w // GHCR p. 1354 + .wcmsb() + .bits(msb) + .wclsb() + .bits(lsb) + .vcid() + .bits(self.channel as u8) + .dt() + .bits(dt) + }); + } + + pub fn start(&mut self) { + self.dsi.cr.modify(|_, w| w.en().set_bit()); + self.dsi.wcr.modify(|_, w| w.dsien().set_bit()); + } + + pub fn refresh(&mut self) { + self.dsi.wcr.modify(|_, w| w.ltdcen().set_bit()); + } + + pub fn refresh_handle(&self) -> DsiRefreshHandle { + let dsi = unsafe { crate::pac::Peripherals::steal().DSIHOST }; + DsiRefreshHandle { dsi } + } + + pub fn enable_bus_turn_around(&mut self) { + self.dsi.pcr.modify(|_, w| w.btae().set_bit()); // Enable bus turn around + } +} + +impl DsiRefreshHandle { + pub fn refresh_now(&mut self) { + self.dsi.wcr.modify(|_, w| w.ltdcen().set_bit()); + } + + // pub fn refresh_when_te_happens(&mut self) { + // cortex_m::interrupt::free(|_| unsafe { + // *self.refresh_request = true; + // }) + // } +} + +impl DsiHostCtrlIo for DsiHost { + type Error = Error; + + fn write(&mut self, kind: DsiWriteCommand) -> Result<(), Error> { + // debug!("DSI write: {:x?}", kind); + // wait for command fifo to be empty + block_with_timeout( + || self.dsi.gpsr.read().cmdfe() == false, + DSI_TIMEOUT_MS, + self.cycles_1ms, + Error::FifoTimeout, + )?; + match kind { + DsiWriteCommand::DcsShortP0 { .. } => todo!(), + DsiWriteCommand::DcsShortP1 { reg, data } => { + // debug!("{}, short_p1: reg: {reg:02x}, data: {data:02x}", self.write_idx); + // self.write_idx += 1; + self.ghcr_write(data, reg, kind.discriminant()); + } + DsiWriteCommand::DcsLongWrite { dcs_cmd, buf } => { + self.long_write(dcs_cmd, buf, kind.discriminant())? + } + DsiWriteCommand::GenericShortP0 => todo!(), + DsiWriteCommand::GenericShortP1 => todo!(), + DsiWriteCommand::GenericShortP2 => todo!(), + DsiWriteCommand::GenericLongWrite { cmd, buf } => { + self.long_write(cmd, buf, kind.discriminant())? + } + DsiWriteCommand::SetMaximumReturnPacketSize(len) => { + self.ghcr_write( + ((len >> 8) & 0xff) as u8, + (len & 0xff) as u8, + kind.discriminant(), + ); + } + } + Ok(()) + } + + fn read( + &mut self, + kind: DsiReadCommand, + buf: &mut [u8], + ) -> Result<(), Error> { + // println!("DSI read: {:x?}", kind); + if buf.len() > 2 && buf.len() <= 65_535 { + self.write(DsiWriteCommand::SetMaximumReturnPacketSize( + buf.len() as u16 + ))?; + } else if buf.len() > 65_535 { + return Err(Error::BufferIsToBig); + } + + match kind { + DsiReadCommand::DcsShort { dcs_cmd } => { + self.ghcr_write(0, dcs_cmd, kind.discriminant()); + } + DsiReadCommand::GenericShortP0 => { + self.ghcr_write(0, 0, kind.discriminant()); + } + DsiReadCommand::GenericShortP1 { arg0 } => { + self.ghcr_write(0, arg0, kind.discriminant()); + } + DsiReadCommand::GenericShortP2 { arg0, arg1 } => { + self.ghcr_write(arg1, arg0, kind.discriminant()); + } + } + + let mut idx = 0; + let mut bytes_left = buf.len(); + block_with_timeout( + || { + if bytes_left > 0 { + if self.dsi.gpsr.read().prdfe().bit_is_clear() { + // GPSR: p. 1355 + let fifoword = self.dsi.gpdr.read().bits(); + //debug!("fifoword read: {fifoword:08x}"); + for b in fifoword + // .swap_bytes() + .to_ne_bytes() + .iter() + .take(min(bytes_left, 4)) + { + buf[idx] = *b; + bytes_left -= 1; + idx += 1; + } + } + // Software workaround to avoid HAL_TIMEOUT when a DSI read command is + // issued to the panel and the read data is not captured by the DSI Host + // which returns Packet Size Error. + // Need to ensure that the Read command has finished before checking PSE + if self.dsi.gpsr.read().rcb().bit_is_clear() + && self.dsi.isr1.read().pse().bit_is_set() + { + return false; + } + true + } else { + false + } + }, + DSI_TIMEOUT_MS, + self.cycles_1ms, + Error::ReadTimeout, + ) + .map_err(|_| Error::ReadTimeout)?; + if bytes_left > 0 { + return Err(Error::ReadError); + } + Ok(()) + } +} + +fn block_with_timeout bool>( + mut f: F, + retries: usize, + delay_cycles: u32, + err: Error, +) -> Result<(), Error> { + for _ in 0..retries { + if f() { + cortex_m::asm::delay(delay_cycles); + } else { + return Ok(()); + } + } + //debug!("{name} {}", self.tim.counter()); + Err(err) +} diff --git a/src/lib.rs b/src/lib.rs index 054a7f65..c45297d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -217,6 +217,8 @@ pub mod usb_hs; #[cfg(all(feature = "device-selected", feature = "xspi"))] #[cfg_attr(docsrs, doc(cfg(feature = "xspi")))] pub mod xspi; +#[cfg(feature="dsi")] +pub mod dsi; #[cfg(feature = "device-selected")] mod sealed { From 2dfc9192c0c05d589f7b374511fea31a74035295 Mon Sep 17 00:00:00 2001 From: Roman Isaikin Date: Fri, 1 Dec 2023 12:02:15 +0100 Subject: [PATCH 53/75] Update dependencies to git links. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af5c61a1..bb2b6d14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ embedded-display-controller = { version = "^0.1.0", optional = true } log = { version = "0.4.14", optional = true} # see also the dev-dependencies section fdcan = { version = "0.2", optional = true } embedded-storage = "0.3" -embedded-dsi = { path = "../embedded-hal/embedded-dsi", optional = true } +embedded-dsi = { git = "https://github.com/romixlab/embedded-hal.git", branch = "dsi", optional = true } [dependencies.smoltcp] version = "0.10.0" @@ -82,7 +82,7 @@ usbd-serial = "0.2.0" numtoa = "0.2.3" tinybmp = "0.5" embedded-graphics = "0.8" -otm8009a = { path = "../otm8009a" } +otm8009a = { git = "https://github.com/romixlab/otm8009a.git" } eg-seven-segment = "0.2.0" ft6236 = { git = "https://github.com/romixlab/ft6236.git" } From d33298a5d3f5ac791b51f6efb30d33195a56c159 Mon Sep 17 00:00:00 2001 From: Youndong Park Date: Thu, 18 Jan 2024 09:40:43 +0900 Subject: [PATCH 54/75] This is an example of controlling LEDs using GPIOs on STM32H747i-Disco. Changes to be committed: modified: Cargo.toml new file: examples/blinky-stm32h747i-disco.rs by Youndong (youndong.park@gmail.com) --- Cargo.toml | 4 ++ examples/blinky-stm32h747i-disco.rs | 66 +++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 examples/blinky-stm32h747i-disco.rs diff --git a/Cargo.toml b/Cargo.toml index b3aef94c..62abb1f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -151,6 +151,10 @@ opt-level = "s" # optimize for binary size # `required-features` field specifies the hal features and/or the hardware # configuration required by the example. +[[example]] +name = "blinky-stm32h747i-disco" +required-features = ["rt", "stm32h747cm7"] + [[example]] name = "can-echo" required-features = ["can"] diff --git a/examples/blinky-stm32h747i-disco.rs b/examples/blinky-stm32h747i-disco.rs new file mode 100644 index 00000000..78dd71be --- /dev/null +++ b/examples/blinky-stm32h747i-disco.rs @@ -0,0 +1,66 @@ +#![deny(warnings)] // This code runs on stm32h747i-disco and does not use example! macro. +#![allow(unused_macros)] +#![no_main] +#![no_std] + +use cortex_m_rt::entry; +use stm32h7xx_hal::{pac, prelude::*}; + +use log::info; + +#[macro_use] +mod utilities; + +#[entry] +fn main() -> ! { + utilities::logger::init(); + let cp = cortex_m::Peripherals::take().unwrap(); + let dp = pac::Peripherals::take().unwrap(); + + // Constrain and Freeze power + info!("Setup PWR... "); + let pwr = dp.PWR.constrain(); + // let pwrcfg = example_power!(pwr).freeze(); + let pwrcfg = pwr.smps().freeze(); // This code works normally on stm32h747i-disco. + + // Constrain and Freeze clock + // RCC (Reset and Clock Control) + info!("Setup RCC... "); + let rcc = dp.RCC.constrain(); + + // CCDR (Core Clock Distribution and Reset) + // link: https://docs.rs/stm32h7xx-hal/latest/stm32h7xx_hal/rcc/struct.Ccdr.html + let ccdr = rcc.sys_ck(100.MHz()).freeze(pwrcfg, &dp.SYSCFG); + + info!(""); + info!("stm32h7xx-hal example - Blinky"); + info!(""); + + let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI); // <= GPIO settings for LEDs + + // Configure gpio pins as output. + let mut led1 = gpioi.pi12.into_push_pull_output(); // PI12 for LED1 + let mut led2 = gpioi.pi13.into_push_pull_output(); // PI13 for LED2 + let mut led3 = gpioi.pi14.into_push_pull_output(); // PI14 for LED3 + let mut led4 = gpioi.pi15.into_push_pull_output(); // PI15 for LED4 + + + // Get the delay provider. + let mut delay = cp.SYST.delay(ccdr.clocks); + + loop { + loop { + led1.set_high(); + led2.set_low(); + led3.set_high(); + led4.set_low(); + delay.delay_ms(500_u16); + + led1.set_low(); + led2.set_high(); + led3.set_low(); + led4.set_high(); + delay.delay_ms(500_u16); + } + } +} From 7ae2df5765c3489c81c168f7e2d313d5f431e5d3 Mon Sep 17 00:00:00 2001 From: Youndong Park Date: Wed, 24 Jan 2024 19:31:39 +0900 Subject: [PATCH 55/75] Update blinky-stm32h747i-disco.rs check code formatting --- examples/blinky-stm32h747i-disco.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/examples/blinky-stm32h747i-disco.rs b/examples/blinky-stm32h747i-disco.rs index 78dd71be..2310e34b 100644 --- a/examples/blinky-stm32h747i-disco.rs +++ b/examples/blinky-stm32h747i-disco.rs @@ -2,52 +2,51 @@ #![allow(unused_macros)] #![no_main] #![no_std] - + use cortex_m_rt::entry; use stm32h7xx_hal::{pac, prelude::*}; - + use log::info; - + #[macro_use] mod utilities; - + #[entry] fn main() -> ! { utilities::logger::init(); let cp = cortex_m::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); - + // Constrain and Freeze power info!("Setup PWR... "); let pwr = dp.PWR.constrain(); // let pwrcfg = example_power!(pwr).freeze(); let pwrcfg = pwr.smps().freeze(); // This code works normally on stm32h747i-disco. - + // Constrain and Freeze clock // RCC (Reset and Clock Control) info!("Setup RCC... "); let rcc = dp.RCC.constrain(); - + // CCDR (Core Clock Distribution and Reset) // link: https://docs.rs/stm32h7xx-hal/latest/stm32h7xx_hal/rcc/struct.Ccdr.html let ccdr = rcc.sys_ck(100.MHz()).freeze(pwrcfg, &dp.SYSCFG); - + info!(""); info!("stm32h7xx-hal example - Blinky"); info!(""); - + let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI); // <= GPIO settings for LEDs - + // Configure gpio pins as output. let mut led1 = gpioi.pi12.into_push_pull_output(); // PI12 for LED1 let mut led2 = gpioi.pi13.into_push_pull_output(); // PI13 for LED2 let mut led3 = gpioi.pi14.into_push_pull_output(); // PI14 for LED3 let mut led4 = gpioi.pi15.into_push_pull_output(); // PI15 for LED4 - - + // Get the delay provider. let mut delay = cp.SYST.delay(ccdr.clocks); - + loop { loop { led1.set_high(); @@ -55,7 +54,7 @@ fn main() -> ! { led3.set_high(); led4.set_low(); delay.delay_ms(500_u16); - + led1.set_low(); led2.set_high(); led3.set_low(); From cf8701e037d8475f0647c79b94e81bb429486ad0 Mon Sep 17 00:00:00 2001 From: Roman Isaikin Date: Wed, 24 Jan 2024 15:12:30 +0100 Subject: [PATCH 56/75] Update embedded-display-controller to 0.2. Use otm8009a from crates. Update DSI examples. --- Cargo.toml | 8 ++--- ...y-dsi-command-teartest-stm32h747i-disco.rs | 16 +--------- .../display-dsi-video-stm32h747i-disco.rs | 29 +++++++++---------- ...lay-dsi-video-teartest-stm32h747i-disco.rs | 16 +--------- src/dsi.rs | 18 ++++++------ 5 files changed, 28 insertions(+), 59 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bb2b6d14..791a2c60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,11 +42,10 @@ sdio-host = { version = "0.9", optional = true } embedded-sdmmc = { version = "0.5", optional = true } stm32-fmc = { version = "0.3", optional = true } synopsys-usb-otg = { version = "0.4", features = ["cortex-m"], optional = true } -embedded-display-controller = { version = "^0.1.0", optional = true } +embedded-display-controller = { version = "^0.2.0", optional = true } log = { version = "0.4.14", optional = true} # see also the dev-dependencies section fdcan = { version = "0.2", optional = true } embedded-storage = "0.3" -embedded-dsi = { git = "https://github.com/romixlab/embedded-hal.git", branch = "dsi", optional = true } [dependencies.smoltcp] version = "0.10.0" @@ -82,9 +81,8 @@ usbd-serial = "0.2.0" numtoa = "0.2.3" tinybmp = "0.5" embedded-graphics = "0.8" -otm8009a = { git = "https://github.com/romixlab/otm8009a.git" } +otm8009a = "0.1" eg-seven-segment = "0.2.0" -ft6236 = { git = "https://github.com/romixlab/ft6236.git" } [dev-dependencies.smoltcp] version = "0.10.0" @@ -104,7 +102,7 @@ gpio-h72 = [] gpio-h747 = [] gpio-h7a2 = [] -dsi = ["embedded-dsi", "embedded-display-controller"] +dsi = ["embedded-display-controller"] cm4 = [] cm7 = [] smps = [] diff --git a/examples/display-dsi-command-teartest-stm32h747i-disco.rs b/examples/display-dsi-command-teartest-stm32h747i-disco.rs index 6b642729..b673f40f 100644 --- a/examples/display-dsi-command-teartest-stm32h747i-disco.rs +++ b/examples/display-dsi-command-teartest-stm32h747i-disco.rs @@ -45,9 +45,8 @@ use embedded_display_controller::DisplayConfiguration; use otm8009a::Otm8009A; use stm32h7xx_hal::dsi::{ DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, - DsiVideoMode, LaneCount, + LaneCount, }; -use ft6236::{FT6236}; use crate::utilities::mpu_config::init_mpu; use crate::utilities::write::write_to::WriteTo; use core::fmt::Write; @@ -303,14 +302,6 @@ fn main() -> ! { let mut dsi_refresh_handle = dsi_host.refresh_handle(); info!("Initialised Display..."); - let scl = gpiod.pd12.into_alternate_open_drain(); - let sda = gpiod.pd13.into_alternate_open_drain(); - let i2c4 = - dp.I2C4 - .i2c((scl, sda), 100.kHz(), ccdr.peripheral.I2C4, &ccdr.clocks); - let mut touch_ctrl = FT6236::new(i2c4); - // let touch_int = gpiok.pk7 - let mut x = 0; let mut y = 0; let mut frame = 0; @@ -348,11 +339,6 @@ fn main() -> ! { frame += 1; colored_label(buf.as_str().unwrap(), 50, 20, Rgb888::RED, draw).unwrap(); - if let Ok(Some(pt)) = touch_ctrl.get_point0() { - info!("Touch: {} {}", pt.y, 480 - pt.x); - Circle::new(Point::new(480 - pt.x as i32 - 25, pt.y as i32 - 25), 50).into_styled(style_green).draw(draw).unwrap(); - } - display_test(draw).unwrap(); }); disp.swap_layer_wait(); diff --git a/examples/display-dsi-video-stm32h747i-disco.rs b/examples/display-dsi-video-stm32h747i-disco.rs index 65ee0471..6ed865cb 100644 --- a/examples/display-dsi-video-stm32h747i-disco.rs +++ b/examples/display-dsi-video-stm32h747i-disco.rs @@ -35,7 +35,6 @@ use embedded_display_controller::DisplayController; use chrono::{NaiveDateTime, NaiveTime}; use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::*; -use embedded_graphics::primitives::{Circle, PrimitiveStyleBuilder}; use embedded_display_controller::DisplayConfiguration; use otm8009a::Otm8009A; @@ -43,7 +42,6 @@ use stm32h7xx_hal::dsi::{ DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, DsiVideoMode, LaneCount, }; -use ft6236::{FT6236}; use crate::utilities::display_primitives::time_circuit; use crate::utilities::mpu_config::init_mpu; @@ -309,17 +307,18 @@ fn main() -> ! { //let mut dsi_refresh_handle = dsi_host.refresh_handle(); info!("Initialised Display..."); - let scl = gpiod.pd12.into_alternate_open_drain(); - let sda = gpiod.pd13.into_alternate_open_drain(); - let i2c4 = - dp.I2C4 - .i2c((scl, sda), 100.kHz(), ccdr.peripheral.I2C4, &ccdr.clocks); - let mut touch_ctrl = FT6236::new(i2c4); + // Works + // let scl = gpiod.pd12.into_alternate_open_drain(); + // let sda = gpiod.pd13.into_alternate_open_drain(); + // let i2c4 = + // dp.I2C4 + // .i2c((scl, sda), 100.kHz(), ccdr.peripheral.I2C4, &ccdr.clocks); + // let mut touch_ctrl = FT6236::new(i2c4); // let touch_int = gpiok.pk7 - let style_green = PrimitiveStyleBuilder::new() - .fill_color(Rgb888::GREEN) - .build(); + // let style_green = PrimitiveStyleBuilder::new() + // .fill_color(Rgb888::GREEN) + // .build(); loop { // Draw on a double buffered display @@ -332,10 +331,10 @@ fn main() -> ! { time_circuit(now, tc_x, 250, "PRESENT TIME", Rgb888::CSS_LIME_GREEN, Rgb888::new(15, 64, 15), draw).unwrap(); time_circuit(NaiveDateTime::new(NaiveDate::from_ymd_opt(1985, 10, 26).unwrap(), NaiveTime::from_hms_opt(01, 20, 0).unwrap()), tc_x, 400, "LAST TIME DEPARTED", Rgb888::CSS_ORANGE, Rgb888::new(77, 42, 0), draw).unwrap(); - if let Ok(Some(pt)) = touch_ctrl.get_point0() { - info!("Touch: {} {}", pt.y, 480 - pt.x); - Circle::new(Point::new(pt.y as i32 - 25, 480 - pt.x as i32 - 25), 50).into_styled(style_green).draw(draw).unwrap(); - } + // if let Ok(Some(pt)) = touch_ctrl.get_point0() { + // info!("Touch: {} {}", pt.y, 480 - pt.x); + // Circle::new(Point::new(pt.y as i32 - 25, 480 - pt.x as i32 - 25), 50).into_styled(style_green).draw(draw).unwrap(); + // } }); disp.swap_layer_wait(); } diff --git a/examples/display-dsi-video-teartest-stm32h747i-disco.rs b/examples/display-dsi-video-teartest-stm32h747i-disco.rs index 0d249daa..db751a76 100644 --- a/examples/display-dsi-video-teartest-stm32h747i-disco.rs +++ b/examples/display-dsi-video-teartest-stm32h747i-disco.rs @@ -39,7 +39,7 @@ use embedded_display_controller::DisplayController; use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::*; -use embedded_graphics::primitives::{Circle, PrimitiveStyleBuilder, Rectangle}; +use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_display_controller::DisplayConfiguration; use otm8009a::Otm8009A; @@ -47,7 +47,6 @@ use stm32h7xx_hal::dsi::{ DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, DsiVideoMode, LaneCount, }; -use ft6236::{FT6236}; use crate::utilities::mpu_config::init_mpu; use crate::utilities::write::write_to::WriteTo; use core::fmt::Write; @@ -304,14 +303,6 @@ fn main() -> ! { //let mut dsi_refresh_handle = dsi_host.refresh_handle(); info!("Initialised Display..."); - let scl = gpiod.pd12.into_alternate_open_drain(); - let sda = gpiod.pd13.into_alternate_open_drain(); - let i2c4 = - dp.I2C4 - .i2c((scl, sda), 100.kHz(), ccdr.peripheral.I2C4, &ccdr.clocks); - let mut touch_ctrl = FT6236::new(i2c4); - // let touch_int = gpiok.pk7 - let mut x = 0; let mut y = 0; let mut frame = 0; @@ -349,11 +340,6 @@ fn main() -> ! { frame += 1; colored_label(buf.as_str().unwrap(), 50, 20, Rgb888::RED, draw).unwrap(); - if let Ok(Some(pt)) = touch_ctrl.get_point0() { - info!("Touch: {} {}", pt.y, 480 - pt.x); - Circle::new(Point::new(480 - pt.x as i32 - 25, pt.y as i32 - 25), 50).into_styled(style_green).draw(draw).unwrap(); - } - display_test(draw).unwrap(); }); disp.swap_layer_wait(); diff --git a/src/dsi.rs b/src/dsi.rs index 1a60fc76..d08e0395 100644 --- a/src/dsi.rs +++ b/src/dsi.rs @@ -6,7 +6,7 @@ use crate::{ }; use core::cmp::{max, min}; use embedded_display_controller::DisplayConfiguration; -use embedded_dsi::{DsiHostCtrlIo, DsiReadCommand, DsiWriteCommand}; +use embedded_display_controller::dsi::{DsiHostCtrlIo, DsiReadCommand, DsiWriteCommand}; #[cfg(feature = "log")] use log::debug; @@ -589,19 +589,19 @@ impl DsiHostCtrlIo for DsiHost { )?; match kind { DsiWriteCommand::DcsShortP0 { .. } => todo!(), - DsiWriteCommand::DcsShortP1 { reg, data } => { + DsiWriteCommand::DcsShortP1 { arg, data } => { // debug!("{}, short_p1: reg: {reg:02x}, data: {data:02x}", self.write_idx); // self.write_idx += 1; - self.ghcr_write(data, reg, kind.discriminant()); + self.ghcr_write(data, arg, kind.discriminant()); } - DsiWriteCommand::DcsLongWrite { dcs_cmd, buf } => { - self.long_write(dcs_cmd, buf, kind.discriminant())? + DsiWriteCommand::DcsLongWrite { arg, data } => { + self.long_write(arg, data, kind.discriminant())? } DsiWriteCommand::GenericShortP0 => todo!(), DsiWriteCommand::GenericShortP1 => todo!(), DsiWriteCommand::GenericShortP2 => todo!(), - DsiWriteCommand::GenericLongWrite { cmd, buf } => { - self.long_write(cmd, buf, kind.discriminant())? + DsiWriteCommand::GenericLongWrite { arg, data } => { + self.long_write(arg, data, kind.discriminant())? } DsiWriteCommand::SetMaximumReturnPacketSize(len) => { self.ghcr_write( @@ -629,8 +629,8 @@ impl DsiHostCtrlIo for DsiHost { } match kind { - DsiReadCommand::DcsShort { dcs_cmd } => { - self.ghcr_write(0, dcs_cmd, kind.discriminant()); + DsiReadCommand::DcsShort { arg } => { + self.ghcr_write(0, arg, kind.discriminant()); } DsiReadCommand::GenericShortP0 => { self.ghcr_write(0, 0, kind.discriminant()); From e6f606544d6028a1e9b7e314ccbbfc0384f8baeb Mon Sep 17 00:00:00 2001 From: Youndong Park Date: Thu, 25 Jan 2024 08:13:39 +0900 Subject: [PATCH 57/75] remove trailing whitespaces --- examples/blinky-stm32h747i-disco.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/blinky-stm32h747i-disco.rs b/examples/blinky-stm32h747i-disco.rs index 2310e34b..d520cf61 100644 --- a/examples/blinky-stm32h747i-disco.rs +++ b/examples/blinky-stm32h747i-disco.rs @@ -1,5 +1,5 @@ #![deny(warnings)] // This code runs on stm32h747i-disco and does not use example! macro. -#![allow(unused_macros)] +#![allow(unused_macros)] #![no_main] #![no_std] @@ -16,37 +16,37 @@ fn main() -> ! { utilities::logger::init(); let cp = cortex_m::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); - + // Constrain and Freeze power info!("Setup PWR... "); let pwr = dp.PWR.constrain(); // let pwrcfg = example_power!(pwr).freeze(); let pwrcfg = pwr.smps().freeze(); // This code works normally on stm32h747i-disco. - + // Constrain and Freeze clock // RCC (Reset and Clock Control) info!("Setup RCC... "); let rcc = dp.RCC.constrain(); - + // CCDR (Core Clock Distribution and Reset) // link: https://docs.rs/stm32h7xx-hal/latest/stm32h7xx_hal/rcc/struct.Ccdr.html let ccdr = rcc.sys_ck(100.MHz()).freeze(pwrcfg, &dp.SYSCFG); - + info!(""); info!("stm32h7xx-hal example - Blinky"); info!(""); - + let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI); // <= GPIO settings for LEDs - + // Configure gpio pins as output. let mut led1 = gpioi.pi12.into_push_pull_output(); // PI12 for LED1 let mut led2 = gpioi.pi13.into_push_pull_output(); // PI13 for LED2 let mut led3 = gpioi.pi14.into_push_pull_output(); // PI14 for LED3 let mut led4 = gpioi.pi15.into_push_pull_output(); // PI15 for LED4 - + // Get the delay provider. let mut delay = cp.SYST.delay(ccdr.clocks); - + loop { loop { led1.set_high(); @@ -54,7 +54,7 @@ fn main() -> ! { led3.set_high(); led4.set_low(); delay.delay_ms(500_u16); - + led1.set_low(); led2.set_high(); led3.set_low(); From ae2c504e2d76b671468e3c23795d58a4baa0f0ee Mon Sep 17 00:00:00 2001 From: Roman Isaikin Date: Sat, 27 Jan 2024 12:42:48 +0100 Subject: [PATCH 58/75] Move display related utility functions to utilities_display mod. Clarify examples run commands. Reformat. --- Cargo.toml | 2 +- ...y-dsi-command-teartest-stm32h747i-disco.rs | 27 +++--- .../display-dsi-video-stm32h747i-disco.rs | 51 ++++++++-- ...lay-dsi-video-teartest-stm32h747i-disco.rs | 20 ++-- examples/embedded-graphics.rs | 3 +- examples/utilities/mod.rs | 7 -- .../display_primitives.rs | 93 +++++++++++-------- .../display_target.rs | 0 examples/utilities_display/mod.rs | 3 + .../{utilities => utilities_display}/write.rs | 7 +- src/dsi.rs | 25 +++-- src/lib.rs | 4 +- 12 files changed, 157 insertions(+), 85 deletions(-) rename examples/{utilities => utilities_display}/display_primitives.rs (71%) rename examples/{utilities => utilities_display}/display_target.rs (100%) create mode 100644 examples/utilities_display/mod.rs rename examples/{utilities => utilities_display}/write.rs (92%) diff --git a/Cargo.toml b/Cargo.toml index 791a2c60..bfe37aef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -267,7 +267,7 @@ required-features = ["revision_v"] [[example]] name = "display-dsi-video-stm32h747i-disco" -required-features = ["dsi", "ltdc", "fmc"] +required-features = ["dsi", "ltdc", "fmc", "rtc"] [[example]] name = "display-dsi-video-teartest-stm32h747i-disco" diff --git a/examples/display-dsi-command-teartest-stm32h747i-disco.rs b/examples/display-dsi-command-teartest-stm32h747i-disco.rs index b673f40f..e14907da 100644 --- a/examples/display-dsi-command-teartest-stm32h747i-disco.rs +++ b/examples/display-dsi-command-teartest-stm32h747i-disco.rs @@ -7,7 +7,7 @@ //! While in Landscape mode diagonal line is visible, because display is still refreshed //! in 480px lines from display's own graphics RAM, while writes are now 800px high. //! -//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,rm0399,smps,example-smps,log-rtt,rt,rtc" --example display-dsi-command-teartest-stm32h747i-disco +//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,example-smps,log-rtt,rt" --example display-dsi-command-teartest-stm32h747i-disco //! //! Tested on a STM32H747I-DISCO development board with a ST MB1166 Display //! (supplied together with the development kit). @@ -21,6 +21,8 @@ use core::{mem, slice}; #[macro_use] mod utilities; +mod utilities_display; + use log::info; use otm8009a::Otm8009AConfig; use stm32h7xx_hal::dsi::{ColorCoding, DsiChannel, DsiConfig, DsiPllConfig}; @@ -29,7 +31,7 @@ extern crate cortex_m; extern crate cortex_m_rt as rt; use cortex_m_rt::{entry, exception}; -use crate::utilities::display_target::BufferedDisplay; +use crate::utilities_display::display_target::BufferedDisplay; use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::ltdc; use stm32h7xx_hal::stm32::rcc::d1ccipr::FMCSEL_A; @@ -39,19 +41,21 @@ use embedded_display_controller::DisplayController; use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::*; -use embedded_graphics::primitives::{Circle, PrimitiveStyleBuilder, Rectangle}; +use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; +use crate::utilities::mpu_config::init_mpu; +use crate::utilities_display::display_primitives::{ + colored_label, display_test, +}; +use crate::utilities_display::write::write_to::WriteTo; +use core::fmt::Write; use embedded_display_controller::DisplayConfiguration; use otm8009a::Otm8009A; use stm32h7xx_hal::dsi::{ DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, LaneCount, }; -use crate::utilities::mpu_config::init_mpu; -use crate::utilities::write::write_to::WriteTo; -use core::fmt::Write; use stm32h7xx_hal::rcc::PllConfigStrategy; -use crate::utilities::display_primitives::{colored_label, display_test}; // Remember to use correct display controller orientation, Portrait in this case pub const WIDTH: usize = 480; @@ -240,9 +244,7 @@ fn main() -> ! { let dsi_pll_config = unsafe { DsiPllConfig::manual(100, 5, 0, 4) }; let dsi_config = DsiConfig { - mode: DsiMode::AdaptedCommand { - tear_effect: None, - }, + mode: DsiMode::AdaptedCommand { tear_effect: None }, lane_count: LaneCount::DoubleLane, channel: DsiChannel::Ch0, hse_freq, @@ -337,7 +339,8 @@ fn main() -> ! { let mut buf = WriteTo::new(&mut buf); write!(&mut buf, "f: {frame}").unwrap(); frame += 1; - colored_label(buf.as_str().unwrap(), 50, 20, Rgb888::RED, draw).unwrap(); + colored_label(buf.as_str().unwrap(), 50, 20, Rgb888::RED, draw) + .unwrap(); display_test(draw).unwrap(); }); @@ -355,4 +358,4 @@ unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { #[exception] unsafe fn DefaultHandler(irqn: i16) { panic!("Unhandled exception (IRQn = {})", irqn); -} \ No newline at end of file +} diff --git a/examples/display-dsi-video-stm32h747i-disco.rs b/examples/display-dsi-video-stm32h747i-disco.rs index 6ed865cb..e27fc9b4 100644 --- a/examples/display-dsi-video-stm32h747i-disco.rs +++ b/examples/display-dsi-video-stm32h747i-disco.rs @@ -2,7 +2,7 @@ //! an external display. The external display is connected through the DSI link. //! DSI Video mode is used, so the display is constantly refreshed by hardware. //! -//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,rm0399,smps,example-smps,log-rtt,rt,rtc" --example display-dsi-video-stm32h747i-disco +//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,example-smps,log-rtt,rt,rtc" --example display-dsi-video-stm32h747i-disco //! //! Tested on a STM32H747I-DISCO development board with a ST MB1166 Display //! (supplied together with the development kit). @@ -16,6 +16,8 @@ use core::{mem, slice}; #[macro_use] mod utilities; +mod utilities_display; + use log::info; use otm8009a::Otm8009AConfig; use stm32h7xx_hal::dsi::{ColorCoding, DsiChannel, DsiConfig, DsiPllConfig}; @@ -24,7 +26,7 @@ extern crate cortex_m; extern crate cortex_m_rt as rt; use cortex_m_rt::{entry, exception}; -use crate::utilities::display_target::BufferedDisplay; +use crate::utilities_display::display_target::BufferedDisplay; use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::ltdc; use stm32h7xx_hal::stm32::rcc::d1ccipr::FMCSEL_A; @@ -36,14 +38,14 @@ use chrono::{NaiveDateTime, NaiveTime}; use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::*; +use crate::utilities::mpu_config::init_mpu; +use crate::utilities_display::display_primitives::time_circuit; use embedded_display_controller::DisplayConfiguration; use otm8009a::Otm8009A; use stm32h7xx_hal::dsi::{ DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, DsiVideoMode, LaneCount, }; -use crate::utilities::display_primitives::time_circuit; -use crate::utilities::mpu_config::init_mpu; pub const WIDTH: usize = 800; pub const HEIGHT: usize = 480; @@ -326,10 +328,43 @@ fn main() -> ! { draw.clear(); let tc_x = 54; - time_circuit(NaiveDateTime::new(NaiveDate::from_ymd_opt(1985, 10, 26).unwrap(), NaiveTime::from_hms_opt(01, 21, 0).unwrap()), tc_x, 100, "DESTINATION TIME", Rgb888::CSS_ORANGE_RED, Rgb888::new(102, 27, 0), draw).unwrap(); + time_circuit( + NaiveDateTime::new( + NaiveDate::from_ymd_opt(1985, 10, 26).unwrap(), + NaiveTime::from_hms_opt(01, 21, 0).unwrap(), + ), + tc_x, + 100, + "DESTINATION TIME", + Rgb888::CSS_ORANGE_RED, + Rgb888::new(102, 27, 0), + draw, + ) + .unwrap(); let now = rtc.date_time().unwrap(); - time_circuit(now, tc_x, 250, "PRESENT TIME", Rgb888::CSS_LIME_GREEN, Rgb888::new(15, 64, 15), draw).unwrap(); - time_circuit(NaiveDateTime::new(NaiveDate::from_ymd_opt(1985, 10, 26).unwrap(), NaiveTime::from_hms_opt(01, 20, 0).unwrap()), tc_x, 400, "LAST TIME DEPARTED", Rgb888::CSS_ORANGE, Rgb888::new(77, 42, 0), draw).unwrap(); + time_circuit( + now, + tc_x, + 250, + "PRESENT TIME", + Rgb888::CSS_LIME_GREEN, + Rgb888::new(15, 64, 15), + draw, + ) + .unwrap(); + time_circuit( + NaiveDateTime::new( + NaiveDate::from_ymd_opt(1985, 10, 26).unwrap(), + NaiveTime::from_hms_opt(01, 20, 0).unwrap(), + ), + tc_x, + 400, + "LAST TIME DEPARTED", + Rgb888::CSS_ORANGE, + Rgb888::new(77, 42, 0), + draw, + ) + .unwrap(); // if let Ok(Some(pt)) = touch_ctrl.get_point0() { // info!("Touch: {} {}", pt.y, 480 - pt.x); @@ -348,4 +383,4 @@ unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { #[exception] unsafe fn DefaultHandler(irqn: i16) { panic!("Unhandled exception (IRQn = {})", irqn); -} \ No newline at end of file +} diff --git a/examples/display-dsi-video-teartest-stm32h747i-disco.rs b/examples/display-dsi-video-teartest-stm32h747i-disco.rs index db751a76..4b95ac8c 100644 --- a/examples/display-dsi-video-teartest-stm32h747i-disco.rs +++ b/examples/display-dsi-video-teartest-stm32h747i-disco.rs @@ -7,7 +7,7 @@ //! While in Landscape mode diagonal line is visible, because display is still refreshed //! in 480px lines from display's own graphics RAM, while writes are now 800px high. //! -//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,rm0399,smps,example-smps,log-rtt,rt,rtc" --example display-dsi-video-teartest-stm32h747i-disco +//! Run command: cargo embed --release --features="stm32h747cm7,dsi,log,ltdc,fmc,example-smps,log-rtt,rt" --example display-dsi-video-teartest-stm32h747i-disco //! //! Tested on a STM32H747I-DISCO development board with a ST MB1166 Display //! (supplied together with the development kit). @@ -21,6 +21,7 @@ use core::{mem, slice}; #[macro_use] mod utilities; +mod utilities_display; use log::info; use otm8009a::Otm8009AConfig; use stm32h7xx_hal::dsi::{ColorCoding, DsiChannel, DsiConfig, DsiPllConfig}; @@ -29,7 +30,7 @@ extern crate cortex_m; extern crate cortex_m_rt as rt; use cortex_m_rt::{entry, exception}; -use crate::utilities::display_target::BufferedDisplay; +use crate::utilities_display::display_target::BufferedDisplay; use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::ltdc; use stm32h7xx_hal::stm32::rcc::d1ccipr::FMCSEL_A; @@ -41,17 +42,19 @@ use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; +use crate::utilities::mpu_config::init_mpu; +use crate::utilities_display::display_primitives::{ + colored_label, display_test, +}; +use crate::utilities_display::write::write_to::WriteTo; +use core::fmt::Write; use embedded_display_controller::DisplayConfiguration; use otm8009a::Otm8009A; use stm32h7xx_hal::dsi::{ DsiCmdModeTransmissionKind, DsiHost, DsiInterrupts, DsiMode, DsiPhyTimers, DsiVideoMode, LaneCount, }; -use crate::utilities::mpu_config::init_mpu; -use crate::utilities::write::write_to::WriteTo; -use core::fmt::Write; use stm32h7xx_hal::rcc::PllConfigStrategy; -use crate::utilities::display_primitives::{colored_label, display_test}; // Remember to use correct display controller orientation, Portrait in this case pub const WIDTH: usize = 480; @@ -338,7 +341,8 @@ fn main() -> ! { let mut buf = WriteTo::new(&mut buf); write!(&mut buf, "f: {frame}").unwrap(); frame += 1; - colored_label(buf.as_str().unwrap(), 50, 20, Rgb888::RED, draw).unwrap(); + colored_label(buf.as_str().unwrap(), 50, 20, Rgb888::RED, draw) + .unwrap(); display_test(draw).unwrap(); }); @@ -354,4 +358,4 @@ unsafe fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { #[exception] unsafe fn DefaultHandler(irqn: i16) { panic!("Unhandled exception (IRQn = {})", irqn); -} \ No newline at end of file +} diff --git a/examples/embedded-graphics.rs b/examples/embedded-graphics.rs index 7c37cf01..cbdc2386 100644 --- a/examples/embedded-graphics.rs +++ b/examples/embedded-graphics.rs @@ -13,6 +13,7 @@ use core::{mem, slice}; #[macro_use] mod utilities; +mod utilities_display; use log::info; extern crate cortex_m; @@ -32,9 +33,9 @@ use embedded_graphics::mono_font::{ascii, MonoTextStyle}; use embedded_graphics::prelude::*; use embedded_graphics::text::Text; +use crate::utilities_display::display_target::BufferedDisplay; use numtoa::NumToA; use tinybmp::Bmp; -use crate::utilities::display_target::BufferedDisplay; const WIDTH: usize = 480; const HEIGHT: usize = 272; diff --git a/examples/utilities/mod.rs b/examples/utilities/mod.rs index 87f09dbf..63bfbc0c 100644 --- a/examples/utilities/mod.rs +++ b/examples/utilities/mod.rs @@ -6,10 +6,3 @@ mod power; #[cfg(feature = "fmc")] pub mod mpu_config; - -#[cfg(feature = "ltdc")] -pub mod display_target; -#[cfg(feature = "ltdc")] -pub mod write; -#[cfg(feature = "ltdc")] -pub mod display_primitives; \ No newline at end of file diff --git a/examples/utilities/display_primitives.rs b/examples/utilities_display/display_primitives.rs similarity index 71% rename from examples/utilities/display_primitives.rs rename to examples/utilities_display/display_primitives.rs index 6004ac8c..2cc75e88 100644 --- a/examples/utilities/display_primitives.rs +++ b/examples/utilities_display/display_primitives.rs @@ -7,7 +7,6 @@ use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; -#[allow(dead_code)] pub fn colored_label( text: &str, x: i32, @@ -15,16 +14,16 @@ pub fn colored_label( color: Rgb888, target: &mut D, ) -> Result<(), D::Error> - where - D: DrawTarget, +where + D: DrawTarget, { let style_red = PrimitiveStyleBuilder::new().fill_color(color).build(); Rectangle::new( Point::new(x, y), Size::new((text.len() as u32) * 9 + 8, 22), ) - .into_styled(style_red) - .draw(target)?; + .into_styled(style_red) + .draw(target)?; let text_style = MonoTextStyle::new(&ascii::FONT_9X18_BOLD, RgbColor::WHITE); @@ -33,11 +32,9 @@ pub fn colored_label( } #[allow(dead_code)] -pub fn display_test( - target: &mut D, -) -> Result<(), D::Error> - where - D: DrawTarget, +pub fn display_test(target: &mut D) -> Result<(), D::Error> +where + D: DrawTarget, { let style_red = PrimitiveStyleBuilder::new().fill_color(Rgb888::RED).build(); @@ -58,28 +55,34 @@ pub fn display_test( Rectangle::new(Point::new(size.width as i32 - 10, 0), Size::new(10, 10)) .into_styled(style_green) .draw(target)?; - Rectangle::new( - Point::new(0, size.height as i32 - 10), - Size::new(10, 10), - ) + Rectangle::new(Point::new(0, size.height as i32 - 10), Size::new(10, 10)) .into_styled(style_blue) .draw(target)?; Rectangle::new( Point::new(size.width as i32 - 10, size.height as i32 - 10), Size::new(10, 10), ) - .into_styled(style_cyan) - .draw(target)?; + .into_styled(style_cyan) + .draw(target)?; - let ferris = tinybmp::Bmp::from_slice(include_bytes!("../ferris.bmp")).unwrap(); - let ferris = Image::new(&ferris, Point::new((size.width / 2 - ferris.size().width / 2) as i32, (size.height / 2 - ferris.size().height / 2) as i32)); + let ferris = + tinybmp::Bmp::from_slice(include_bytes!("../ferris.bmp")).unwrap(); + let ferris = Image::new( + &ferris, + Point::new( + (size.width / 2 - ferris.size().width / 2) as i32, + (size.height / 2 - ferris.size().height / 2) as i32, + ), + ); ferris.draw(target)?; Ok(()) } #[cfg(feature = "chrono")] #[allow(dead_code)] -pub fn seven_segment_style(color: Rgb888) -> eg_seven_segment::SevenSegmentStyle { +pub fn seven_segment_style( + color: Rgb888, +) -> eg_seven_segment::SevenSegmentStyle { eg_seven_segment::SevenSegmentStyleBuilder::new() .digit_size(Size::new(36, 48)) // digits are 10x20 pixels .digit_spacing(5) // 5px spacing between digits @@ -91,8 +94,8 @@ pub fn seven_segment_style(color: Rgb888) -> eg_seven_segment::SevenSegmentStyle #[cfg(feature = "chrono")] #[allow(dead_code)] pub fn date_labels(y: i32, target: &mut D) -> Result<(), D::Error> - where - D: DrawTarget, +where + D: DrawTarget, { let bg_color = Rgb888::RED; colored_label("MONTH", 86, y, bg_color, target)?; @@ -105,15 +108,22 @@ pub fn date_labels(y: i32, target: &mut D) -> Result<(), D::Error> #[cfg(feature = "chrono")] #[allow(dead_code)] -pub fn time_circuit(dt: NaiveDateTime, x: i32, y: i32, label: &str, fg: Rgb888, bg: Rgb888, target: &mut D) -> Result<(), D::Error> - where - D: DrawTarget, +pub fn time_circuit( + dt: NaiveDateTime, + x: i32, + y: i32, + label: &str, + fg: Rgb888, + bg: Rgb888, + target: &mut D, +) -> Result<(), D::Error> +where + D: DrawTarget, { let fg_text_style = seven_segment_style(fg); let bg_text_style = seven_segment_style(bg); let all_segments = "888 88 8888 88 88"; - Text::new(all_segments, Point::new(x, y), bg_text_style) - .draw(target)?; + Text::new(all_segments, Point::new(x, y), bg_text_style).draw(target)?; let month = match dt.date().month() { 1 => "JAN", 2 => "FEB", @@ -127,14 +137,23 @@ pub fn time_circuit(dt: NaiveDateTime, x: i32, y: i32, label: &str, fg: Rgb88 10 => "OCT", 11 => "NOU", 12 => "DEC", - _ => unreachable!() + _ => unreachable!(), }; let mut buf = [0u8; 17]; - use crate::utilities::write::write_to::WriteTo; + use crate::utilities_display::write::write_to::WriteTo; use core::fmt::Write; let mut buf = WriteTo::new(&mut buf); let (is_pm, hour) = dt.time().hour12(); - write!(&mut buf, "{} {:02} {:04} {:02} {:02}", month, dt.date().day(), dt.date().year(), hour, dt.time().minute()).unwrap(); + write!( + &mut buf, + "{} {:02} {:04} {:02} {:02}", + month, + dt.date().day(), + dt.date().year(), + hour, + dt.time().minute() + ) + .unwrap(); Text::new(buf.as_str().unwrap(), Point::new(x, y), fg_text_style) .draw(target)?; date_labels(y - 75, target)?; @@ -146,12 +165,8 @@ pub fn time_circuit(dt: NaiveDateTime, x: i32, y: i32, label: &str, fg: Rgb88 target, )?; - let fg_style = PrimitiveStyleBuilder::new() - .fill_color(fg) - .build(); - let bg_style = PrimitiveStyleBuilder::new() - .fill_color(bg) - .build(); + let fg_style = PrimitiveStyleBuilder::new().fill_color(fg).build(); + let bg_style = PrimitiveStyleBuilder::new().fill_color(bg).build(); colored_label("AM", 633, y - 65, Rgb888::RED, target)?; let (am_style, pm_style) = if is_pm { (bg_style, fg_style) @@ -159,8 +174,12 @@ pub fn time_circuit(dt: NaiveDateTime, x: i32, y: i32, label: &str, fg: Rgb88 (fg_style, bg_style) }; use embedded_graphics::primitives::Circle; - Circle::new(Point::new(641, y - 40), 10).into_styled(am_style).draw(target)?; + Circle::new(Point::new(641, y - 40), 10) + .into_styled(am_style) + .draw(target)?; colored_label("PM", 633, y - 26, Rgb888::RED, target)?; - Circle::new(Point::new(641, y), 10).into_styled(pm_style).draw(target)?; + Circle::new(Point::new(641, y), 10) + .into_styled(pm_style) + .draw(target)?; Ok(()) } diff --git a/examples/utilities/display_target.rs b/examples/utilities_display/display_target.rs similarity index 100% rename from examples/utilities/display_target.rs rename to examples/utilities_display/display_target.rs diff --git a/examples/utilities_display/mod.rs b/examples/utilities_display/mod.rs new file mode 100644 index 00000000..315a58cf --- /dev/null +++ b/examples/utilities_display/mod.rs @@ -0,0 +1,3 @@ +pub mod display_primitives; +pub mod display_target; +pub mod write; diff --git a/examples/utilities/write.rs b/examples/utilities_display/write.rs similarity index 92% rename from examples/utilities/write.rs rename to examples/utilities_display/write.rs index 7eabc933..c6b7bd9d 100644 --- a/examples/utilities/write.rs +++ b/examples/utilities_display/write.rs @@ -46,9 +46,12 @@ pub mod write_to { } #[allow(dead_code)] - pub fn show<'a>(buffer: &'a mut [u8], args: fmt::Arguments) -> Result<&'a str, fmt::Error> { + pub fn show<'a>( + buffer: &'a mut [u8], + args: fmt::Arguments, + ) -> Result<&'a str, fmt::Error> { let mut w = WriteTo::new(buffer); fmt::write(&mut w, args)?; w.as_str().ok_or(fmt::Error) } -} \ No newline at end of file +} diff --git a/src/dsi.rs b/src/dsi.rs index d08e0395..de41b890 100644 --- a/src/dsi.rs +++ b/src/dsi.rs @@ -5,8 +5,10 @@ use crate::{ time::Hertz, }; use core::cmp::{max, min}; +use embedded_display_controller::dsi::{ + DsiHostCtrlIo, DsiReadCommand, DsiWriteCommand, +}; use embedded_display_controller::DisplayConfiguration; -use embedded_display_controller::dsi::{DsiHostCtrlIo, DsiReadCommand, DsiWriteCommand}; #[cfg(feature = "log")] use log::debug; @@ -115,7 +117,7 @@ pub enum ColorCoding { SixteenBitsConfig3 = 0b010, EighteenBitsConfig1 = 0b011, EighteenBitsConfig2 = 0b100, - TwentyFourBits = 0b101 + TwentyFourBits = 0b101, } pub struct DsiConfig { @@ -219,7 +221,12 @@ impl DsiHost { let f_pix_khz = f_phy_hz / 1_000 / 8; let uix4 = 4_000_000_000 / f_phy_hz; #[cfg(feature = "log")] - debug!("f_phy={}kHz, f_pix={}kHz, uix4={}", f_phy_hz / 1_000, f_pix_khz, uix4); + debug!( + "f_phy={}kHz, f_pix={}kHz, uix4={}", + f_phy_hz / 1_000, + f_pix_khz, + uix4 + ); dsi.wpcr0 .modify(|_, w| unsafe { w.uix4().bits(uix4 as u8) }); // debug!("f_phy={}, uix4=override=8", f_phy); @@ -304,13 +311,15 @@ impl DsiHost { // Horizontal sync active (HSA) in lane byte clock cycles let f_ltdc_khz = dsi_config.ltdc_freq.to_kHz(); - let hsa = ((display_config.h_sync as u32) * f_pix_khz / f_ltdc_khz) as u16; + let hsa = ((display_config.h_sync as u32) * f_pix_khz + / f_ltdc_khz) as u16; #[cfg(feature = "log")] debug!("hsa={}", hsa); dsi.vhsacr.modify(|_, w| unsafe { w.hsa().bits(hsa) }); // Horizontal back porch (HBP) in lane byte clock cycles - let hbp = ((display_config.h_back_porch as u32) * f_pix_khz / f_ltdc_khz) as u16; + let hbp = ((display_config.h_back_porch as u32) * f_pix_khz + / f_ltdc_khz) as u16; #[cfg(feature = "log")] debug!("hbp={}", hbp); dsi.vhbpcr.modify(|_, w| unsafe { w.hbp().bits(hbp) }); @@ -398,7 +407,7 @@ impl DsiHost { let lpe = match dsi_config.color_coding_host { ColorCoding::EighteenBitsConfig1 => true, ColorCoding::EighteenBitsConfig2 => true, - _ => false + _ => false, }; dsi.lcolcr.modify(|_, w| unsafe { w.lpe() @@ -408,7 +417,9 @@ impl DsiHost { }); // Color coding for the wrapper - dsi.wcfgr.modify(|_, w| unsafe { w.colmux().bits(dsi_config.color_coding_wrapper as u8) }); + dsi.wcfgr.modify(|_, w| unsafe { + w.colmux().bits(dsi_config.color_coding_wrapper as u8) + }); dsi.lpmcr.modify(|_, w| unsafe { w.lpsize() diff --git a/src/lib.rs b/src/lib.rs index 295556fe..7b8ff309 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,6 +156,8 @@ pub mod dac; pub mod delay; #[cfg(feature = "device-selected")] pub mod dma; +#[cfg(feature = "dsi")] +pub mod dsi; #[cfg(all( feature = "device-selected", feature = "ethernet", @@ -217,8 +219,6 @@ pub mod usb_hs; #[cfg(all(feature = "device-selected", feature = "xspi"))] #[cfg_attr(docsrs, doc(cfg(feature = "xspi")))] pub mod xspi; -#[cfg(feature="dsi")] -pub mod dsi; #[cfg(feature = "device-selected")] mod sealed { From 7f67fe5d8e64160c2a1f116887939e9aad3f1b08 Mon Sep 17 00:00:00 2001 From: Roman Isaikin Date: Sat, 27 Jan 2024 14:56:05 +0100 Subject: [PATCH 59/75] Add attributes to utilities::init_mpu fn. --- examples/utilities/mpu_config.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/utilities/mpu_config.rs b/examples/utilities/mpu_config.rs index b91afa60..18a4f7e1 100644 --- a/examples/utilities/mpu_config.rs +++ b/examples/utilities/mpu_config.rs @@ -1,5 +1,6 @@ use cortex_m::peripheral::{MPU, SCB}; +#[allow(unused, unsafe_code)] pub fn init_mpu(mpu: MPU, scb: &mut SCB, sdram_size: usize) { // Refer to ARM®v7-M Architecture Reference Manual ARM DDI 0403 // Version E.b Section B3.5 @@ -74,4 +75,4 @@ pub fn init_mpu(mpu: MPU, scb: &mut SCB, sdram_size: usize) { cortex_m::asm::dsb(); cortex_m::asm::isb(); } -} \ No newline at end of file +} From c90484c1271794cbf8140f439bc14642e1f38f97 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 27 Jan 2024 18:00:38 +0100 Subject: [PATCH 60/75] dsi: revert unneeded change to delay.rs --- src/delay.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/delay.rs b/src/delay.rs index d3bd2087..42f5b13a 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -49,7 +49,7 @@ use void::Void; use crate::nb::block; use crate::rcc::CoreClocks; -use crate::time::{Hertz, MicroSeconds}; +use crate::time::Hertz; use fugit::RateExtU32; pub trait DelayExt { From 34841e4a30eca7558bf589f805618e329d91a5b7 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 27 Jan 2024 18:02:22 +0100 Subject: [PATCH 61/75] dsi: add to ci; dsi is only available on rm0399 parts --- .github/workflows/ci.yml | 2 +- .github/workflows/nightly.yml | 2 +- Cargo.toml | 24 ++++++++++++------------ src/dsi.rs | 4 ++++ src/lib.rs | 2 +- src/rcc/rec.rs | 2 +- 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e9346b9..8c1743be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: - stm32h7b0 - stm32h735 env: # Peripheral Feature flags - FLAGS: rt,xspi,sdmmc,sdmmc-fatfs,fmc,usb_hs,rtc,ethernet,ltdc,crc,rand,can,defmt + FLAGS: rt,xspi,sdmmc,sdmmc-fatfs,fmc,usb_hs,rtc,ethernet,ltdc,crc,rand,can,dsi,defmt steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 4d991ec7..9e12fee8 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -19,7 +19,7 @@ jobs: - log-semihost - log-rtt env: # Peripheral Feature flags - FLAGS: rt,xspi,sdmmc,sdmmc-fatfs,fmc,usb_hs,rtc,ethernet,ltdc,crc,rand,can + FLAGS: rt,xspi,sdmmc,sdmmc-fatfs,fmc,usb_hs,rtc,ethernet,ltdc,crc,rand,can,dsi steps: - uses: actions/checkout@v4 diff --git a/Cargo.toml b/Cargo.toml index bfe37aef..6e568d36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -165,6 +165,18 @@ required-features = ["can"] name = "crc" required-features = ["crc"] +[[example]] +name = "display-dsi-video-stm32h747i-disco" +required-features = ["dsi", "ltdc", "fmc", "rtc", "rm0399"] + +[[example]] +name = "display-dsi-video-teartest-stm32h747i-disco" +required-features = ["dsi", "ltdc", "fmc", "rm0399"] + +[[example]] +name = "display-dsi-command-teartest-stm32h747i-disco" +required-features = ["dsi", "ltdc", "fmc", "rm0399"] + [[example]] name = "embedded-graphics" required-features = ["ltdc", "xspi", "rm0468"] @@ -264,15 +276,3 @@ required-features = ["rt", "usb_hs", "rm0433"] [[example]] name = "vos0" required-features = ["revision_v"] - -[[example]] -name = "display-dsi-video-stm32h747i-disco" -required-features = ["dsi", "ltdc", "fmc", "rtc"] - -[[example]] -name = "display-dsi-video-teartest-stm32h747i-disco" -required-features = ["dsi", "ltdc", "fmc"] - -[[example]] -name = "display-dsi-command-teartest-stm32h747i-disco" -required-features = ["dsi", "ltdc", "fmc"] diff --git a/src/dsi.rs b/src/dsi.rs index de41b890..4aff69f6 100644 --- a/src/dsi.rs +++ b/src/dsi.rs @@ -1,3 +1,7 @@ +//! Display Serial Interface +//! +//! Interface with MIPI D-PHY + use crate::rcc::CoreClocks; use crate::{ device::DSIHOST, diff --git a/src/lib.rs b/src/lib.rs index 7b8ff309..fd63fb5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,7 +156,7 @@ pub mod dac; pub mod delay; #[cfg(feature = "device-selected")] pub mod dma; -#[cfg(feature = "dsi")] +#[cfg(all(feature = "device-selected", feature = "dsi", feature = "rm0399"))] pub mod dsi; #[cfg(all( feature = "device-selected", diff --git a/src/rcc/rec.rs b/src/rcc/rec.rs index 6b2390da..e2cc75d6 100644 --- a/src/rcc/rec.rs +++ b/src/rcc/rec.rs @@ -698,7 +698,7 @@ peripheral_reset_and_enable_control! { #[cfg(all())] APB3, "Advanced Peripheral Bus 3 (APB3) peripherals" => [ Ltdc [fixed clk: "pll3_r_ck"], - #[cfg(any(feature = "dsi"))] Dsi + #[cfg(any(feature = "rm0399"))] Dsi ]; From 891d9f53f004632296321904739e690ec45168ff Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 27 Jan 2024 18:26:58 +0100 Subject: [PATCH 62/75] dsi: increase MSRV to 1.66.1 --- .github/workflows/ci.yml | 2 +- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- README.md | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c1743be..66dbe040 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: strategy: matrix: # All permutations of {rust, mcu} rust: - - 1.65.0 # MSRV + - 1.66.1 # MSRV - stable mcu: - stm32h743 diff --git a/CHANGELOG.md b/CHANGELOG.md index b5bd57bc..30893f4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +* MSRV increased to Rust 1.66.1 [#473] + ## [v0.15.1] 2023-11-03 * Bugfix, usb: On RM0455 and RM0468 parts, PA11/PA12 do not have an alternate function diff --git a/Cargo.toml b/Cargo.toml index 6e568d36..8b04bee5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ authors = ["Andrew Straw ", "Florian Jung ", "Matt Ickstadt "] edition = "2021" -rust-version = "1.65" +rust-version = "1.66.1" categories = ["embedded", "hardware-support", "no-std"] description = "Hardware Abstraction Layer implementation for STM32H7 series microcontrollers" keywords = ["arm", "cortex-m", "stm32h7xx", "hal", "embedded-hal"] diff --git a/README.md b/README.md index 9b42e16a..a7474095 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ stm32h7xx-hal [![docs.rs](https://docs.rs/stm32h7xx-hal/badge.svg)](https://docs.rs/stm32h7xx-hal) [![CI](https://github.com/stm32-rs/stm32h7xx-hal/workflows/Continuous%20integration/badge.svg)](https://github.com/stm32-rs/stm32h7xx-hal/actions) [![Crates.io](https://img.shields.io/crates/v/stm32h7xx-hal.svg)](https://crates.io/crates/stm32h7xx-hal) -![Minimum rustc version](https://img.shields.io/badge/rustc-1.65.0+-yellow.svg) +![Minimum rustc version](https://img.shields.io/badge/rustc-1.66.1+-yellow.svg) [_stm32h7xx-hal_](https://github.com/stm32-rs/stm32h7xx-hal) contains a hardware abstraction layer on top of the peripheral access API for @@ -110,7 +110,7 @@ programming interfaces are only available on the high density connectors. Minimum supported Rust version ------------------------------ -The Minimum Supported Rust Version (MSRV) at the moment is **1.65.0**. Older +The Minimum Supported Rust Version (MSRV) at the moment is **1.66.1**. Older versions **may** compile, especially when some features are not used in your application. From 71467594af3d5dcb1ffab651b7bed664274e03da Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 20 Jan 2024 22:53:49 +0100 Subject: [PATCH 63/75] Remove references to `static mut` rust/#114447 made `&mut MY_STATIC_MUT` a warning, with the intention of disallowing it entirely in the 2024 edition. We never used this in the crate itself, but it is used in many examples. This commit removes these references from the examples. In general the new approach is to change `static mut` of type `X` to type `MaybeUninit`. These can then cleanly be accessed with [`MY_STATIC_MUT.write()`](https://doc.rust-lang.org/core/mem/union.MaybeUninit.html#method.write) followed by [`MY_STATIC_MUT.assume_init_mut()`](https://doc.rust-lang.org/core/mem/union.MaybeUninit.html#method.assume_init_mut). Where we need to cast a `MaybeUninit<[X; N]>` to a `[MaybeUninit; N]` in order to initialise it element-by-element, the `&mut *ptr::addr_of_mut!(MY_STATIC_MUT)` construction is still used. After initialisation, we can then access it with `MY_STATIC_MUT.assume_init_mut()`. In a few DMA Examples we were taking a reference `&mut TARGET_BUFFER` without initialising TARGET_BUFFER. This commit changes this to `TARGET_BUFFER.assume_init_mut()` *without* initialising `TARGET_BUFFER`. This was and remains UB. * USB Examples: `static mut EP_MEMORY` now has type `MaybeUninit<[u32; 1024]>` * Ethernet Examples: `static mut DES_RING` now has type `MaybeUninit>` --- examples/adc_dma.rs | 8 ++++-- examples/dma.rs | 17 +++++++----- examples/ethernet-nucleo-h743zi2.rs | 8 ++++-- examples/ethernet-rtic-nucleo-h723zg.rs | 30 ++++++++++++++++----- examples/ethernet-rtic-stm32h735g-dk.rs | 7 +++-- examples/ethernet-rtic-stm32h747i-disco.rs | 7 +++-- examples/ethernet-stm32h747i-disco.rs | 8 ++++-- examples/i2c4_bdma.rs | 20 +++++++------- examples/mdma.rs | 13 ++++----- examples/mdma_bursts.rs | 18 ++++++------- examples/sai_dma_passthru.rs | 31 +++++++++++++++------- examples/serial-dma.rs | 11 ++++---- examples/spi-dma-rtic.rs | 7 ++--- examples/spi-dma.rs | 11 ++++---- examples/usb_passthrough.rs | 28 ++++++++++++++++--- examples/usb_phy_serial_interrupt.rs | 15 +++++++++-- examples/usb_rtic.rs | 15 +++++++++-- examples/usb_serial.rs | 17 ++++++++++-- 18 files changed, 188 insertions(+), 83 deletions(-) diff --git a/examples/adc_dma.rs b/examples/adc_dma.rs index b89469db..7561bdcf 100644 --- a/examples/adc_dma.rs +++ b/examples/adc_dma.rs @@ -4,6 +4,7 @@ //! For an example of using ADC1 and ADC2 together, see examples/adc12.rs //! For an example of using ADC1 and ADC2 in parallel, see examples/adc12_parallel.rs +#![deny(warnings)] #![no_main] #![no_std] @@ -33,8 +34,11 @@ fn main() -> ! { let adc_buffer: &'static mut [u16; 32_768] = { // Convert an uninitialised array into an array of uninitialised - let buf: &mut [MaybeUninit; 32_768] = - unsafe { mem::transmute(&mut BUFFER) }; + let buf: &mut [MaybeUninit; 32_768] = unsafe { + &mut *(core::ptr::addr_of_mut!(BUFFER) + as *mut [MaybeUninit<_>; 32_768]) + }; + // Initialise memory to valid values for slot in buf.iter_mut() { // Never create even a _temporary_ reference to uninitialised memory diff --git a/examples/dma.rs b/examples/dma.rs index 9c27d577..730a2c5b 100644 --- a/examples/dma.rs +++ b/examples/dma.rs @@ -1,11 +1,10 @@ //! Example of Memory to Memory Transfer with the DMA -#![allow(clippy::transmute_ptr_to_ptr)] #![deny(warnings)] #![no_main] #![no_std] -use core::{mem, mem::MaybeUninit}; +use core::mem::MaybeUninit; use cortex_m_rt::entry; #[macro_use] @@ -57,15 +56,17 @@ fn main() -> ! { // Initialise the source buffer with truly random data, without taking any // references to uninitialisated memory let source_buffer: &'static mut [u32; 20] = { - let buf: &mut [MaybeUninit; 20] = - unsafe { mem::transmute(&mut SOURCE_BUFFER) }; + let buf: &mut [MaybeUninit; 20] = unsafe { + &mut *(core::ptr::addr_of_mut!(SOURCE_BUFFER) + as *mut [MaybeUninit; 20]) + }; for value in buf.iter_mut() { unsafe { value.as_mut_ptr().write(rng.gen().unwrap()); } } - unsafe { mem::transmute(buf) } + unsafe { SOURCE_BUFFER.assume_init_mut() } }; // Save a copy on the stack so we can check it later let source_buffer_cloned = *source_buffer; @@ -85,7 +86,9 @@ fn main() -> ! { Transfer::init( streams.4, MemoryToMemory::new(), - unsafe { mem::transmute(&mut TARGET_BUFFER) }, // Uninitialised memory + unsafe { + (*core::ptr::addr_of_mut!(TARGET_BUFFER)).assume_init_mut() + }, // Uninitialised memory Some(source_buffer), config, ); @@ -97,7 +100,7 @@ fn main() -> ! { // Now the target memory is actually initialised let target_buffer: &'static mut [u32; 20] = - unsafe { mem::transmute(&mut TARGET_BUFFER) }; + unsafe { TARGET_BUFFER.assume_init_mut() }; // Comparison check assert_eq!(&source_buffer_cloned, target_buffer); diff --git a/examples/ethernet-nucleo-h743zi2.rs b/examples/ethernet-nucleo-h743zi2.rs index 29fa24fc..917f56d8 100644 --- a/examples/ethernet-nucleo-h743zi2.rs +++ b/examples/ethernet-nucleo-h743zi2.rs @@ -13,6 +13,7 @@ #![no_std] extern crate cortex_m_rt as rt; +use core::mem::MaybeUninit; use core::sync::atomic::{AtomicU32, Ordering}; use rt::{entry, exception}; @@ -51,7 +52,8 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".sram3.eth"] -static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); +static mut DES_RING: MaybeUninit> = + MaybeUninit::uninit(); // the program entry point #[entry] @@ -112,6 +114,8 @@ fn main() -> ! { let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); let (_eth_dma, eth_mac) = unsafe { + DES_RING.write(ethernet::DesRing::new()); + ethernet::new( dp.ETHERNET_MAC, dp.ETHERNET_MTL, @@ -127,7 +131,7 @@ fn main() -> ! { rmii_txd0, rmii_txd1, ), - &mut DES_RING, + DES_RING.assume_init_mut(), mac_addr, ccdr.peripheral.ETH1MAC, &ccdr.clocks, diff --git a/examples/ethernet-rtic-nucleo-h723zg.rs b/examples/ethernet-rtic-nucleo-h723zg.rs index fb13fb8d..b155bec7 100644 --- a/examples/ethernet-rtic-nucleo-h723zg.rs +++ b/examples/ethernet-rtic-nucleo-h723zg.rs @@ -19,6 +19,8 @@ #[allow(unused)] mod utilities; +use core::mem::MaybeUninit; +use core::ptr::addr_of_mut; use core::sync::atomic::AtomicU32; use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage}; @@ -47,16 +49,17 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".axisram.eth"] -static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); +static mut DES_RING: MaybeUninit> = + MaybeUninit::uninit(); /// Net storage with static initialisation - another global singleton pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } -static mut STORE: NetStorageStatic = NetStorageStatic { - socket_storage: [SocketStorage::EMPTY; 8], -}; +// MaybeUninit allows us write code that is correct even if STORE is not +// initialised by the runtime +static mut STORE: MaybeUninit = MaybeUninit::uninit(); pub struct Net<'a> { iface: Interface, @@ -161,6 +164,8 @@ mod app { let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); let (eth_dma, eth_mac) = unsafe { + DES_RING.write(ethernet::DesRing::new()); + ethernet::new( ctx.device.ETHERNET_MAC, ctx.device.ETHERNET_MTL, @@ -176,7 +181,7 @@ mod app { rmii_txd0, rmii_txd1, ), - &mut DES_RING, + DES_RING.assume_init_mut(), mac_addr, ccdr.peripheral.ETH1MAC, &ccdr.clocks, @@ -192,7 +197,20 @@ mod app { unsafe { ethernet::enable_interrupt() }; // unsafe: mutable reference to static storage, we only do this once - let store = unsafe { &mut STORE }; + let store = unsafe { + let store_ptr = STORE.as_mut_ptr(); + + // Initialise the socket_storage field. Using `write` instead of + // assignment via `=` to not call `drop` on the old, uninitialised + // value + addr_of_mut!((*store_ptr).socket_storage) + .write([SocketStorage::EMPTY; 8]); + + // Now that all fields are initialised we can safely use + // assume_init_mut to return a mutable reference to STORE + STORE.assume_init_mut() + }; + let net = Net::new(store, eth_dma, mac_addr.into()); // 1ms tick diff --git a/examples/ethernet-rtic-stm32h735g-dk.rs b/examples/ethernet-rtic-stm32h735g-dk.rs index 033a8204..9cedf52b 100644 --- a/examples/ethernet-rtic-stm32h735g-dk.rs +++ b/examples/ethernet-rtic-stm32h735g-dk.rs @@ -45,7 +45,8 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".axisram.eth"] -static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); +static mut DES_RING: MaybeUninit> = + MaybeUninit::uninit(); // This data will be held by Net through a mutable reference pub struct NetStorageStatic<'a> { @@ -157,6 +158,8 @@ mod app { let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); let (eth_dma, eth_mac) = unsafe { + DES_RING.write(ethernet::DesRing::new()); + ethernet::new( ctx.device.ETHERNET_MAC, ctx.device.ETHERNET_MTL, @@ -172,7 +175,7 @@ mod app { rmii_txd0, rmii_txd1, ), - &mut DES_RING, + DES_RING.assume_init_mut(), mac_addr, ccdr.peripheral.ETH1MAC, &ccdr.clocks, diff --git a/examples/ethernet-rtic-stm32h747i-disco.rs b/examples/ethernet-rtic-stm32h747i-disco.rs index 7d6525d7..682fa111 100644 --- a/examples/ethernet-rtic-stm32h747i-disco.rs +++ b/examples/ethernet-rtic-stm32h747i-disco.rs @@ -52,7 +52,8 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".sram3.eth"] -static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); +static mut DES_RING: MaybeUninit> = + MaybeUninit::uninit(); // This data will be held by Net through a mutable reference pub struct NetStorageStatic<'a> { @@ -167,6 +168,8 @@ mod app { let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); let (eth_dma, eth_mac) = unsafe { + DES_RING.write(ethernet::DesRing::new()); + ethernet::new( ctx.device.ETHERNET_MAC, ctx.device.ETHERNET_MTL, @@ -182,7 +185,7 @@ mod app { rmii_txd0, rmii_txd1, ), - &mut DES_RING, + DES_RING.assume_init_mut(), mac_addr, ccdr.peripheral.ETH1MAC, &ccdr.clocks, diff --git a/examples/ethernet-stm32h747i-disco.rs b/examples/ethernet-stm32h747i-disco.rs index 206c4e43..e4c1a199 100644 --- a/examples/ethernet-stm32h747i-disco.rs +++ b/examples/ethernet-stm32h747i-disco.rs @@ -11,6 +11,7 @@ #![no_main] #![no_std] +use core::mem::MaybeUninit; use cortex_m_rt as rt; use rt::{entry, exception}; @@ -28,7 +29,8 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".sram3.eth"] -static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new(); +static mut DES_RING: MaybeUninit> = + MaybeUninit::uninit(); // the program entry point #[entry] @@ -85,6 +87,8 @@ fn main() -> ! { let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); let (_eth_dma, eth_mac) = unsafe { + DES_RING.write(ethernet::DesRing::new()); + ethernet::new( dp.ETHERNET_MAC, dp.ETHERNET_MTL, @@ -100,7 +104,7 @@ fn main() -> ! { rmii_txd0, rmii_txd1, ), - &mut DES_RING, + DES_RING.assume_init_mut(), mac_addr, ccdr.peripheral.ETH1MAC, &ccdr.clocks, diff --git a/examples/i2c4_bdma.rs b/examples/i2c4_bdma.rs index 9dc012e7..2bd2fc40 100644 --- a/examples/i2c4_bdma.rs +++ b/examples/i2c4_bdma.rs @@ -2,12 +2,11 @@ //! //! -#![allow(clippy::transmute_ptr_to_ptr)] #![deny(warnings)] #![no_std] #![no_main] -use core::{mem, mem::MaybeUninit}; +use core::mem::MaybeUninit; #[macro_use] mod utilities; @@ -93,13 +92,14 @@ fn main() -> ! { let config = BdmaConfig::default().memory_increment(true); // We need to specify the direction with a type annotation - let mut transfer: Transfer<_, _, PeripheralToMemory, _, _> = Transfer::init( - streams.0, - i2c, - unsafe { &mut BUFFER }, // uninitialised memory - None, - config, - ); + let mut transfer: Transfer<_, _, PeripheralToMemory, &mut [u8; 10], _> = + Transfer::init( + streams.0, + i2c, + unsafe { BUFFER.assume_init_mut() }, // uninitialised memory + None, + config, + ); transfer.start(|i2c| { // This closure runs right after enabling the stream @@ -128,7 +128,7 @@ fn I2C4_EV() { info!("I2C transfer complete!"); // Look at BUFFER, which we expect to be initialised - let buffer: &'static mut [u8; 10] = unsafe { mem::transmute(&mut BUFFER) }; + let buffer: &'static [u8; 10] = unsafe { BUFFER.assume_init_mut() }; assert_eq!(buffer[0], 0xBE); diff --git a/examples/mdma.rs b/examples/mdma.rs index 8bb7853a..1b3451af 100644 --- a/examples/mdma.rs +++ b/examples/mdma.rs @@ -1,6 +1,5 @@ //! Example of Memory to Memory Transfer with the Master DMA (MDMA) -#![allow(clippy::transmute_ptr_to_ptr)] #![deny(warnings)] #![no_main] #![no_std] @@ -52,15 +51,17 @@ fn main() -> ! { // Initialise the source buffer without taking any references to // uninitialisated memory let source_buffer: &'static mut [u32; 200] = { - let buf: &mut [MaybeUninit; 200] = - unsafe { mem::transmute(&mut SOURCE_BUFFER) }; + let buf: &mut [MaybeUninit; 200] = unsafe { + &mut *(core::ptr::addr_of_mut!(SOURCE_BUFFER) + as *mut [MaybeUninit; 200]) + }; for value in buf.iter_mut() { unsafe { value.as_mut_ptr().write(0x11223344u32); } } - unsafe { mem::transmute(buf) } + unsafe { SOURCE_BUFFER.assume_init_mut() } }; // @@ -104,8 +105,7 @@ fn main() -> ! { while !transfer.get_transfer_complete_flag() {} // Decompose the stream to get the source buffer back - let (stream, _mem2mem, _target, source_buffer_opt) = transfer.free(); - let source_buffer = source_buffer_opt.unwrap(); + let (stream, _mem2mem, _target, _) = transfer.free(); for a in target_buffer.iter() { assert_eq!(*a, 0x11223344); @@ -118,6 +118,7 @@ fn main() -> ! { // // Reset source buffer + let source_buffer = unsafe { SOURCE_BUFFER.assume_init_mut() }; *source_buffer = [0xAABBCCDD; 200]; // New target buffer on the stack diff --git a/examples/mdma_bursts.rs b/examples/mdma_bursts.rs index 32233500..784fcb74 100644 --- a/examples/mdma_bursts.rs +++ b/examples/mdma_bursts.rs @@ -5,12 +5,11 @@ //! This example demonstrates a transfer with 1 beat/burst, and a 32 //! beats/burst. The latter gives an approximately 25% speedup. -#![allow(clippy::transmute_ptr_to_ptr)] #![deny(warnings)] #![no_main] #![no_std] -use core::{mem, mem::MaybeUninit}; +use core::mem::MaybeUninit; use cortex_m_rt::entry; #[macro_use] @@ -64,15 +63,17 @@ fn main() -> ! { // Initialise the source buffer without taking any references to // uninitialisated memory let _source_buffer: &'static mut [u32; 200] = { - let buf: &mut [MaybeUninit; 200] = - unsafe { mem::transmute(&mut SOURCE_BUFFER) }; + let buf: &mut [MaybeUninit; 200] = unsafe { + &mut *(core::ptr::addr_of_mut!(SOURCE_BUFFER) + as *mut [MaybeUninit; 200]) + }; for value in buf.iter_mut() { unsafe { value.as_mut_ptr().write(0x11223344u32); } } - unsafe { mem::transmute(buf) } + unsafe { SOURCE_BUFFER.assume_init_mut() } }; // Setup DMA @@ -89,9 +90,9 @@ fn main() -> ! { // unsafe: Both source and destination live at least as long as this // transfer let source: &'static mut [u32; 200] = - unsafe { mem::transmute(&mut SOURCE_BUFFER) }; + unsafe { SOURCE_BUFFER.assume_init_mut() }; let target: &'static mut [u32; 200] = - unsafe { mem::transmute(&mut TARGET_BUFFER) }; + unsafe { TARGET_BUFFER.assume_init_mut() }; // uninitialised memory Transfer::init_master( stream, @@ -125,8 +126,7 @@ fn main() -> ! { } // Decompose the stream to get the buffers back - let (_stream0, _mem2mem, target_buffer, _source_buffer_opt) = - transfer.free(); + let (_stream0, _mem2mem, target_buffer, _) = transfer.free(); for a in target_buffer.iter() { assert_eq!(*a, 0x11223344); diff --git a/examples/sai_dma_passthru.rs b/examples/sai_dma_passthru.rs index 34bb0fc9..ca6c14c9 100644 --- a/examples/sai_dma_passthru.rs +++ b/examples/sai_dma_passthru.rs @@ -6,6 +6,8 @@ #![no_main] #![no_std] +use core::mem::MaybeUninit; + use cortex_m::asm; use cortex_m_rt::entry; @@ -43,9 +45,11 @@ const PLL3_P_HZ: Hertz = Hertz::from_raw(AUDIO_SAMPLE_HZ.raw() * 257); // = static data ============================================================== #[link_section = ".sram3"] -static mut TX_BUFFER: [u32; DMA_BUFFER_LENGTH] = [0; DMA_BUFFER_LENGTH]; +static mut TX_BUFFER: MaybeUninit<[u32; DMA_BUFFER_LENGTH]> = + MaybeUninit::uninit(); #[link_section = ".sram3"] -static mut RX_BUFFER: [u32; DMA_BUFFER_LENGTH] = [0; DMA_BUFFER_LENGTH]; +static mut RX_BUFFER: MaybeUninit<[u32; DMA_BUFFER_LENGTH]> = + MaybeUninit::uninit(); pub const CLOCK_RATE_HZ: Hertz = Hertz::MHz(400); const HSE_CLOCK_MHZ: Hertz = Hertz::MHz(16); @@ -107,7 +111,7 @@ fn main() -> ! { // dma1 stream 0 let tx_buffer: &'static mut [u32; DMA_BUFFER_LENGTH] = - unsafe { &mut TX_BUFFER }; + unsafe { TX_BUFFER.assume_init_mut() }; // uninitialised memory let dma_config = dma::dma::DmaConfig::default() .priority(dma::config::Priority::High) .memory_increment(true) @@ -125,7 +129,7 @@ fn main() -> ! { // dma1 stream 1 let rx_buffer: &'static mut [u32; DMA_BUFFER_LENGTH] = - unsafe { &mut RX_BUFFER }; + unsafe { RX_BUFFER.assume_init_mut() }; // uninitialised memory let dma_config = dma_config .transfer_complete_interrupt(true) .half_transfer_interrupt(true); @@ -172,6 +176,12 @@ fn main() -> ! { pac::NVIC::unmask(pac::Interrupt::DMA1_STR1); } + static mut TRANSFER_DMA1_STR1: MaybeUninit> = + MaybeUninit::uninit(); + unsafe { + TRANSFER_DMA1_STR1.write(None); + } + dma1_str1.start(|_sai1_rb| { sai1.enable_dma(SaiChannel::ChannelB); }); @@ -209,25 +219,26 @@ fn main() -> ! { dma::DBTransfer, >; - static mut TRANSFER_DMA1_STR1: Option = None; unsafe { - TRANSFER_DMA1_STR1 = Some(dma1_str1); + TRANSFER_DMA1_STR1.write(Some(dma1_str1)); // drops previous None info!( "{:?}, {:?}", - &TX_BUFFER[0] as *const u32, &RX_BUFFER[0] as *const u32 + TX_BUFFER.assume_init()[0] as *const u32, + RX_BUFFER.assume_init()[0] as *const u32 ); } #[interrupt] fn DMA1_STR1() { let tx_buffer: &'static mut [u32; DMA_BUFFER_LENGTH] = - unsafe { &mut TX_BUFFER }; + unsafe { TX_BUFFER.assume_init_mut() }; let rx_buffer: &'static mut [u32; DMA_BUFFER_LENGTH] = - unsafe { &mut RX_BUFFER }; + unsafe { RX_BUFFER.assume_init_mut() }; let stereo_block_length = tx_buffer.len() / 2; - if let Some(transfer) = unsafe { &mut TRANSFER_DMA1_STR1 } { + if let Some(transfer) = unsafe { TRANSFER_DMA1_STR1.assume_init_mut() } + { let skip = if transfer.get_half_transfer_flag() { transfer.clear_half_transfer_interrupt(); (0, stereo_block_length) diff --git a/examples/serial-dma.rs b/examples/serial-dma.rs index 76fee88b..c61a36e2 100644 --- a/examples/serial-dma.rs +++ b/examples/serial-dma.rs @@ -7,7 +7,6 @@ //! into chunks and using the `next_transfer_with` method to start each part of //! the transfer. -#![allow(clippy::transmute_ptr_to_ptr)] #![deny(warnings)] #![no_main] #![no_std] @@ -83,26 +82,28 @@ fn main() -> ! { // uninitialised memory let short_buffer: &'static mut [u8; 10] = { let buf: &mut [MaybeUninit; 10] = - unsafe { mem::transmute(&mut SHORT_BUFFER) }; + unsafe { &mut *(core::ptr::addr_of_mut!(SHORT_BUFFER) as *mut _) }; for (i, value) in buf.iter_mut().enumerate() { unsafe { value.as_mut_ptr().write(i as u8 + 96); // 0x60, 0x61, 0x62... } } - unsafe { mem::transmute(buf) } + unsafe { SHORT_BUFFER.assume_init_mut() } }; // view u32 buffer as u8. Endianess is undefined (little-endian on STM32H7) let long_buffer: &'static mut [u8; 0x2_0010] = { let buf: &mut [MaybeUninit; 0x8004] = - unsafe { mem::transmute(&mut LONG_BUFFER) }; + unsafe { &mut *(core::ptr::addr_of_mut!(LONG_BUFFER) as *mut _) }; for (i, value) in buf.iter_mut().enumerate() { unsafe { value.as_mut_ptr().write(i as u32); } } - unsafe { mem::transmute(buf) } + unsafe { + &mut *(core::ptr::addr_of_mut!(LONG_BUFFER) as *mut [u8; 0x2_0010]) + } }; // Setup the DMA transfer on stream 0 diff --git a/examples/spi-dma-rtic.rs b/examples/spi-dma-rtic.rs index 7e6ae909..bd78229c 100644 --- a/examples/spi-dma-rtic.rs +++ b/examples/spi-dma-rtic.rs @@ -97,7 +97,7 @@ mod app { // Initialize our transmit buffer. let buffer: &'static mut [u8; BUFFER_SIZE] = { let buf: &mut [MaybeUninit; BUFFER_SIZE] = unsafe { - &mut *(&mut BUFFER as *mut MaybeUninit<[u8; BUFFER_SIZE]> + &mut *(core::ptr::addr_of_mut!(BUFFER) as *mut [MaybeUninit; BUFFER_SIZE]) }; @@ -107,10 +107,7 @@ mod app { } } - unsafe { - &mut *(buf as *mut [MaybeUninit; BUFFER_SIZE] - as *mut [u8; BUFFER_SIZE]) - } + unsafe { BUFFER.assume_init_mut() } }; let streams = hal::dma::dma::StreamsTuple::new( diff --git a/examples/spi-dma.rs b/examples/spi-dma.rs index 0bd91de0..b3a59a2e 100644 --- a/examples/spi-dma.rs +++ b/examples/spi-dma.rs @@ -7,7 +7,6 @@ //! into chunks and using the `next_transfer_with` method to start each part of //! the transfer. -#![allow(clippy::transmute_ptr_to_ptr)] #![deny(warnings)] #![no_main] #![no_std] @@ -85,26 +84,28 @@ fn main() -> ! { // uninitialisated memory let short_buffer: &'static mut [u8; 10] = { let buf: &mut [MaybeUninit; 10] = - unsafe { mem::transmute(&mut SHORT_BUFFER) }; + unsafe { &mut *(core::ptr::addr_of_mut!(SHORT_BUFFER) as *mut _) }; for (i, value) in buf.iter_mut().enumerate() { unsafe { value.as_mut_ptr().write(i as u8 + 96); // 0x60, 0x61, 0x62... } } - unsafe { mem::transmute(buf) } + unsafe { SHORT_BUFFER.assume_init_mut() } }; // view u32 buffer as u8. Endianess is undefined (little-endian on STM32H7) let long_buffer: &'static mut [u8; 0x2_0010] = { let buf: &mut [MaybeUninit; 0x8004] = - unsafe { mem::transmute(&mut LONG_BUFFER) }; + unsafe { &mut *(core::ptr::addr_of_mut!(LONG_BUFFER) as *mut _) }; for (i, value) in buf.iter_mut().enumerate() { unsafe { value.as_mut_ptr().write(i as u32); } } - unsafe { mem::transmute(buf) } + unsafe { + &mut *(core::ptr::addr_of_mut!(LONG_BUFFER) as *mut [u8; 0x2_0010]) + } }; // Setup the DMA transfer on stream 0 diff --git a/examples/usb_passthrough.rs b/examples/usb_passthrough.rs index 89440baa..f7f68f80 100644 --- a/examples/usb_passthrough.rs +++ b/examples/usb_passthrough.rs @@ -4,11 +4,14 @@ //! //! This example uses both USB1 and USB2. This is only possible on devices that //! have the USB2 peripheral. +#![deny(warnings)] #![no_std] #![no_main] use panic_itm as _; +use core::mem::MaybeUninit; + use cortex_m_rt::entry; use stm32h7xx_hal::rcc::rec::UsbClkSel; @@ -17,8 +20,8 @@ use stm32h7xx_hal::{prelude::*, stm32}; use usb_device::prelude::*; -static mut EP_MEMORY_1: [u32; 1024] = [0; 1024]; -static mut EP_MEMORY_2: [u32; 1024] = [0; 1024]; +static mut EP_MEMORY_1: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit(); +static mut EP_MEMORY_2: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit(); #[entry] fn main() -> ! { @@ -68,8 +71,25 @@ fn main() -> ! { &ccdr.clocks, ); + // Initialise EP_MEMORY_1 to zero + unsafe { + let buf: &mut [MaybeUninit; 1024] = + &mut *(core::ptr::addr_of_mut!(EP_MEMORY_1) as *mut _); + for value in buf.iter_mut() { + value.as_mut_ptr().write(0); + } + } + // Initialise EP_MEMORY_2 to zero + unsafe { + let buf: &mut [MaybeUninit; 1024] = + &mut *(core::ptr::addr_of_mut!(EP_MEMORY_2) as *mut _); + for value in buf.iter_mut() { + value.as_mut_ptr().write(0); + } + } + // Port 1 - let usb1_bus = UsbBus::new(usb1, unsafe { &mut EP_MEMORY_1 }); + let usb1_bus = UsbBus::new(usb1, unsafe { EP_MEMORY_1.assume_init_mut() }); let mut serial1 = usbd_serial::SerialPort::new(&usb1_bus); let mut usb1_dev = UsbDeviceBuilder::new(&usb1_bus, UsbVidPid(0x16c0, 0x27dd)) @@ -82,7 +102,7 @@ fn main() -> ! { .build(); // Port 2 - let usb2_bus = UsbBus::new(usb2, unsafe { &mut EP_MEMORY_2 }); + let usb2_bus = UsbBus::new(usb2, unsafe { EP_MEMORY_2.assume_init_mut() }); let mut serial2 = usbd_serial::SerialPort::new(&usb2_bus); let mut usb2_dev = UsbDeviceBuilder::new(&usb2_bus, UsbVidPid(0x16c0, 0x27dd)) diff --git a/examples/usb_phy_serial_interrupt.rs b/examples/usb_phy_serial_interrupt.rs index 4ed5d4f4..b3f550be 100644 --- a/examples/usb_phy_serial_interrupt.rs +++ b/examples/usb_phy_serial_interrupt.rs @@ -2,11 +2,13 @@ //! //! This example is for RM0433/RM0399 parts. It has been tested on the Arduino //! Portenta H7 +#![deny(warnings)] #![no_std] #![no_main] use { core::cell::RefCell, + core::mem::MaybeUninit, cortex_m::interrupt::{free as interrupt_free, Mutex}, stm32h7xx_hal::{ interrupt, pac, @@ -27,7 +29,7 @@ mod utilities; pub const VID: u16 = 0x2341; pub const PID: u16 = 0x025b; -pub static mut USB_MEMORY_1: [u32; 1024] = [0u32; 1024]; +pub static mut USB_MEMORY_1: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit(); pub static mut USB_BUS_ALLOCATOR: Option>> = None; pub static SERIAL_PORT: Mutex< @@ -143,7 +145,16 @@ unsafe fn main() -> ! { &ccdr.clocks, ); - USB_BUS_ALLOCATOR = Some(UsbBus::new(usb, &mut USB_MEMORY_1)); + // Initialise USB_MEMORY_1 to zero + { + let buf: &mut [MaybeUninit; 1024] = + &mut *(core::ptr::addr_of_mut!(USB_MEMORY_1) as *mut _); + for value in buf.iter_mut() { + value.as_mut_ptr().write(0); + } + } + + USB_BUS_ALLOCATOR = Some(UsbBus::new(usb, USB_MEMORY_1.assume_init_mut())); let usb_serial = usbd_serial::SerialPort::new(USB_BUS_ALLOCATOR.as_ref().unwrap()); diff --git a/examples/usb_rtic.rs b/examples/usb_rtic.rs index aa1e99b9..418bb8b6 100644 --- a/examples/usb_rtic.rs +++ b/examples/usb_rtic.rs @@ -15,6 +15,7 @@ mod utilities; #[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true)] mod app { + use core::mem::MaybeUninit; use stm32h7xx_hal::gpio::gpioe::PE1; use stm32h7xx_hal::gpio::{Output, PushPull}; use stm32h7xx_hal::prelude::*; @@ -22,7 +23,7 @@ mod app { use stm32h7xx_hal::usb_hs::{UsbBus, USB1}; use usb_device::prelude::*; - static mut EP_MEMORY: [u32; 1024] = [0; 1024]; + static mut EP_MEMORY: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit(); use super::utilities; #[shared] @@ -84,9 +85,19 @@ mod app { &ccdr.clocks, ); + // Initialise EP_MEMORY to zero + unsafe { + let buf: &mut [MaybeUninit; 1024] = + &mut *(core::ptr::addr_of_mut!(EP_MEMORY) as *mut _); + for value in buf.iter_mut() { + value.as_mut_ptr().write(0); + } + } + + // Now we may assume that EP_MEMORY is initialised let usb_bus = cortex_m::singleton!( : usb_device::class_prelude::UsbBusAllocator> = - UsbBus::new(usb, unsafe { &mut EP_MEMORY }) + UsbBus::new(usb, unsafe { EP_MEMORY.assume_init_mut() }) ) .unwrap(); let serial = usbd_serial::SerialPort::new(usb_bus); diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs index 951627da..ed9100b4 100644 --- a/examples/usb_serial.rs +++ b/examples/usb_serial.rs @@ -8,9 +8,12 @@ //! to use the USB2 peripheral together with PA11 and PA12. This applies to the //! NUCLEO-H743ZI2 board. //! +#![deny(warnings)] #![no_std] #![no_main] +use core::mem::MaybeUninit; + #[macro_use] #[allow(unused)] mod utilities; @@ -23,7 +26,7 @@ use stm32h7xx_hal::{prelude::*, stm32}; use usb_device::prelude::*; -static mut EP_MEMORY: [u32; 1024] = [0; 1024]; +static mut EP_MEMORY: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit(); #[entry] fn main() -> ! { @@ -72,7 +75,17 @@ fn main() -> ! { &ccdr.clocks, ); - let usb_bus = UsbBus::new(usb, unsafe { &mut EP_MEMORY }); + // Initialise EP_MEMORY to zero + unsafe { + let buf: &mut [MaybeUninit; 1024] = + &mut *(core::ptr::addr_of_mut!(EP_MEMORY) as *mut _); + for value in buf.iter_mut() { + value.as_mut_ptr().write(0); + } + } + + // Now we may assume that EP_MEMORY is initialised + let usb_bus = UsbBus::new(usb, unsafe { EP_MEMORY.assume_init_mut() }); let mut serial = usbd_serial::SerialPort::new(&usb_bus); From c79922ce79053699959a9ec8d5285988ac8fc6f3 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 20 Jan 2024 23:08:45 +0100 Subject: [PATCH 64/75] Tidy clippy lints --- examples/sdmmc.rs | 2 +- examples/usb_phy_serial_interrupt.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/sdmmc.rs b/examples/sdmmc.rs index 73dd3417..206a6c0b 100644 --- a/examples/sdmmc.rs +++ b/examples/sdmmc.rs @@ -41,7 +41,7 @@ fn main() -> ! { let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD); // STM32H747I-DISCO development board - #[cfg(any(feature = "rm0399"))] + #[cfg(feature = "rm0399")] let mut led = { let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI); diff --git a/examples/usb_phy_serial_interrupt.rs b/examples/usb_phy_serial_interrupt.rs index b3f550be..88b7d891 100644 --- a/examples/usb_phy_serial_interrupt.rs +++ b/examples/usb_phy_serial_interrupt.rs @@ -3,6 +3,7 @@ //! This example is for RM0433/RM0399 parts. It has been tested on the Arduino //! Portenta H7 #![deny(warnings)] +#![allow(clippy::type_complexity)] #![no_std] #![no_main] From 4586b6fb0b7933baf09467ee3871a327c974e3af Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Wed, 31 Jan 2024 21:36:38 +0100 Subject: [PATCH 65/75] examples/i2c4_bdma: Initialise target buffer --- examples/i2c4_bdma.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/i2c4_bdma.rs b/examples/i2c4_bdma.rs index 2bd2fc40..e6402567 100644 --- a/examples/i2c4_bdma.rs +++ b/examples/i2c4_bdma.rs @@ -91,12 +91,20 @@ fn main() -> ! { let config = BdmaConfig::default().memory_increment(true); + // Initialise buffer + unsafe { + // Convert an uninitialised array into an array of uninitialised + let buf: &mut [core::mem::MaybeUninit; 10] = + &mut *(core::ptr::addr_of_mut!(BUFFER) as *mut _); + buf.iter_mut().for_each(|x| x.as_mut_ptr().write(0)); + } + // We need to specify the direction with a type annotation let mut transfer: Transfer<_, _, PeripheralToMemory, &mut [u8; 10], _> = Transfer::init( streams.0, i2c, - unsafe { BUFFER.assume_init_mut() }, // uninitialised memory + unsafe { BUFFER.assume_init_mut() }, None, config, ); From 2bcf2af62fa4ff5092bbbc6d2790beb3c04e8116 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Wed, 31 Jan 2024 21:43:06 +0100 Subject: [PATCH 66/75] Add note where TARGET_BUFFER should be initialised (but is not) --- examples/dma.rs | 3 +++ examples/mdma_bursts.rs | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/dma.rs b/examples/dma.rs index 730a2c5b..c1ec1762 100644 --- a/examples/dma.rs +++ b/examples/dma.rs @@ -71,6 +71,9 @@ fn main() -> ! { // Save a copy on the stack so we can check it later let source_buffer_cloned = *source_buffer; + // NOTE(unsafe): TARGET_BUFFER must also be initialised to prevent undefined + // behaviour (taking a mutable reference to uninitialised memory) + // Setup DMA // // We need to specify the transfer size with a type annotation diff --git a/examples/mdma_bursts.rs b/examples/mdma_bursts.rs index 784fcb74..bfcd6083 100644 --- a/examples/mdma_bursts.rs +++ b/examples/mdma_bursts.rs @@ -61,7 +61,7 @@ fn main() -> ! { info!(""); // Initialise the source buffer without taking any references to - // uninitialisated memory + // uninitialised memory let _source_buffer: &'static mut [u32; 200] = { let buf: &mut [MaybeUninit; 200] = unsafe { &mut *(core::ptr::addr_of_mut!(SOURCE_BUFFER) @@ -76,6 +76,9 @@ fn main() -> ! { unsafe { SOURCE_BUFFER.assume_init_mut() } }; + // NOTE(unsafe): TARGET_BUFFER must also be initialised to prevent undefined + // behaviour (taking a mutable reference to uninitialised memory) + // Setup DMA let streams = StreamsTuple::new(dp.MDMA, ccdr.peripheral.MDMA); From a2ef40c8183d9aef67b2a9e636e0e77069446992 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 20 Jan 2024 22:23:20 +0100 Subject: [PATCH 67/75] Add support for TIM23 and TIM24 found on RM0468 parts --- src/pwm.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++- src/rcc/rec.rs | 4 ++- src/timer.rs | 12 +++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 4d5833ea..ef6baae0 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -915,6 +915,56 @@ pins! { ] } +// Quad channel timers (RM0468) +#[cfg(feature = "rm0468")] +pins! { + pac::TIM23: + CH1(ComplementaryImpossible): [ + gpio::PG12>, + gpio::PF0>, + gpio::PF6> + ] + CH2(ComplementaryImpossible): [ + gpio::PG13>, + gpio::PF1>, + gpio::PF7> + ] + CH3(ComplementaryImpossible): [ + gpio::PG14>, + gpio::PF2>, + gpio::PF8> + ] + CH4(ComplementaryImpossible): [ + gpio::PF3>, + gpio::PF9> + ] + CH1N: [] + CH2N: [] + CH3N: [] + CH4N: [] + BRK: [] + BRK2: [] + pac::TIM24: + CH1(ComplementaryImpossible): [ + gpio::PF11> + ] + CH2(ComplementaryImpossible): [ + gpio::PF12> + ] + CH3(ComplementaryImpossible): [ + gpio::PF13> + ] + CH4(ComplementaryImpossible): [ + gpio::PF14> + ] + CH1N: [] + CH2N: [] + CH3N: [] + CH4N: [] + BRK: [] + BRK2: [] +} + // Period and prescaler calculator for 32-bit timers // Returns (arr, psc) fn calculate_frequency_32bit( @@ -1369,6 +1419,11 @@ tim_hal! { pac::TIM5: (tim5, Tim5, u32, 32, DIR: cms), pac::TIM8: (tim8, Tim8, u16, 16, DIR: cms, BDTR: bdtr, enabled, af1, clear_bit, clear_bit), } +#[cfg(feature = "rm0468")] +tim_hal! { + pac::TIM23: (tim23, Tim23, u32, 32, DIR: cms), + pac::TIM24: (tim24, Tim24, u32, 32, DIR: cms), +} tim_hal! { pac::TIM12: (tim12, Tim12, u16, 16), pac::TIM13: (tim13, Tim13, u16, 16), @@ -1621,7 +1676,6 @@ tim_pin_hal! { (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } -// Quad channel timers tim_pin_hal! { pac::TIM8, u16: (C1, ccmr1_output, oc1pe, oc1m), @@ -1629,6 +1683,22 @@ tim_pin_hal! { (C3, ccmr2_output, oc3pe, oc3m), (C4, ccmr2_output, oc4pe, oc4m), } +#[cfg(feature = "rm0468")] +tim_pin_hal! { + pac::TIM23, u32: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} +#[cfg(feature = "rm0468")] +tim_pin_hal! { + pac::TIM24, u32: + (C1, ccmr1_output, oc1pe, oc1m), + (C2, ccmr1_output, oc2pe, oc2m), + (C3, ccmr2_output, oc3pe, oc3m), + (C4, ccmr2_output, oc4pe, oc4m), +} // Low-power timers macro_rules! lptim_hal { diff --git a/src/rcc/rec.rs b/src/rcc/rec.rs index e2cc75d6..a4533f77 100644 --- a/src/rcc/rec.rs +++ b/src/rcc/rec.rs @@ -639,7 +639,9 @@ peripheral_reset_and_enable_control! { ]; #[cfg(feature = "rm0468")] APB1H, "" => [ - Swpmi [kernel clk: Swpmi d2ccip1 "SWPMI"] + Swpmi [kernel clk: Swpmi d2ccip1 "SWPMI"], + + Tim23, Tim24 ]; diff --git a/src/timer.rs b/src/timer.rs index c6fa59aa..bd525cf5 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -22,6 +22,8 @@ use crate::stm32::{ TIM1, TIM12, TIM13, TIM14, TIM15, TIM16, TIM17, TIM2, TIM3, TIM4, TIM5, TIM6, TIM7, TIM8, }; +#[cfg(feature = "rm0468")] +use crate::stm32::{TIM23, TIM24}; use cast::{u16, u32}; use void::Void; @@ -58,6 +60,10 @@ impl_tim_ker_ck! { timx_ker_ck: TIM2, TIM3, TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14 timy_ker_ck: TIM1, TIM8, TIM15, TIM16, TIM17 } +#[cfg(feature = "rm0468")] +impl_tim_ker_ck! { + timx_ker_ck: TIM23, TIM24 +} /// LPTIM1 Kernel Clock impl GetClk for LPTIM1 { @@ -591,6 +597,12 @@ hal! { TIM16: (tim16, Tim16, u16), TIM17: (tim17, Tim17, u16), } +#[cfg(feature = "rm0468")] +hal! { + // General-purpose + TIM23: (tim23, Tim23, u32), + TIM24: (tim24, Tim24, u32), +} macro_rules! lptim_hal { ($($TIMX:ident: ($timx:ident, $Rec:ident, $timXpac:ident),)+) => { From 03b8dcf0fd5dcce324e557830838eff729cfeecb Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 20 Jan 2024 22:21:59 +0100 Subject: [PATCH 68/75] Tidy `cargo doc` warnings, fix links in rcc --- src/adc.rs | 4 ++-- src/delay.rs | 11 +++++------ src/dma/mdma.rs | 8 ++++---- src/dma/mod.rs | 4 ++-- src/lib.rs | 2 +- src/rcc/mod.rs | 9 ++++----- 6 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index f07391c1..2acb56f1 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -1,7 +1,7 @@ //! Analog to Digital Converter (ADC) //! //! ADC1 and ADC2 share a reset line. To initialise both of them, use the -//! [`adc12`](adc12) method. +//! [`adc12`] method. //! //! # Examples //! @@ -999,7 +999,7 @@ macro_rules! adc_hal { /// Set ADC sampling time /// - /// Options can be found in [AdcSampleTime](crate::adc::AdcSampleTime). + /// Options can be found in [AdcSampleTime]. pub fn set_sample_time(&mut self, t_samp: AdcSampleTime) { self.sample_time = t_samp; } diff --git a/src/delay.rs b/src/delay.rs index 42f5b13a..31478806 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -1,11 +1,10 @@ //! Delay providers //! //! There are currently two delay providers. In general you should prefer to use -//! [Delay](Delay), however if you do not have access to `SYST` you can use -//! [DelayFromCountDownTimer](DelayFromCountDownTimer) with any timer that -//! implements the [CountDown](embedded_hal::timer::CountDown) trait. This can be -//! useful if you're using [RTIC](https://rtic.rs)'s schedule API, which occupies -//! the `SYST` peripheral. +//! [Delay], however if you do not have access to `SYST` you can use +//! [DelayFromCountDownTimer] with any timer that implements the [CountDown] +//! trait. This can be useful if you're using [RTIC](https://rtic.rs)'s schedule +//! API, which occupies the `SYST` peripheral. //! //! # Examples //! @@ -68,7 +67,7 @@ pub struct Delay { syst: SYST, } -/// Implements [CountDown](embedded_hal::timer::CountDown) for the System timer (SysTick). +/// Implements [CountDown] for the System timer (SysTick). pub struct Countdown<'a> { clocks: CoreClocks, syst: &'a mut SYST, diff --git a/src/dma/mdma.rs b/src/dma/mdma.rs index 52d884fb..49f7b53f 100644 --- a/src/dma/mdma.rs +++ b/src/dma/mdma.rs @@ -44,10 +44,10 @@ //! Unlike DMA1/DMA2, it is valid to assign the same request line to multiple //! MDMA streams. Additionally there are multiple requests lines to choose from //! for each target peripheral. For this reason, hardware request lines are -//! specified as part of the [`MdmaConfig`](MdmaConfig) instead of being -//! inferred from the peripheral type. If no hardware request line is specified, -//! then the request line originates from software and the transfer is started -//! immediately when [`enable`](Stream0#method.enable) is called. +//! specified as part of the [`MdmaConfig`] instead of being inferred from the +//! peripheral type. If no hardware request line is specified, then the request +//! line originates from software and the transfer is started immediately when +//! [`enable`](Stream0#method.enable) is called. //! //! diff --git a/src/dma/mod.rs b/src/dma/mod.rs index 6359792d..6bfe475c 100644 --- a/src/dma/mod.rs +++ b/src/dma/mod.rs @@ -19,14 +19,14 @@ //! //! The following table summarizes the available DMA controllers //! -//! | Controller | Accessible Memories | Peripheral [TargetAddress](traits::TargetAddress) Implementations | Double Buffering Supported ? | Number of DMA Streams | Initialization Method +//! | Controller | Accessible Memories | Peripheral [TargetAddress] Implementations | Double Buffering Supported ? | Number of DMA Streams | Initialization Method //! | --- | --- | --- | --- | --- | --- //! | [MDMA](mdma) | All | `QUADSPI`, .. | No |16| [Transfer::init_master](Transfer#method.init_master) //! | [DMA1](dma) | AXISRAM, SRAM1/2/3/4 | all others [^notimpl] | Yes |8| [Transfer::init](Transfer#method.init) //! | [DMA2](dma) | AXISRAM, SRAM1/2/3/4 | all others [^notimpl] | Yes |8| [Transfer::init](Transfer#method.init) //! | [BDMA](bdma) | SRAM4 [^rm0455bdma] | `LPUART1`, `SPI6`, `I2C4`, `SAI4` | Yes |8| [Transfer::init](Transfer#method.init) //! -//! [^notimpl]: [TargetAddress](traits::TargetAddress) is not yet implemented +//! [^notimpl]: [TargetAddress] is not yet implemented //! for many peripherals //! //! [^rm0455bdma]: On 7B3/7A3/7B0 parts there are two BDMA controllers. BDMA1 diff --git a/src/lib.rs b/src/lib.rs index fd63fb5e..299a33db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ //! //! * [Direct Memory Access (DMA)](crate::dma) //! * [Cyclic Redundancy Check (CRC)](crate::crc) Feature gate `crc` -//! * [Random Number Generator](crate::rng) ([rand_core::RngCore](rand_core::RngCore) is implemented under the `rand` feature gate) +//! * [Random Number Generator](crate::rng) ([rand_core::RngCore] is implemented under the `rand` feature gate) //! * [Embedded Flash Memory](crate::flash) //! * [System Window Watchdog](crate::system_watchdog) //! * [Independent Watchdog](crate::independent_watchdog) diff --git a/src/rcc/mod.rs b/src/rcc/mod.rs index 34032115..0d7c6015 100644 --- a/src/rcc/mod.rs +++ b/src/rcc/mod.rs @@ -108,10 +108,9 @@ //! # Peripherals //! //! The `freeze()` method returns a [Core Clocks Distribution and Reset -//! (CCDR)](struct.Ccdr.html) object. This singleton tells you how the core -//! clocks were actually configured (in [CoreClocks](struct.CoreClocks.html)) -//! and allows you to configure the remaining peripherals (see -//! [PeripheralREC](crate::rcc::rec::struct.PeripheralREC.html)). +//! (CCDR)](Ccdr) object. This singleton tells you how the core clocks were +//! actually configured (in [CoreClocks]) and allows you to configure the +//! remaining peripherals (see [PeripheralREC]). //! //!```rust //! let ccdr = ...; // Returned by `freeze()`, see examples above @@ -126,7 +125,7 @@ //! ccdr.peripheral.FDCAN.enable().reset(); //!``` //! -//! The [PeripheralREC](struct.PeripheralREC.html) members implement move +//! The [PeripheralREC] members implement move //! semantics, so once you have passed them to a constructor they cannot be //! modified again in safe Rust. //! From fcd495e888d2d7357bfd9958bcf492e35d726bf0 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:46:30 +0100 Subject: [PATCH 69/75] Upgrade smoltcp to 0.11.0 Also remove extra "proto-ipv6" feature that is not needed by examples --- Cargo.toml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 68c0c63b..b8a8c9cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ fdcan = { version = "0.2", optional = true } embedded-storage = "0.3" [dependencies.smoltcp] -version = "0.10.0" +version = "0.11.0" default-features = false features = ["medium-ethernet", "proto-ipv4", "socket-raw"] optional = true @@ -84,11 +84,6 @@ embedded-graphics = "0.8" otm8009a = "0.1" eg-seven-segment = "0.2.0" -[dev-dependencies.smoltcp] -version = "0.10.0" -default-features = false -features = ["medium-ethernet", "proto-ipv4", "proto-ipv6", "socket-raw"] - [features] default = ["rt"] device-selected = [] From a3171010c8dea328cfc380871d22f7a5d2c2fd5b Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sun, 3 Mar 2024 18:20:00 +0100 Subject: [PATCH 70/75] Tidy redundant imports `TryFrom` and `TryInto` part of the prelude [since the 2021 edition](https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html). https://github.com/stm32-rs/stm32h7xx-hal/pull/236 --- examples/usb_phy_serial_interrupt.rs | 6 ++++-- src/crc.rs | 1 - src/ethernet/eth.rs | 1 - src/sai/i2s.rs | 1 - src/sai/pdm.rs | 2 -- src/spi.rs | 1 - src/timer.rs | 1 - 7 files changed, 4 insertions(+), 9 deletions(-) diff --git a/examples/usb_phy_serial_interrupt.rs b/examples/usb_phy_serial_interrupt.rs index 88b7d891..90b2533a 100644 --- a/examples/usb_phy_serial_interrupt.rs +++ b/examples/usb_phy_serial_interrupt.rs @@ -18,8 +18,10 @@ use { stm32, usb_hs::{UsbBus, USB1_ULPI}, }, - usb_device::prelude::*, - usb_device::{bus::UsbBusAllocator, device::UsbDevice}, + usb_device::{ + bus::UsbBusAllocator, + device::{UsbDevice, UsbDeviceBuilder, UsbVidPid}, + }, usbd_serial::{DefaultBufferStore, SerialPort}, }; diff --git a/src/crc.rs b/src/crc.rs index 5319e716..41af5e96 100644 --- a/src/crc.rs +++ b/src/crc.rs @@ -4,7 +4,6 @@ //! //! - [CRC example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/crc.rs) -use core::convert::TryInto; use core::fmt; use crate::rcc::{rec, ResetEnable}; diff --git a/src/ethernet/eth.rs b/src/ethernet/eth.rs index d786dac0..b825595b 100644 --- a/src/ethernet/eth.rs +++ b/src/ethernet/eth.rs @@ -28,7 +28,6 @@ use crate::rcc::{rec, CoreClocks, ResetEnable}; use crate::stm32; use smoltcp::{ - self, phy::{self, DeviceCapabilities}, time::Instant, wire::EthernetAddress, diff --git a/src/sai/i2s.rs b/src/sai/i2s.rs index 794bde7f..d06735a5 100644 --- a/src/sai/i2s.rs +++ b/src/sai/i2s.rs @@ -2,7 +2,6 @@ //! //! Inter-IC Sound. //! -use core::convert::TryInto; use crate::rcc::{rec, CoreClocks, ResetEnable}; use crate::sai::{GetClkSAI, Sai, SaiChannel, CLEAR_ALL_FLAGS_BITS, INTERFACE}; diff --git a/src/sai/pdm.rs b/src/sai/pdm.rs index 3bb19158..2135335a 100644 --- a/src/sai/pdm.rs +++ b/src/sai/pdm.rs @@ -15,8 +15,6 @@ //! let _ = block!(sai.read_data()).unwrap(); //! ``` -use core::convert::TryInto; - use crate::rcc::{rec, CoreClocks, ResetEnable}; use crate::sai::{GetClkSAI, Sai, SaiChannel, INTERFACE}; diff --git a/src/spi.rs b/src/spi.rs index 3247a0e2..9754c038 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -63,7 +63,6 @@ //! [embedded_hal]: https://docs.rs/embedded-hal/0.2.3/embedded_hal/spi/index.html use core::cell::UnsafeCell; -use core::convert::From; use core::marker::PhantomData; use core::ptr; diff --git a/src/timer.rs b/src/timer.rs index bd525cf5..06d881d0 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -8,7 +8,6 @@ // TODO: on the h7x3 at least, only TIM2, TIM3, TIM4, TIM5 can support 32 bits. // TIM1 is 16 bit. -use core::convert::TryFrom; use core::marker::PhantomData; use crate::hal::timer::{CountDown, Periodic}; From 6c76647ed912a8606b18adcbaa6d90a854b088c2 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Wed, 6 Mar 2024 22:49:42 +0100 Subject: [PATCH 71/75] v0.16.0 --- CHANGELOG.md | 16 ++++++++++++++-- Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 1 + 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30893f4a..8f8e08eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,19 @@ ## [Unreleased] +## [v0.16.0] 2024-03-12 + * MSRV increased to Rust 1.66.1 [#473] +* **Breaking** Update `smoltcp` to `0.11.0` (from `0.10.0`) [#484] +* **Breaking** Update `usb-device` to `0.3` (from `0.2.5`) [#469] +* Add support for MIPI DSI peripheral on STM32H747/757 (feature gate `dsi`) [#473] +* qspi: Add `change_back_unchecked` method [#449] +* timers: Add support for TIM23 and TIM24 found on RM0468 parts [#482] ## [v0.15.1] 2023-11-03 * Bugfix, usb: On RM0455 and RM0468 parts, PA11/PA12 do not have an alternate function (AF) for USB. Use `into_analog()` when passing pins to `USB1/2::new` on these parts [#464] -* [breaking] `usb-device` updated to v0.3.0 ## [v0.15.0] 2023-10-09 @@ -295,7 +301,8 @@ * Upgrade to stm32-rs v0.9.0 (including svd2rust v0.16) * Started Changelog -[Unreleased]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.15.1...HEAD +[Unreleased]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.16.0...HEAD +[v0.16.0]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.15.1...v0.16.0 [v0.15.1]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.15.0...v0.15.1 [v0.15.0]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.14.0...v0.15.0 [v0.14.0]: https://github.com/stm32-rs/stm32h7xx-hal/compare/v0.13.1...v0.14.0 @@ -391,7 +398,12 @@ [#429]: https://github.com/stm32-rs/stm32h7xx-hal/pull/429 [#434]: https://github.com/stm32-rs/stm32h7xx-hal/pull/434 [#440]: https://github.com/stm32-rs/stm32h7xx-hal/pull/440 +[#449]: https://github.com/stm32-rs/stm32h7xx-hal/pull/449 [#451]: https://github.com/stm32-rs/stm32h7xx-hal/pull/451 [#453]: https://github.com/stm32-rs/stm32h7xx-hal/pull/453 [#456]: https://github.com/stm32-rs/stm32h7xx-hal/pull/456 [#464]: https://github.com/stm32-rs/stm32h7xx-hal/pull/464 +[#469]: https://github.com/stm32-rs/stm32h7xx-hal/pull/469 +[#473]: https://github.com/stm32-rs/stm32h7xx-hal/pull/473 +[#482]: https://github.com/stm32-rs/stm32h7xx-hal/pull/482 +[#484]: https://github.com/stm32-rs/stm32h7xx-hal/pull/484 diff --git a/Cargo.toml b/Cargo.toml index b8a8c9cf..dcef60b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stm32h7xx-hal" -version = "0.15.1" +version = "0.16.0" authors = ["Andrew Straw ", "Richard Meadows ", "Henrik Böving ", diff --git a/README.md b/README.md index a7474095..f773ddda 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ target device feature must be specified in the `Cargo.toml` file: [dependencies] cortex-m = "0.7.4" cortex-m-rt = "0.7.1" -stm32h7xx-hal = {version = "0.15.1", features = ["stm32h743v","rt"]} +stm32h7xx-hal = {version = "0.16.0", features = ["stm32h743v","rt"]} ``` If you are unfamiliar with embedded development using Rust, there are diff --git a/src/lib.rs b/src/lib.rs index 299a33db..514c82f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ //! * [Ethernet](crate::ethernet) Feature gate `ethernet` //! * [USB HS](crate::usb_hs) Feature gate `usb_hs` //! * [LCD-TFT Display Controller](crate::ltdc) Feature gate `ltdc` +//! * MIPI DSI (STM32H747/757 only) Feature gate `dsi` //! * [CAN and CAN-FD](crate::can) Feature gate `can` //! //! External Memory From 4a3db6106eae0164aa8b44ed15abe3d726cb1431 Mon Sep 17 00:00:00 2001 From: Endre Bakka Date: Wed, 15 May 2024 14:36:26 +0200 Subject: [PATCH 72/75] adc: Remove hack for yango --- src/adc.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index a68085e1..afa9ef0a 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -387,14 +387,6 @@ adc_internal!( #[cfg(any(feature = "rm0433", feature = "rm0399"))] adc_pins!(ADC3, // 0, 1 are Pxy_C pins - - // EB: These two are a bit of "hack" (normally not supported by hal). - // EB: Requires the PC2/3_C to be connected. Should not be included in any patches... - // EB: Use these because they are faster and we then don't need to mess with syscfg - // EB: (on mainboard) - gpio::PC2 => 0, // Force PC2 to use channel 0 (PC2_C) - gpio::PC3 => 1, // Add PC3_C on channel 0 - gpio::PF9 => 2, gpio::PF7 => 3, gpio::PF5 => 4, @@ -405,7 +397,7 @@ adc_pins!(ADC3, gpio::PF4 => 9, gpio::PC0 => 10, gpio::PC1 => 11, - //gpio::PC2 => 12, + gpio::PC2 => 12, gpio::PH2 => 13, gpio::PH3 => 14, gpio::PH4 => 15, From b2d98b066c4a07ec959d3e477675eddc57714dff Mon Sep 17 00:00:00 2001 From: Endre Bakka Date: Wed, 15 May 2024 14:44:45 +0200 Subject: [PATCH 73/75] gpio: Add support for CPins (ADC analog input pins) --- src/gpio.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 3419e22c..0c97cf6d 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -64,6 +64,10 @@ use core::marker::PhantomData; use crate::rcc::ResetEnable; +// EB: Todo: If making PR upstream, this should only be include for some boards (see pwr.rs) +use crate::stm32::SYSCFG; +// EB: Todo: If making PR upstream, check which boards has relevant Pxy_C pins and update +// EB: adc_pins! macros accordingly mod convert; pub use convert::PinMode; @@ -257,6 +261,28 @@ af!( 15: AF15 ); +/// Joined state +pub struct Joined; + +/// Split state +pub struct Split; + +/// C pin type +/// +/// This type is used to specify ADC analog input pins (typically named PA0_C or PC2_C). +/// These pins can be connected to corresponding GPIO pins (PA0 or PC2) through an +/// analog switch. +/// - `MODE` is one of Joined (connected to gpio pin (e.g. PA0 and PA0_C are +/// connected)) or Split (PA0 and PA0_C are not connected) +pub struct CPin { + _mode: PhantomData, +} +impl CPin { + const fn new() -> Self { + Self { _mode: PhantomData } + } +} + /// Generic pin type /// /// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). @@ -520,7 +546,8 @@ where macro_rules! gpio { ($GPIOX:ident, $gpiox:ident, $Rec:ident, $PEPin:ident, $port_id:expr, $PXn:ident, [ - $($PXi:ident: ($pxi:ident, $i:expr, [$($A:literal),*] $(, $MODE:ty)?),)+ + $($PXi:ident: ($pxi:ident, $i:expr, [$($A:literal),*] $(, $MODE:ty)?) + $(, ($CPIN:ident, $cpin:ident, $creg:ident))?,)+ ]) => { #[doc=concat!("Port ", $port_id)] pub mod $gpiox { @@ -533,6 +560,9 @@ macro_rules! gpio { /// Pin pub $pxi: $PXi $(<$MODE>)?, )+ + $( + $(pub $cpin: $CPIN,)? + )* } impl super::GpioExt for $GPIOX { @@ -546,6 +576,10 @@ macro_rules! gpio { $( $pxi: $PXi::new(), )+ + $( + $($cpin: $CPIN::new(),)? + )* + } } @@ -556,6 +590,10 @@ macro_rules! gpio { $( $pxi: $PXi::new(), )+ + $( + $($cpin: $CPIN::new(),)? + )* + } } } @@ -572,9 +610,40 @@ macro_rules! gpio { )* )+ + $( + $( + #[doc=concat!("P", $port_id, $i, "_C pin")] + #[allow(non_camel_case_types)] + pub type $CPIN = super::CPin<$port_id, $i, MODE>; + )? + )* + } - pub use $gpiox::{ $($PXi,)+ }; + pub use $gpiox::{ $($PXi,)+ $($($CPIN,)?)* }; + + $( + $( + impl CPin<$port_id, $i, MODE> { + #[doc=concat!("Configures the pin to split mode (P", $port_id, $i," and P", $port_id, $i,"_C are not connected)")] + pub fn into_split(self) -> CPin<$port_id, $i, Split> { + unsafe { + (*SYSCFG::ptr()).pmcr.modify(|_, w| w.$creg().set_bit()); + } + CPin::new() + } + #[doc=concat!("Configures the pin to joined mode (P", $port_id, $i," and P", $port_id, $i,"_C are connected)")] + pub fn into_joined(self) -> CPin<$port_id, $i, Joined> { + unsafe { + (*SYSCFG::ptr()).pmcr.modify(|_, w| w.$creg().clear_bit()); + } + + CPin::new() + } + } + )? + )* + } } @@ -755,8 +824,8 @@ gpio!(GPIOK, gpiok, Gpiok, PK, 'K', PKn, [ #[cfg(feature = "gpio-h747")] gpio!(GPIOA, gpioa, Gpioa, PA, 'A', PAn, [ - PA0: (pa0, 0, [1, 2, 3, 4, 7, 8, 9, 10, 11, 15]), - PA1: (pa1, 1, [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15]), + PA0: (pa0, 0, [1, 2, 3, 4, 7, 8, 9, 10, 11, 15]), (PA0_C, pa0_c, pa0so), + PA1: (pa1, 1, [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15]), (PA1_C, pa1_c, pa1so), PA2: (pa2, 2, [1, 2, 3, 4, 7, 8, 11, 12, 14, 15]), PA3: (pa3, 3, [1, 2, 3, 4, 7, 9, 10, 11, 14, 15]), PA4: (pa4, 4, [2, 5, 6, 7, 8, 12, 13, 14, 15]), @@ -797,8 +866,8 @@ gpio!(GPIOB, gpiob, Gpiob, PB, 'B', PBn, [ gpio!(GPIOC, gpioc, Gpioc, PC, 'C', PCn, [ PC0: (pc0, 0, [3, 6, 8, 10, 12, 14, 15]), PC1: (pc1, 1, [0, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 15]), - PC2: (pc2, 2, [3, 5, 6, 10, 11, 12, 15]), - PC3: (pc3, 3, [3, 5, 10, 11, 12, 15]), + PC2: (pc2, 2, [3, 5, 6, 10, 11, 12, 15]), (PC2_C, pc2_c, pc2so), + PC3: (pc3, 3, [3, 5, 10, 11, 12, 15]), (PC3_C, pc3_c, pc3so), PC4: (pc4, 4, [3, 5, 9, 11, 12, 15]), PC5: (pc5, 5, [2, 3, 9, 10, 11, 12, 13, 15]), PC6: (pc6, 6, [1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15]), From c455210822257045a2206a2dcc3a4f0cfb9edc96 Mon Sep 17 00:00:00 2001 From: Endre Bakka Date: Wed, 15 May 2024 14:45:35 +0200 Subject: [PATCH 74/75] adc: Add support for C pins --- src/adc.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/adc.rs b/src/adc.rs index afa9ef0a..173f7291 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -29,7 +29,7 @@ use crate::stm32::adc12_common::ccr::PRESC_A; #[cfg(not(feature = "rm0455"))] use crate::stm32::adc3_common::ccr::PRESC_A; -use crate::gpio::{self, Analog}; +use crate::gpio::{self, Analog, Split}; use crate::pwr::{current_vos, VoltageScale}; use crate::rcc::rec::AdcClkSelGetter; use crate::rcc::{rec, CoreClocks, ResetEnable}; @@ -332,6 +332,8 @@ pub struct Temperature; // Refer to DS12110 Rev 7 - Chapter 5 (Table 9) adc_pins!(ADC1, // 0, 1 are Pxy_C pins + gpio::PA0_C => 0, + gpio::PA1_C => 1, gpio::PF11 => 2, gpio::PA6 => 3, gpio::PC4 => 4, @@ -387,6 +389,8 @@ adc_internal!( #[cfg(any(feature = "rm0433", feature = "rm0399"))] adc_pins!(ADC3, // 0, 1 are Pxy_C pins + gpio::PC2_C => 0, + gpio::PC3_C => 1, gpio::PF9 => 2, gpio::PF7 => 3, gpio::PF5 => 4, From 6f13b8f872dd2545c560a22174fada53d123c6cb Mon Sep 17 00:00:00 2001 From: Endre Bakka Date: Wed, 15 May 2024 20:19:59 +0200 Subject: [PATCH 75/75] adc: Need some restrictions to pass CI (builds for a ton of platforms) --- src/adc.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index 173f7291..1fa439ad 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -29,7 +29,10 @@ use crate::stm32::adc12_common::ccr::PRESC_A; #[cfg(not(feature = "rm0455"))] use crate::stm32::adc3_common::ccr::PRESC_A; -use crate::gpio::{self, Analog, Split}; +#[cfg(feature = "rm0399")] +use crate::gpio::Split; +use crate::gpio::{self, Analog}; + use crate::pwr::{current_vos, VoltageScale}; use crate::rcc::rec::AdcClkSelGetter; use crate::rcc::{rec, CoreClocks, ResetEnable}; @@ -332,8 +335,6 @@ pub struct Temperature; // Refer to DS12110 Rev 7 - Chapter 5 (Table 9) adc_pins!(ADC1, // 0, 1 are Pxy_C pins - gpio::PA0_C => 0, - gpio::PA1_C => 1, gpio::PF11 => 2, gpio::PA6 => 3, gpio::PC4 => 4, @@ -354,6 +355,13 @@ adc_pins!(ADC1, gpio::PA5 => 19, ); +#[cfg(feature = "rm0399")] +adc_pins!(ADC1, + // 0, 1 are Pxy_C pins + gpio::PA0_C => 0, + gpio::PA1_C => 1, +); + adc_pins!(ADC2, // 0, 1 are Pxy_C pins gpio::PF13 => 2, @@ -389,8 +397,6 @@ adc_internal!( #[cfg(any(feature = "rm0433", feature = "rm0399"))] adc_pins!(ADC3, // 0, 1 are Pxy_C pins - gpio::PC2_C => 0, - gpio::PC3_C => 1, gpio::PF9 => 2, gpio::PF7 => 3, gpio::PF5 => 4, @@ -407,6 +413,15 @@ adc_pins!(ADC3, gpio::PH4 => 15, gpio::PH5 => 16, ); +// EB: Todo: If we want to merge upstream, we need to figure out exactly which MCUs have these pins +// EB: which is complicated as it depends on the package... +#[cfg(feature = "rm0399")] +adc_pins!(ADC3, + // 0, 1 are Pxy_C pins + gpio::PC2_C => 0, + gpio::PC3_C => 1, +); + #[cfg(any(feature = "rm0433", feature = "rm0399"))] adc_internal!( [ADC3, ADC3_COMMON]; @@ -438,6 +453,7 @@ adc_pins!(ADC3, // Although ADC3_INP16 appears in device datasheets (on PH5), RM0468 Rev 7 // Figure 231 does not show ADC3_INP16 ); + #[cfg(feature = "rm0468")] adc_internal!( [ADC3, ADC3_COMMON];