import time import machine from machine import Pin, I2S import board_config def play_ram_pcm(audio_chunks, channels=2, rate=16000, bits=16, volume=90): from audio_util import ES8311 # 1. Start MCLK PWM using board config parameters mclk_pwm = None if board_config.audio_mclk_pin is not None: mclk_pin = Pin(board_config.audio_mclk_pin, Pin.OUT) mclk_pwm = machine.PWM(mclk_pin) mclk_pwm.freq(board_config.audio_mclk_freq) mclk_pwm.duty_u16(32768) # 2. Wake up and configure ES8311 DAC dac = ES8311(board_config.i2c_bus) dac.init(sample_rate=rate) dac.set_volume(volume) # 3. Configure I2S TX i2s_format = I2S.MONO if channels == 1 else I2S.STEREO i2s = I2S(1, sck=Pin(board_config.audio_i2s_sck), ws=Pin(board_config.audio_i2s_ws), sd=Pin(board_config.audio_i2s_tx_sd), mode=I2S.TX, ibuf=4096, rate=rate, bits=bits, format=i2s_format) # 4. Enable Speaker Amplifier on_val = 0 if board_config.audio_amp_active_level == 0 else 1 off_val = 1 if board_config.audio_amp_active_level == 0 else 0 amp_pin = Pin(board_config.audio_amp_pin, Pin.OUT, value=on_val) try: print(f"Streaming raw audio to speaker from RAM ({len(audio_chunks)} chunks)...") for chunk in audio_chunks: i2s.write(chunk) except Exception as e: print("Error during RAM playback:", e) finally: time.sleep_ms(100) # Let buffer play out amp_pin.value(off_val) # Disable amp i2s.deinit() if mclk_pwm: mclk_pwm.deinit() print("Playback complete.") def main(): display = board_config.display_instance print("=== Dynamic RAM-based Audio Loopback Script ===") print(f"Board Detected: {board_config.BOARD_TYPE}") # Initialize buttons using polling Pins instead of BoardButtons class key_pin = Pin(18, Pin.IN, Pin.PULL_UP) boot_pin = Pin(0, Pin.IN, Pin.PULL_UP) # Helper to check if trigger is active def is_talk_trigger_active(): if board_config.touch: return board_config.touch.is_touched() return key_pin.value() == 0 while True: if display: display.clear(0) if board_config.BOARD_TYPE == 'WAVESHARE_RLCD': display.text("RLCD Audio Loopback Test", 10, 10, 1) display.line(10, 20, 390, 20, 1) display.text("1. Press KEY button to record 10s", 15, 60, 1) display.text("2. Playback will start automatically", 15, 80, 1) display.text("Ready (RAM-based)...", 15, 120, 1) else: display.text("Touch Audio Loopback Test", 10, 10, 1) display.line(10, 20, 310, 20, 1) display.text("1. Press screen/KEY to record 10s", 10, 50, 1) display.text("2. Playback starts automatically", 10, 70, 1) display.text("Ready (RAM-based)...", 10, 100, 1) display.show() print("Ready: Press and hold key/screen to record...") start_wait = time.ticks_ms() while not is_talk_trigger_active(): if boot_pin.value() == 0 or time.ticks_diff(time.ticks_ms(), start_wait) > 120000: print("Exit condition met. Deleting flag and resetting...") if display: display.clear(0) if board_config.BOARD_TYPE == 'WAVESHARE_RLCD': display.text("Exiting test...", 15, 60, 1) display.text("Rebooting to normal...", 15, 80, 1) else: display.text("Exiting test...", 10, 50, 1) display.text("Rebooting to normal...", 10, 70, 1) display.show() time.sleep(1) try: import os os.remove("run_loopback.txt") except: pass import machine machine.reset() time.sleep_ms(30) print("Recording started! Speak into the microphone...") if display: display.clear(0) if board_config.BOARD_TYPE == 'WAVESHARE_RLCD': display.text("RLCD Audio Loopback Test", 10, 10, 1) display.line(10, 20, 390, 20, 1) display.text("RECORDING: 10 seconds...", 15, 80, 1) display.text("Speak into microphone!", 15, 100, 1) else: display.text("Touch Audio Loopback Test", 10, 10, 1) display.line(10, 20, 310, 20, 1) display.text("RECORDING: 10 seconds...", 10, 60, 1) display.text("Speak now!", 10, 80, 1) display.show() # 1. Start MCLK PWM using board config parameters mclk_pwm = None if board_config.audio_mclk_pin is not None: mclk_pin = Pin(board_config.audio_mclk_pin, Pin.OUT) mclk_pwm = machine.PWM(mclk_pin) mclk_pwm.freq(board_config.audio_mclk_freq) mclk_pwm.duty_u16(32768) # 2. Configure I2S RX (Stereo 16kHz) - ibuf set to 16000 for safety i2s_rx = I2S(1, sck=Pin(board_config.audio_i2s_sck), ws=Pin(board_config.audio_i2s_ws), sd=Pin(board_config.audio_i2s_rx_sd), mode=I2S.RX, ibuf=16000, rate=16000, bits=16, format=I2S.STEREO) # 3. Wake up and configure the microphone chip (ES7210 vs ES8311) init_ok = False if board_config.audio_mic_codec == "ES7210": from audio_util import ES7210 mic_adc = ES7210(board_config.i2c_bus) init_ok = mic_adc.init(sample_rate=16000, bit_width=16) else: from audio_util import ES8311 mic_adc = ES8311(board_config.i2c_bus) if mic_adc.init(sample_rate=16000): init_ok = True mic_adc.set_volume(80) try: mic_adc._write(0x14, 0x1A) # Enable analog mic input & PGA mic_adc._write(0x16, 0x01) # Enable +6dB gain boost mic_adc._write(0x17, 0xC8) # Set ADC digital volume except: pass if not init_ok: print("Microphone codec initialization failed! Aborting recording.") i2s_rx.deinit() if mclk_pwm: mclk_pwm.deinit() if display: display.clear(0) display.text("Codec Init Failed!", 15, 80, 1) display.show() time.sleep(3) continue # Record loop to RAM - using ticks_ms for safe timing buffer = bytearray(2048) audio_chunks = [] total_bytes = 0 start_rec_time = time.ticks_ms() max_duration_ms = 10000 # 10 seconds try: while time.ticks_diff(time.ticks_ms(), start_rec_time) < max_duration_ms: bytes_read = i2s_rx.readinto(buffer) if bytes_read > 0: audio_chunks.append(bytes(buffer[:bytes_read])) total_bytes += bytes_read except Exception as e: print("Recording failed:", e) finally: i2s_rx.deinit() if mclk_pwm: mclk_pwm.deinit() print(f"Recorded {total_bytes} bytes in RAM ({len(audio_chunks)} chunks).") # Wait for release of key/trigger to debounce time.sleep_ms(200) # 4. Playback from RAM if display: display.clear(0) if board_config.BOARD_TYPE == 'WAVESHARE_RLCD': display.text("RLCD Audio Loopback Test", 10, 10, 1) display.line(10, 20, 390, 20, 1) display.text("PLAYING BACK RESPONSE...", 15, 80, 1) display.text(f"Bytes: {total_bytes}", 15, 100, 1) else: display.text("Touch Audio Loopback Test", 10, 10, 1) display.line(10, 20, 310, 20, 1) display.text("PLAYING BACK RESPONSE...", 10, 60, 1) display.text(f"Bytes: {total_bytes}", 10, 80, 1) display.show() play_ram_pcm(audio_chunks, channels=2, rate=16000, bits=16, volume=95) if display: display.clear(0) if board_config.BOARD_TYPE == 'WAVESHARE_RLCD': display.text("RLCD Audio Loopback Test", 10, 10, 1) display.line(10, 20, 390, 20, 1) display.text("Playback Finished!", 15, 70, 1) display.text("Release trigger to restart...", 15, 95, 1) else: display.text("Touch Audio Loopback Test", 10, 10, 1) display.line(10, 20, 310, 20, 1) display.text("Playback Finished!", 10, 50, 1) display.text("Release trigger to restart...", 10, 75, 1) display.show() # Wait for release of button/touch to debounce before ready again while is_talk_trigger_active(): time.sleep_ms(30) time.sleep_ms(500) if __name__ == "__main__": main()