diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs
new file mode 100644
index 000000000..b8761724a
--- /dev/null
+++ b/embassy-stm32/src/pwm/complementary_pwm.rs
@@ -0,0 +1,145 @@
+use core::marker::PhantomData;
+
+use embassy_hal_common::{into_ref, PeripheralRef};
+
+use super::*;
+#[allow(unused_imports)]
+use crate::gpio::sealed::{AFType, Pin};
+use crate::gpio::AnyPin;
+use crate::time::Hertz;
+use crate::Peripheral;
+
+pub struct Ch1;
+pub struct Ch2;
+pub struct Ch3;
+pub struct Ch4;
+
+pub struct PwmPin<'d, Perip, Channel> {
+    _pin: PeripheralRef<'d, AnyPin>,
+    phantom: PhantomData<(Perip, Channel)>,
+}
+
+pub struct ComplementaryPwmPin<'d, Perip, Channel> {
+    _pin: PeripheralRef<'d, AnyPin>,
+    phantom: PhantomData<(Perip, Channel)>,
+}
+
+macro_rules! channel_impl {
+    ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => {
+        impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
+            pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
+                into_ref!(pin);
+                critical_section::with(|_| unsafe {
+                    pin.set_low();
+                    pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
+                    #[cfg(gpio_v2)]
+                    pin.set_speed(crate::gpio::Speed::VeryHigh);
+                });
+                PwmPin {
+                    _pin: pin.map_into(),
+                    phantom: PhantomData,
+                }
+            }
+        }
+
+        impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
+            pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
+                into_ref!(pin);
+                critical_section::with(|_| unsafe {
+                    pin.set_low();
+                    pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
+                    #[cfg(gpio_v2)]
+                    pin.set_speed(crate::gpio::Speed::VeryHigh);
+                });
+                ComplementaryPwmPin {
+                    _pin: pin.map_into(),
+                    phantom: PhantomData,
+                }
+            }
+        }
+    };
+}
+
+channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin);
+channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin);
+channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin);
+channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin);
+
+pub struct ComplementaryPwm<'d, T> {
+    inner: PeripheralRef<'d, T>,
+}
+
+impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
+    pub fn new(
+        tim: impl Peripheral<P = T> + 'd,
+        _ch1: Option<PwmPin<'d, T, Ch1>>,
+        _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>,
+        _ch2: Option<PwmPin<'d, T, Ch2>>,
+        _ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>,
+        _ch3: Option<PwmPin<'d, T, Ch3>>,
+        _ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>,
+        _ch4: Option<PwmPin<'d, T, Ch4>>,
+        _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>,
+        freq: Hertz,
+    ) -> Self {
+        Self::new_inner(tim, freq)
+    }
+
+    fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self {
+        into_ref!(tim);
+
+        T::enable();
+        <T as crate::rcc::sealed::RccPeripheral>::reset();
+
+        let mut this = Self { inner: tim };
+
+        this.inner.set_frequency(freq);
+        this.inner.start();
+
+        unsafe {
+            this.inner.enable_outputs(true);
+
+            this.inner
+                .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
+            this.inner
+                .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
+            this.inner
+                .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
+            this.inner
+                .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
+        }
+        this
+    }
+
+    pub fn enable(&mut self, channel: Channel) {
+        unsafe {
+            self.inner.enable_channel(channel, true);
+        }
+    }
+
+    pub fn disable(&mut self, channel: Channel) {
+        unsafe {
+            self.inner.enable_channel(channel, false);
+        }
+    }
+
+    pub fn set_freq(&mut self, freq: Hertz) {
+        self.inner.set_frequency(freq);
+    }
+
+    pub fn get_max_duty(&self) -> u16 {
+        unsafe { self.inner.get_max_compare_value() }
+    }
+
+    pub fn set_duty(&mut self, channel: Channel, duty: u16) {
+        assert!(duty < self.get_max_duty());
+        unsafe { self.inner.set_compare_value(channel, duty) }
+    }
+
+    /*
+        set the value of the dead-time register
+    */
+    pub fn set_dead_time_value(&mut self, value: u8) {
+        unsafe { self.inner.set_dead_time_value(value) }
+    }
+}
diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs
index d3713391c..6f3c12665 100644
--- a/embassy-stm32/src/pwm/mod.rs
+++ b/embassy-stm32/src/pwm/mod.rs
@@ -1,3 +1,4 @@
+pub mod complementary_pwm;
 pub mod simple_pwm;
 
 #[cfg(feature = "unstable-pac")]
@@ -67,6 +68,10 @@ pub(crate) mod sealed {
         unsafe fn get_max_compare_value(&self) -> u16;
     }
 
+    pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
+        unsafe fn set_dead_time_value(&mut self, value: u8);
+    }
+
     pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance {
         unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
 
@@ -82,6 +87,12 @@ pub trait CaptureCompare16bitInstance:
     sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static
 {
 }
+
+pub trait ComplementaryCaptureCompare16bitInstance:
+    sealed::ComplementaryCaptureCompare16bitInstance + crate::timer::AdvancedControlInstance + 'static
+{
+}
+
 pub trait CaptureCompare32bitInstance:
     sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + crate::timer::GeneralPurpose32bitInstance + 'static
 {
@@ -209,6 +220,17 @@ foreach_interrupt! {
         impl CaptureCompare16bitInstance for crate::peripherals::$inst {
 
         }
+
+        impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
+            unsafe fn set_dead_time_value(&mut self, value: u8) {
+                use crate::timer::sealed::AdvancedControlInstance;
+                Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
+            }
+        }
+
+        impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
+
+        }
     };
 }