Skip to content

Commit 983a5f7

Browse files
AudioManager: set MCLK frequency and duty cycle that doesn't wake up Fri3d Communicator when playing to headset
1 parent 972476e commit 983a5f7

2 files changed

Lines changed: 33 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ Builtin Apps:
99
Frameworks:
1010
- AudioManager: load and apply configured default_output and default_input devices
1111
- AudioManager: fix final 1-2 seconds of WAV files not being played
12+
- AudioManager: add support for PDM microphones
13+
- AudioManager: set MCLK frequency and duty cycle that doesn't wake up Fri3d Communicator when playing to headset
1214
- SensorManager: add BMA423 IMU support
1315
- TimeZone: set Real Time Clock if present
1416

1517
OS:
18+
- LilyGo T-Watch S3 Plus: add battery charge level support
19+
- LilyGo T-Watch S3 Plus: add IMU accelerometer support so IMU app works
1620
- LilyGo T-Watch S3 Plus: enable audio input (PDM microphone) and output (I2S speaker)
1721
- LilyGo T-Watch S3 Plus: enable Real Time Clock to keep time when powered off
18-
- LilyGo T-Watch S3 Plus: add IMU accelerometer support so IMU app works
19-
- LilyGo T-Watch S3 Plus: add battery charge level support
22+
- Fix lvgl_micropython UI hang when lv.event_handler() throws exception from timers or callbacks
2023

2124

2225

internal_filesystem/lib/mpos/audio/stream_wav.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ def get_progress_ms(self):
226226
def get_duration_ms(self):
227227
return self._duration_ms
228228

229+
229230
# ----------------------------------------------------------------------
230231
# WAV header parser - returns bit-depth and format info
231232
# ----------------------------------------------------------------------
@@ -370,6 +371,28 @@ def _convert_32_to_16(buf):
370371
out[i * 2] = s16 & 0xFF
371372
out[i * 2 + 1] = (s16 >> 8) & 0xFF
372373
j += 4
374+
375+
@staticmethod
376+
def _get_freq_duty(sample_rate):
377+
# Would be good to do this default when no communicator (external speaker) is connected, as it's better for quality:
378+
#return (sample_rate * 256, 32768)
379+
if sample_rate == 8000:
380+
return (640000,1365)
381+
elif sample_rate == 11025:
382+
return (1060800,1024)
383+
elif sample_rate == 16000:
384+
return (512000,512)
385+
elif sample_rate == 22050:
386+
return (705600,1024)
387+
elif sample_rate == 32000:
388+
print("Warning: sample rate 32kHz hasn't been testing, guessing!")
389+
return (1024000,1024)
390+
elif sample_rate == 44100:
391+
return (1411200,2048)
392+
else:
393+
print(f"Uncommon sample rate {sample_rate} hasn't been tried, returning default sample_rate * 256 amd 50% duty cycle")
394+
return (sample_rate * 256, 32768)
395+
373396
return out
374397

375398
# ----------------------------------------------------------------------
@@ -457,14 +480,12 @@ def play(self):
457480
if 'mck' in self.i2s_pins:
458481
mck_pin = machine.Pin(self.i2s_pins['mck'], machine.Pin.OUT)
459482
from machine import Pin, PWM
460-
# Add MCLK generation on GPIO2
461483
try:
462484
self._mck_pwm = PWM(mck_pin)
463-
# Set frequency to sample_rate * 256 (common ratio for CJC4334H auto-detect)
464-
# Use duty_u16 for finer control (0–65535 range, 32768 = 50%)
465-
self._mck_pwm.freq(playback_rate * 256)
466-
self._mck_pwm.duty_u16(32768) # 50% duty cycle
467-
print(f"MCLK PWM started on GPIO2 at {playback_rate * 256} Hz")
485+
freq, duty = WAVStream._get_freq_duty(playback_rate)
486+
self._mck_pwm.freq(freq)
487+
self._mck_pwm.duty_u16(duty) # 50% duty cycle
488+
print(f"MCLK PWM started at {freq} Hz with duty cycle {duty}/65535")
468489
except Exception as e:
469490
print(f"MCLK PWM init failed: {e}")
470491
# fallback or error handling
@@ -560,7 +581,7 @@ def play(self):
560581
print(f"_i2s.shift got exception, falling back to software scaling: {e}")
561582
_scale_audio_optimized(raw, len(raw), scale_fixed)
562583
else:
563-
print("_i2s has no shift attribute, falling back to software scaling")
584+
#print("_i2s has no shift attribute, falling back to software scaling")
564585
_scale_audio_optimized(raw, len(raw), scale_fixed)
565586

566587
# 4. Output to I2S (blocking write is OK - we're in a separate thread)

0 commit comments

Comments
 (0)