mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-08-04 11:16:13 +00:00
fix: improve buzzer volume control on nRF52
- Use inverted PWM polarity (0x8000) with PCT {2,5,12,25,50} giving
~6-8 dB perceptual steps (-24/-16/-9/-3/0 dB) vs the original
uneven steps where levels 4 and 5 were only 1 dB apart
- Guard against cmp=0 truncation in both _nrfStartPwm and applyVolume:
at level 1 with high notes (freq > ~2.5 kHz) integer math gives
cmp=0 which with inverted polarity means 100% HIGH → complete silence
- Change volume preview note from C5 (523 Hz) to C6 (1047 Hz) to better
match the piezo resonant frequency range and actual notification sounds
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
31e91bda21
commit
6399df1f4a
@@ -1560,7 +1560,7 @@ void UITask::setBuzzerVolumeLevel(uint8_t level) {
|
|||||||
if (level > 4) level = 4;
|
if (level > 4) level = 4;
|
||||||
_node_prefs->buzzer_volume = level;
|
_node_prefs->buzzer_volume = level;
|
||||||
buzzer.setVolume(level);
|
buzzer.setVolume(level);
|
||||||
if (level > 0) buzzer.playForced("Vol:d=16,o=5,b=120:c");
|
if (level > 0) buzzer.playForced("Vol:d=16,o=6,b=120:c");
|
||||||
_next_refresh = 0;
|
_next_refresh = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,9 @@ bool genericBuzzer::_parseNext(const char*& p, uint8_t def_dur, uint8_t def_oct,
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t genericBuzzer::_dutyPct() const {
|
uint8_t genericBuzzer::_dutyPct() const {
|
||||||
static const uint8_t PCT[5] = { 2, 8, 20, 35, 50 };
|
// Inverted polarity (0x8000 bit): duty_HIGH = 100% - PCT.
|
||||||
|
// Values chosen for ~6-8 dB perceptual steps: -24/-16/-9/-3/0 dB.
|
||||||
|
static const uint8_t PCT[5] = { 2, 5, 12, 25, 50 };
|
||||||
return PCT[_volume_level < 5 ? _volume_level : 4];
|
return PCT[_volume_level < 5 ? _volume_level : 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +98,7 @@ void genericBuzzer::_nrfStartPwm(uint16_t freq) {
|
|||||||
uint32_t nrf_pin = g_ADigitalPinMap[PIN_BUZZER];
|
uint32_t nrf_pin = g_ADigitalPinMap[PIN_BUZZER];
|
||||||
uint16_t top = 125000 / freq;
|
uint16_t top = 125000 / freq;
|
||||||
uint16_t cmp = (uint16_t)(((uint32_t)top * _dutyPct()) / 100);
|
uint16_t cmp = (uint16_t)(((uint32_t)top * _dutyPct()) / 100);
|
||||||
|
if (cmp == 0) cmp = 1; // inverted polarity: cmp=0 → 100% HIGH → no AC → silence
|
||||||
|
|
||||||
// Write duty BEFORE SEQSTART so DMA reads our value on the very first period
|
// Write duty BEFORE SEQSTART so DMA reads our value on the very first period
|
||||||
_duty_buf = 0x8000U | cmp;
|
_duty_buf = 0x8000U | cmp;
|
||||||
@@ -168,6 +171,7 @@ void genericBuzzer::applyVolume() {
|
|||||||
if (!_pwm_on) return;
|
if (!_pwm_on) return;
|
||||||
uint16_t top = (uint16_t)NRF_PWM2->COUNTERTOP;
|
uint16_t top = (uint16_t)NRF_PWM2->COUNTERTOP;
|
||||||
uint16_t cmp = (uint16_t)(((uint32_t)top * _dutyPct()) / 100);
|
uint16_t cmp = (uint16_t)(((uint32_t)top * _dutyPct()) / 100);
|
||||||
|
if (cmp == 0) cmp = 1;
|
||||||
_duty_buf = 0x8000U | cmp; // DMA picks this up within one period (< 2.3 ms at A4)
|
_duty_buf = 0x8000U | cmp; // DMA picks this up within one period (< 2.3 ms at A4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user