From b7bb4b23f8e59e90cff4773cc1e93e493d72ae56 Mon Sep 17 00:00:00 2001
From: Ralf <jr-oss@gmx.net>
Date: Fri, 1 Mar 2024 13:50:14 +0100
Subject: [PATCH] STM32 SimplePwm: Fix regression and re-enable output pin

PR #2499 implemented timer hierarchy, but removed enable_outputs()
from trait CaptureCompare16bitInstance and from SimplePwm.

This functions is required for advanced timers to set bit BDTR.MOE
and to enable the output signal.
---
 embassy-stm32/src/timer/mod.rs        | 37 ++++++++++++++++++++++-----
 embassy-stm32/src/timer/simple_pwm.rs |  1 +
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 8530c5229..ef893c7f5 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -439,9 +439,9 @@ pub(crate) mod sealed {
             Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
         }
 
-        /// Enable timer outputs.
-        fn enable_outputs(&self) {
-            Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true));
+        /// Set state of MOE-bit in BDTR register to en-/disable output
+        fn set_moe(&self, enable: bool) {
+            Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable));
         }
     }
 
@@ -685,6 +685,13 @@ pub trait CaptureCompare16bitInstance:
     + sealed::GeneralPurpose16bitInstance
     + 'static
 {
+    // SimplePwm<'d, T> is implemented for T: CaptureCompare16bitInstance
+    // Advanced timers implement this trait, but the output needs to be
+    // enabled explicitly.
+    // To support general-purpose and advanced timers, this function is added
+    // here defaulting to noop and overwritten for advanced timers.
+    /// Enable timer outputs.
+    fn enable_outputs(&self) {}
 }
 
 #[cfg(not(stm32l0))]
@@ -911,7 +918,13 @@ foreach_interrupt! {
         impl_1ch_cmp_timer!($inst);
         impl_2ch_cmp_timer!($inst);
         impl BasicInstance for crate::peripherals::$inst {}
-        impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
+        impl CaptureCompare16bitInstance for crate::peripherals::$inst {
+            /// Enable timer outputs.
+            fn enable_outputs(&self) {
+                use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance;
+                self.set_moe(true);
+            }
+        }
         impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
     };
     ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => {
@@ -929,7 +942,13 @@ foreach_interrupt! {
         impl_1ch_cmp_timer!($inst);
         impl_2ch_cmp_timer!($inst);
         impl BasicInstance for crate::peripherals::$inst {}
-        impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
+        impl CaptureCompare16bitInstance for crate::peripherals::$inst {
+            /// Enable timer outputs.
+            fn enable_outputs(&self) {
+                use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance;
+                self.set_moe(true);
+            }
+        }
         impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
     };
     ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => {
@@ -947,7 +966,13 @@ foreach_interrupt! {
         impl_1ch_cmp_timer!($inst);
         impl_2ch_cmp_timer!($inst);
         impl BasicInstance for crate::peripherals::$inst {}
-        impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
+        impl CaptureCompare16bitInstance for crate::peripherals::$inst {
+            /// Enable timer outputs.
+            fn enable_outputs(&self) {
+                use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance;
+                self.set_moe(true);
+            }
+        }
         impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
     };
     ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => {
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 1acba504e..6df2f66ec 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -82,6 +82,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
 
         this.inner.set_counting_mode(counting_mode);
         this.set_frequency(freq);
+        this.inner.enable_outputs(); // Required for advanced timers, see CaptureCompare16bitInstance for details
         this.inner.start();
 
         [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]