From fb8351b325d9b7e345335aa83d249ca894900e4f Mon Sep 17 00:00:00 2001 From: David Hoelscher Date: Fri, 18 Oct 2024 21:35:13 -0500 Subject: [PATCH 1/6] always return audio pin to 0 on ARM --- .../chibios/drivers/audio_pwm_hardware.c | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c index 1ba7ec13bcf..0667b398586 100644 --- a/platforms/chibios/drivers/audio_pwm_hardware.c +++ b/platforms/chibios/drivers/audio_pwm_hardware.c @@ -31,6 +31,20 @@ extern bool playing_note; extern bool playing_melody; extern uint8_t note_timbre; +static bool channel_1_stopped = true; + +void channel_1_stop(void); +void channel_1_start(void); + +void audio_wait_for_pin(pin_t pin, uint8_t target_state) { + rtcnt_t start = chSysGetRealtimeCounterX(); + rtcnt_t end = start + 5000; + while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) { + if (gpio_read_pin(pin) == target_state) { + break; + } + } +} static PWMConfig pwmCFG = {.frequency = AUDIO_PWM_COUNTER_FREQUENCY, /* PWM clock frequency */ .period = 2, @@ -44,8 +58,12 @@ void channel_1_set_frequency(float freq) { if (freq <= 0.0) { // a pause/rest has freq=0 + channel_1_stop(); return; } + if (channel_1_stopped) { + channel_1_start(); + } pwmcnt_t period = (pwmCFG.frequency / freq); chSysLockFromISR(); @@ -63,12 +81,32 @@ float channel_1_get_frequency(void) { void channel_1_start(void) { pwmStop(&AUDIO_PWM_DRIVER); pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); + channel_1_stopped = false; } void channel_1_stop(void) { - pwmStop(&AUDIO_PWM_DRIVER); -} + // only certain timers will disable the output (set to zero) when the pwm is stopped. + // to ensure the pin is low (without having changing the pin modes), set the + // frequency to the highest valid value and wait for the pin to be zero + chSysLockFromISR(); + pwmChangePeriodI(&AUDIO_PWM_DRIVER, 2); + pwmEnableChannelI(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, + // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH + PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, 5000)); + chSysUnlockFromISR(); + // try stopping now if the pin is currently low + audio_wait_for_pin(AUDIO_PIN,0); + pwmStop(&AUDIO_PWM_DRIVER); + + // if it isn't actively low, it was stopped a little too late, so keep trying (should only need one more attempt) + while (gpio_read_pin(AUDIO_PIN) == 1) { + pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); + audio_wait_for_pin(AUDIO_PIN,0); + pwmStop(&AUDIO_PWM_DRIVER); + } + channel_1_stopped = true; +} static virtual_timer_t audio_vt; static void audio_callback(virtual_timer_t *vtp, void *p); From 9b8d4803dcd60042412f321a0683e4806edc4042 Mon Sep 17 00:00:00 2001 From: David Hoelscher Date: Sat, 19 Oct 2024 02:49:07 -0500 Subject: [PATCH 2/6] switch to timer_read for limiting audio pin wait times --- platforms/chibios/drivers/audio_pwm_hardware.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c index 0667b398586..a69e039bc58 100644 --- a/platforms/chibios/drivers/audio_pwm_hardware.c +++ b/platforms/chibios/drivers/audio_pwm_hardware.c @@ -13,6 +13,7 @@ #include "audio.h" #include "gpio.h" +#include "timer.h" #if !defined(AUDIO_PIN) # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" @@ -37,9 +38,9 @@ void channel_1_stop(void); void channel_1_start(void); void audio_wait_for_pin(pin_t pin, uint8_t target_state) { - rtcnt_t start = chSysGetRealtimeCounterX(); - rtcnt_t end = start + 5000; - while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) { + uint16_t wait_limiter_timer; + wait_limiter_timer = timer_read(); + while (timer_elapsed(wait_limiter_timer) < 2) { if (gpio_read_pin(pin) == target_state) { break; } @@ -99,8 +100,11 @@ void channel_1_stop(void) { audio_wait_for_pin(AUDIO_PIN,0); pwmStop(&AUDIO_PWM_DRIVER); - // if it isn't actively low, it was stopped a little too late, so keep trying (should only need one more attempt) - while (gpio_read_pin(AUDIO_PIN) == 1) { + uint16_t wait_limiter_timer; + wait_limiter_timer = timer_read(); + // if it isn't actively low, it may have been stopped a little too late, so keep trying + // it should not require very many attempts, so limit to 2ms maximum wait time as a failsafe + while ((gpio_read_pin(AUDIO_PIN) == 1) && (timer_elapsed(wait_limiter_timer) < 2)) { pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); audio_wait_for_pin(AUDIO_PIN,0); pwmStop(&AUDIO_PWM_DRIVER); From 0179f979e58b6c107e7c0031b117c078bd6b01c6 Mon Sep 17 00:00:00 2001 From: David Hoelscher Date: Sun, 20 Oct 2024 17:57:50 -0500 Subject: [PATCH 3/6] updated return-to-zero method to use pwm width of 0 --- .../chibios/drivers/audio_pwm_hardware.c | 62 ++++--------------- 1 file changed, 12 insertions(+), 50 deletions(-) diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c index a69e039bc58..6d374a27812 100644 --- a/platforms/chibios/drivers/audio_pwm_hardware.c +++ b/platforms/chibios/drivers/audio_pwm_hardware.c @@ -13,7 +13,6 @@ #include "audio.h" #include "gpio.h" -#include "timer.h" #if !defined(AUDIO_PIN) # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" @@ -32,20 +31,6 @@ extern bool playing_note; extern bool playing_melody; extern uint8_t note_timbre; -static bool channel_1_stopped = true; - -void channel_1_stop(void); -void channel_1_start(void); - -void audio_wait_for_pin(pin_t pin, uint8_t target_state) { - uint16_t wait_limiter_timer; - wait_limiter_timer = timer_read(); - while (timer_elapsed(wait_limiter_timer) < 2) { - if (gpio_read_pin(pin) == target_state) { - break; - } - } -} static PWMConfig pwmCFG = {.frequency = AUDIO_PWM_COUNTER_FREQUENCY, /* PWM clock frequency */ .period = 2, @@ -56,22 +41,19 @@ static float channel_1_frequency = 0.0f; void channel_1_set_frequency(float freq) { channel_1_frequency = freq; + pwmcnt_t period; + pwmcnt_t width; if (freq <= 0.0) { - // a pause/rest has freq=0 - channel_1_stop(); - return; + period = 2; + width = 0; + } else { + period = (pwmCFG.frequency / freq); + width = PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100); } - if (channel_1_stopped) { - channel_1_start(); - } - - pwmcnt_t period = (pwmCFG.frequency / freq); chSysLockFromISR(); pwmChangePeriodI(&AUDIO_PWM_DRIVER, period); - pwmEnableChannelI(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, - // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH - PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100)); + pwmEnableChannelI(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, width); chSysUnlockFromISR(); } @@ -82,35 +64,15 @@ float channel_1_get_frequency(void) { void channel_1_start(void) { pwmStop(&AUDIO_PWM_DRIVER); pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); - channel_1_stopped = false; } void channel_1_stop(void) { - // only certain timers will disable the output (set to zero) when the pwm is stopped. - // to ensure the pin is low (without having changing the pin modes), set the - // frequency to the highest valid value and wait for the pin to be zero - chSysLockFromISR(); - pwmChangePeriodI(&AUDIO_PWM_DRIVER, 2); - pwmEnableChannelI(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, - // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH - PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, 5000)); - chSysUnlockFromISR(); - - // try stopping now if the pin is currently low - audio_wait_for_pin(AUDIO_PIN,0); pwmStop(&AUDIO_PWM_DRIVER); - - uint16_t wait_limiter_timer; - wait_limiter_timer = timer_read(); - // if it isn't actively low, it may have been stopped a little too late, so keep trying - // it should not require very many attempts, so limit to 2ms maximum wait time as a failsafe - while ((gpio_read_pin(AUDIO_PIN) == 1) && (timer_elapsed(wait_limiter_timer) < 2)) { - pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); - audio_wait_for_pin(AUDIO_PIN,0); - pwmStop(&AUDIO_PWM_DRIVER); - } - channel_1_stopped = true; + pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); + pwmEnableChannelI(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, 0); + pwmStop(&AUDIO_PWM_DRIVER); } + static virtual_timer_t audio_vt; static void audio_callback(virtual_timer_t *vtp, void *p); From 9948b0541079203da3233a0e966bf3a39ac0d403 Mon Sep 17 00:00:00 2001 From: David Hoelscher Date: Sun, 20 Oct 2024 18:09:16 -0500 Subject: [PATCH 4/6] lint correction --- platforms/chibios/drivers/audio_pwm_hardware.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c index 6d374a27812..ce1e8e26dd6 100644 --- a/platforms/chibios/drivers/audio_pwm_hardware.c +++ b/platforms/chibios/drivers/audio_pwm_hardware.c @@ -46,10 +46,10 @@ void channel_1_set_frequency(float freq) { if (freq <= 0.0) { period = 2; - width = 0; + width = 0; } else { period = (pwmCFG.frequency / freq); - width = PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100); + width = PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100); } chSysLockFromISR(); pwmChangePeriodI(&AUDIO_PWM_DRIVER, period); From d29cc98240fcfcec78e1a772bbe5ff36c5e56d8d Mon Sep 17 00:00:00 2001 From: David Hoelscher Date: Tue, 22 Oct 2024 00:38:56 -0500 Subject: [PATCH 5/6] fixed tone playing after a rest, optimized tone stopping algorithm --- platforms/chibios/drivers/audio_pwm_hardware.c | 4 ++-- quantum/audio/audio.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c index ce1e8e26dd6..afa341abb60 100644 --- a/platforms/chibios/drivers/audio_pwm_hardware.c +++ b/platforms/chibios/drivers/audio_pwm_hardware.c @@ -49,7 +49,7 @@ void channel_1_set_frequency(float freq) { width = 0; } else { period = (pwmCFG.frequency / freq); - width = PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100); + width = (pwmcnt_t)(((period) * (pwmcnt_t)((100 - note_timbre) * 100)) / (pwmcnt_t)(10000)); } chSysLockFromISR(); pwmChangePeriodI(&AUDIO_PWM_DRIVER, period); @@ -69,7 +69,7 @@ void channel_1_start(void) { void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); - pwmEnableChannelI(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, 0); + pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, 0); pwmStop(&AUDIO_PWM_DRIVER); } diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c index b2611c5f099..802a62395b8 100644 --- a/quantum/audio/audio.c +++ b/quantum/audio/audio.c @@ -258,11 +258,10 @@ void audio_stop_tone(float pitch) { for (int i = AUDIO_TONE_STACKSIZE - 1; i >= 0; i--) { found = (tones[i].pitch == pitch); if (found) { - tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0}; for (int j = i; (j < AUDIO_TONE_STACKSIZE - 1); j++) { tones[j] = tones[j + 1]; - tones[j + 1] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0}; } + tones[AUDIO_TONE_STACKSIZE - 1] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0}; break; } } From f664d766e46155545beb82d409f083d86bad5d0d Mon Sep 17 00:00:00 2001 From: David Hoelscher Date: Tue, 22 Oct 2024 01:14:05 -0500 Subject: [PATCH 6/6] lint --- quantum/audio/audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c index 802a62395b8..2cc3c2d6613 100644 --- a/quantum/audio/audio.c +++ b/quantum/audio/audio.c @@ -259,7 +259,7 @@ void audio_stop_tone(float pitch) { found = (tones[i].pitch == pitch); if (found) { for (int j = i; (j < AUDIO_TONE_STACKSIZE - 1); j++) { - tones[j] = tones[j + 1]; + tones[j] = tones[j + 1]; } tones[AUDIO_TONE_STACKSIZE - 1] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0}; break;