Fix LED flickering while the buzzer is playing

This commit is contained in:
Alessandro Genova
2025-08-15 21:34:29 -04:00
parent 557a785b1a
commit bf9d89106f

View File

@ -43,6 +43,9 @@ static watch_cb_t _cb_start_global = NULL;
static watch_cb_t _cb_stop_global = NULL; static watch_cb_t _cb_stop_global = NULL;
static volatile bool _led_is_active = false; static volatile bool _led_is_active = false;
static volatile bool _buzzer_is_active = false; static volatile bool _buzzer_is_active = false;
static volatile uint8_t _current_led_color[3] = {0, 0, 0};
static void _watch_set_led_duty_cycle(uint32_t period, uint8_t red, uint8_t green, uint8_t blue);
static void _tcc_write_RUNSTDBY(bool value) { static void _tcc_write_RUNSTDBY(bool value) {
// enables or disables RUNSTDBY of the tcc // enables or disables RUNSTDBY of the tcc
@ -276,6 +279,11 @@ void watch_enable_buzzer(void) {
void watch_set_buzzer_period_and_duty_cycle(uint32_t period, uint8_t duty) { void watch_set_buzzer_period_and_duty_cycle(uint32_t period, uint8_t duty) {
tcc_set_period(0, period, true); tcc_set_period(0, period, true);
tcc_set_cc(0, (WATCH_BUZZER_TCC_CHANNEL) % 4, period / (100 / duty), true); tcc_set_cc(0, (WATCH_BUZZER_TCC_CHANNEL) % 4, period / (100 / duty), true);
// The buzzer determines the period, which means that if the LED was active before it will flicker
// Update the LED duty cycle to match the new period required by the buzzer.
if (_led_is_active) {
_watch_set_led_duty_cycle(period, _current_led_color[0], _current_led_color[1], _current_led_color[2]);
}
} }
void watch_disable_buzzer(void) { void watch_disable_buzzer(void) {
@ -400,10 +408,27 @@ void watch_set_led_color(uint8_t red, uint8_t green) {
#endif #endif
} }
static void _watch_set_led_duty_cycle(uint32_t period, uint8_t red, uint8_t green, uint8_t blue) {
tcc_set_cc(0, (WATCH_RED_TCC_CHANNEL) % 4, ((period * (uint32_t)red * 1000ull) / 255000ull), true);
#ifdef WATCH_GREEN_TCC_CHANNEL
tcc_set_cc(0, (WATCH_GREEN_TCC_CHANNEL) % 4, ((period * (uint32_t)green * 1000ull) / 255000ull), true);
#else
(void) green; // silence warning
#endif
#ifdef WATCH_BLUE_TCC_CHANNEL
tcc_set_cc(0, (WATCH_BLUE_TCC_CHANNEL) % 4, ((period * (uint32_t)blue * 1000ull) / 255000ull), true);
#else
(void) blue; // silence warning
#endif
}
void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue) { void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue) {
bool turning_on = (red | green | blue) != 0; bool turning_on = (red | green | blue) != 0;
if (turning_on) { if (turning_on) {
_current_led_color[0] = red;
_current_led_color[1] = green;
_current_led_color[2] = blue;
_led_is_active = true; _led_is_active = true;
watch_enable_buzzer_and_leds(); watch_enable_buzzer_and_leds();
} else { } else {
@ -412,17 +437,7 @@ void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue) {
if (tcc_is_enabled(0)) { if (tcc_is_enabled(0)) {
uint32_t period = tcc_get_period(0); uint32_t period = tcc_get_period(0);
tcc_set_cc(0, (WATCH_RED_TCC_CHANNEL) % 4, ((period * (uint32_t)red * 1000ull) / 255000ull), true); _watch_set_led_duty_cycle(period, red, green, blue);
#ifdef WATCH_GREEN_TCC_CHANNEL
tcc_set_cc(0, (WATCH_GREEN_TCC_CHANNEL) % 4, ((period * (uint32_t)green * 1000ull) / 255000ull), true);
#else
(void) green; // silence warning
#endif
#ifdef WATCH_BLUE_TCC_CHANNEL
tcc_set_cc(0, (WATCH_BLUE_TCC_CHANNEL) % 4, ((period * (uint32_t)blue * 1000ull) / 255000ull), true);
#else
(void) blue; // silence warning
#endif
} }
if (!turning_on) { if (!turning_on) {