]> git.earman.xyz Git - sensor-watch.git/commitdiff
Improve watch_tcc to decouple leds and buzzer as much as allowed
authorAlessandro Genova <ales.genova@gmail.com>
Mon, 18 Aug 2025 03:14:25 +0000 (23:14 -0400)
committerAlessandro Genova <ales.genova@gmail.com>
Sat, 3 Jan 2026 01:07:56 +0000 (20:07 -0500)
As a positive side effect, the led will stop emitting the faintiest
of blinks when the buzzer starts playing.

watch-library/hardware/watch/watch_deepsleep.c
watch-library/hardware/watch/watch_tcc.c
watch-library/shared/watch/watch_tcc.h
watch-library/simulator/watch/watch.c
watch-library/simulator/watch/watch_private.c
watch-library/simulator/watch/watch_tcc.c

index e90150ee6c14cefee7ba42cfbccfe71283271067..20254df4a517fc83c83d94c5c20b5f7c5810145a 100644 (file)
@@ -151,7 +151,8 @@ static void _watch_disable_all_pins_except_rtc(void) {
 }
 
 static void _watch_disable_all_peripherals_except_slcd(void) {
-    _watch_disable_tcc();
+    watch_disable_leds();
+    watch_disable_buzzer();
     watch_disable_adc();
     watch_disable_external_interrupts();
 
index fa81d0749b08b6da12987ebe2b050af4b6693235..cde3c0dd6f2cc374e43a8dd24f5a815da60adc51 100644 (file)
 #include "tcc.h"
 #include "tc.h"
 
-void _watch_enable_tcc(void);
+static void _watch_enable_tcc(void);
+static void _watch_disable_tcc(void);
+static void _watch_maybe_enable_tcc(void);
+static void _watch_maybe_disable_tcc(void);
+static void _watch_enable_led_pins(void);
+static void _watch_disable_led_pins(void);
 static void (*_cb_tc0)(void) = NULL;
-void cb_watch_buzzer_seq(void);
-void cb_watch_buzzer_raw_source(void);
+static void cb_watch_buzzer_seq(void);
+static void cb_watch_buzzer_raw_source(void);
 
 static uint16_t _seq_position;
 static int8_t _tone_ticks, _repeat_counter;
@@ -84,14 +89,11 @@ void watch_buzzer_play_sequence_with_volume(int8_t *note_sequence, void (*callba
     // Abort any previous sequence
     watch_buzzer_abort_sequence();
 
-    _buzzer_is_active = true;
-
     if (_cb_start_global) {
         _cb_start_global();
     }
 
-    watch_enable_buzzer_and_leds();
-
+    watch_enable_buzzer();
     watch_set_buzzer_off();
     _sequence = note_sequence;
     _cb_finished = callback_on_end;
@@ -154,13 +156,11 @@ void watch_buzzer_play_raw_source_with_volume(watch_buzzer_raw_source_t raw_sour
     // Abort any previous sequence
     watch_buzzer_abort_sequence();
 
-    _buzzer_is_active = true;
-
     if (_cb_start_global) {
         _cb_start_global();
     }
 
-    watch_enable_buzzer_and_leds();
+    watch_enable_buzzer();
 
     watch_set_buzzer_off();
     _raw_source = raw_source;
@@ -213,14 +213,12 @@ void watch_buzzer_abort_sequence(void) {
         return;
     }
 
-    _buzzer_is_active = false;
-
     _tc0_stop();
 
     watch_set_buzzer_off();
 
     // disable TCC
-    watch_maybe_disable_buzzer_and_leds();
+    watch_disable_buzzer();
 
     if (_cb_stop_global) {
         _cb_stop_global();
@@ -244,11 +242,11 @@ void irq_handler_tc0(void) {
     TC0->COUNT8.INTFLAG.reg |= TC_INTFLAG_OVF;
 }
 
-bool watch_is_buzzer_or_led_enabled(void){
-    return tcc_is_enabled(0);
-}
+void _watch_maybe_enable_tcc(void) {
+    if (!_buzzer_is_active && !_led_is_active) {
+        return;
+    }
 
-void watch_enable_buzzer_and_leds(void) {
     if (!tcc_is_enabled(0)) {
         // tcc_set_run_in_standby(0, true);
         _watch_enable_tcc();
@@ -257,23 +255,26 @@ void watch_enable_buzzer_and_leds(void) {
     }
 }
 
-void watch_disable_buzzer_and_leds(void) {
+void _watch_maybe_disable_tcc(void) {
+    if (_buzzer_is_active || _led_is_active) {
+        return;
+    }
+
     if (tcc_is_enabled(0)) {
         _tcc_write_RUNSTDBY(false);
         _watch_disable_tcc();
     }
 }
 
-void watch_maybe_disable_buzzer_and_leds(void) {
-    if (_buzzer_is_active || _led_is_active) {
-        return;
-    }
-
-    watch_disable_buzzer_and_leds();
+void watch_enable_buzzer(void) {
+    _buzzer_is_active = true;
+    _watch_maybe_enable_tcc();
 }
 
-void watch_enable_buzzer(void) {
-    watch_enable_buzzer_and_leds();
+void watch_disable_buzzer(void) {
+    _buzzer_is_active = false;
+    watch_set_buzzer_off();
+    _watch_maybe_disable_tcc();
 }
 
 void watch_set_buzzer_period_and_duty_cycle(uint32_t period, uint8_t duty) {
@@ -286,10 +287,6 @@ void watch_set_buzzer_period_and_duty_cycle(uint32_t period, uint8_t duty) {
     }
 }
 
-void watch_disable_buzzer(void) {
-    watch_maybe_disable_buzzer_and_leds();
-}
-
 inline void watch_set_buzzer_on(void) {
     HAL_GPIO_BUZZER_out();
     HAL_GPIO_BUZZER_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
@@ -356,6 +353,40 @@ void _watch_enable_tcc(void) {
     tcc_set_cc(0, (WATCH_BLUE_TCC_CHANNEL) % 4, 0, false);
 #endif
 
+    // Enable the TCC
+    tcc_enable(0);
+}
+
+void _watch_disable_tcc(void) {
+    // disable all PWM pins
+    HAL_GPIO_BUZZER_pmuxdis();
+    HAL_GPIO_BUZZER_off();
+    HAL_GPIO_RED_pmuxdis();
+    HAL_GPIO_RED_off();
+#ifdef WATCH_GREEN_TCC_CHANNEL
+    HAL_GPIO_GREEN_pmuxdis();
+    HAL_GPIO_GREEN_off();
+#endif
+#ifdef WATCH_BLUE_TCC_CHANNEL
+    HAL_GPIO_BLUE_pmuxdis();
+    HAL_GPIO_BLUE_off();
+#endif
+    tcc_disable(0);
+}
+
+void watch_enable_leds(void) {
+    _led_is_active = true;
+    _watch_enable_led_pins();
+    _watch_maybe_enable_tcc();
+}
+
+void watch_disable_leds(void) {
+    _led_is_active = false;
+    _watch_disable_led_pins();
+    _watch_maybe_disable_tcc();
+}
+
+void _watch_enable_led_pins(void) {
     // enable LED PWM pins (the LED driver assumes if the TCC is on, the pins are enabled)
     HAL_GPIO_RED_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
     HAL_GPIO_RED_drvstr(1);
@@ -370,15 +401,9 @@ void _watch_enable_tcc(void) {
     HAL_GPIO_BLUE_drvstr(1);
     HAL_GPIO_BLUE_out();
 #endif
-
-    // Enable the TCC
-    tcc_enable(0);
 }
 
-void _watch_disable_tcc(void) {
-    // disable all PWM pins
-    HAL_GPIO_BUZZER_pmuxdis();
-    HAL_GPIO_BUZZER_off();
+void _watch_disable_led_pins(void) {
     HAL_GPIO_RED_pmuxdis();
     HAL_GPIO_RED_off();
 #ifdef WATCH_GREEN_TCC_CHANNEL
@@ -389,15 +414,6 @@ void _watch_disable_tcc(void) {
     HAL_GPIO_BLUE_pmuxdis();
     HAL_GPIO_BLUE_off();
 #endif
-    tcc_disable(0);
-}
-
-void watch_enable_leds(void) {
-    watch_enable_buzzer_and_leds();
-}
-
-void watch_disable_leds(void) {
-    watch_maybe_disable_buzzer_and_leds();
 }
 
 void watch_set_led_color(uint8_t red, uint8_t green) {
@@ -429,19 +445,14 @@ void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue) {
         _current_led_color[0] = red;
         _current_led_color[1] = green;
         _current_led_color[2] = blue;
-        _led_is_active = true;
-        watch_enable_buzzer_and_leds();
-    } else {
-        _led_is_active = false;
-    }
-
-    if (tcc_is_enabled(0)) {
+        watch_enable_leds();
         uint32_t period = tcc_get_period(0);
         _watch_set_led_duty_cycle(period, red, green, blue);
-    }
-
-    if (!turning_on) {
-        watch_maybe_disable_buzzer_and_leds();
+    } else {
+        if (tcc_is_enabled(0)) {
+            _watch_set_led_duty_cycle(1, red, green, blue);
+        }
+        watch_disable_leds();
     }
 }
 
index e87e53bf0e26df8ce5231c7b86aacdc187ecde62..056844b3ba0605f6aa17296f792f9a7b05fd11d7 100644 (file)
@@ -130,13 +130,6 @@ typedef enum {
 
 typedef bool (*watch_buzzer_raw_source_t)(uint16_t position, void* userdata, uint16_t* period, uint16_t* duration);
 
-/** @brief Returns true if either the buzzer or the LED driver is enabled.
-  * @details Both the buzzer and the LED use the TCC peripheral to drive their behavior. This function returns true if that
-  *          peripheral is enabled. You can use this function to determine whether you need to call the watch_enable_leds or
-  *          or watch_enable_buzzer functions before using these peripherals.
-  */
-bool watch_is_buzzer_or_led_enabled(void);
-
 /** @addtogroup tcc Buzzer and LED Control (via the TCC peripheral)
   * @brief This section covers functions related to Timer Counter for Control peripheral, which drives the piezo buzzer
   *        embedded in the F-91W's back plate as well as the LED that backlights the display.
@@ -155,15 +148,13 @@ void watch_enable_buzzer(void);
   */
 void watch_set_buzzer_period_and_duty_cycle(uint32_t period, uint8_t duty);
 
-/** @brief Disables the TCC peripheral that drives the buzzer.
-  * @note If you are using PWM to set custom LED colors, this method will also disable the LED PWM driver,
-  *       since the buzzer and LED both make use of the same peripheral to drive their PWM behavior.
+/** @brief Disables the TCC peripheral that drives the buzzer (if LED not active).
   */
 void watch_disable_buzzer(void);
 
 /** @brief Turns the buzzer output on. It will emit a continuous sound at the given frequency.
-  * @note The TCC peripheral that drives the buzzer does not run in standby mode; if you wish for buzzer
-  *       output to continue, you should prevent your app from going to sleep.
+  * @note The TCC peripheral that drives the buzzer does run in standby mode; if you wish for buzzer
+  *       output to continue, you don't need to prevent your app from going to sleep.
   */
 void watch_set_buzzer_on(void);
 
@@ -265,18 +256,6 @@ void watch_buzzer_abort_sequence(void);
 
 void watch_buzzer_register_global_callbacks(watch_cb_t cb_start, watch_cb_t cb_stop);
 
-/** @brief Enables the TCC peripheral, which drives the buzzer and the leds.
-*/
-void watch_enable_buzzer_and_leds(void);
-
-/** @brief Disables the TCC peripheral that drives the buzzer and the leds.
- */
-void watch_disable_buzzer_and_leds(void);
-
-/** @brief Disables the TCC peripheral that drives the buzzer and the leds if neither is currently active
- */
-void watch_maybe_disable_buzzer_and_leds(void);
-
 #ifndef __EMSCRIPTEN__
 void irq_handler_tc0(void);
 #endif
@@ -294,26 +273,17 @@ void irq_handler_tc0(void);
   *       so that watch_set_led_red sets the red LED, and watch_set_led_green sets the blue one.
   */
 /// @{
-/** @brief Enables the bi-color LED.
-  * @note The TCC peripheral that drives the LEDs does not run in STANDBY mode — but the outputs do! This
-  *       means that if you set either red, green or both LEDs to full power, they will shine even when
-  *       your app is asleep. If, however, you set a custom color using watch_set_led_color, the color will
-  *       not display correctly in STANDBY mode. You will need to keep your app running while the LED is on.
+/** @brief Enables the TCC peripheral, which drives the LEDs.
   */
 void watch_enable_leds(void);
 
-/** @brief Disables the LEDs.
-  * @note This method will also disable the buzzer, since the buzzer and LED both make use of the same
-  *       peripheral to drive their PWM behavior.
+/** @brief Disables the TCC peripheral that drives the LEDs (if buzzer not active).
   */
 void watch_disable_leds(void);
 
 /** @brief Sets the LED to a custom color by modulating each output's duty cycle.
   * @param red The red value from 0-255.
   * @param green The green value from 0-255. If your watch has a red/blue LED, this will be the blue value.
-  * @note If you are displaying a custom color, you will need to prevent your app from going to sleep
-  *       while the LED is on; otherwise, the color will not display correctly. You can do this by
-  *       returning false in your app_loop method.
   */
 void watch_set_led_color(uint8_t red, uint8_t green);
 
@@ -321,9 +291,6 @@ void watch_set_led_color(uint8_t red, uint8_t green);
   * @param red The red value from 0-255.
   * @param green The green value from 0-255.
   * @param blue The blue value from 0-255.
-  * @note If you are displaying a custom color, you will need to prevent your app from going to sleep
-  *       while the LED is on; otherwise, the color will not display correctly. You can do this by
-  *       returning false in your app_loop method.
   */
 void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue);
 
@@ -348,9 +315,6 @@ void watch_set_led_yellow(void);
 /** @brief Turns both the red and the green LEDs off. */
 void watch_set_led_off(void);
 
-/** @brief Disables the TCC peripheral. Should only be called internally. */
-void _watch_disable_tcc(void);
-
 /// @brief An array of periods for all the notes on a piano, corresponding to the names in watch_buzzer_note_t.
 extern const uint16_t NotePeriods[108];
 
index 4e89f3d335d2d9ed1c5e30105a7ba0092dfcab06..7584cd38af508211ec7506f298f70b577babd904 100644 (file)
@@ -1,9 +1,5 @@
 #include "watch.h"
 
-bool watch_is_buzzer_or_led_enabled(void) {
-    return false;
-}
-
 bool watch_is_usb_enabled(void) {
     return true;
 }
index 6f97490ba650e16dc69781dff5a9884388effb9b..b94fbf12d84f6a2aa9aca318a3a18571fcadc3f6 100644 (file)
@@ -51,8 +51,6 @@ int _gettimeofday(struct timeval *tv, void *tzvp) {
     return 0;
 }
 
-void _watch_disable_tcc(void) {}
-
 void _watch_enable_usb(void) {}
 
 void watch_disable_TRNG() {}
index 1ca4bbf0e2930e21997abc32e50268f70fef17da..6cbf98226564d666dfc1369d4a5cbde2824f43bf 100644 (file)
@@ -46,8 +46,6 @@ static watch_cb_t _cb_start_global = NULL;
 static watch_cb_t _cb_stop_global = NULL;
 static volatile bool _buzzer_is_active = false;
 
-void _watch_enable_tcc(void) {}
-
 static inline void _em_interval_stop() {
     emscripten_clear_interval(_em_interval_id);
     _em_interval_id = 0;