diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index a50da1a9e..a7137d132 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -89,7 +89,6 @@ volatile-register = { version = "0.2.1" } bitflags = "2.4.2" - [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ba118f338..dbc8f9153 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -836,6 +836,35 @@ fn main() { (("dcmi", "HSYNC"), quote!(crate::dcmi::HSyncPin)), (("dcmi", "VSYNC"), quote!(crate::dcmi::VSyncPin)), (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)), + (("dsihost", "TE"), quote!(crate::dsihost::TePin)), + (("ltdc", "CLK"), quote!(crate::ltdc::ClkPin)), + (("ltdc", "HSYNC"), quote!(crate::ltdc::HsyncPin)), + (("ltdc", "VSYNC"), quote!(crate::ltdc::VsyncPin)), + (("ltdc", "DE"), quote!(crate::ltdc::DePin)), + (("ltdc", "R0"), quote!(crate::ltdc::R0Pin)), + (("ltdc", "R1"), quote!(crate::ltdc::R1Pin)), + (("ltdc", "R2"), quote!(crate::ltdc::R2Pin)), + (("ltdc", "R3"), quote!(crate::ltdc::R3Pin)), + (("ltdc", "R4"), quote!(crate::ltdc::R4Pin)), + (("ltdc", "R5"), quote!(crate::ltdc::R5Pin)), + (("ltdc", "R6"), quote!(crate::ltdc::R6Pin)), + (("ltdc", "R7"), quote!(crate::ltdc::R7Pin)), + (("ltdc", "G0"), quote!(crate::ltdc::G0Pin)), + (("ltdc", "G1"), quote!(crate::ltdc::G1Pin)), + (("ltdc", "G2"), quote!(crate::ltdc::G2Pin)), + (("ltdc", "G3"), quote!(crate::ltdc::G3Pin)), + (("ltdc", "G4"), quote!(crate::ltdc::G4Pin)), + (("ltdc", "G5"), quote!(crate::ltdc::G5Pin)), + (("ltdc", "G6"), quote!(crate::ltdc::G6Pin)), + (("ltdc", "G7"), quote!(crate::ltdc::G7Pin)), + (("ltdc", "B0"), quote!(crate::ltdc::B0Pin)), + (("ltdc", "B1"), quote!(crate::ltdc::B1Pin)), + (("ltdc", "B2"), quote!(crate::ltdc::B2Pin)), + (("ltdc", "B3"), quote!(crate::ltdc::B3Pin)), + (("ltdc", "B4"), quote!(crate::ltdc::B4Pin)), + (("ltdc", "B5"), quote!(crate::ltdc::B5Pin)), + (("ltdc", "B6"), quote!(crate::ltdc::B6Pin)), + (("ltdc", "B7"), quote!(crate::ltdc::B7Pin)), (("usb", "DP"), quote!(crate::usb::DpPin)), (("usb", "DM"), quote!(crate::usb::DmPin)), (("otg", "DP"), quote!(crate::usb::DpPin)), diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs new file mode 100644 index 000000000..f1c737fdc --- /dev/null +++ b/embassy-stm32/src/dsihost.rs @@ -0,0 +1,429 @@ +//! DSI HOST + +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; + +//use crate::gpio::{AnyPin, SealedPin}; +use crate::gpio::{AFType, AnyPin, Pull, Speed}; +use crate::rcc::RccPeripheral; +use crate::{peripherals, Peripheral}; + +/// Performs a busy-wait delay for a specified number of microseconds. +pub fn blocking_delay_ms(ms: u32) { + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_millis(ms)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1_000 * ms); +} + +/// PacketTypes extracted from CubeMX +#[repr(u8)] +#[allow(dead_code)] +pub enum PacketType { + /// DCS short write, no parameters + DcsShortPktWriteP0, + /// DCS short write, one parameter + DcsShortPktWriteP1, + /// Generic short write, no parameters + GenShortPktWriteP0, + /// Generic short write, one parameter + GenShortPktWriteP1, + /// Generic short write, two parameters + GenShortPktWriteP2, + /// DCS long write + DcsLongPktWrite, + /// Generic long write + GenLongPktWrite, + /// DCS short read + DcsShortPktRead(u8), + /// Generic short read, no parameters + GenShortPktReadP0, + /// Generic short read, one parameter + GenShortPktReadP1(u8), + /// Generic short read, two parameters + GenShortPktReadP2(u8, u8), + /// Used to set the maximum return packet size for reading data + MaxReturnPktSize, +} + +impl From for u8 { + fn from(packet_type: PacketType) -> u8 { + match packet_type { + PacketType::DcsShortPktWriteP0 => 0x05, + PacketType::DcsShortPktWriteP1 => 0x15, + PacketType::GenShortPktWriteP0 => 0x03, + PacketType::GenShortPktWriteP1 => 0x13, + PacketType::GenShortPktWriteP2 => 0x23, + PacketType::DcsLongPktWrite => 0x39, + PacketType::GenLongPktWrite => 0x29, + PacketType::DcsShortPktRead(_) => 0x06, + PacketType::GenShortPktReadP0 => 0x04, + PacketType::GenShortPktReadP1(_) => 0x14, + PacketType::GenShortPktReadP2(_, _) => 0x24, + PacketType::MaxReturnPktSize => 0x37, + } + } +} + +/// DSIHOST driver. +pub struct DsiHost<'d, T: Instance> { + _peri: PhantomData<&'d mut T>, + _te: PeripheralRef<'d, AnyPin>, +} + +impl<'d, T: Instance> DsiHost<'d, T> { + /// Note: Full-Duplex modes are not supported at this time + pub fn new(_peri: impl Peripheral

+ 'd, te: impl Peripheral

> + 'd) -> Self { + into_ref!(te); + + T::enable_and_reset(); + + // Set Tearing Enable pin according to CubeMx example + te.set_as_af_pull(te.af_num(), AFType::OutputPushPull, Pull::None); + te.set_speed(Speed::Low); + /* + T::regs().wcr().modify(|w| { + w.set_dsien(true); + }); + */ + Self { + _peri: PhantomData, + _te: te.map_into(), + } + } + + /// Get the DSIHOST hardware version. Found in the reference manual for comparison. + pub fn get_version(&self) -> u32 { + T::regs().vr().read().version() + } + + /// Set the enable bit in the control register and assert that it has been enabled + pub fn enable(&mut self) { + T::regs().cr().modify(|w| w.set_en(true)); + assert!(T::regs().cr().read().en()) + } + + /// Unset the enable bit in the control register and assert that it has been disabled + pub fn disable(&mut self) { + T::regs().cr().modify(|w| w.set_en(false)); + assert!(!T::regs().cr().read().en()) + } + + /// Set the DSI enable bit in the wrapper control register and assert that it has been enabled + pub fn enable_wrapper_dsi(&mut self) { + T::regs().wcr().modify(|w| w.set_dsien(true)); + assert!(T::regs().wcr().read().dsien()) + } + + /// Unset the DSI enable bit in the wrapper control register and assert that it has been disabled + pub fn disable_wrapper_dsi(&mut self) { + T::regs().wcr().modify(|w| w.set_dsien(false)); + assert!(!T::regs().wcr().read().dsien()) + } + + /// DCS or Generic short/long write command + pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> { + assert!(data.len() > 0); + + if data.len() == 1 { + self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]) + } else { + self.long_write( + channel_id, + PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well... + address, + data, + ) + } + } + + fn short_write(&mut self, channel_id: u8, packet_type: PacketType, param1: u8, param2: u8) -> Result<(), Error> { + #[cfg(feature = "defmt")] + defmt::debug!("short_write: BEGIN wait for command fifo empty"); + + // Wait for Command FIFO empty + self.wait_command_fifo_empty()?; + #[cfg(feature = "defmt")] + defmt::debug!("short_write: END wait for command fifo empty"); + + // Configure the packet to send a short DCS command with 0 or 1 parameters + // Update the DSI packet header with new information + self.config_packet_header(channel_id, packet_type, param1, param2); + + self.wait_command_fifo_empty()?; + + let status = T::regs().isr1().read().0; + if status != 0 { + error!("ISR1 after short_write(): {:b}", status); + } + Ok(()) + } + + fn config_packet_header(&mut self, channel_id: u8, packet_type: PacketType, param1: u8, param2: u8) { + T::regs().ghcr().write(|w| { + w.set_dt(packet_type.into()); + w.set_vcid(channel_id); + w.set_wclsb(param1); + w.set_wcmsb(param2); + }); + } + + /// Write long DCS or long Generic command. + /// + /// `params` is expected to contain at least 2 elements. Use [`short_write`] for a single element. + fn long_write(&mut self, channel_id: u8, packet_type: PacketType, address: u8, data: &[u8]) -> Result<(), Error> { + // Must be a long packet if we do the long write, obviously. + assert!(matches!( + packet_type, + PacketType::DcsLongPktWrite | PacketType::GenLongPktWrite + )); + + // params needs to have at least 2 elements, otherwise short_write should be used + assert!(data.len() >= 2); + + #[cfg(feature = "defmt")] + defmt::debug!("long_write: BEGIN wait for command fifo empty"); + + self.wait_command_fifo_empty()?; + + #[cfg(feature = "defmt")] + defmt::debug!("long_write: DONE wait for command fifo empty"); + + // Note: CubeMX example "NbParams" is always one LESS than params.len() + // DCS code (last element of params) must be on payload byte 1 and if we have only 2 more params, + // then they must go into data2 and data3 + T::regs().gpdr().write(|w| { + // data[2] may or may not exist. + if let Some(x) = data.get(2) { + w.set_data4(*x); + } + // data[0] and [1] have to exist if long_write is called. + w.set_data3(data[1]); + w.set_data2(data[0]); + + // DCS Code + w.set_data1(address); + }); + + self.wait_command_fifo_empty()?; + + // These steps are only necessary if more than 1x 4 bytes need to go into the FIFO + if data.len() >= 4 { + // Generate an iterator that iterates over chunks of exactly 4 bytes + let iter = data[3..data.len()].chunks_exact(4); + // Obtain remainder before consuming iter + let remainder = iter.remainder(); + + // Keep filling the buffer with remaining data + for param in iter { + self.wait_command_fifo_not_full()?; + T::regs().gpdr().write(|w| { + w.set_data4(param[3]); + w.set_data3(param[2]); + w.set_data2(param[1]); + w.set_data1(param[0]); + }); + + self.wait_command_fifo_empty().unwrap(); + } + + // If the remaining data was not devisible by 4 we get a remainder + if remainder.len() >= 1 { + self.wait_command_fifo_not_full()?; + T::regs().gpdr().write(|w| { + if let Some(x) = remainder.get(2) { + w.set_data3(*x); + } + if let Some(x) = remainder.get(1) { + w.set_data2(*x); + } + w.set_data1(remainder[0]); + }); + self.wait_command_fifo_empty().unwrap(); + } + } + // Configure the packet to send a long DCS command + self.config_packet_header( + channel_id, + packet_type, + ((data.len() + 1) & 0x00FF) as u8, // +1 to account for address byte + (((data.len() + 1) & 0xFF00) >> 8) as u8, // +1 to account for address byte + ); + + self.wait_command_fifo_empty()?; + + let status = T::regs().isr1().read().0; + if status != 0 { + error!("ISR1 after long_write(): {:b}", status); + } + Ok(()) + } + + /// Read DSI Register + pub fn read( + &mut self, + channel_id: u8, + packet_type: PacketType, + read_size: u16, + data: &mut [u8], + ) -> Result<(), Error> { + if data.len() != read_size as usize { + return Err(Error::InvalidReadSize); + } + + // Set the maximum return packet size + self.short_write( + channel_id, + PacketType::MaxReturnPktSize, + (read_size & 0xFF) as u8, + ((read_size & 0xFF00) >> 8) as u8, + )?; + + // Set the packet header according to the packet_type + use PacketType::*; + match packet_type { + DcsShortPktRead(cmd) => self.config_packet_header(channel_id, packet_type, cmd, 0), + GenShortPktReadP0 => self.config_packet_header(channel_id, packet_type, 0, 0), + GenShortPktReadP1(param1) => self.config_packet_header(channel_id, packet_type, param1, 0), + GenShortPktReadP2(param1, param2) => self.config_packet_header(channel_id, packet_type, param1, param2), + _ => return Err(Error::InvalidPacketType), + } + + self.wait_read_not_busy()?; + + // Obtain chunks of 32-bit so the entire FIFO data register can be read + for bytes in data.chunks_exact_mut(4) { + self.wait_payload_read_fifo_not_empty()?; + + // Only perform a single read on the entire register to avoid unintended side-effects + let gpdr = T::regs().gpdr().read(); + bytes[0] = gpdr.data1(); + bytes[1] = gpdr.data2(); + bytes[2] = gpdr.data3(); + bytes[3] = gpdr.data4(); + } + + // Collect the remaining chunks and read the corresponding number of bytes from the FIFO + let remainder = data.chunks_exact_mut(4).into_remainder(); + if !remainder.is_empty() { + self.wait_payload_read_fifo_not_empty()?; + // Only perform a single read on the entire register to avoid unintended side-effects + let gpdr = T::regs().gpdr().read(); + if let Some(x) = remainder.get_mut(0) { + *x = gpdr.data1() + } + if let Some(x) = remainder.get_mut(1) { + *x = gpdr.data2() + } + if let Some(x) = remainder.get_mut(2) { + *x = gpdr.data3() + } + } + + /* + // Used this to check whether there are read errors. Does not seem like it. + if !self.read_busy() { + defmt::debug!("Read not busy!"); + if self.packet_size_error() { + return Err(Error::ReadError); + } + } + */ + Ok(()) + } + + fn wait_command_fifo_empty(&self) -> Result<(), Error> { + for _ in 1..1000 { + // Wait for Command FIFO empty + if T::regs().gpsr().read().cmdfe() { + return Ok(()); + } + blocking_delay_ms(1); + } + Err(Error::FifoTimeout) + } + + fn wait_command_fifo_not_full(&self) -> Result<(), Error> { + for _ in 1..1000 { + // Wait for Command FIFO not empty + if !T::regs().gpsr().read().cmdff() { + return Ok(()); + } + blocking_delay_ms(1); + } + Err(Error::FifoTimeout) + } + + fn wait_read_not_busy(&self) -> Result<(), Error> { + for _ in 1..1000 { + // Wait for read not busy + if !self.read_busy() { + return Ok(()); + } + blocking_delay_ms(1); + } + Err(Error::ReadTimeout) + } + + fn wait_payload_read_fifo_not_empty(&self) -> Result<(), Error> { + for _ in 1..1000 { + // Wait for payload read FIFO not empty + if !T::regs().gpsr().read().prdfe() { + return Ok(()); + } + blocking_delay_ms(1); + } + Err(Error::FifoTimeout) + } + + fn _packet_size_error(&self) -> bool { + T::regs().isr1().read().pse() + } + + fn read_busy(&self) -> bool { + T::regs().gpsr().read().rcb() + } +} + +/// Possible Error Types for DSI HOST +#[non_exhaustive] +#[derive(Debug)] +pub enum Error { + /// Waiting for FIFO empty flag timed out + FifoTimeout, + /// The specified `PacketType` is invalid for the selected operation + InvalidPacketType, + /// Provided read size does not match the read buffer length + InvalidReadSize, + /// Error during read + ReadError, + /// Read operation timed out + ReadTimeout, +} + +impl<'d, T: Instance> Drop for DsiHost<'d, T> { + fn drop(&mut self) {} +} + +trait SealedInstance: crate::rcc::SealedRccPeripheral { + fn regs() -> &'static crate::pac::dsihost::Dsihost; +} + +/// DSI instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + 'static {} + +pin_trait!(TePin, Instance); + +foreach_peripheral!( + (dsihost, $inst:ident) => { + impl crate::dsihost::SealedInstance for peripherals::$inst { + fn regs() -> &'static crate::pac::dsihost::Dsihost { + &crate::pac::$inst + } + } + + impl crate::dsihost::Instance for peripherals::$inst {} + }; +); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 1f4e9ab1e..029e01480 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -66,6 +66,8 @@ pub mod cryp; pub mod dac; #[cfg(dcmi)] pub mod dcmi; +#[cfg(dsihost)] +pub mod dsihost; #[cfg(eth)] pub mod eth; #[cfg(feature = "exti")] @@ -85,6 +87,8 @@ pub mod i2s; pub mod ipcc; #[cfg(feature = "low-power")] pub mod low_power; +#[cfg(ltdc)] +pub mod ltdc; #[cfg(opamp)] pub mod opamp; #[cfg(octospi)] diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs new file mode 100644 index 000000000..0cc8a0557 --- /dev/null +++ b/embassy-stm32/src/ltdc.rs @@ -0,0 +1,142 @@ +//! LTDC +use core::marker::PhantomData; + +use crate::rcc::RccPeripheral; +use crate::{peripherals, Peripheral}; + +/// LTDC driver. +pub struct Ltdc<'d, T: Instance> { + _peri: PhantomData<&'d mut T>, +} + +impl<'d, T: Instance> Ltdc<'d, T> { + /// Note: Full-Duplex modes are not supported at this time + pub fn new( + _peri: impl Peripheral

+ 'd, + /* + clk: impl Peripheral

> + 'd, + hsync: impl Peripheral

> + 'd, + vsync: impl Peripheral

> + 'd, + b0: impl Peripheral

> + 'd, + b1: impl Peripheral

> + 'd, + b2: impl Peripheral

> + 'd, + b3: impl Peripheral

> + 'd, + b4: impl Peripheral

> + 'd, + b5: impl Peripheral

> + 'd, + b6: impl Peripheral

> + 'd, + b7: impl Peripheral

> + 'd, + g0: impl Peripheral

> + 'd, + g1: impl Peripheral

> + 'd, + g2: impl Peripheral

> + 'd, + g3: impl Peripheral

> + 'd, + g4: impl Peripheral

> + 'd, + g5: impl Peripheral

> + 'd, + g6: impl Peripheral

> + 'd, + g7: impl Peripheral

> + 'd, + r0: impl Peripheral

> + 'd, + r1: impl Peripheral

> + 'd, + r2: impl Peripheral

> + 'd, + r3: impl Peripheral

> + 'd, + r4: impl Peripheral

> + 'd, + r5: impl Peripheral

> + 'd, + r6: impl Peripheral

> + 'd, + r7: impl Peripheral

> + 'd, + */ + ) -> Self { + //into_ref!(clk); + + critical_section::with(|_cs| { + // RM says the pllsaidivr should only be changed when pllsai is off. But this could have other unintended side effects. So let's just give it a try like this. + // According to the debugger, this bit gets set, anyway. + #[cfg(stm32f7)] + stm32_metapac::RCC + .dckcfgr1() + .modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2)); + + // It is set to RCC_PLLSAIDIVR_2 in ST's BSP example for the STM32469I-DISCO. + #[cfg(not(any(stm32f7, stm32u5)))] + stm32_metapac::RCC + .dckcfgr() + .modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2)); + }); + + T::enable_and_reset(); + + //new_pin!(clk, AFType::OutputPushPull, Speed::VeryHigh, Pull::None); + + // Set Tearing Enable pin according to CubeMx example + //te.set_as_af_pull(te.af_num(), AFType::OutputPushPull, Pull::None); + //te.set_speed(Speed::Low); + /* + T::regs().wcr().modify(|w| { + w.set_dsien(true); + }); + */ + Self { _peri: PhantomData } + } + + /// Set the enable bit in the control register and assert that it has been enabled + pub fn enable(&mut self) { + T::regs().gcr().modify(|w| w.set_ltdcen(true)); + assert!(T::regs().gcr().read().ltdcen()) + } + + /// Unset the enable bit in the control register and assert that it has been disabled + pub fn disable(&mut self) { + T::regs().gcr().modify(|w| w.set_ltdcen(false)); + assert!(!T::regs().gcr().read().ltdcen()) + } +} + +impl<'d, T: Instance> Drop for Ltdc<'d, T> { + fn drop(&mut self) {} +} + +trait SealedInstance: crate::rcc::SealedRccPeripheral { + fn regs() -> &'static crate::pac::ltdc::Ltdc; +} + +/// DSI instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + RccPeripheral + 'static {} + +pin_trait!(ClkPin, Instance); +pin_trait!(HsyncPin, Instance); +pin_trait!(VsyncPin, Instance); +pin_trait!(DePin, Instance); +pin_trait!(R0Pin, Instance); +pin_trait!(R1Pin, Instance); +pin_trait!(R2Pin, Instance); +pin_trait!(R3Pin, Instance); +pin_trait!(R4Pin, Instance); +pin_trait!(R5Pin, Instance); +pin_trait!(R6Pin, Instance); +pin_trait!(R7Pin, Instance); +pin_trait!(G0Pin, Instance); +pin_trait!(G1Pin, Instance); +pin_trait!(G2Pin, Instance); +pin_trait!(G3Pin, Instance); +pin_trait!(G4Pin, Instance); +pin_trait!(G5Pin, Instance); +pin_trait!(G6Pin, Instance); +pin_trait!(G7Pin, Instance); +pin_trait!(B0Pin, Instance); +pin_trait!(B1Pin, Instance); +pin_trait!(B2Pin, Instance); +pin_trait!(B3Pin, Instance); +pin_trait!(B4Pin, Instance); +pin_trait!(B5Pin, Instance); +pin_trait!(B6Pin, Instance); +pin_trait!(B7Pin, Instance); + +foreach_peripheral!( + (ltdc, $inst:ident) => { + impl crate::ltdc::SealedInstance for peripherals::$inst { + fn regs() -> &'static crate::pac::ltdc::Ltdc { + &crate::pac::$inst + } + } + + impl crate::ltdc::Instance for peripherals::$inst {} + }; +); diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index e3ee9a039..555dd63a1 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -277,7 +277,7 @@ pub(crate) unsafe fn init(config: Config) { pclk2_tim: Some(pclk2_tim), rtc: rtc, pll1_q: pll.q, - pll1_r: None, // TODO + pll1_r: pll.r, #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] plli2s1_p: plli2s.p, @@ -297,11 +297,12 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))] pllsai1_q: None, + #[cfg(dsihost)] + dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers + hsi_div488: hsi.map(|hsi| hsi/488u32), hsi_hse: None, afif: None, - #[cfg(any(stm32f4, stm32f7))] - dsi_phy: None, // TODO ); } diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 5d47d400c..4d7004872 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -677,11 +677,12 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(rcc_h50)] pll3_r: None, + #[cfg(dsihost)] + dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers + #[cfg(stm32h5)] audioclk: None, i2s_ckin: None, - #[cfg(any(stm32h7, stm32h7rs))] - dsi_phy: None, // TODO #[cfg(stm32h7rs)] spdifrx_symb: None, // TODO #[cfg(stm32h7rs)] diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index c625948fb..76c06e9f8 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -413,6 +413,9 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] pllsai2_r: pllsai2.r, + #[cfg(dsihost)] + dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers + rtc: rtc, // TODO @@ -420,8 +423,6 @@ pub(crate) unsafe fn init(config: Config) { sai2_extclk: None, lsi: None, lse: None, - #[cfg(stm32l4)] - dsi_phy: None, ); } diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 4013d0a46..d6331f512 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -289,6 +289,9 @@ pub(crate) unsafe fn init(config: Config) { pll3_q: pll3.q, pll3_r: pll3.r, + #[cfg(dsihost)] + dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers + // TODO audioclk: None, hsi48_div_2: None, @@ -297,7 +300,6 @@ pub(crate) unsafe fn init(config: Config) { msik: None, shsi: None, shsi_div_2: None, - dsi_phy: None, ); }