// Copyright (c) 2016-2018, XMOS Ltd, All rights reserved #include #include #include #include #include "xua.h" #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] = {PORT_I2S_DAC0, #endif #if I2S_WIRES_DAC > 1 PORT_I2S_DAC1, #endif #if I2S_WIRES_DAC > 2 PORT_I2S_DAC2, #endif #if I2S_WIRES_DAC > 3 PORT_I2S_DAC3, #endif #if I2S_WIRES_DAC > 4 PORT_I2S_DAC4, #endif #if I2S_WIRES_DAC > 5 PORT_I2S_DAC5, #endif #if I2S_WIRES_DAC > 6 PORT_I2S_DAC6, #endif #if I2S_WIRES_DAC > 7 #error I2S_WIRES_DAC value is too large! #endif #if I2S_WIRES_DAC > 0 }; #endif #if I2S_WIRES_ADC > 0 on tile[AUDIO_IO_TILE] : buffered in port:32 p_i2s_adc[I2S_WIRES_ADC] = {PORT_I2S_ADC0, #endif #if I2S_WIRES_ADC > 1 PORT_I2S_ADC1, #endif #if I2S_WIRES_ADC > 2 PORT_I2S_ADC2, #endif #if I2S_WIRES_ADC > 3 PORT_I2S_ADC3, #endif #if I2S_WIRES_ADC > 4 PORT_I2S_ADC4, #endif #if I2S_WIRES_ADC > 5 PORT_I2S_ADC5, #endif #if I2S_WIRES_ADC > 6 PORT_I2S_ADC6, #endif #if I2S_WIRES_ADC > 7 #error I2S_WIRES_ADC value is too large! #endif #if I2S_WIRES_ADC > 0 }; #endif #if CODEC_MASTER buffered in port:32 p_lrclk = PORT_I2S_LRCLK; buffered in port:32 p_bclk = PORT_I2S_BCLK; #else buffered out port:32 p_lrclk = PORT_I2S_LRCLK; /* I2S Bit-clock */ buffered out port:32 p_bclk = PORT_I2S_BCLK; /* I2S L/R-clock */ #endif /* Note, declared unsafe as sometimes we want to share this port e.g. PDM mics and I2S use same master clock IO */ port p_mclk_in_ = PORT_MCLK_IN; /* Clock-block declarations */ clock clk_audio_bclk = on tile[AUDIO_IO_TILE]: XS1_CLKBLK_1; /* Bit clock */ clock clk_audio_mclk = on tile[AUDIO_IO_TILE]: XS1_CLKBLK_2; /* Master clock */ unsafe { /* TODO simplify this */ unsafe port p_mclk_in; /* Audio master clock input */ } #ifdef SIMULATION #define INITIAL_SKIP_FRAMES 10 #define TOTAL_TEST_FRAMES 100 #else #define INITIAL_SKIP_FRAMES 1000 #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) void generator(chanend c_checker, chanend c_out) { unsigned frame_count; int underflow_word; int fail; int i; frame_count = 0; while (1) { underflow_word = inuint(c_out); #pragma loop unroll for (i = 0; i < NUM_USB_CHAN_OUT; i++) { outuint(c_out, SAMPLE(frame_count, i)); } fail = inuint(c_checker); #pragma loop unroll for (i = 0; i < NUM_USB_CHAN_IN; i++) { outuint(c_checker, inuint(c_out)); } if (frame_count == TOTAL_TEST_FRAMES) { if (!fail) { debug_printf("PASS\n"); } outct(c_out, AUDIO_STOP_FOR_DFU); //inuint(c_out); //This causes the DFUhandler to be called with exceptiopn in slave mode so skip this - we are out of here anyhow exit(0); } frame_count++; } } void checker(chanend c_checker, int disable) { unsigned x[NUM_USB_CHAN_IN]; int last_frame_number; unsigned frame_count; int fail; int i; if (disable) debug_printf("checker disabled\n"); /*debug_printf("%s %d/%d %d\n", I2S_MODE_TDM ? "TDM" : "I2S", NUM_USB_CHAN_IN, NUM_USB_CHAN_OUT, DEFAULT_FREQ);*/ fail = 0; frame_count = 0; last_frame_number = -1; while (1) { outuint(c_checker, fail); #pragma loop unroll for (i = 0; i < NUM_USB_CHAN_IN; i++) { x[i] = inuint(c_checker); } if (frame_count > INITIAL_SKIP_FRAMES) { // check that frame number is incrementing if (!disable && SAMPLE_FRAME_NUM(x[0]) != last_frame_number + 1) { debug_printf("%d: 0x%x (%d)\n", frame_count, x[0], last_frame_number); fail = 1; } for (i = 0; i < NUM_USB_CHAN_IN; i++) { // check channel numbers are 0 to N-1 in a frame if (!disable && SAMPLE_CHANNEL_NUM(x[i]) != i) { debug_printf("%d,%d: 0x%x\n", frame_count, i, x[i]); fail = 1; } // check frame number doesn't change in a frame if (!disable && SAMPLE_FRAME_NUM(x[i]) != SAMPLE_FRAME_NUM(x[0])) { debug_printf("%d,%d: 0x%x (0x%x)\n", frame_count, i, x[i], x[0]); fail = 1; } } } last_frame_number = SAMPLE_FRAME_NUM(x[0]); frame_count++; } } #ifdef SIMULATION out port p_mclk_gen = on tile[AUDIO_IO_TILE] : XS1_PORT_1A; clock clk_audio_mclk_gen = on tile[AUDIO_IO_TILE] : XS1_CLKBLK_3; void master_mode_clk_setup(void); #if CODEC_MASTER out port p_bclk_gen = on tile[AUDIO_IO_TILE] : XS1_PORT_1B; clock clk_audio_bclk_gen = on tile[AUDIO_IO_TILE] : XS1_CLKBLK_4; out port p_lrclk_gen = on tile[AUDIO_IO_TILE] : XS1_PORT_1C; clock clk_audio_lrclk_gen = on tile[AUDIO_IO_TILE] : XS1_CLKBLK_5; void slave_mode_clk_setup(const unsigned samFreq, const unsigned chans_per_frame); #endif #endif #if I2S_MODE_TDM const int i2s_tdm_mode = 1; #else const int i2s_tdm_mode = 0; #endif int main(void) { chan c_checker; chan c_out; par { on tile[AUDIO_IO_TILE]: { unsafe { p_mclk_in = p_mclk_in_; } par { XUA_AudioHub(c_out); generator(c_checker, c_out); checker(c_checker, 0); #ifdef SIMULATION #if CODEC_MASTER slave_mode_clk_setup(DEFAULT_FREQ, (i2s_tdm_mode != 0) ? 8 : 2); #else master_mode_clk_setup(); #endif #endif } } } return 0; }