From 2e738db673d642692ff21c33e3e24b8308f9ab59 Mon Sep 17 00:00:00 2001 From: joeycastillo Date: Sun, 22 Sep 2024 13:34:46 -0400 Subject: [PATCH] add buzzer volume control --- .../watch_faces/complication/activity_face.c | 4 +-- .../complication/tuning_tones_face.c | 2 +- movement/watch_faces/demo/chirpy_demo_face.c | 6 ++--- watch-library/hardware/watch/watch_tcc.c | 14 +++++++---- watch-library/shared/watch/watch_tcc.h | 25 ++++++++++++++++--- watch-library/simulator/watch/watch_tcc.c | 7 +++--- 6 files changed, 41 insertions(+), 17 deletions(-) diff --git a/movement/watch_faces/complication/activity_face.c b/movement/watch_faces/complication/activity_face.c index f92984cd..136352f7 100644 --- a/movement/watch_faces/complication/activity_face.c +++ b/movement/watch_faces/complication/activity_face.c @@ -334,7 +334,7 @@ static void _activity_chirp_tick_transmit(void *context) { return; } uint16_t period = chirpy_get_tone_period(tone); - watch_set_buzzer_period(period); + watch_set_buzzer_period_and_duty_cycle(period, 25); watch_set_buzzer_on(); } @@ -351,7 +351,7 @@ static void _activity_chirp_tick_countdown(void *context) { } // Sound or turn off buzzer if ((state->chirpy_tick_state.seq_pos % 8) == 0) { - watch_set_buzzer_period(NotePeriods[BUZZER_NOTE_A5]); + watch_set_buzzer_period_and_duty_cycle(NotePeriods[BUZZER_NOTE_A5], 25); watch_set_buzzer_on(); if (state->chirpy_tick_state.seq_pos == 0) { watch_display_string(" --- ", 4); diff --git a/movement/watch_faces/complication/tuning_tones_face.c b/movement/watch_faces/complication/tuning_tones_face.c index a139427a..a12c076a 100644 --- a/movement/watch_faces/complication/tuning_tones_face.c +++ b/movement/watch_faces/complication/tuning_tones_face.c @@ -84,7 +84,7 @@ static void update_buzzer(const tuning_tones_state_t *state) { if (state->playing) { watch_set_buzzer_off(); - watch_set_buzzer_period(NotePeriods[notes[state->note_ind].note]); + watch_set_buzzer_period_and_duty_cycle(NotePeriods[notes[state->note_ind].note], 25); watch_set_buzzer_on(); } } diff --git a/movement/watch_faces/demo/chirpy_demo_face.c b/movement/watch_faces/demo/chirpy_demo_face.c index ee3e5b41..5c699018 100644 --- a/movement/watch_faces/demo/chirpy_demo_face.c +++ b/movement/watch_faces/demo/chirpy_demo_face.c @@ -168,7 +168,7 @@ static void _cdf_scale_tick(void *context) { } uint32_t freq = 700 + tick_state->seq_pos * 200; uint32_t period = 1000000 / freq; - watch_set_buzzer_period(period); + watch_set_buzzer_period_and_duty_cycle(period, 25); watch_set_buzzer_on(); ++tick_state->seq_pos; } @@ -183,7 +183,7 @@ static void _cdf_data_tick(void *context) { return; } uint16_t period = chirpy_get_tone_period(tone); - watch_set_buzzer_period(period); + watch_set_buzzer_period_and_duty_cycle(period, 25); watch_set_buzzer_on(); } @@ -234,7 +234,7 @@ static void _cdf_countdown_tick(void *context) { } // Sound or turn off buzzer if ((tick_state->seq_pos % 8) == 0) { - watch_set_buzzer_period(NotePeriods[BUZZER_NOTE_A5]); + watch_set_buzzer_period_and_duty_cycle(NotePeriods[BUZZER_NOTE_A5], 25); watch_set_buzzer_on(); } else if ((tick_state->seq_pos % 8) == 1) { watch_set_buzzer_off(); diff --git a/watch-library/hardware/watch/watch_tcc.c b/watch-library/hardware/watch/watch_tcc.c index efee7a98..41f8f933 100644 --- a/watch-library/hardware/watch/watch_tcc.c +++ b/watch-library/hardware/watch/watch_tcc.c @@ -110,7 +110,7 @@ void cb_watch_buzzer_seq(void) { // read note BuzzerNote note = _sequence[_seq_position]; if (note != BUZZER_NOTE_REST) { - watch_set_buzzer_period(NotePeriods[note]); + watch_set_buzzer_period_and_duty_cycle(NotePeriods[note], 25); watch_set_buzzer_on(); } else watch_set_buzzer_off(); // set duration ticks and move to next tone @@ -148,9 +148,9 @@ inline void watch_enable_buzzer(void) { } } -inline void watch_set_buzzer_period(uint32_t period) { +void watch_set_buzzer_period_and_duty_cycle(uint32_t period, uint8_t duty) { tcc_set_period(0, period, true); - tcc_set_cc(0, (WATCH_BUZZER_TCC_CHANNEL) % 4, period / 2, true); + tcc_set_cc(0, (WATCH_BUZZER_TCC_CHANNEL) % 4, period / (100 / duty), true); } void watch_disable_buzzer(void) { @@ -168,10 +168,14 @@ inline void watch_set_buzzer_off(void) { } void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms) { + watch_buzzer_play_note_with_volume(note, duration_ms, WATCH_BUZZER_VOLUME_LOUD); +} + +void watch_buzzer_play_note_with_volume(BuzzerNote note, uint16_t duration_ms, watch_buzzer_volume_t volume) { if (note == BUZZER_NOTE_REST) { watch_set_buzzer_off(); - } else { - watch_set_buzzer_period(NotePeriods[note]); + } else { + watch_set_buzzer_period_and_duty_cycle(NotePeriods[note], volume == WATCH_BUZZER_VOLUME_SOFT ? 5 : 25); watch_set_buzzer_on(); } delay_ms(duration_ms); diff --git a/watch-library/shared/watch/watch_tcc.h b/watch-library/shared/watch/watch_tcc.h index 6f965b66..7967637d 100644 --- a/watch-library/shared/watch/watch_tcc.h +++ b/watch-library/shared/watch/watch_tcc.h @@ -36,7 +36,8 @@ 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 the piezo buzzer embedded in the F-91W's back plate. + * @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. */ /// @{ /** @brief Enables the TCC peripheral, which drives the buzzer. @@ -46,8 +47,11 @@ void watch_enable_buzzer(void); /** @brief Sets the period of the buzzer. * @param period The period of a single cycle for the TCC peripheral. You can determine the period for * a desired frequency with the following formula: period = 1000000 / freq + * @param duty The duty cycle of the buzzer, from 0 to 50 (percent ON time). Do not use values over 50. + * @note Unless you _really_ know what you're doing, use 25% for the duty cycle. If you're just aiming + * to play a tone at a given volume, use watch_buzzer_play_note_with_volume instead. */ -void watch_set_buzzer_period(uint32_t period); +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, @@ -65,6 +69,12 @@ void watch_set_buzzer_on(void); */ void watch_set_buzzer_off(void); +/// @brief An enum for controlling the volume of the buzzer. +typedef enum { + WATCH_BUZZER_VOLUME_SOFT = 0, + WATCH_BUZZER_VOLUME_LOUD +} watch_buzzer_volume_t; + /// @brief 87 notes for use with watch_buzzer_play_note typedef enum BuzzerNote { BUZZER_NOTE_A1, ///< 55.00 Hz @@ -157,7 +167,7 @@ typedef enum BuzzerNote { BUZZER_NOTE_REST ///< no sound } BuzzerNote; -/** @brief Plays the given note for a set duration. +/** @brief Plays the given note for a set duration at the loudest possible volume. * @param note The note you wish to play, or BUZZER_NOTE_REST to disable output for the given duration. * @param duration_ms The duration of the note. * @note Note that this will block your UI for the duration of the note's play time, and it will @@ -165,6 +175,15 @@ typedef enum BuzzerNote { */ void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms); +/** @brief Plays the given note for a set duration. + * @param note The note you wish to play, or BUZZER_NOTE_REST to disable output for the given duration. + * @param duration_ms The duration of the note. + * @param volume either WATCH_BUZZER_VOLUME_SOFT or WATCH_BUZZER_VOLUME_LOUD + * @note This will block your UI for the duration of the note's play time, and after this call, the + * buzzer will stop sounding, but the TCC period will remain set to the period of this note. + */ +void watch_buzzer_play_note_with_volume(BuzzerNote note, uint16_t duration_ms, watch_buzzer_volume_t volume); + /// @brief An array of periods for all the notes on a piano, corresponding to the names in BuzzerNote. extern const uint16_t NotePeriods[108]; diff --git a/watch-library/simulator/watch/watch_tcc.c b/watch-library/simulator/watch/watch_tcc.c index 77c06401..fa1e1a8c 100644 --- a/watch-library/simulator/watch/watch_tcc.c +++ b/watch-library/simulator/watch/watch_tcc.c @@ -89,7 +89,7 @@ void cb_watch_buzzer_seq(void *userData) { if (note == BUZZER_NOTE_REST) { watch_set_buzzer_off(); } else { - watch_set_buzzer_period(NotePeriods[note]); + watch_set_buzzer_period_and_duty_cycle(NotePeriods[note], 25); watch_set_buzzer_on(); } // set duration ticks and move to next tone @@ -118,7 +118,8 @@ void watch_enable_buzzer(void) { }); } -void watch_set_buzzer_period(uint32_t period) { +void watch_set_buzzer_period_and_duty_cycle(uint32_t period, uint8_t duty_cycle) { + (void) duty_cycle; if (!buzzer_enabled) return; buzzer_period = period; } @@ -174,7 +175,7 @@ void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms) { if (note == BUZZER_NOTE_REST) { watch_set_buzzer_off(); } else { - watch_set_buzzer_period(NotePeriods[note]); + watch_set_buzzer_period_and_duty_cycle(NotePeriods[note], 25); watch_set_buzzer_on(); }