nRF9151: I2S Direct Register Access Causes Memory Corruption - Need Help

Hardware Setup

  • Board: nRF9151 DK (nrf9151dk_nrf9151_ns)
  • SDK: nRF Connect SDK v2.7.0
  • Audio Amplifier: MAX98357A
  • I2S Pins: SCK=25, LRCK=26, SDOUT=27, MCK=24

Problem Description

I'm implementing I2S audio playback using direct Nordic register access (bypassing Zephyr I2S driver due to compatibility issues). However, any I2S register operation causes severe memory corruption that manifests as garbled log output.

Code Configuration

Following the official Nordic I2S documentation exactly:

// I2S Configuration (matches Nordic docs)
NRF_I2S->CONFIG.RXEN = I2S_CONFIG_RXEN_RXEN_Disabled << I2S_CONFIG_RXEN_RXEN_Pos;
NRF_I2S->CONFIG.TXEN = I2S_CONFIG_TXEN_TXEN_Enabled << I2S_CONFIG_TXEN_TXEN_Pos;
NRF_I2S->CONFIG.MCKEN = I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos;
NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV8 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos;
NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_256X << I2S_CONFIG_RATIO_RATIO_Pos;
NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos;
NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left << I2S_CONFIG_ALIGN_ALIGN_Pos;
NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos;
NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Stereo << I2S_CONFIG_CHANNELS_CHANNELS_Pos;

// Pin Configuration
NRF_I2S->PSEL.SCK = (25 << I2S_PSEL_SCK_PIN_Pos) | (I2S_PSEL_SCK_CONNECT_Connected << I2S_PSEL_SCK_CONNECT_Pos);
NRF_I2S->PSEL.LRCK = (26 << I2S_PSEL_LRCK_PIN_Pos) | (I2S_PSEL_LRCK_CONNECT_Connected << I2S_PSEL_LRCK_CONNECT_Pos);
NRF_I2S->PSEL.SDOUT = (27 << I2S_PSEL_SDOUT_PIN_Pos) | (I2S_PSEL_SDOUT_CONNECT_Connected << I2S_PSEL_SDOUT_CONNECT_Pos);
NRF_I2S->PSEL.MCK = (24 << I2S_PSEL_MCK_PIN_Pos) | (I2S_PSEL_MCK_CONNECT_Connected << I2S_PSEL_MCK_CONNECT_Pos);

// Buffer Setup (16-bit stereo, 32-bit aligned)
static int16_t tx_buffers[4][512] __aligned(4);  // 256 samples * 2 channels

// Audio Start (minimal implementation)
NRF_I2S->TXD.PTR = (uint32_t)tx_buffers[0];
NRF_I2S->RXTXD.MAXCNT = 256;  // 256 words for stereo
NRF_I2S->ENABLE = 1;
NRF_I2S->TASKS_START = 1;

Observed Behavior

Normal logs before I2S operations:

[00:00:18.000,000] <inf> audio_counter: Counter: 18
[00:00:19.000,000] <inf> audio_counter: Counter: 19
[00:00:20.000,000] <inf> audio_counter: Starting audio

Corrupted logs after ANY I2S register write:

[00:00:20.000,000] <inf> audio_counter: Starting audio
[0ӗ�7>��_����O/���go���o~/���e������7>r�7.���g>^�}������������

Debugging Results

  1. White check mark CONFIRMED: Memory corruption happens immediately when any I2S register is written
  2. White check mark TESTED: Complete application works perfectly when I2S operations are disabled
  3. White check mark VERIFIED: Corruption occurs even with:
    • No interrupts enabled
    • Minimal register writes
    • Different buffer sizes/formats
    • Various memory alignments

Key Questions

  1. Register Documentation Discrepancy: Nordic docs show NRF_I2S->TXD.MAXCNT = MY_BUF_SIZE; but this register doesn't exist in nRF9151 headers. Should I use RXTXD.MAXCNT for TX-only mode?

  2. Memory Protection: Could I2S register access conflict with Zephyr's memory protection or the secure/non-secure boundary on nRF9151?

  3. Clock Domain Issues: Could writing to I2S registers while clocks are disabled cause memory corruption?

  4. Buffer Requirements: Are there specific memory layout requirements for I2S buffers on nRF9151 that differ from other Nordic chips?

Configuration Files

prj.conf:

CONFIG_DK_LIBRARY=y
CONFIG_GPIO=y
CONFIG_LOG=y
CONFIG_ASSERT=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_OPTIMIZATIONS=y

Device Tree (overlay):

&i2s0 {
    status = "okay";
    pinctrl-0 = <&i2s0_default>;
    pinctrl-names = "default";
};

&pinctrl {
    i2s0_default: i2s0_default {
        group1 {
            psels = <NRF_PSEL(I2S_SCK, 0, 25)>,
                   <NRF_PSEL(I2S_LRCK, 0, 26)>,
                   <NRF_PSEL(I2S_SDOUT, 0, 27)>;
        };
    };
};

Environment

  • Compiler: arm-none-eabi-gcc (Zephyr SDK)
  • Build System: west build -b nrf9151dk_nrf9151_ns
  • Debugger: Segger J-Link

Has anyone encountered similar I2S memory corruption issues on nRF9151? Any guidance on proper I2S register access patterns would be greatly appreciated!

main code:

main.c:
/*
 * Copyright 2023 NXP
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/irq.h>
#include <nrf.h>
#include <hal/nrf_i2s.h>
// Using direct Nordic I2S registers with Zephyr interrupt management

LOG_MODULE_REGISTER(audio_counter, LOG_LEVEL_INF);

#define SAMPLE_NO 256

/* Generate square wave dynamically to avoid large static arrays */

/* Fill buffer with square wave (stereo for Nordic HAL compatibility)
 * "att" represents a power of two to attenuate the samples by
 */
static void fill_buf(int16_t *tx_block, int att)
{
	for (int i = 0; i < SAMPLE_NO; i++) {
		/* Generate square wave: high for first half, low for second half */
		int16_t sample = (i < SAMPLE_NO / 2) ? (10000 / (1 << att)) : (-10000 / (1 << att));
		/* Nordic I2S stereo format: [left][right][left][right]... */
		tx_block[i * 2] = sample;     /* Left channel */
		tx_block[i * 2 + 1] = sample; /* Right channel (same as left for mono) */
	}
}

#define NUM_BLOCKS 4

/* Nordic I2S buffers - 16-bit stereo, 32-bit aligned */
static int16_t tx_buffers[NUM_BLOCKS][SAMPLE_NO * 2] __aligned(4);
static uint32_t current_buffer = 0;

/* Counter state */
static volatile uint32_t counter = 0;
static volatile bool counter_running = false;
static volatile bool sound_playing = false;

/* Synchronization */
static struct k_mutex counter_mutex;
static struct k_sem counter_sem;

/* Direct Nordic I2S register control */
static bool i2s_initialized = false;
static volatile bool buffer_ready = false;

/* Simple audio test - no external files */
static bool use_embedded_audio = false;  /* Always false for basic test */

/* Removed - no embedded audio in basic test */

/* Simple function - always use square wave */
static void fill_buf_from_source(int16_t *tx_block, int att)
{
	/* Always use basic square wave */
	fill_buf(tx_block, att);
}

/* I2S interrupt handler for buffer updates - MINIMAL CODE ONLY */
void I2S_IRQHandler(void)
{
	/* Check if TX pointer was updated */
	if (NRF_I2S->EVENTS_TXPTRUPD) {
		NRF_I2S->EVENTS_TXPTRUPD = 0;
		
		if (sound_playing) {
			/* Switch to next buffer */
			current_buffer = (current_buffer + 1) % NUM_BLOCKS;
			
			/* Update TX pointer to next buffer */
			NRF_I2S->TXD.PTR = (uint32_t)tx_buffers[current_buffer];
		}
		
		buffer_ready = true;
	}
}

/* Audio initialization function */
static int audio_init(void)
{
	uint32_t tx_idx;

	LOG_INF("Initializing Nordic I2S with direct register access");

	/* Disable I2S first */
	NRF_I2S->ENABLE = 0;

	/* Configure I2S pins - same as our overlay */
	NRF_I2S->PSEL.SCK = (25 << I2S_PSEL_SCK_PIN_Pos) | 
	                    (I2S_PSEL_SCK_CONNECT_Connected << I2S_PSEL_SCK_CONNECT_Pos);
	NRF_I2S->PSEL.LRCK = (26 << I2S_PSEL_LRCK_PIN_Pos) | 
	                     (I2S_PSEL_LRCK_CONNECT_Connected << I2S_PSEL_LRCK_CONNECT_Pos);
	NRF_I2S->PSEL.SDOUT = (27 << I2S_PSEL_SDOUT_PIN_Pos) | 
	                      (I2S_PSEL_SDOUT_CONNECT_Connected << I2S_PSEL_SDOUT_CONNECT_Pos);
	/* MCK required for Nordic I2S Master mode - using pin 24 (available GPIO) */
	NRF_I2S->PSEL.MCK = (24 << I2S_PSEL_MCK_PIN_Pos) | 
	                    (I2S_PSEL_MCK_CONNECT_Connected << I2S_PSEL_MCK_CONNECT_Pos);
	/* SDIN not used */
	NRF_I2S->PSEL.SDIN = I2S_PSEL_SDIN_CONNECT_Disconnected << I2S_PSEL_SDIN_CONNECT_Pos;

	/* Configure I2S settings */
	NRF_I2S->CONFIG.RXEN = I2S_CONFIG_RXEN_RXEN_Disabled << I2S_CONFIG_RXEN_RXEN_Pos;
	NRF_I2S->CONFIG.TXEN = I2S_CONFIG_TXEN_TXEN_Enabled << I2S_CONFIG_TXEN_TXEN_Pos;
	NRF_I2S->CONFIG.MCKEN = I2S_CONFIG_MCKEN_MCKEN_Enabled << I2S_CONFIG_MCKEN_MCKEN_Pos;
	NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV8 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos;
	NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_256X << I2S_CONFIG_RATIO_RATIO_Pos;
	NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit << I2S_CONFIG_SWIDTH_SWIDTH_Pos;
	NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left << I2S_CONFIG_ALIGN_ALIGN_Pos;
	NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos;
	NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Stereo << I2S_CONFIG_CHANNELS_CHANNELS_Pos;

	/* DISABLE I2S interrupts for testing */
	/* NRF_I2S->INTENSET = I2S_INTENSET_TXPTRUPD_Set << I2S_INTENSET_TXPTRUPD_Pos; */
	
	/* DISABLE I2S interrupt to test without corruption */
	/* IRQ_CONNECT(I2S_IRQn, 3, I2S_IRQHandler, NULL, 0); */
	/* irq_enable(I2S_IRQn); */

	/* Pre-fill all TX buffers with the same square wave */
	for (tx_idx = 0; tx_idx < NUM_BLOCKS; tx_idx++) {
		fill_buf_from_source(tx_buffers[tx_idx], 2); /* Same attenuation for all */
	}

	i2s_initialized = true;
	LOG_INF("Direct Nordic I2S registers configured successfully");
	LOG_INF("16kHz, 16-bit, stereo, pins: SCK=25, LRCK=26, SDOUT=27, MCK=24");
	LOG_INF("SAMPLE_NO: %d, NUM_BLOCKS: %d", SAMPLE_NO, NUM_BLOCKS);
	return 0;
}

/* Start audio playback */
static int audio_start(void)
{
	if (sound_playing) {
		return 0; /* Already playing */
	}

	if (!i2s_initialized) {
		LOG_ERR("Nordic I2S not initialized");
		return -ENODEV;
	}

	/* Minimal I2S setup following Nordic docs exactly */
	current_buffer = 0;
	fill_buf_from_source(tx_buffers[current_buffer], 2);

	/* Set buffer pointer - following Nordic documentation */
	NRF_I2S->TXD.PTR = (uint32_t)tx_buffers[current_buffer];
	
	/* Set buffer size - using RXTXD.MAXCNT since TXD.MAXCNT doesn't exist */
	NRF_I2S->RXTXD.MAXCNT = SAMPLE_NO;

	/* Enable and start I2S - minimal sequence */
	NRF_I2S->ENABLE = 1;
	NRF_I2S->TASKS_START = 1;

	sound_playing = true;
	LOG_INF("Minimal Nordic I2S started");
	return 0;
}

/* Stop audio playback */
static int audio_stop(void)
{
	if (!sound_playing) {
		return 0; /* Already stopped */
	}

	/* Set flag first to stop interrupt handler from providing more buffers */
	sound_playing = false;
	
	/* Stop I2S transmission */
	NRF_I2S->TASKS_STOP = 1;
	
	/* Wait for stop to complete */
	while (NRF_I2S->EVENTS_STOPPED == 0) {
		k_sleep(K_MSEC(1));
	}
	NRF_I2S->EVENTS_STOPPED = 0;
	
	/* Disable I2S */
	NRF_I2S->ENABLE = 0;
	
	LOG_INF("Direct Nordic I2S audio playback stopped");
	return 0;
}

/* Audio thread removed - Nordic HAL handles buffer management via data handler callback */

/* Button handler callback */
static void button_handler(uint32_t button_state, uint32_t has_changed)
{
	/* Check if button 1 was pressed */
	if (has_changed & DK_BTN1_MSK) {
		if (button_state & DK_BTN1_MSK) {
			/* Button 1 pressed - start/restart counter */
			k_mutex_lock(&counter_mutex, K_FOREVER);
			counter = 0;
			counter_running = true;
			k_mutex_unlock(&counter_mutex);
			
			/* Signal the counter thread */
			k_sem_give(&counter_sem);
			
			LOG_INF("Button 1 pressed - counter started");
		}
	}

	/* Check if button 2 was pressed */
	if (has_changed & DK_BTN2_MSK) {
		if (button_state & DK_BTN2_MSK) {
			/* Button 2 pressed - toggle audio source */
			use_embedded_audio = !use_embedded_audio;
			LOG_INF("Button 2 pressed - Audio source: %s", 
				use_embedded_audio ? "Embedded audio" : "Sine wave");
			
			/* Reset audio position when switching */
			//if (use_embedded_audio) {
			//	embedded_audio_pos = 0;
			//}
		}
	}
}

/* Counter thread function */
static void counter_thread(void *arg1, void *arg2, void *arg3)
{
	ARG_UNUSED(arg1);
	ARG_UNUSED(arg2);
	ARG_UNUSED(arg3);

	while (1) {
		/* Wait for counter to be started */
		k_sem_take(&counter_sem, K_FOREVER);

		while (counter_running) {
			k_mutex_lock(&counter_mutex, K_FOREVER);
			
			if (counter_running) {
				counter++;
				LOG_INF("Counter: %d", counter);

				/* Start sound at counter 20 */
				if (counter == 20 && !sound_playing) {
					LOG_INF("Counter reached 20 - starting audio");
					audio_start();
				}
				
				/* Stop sound at counter 35 */
				if (counter == 35 && sound_playing) {
					LOG_INF("Counter reached 35 - stopping audio");
					audio_stop();
					counter_running = false; /* Stop counter */
				}
			}
			
			k_mutex_unlock(&counter_mutex);

			/* Wait 1 second */
			k_sleep(K_SECONDS(1));
		}
	}
}

/* Define threads */
#define COUNTER_THREAD_STACK_SIZE 1024
#define COUNTER_THREAD_PRIORITY 5

#define AUDIO_THREAD_STACK_SIZE 1024
#define AUDIO_THREAD_PRIORITY 4  /* Higher priority than counter */

K_THREAD_DEFINE(counter_tid, COUNTER_THREAD_STACK_SIZE,
		counter_thread, NULL, NULL, NULL,
		COUNTER_THREAD_PRIORITY, 0, 0);

/* DISABLED: Temporarily disable audio thread to isolate corruption source
K_THREAD_DEFINE(audio_tid, AUDIO_THREAD_STACK_SIZE,
		audio_thread, NULL, NULL, NULL,
		AUDIO_THREAD_PRIORITY, 0, 0);
*/

int main(void)
{
	int ret;

	LOG_INF("Audio Counter Application Starting");

	/* Initialize synchronization primitives */
	k_mutex_init(&counter_mutex);
	k_sem_init(&counter_sem, 0, 1);

	/* Initialize audio system */
	ret = audio_init();
	if (ret < 0) {
		LOG_ERR("Audio initialization failed: %d", ret);
		return ret;
	}

	/* Initialize DK buttons and LEDs */
	ret = dk_buttons_init(button_handler);
	if (ret < 0) {
		LOG_ERR("Cannot init buttons (error: %d)", ret);
		return ret;
	}

	ret = dk_leds_init();
	if (ret < 0) {
		LOG_ERR("Cannot init LEDs (error: %d)", ret);
		return ret;
	}

	LOG_INF("=== Audio Counter Application ===");
	LOG_INF("Button 1: Start counter (sound at 20-35)");
	LOG_INF("Button 2: Toggle audio source (Embedded/Sine wave)");
	LOG_INF("Current audio source: %s", use_embedded_audio ? "Test audio" : "Sine wave");
	//LOG_INF("Test audio: %zu samples ready", TEST_AUDIO_SIZE);

	/* Main loop - just keep the application running */
	while (1) {
		k_sleep(K_SECONDS(1));
		
		/* LED indicators */
		dk_set_led(DK_LED1, counter_running);           /* LED1: Counter running */
		dk_set_led(DK_LED2, use_embedded_audio);        /* LED2: Embedded audio mode */
		dk_set_led(DK_LED3, true);                      /* LED3: Always on (embedded audio available) */
		dk_set_led(DK_LED4, sound_playing);             /* LED4: Sound playing */
	}

	return 0;
}

device overlay:

/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <dt-bindings/pinctrl/nrf-pinctrl.h>

/ {
	chosen {
		zephyr,i2s = &i2s0;
	};

	/* Simple buttons for audio control */
	buttons {
		compatible = "gpio-keys";
		button0: button_0 {
			gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
			label = "Push button 1";
		};
		button1: button_1 {
			gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
			label = "Push button 2";
		};
	};

	aliases {
		sw0 = &button0;
		sw1 = &button1;
	};
};

&pinctrl {
	i2s0_default_alt: i2s0_default_alt {
		group1 {
			psels = <NRF_PSEL(I2S_SCK_M, 0, 25)>, /* SCK is BCLK to MAX98357A pin 25 */
				<NRF_PSEL(I2S_LRCK_M, 0, 26)>, /* LRCK is LRC to MAX98357A pin 26 */
				<NRF_PSEL(I2S_SDOUT, 0, 27)>; /* SDOUT is DIN to MAX98357A pin 27 */
		};
	};

	i2s0_sleep_alt: i2s0_sleep_alt {
		group1 {
			psels = <NRF_PSEL(I2S_SCK_M, 0, 25)>,
				<NRF_PSEL(I2S_LRCK_M, 0, 26)>,
				<NRF_PSEL(I2S_SDOUT, 0, 27)>;
			low-power-enable;
		};
	};
};

&i2s0 {
	status = "okay";
	pinctrl-0 = <&i2s0_default_alt>;
	pinctrl-1 = <&i2s0_sleep_alt>;
	pinctrl-names = "default", "sleep";
	
	/* MAX98357A mono amplifier - hardware configured */
	/* Only needs BCLK, LRCLK and DIN signals */
};

serial output:

*** Booting nRF Connect SDK v2.7.0-5cb85570ca43 ***
*** Using Zephyr OS v3.6.99-100befc70c74 ***
[00:00:00.376,403] <inf> audio_counter: Audio Counter Application Starting
[00:00:00.376,403] <inf> audio_counter: Initializing Nordic I2S with direct register access
[00:00:00.376,678] <inf> audio_counter: Direct Nordic I2S registers configured successfully
[00:00:00.376,678] <inf> audio_counter: 16kHz, 16-bit, stereo, pins: SCK=25, LRCK=26, SDOUT=27, MCK=24
[00:00:00.376,678] <inf> audio_counter: SAMPLE_NO: 256, NUM_BLOCKS: 4
[00:00:00.376,953] <inf> audio_counter: === Audio Counter Application ===
[00:00:00.376,953] <inf> audio_counter: Button 1: Start counter (sound at 20-35)
[00:00:00.376,953] <inf> audio_counter: Button 2: Toggle audio source (Embedded/Sine wave)
[00:00:00.377,014] <inf> audio_counter: Current audio source: Sine wave
[00:00:21.243,621] <inf> audio_counter: Button 1 pressed - counter started
[00:00:21.243,713] <inf> audio_counter: Counter: 1
[00:00:22.243,865] <inf> audio_counter: Counter: 2
[00:00:23.243,988] <inf> audio_counter: Counter: 3
[00:00:24.244,232] <inf> audio_counter: Counter: 4
[00:00:25.244,445] <inf> audio_counter: Counter: 5
[00:00:26.244,689] <inf> audio_counter: Counter: 6
[00:00:27.244,903] <inf> audio_counter: Counter: 7
[00:00:28.245,147] <inf> audio_counter: Counter: 8
[00:00:29.245,361] <inf> audio_counter: Counter: 9
[00:00:30.245,605] <inf> audio_counter: Counter: 10
[00:00:31.245,819] <inf> audio_counter: Counter: 11
[00:00:32.246,063] <inf> audio_counter: Counter: 12
[00:00:33.246,276] <inf> audio_counter: Counter: 13
[00:00:34.246,520] <inf> audio_counter: Counter: 14
[00:00:35.246,734] <inf> audio_counter: Counter: 15
[00:00:36.246,978] <inf> audio_counter: Counter: 16
[00:00:37.247,192] <inf> audio_counter: Counter: 17
[00:00:38.247,436] <inf> audio_counter: Counter: 18
[07?�����+���*��������.��g~N>�=����/>397_�_�z��?��/����������������������������������������������~o�c}^�o2mG�:4'���?>�]$�/�y�'o_��5�[.^.Z_���oo��Y_������Ͽ������������=��������o7o����Ӧ�7>O�[0�O/���go���o~/���ߕ�'>�_�������������������������~�7?��_�����.>N�_>_O/�����_o����v>���vm'.��������������������������Ͽ���O�s�އ�Zg>^[^���g~N�o~/���z��7>.7.���}���������������������������������������������&>�_���>���~���??��wzyn;:�ui�������?.����g~_>_��������������������������������۲�������N/�=����w���o7o����Ӯ�7?7��0�O/���go_co~/����������������������������������������O�7,��f>^�}��wn�g~N�nt_.4�[00:00:55.251,312] <inf> audio_counter: Counter: 35
[00:00:55.251,342] <inf> audio_counter: Counter reached 35 - stopping audio
[00:00:55.251,342] <inf> audio_counter: Direct Nordic I2S audio playback stopped

Parents Reply Children
Related