diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbe7664..a9c3906 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,7 +83,7 @@ jobs: - name: Run tests run: | - docker run --rm -u $(id -u):$(id -g) -w /fwk_io/test -v ${{github.workspace}}:/fwk_io ${FWK_IO_TESTER_IMAGE} bash -l run_tests.sh lib_i2c + docker run --rm -w /fwk_io/test -v ${{github.workspace}}:/fwk_io ${FWK_IO_TESTER_IMAGE} bash -l run_tests.sh lib_i2c i2stests: name: I2S tests @@ -102,7 +102,7 @@ jobs: - name: Run tests run: | - docker run --rm -u $(id -u):$(id -g) -w /fwk_io/test -v ${{github.workspace}}:/fwk_io ${FWK_IO_TESTER_IMAGE} bash -l run_tests.sh lib_i2s + docker run --rm -w /fwk_io/test -v ${{github.workspace}}:/fwk_io ${FWK_IO_TESTER_IMAGE} bash -l run_tests.sh lib_i2s spitests: name: SPI tests @@ -121,7 +121,7 @@ jobs: - name: Run tests run: | - docker run --rm -u $(id -u):$(id -g) -w /fwk_io/test -v ${{github.workspace}}:/fwk_io ${FWK_IO_TESTER_IMAGE} bash -l run_tests.sh lib_spi + docker run --rm -w /fwk_io/test -v ${{github.workspace}}:/fwk_io ${FWK_IO_TESTER_IMAGE} bash -l run_tests.sh lib_spi uarttests: @@ -141,4 +141,4 @@ jobs: - name: Run tests run: | - docker run --rm -u $(id -u):$(id -g) -w /fwk_io/test -v ${{github.workspace}}:/fwk_io ${FWK_IO_TESTER_IMAGE} bash -l run_tests.sh lib_uart + docker run --rm -w /fwk_io/test -v ${{github.workspace}}:/fwk_io ${FWK_IO_TESTER_IMAGE} bash -l run_tests.sh lib_uart diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 28d8ead..2cf3319 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,12 @@ IO Framework change log ======================= +3.1.0 +----- + + * ADDED: TDM16 Slave Tx library + * CHANGE: Updated lib_mic_array to v5.1.0 + 3.0.1 ----- diff --git a/modules/i2s/CMakeLists.txt b/modules/i2s/CMakeLists.txt index 3bc04e3..59bf2ea 100644 --- a/modules/i2s/CMakeLists.txt +++ b/modules/i2s/CMakeLists.txt @@ -13,7 +13,7 @@ if((${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) OR (${CMAKE_SYSTEM_NAME} STREQUAL set(XCORE_XS3A_SOURCES ${LIB_ASM_SOURCES}) ## Set any local library compile options - set(LIB_COMPILE_FLAGS "-Os") + set(LIB_COMPILE_FLAGS -Os -g) ## Includes files set(LIB_PUBLIC_INCLUDES api) diff --git a/modules/i2s/api/i2s.h b/modules/i2s/api/i2s.h index 01a22c5..a7b3073 100644 --- a/modules/i2s/api/i2s.h +++ b/modules/i2s/api/i2s.h @@ -1,4 +1,4 @@ -// Copyright 2021-2022 XMOS LIMITED. +// Copyright 2021-2023 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef _i2s_h_ #define _i2s_h_ @@ -47,9 +47,9 @@ typedef enum i2s_slave_bclk_polarity { * This structure describes the configuration of an I2S bus. */ typedef struct i2s_config { - unsigned mclk_bclk_ratio; /**< The ratio between the master clock and bit clock signals. */ - i2s_mode_t mode; /**< The mode of the LR clock. */ - i2s_slave_bclk_polarity_t slave_bclk_polarity; /**< Slave bit clock polarity. */ + unsigned mclk_bclk_ratio; /**< The ratio between the master clock and bit clock signals. */ + i2s_mode_t mode; /**< The mode of the LR clock. */ + i2s_slave_bclk_polarity_t slave_bclk_polarity; /**< Slave bit clock polarity. */ } i2s_config_t; /** @@ -58,9 +58,9 @@ typedef struct i2s_config { * Restart commands that can be signalled to the I2S or TDM component. */ typedef enum i2s_restart { - I2S_NO_RESTART = 0, /**< Do not restart. */ - I2S_RESTART, /**< Restart the bus (causes the I2S/TDM to stop and a new init callback to occur allowing reconfiguration of the BUS). */ - I2S_SHUTDOWN /**< Shutdown. This will cause the I2S/TDM component to exit. */ + I2S_NO_RESTART = 0, /**< Do not restart. */ + I2S_RESTART, /**< Restart the bus (causes the I2S/TDM to stop and a new init callback to occur allowing reconfiguration of the BUS). */ + I2S_SHUTDOWN /**< Shutdown. This will cause the I2S/TDM component to exit. */ } i2s_restart_t; /** @@ -73,10 +73,13 @@ typedef enum i2s_restart { * by the application. May be used for context * data specific to each I2S task instance. * + * This will contain the TDM context when in TDM mode. + * * \param i2s_config This structure is provided if the connected * component drives an I2S bus. The members * of the structure should be set to the - * required configuration. + * required configuration. This is ignored when + * used in TDM mode. */ typedef void (*i2s_init_t)(void *app_data, i2s_config_t *i2s_config); @@ -161,6 +164,7 @@ typedef struct { void *app_data; } i2s_callback_group_t; + /**@}*/ // END: addtogroup hil_i2s_core DECLARE_JOB(i2s_master, (const i2s_callback_group_t *, const port_t *, const size_t, const port_t *, const size_t, const port_t, const port_t, const port_t, const xclock_t)); diff --git a/modules/i2s/api/i2s_tdm_slave.h b/modules/i2s/api/i2s_tdm_slave.h new file mode 100644 index 0000000..6e180a6 --- /dev/null +++ b/modules/i2s/api/i2s_tdm_slave.h @@ -0,0 +1,224 @@ +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include "i2s.h" + +/** + * \addtogroup hil_i2s_tdm_core hil_i2s_tdm_core + * + * The public API for using the HIL I2S TDM core. + * @{ + */ + +#define I2S_TDM_MAX_POUT_CNT 4 +#define I2S_TDM_MAX_PIN_CNT 4 + +/* Max channels per frame. This is overrideable to enable + * memory savings in specific applications by allowing + * IO buffers to be optimal size, saving up to + * word length bytes * (default val - app defined value) bytes. + */ +#ifndef I2S_TDM_MAX_CH_PER_FRAME +#define I2S_TDM_MAX_CH_PER_FRAME 16 +#endif /* I2S_TDM_MAX_CH_PER_FRAME */ + +/** + * TDM post resource initialization event callback. + * + * The TDM component will call this after it first initializes the ports. + * This gives the app the chance to make adjustments to port timing which + * are often needed when clocking above 15MHz. + * + * \param i2s_tdm_ctx Points to i2s_tdm_ctx_t struct allowing the resources to be + * modified after they have been enabled and initialised. + * + */ +typedef void (*tdm_post_port_init_t)(void *i2s_tdm_ctx); + +/** + * This attribute must be specified on the TDM callback function + * provided by the application. + */ +#define TDM_CALLBACK_ATTR __attribute__((fptrgroup("i2s_callback"))) + + +/** + * Struct to hold an I2S TDM context. + * + * The members in this struct should not be accessed directly. + */ +typedef struct { + i2s_callback_group_t *i2s_cbg; + TDM_CALLBACK_ATTR tdm_post_port_init_t tdm_post_port_init; + port_t p_dout[I2S_TDM_MAX_POUT_CNT]; + size_t num_out; + port_t p_din[I2S_TDM_MAX_PIN_CNT]; + size_t num_in; + port_t p_fsync; + port_t p_bclk; + xclock_t bclk; + uint32_t tx_offset; + uint32_t fsync_len; + uint32_t word_len; + uint32_t ch_len; + uint32_t ch_per_frame; + i2s_slave_bclk_polarity_t slave_bclk_polarity; + bool fysnch_error; /* This is set (and can be checked in tdm_post_port_init() if needed) */ + void *app_data; +} i2s_tdm_ctx_t; + +/**@}*/ // END: addtogroup hil_i2s_tdm_core + +DECLARE_JOB(i2s_tdm_slave_tx_16_thread, (i2s_tdm_ctx_t *)); +DECLARE_JOB(i2s_slave_tdm_thread, (i2s_tdm_ctx_t *)); + +/** + * \addtogroup hil_i2s_tdm_slave_tx16 hil_i2s_tdm_slave_tx16 + * + * The public API for using the HIL I2S TDM TX 16 slave. + * @{ + */ + +/** + * I2S TDM slave context initialization for 16 channel TX only with + * 1 output port, 32b word length, 32b channel length, + * and 16 channels per frame. + * + * This prepares a context for I2S TDM slave on the provided pins. + * + * The resulting context can be used with i2s_tdm_slave_tx_16_thread(). + * + * \param ctx A pointer to the I2S TDM context to use. + * \param i2s_cbg The I2S callback group pointing to the application's + * functions to use for initialization and getting and receiving + * frames. For TDM the app_data variable within this + * struct is NOT used. + * \param p_dout The data output port. MUST be a 1b port + * \param p_fsync The fsync input port. MUST be a 1b port + * \param p_bclk The bit clock input port. MUST be a 1b port + * \param bclk A clock that will get configured for use with + * the bit clock + * \param tx_offset The number of bclks from FSYNC transition to the MSB + * of Slot 0 + * \param slave_bclk_pol The polarity of bclk + * \param tdm_post_port_init Callback to be called just after resource init. + * Allows for modification of port timing for >15MHz clocks. + * Set to NULL if not needed. + */ +void i2s_tdm_slave_tx_16_init( + i2s_tdm_ctx_t *ctx, + i2s_callback_group_t *i2s_cbg, + port_t p_dout, + port_t p_fsync, + port_t p_bclk, + xclock_t bclk, + uint32_t tx_offset, + i2s_slave_bclk_polarity_t slave_bclk_polarity, + tdm_post_port_init_t tdm_post_port_init); + +/** + * I2S TDM TX 16 ch slave task + * + * This task performs I2S TDM slave on the provided context which was + * initialized with i2s_tdm_slave_tx_16_init(). It will perform + * callbacks over the i2s_callback_group_t callback group to get + * data from the application using this component. + * + * This thread assumes 1 data output port, 32b word length, + * 32b channel length, and 16 channels per frame. + * + * The component performs I2S TDM slave so will expect the fsync and + * bit clock to be driven externally. + * + * \param ctx A pointer to the I2S TDM context to use. + */ +void i2s_tdm_slave_tx_16_thread( + i2s_tdm_ctx_t *ctx); + +/**@}*/ // END: addtogroup hil_i2s_tdm_slave_tx16 + +/** + * \addtogroup hil_i2s_tdm_slave hil_i2s_tdm_slave + * + * The public API for using the HIL I2S TDM generic slave. + * @{ + */ + +/** + * I2S generic TDM slave context initialization + * + * This prepares a context for I2S TDM slave on the provided pins. + * + * The resulting context can be used with an I2S thread call. + * + * \param ctx A pointer to the I2S TDM context to use. + * \param i2s_cbg The I2S callback group pointing to the application's + * functions to use for initialization and getting and receiving + * frames. For TDM the app_data variable within this + * struct is NOT used. + * \param p_dout An array of data output ports. MUST be 1b ports + * \param num_out The number of output data ports + * \param p_din An array of data input ports. MUST be 1b ports + * \param num_in The number of input data ports + * \param p_fsync The fsync input port. MUST be a 1b port + * \param p_bclk The bit clock input port. MUST be a 1b port + * \param bclk A clock that will get configured for use with + * the bit clock + * \param tx_offset The number of BCLKS from FSYNC transition to the MSB + * of Slot 0 + * \param fsync_len The length of the FSYNC in BCLKS + * \param word_len The number of bits in each sample frame slot. + * MUST be 32. + * \param ch_len The number of bits in each channel. MUST be less than + * word_len + * \param ch_per_frame The number of channels per frame + * \param slave_bclk_pol The polarity of bclk + * \param tdm_post_port_init Callback to be called just after resource init. + * Allows for modification of port timing for >15MHz clocks. + * Set to NULL if not needed. + */ +void i2s_tdm_slave_init( + i2s_tdm_ctx_t *ctx, + i2s_callback_group_t *i2s_cbg, + port_t p_dout[], + size_t num_out, + port_t p_din[], + size_t num_in, + port_t p_fsync, + port_t p_bclk, + xclock_t bclk, + uint32_t tx_offset, + uint32_t fsync_len, + uint32_t word_len, + uint32_t ch_len, + uint32_t ch_per_frame, + i2s_slave_bclk_polarity_t slave_bclk_pol, + tdm_post_port_init_t tdm_post_port_init +); + +/** + * I2S generic TDM slave task + * + * This task performs I2S TDM slave on the provided context. It will perform + * callbacks over the i2s_callback_group_t callback group to get/receive + * data from the application using this component. + * + * The component performs I2S TDM slave so will expect the fsync and + * bit clock to be driven externally. + * + * \param ctx A pointer to the I2S TDM context to use. + */ +void i2s_slave_tdm_thread( + i2s_tdm_ctx_t *ctx); + +/**@}*/ // END: addtogroup hil_i2s_tdm_slave diff --git a/modules/i2s/src/i2s_master.c b/modules/i2s/src/i2s_master.c index 992a9ce..c8323fd 100644 --- a/modules/i2s/src/i2s_master.c +++ b/modules/i2s/src/i2s_master.c @@ -31,6 +31,8 @@ static void i2s_init_ports( { size_t i; + clock_stop(bclk); + port_reset(p_bclk); port_set_clock(p_bclk, bclk); port_set_out_clock(p_bclk); diff --git a/modules/i2s/src/i2s_tdm_slave.c b/modules/i2s/src/i2s_tdm_slave.c new file mode 100644 index 0000000..1373728 --- /dev/null +++ b/modules/i2s/src/i2s_tdm_slave.c @@ -0,0 +1,222 @@ +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include +#include + +#include +#include +#include + +#include "i2s.h" +#include "i2s_tdm_slave.h" + +void i2s_tdm_slave_init( + i2s_tdm_ctx_t *ctx, + i2s_callback_group_t *i2s_cbg, + port_t p_dout[], + size_t num_out, + port_t p_din[], + size_t num_in, + port_t p_fsync, + port_t p_bclk, + xclock_t bclk, + uint32_t tx_offset, + uint32_t fsync_len, + uint32_t word_len, + uint32_t ch_len, + uint32_t ch_per_frame, + i2s_slave_bclk_polarity_t slave_bclk_pol, + tdm_post_port_init_t tdm_post_port_init) +{ + memset(ctx, 0, sizeof(i2s_tdm_ctx_t)); + ctx->i2s_cbg = i2s_cbg; + + xassert(num_out <= I2S_TDM_MAX_POUT_CNT); + memcpy((void*)ctx->p_dout, p_dout, sizeof(port_t) * num_out); + xassert(num_in <= I2S_TDM_MAX_PIN_CNT); + memcpy((void*)ctx->p_din, p_din, sizeof(port_t) * num_in); + ctx->num_out = num_out; + ctx->num_in = num_in; + + ctx->p_fsync = p_fsync; + ctx->p_bclk = p_bclk; + ctx->bclk = bclk; + ctx->tx_offset = tx_offset; + ctx->fsync_len = 1; /* Does not matter for slave as we only care about rising or falling edge */ + ctx->word_len = word_len; + ctx->ch_len = ch_len; + ctx->ch_per_frame = ch_per_frame; + ctx->slave_bclk_polarity = slave_bclk_pol; + ctx->tdm_post_port_init = tdm_post_port_init; + ctx->fysnch_error = false; +} + +void i2s_tdm_slave_tx_16_init( + i2s_tdm_ctx_t *ctx, + i2s_callback_group_t *i2s_cbg, + port_t p_dout, + port_t p_fsync, + port_t p_bclk, + xclock_t bclk, + uint32_t tx_offset, + i2s_slave_bclk_polarity_t slave_bclk_polarity, + tdm_post_port_init_t tdm_post_port_init) +{ + port_t pdout[I2S_TDM_MAX_POUT_CNT]; + pdout[0] = p_dout; + + i2s_tdm_slave_init( + ctx, + i2s_cbg, + pdout, + 1, + NULL, + 0, + p_fsync, + p_bclk, + bclk, + tx_offset, + 1, /* fsync_len: Does not matter for slave as we only care about edge */ + 32, /* word len */ + 32, /* ch len */ + 16, /* ch per frame */ + slave_bclk_polarity, + tdm_post_port_init); +} + +static void i2s_tdm_slave_init_resources( + i2s_tdm_ctx_t *ctx) +{ + port_enable(ctx->p_bclk); + clock_enable(ctx->bclk); + clock_set_source_port(ctx->bclk, ctx->p_bclk); + clock_set_divide(ctx->bclk, 0); + + for(int i=0; inum_out; i++) { + port_start_buffered(ctx->p_dout[i], 32); + port_set_clock(ctx->p_dout[i], ctx->bclk); + port_clear_buffer(ctx->p_dout[i]); + } + for(int i=0; inum_in; i++) { + port_start_buffered(ctx->p_din[i], 32); + port_set_clock(ctx->p_din[i], ctx->bclk); + port_clear_buffer(ctx->p_din[i]); + } + port_enable(ctx->p_fsync); + port_set_clock(ctx->p_fsync, ctx->bclk); + port_clear_buffer(ctx->p_fsync); + + if (ctx->slave_bclk_polarity == I2S_SLAVE_SAMPLE_ON_BCLK_FALLING) { + port_set_invert(ctx->p_bclk); + } else { + port_set_no_invert(ctx->p_bclk); + } + clock_start(ctx->bclk); +} + +static void i2s_tdm_slave_deinit_resources( + i2s_tdm_ctx_t *ctx) +{ + clock_disable(ctx->bclk); + port_disable(ctx->p_bclk); + + for(int i=0; inum_out; i++) { + port_disable(ctx->p_dout[i]); + } + for(int i=0; inum_in; i++) { + port_disable(ctx->p_din[i]); + } +} + +void i2s_tdm_slave_tx_16_thread( + i2s_tdm_ctx_t *ctx) +{ + uint32_t out_samps[I2S_TDM_MAX_CH_PER_FRAME]; + uint32_t fsync_val = 0; + + while(1) { + xassert(ctx->num_out == 1); + + if (ctx->i2s_cbg->init != NULL) { + ctx->i2s_cbg->init(ctx->i2s_cbg->app_data, NULL); + } + + i2s_tdm_slave_init_resources(ctx); + + /* Note we init the resources first to allow port delays etc. to be modified + after ports and clocks have been initialised */ + if (ctx->tdm_post_port_init != NULL) { + ctx->tdm_post_port_init(ctx); + } + + /* Get first frame data */ + ctx->i2s_cbg->send(ctx->i2s_cbg->app_data, ctx->ch_per_frame, (int32_t*)out_samps); + + uint32_t port_frame_time = (ctx->ch_per_frame * ctx->word_len); + + /* Wait for first fsync rising edge to occur */ + ctx->fysnch_error = false; + port_set_trigger_in_equal(ctx->p_fsync, 0); + (void) port_in(ctx->p_fsync); + port_set_trigger_in_equal(ctx->p_fsync, 1); + (void) port_in(ctx->p_fsync); + port_timestamp_t fsync_edge_time = port_get_trigger_time(ctx->p_fsync); + port_clear_trigger_in(ctx->p_fsync); + + /* Setup trigger times */ + port_set_trigger_time(ctx->p_fsync, port_frame_time + fsync_edge_time); + port_set_trigger_time(ctx->p_dout[0], port_frame_time + fsync_edge_time + ctx->tx_offset); + + port_out(ctx->p_dout[0], bitrev(out_samps[0])); + fsync_val = port_in(ctx->p_fsync); + fsync_edge_time = port_get_trigger_time(ctx->p_fsync); + port_set_trigger_time(ctx->p_fsync, port_frame_time + fsync_edge_time); + + for (int i=1; ich_per_frame; i++) { + port_out(ctx->p_dout[0], bitrev(out_samps[i])); + } + + while(1) { + /* Get frame data and tx */ + ctx->i2s_cbg->send(ctx->i2s_cbg->app_data, ctx->ch_per_frame, (int32_t*)out_samps); + + port_out(ctx->p_dout[0], bitrev(out_samps[0])); + fsync_val = port_in(ctx->p_fsync); + fsync_edge_time = port_get_trigger_time(ctx->p_fsync); + port_set_trigger_time(ctx->p_fsync, fsync_edge_time + port_frame_time); + + /* Note: Still possible for us to alias, but this will catch nonperiod drifting */ + if (fsync_val != 1) { + ctx->fysnch_error = true; + break; + } + + for (int i=1; ich_per_frame; i++) { + port_out(ctx->p_dout[0], bitrev(out_samps[i])); + } + + /* Check for exit condition */ + if (ctx->i2s_cbg->restart_check != NULL) { + i2s_restart_t restart = ctx->i2s_cbg->restart_check(ctx->i2s_cbg->app_data); + + if (restart == I2S_RESTART) { + break; + } else if (restart == I2S_SHUTDOWN) { + i2s_tdm_slave_deinit_resources(ctx); + return; + } + } + } + i2s_tdm_slave_deinit_resources(ctx); + } +} + +void i2s_slave_tdm_thread( + i2s_tdm_ctx_t *ctx) +{ + xassert(0); /* Not yet implemented */ + while(1) { + ; + } +} diff --git a/modules/mic_array b/modules/mic_array index c045fc2..beef6eb 160000 --- a/modules/mic_array +++ b/modules/mic_array @@ -1 +1 @@ -Subproject commit c045fc228777baccf5defd7710d029312ede4847 +Subproject commit beef6eb0640feee8c38cb5f5f98fbf3ea0f3ef87 diff --git a/modules/xud/lib_xud b/modules/xud/lib_xud index d5a9973..50dfe9f 160000 --- a/modules/xud/lib_xud +++ b/modules/xud/lib_xud @@ -1 +1 @@ -Subproject commit d5a99733f9c23e2cf48cc1bc526a8c0b267b97a9 +Subproject commit 50dfe9f62f20c7dc752f2bdc2be17e4498e60bc3 diff --git a/settings.json b/settings.json index eb2de71..f45574d 100644 --- a/settings.json +++ b/settings.json @@ -1,5 +1,5 @@ { "title": "XCORE Peripheral IO Framework", "project": "fwk_io", - "version": "3.0.1" + "version": "3.1.0" } \ No newline at end of file diff --git a/test/build_lib_i2s_tests.sh b/test/build_lib_i2s_tests.sh index 1e8bc39..7443962 100755 --- a/test/build_lib_i2s_tests.sh +++ b/test/build_lib_i2s_tests.sh @@ -79,6 +79,9 @@ applications=( "test_hil_i2s_slave_test_1_4_0_inv XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" "test_hil_i2s_slave_test_1_0_4_inv XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" "test_hil_i2s_slave_test_1_2_2_inv XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "test_hil_i2s_tdm_tx16_slave_test_0 XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "test_hil_i2s_tdm_tx16_slave_test_1 XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "test_hil_i2s_tdm_tx16_slave_test_2 XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" ) # perform builds diff --git a/test/conftest.py b/test/conftest.py index 938e25e..2a035aa 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -25,6 +25,8 @@ def pytest_collection_modifyitems(config, items): def pytest_addoption(parser): parser.addoption("--nightly", action="store_true") + parser.addoption("--lib_name", action="store", default=[], help="Optional lib to verify the output from") + @pytest.fixture def build(): diff --git a/test/lib_i2s/expected/tdm_slave_tx16_cb_test.expect b/test/lib_i2s/expected/tdm_slave_tx16_cb_test.expect new file mode 100644 index 0000000..dcc2fb3 --- /dev/null +++ b/test/lib_i2s/expected/tdm_slave_tx16_cb_test.expect @@ -0,0 +1,372 @@ +TDM Slave TX 16 Checker Started +CONFIG: bclk:\d+ sample_edge: [A-Z]+ fsynch_len: \d+ +i2s_init +Got Settings:tx_offset \d+ +Received word: 0 0 0x0 +Received word: 0 1 0x0 +Received word: 0 2 0x0 +Received word: 0 3 0x0 +Received word: 0 4 0x0 +Received word: 0 5 0x0 +Received word: 0 6 0x0 +Received word: 0 7 0x0 +Received word: 0 8 0x0 +Received word: 0 9 0x0 +Received word: 0 10 0x0 +Received word: 0 11 0x0 +Received word: 0 12 0x0 +Received word: 0 13 0x0 +Received word: 0 14 0x0 +Received word: 0 15 0x0 +Received word: 1 0 0x0 +Received word: 1 1 0x0 +Received word: 1 2 0x0 +Received word: 1 3 0x0 +Received word: 1 4 0x0 +Received word: 1 5 0x0 +Received word: 1 6 0x0 +Received word: 1 7 0x0 +Received word: 1 8 0x0 +Received word: 1 9 0x0 +Received word: 1 10 0x0 +Received word: 1 11 0x0 +Received word: 1 12 0x0 +Received word: 1 13 0x0 +Received word: 1 14 0x0 +Received word: 1 15 0x0 +Received word: 2 0 0x1 +Received word: 2 1 0x1000001 +Received word: 2 2 0x2000001 +Received word: 2 3 0x3000001 +Received word: 2 4 0x4000001 +Received word: 2 5 0x5000001 +Received word: 2 6 0x6000001 +Received word: 2 7 0x7000001 +Received word: 2 8 0x8000001 +Received word: 2 9 0x9000001 +Received word: 2 10 0xa000001 +Received word: 2 11 0xb000001 +Received word: 2 12 0xc000001 +Received word: 2 13 0xd000001 +Received word: 2 14 0xe000001 +Received word: 2 15 0xf000001 +Received word: 3 0 0x1 +Received word: 3 1 0x1000001 +Received word: 3 2 0x2000001 +Received word: 3 3 0x3000001 +Received word: 3 4 0x4000001 +Received word: 3 5 0x5000001 +Received word: 3 6 0x6000001 +Received word: 3 7 0x7000001 +Received word: 3 8 0x8000001 +Received word: 3 9 0x9000001 +Received word: 3 10 0xa000001 +Received word: 3 11 0xb000001 +Received word: 3 12 0xc000001 +Received word: 3 13 0xd000001 +Received word: 3 14 0xe000001 +Received word: 3 15 0xf000001 +Received word: 4 0 0x2 +Received word: 4 1 0x1000002 +Received word: 4 2 0x2000002 +Received word: 4 3 0x3000002 +Received word: 4 4 0x4000002 +Received word: 4 5 0x5000002 +Received word: 4 6 0x6000002 +Received word: 4 7 0x7000002 +Received word: 4 8 0x8000002 +Received word: 4 9 0x9000002 +Received word: 4 10 0xa000002 +Received word: 4 11 0xb000002 +Received word: 4 12 0xc000002 +Received word: 4 13 0xd000002 +Received word: 4 14 0xe000002 +Received word: 4 15 0xf000002 +Received word: 5 0 0x3 +Received word: 5 1 0x1000003 +Received word: 5 2 0x2000003 +Received word: 5 3 0x3000003 +Received word: 5 4 0x4000003 +Received word: 5 5 0x5000003 +Received word: 5 6 0x6000003 +Received word: 5 7 0x7000003 +Received word: 5 8 0x8000003 +Received word: 5 9 0x9000003 +Received word: 5 10 0xa000003 +Received word: 5 11 0xb000003 +Received word: 5 12 0xc000003 +Received word: 5 13 0xd000003 +Received word: 5 14 0xe000003 +Received word: 5 15 0xf000003 +Received word: 6 0 0x4 +Received word: 6 1 0x1000004 +Received word: 6 2 0x2000004 +Received word: 6 3 0x3000004 +Received word: 6 4 0x4000004 +Received word: 6 5 0x5000004 +Received word: 6 6 0x6000004 +Received word: 6 7 0x7000004 +Received word: 6 8 0x8000004 +Received word: 6 9 0x9000004 +Received word: 6 10 0xa000004 +Received word: 6 11 0xb000004 +Received word: 6 12 0xc000004 +Received word: 6 13 0xd000004 +Received word: 6 14 0xe000004 +Received word: 6 15 0xf000004 +Received word: 7 0 0x5 +Received word: 7 1 0x1000005 +Received word: 7 2 0x2000005 +Received word: 7 3 0x3000005 +Received word: 7 4 0x4000005 +Received word: 7 5 0x5000005 +Received word: 7 6 0x6000005 +Received word: 7 7 0x7000005 +Received word: 7 8 0x8000005 +Received word: 7 9 0x9000005 +Received word: 7 10 0xa000005 +Received word: 7 11 0xb000005 +Received word: 7 12 0xc000005 +Received word: 7 13 0xd000005 +Received word: 7 14 0xe000005 +Received word: 7 15 0xf000005 +Received word: 8 0 0x6 +Received word: 8 1 0x1000006 +Received word: 8 2 0x2000006 +Received word: 8 3 0x3000006 +Received word: 8 4 0x4000006 +Received word: 8 5 0x5000006 +Received word: 8 6 0x6000006 +Received word: 8 7 0x7000006 +Received word: 8 8 0x8000006 +Received word: 8 9 0x9000006 +Received word: 8 10 0xa000006 +Received word: 8 11 0xb000006 +Received word: 8 12 0xc000006 +Received word: 8 13 0xd000006 +Received word: 8 14 0xe000006 +Received word: 8 15 0xf000006 +Received word: 9 0 0x7 +Received word: 9 1 0x1000007 +Received word: 9 2 0x2000007 +Received word: 9 3 0x3000007 +Received word: 9 4 0x4000007 +Received word: 9 5 0x5000007 +Received word: 9 6 0x6000007 +Received word: 9 7 0x7000007 +Received word: 9 8 0x8000007 +Received word: 9 9 0x9000007 +Received word: 9 10 0xa000007 +Received word: 9 11 0xb000007 +Received word: 9 12 0xc000007 +Received word: 9 13 0xd000007 +Received word: 9 14 0xe000007 +Received word: 9 15 0xf000007 +Received word: 10 0 0x8 +Received word: 10 1 0x1000008 +Received word: 10 2 0x2000008 +Received word: 10 3 0x3000008 +Received word: 10 4 0x4000008 +Received word: 10 5 0x5000008 +Received word: 10 6 0x6000008 +Received word: 10 7 0x7000008 +Received word: 10 8 0x8000008 +Received word: 10 9 0x9000008 +Received word: 10 10 0xa000008 +Received word: 10 11 0xb000008 +Received word: 10 12 0xc000008 +Received word: 10 13 0xd000008 +Received word: 10 14 0xe000008 +Received word: 10 15 0xf000008 +Received word: 11 0 0x9 +Received word: 11 1 0x1000009 +Received word: 11 2 0x2000009 +Received word: 11 3 0x3000009 +Received word: 11 4 0x4000009 +Received word: 11 5 0x5000009 +Received word: 11 6 0x6000009 +Received word: 11 7 0x7000009 +Received word: 11 8 0x8000009 +Received word: 11 9 0x9000009 +Received word: 11 10 0xa000009 +Received word: 11 11 0xb000009 +Received word: 11 12 0xc000009 +Received word: 11 13 0xd000009 +Received word: 11 14 0xe000009 +Received word: 11 15 0xf000009 +Received word: 12 0 0xa +Received word: 12 1 0x100000a +Received word: 12 2 0x200000a +Received word: 12 3 0x300000a +Received word: 12 4 0x400000a +Received word: 12 5 0x500000a +Received word: 12 6 0x600000a +Received word: 12 7 0x700000a +Received word: 12 8 0x800000a +Received word: 12 9 0x900000a +Received word: 12 10 0xa00000a +Received word: 12 11 0xb00000a +Received word: 12 12 0xc00000a +Received word: 12 13 0xd00000a +Received word: 12 14 0xe00000a +Received word: 12 15 0xf00000a +Received word: 13 0 0xb +Received word: 13 1 0x100000b +Received word: 13 2 0x200000b +Received word: 13 3 0x300000b +Received word: 13 4 0x400000b +Received word: 13 5 0x500000b +Received word: 13 6 0x600000b +Received word: 13 7 0x700000b +Received word: 13 8 0x800000b +Received word: 13 9 0x900000b +Received word: 13 10 0xa00000b +Received word: 13 11 0xb00000b +Received word: 13 12 0xc00000b +Received word: 13 13 0xd00000b +Received word: 13 14 0xe00000b +Received word: 13 15 0xf00000b +Received word: 14 0 0xc +Received word: 14 1 0x100000c +Received word: 14 2 0x200000c +Received word: 14 3 0x300000c +Received word: 14 4 0x400000c +Received word: 14 5 0x500000c +Received word: 14 6 0x600000c +Received word: 14 7 0x700000c +Received word: 14 8 0x800000c +Received word: 14 9 0x900000c +Received word: 14 10 0xa00000c +Received word: 14 11 0xb00000c +Received word: 14 12 0xc00000c +Received word: 14 13 0xd00000c +Received word: 14 14 0xe00000c +Received word: 14 15 0xf00000c +Received word: 15 0 0xd +Received word: 15 1 0x100000d +Received word: 15 2 0x200000d +Received word: 15 3 0x300000d +Received word: 15 4 0x400000d +Received word: 15 5 0x500000d +Received word: 15 6 0x600000d +Received word: 15 7 0x700000d +Received word: 15 8 0x800000d +Received word: 15 9 0x900000d +Received word: 15 10 0xa00000d +Received word: 15 11 0xb00000d +Received word: 15 12 0xc00000d +Received word: 15 13 0xd00000d +Received word: 15 14 0xe00000d +Received word: 15 15 0xf00000d +Received word: 16 0 0xe +Received word: 16 1 0x100000e +Received word: 16 2 0x200000e +Received word: 16 3 0x300000e +Received word: 16 4 0x400000e +Received word: 16 5 0x500000e +Received word: 16 6 0x600000e +Received word: 16 7 0x700000e +Received word: 16 8 0x800000e +Received word: 16 9 0x900000e +Received word: 16 10 0xa00000e +Received word: 16 11 0xb00000e +Received word: 16 12 0xc00000e +Received word: 16 13 0xd00000e +Received word: 16 14 0xe00000e +Received word: 16 15 0xf00000e +Received word: 17 0 0xf +Received word: 17 1 0x100000f +Received word: 17 2 0x200000f +Received word: 17 3 0x300000f +Received word: 17 4 0x400000f +Received word: 17 5 0x500000f +Received word: 17 6 0x600000f +Received word: 17 7 0x700000f +Received word: 17 8 0x800000f +Received word: 17 9 0x900000f +Received word: 17 10 0xa00000f +Received word: 17 11 0xb00000f +Received word: 17 12 0xc00000f +Received word: 17 13 0xd00000f +Received word: 17 14 0xe00000f +Received word: 17 15 0xf00000f +Received word: 18 0 0x10 +Received word: 18 1 0x1000010 +Received word: 18 2 0x2000010 +Received word: 18 3 0x3000010 +Received word: 18 4 0x4000010 +Received word: 18 5 0x5000010 +Received word: 18 6 0x6000010 +Received word: 18 7 0x7000010 +Received word: 18 8 0x8000010 +Received word: 18 9 0x9000010 +Received word: 18 10 0xa000010 +Received word: 18 11 0xb000010 +Received word: 18 12 0xc000010 +Received word: 18 13 0xd000010 +Received word: 18 14 0xe000010 +Received word: 18 15 0xf000010 +Received word: 19 0 0x11 +Received word: 19 1 0x1000011 +Received word: 19 2 0x2000011 +Received word: 19 3 0x3000011 +Received word: 19 4 0x4000011 +Received word: 19 5 0x5000011 +Received word: 19 6 0x6000011 +Received word: 19 7 0x7000011 +Received word: 19 8 0x8000011 +Received word: 19 9 0x9000011 +Received word: 19 10 0xa000011 +Received word: 19 11 0xb000011 +Received word: 19 12 0xc000011 +Received word: 19 13 0xd000011 +Received word: 19 14 0xe000011 +Received word: 19 15 0xf000011 +Received word: 20 0 0x12 +Received word: 20 1 0x1000012 +Received word: 20 2 0x2000012 +Received word: 20 3 0x3000012 +Received word: 20 4 0x4000012 +Received word: 20 5 0x5000012 +Received word: 20 6 0x6000012 +Received word: 20 7 0x7000012 +Received word: 20 8 0x8000012 +Received word: 20 9 0x9000012 +Received word: 20 10 0xa000012 +Received word: 20 11 0xb000012 +Received word: 20 12 0xc000012 +Received word: 20 13 0xd000012 +Received word: 20 14 0xe000012 +Received word: 20 15 0xf000012 +Received word: 21 0 0x13 +Received word: 21 1 0x1000013 +Received word: 21 2 0x2000013 +Received word: 21 3 0x3000013 +Received word: 21 4 0x4000013 +Received word: 21 5 0x5000013 +Received word: 21 6 0x6000013 +Received word: 21 7 0x7000013 +Received word: 21 8 0x8000013 +Received word: 21 9 0x9000013 +Received word: 21 10 0xa000013 +Received word: 21 11 0xb000013 +Received word: 21 12 0xc000013 +Received word: 21 13 0xd000013 +Received word: 21 14 0xe000013 +Received word: 21 15 0xf000013 +Received word: 22 0 0x14 +Received word: 22 1 0x1000014 +Received word: 22 2 0x2000014 +Received word: 22 3 0x3000014 +Received word: 22 4 0x4000014 +Received word: 22 5 0x5000014 +Received word: 22 6 0x6000014 +Received word: 22 7 0x7000014 +Received word: 22 8 0x8000014 +Received word: 22 9 0x9000014 +Received word: 22 10 0xa000014 +Received word: 22 11 0xb000014 +Received word: 22 12 0xc000014 +Received word: 22 13 0xd000014 +Received word: 22 14 0xe000014 +Received word: 22 15 0xf000014 diff --git a/test/lib_i2s/i2s_master_checker.py b/test/lib_i2s/i2s_master_checker.py index d402244..28d02c2 100644 --- a/test/lib_i2s/i2s_master_checker.py +++ b/test/lib_i2s/i2s_master_checker.py @@ -14,7 +14,7 @@ class Clock(px.SimThread): def __init__(self, port: str) -> None: - self._rate = 1000000000 + self._rate = 100000000 # Just set to arbitrary 100MHz initially self._driving = True self._half_period = float(500000000000) / self._rate self._port = port diff --git a/test/lib_i2s/i2s_master_test/src/main.c b/test/lib_i2s/i2s_master_test/src/main.c index 2ba6501..42824e7 100644 --- a/test/lib_i2s/i2s_master_test/src/main.c +++ b/test/lib_i2s/i2s_master_test/src/main.c @@ -17,7 +17,7 @@ xclock_t bclk = XS1_CLKBLK_2; port_t setup_strobe_port = XS1_PORT_1L; port_t setup_data_port = XS1_PORT_16A; -port_t setup_resp_port = XS1_PORT_1M; +port_t setup_resp_port = XS1_PORT_1M; #define MAX_RATIO 4 diff --git a/test/lib_i2s/lib_i2s.cmake b/test/lib_i2s/lib_i2s.cmake index efb52da..ee577c6 100644 --- a/test/lib_i2s/lib_i2s.cmake +++ b/test/lib_i2s/lib_i2s.cmake @@ -2,3 +2,4 @@ include(${CMAKE_CURRENT_LIST_DIR}/backpressure_test/backpressure_test.cmake) include(${CMAKE_CURRENT_LIST_DIR}/i2s_master_external_clock_test/i2s_master_external_clock_test.cmake) include(${CMAKE_CURRENT_LIST_DIR}/i2s_master_test/i2s_master_test.cmake) include(${CMAKE_CURRENT_LIST_DIR}/i2s_slave_test/i2s_slave_test.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/tdm_slave_tx16_cb_test/i2s_tdm_tx16_slave_test.cmake) diff --git a/test/lib_i2s/tdm_slave_checker.py b/test/lib_i2s/tdm_slave_checker.py new file mode 100644 index 0000000..36bab4b --- /dev/null +++ b/test/lib_i2s/tdm_slave_checker.py @@ -0,0 +1,170 @@ +# Copyright 2023 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. +import Pyxsim + +class TDMSlaveTX16Checker(Pyxsim.SimThread): + + sample_on_falling = 0 + sample_on_rising = 1 + + def __init__( + self, + sclk, + fsync, + dout, + setup_strobe_port, + setup_data_port, + setup_resp_port, + sample_edge, + sclk_frequency + ): + self._sclk = sclk + self._fsync = fsync + self._dout = dout + self._setup_strobe_port = setup_strobe_port + self._setup_data_port = setup_data_port + self._setup_resp_port = setup_resp_port + self._sample_edge = sample_edge + self._sclk_frequency = sclk_frequency + + def get_setup_data(self, + xsi: Pyxsim.pyxsim.Xsi, + setup_strobe_port: str, + setup_data_port: str) -> int: + self.wait_for_port_pins_change([setup_strobe_port]) + self.wait_for_port_pins_change([setup_strobe_port]) + return xsi.sample_port_pins(setup_data_port) + + def run(self): + xsi = self.xsi + print("TDM Slave TX 16 Checker Started") + + while True: + frame_count = 0 + bit_count = 0 + word_count = 0 + bits_per_word = 32 + ch_count = 16 + fsync_len = 1 + + blcks_per_frame = bits_per_word * ch_count + + edge_str = "FALLING" if self._sample_edge==self.sample_on_falling else "RISING" + print(f"CONFIG: bclk:{self._sclk_frequency} sample_edge: {edge_str} fsynch_len: {fsync_len}") + clock_half_period = float(1000000000) / float(2 * (self._sclk_frequency/1000)) ## Want freq in Hz + clock_quarter_period = clock_half_period / 2 + + #first do the setup rx + strobe_val = xsi.sample_port_pins(self._setup_strobe_port) + if strobe_val == 1: + xsi.drive_port_pins(self._sclk, 1) + xsi.drive_port_pins(self._fsync, 0) + self.wait_for_port_pins_change([self._setup_strobe_port]) + + tx_offset = self.get_setup_data(xsi, self._setup_strobe_port, self._setup_data_port) + + print(f"Got Settings:tx_offset {tx_offset}") + + # drive initial values while slave starts up for the first time + xsi.drive_port_pins(self._sclk, 1 if self._sample_edge == self.sample_on_rising else 0) + xsi.drive_port_pins(self._fsync, 0) + self.wait_until(xsi.get_time() + 1000000) + + frame_cnt = 0 + # Start test + while 1: + bits_rx = 0 + bclk_val = 0 + + + # print(f"frame:{frame_cnt}") + for i in range(0, blcks_per_frame): + if i % bits_per_word == 0: + word_rx = 0 + + # bclk + xsi.drive_port_pins(self._sclk, 0 if self._sample_edge == self.sample_on_rising else 1) + + # fsync + if bits_rx % blcks_per_frame == 0: + xsi.drive_port_pins(self._fsync, 1) + if bits_rx % blcks_per_frame == fsync_len: + xsi.drive_port_pins(self._fsync, 0) + + # half clock update + time = xsi.get_time() + time = time + clock_half_period + self.wait_until(time) + + # bclk + xsi.drive_port_pins(self._sclk, 1 if self._sample_edge == self.sample_on_rising else 0) + + # fsync (unchanged) + if bits_rx % blcks_per_frame == 0: + xsi.drive_port_pins(self._fsync, 1) + if bits_rx % blcks_per_frame == fsync_len: + xsi.drive_port_pins(self._fsync, 0) + + # full clock update + time = xsi.get_time() + time = time + clock_quarter_period + self.wait_until(time) + + # sample + bit_val = xsi.sample_port_pins(self._dout) + word_rx |= bit_val << ((i - tx_offset) % bits_per_word) + + if frame_cnt >= 2: # Ignore init frame as data is 0's while slave syncs up + frame_arg = 0 + bit_arg = 0 + if tx_offset == 0: + frame_arg = frame_cnt-1 + bit_arg = bits_rx + else: + if bits_rx < tx_offset: + frame_arg = (frame_cnt-2) + else: + frame_arg = (frame_cnt-1) + + if frame_arg == (frame_cnt-1): + bit_arg = bits_rx - tx_offset + else: + bit_arg = (blcks_per_frame - 1) + (bits_rx - tx_offset) + + expect_rx = self.calc_expected_bit(frame_arg, bit_arg) + # print(f"asked for {frame_arg}:{bit_arg} check bit[{bits_rx}]:{bit_val}:{expect_rx}") + + # For the first frame, if tx_offset > 0, the first tx_offset bits are don't cares + if frame_cnt == 2 and bits_rx > tx_offset: + if bit_val != expect_rx: + print(f"ERROR: bit[{bits_rx}]:{bit_val}:{expect_rx}") + + bits_rx += 1 + time = xsi.get_time() + time = time + clock_quarter_period + self.wait_until(time) + + if i % bits_per_word == bits_per_word - 1: + print(f"Received word: {frame_cnt} {i // bits_per_word} {hex(word_rx)}") + + frame_cnt += 1 + + def calc_expected_bit(self, frame, bit): + # Each sample in the tdm_slave_tx16_test output is in the format + # bin AAAAAAAA BBBBBBBB BBBBBBBB BBBBBBBB + # Where: + # AAAAAAAA is the channel id, [0,255] + # BBBBBBBB BBBBBBBB BBBBBBBB is frame num starting at 1 + # Additionally, the output data is bitrev, so that it shows up + # in a more easily recognizable format on the wire in vcd traces + ret = 0 + + ch = bit // 32 + ch_index = bit % 32 + + if ch_index >= 24: + ret = (ch >> (ch_index - 24)) & 0b1 + else: + ret = (frame >> ch_index) & 0b1 + + return ret diff --git a/test/lib_i2s/tdm_slave_tx16_cb_test/i2s_tdm_tx16_slave_test.cmake b/test/lib_i2s/tdm_slave_tx16_cb_test/i2s_tdm_tx16_slave_test.cmake new file mode 100644 index 0000000..bda00db --- /dev/null +++ b/test/lib_i2s/tdm_slave_tx16_cb_test/i2s_tdm_tx16_slave_test.cmake @@ -0,0 +1,46 @@ +#********************** +# Gather Sources +#********************** +file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c) +set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src) + +#********************** +# Flags +#********************** +set(APP_COMPILER_FLAGS + -O3 + -target=XCORE-AI-EXPLORER +) +set(APP_LINK_OPTIONS + -report + -target=XCORE-AI-EXPLORER +) + +#********************** +# Tile Targets +#********************** +if(NOT DEFINED ENV{TX_OFFSET}) + set(TX_OFFSET "0" "1" "2") +else() + set(TX_OFFSET $ENV{TX_OFFSET}) +endif() + +#********************** +# Setup targets +#********************** +foreach(tx_offset ${TX_OFFSET}) + set(TARGET_NAME "test_hil_i2s_tdm_tx16_slave_test_${tx_offset}") + add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) + target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES}) + target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES}) + target_compile_definitions(${TARGET_NAME} + PRIVATE + ${APP_COMPILE_DEFINITIONS} + TX_OFFSET=${tx_offset} + ) + target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) + target_link_libraries(${TARGET_NAME} PUBLIC lib_i2s) + target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) + set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/bin) + unset(TARGET_NAME) +endforeach() diff --git a/test/lib_i2s/tdm_slave_tx16_cb_test/src/tdm_slave_tx16_test.c b/test/lib_i2s/tdm_slave_tx16_cb_test/src/tdm_slave_tx16_test.c new file mode 100644 index 0000000..69cf068 --- /dev/null +++ b/test/lib_i2s/tdm_slave_tx16_cb_test/src/tdm_slave_tx16_test.c @@ -0,0 +1,158 @@ +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include +#include +#include +#include + +#include "xcore/port.h" +#include "xcore/clock.h" +#include "xcore/parallel.h" + +#include "i2s.h" +#include "i2s_tdm_slave.h" + +port_t p_bclk = XS1_PORT_1A; +port_t p_fsync = XS1_PORT_1C; +port_t p_dout = XS1_PORT_1D; + +xclock_t bclk = XS1_CLKBLK_1; + +port_t setup_strobe_port = XS1_PORT_1E; +port_t setup_data_port = XS1_PORT_16B; +port_t setup_resp_port = XS1_PORT_1F; + +#ifndef TEST_FRAME_COUNT +#define TEST_FRAME_COUNT 20 +#endif +#ifndef TEST_NUM_CH +#define TEST_NUM_CH 16 +#endif + +int32_t test_data[TEST_FRAME_COUNT][TEST_NUM_CH] = {{0}}; +volatile int32_t cnt = 0; + + +DECLARE_JOB(burn, (void)); + +void burn(void) { + for(;;); +} + +static void send_data_to_tester( + port_t setup_strobe_port, + port_t setup_data_port, + unsigned data){ + port_out(setup_data_port, data); + asm volatile("syncr res[%0]" : : "r" (setup_data_port)); + port_out(setup_strobe_port, 1); + port_out(setup_strobe_port, 0); + asm volatile("syncr res[%0]" : : "r" (setup_data_port)); +} + +static void broadcast_settings( + port_t setup_strobe_port, + port_t setup_data_port) +{ + port_out(setup_strobe_port, 0); + + send_data_to_tester(setup_strobe_port, setup_data_port, TX_OFFSET); +} + +static uint32_t request_response( + port_t setup_strobe_port, + port_t setup_resp_port) +{ + port_enable(setup_resp_port); + port_out(setup_strobe_port, 1); + port_out(setup_strobe_port, 0); + uint32_t tmp = port_in(setup_resp_port); + return tmp; +} + + +I2S_CALLBACK_ATTR +void i2s_init(void *app_data, i2s_config_t *i2s_config) +{ + printf("i2s_init\n"); + (void) app_data; + (void) i2s_config; + + if (cnt > 0) { + printf("Restart likely due to fsynch error at frame count: %ld\n", cnt); + _Exit(1); + } + + + /* Initialize test data */ + for (int i=1; i<=TEST_FRAME_COUNT; i++) { + for (int j=0; j 0 for testcase in tsuite.iter("testcase"): + # Test passed if there are no children if len(testcase) == 0: + if "name" in testcase.attrib: + print(testcase.attrib['name'], "passed") continue # Otherwise, test was either skipped, errored, or failed. The testcase # will have a child with a relevant tag - skipped, error, or failure. @@ -37,3 +39,4 @@ def test_results(fname): assert ( child.tag in acceptable_outcomes ), f"A test reports as {child.tag}, which is not accepted." + print(testcase.attrib['name'], child.tag )