Variable i2s bit width (#331)

- Add support for variable width I2S (via XUA_I2S_N_BITS)
- Add support for variable width TDM (again via XUD_I2S_N_BITS when XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM)
- Includes support for xcore as I2S/TDM master and slave
- Add testing of the the above to test_i2s_loopback
- Rationalised test config building in test_i2s_loopback
- Documentation updated
This commit is contained in:
Ross Owen
2023-06-08 15:31:12 +01:00
committed by GitHub
parent d3ad29e8a6
commit 1ef5129fde
16 changed files with 221 additions and 196 deletions

View File

@@ -1,4 +1,4 @@
# Copyright 2018-2022 XMOS LIMITED.
# Copyright 2018-2023 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import pytest
import Pyxsim
@@ -11,16 +11,21 @@ import sys
def test_file(request):
return str(request.node.fspath)
def do_test(
pcm_format, i2s_role, channel_count, sample_rate, test_file, options, capfd
pcm_format, i2s_role, channel_count, sample_rate, word_length, test_file, options, capfd
):
build_options = []
output = []
testname, _ = os.path.splitext(os.path.basename(test_file))
desc = f"simulation_{pcm_format}_{i2s_role}_{channel_count}in_{channel_count}out_{sample_rate}"
build_options += [f"pcm_format={pcm_format}"]
build_options += [f"i2s_role={i2s_role}"]
build_options += [f"channel_count={channel_count}"]
build_options += [f"sample_rate={sample_rate}"]
build_options += [f"word_length={word_length}"]
desc = f"simulation_{pcm_format}_{i2s_role}_{channel_count}in_{channel_count}out_{sample_rate}_{word_length}bit"
binary = f"{testname}/bin/{desc}/{testname}_{desc}.xe"
tester = testers.ComparisonTester(open("pass.expect"))
@@ -52,6 +57,7 @@ def do_test(
result = Pyxsim.run_on_simulator(
binary,
build_options=build_options,
tester=tester,
simargs=simargs,
capfd=capfd,
@@ -65,25 +71,26 @@ def do_test(
@pytest.mark.parametrize("i2s_role", ["master", "slave"])
@pytest.mark.parametrize("pcm_format", ["i2s", "tdm"])
@pytest.mark.parametrize("channel_count", [2, 8, 16])
@pytest.mark.parametrize("sample_rate", ["48khz", "96khz", "192khz"])
@pytest.mark.parametrize("word_length", [16, 32]) # I2S world length in bits
@pytest.mark.parametrize("sample_rate", [48000, 96000, 192000])
def test_i2s_loopback(
i2s_role, pcm_format, channel_count, sample_rate, test_file, options, capfd
i2s_role, pcm_format, channel_count, sample_rate, word_length, test_file, options, capfd
):
if pcm_format == "i2s" and channel_count == 16:
pytest.skip("Invalid parameter combination")
if pcm_format == "i2s" and sample_rate not in ["48khz", "192khz"]:
if pcm_format == "i2s" and sample_rate not in [48000, 192000]:
pytest.skip("Invalid parameter combination")
if pcm_format == "tdm" and channel_count == 2:
pytest.skip("Invalid parameter combination")
if pcm_format == "tdm" and sample_rate == "192khz":
if pcm_format == "tdm" and sample_rate == 192000:
pytest.skip("Invalid parameter combination")
result = do_test(
pcm_format, i2s_role, channel_count, sample_rate, test_file, options, capfd
pcm_format, i2s_role, channel_count, sample_rate, word_length, test_file, options, capfd
)
assert result

View File

@@ -1,126 +1,44 @@
TARGET = xk-audio-216-mc.xn
USED_MODULES = lib_xua lib_i2c lib_logging
BUILD_FLAGS = -O0 -g -lflash -DXUD_CORE_CLOCK=600 -fxscope -save-temps -march=xs2a -DUSB_TILE=tile[1]
BUILD_FLAGS = -O3 -g -lflash -DXUD_CORE_CLOCK=600 -fxscope -save-temps -march=xs2a -DUSB_TILE=tile[1] \
-DXUA_ADAT_RX_EN=0 -DXUA_ADAT_TX_EN=0 -DXUA_SPDIF_RX_EN=0 -DXUA_SPDIF_TX_EN=0 -DMIDI=0 \
-DSIMULATION=1
BUILD_FLAGS_i2s_master_2in_2out_48khz = $(BUILD_FLAGS) \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
-D DEFAULT_FREQ=48000
ifndef pcm_format
$(error pcm_format is not set)
endif
BUILD_FLAGS_i2s_slave_2in_2out_48khz = $(BUILD_FLAGS) \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1
ifndef i2s_role
$(error i2s_role is not set)
endif
BUILD_FLAGS_i2s_master_2in_2out_192khz = $(BUILD_FLAGS) \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -D I2S_CHANS_ADC=2 -D I2S_CHANS_DAC=2 \
-D DEFAULT_FREQ=192000
ifndef channel_count
$(error channel_count is not set)
endif
BUILD_FLAGS_i2s_slave_2in_2out_192khz = $(BUILD_FLAGS) \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
-D DEFAULT_FREQ=192000 -DCODEC_MASTER=1
ifndef sample_rate
$(error sample_rate is not set)
endif
BUILD_FLAGS_i2s_master_8in_8out_48khz = $(BUILD_FLAGS) \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
-D DEFAULT_FREQ=48000
ifndef word_length
$(error word_length is not set)
endif
BUILD_FLAGS_i2s_slave_8in_8out_48khz = $(BUILD_FLAGS) \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1
ifeq ($(pcm_format),tdm)
BUILD_FLAGS += -DXUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM
endif
ifeq ($(i2s_role),slave)
BUILD_FLAGS += -DCODEC_MASTER=1
endif
BUILD_FLAGS_i2s_master_8in_8out_192khz = $(BUILD_FLAGS) \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
-D DEFAULT_FREQ=192000 \
-O2 # optimisations to meet timing
BUILD_FLAGS_i2s_slave_8in_8out_192khz = $(BUILD_FLAGS) \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
-D DEFAULT_FREQ=192000 -DCODEC_MASTER=1 \
-O2 # optimisations to meet timing
BUILD_FLAGS_tdm_master_8in_8out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
-D DEFAULT_FREQ=48000 \
-O2 # optimisations to meet timing
BUILD_FLAGS_tdm_master_8in_8out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
-D DEFAULT_FREQ=96000 \
-O3 # optimisations to meet timing
BUILD_FLAGS_tdm_slave_8in_8out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1 \
-O2 # optimisations to meet timing
BUILD_FLAGS_tdm_slave_8in_8out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
-D DEFAULT_FREQ=96000 -DCODEC_MASTER=1 \
-O2 # optimisations to meet timing
BUILD_FLAGS_tdm_master_16in_16out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
-D DEFAULT_FREQ=48000 \
-O2 # optimisations to meet timing
BUILD_FLAGS_tdm_master_16in_16out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
-D DEFAULT_FREQ=96000 \
-O2 # optimisations to meet timing
BUILD_FLAGS_tdm_slave_16in_16out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1 \
-O2 # optimisations to meet timing
BUILD_FLAGS_tdm_slave_16in_16out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
-D DEFAULT_FREQ=96000 -DCODEC_MASTER=1 \
-O2 # optimisations to meet timing
#XCC_FLAGS_hardware_i2s_master_2in_2out_48khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_2in_2out_48khz)
#XCC_FLAGS_hardware_i2s_master_2in_2out_192khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_2in_2out_192khz)
#XCC_FLAGS_hardware_i2s_master_8in_8out_48khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_8in_8out_48khz)
#XCC_FLAGS_hardware_i2s_master_8in_8out_192khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_8in_8out_192khz)
#XCC_FLAGS_hardware_tdm_master_8in_8out_48khz = -D HARDWARE $(BUILD_FLAGS_tdm_master_8in_8out_48khz)
XCC_FLAGS_simulation_i2s_master_2in_2out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_2in_2out_48khz)
XCC_FLAGS_simulation_i2s_slave_2in_2out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_2in_2out_48khz)
XCC_FLAGS_simulation_i2s_master_2in_2out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_2in_2out_192khz)
XCC_FLAGS_simulation_i2s_slave_2in_2out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_2in_2out_192khz)
XCC_FLAGS_simulation_i2s_master_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_8in_8out_48khz)
XCC_FLAGS_simulation_i2s_slave_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_8in_8out_48khz)
XCC_FLAGS_simulation_i2s_master_8in_8out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_8in_8out_192khz)
XCC_FLAGS_simulation_i2s_slave_8in_8out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_8in_8out_192khz)
XCC_FLAGS_simulation_tdm_master_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_8in_8out_48khz)
XCC_FLAGS_simulation_tdm_master_8in_8out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_8in_8out_96khz)
XCC_FLAGS_simulation_tdm_slave_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_8in_8out_48khz)
XCC_FLAGS_simulation_tdm_slave_8in_8out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_8in_8out_96khz)
XCC_FLAGS_simulation_tdm_master_16in_16out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_16in_16out_48khz)
XCC_FLAGS_simulation_tdm_master_16in_16out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_16in_16out_96khz)
XCC_FLAGS_simulation_tdm_slave_16in_16out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_16in_16out_48khz)
XCC_FLAGS_simulation_tdm_slave_16in_16out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_16in_16out_96khz)
XCC_FLAGS_simulation_${pcm_format}_${i2s_role}_$(channel_count)in_$(channel_count)out_$(sample_rate)_$(word_length)bit = $(BUILD_FLAGS) \
-DNUM_USB_CHAN_IN=${channel_count} \
-DNUM_USB_CHAN_OUT=${channel_count} \
-DI2S_CHANS_DAC=${channel_count} \
-DI2S_CHANS_ADC=${channel_count} \
-DDEFAULT_FREQ=${sample_rate} \
-DXUA_I2S_N_BITS=${word_length}
XMOS_MAKE_PATH ?= ../..
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -1,4 +1,4 @@
// Copyright 2016-2022 XMOS LIMITED.
// Copyright 2016-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <platform.h>
#include <stdlib.h>
@@ -9,7 +9,6 @@
#define DEBUG_UNIT MAIN
#include "debug_print.h"
/* Port declarations. Note, the defines come from the xn file */
#if I2S_WIRES_DAC > 0
on tile[AUDIO_IO_TILE] : buffered out port:32 p_i2s_dac[I2S_WIRES_DAC] =
@@ -92,9 +91,10 @@ clock clk_audio_mclk = on tile[AUDIO_IO_TILE]: XS1_CLKBLK_2; /*
#define TOTAL_TEST_FRAMES (5 * DEFAULT_FREQ)
#endif
#define SAMPLE(frame_count, channel_num) (((frame_count) << 8) | ((channel_num) & 0xFF))
#define SAMPLE_FRAME_NUM(test_word) ((test_word) >> 8)
#define SAMPLE_CHANNEL_NUM(test_word) ((test_word) & 0xFF)
#define SHIFT (16) /* Note, we shift samples up such that we can test down to 16bit I2S */
#define SAMPLE(frame_count, channel_num) ((((frame_count) << 8) | ((channel_num) & 0xFF))<<SHIFT)
#define SAMPLE_FRAME_NUM(test_word) ((test_word>>SHIFT) >> 8)
#define SAMPLE_CHANNEL_NUM(test_word) ((test_word>>SHIFT) & 0xFF)
void generator(chanend c_checker, chanend c_out)
{
@@ -105,7 +105,6 @@ void generator(chanend c_checker, chanend c_out)
frame_count = 0;
while (1) {
underflow_word = inuint(c_out);

View File

@@ -1,4 +1,4 @@
// Copyright 2016-2022 XMOS LIMITED.
// Copyright 2016-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifdef SIMULATION
@@ -41,7 +41,7 @@ extern out port p_lrclk_gen;
extern clock clk_audio_lrclk_gen;
void slave_mode_clk_setup(const unsigned samFreq, const unsigned chans_per_frame){
const unsigned data_bits = 32;
const unsigned data_bits = XUA_I2S_N_BITS;
const unsigned mclk_freq = 24576000;
const unsigned mclk_bclk_ratio = mclk_freq / (chans_per_frame * samFreq * data_bits);
@@ -61,5 +61,4 @@ void slave_mode_clk_setup(const unsigned samFreq, const unsigned chans_per_frame
master_mode_clk_setup();
}
#endif
#endif