From 770c11b3f09151af954b057609ca30da7f11d497 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Thu, 25 Oct 2018 17:52:13 +0100 Subject: [PATCH 001/123] Very early cut of xua_lite app. Builds (4 threads + I2C) but not functional --- examples/xua_lite_example/Makefile | 22 ++ examples/xua_lite_example/src/AudioConfig.h | 15 + examples/xua_lite_example/src/AudioConfig.xc | 220 ++++++++++++++ .../xua_lite_example/src/RPI_HAT_60QFN.xn | 66 +++++ examples/xua_lite_example/src/app_xua_lite.xc | 106 +++++++ examples/xua_lite_example/src/audio_hub.xc | 44 +++ examples/xua_lite_example/src/xua_buffer.xc | 274 ++++++++++++++++++ examples/xua_lite_example/src/xua_conf.h | 25 ++ examples/xua_lite_example/src/xud_conf.h | 7 + 9 files changed, 779 insertions(+) create mode 100644 examples/xua_lite_example/Makefile create mode 100755 examples/xua_lite_example/src/AudioConfig.h create mode 100755 examples/xua_lite_example/src/AudioConfig.xc create mode 100644 examples/xua_lite_example/src/RPI_HAT_60QFN.xn create mode 100644 examples/xua_lite_example/src/app_xua_lite.xc create mode 100644 examples/xua_lite_example/src/audio_hub.xc create mode 100644 examples/xua_lite_example/src/xua_buffer.xc create mode 100644 examples/xua_lite_example/src/xua_conf.h create mode 100644 examples/xua_lite_example/src/xud_conf.h diff --git a/examples/xua_lite_example/Makefile b/examples/xua_lite_example/Makefile new file mode 100644 index 00000000..c52597dd --- /dev/null +++ b/examples/xua_lite_example/Makefile @@ -0,0 +1,22 @@ +APP_NAME = + +TARGET = RPI_HAT_60QFN.xn + +# The flags passed to xcc when building the application +XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report \ + -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[0] + +#-DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope + +# The USED_MODULES variable lists other module used by the application. These +# modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables. +# Modules are expected to be in the directory above the BASE_DIR directory. +USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_gpio + +#============================================================================= +# The following part of the Makefile includes the common build infrastructure +# for compiling XMOS applications. You should not need to edit below here. + +XMOS_MAKE_PATH ?= ../.. +include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common + diff --git a/examples/xua_lite_example/src/AudioConfig.h b/examples/xua_lite_example/src/AudioConfig.h new file mode 100755 index 00000000..9843cb1d --- /dev/null +++ b/examples/xua_lite_example/src/AudioConfig.h @@ -0,0 +1,15 @@ +#ifndef _AUDIO_CONFIG_ +#define _AUDIO_CONFIG_ + +void ConfigAudioPorts(unsigned divide); + +void AudioHwInit(); + +void PLL_Init(void); + +/* Configures master clock and codc for passed sample freq */ +void AudioHwConfig(unsigned samFreq); + +void ConfigCodec24576(unsigned samFeq); + +#endif diff --git a/examples/xua_lite_example/src/AudioConfig.xc b/examples/xua_lite_example/src/AudioConfig.xc new file mode 100755 index 00000000..e42a09db --- /dev/null +++ b/examples/xua_lite_example/src/AudioConfig.xc @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include + + + +// TLV320DAC3101 Device I2C Address +#define DAC3101_I2C_DEVICE_ADDR 0x18 + +// TLV320DAC3101 Register Addresses +// Page 0 +#define DAC3101_PAGE_CTRL 0x00 // Register 0 - Page Control +#define DAC3101_SW_RST 0x01 // Register 1 - Software Reset +#define DAC3101_CLK_GEN_MUX 0x04 // Register 4 - Clock-Gen Muxing +#define DAC3101_PLL_P_R 0x05 // Register 5 - PLL P and R Values +#define DAC3101_PLL_J 0x06 // Register 6 - PLL J Value +#define DAC3101_PLL_D_MSB 0x07 // Register 7 - PLL D Value (MSB) +#define DAC3101_PLL_D_LSB 0x08 // Register 8 - PLL D Value (LSB) +#define DAC3101_NDAC_VAL 0x0B // Register 11 - NDAC Divider Value +#define DAC3101_MDAC_VAL 0x0C // Register 12 - MDAC Divider Value +#define DAC3101_DOSR_VAL_LSB 0x0E // Register 14 - DOSR Divider Value (LS Byte) +#define DAC3101_CLKOUT_MUX 0x19 // Register 25 - CLKOUT MUX +#define DAC3101_CLKOUT_M_VAL 0x1A // Register 26 - CLKOUT M_VAL +#define DAC3101_CODEC_IF 0x1B // Register 27 - CODEC Interface Control +#define DAC3101_DAC_DAT_PATH 0x3F // Register 63 - DAC Data Path Setup +#define DAC3101_DAC_VOL 0x40 // Register 64 - DAC Vol Control +#define DAC3101_DACL_VOL_D 0x41 // Register 65 - DAC Left Digital Vol Control +#define DAC3101_DACR_VOL_D 0x42 // Register 66 - DAC Right Digital Vol Control +#define DAC3101_GPIO1_IO 0x33 // Register 51 - GPIO1 In/Out Pin Control +// Page 1 +#define DAC3101_HP_DRVR 0x1F // Register 31 - Headphone Drivers +#define DAC3101_SPK_AMP 0x20 // Register 32 - Class-D Speaker Amp +#define DAC3101_HP_DEPOP 0x21 // Register 33 - Headphone Driver De-pop +#define DAC3101_DAC_OP_MIX 0x23 // Register 35 - DAC_L and DAC_R Output Mixer Routing +#define DAC3101_HPL_VOL_A 0x24 // Register 36 - Analog Volume to HPL +#define DAC3101_HPR_VOL_A 0x25 // Register 37 - Analog Volume to HPR +#define DAC3101_SPKL_VOL_A 0x26 // Register 38 - Analog Volume to Left Speaker +#define DAC3101_SPKR_VOL_A 0x27 // Register 39 - Analog Volume to Right Speaker +#define DAC3101_HPL_DRVR 0x28 // Register 40 - Headphone Left Driver +#define DAC3101_HPR_DRVR 0x29 // Register 41 - Headphone Right Driver +#define DAC3101_SPKL_DRVR 0x2A // Register 42 - Left Class-D Speaker Driver +#define DAC3101_SPKR_DRVR 0x2B // Register 43 - Right Class-D Speaker Driver + +// TLV320DAC3101 easy register access defines +//#define DAC3101_REGREAD(reg, data) {data[0] = 0xAA; i2c_master_read_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);} +//#define DAC3101_REGWRITE(reg, val) {data[0] = val; i2c_master_write_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);} + +//#define DAC3101_REGWRITE(reg, val) {i_i2c[0].write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);} + +// TLV320DAC3101 easy register access defines +//#define DAC3101_REGWRITE(reg, val) {data[0] = val; i2c_master_write_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);} +#define DAC3101_REGWRITE(reg, val) + + +void AudioHwConfigure(unsigned samFreq) +{ + + // Take DAC out of reset. + //p_gpio <: 1; + + par + { + { + unsigned char data[1] = {0}; + + // Wait for 1ms + delay_milliseconds(1); + + // Set register page to 0 + DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); + // Initiate SW reset (PLL is powered off as part of reset) + DAC3101_REGWRITE(DAC3101_SW_RST, 0x01); + + // so I've got 24MHz in to PLL, I want 24.576MHz or 22.5792MHz out. + + // I will always be using fractional-N (D != 0) so we must set R = 1 + // PLL_CLKIN/P must be between 10 and 20MHz so we must set P = 2 + + // PLL_CLK = CLKIN * ((RxJ.D)/P) + // We know R = 1, P = 2. + // PLL_CLK = CLKIN * (J.D / 2) + + // For 24.576MHz: + // J = 8 + // D = 1920 + // So PLL_CLK = 24 * (8.192/2) = 24 x 4.096 = 98.304MHz + // Then: + // NDAC = 4 + // MDAC = 4 + // DOSR = 128 + // So: + // DAC_CLK = PLL_CLK / 4 = 24.576MHz. + // DAC_MOD_CLK = DAC_CLK / 4 = 6.144MHz. + // DAC_FS = DAC_MOD_CLK / 128 = 48kHz. + + // For 22.5792MHz: + // J = 7 + // D = 5264 + // So PLL_CLK = 24 * (7.5264/2) = 24 x 3.7632 = 90.3168MHz + // Then: + // NDAC = 4 + // MDAC = 4 + // DOSR = 128 + // So: + // DAC_CLK = PLL_CLK / 4 = 22.5792MHz. + // DAC_MOD_CLK = DAC_CLK / 4 = 5.6448MHz. + // DAC_FS = DAC_MOD_CLK / 128 = 44.1kHz. + + /* Sample frequency dependent register settings */ + if ((samFreq % 11025) == 0) + { + // MCLK = 22.5792MHz (44.1,88.2,176.4kHz) + // Set PLL J Value to 7 + DAC3101_REGWRITE(DAC3101_PLL_J, 0x07); + // Set PLL D to 5264 ... (0x1490) + // Set PLL D MSB Value to 0x14 + DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x14); + // Set PLL D LSB Value to 0x90 + DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x90); + + } + else if ((samFreq % 8000) == 0) + { + // MCLK = 24.576MHz (48,96,192kHz) + // Set PLL J Value to 8 + DAC3101_REGWRITE(DAC3101_PLL_J, 0x08); + // Set PLL D to 1920 ... (0x780) + // Set PLL D MSB Value to 0x07 + DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x07); + // Set PLL D LSB Value to 0x80 + DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x80); + } + else + { + //debug_printf("Unrecognised sample freq of %d in ConfigCodec\n", samFreq); + } + + delay_milliseconds(1); + + // Set PLL_CLKIN = MCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) + DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x03); + + // Set PLL P and R values and power up. + DAC3101_REGWRITE(DAC3101_PLL_P_R, 0xA1); + // Set NDAC clock divider to 4 and power up. + DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x84); + // Set MDAC clock divider to 4 and power up. + DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x84); + // Set OSR clock divider to 128. + DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80); + + // Set CLKOUT Mux to DAC_CLK + DAC3101_REGWRITE(DAC3101_CLKOUT_MUX, 0x04); + // Set CLKOUT M divider to 1 and power up. + DAC3101_REGWRITE(DAC3101_CLKOUT_M_VAL, 0x81); + // Set GPIO1 output to come from CLKOUT output. + DAC3101_REGWRITE(DAC3101_GPIO1_IO, 0x10); + + // Set CODEC interface mode: I2S, 24 bit, slave mode (BCLK, WCLK both inputs). + DAC3101_REGWRITE(DAC3101_CODEC_IF, 0x20); + // Set register page to 1 + DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x01); + // Program common-mode voltage to mid scale 1.65V. + DAC3101_REGWRITE(DAC3101_HP_DRVR, 0x14); + // Program headphone-specific depop settings. + // De-pop, Power on = 800 ms, Step time = 4 ms + DAC3101_REGWRITE(DAC3101_HP_DEPOP, 0x4E); + // Program routing of DAC output to the output amplifier (headphone/lineout or speaker) + // LDAC routed to left channel mixer amp, RDAC routed to right channel mixer amp + DAC3101_REGWRITE(DAC3101_DAC_OP_MIX, 0x44); + // Unmute and set gain of output driver + // Unmute HPL, set gain = 0 db + DAC3101_REGWRITE(DAC3101_HPL_DRVR, 0x06); + // Unmute HPR, set gain = 0 dB + DAC3101_REGWRITE(DAC3101_HPR_DRVR, 0x06); + // Unmute Left Class-D, set gain = 12 dB + DAC3101_REGWRITE(DAC3101_SPKL_DRVR, 0x0C); + // Unmute Right Class-D, set gain = 12 dB + DAC3101_REGWRITE(DAC3101_SPKR_DRVR, 0x0C); + // Power up output drivers + // HPL and HPR powered up + DAC3101_REGWRITE(DAC3101_HP_DRVR, 0xD4); + // Power-up L and R Class-D drivers + DAC3101_REGWRITE(DAC3101_SPK_AMP, 0xC6); + // Enable HPL output analog volume, set = -9 dB + DAC3101_REGWRITE(DAC3101_HPL_VOL_A, 0x92); + // Enable HPR output analog volume, set = -9 dB + DAC3101_REGWRITE(DAC3101_HPR_VOL_A, 0x92); + // Enable Left Class-D output analog volume, set = -9 dB + DAC3101_REGWRITE(DAC3101_SPKL_VOL_A, 0x92); + // Enable Right Class-D output analog volume, set = -9 dB + DAC3101_REGWRITE(DAC3101_SPKR_VOL_A, 0x92); + + delay_milliseconds(100); + + // Power up DAC + // Set register page to 0 + DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); + // Power up DAC channels and set digital gain + // Powerup DAC left and right channels (soft step enabled) + DAC3101_REGWRITE(DAC3101_DAC_DAT_PATH, 0xD4); + // DAC Left gain = 0dB + DAC3101_REGWRITE(DAC3101_DACL_VOL_D, 0x00); + // DAC Right gain = 0dB + DAC3101_REGWRITE(DAC3101_DACR_VOL_D, 0x00); + // Unmute digital volume control + // Unmute DAC left and right channels + DAC3101_REGWRITE(DAC3101_DAC_VOL, 0x00); + + // Shutdown + //i_i2c[0].shutdown(); + } + } /* par */ +} + +//These are here just to silence compiler warnings +void AudioHwInit(){} +void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC){} \ No newline at end of file diff --git a/examples/xua_lite_example/src/RPI_HAT_60QFN.xn b/examples/xua_lite_example/src/RPI_HAT_60QFN.xn new file mode 100644 index 00000000..c0c3f85c --- /dev/null +++ b/examples/xua_lite_example/src/RPI_HAT_60QFN.xn @@ -0,0 +1,66 @@ + + + Device + XVF3510 Device + + + tileref tile[2] + tileref usb_tile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc new file mode 100644 index 00000000..8e5fea8e --- /dev/null +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -0,0 +1,106 @@ +// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved + +// A very simple *example* of a USB audio application (and as such is un-verified for production) + +#include +#include + +#include "xua.h" +#include "i2s.h" +#include "i2c.h" +#include "gpio.h" + +// Port declarations. Note, the defines come from the xn file +on tile[0]: buffered out port:32 p_i2s_dac[] = {XS1_PORT_1M}; //DAC +on tile[0]: buffered in port:32 p_i2s_adc[] = {XS1_PORT_1N}; //Unused currently +on tile[0]: buffered out port:32 p_lrclk = XS1_PORT_1O; //I2S Bit-clock +on tile[0]: out port p_bclk = XS1_PORT_1P; //I2S L/R-clock + +// Master clock for the audio IO tile +on tile[0]: in port p_mclk_in = XS1_PORT_1A; + +// Resources for USB feedback +on tile[0]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks + +// [0] : DAC_RESET_N +// [1] : I2C_INTERRUPT_N +// [2] : MUTE_EN +// [3] : LED +on tile[0]: out port p_gpio = XS1_PORT_4D; + +on tile[1]: port p_scl = XS1_PORT_1C; +on tile[1]: port p_sda = XS1_PORT_1D; + + +// Clock-block declarations +clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_2; // Bit clock +clock clk_audio_mclk = on tile[0]: XS1_CLKBLK_3; // Master clock + +// Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also +// if the endpoint wishes to be informed of USB bus resets + +XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO}; +XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO}; + +void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_aud_host); +[[distributable]] +void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, client i2c_master_if i2c, client output_gpio_if dac_reset); + +int main() +{ + // Channels for lib_xud + chan c_ep_out[2]; + chan c_ep_in[3]; + + // Channel for communicating SOF notifications from XUD to the Buffering cores + chan c_sof; + + interface i2s_frame_callback_if i_i2s; + interface i2c_master_if i_i2c[1]; + interface output_gpio_if i_gpio[1]; + + chan c_audio; + + + // Channel for communicating control messages from EP0 to the rest of the device (via the buffering cores) + chan c_aud_ctl; + + par + { + on tile[0]: { + // Connect master-clock clock-block to clock-block pin + set_clock_src(clk_audio_mclk, p_mclk_in); // Clock clock-block from mclk pin + set_port_clock(p_for_mclk_count, clk_audio_mclk); // Clock the "count" port from the clock block + start_clock(clk_audio_mclk); // Set the clock off running + + + par { + // Low level USB device layer core + XUD_Main(c_ep_out, 2, c_ep_in, 3, + c_sof, epTypeTableOut, epTypeTableIn, + null, null, -1 , + XUD_SPEED_FS, XUD_PWR_BUS); + + // Endpoint 0 core from lib_xua + // Note, since we are not using many features we pass in null for quite a few params.. + XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); + + // Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core + XUA_Buffer_lite(c_ep_out[1], c_ep_in[2], c_ep_in[1], c_sof, c_aud_ctl, p_for_mclk_count, c_audio); + + i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); + [[distribute]]AudioHub(i_i2s, c_audio, i_i2c[0], i_gpio[0]); + [[distribute]]output_gpio(i_gpio, 1, p_gpio, null); + } + } + on tile[1]:{ + par{ + i2c_master(i_i2c, 1, p_scl, p_sda, 100); + } + } + } + + return 0; +} + + diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc new file mode 100644 index 00000000..32b9e639 --- /dev/null +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -0,0 +1,44 @@ +#include "i2s.h" +#include "i2c.h" +#include "gpio.h" +#include "xua.h" + +[[distributable]] +void AudioHub(server i2s_frame_callback_if i2s, + chanend c_aud, + client i2c_master_if i2c, + client output_gpio_if dac_reset) +{ + int32_t samples[8] = {0}; // Array used for looping back samples + while (1) { + select { + case i2s.init(i2s_config_t &?i2s_config, tdm_config_t &?tdm_config): + i2s_config.mode = I2S_MODE_I2S; + i2s_config.mclk_bclk_ratio = (MCLK_48/DEFAULT_FREQ)/64; + + // Set CODECs in reset + dac_reset.output(0); + + // Allow reset to assert + delay_milliseconds(1); + + // Take CODECs out of reset + dac_reset.output(1); + + //reset_codecs(i2c); + break; + + case i2s.receive(size_t n_chans, int32_t in_samps[n_chans]): + for (int i = 0; i < n_chans; i++) samples[i] = in_samps[i]; // copy samples + break; + + case i2s.send(size_t n_chans, int32_t out_samps[n_chans]): + for (int i = 0; i < n_chans; i++) out_samps[i] = samples[i]; // copy samples + break; + + case i2s.restart_check() -> i2s_restart_t restart: + restart = I2S_NO_RESTART; // Keep on looping + break; + } + } +} diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc new file mode 100644 index 00000000..34508910 --- /dev/null +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -0,0 +1,274 @@ +#include +#include "xua_commands.h" +#include "xud.h" +#include "testct_byref.h" +#include "debug_print.h" +#include "xua_conf.h" +//#include "fifo_impl.h" //xua_conf.h must be included before hand so that we have FIFO sizes + +//Currently only single frequency supported +#define NOMINAL_SR_DEVICE DEFAULT_FREQ +#define NOMINAL_SR_HOST DEFAULT_FREQ + +#define DIV_ROUND_UP(n, d) (n / d + 1) //Always rounds up to the next integer. Needed for 48001Hz case etc. +#define BIGGEST(a, b) (a > b ? a : b) + +#define SOF_FREQ_HZ (8000 - ((2 - AUDIO_CLASS) * 7000) ) + +//Defines for endpoint buffer sizes. Samples is total number of samples across all channels +#define MAX_OUT_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_OUT) +#define MAX_IN_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_IN) +#define MAX_OUTPUT_SLOT_SIZE 4 +#define MAX_INPUT_SLOT_SIZE 4 + +#define OUT_AUDIO_BUFFER_SIZE_BYTES (MAX_OUT_SAMPLES_PER_SOF_PERIOD * MAX_OUTPUT_SLOT_SIZE) +#define IN_AUDIO_BUFFER_SIZE_BYTES (MAX_IN_SAMPLES_PER_SOF_PERIOD * MAX_INPUT_SLOT_SIZE) + +//Helper to disassemble USB packets into 32b left aligned audio samples +static inline void unpack_buff_to_samples(unsigned char input[], const unsigned n_samples, const unsigned slot_size, int output[]){ + switch(slot_size){ + case 4: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 4; + output[i] = (input[base + 3] << 24) | (input[base + 2] << 16) | (input[base + 1] << 8) | input[base + 0]; + } + break; + case 3: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 3; + output[i] = (input[base + 2] << 24) | (input[base + 1] << 16) | (input[base + 0] << 8); + } + break; + case 2: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 2; + output[i] = (input[base + 1] << 24) | (input[base + 0] << 16); + } + break; + default: + debug_printf("Invalid slot_size\n"); + break; + } +} + +//Helper to assemble USB packets from 32b left aligned audio samples +static inline void pack_samples_to_buff(int input[], const unsigned n_samples, const unsigned slot_size, unsigned char output[]){ + switch(slot_size){ + case 4: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 4; + unsigned in_word = (unsigned)input[i]; + output[base + 0] = in_word & 0xff; + output[base + 1] = (in_word & 0xff00) >> 8; + output[base + 2] = (in_word & 0xff0000) >> 16; + output[base + 3] = (in_word) >> 24; + } + break; + case 3: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 3; + unsigned in_word = (unsigned)input[i]; + output[base + 0] = (in_word & 0xff00) >> 8; + output[base + 1] = (in_word & 0xff0000) >> 16; + output[base + 2] = (in_word) >> 24; + } + break; + case 2: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 2; + unsigned in_word = (unsigned)input[i]; + output[base + 0] = (in_word & 0xff0000) >> 16; + output[base + 1] = (in_word) >> 24; + } + break; + default: + debug_printf("Invalid slot_size\n"); + break; + } +} + +//Shared memory buffers between buffer task and audio side +int asrc_to_host_sample_buffer[MAX_IN_SAMPLES_PER_SOF_PERIOD] = {0}; + +void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_aud_host){ + + debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); + + unsigned sampleFreq = DEFAULT_FREQ; + + unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; + unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; + + unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; + unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; + + unsigned in_num_chan = NUM_USB_CHAN_IN; + unsigned out_num_chan = NUM_USB_CHAN_OUT; + + unsigned tmp; + + XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); + XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); + + unsigned num_samples_received_from_host = 0; + unsigned outstanding_samples_to_host = 0; + unsigned num_samples_to_send_to_host = 0; + + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); + + // printintln(OUT_AUDIO_BUFFER_SIZE_BYTES); + // printintln(MAX_OUT_SAMPLES_PER_SOF_PERIOD); + + while(1){ + XUD_Result_t result; + unsigned length = 0; + + + select{ + //Handle control path from EP0 + case testct_byref(c_aud_ctl, tmp): + //ignore tmp as is used for reboot signalling only + unsigned cmd = inuint(c_aud_ctl); + + debug_printf("c_aud_ctl cmd: %d\n", cmd); + if(cmd == SET_SAMPLE_FREQ){ + unsigned receivedSampleFreq = inuint(c_aud_ctl); + debug_printf("SET_SAMPLE_FREQ: %d\n", receivedSampleFreq); + sampleFreq = receivedSampleFreq; + } + + else if(cmd == SET_STREAM_FORMAT_IN){ + unsigned formatChange_DataFormat = inuint(c_aud_ctl); + unsigned formatChange_NumChans = inuint(c_aud_ctl); + unsigned formatChange_SubSlot = inuint(c_aud_ctl); + unsigned formatChange_SampRes = inuint(c_aud_ctl); + debug_printf("SET_STREAM_FORMAT_IN: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); + in_subslot_size = formatChange_SubSlot; + in_num_chan = formatChange_NumChans; + } + + else if (cmd == SET_STREAM_FORMAT_OUT) + { + XUD_BusSpeed_t busSpeed; + unsigned formatChange_DataFormat = inuint(c_aud_ctl); + unsigned formatChange_NumChans = inuint(c_aud_ctl); + unsigned formatChange_SubSlot = inuint(c_aud_ctl); + unsigned formatChange_SampRes = inuint(c_aud_ctl); + debug_printf("SET_STREAM_FORMAT_OUT: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); + out_subslot_size = formatChange_SubSlot; + out_num_chan = formatChange_NumChans; + } + + else{ + debug_printf("Unhandled command\n"); + } + outct(c_aud_ctl, XS1_CT_END); + break; + + //SOF + case inuint_byref(c_sof, tmp): + unsigned mclk_port_count = 0; + asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_count) : "r" (p_for_mclk_count)); + + static unsigned sof_count=0; + sof_count++; + if (sof_count > SOF_FREQ_HZ * 10){ + debug_printf("SOF\n"); + sof_count = 0; + } + + /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) + * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. + * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. + * Average over 128 SOFs - 128 x 3072 = 0x60000. + */ +#if 0 + unsigned long long feedbackMul = 64ULL; + if(usb_speed != XUD_SPEED_HS) + feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ + + /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ + int count = (int) ((short)(u_tmp - lastClock)); + + unsigned long long full_result = count * feedbackMul * sampleFreq; + + clockcounter += full_result; + + /* Store MCLK for next time around... */ + lastClock = u_tmp; + + /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll + * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ + if(sofCount == 128) + { + sofCount = 0; + + clockcounter += mod_from_last_time; + clocks = clockcounter / masterClockFreq; + mod_from_last_time = clockcounter % masterClockFreq; + + if(usb_speed == XUD_SPEED_HS) + { + clocks <<= 3; + } + else + { + clocks <<= 6; + } + + { + int usb_speed; + asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks + + GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed); + + if (usb_speed == XUD_SPEED_HS) + { + fb_clocks[0] = clocks; + } + else + { + fb_clocks[0] = clocks >> 2; + } + } + clockcounter = 0; + } +#endif + + break; + + //Receive samples from host + case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): + num_samples_received_from_host = length / out_subslot_size; + //debug_printf("out samps: %d\n", num_samples_received_from_host); + outstanding_samples_to_host += num_samples_received_from_host; + int samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD]; + unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, samples); + + //Push into fifo for ASRC + + //else debug_printf("Push\n"); + + //Tell ASRC manager what we have just sent + outuint(c_aud_host, num_samples_received_from_host); //We assume this will not block and other side always consumes + num_samples_to_send_to_host = inuint(c_aud_host); //get number of return samples for sending back to host + + //Mark EP as ready for next frame from host + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + break; + + //Send samples to host + case XUD_SetData_Select(c_aud_in, ep_aud_in, result): + //debug_printf("sent data\n"); + + //Populate the input buffer ready for the next read + pack_samples_to_buff(asrc_to_host_sample_buffer, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); + //Use the number of samples we received last time so we are always balanced (assumes same in/out count) + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback + num_samples_to_send_to_host = 0; + break; + } + } +} \ No newline at end of file diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h new file mode 100644 index 00000000..d879e272 --- /dev/null +++ b/examples/xua_lite_example/src/xua_conf.h @@ -0,0 +1,25 @@ +// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved + +#ifndef _XUA_CONF_H_ +#define _XUA_CONF_H_ + +#define NUM_USB_CHAN_OUT 2 /* Number of channels from host to device */ +#define NUM_USB_CHAN_IN 2 /* Number of channels from device to host */ +#define I2S_CHANS_DAC 2 /* Number of I2S channels out of xCORE */ +#define I2S_CHANS_ADC 2 /* Number of I2S channels in to xCORE */ +#define MCLK_441 (512 * 44100) /* 44.1kHz family master clock frequency */ +#define MCLK_48 (512 * 48000) /* 48kHz family master clock frequency */ +#define MIN_FREQ 48000 /* Minimum sample rate */ +#define MAX_FREQ 48000 /* Maximum sample rate */ + +#define EXCLUDE_USB_AUDIO_MAIN + +#define VENDOR_STR "XMOS" +#define VENDOR_ID 0x20B1 +#define PRODUCT_STR_A2 "XUA Example" +#define PRODUCT_STR_A1 "XUA Example" +#define PID_AUDIO_1 1 +#define PID_AUDIO_2 2 +#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example */ + +#endif diff --git a/examples/xua_lite_example/src/xud_conf.h b/examples/xua_lite_example/src/xud_conf.h new file mode 100644 index 00000000..c14d64a8 --- /dev/null +++ b/examples/xua_lite_example/src/xud_conf.h @@ -0,0 +1,7 @@ +// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved + +#include "xua_conf.h" + +/* TODO */ +#define XUD_UAC_NUM_USB_CHAN_OUT NUM_USB_CHAN_OUT +#define XUD_UAC_NUM_USB_CHAN_IN NUM_USB_CHAN_IN From 161b934b8fec3660ba926f1b09cb034ffb73a454 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 26 Oct 2018 11:25:39 +0100 Subject: [PATCH 002/123] WIP + get DAC config running --- .gitignore | 1 + examples/xua_lite_example/Makefile | 4 +- examples/xua_lite_example/config.xscope | 3 + examples/xua_lite_example/src/AudioConfig.xc | 295 +++++++++--------- examples/xua_lite_example/src/app_xua_lite.xc | 9 +- examples/xua_lite_example/src/audio_hub.xc | 11 +- examples/xua_lite_example/src/xua_buffer.xc | 22 +- lib_xua/src/core/endpoint0/xua_endpoint0.c | 18 +- 8 files changed, 198 insertions(+), 165 deletions(-) create mode 100644 examples/xua_lite_example/config.xscope diff --git a/.gitignore b/.gitignore index e7e76877..3829862e 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ _build* build/ .build* *.pyc +xscope.xmt diff --git a/examples/xua_lite_example/Makefile b/examples/xua_lite_example/Makefile index c52597dd..508ee2b5 100644 --- a/examples/xua_lite_example/Makefile +++ b/examples/xua_lite_example/Makefile @@ -4,7 +4,9 @@ TARGET = RPI_HAT_60QFN.xn # The flags passed to xcc when building the application XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report \ - -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[0] + -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[0] \ + -D XUA_LITE=1 + #-DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope diff --git a/examples/xua_lite_example/config.xscope b/examples/xua_lite_example/config.xscope new file mode 100644 index 00000000..f336ddac --- /dev/null +++ b/examples/xua_lite_example/config.xscope @@ -0,0 +1,3 @@ + + + diff --git a/examples/xua_lite_example/src/AudioConfig.xc b/examples/xua_lite_example/src/AudioConfig.xc index e42a09db..5f9c92d5 100755 --- a/examples/xua_lite_example/src/AudioConfig.xc +++ b/examples/xua_lite_example/src/AudioConfig.xc @@ -3,6 +3,7 @@ #include #include #include +#include "i2c.h" @@ -51,168 +52,156 @@ // TLV320DAC3101 easy register access defines //#define DAC3101_REGWRITE(reg, val) {data[0] = val; i2c_master_write_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);} -#define DAC3101_REGWRITE(reg, val) +#define DAC3101_REGWRITE(reg, val) {i_i2c.write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);} -void AudioHwConfigure(unsigned samFreq) +void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) { - - // Take DAC out of reset. - //p_gpio <: 1; - par + // Wait for 1ms + delay_milliseconds(1); + + // Set register page to 0 + DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); + // Initiate SW reset (PLL is powered off as part of reset) + DAC3101_REGWRITE(DAC3101_SW_RST, 0x01); + + // so I've got 24MHz in to PLL, I want 24.576MHz or 22.5792MHz out. + + // I will always be using fractional-N (D != 0) so we must set R = 1 + // PLL_CLKIN/P must be between 10 and 20MHz so we must set P = 2 + + // PLL_CLK = CLKIN * ((RxJ.D)/P) + // We know R = 1, P = 2. + // PLL_CLK = CLKIN * (J.D / 2) + + // For 24.576MHz: + // J = 8 + // D = 1920 + // So PLL_CLK = 24 * (8.192/2) = 24 x 4.096 = 98.304MHz + // Then: + // NDAC = 4 + // MDAC = 4 + // DOSR = 128 + // So: + // DAC_CLK = PLL_CLK / 4 = 24.576MHz. + // DAC_MOD_CLK = DAC_CLK / 4 = 6.144MHz. + // DAC_FS = DAC_MOD_CLK / 128 = 48kHz. + + // For 22.5792MHz: + // J = 7 + // D = 5264 + // So PLL_CLK = 24 * (7.5264/2) = 24 x 3.7632 = 90.3168MHz + // Then: + // NDAC = 4 + // MDAC = 4 + // DOSR = 128 + // So: + // DAC_CLK = PLL_CLK / 4 = 22.5792MHz. + // DAC_MOD_CLK = DAC_CLK / 4 = 5.6448MHz. + // DAC_FS = DAC_MOD_CLK / 128 = 44.1kHz. + + /* Sample frequency dependent register settings */ + if ((samFreq % 11025) == 0) { - { - unsigned char data[1] = {0}; + // MCLK = 22.5792MHz (44.1,88.2,176.4kHz) + // Set PLL J Value to 7 + DAC3101_REGWRITE(DAC3101_PLL_J, 0x07); + // Set PLL D to 5264 ... (0x1490) + // Set PLL D MSB Value to 0x14 + DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x14); + // Set PLL D LSB Value to 0x90 + DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x90); - // Wait for 1ms - delay_milliseconds(1); - - // Set register page to 0 - DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); - // Initiate SW reset (PLL is powered off as part of reset) - DAC3101_REGWRITE(DAC3101_SW_RST, 0x01); - - // so I've got 24MHz in to PLL, I want 24.576MHz or 22.5792MHz out. - - // I will always be using fractional-N (D != 0) so we must set R = 1 - // PLL_CLKIN/P must be between 10 and 20MHz so we must set P = 2 - - // PLL_CLK = CLKIN * ((RxJ.D)/P) - // We know R = 1, P = 2. - // PLL_CLK = CLKIN * (J.D / 2) - - // For 24.576MHz: - // J = 8 - // D = 1920 - // So PLL_CLK = 24 * (8.192/2) = 24 x 4.096 = 98.304MHz - // Then: - // NDAC = 4 - // MDAC = 4 - // DOSR = 128 - // So: - // DAC_CLK = PLL_CLK / 4 = 24.576MHz. - // DAC_MOD_CLK = DAC_CLK / 4 = 6.144MHz. - // DAC_FS = DAC_MOD_CLK / 128 = 48kHz. - - // For 22.5792MHz: - // J = 7 - // D = 5264 - // So PLL_CLK = 24 * (7.5264/2) = 24 x 3.7632 = 90.3168MHz - // Then: - // NDAC = 4 - // MDAC = 4 - // DOSR = 128 - // So: - // DAC_CLK = PLL_CLK / 4 = 22.5792MHz. - // DAC_MOD_CLK = DAC_CLK / 4 = 5.6448MHz. - // DAC_FS = DAC_MOD_CLK / 128 = 44.1kHz. + } + else if ((samFreq % 8000) == 0) + { + // MCLK = 24.576MHz (48,96,192kHz) + // Set PLL J Value to 8 + DAC3101_REGWRITE(DAC3101_PLL_J, 0x08); + // Set PLL D to 1920 ... (0x780) + // Set PLL D MSB Value to 0x07 + DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x07); + // Set PLL D LSB Value to 0x80 + DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x80); + } + else + { + //debug_printf("Unrecognised sample freq of %d in ConfigCodec\n", samFreq); + } - /* Sample frequency dependent register settings */ - if ((samFreq % 11025) == 0) - { - // MCLK = 22.5792MHz (44.1,88.2,176.4kHz) - // Set PLL J Value to 7 - DAC3101_REGWRITE(DAC3101_PLL_J, 0x07); - // Set PLL D to 5264 ... (0x1490) - // Set PLL D MSB Value to 0x14 - DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x14); - // Set PLL D LSB Value to 0x90 - DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x90); + delay_milliseconds(1); + + // Set PLL_CLKIN = MCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) + DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x03); + + // Set PLL P and R values and power up. + DAC3101_REGWRITE(DAC3101_PLL_P_R, 0xA1); + // Set NDAC clock divider to 4 and power up. + DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x84); + // Set MDAC clock divider to 4 and power up. + DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x84); + // Set OSR clock divider to 128. + DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80); + + // Set CLKOUT Mux to DAC_CLK + DAC3101_REGWRITE(DAC3101_CLKOUT_MUX, 0x04); + // Set CLKOUT M divider to 1 and power up. + DAC3101_REGWRITE(DAC3101_CLKOUT_M_VAL, 0x81); + // Set GPIO1 output to come from CLKOUT output. + DAC3101_REGWRITE(DAC3101_GPIO1_IO, 0x10); + + // Set CODEC interface mode: I2S, 24 bit, slave mode (BCLK, WCLK both inputs). + DAC3101_REGWRITE(DAC3101_CODEC_IF, 0x20); + // Set register page to 1 + DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x01); + // Program common-mode voltage to mid scale 1.65V. + DAC3101_REGWRITE(DAC3101_HP_DRVR, 0x14); + // Program headphone-specific depop settings. + // De-pop, Power on = 800 ms, Step time = 4 ms + DAC3101_REGWRITE(DAC3101_HP_DEPOP, 0x4E); + // Program routing of DAC output to the output amplifier (headphone/lineout or speaker) + // LDAC routed to left channel mixer amp, RDAC routed to right channel mixer amp + DAC3101_REGWRITE(DAC3101_DAC_OP_MIX, 0x44); + // Unmute and set gain of output driver + // Unmute HPL, set gain = 0 db + DAC3101_REGWRITE(DAC3101_HPL_DRVR, 0x06); + // Unmute HPR, set gain = 0 dB + DAC3101_REGWRITE(DAC3101_HPR_DRVR, 0x06); + // Unmute Left Class-D, set gain = 12 dB + DAC3101_REGWRITE(DAC3101_SPKL_DRVR, 0x0C); + // Unmute Right Class-D, set gain = 12 dB + DAC3101_REGWRITE(DAC3101_SPKR_DRVR, 0x0C); + // Power up output drivers + // HPL and HPR powered up + DAC3101_REGWRITE(DAC3101_HP_DRVR, 0xD4); + // Power-up L and R Class-D drivers + DAC3101_REGWRITE(DAC3101_SPK_AMP, 0xC6); + // Enable HPL output analog volume, set = -9 dB + DAC3101_REGWRITE(DAC3101_HPL_VOL_A, 0x92); + // Enable HPR output analog volume, set = -9 dB + DAC3101_REGWRITE(DAC3101_HPR_VOL_A, 0x92); + // Enable Left Class-D output analog volume, set = -9 dB + DAC3101_REGWRITE(DAC3101_SPKL_VOL_A, 0x92); + // Enable Right Class-D output analog volume, set = -9 dB + DAC3101_REGWRITE(DAC3101_SPKR_VOL_A, 0x92); + + delay_milliseconds(100); - } - else if ((samFreq % 8000) == 0) - { - // MCLK = 24.576MHz (48,96,192kHz) - // Set PLL J Value to 8 - DAC3101_REGWRITE(DAC3101_PLL_J, 0x08); - // Set PLL D to 1920 ... (0x780) - // Set PLL D MSB Value to 0x07 - DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x07); - // Set PLL D LSB Value to 0x80 - DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x80); - } - else - { - //debug_printf("Unrecognised sample freq of %d in ConfigCodec\n", samFreq); - } + // Power up DAC + // Set register page to 0 + DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); + // Power up DAC channels and set digital gain + // Powerup DAC left and right channels (soft step enabled) + DAC3101_REGWRITE(DAC3101_DAC_DAT_PATH, 0xD4); + // DAC Left gain = 0dB + DAC3101_REGWRITE(DAC3101_DACL_VOL_D, 0x00); + // DAC Right gain = 0dB + DAC3101_REGWRITE(DAC3101_DACR_VOL_D, 0x00); + // Unmute digital volume control + // Unmute DAC left and right channels + DAC3101_REGWRITE(DAC3101_DAC_VOL, 0x00); - delay_milliseconds(1); - - // Set PLL_CLKIN = MCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) - DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x03); - - // Set PLL P and R values and power up. - DAC3101_REGWRITE(DAC3101_PLL_P_R, 0xA1); - // Set NDAC clock divider to 4 and power up. - DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x84); - // Set MDAC clock divider to 4 and power up. - DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x84); - // Set OSR clock divider to 128. - DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80); - - // Set CLKOUT Mux to DAC_CLK - DAC3101_REGWRITE(DAC3101_CLKOUT_MUX, 0x04); - // Set CLKOUT M divider to 1 and power up. - DAC3101_REGWRITE(DAC3101_CLKOUT_M_VAL, 0x81); - // Set GPIO1 output to come from CLKOUT output. - DAC3101_REGWRITE(DAC3101_GPIO1_IO, 0x10); - - // Set CODEC interface mode: I2S, 24 bit, slave mode (BCLK, WCLK both inputs). - DAC3101_REGWRITE(DAC3101_CODEC_IF, 0x20); - // Set register page to 1 - DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x01); - // Program common-mode voltage to mid scale 1.65V. - DAC3101_REGWRITE(DAC3101_HP_DRVR, 0x14); - // Program headphone-specific depop settings. - // De-pop, Power on = 800 ms, Step time = 4 ms - DAC3101_REGWRITE(DAC3101_HP_DEPOP, 0x4E); - // Program routing of DAC output to the output amplifier (headphone/lineout or speaker) - // LDAC routed to left channel mixer amp, RDAC routed to right channel mixer amp - DAC3101_REGWRITE(DAC3101_DAC_OP_MIX, 0x44); - // Unmute and set gain of output driver - // Unmute HPL, set gain = 0 db - DAC3101_REGWRITE(DAC3101_HPL_DRVR, 0x06); - // Unmute HPR, set gain = 0 dB - DAC3101_REGWRITE(DAC3101_HPR_DRVR, 0x06); - // Unmute Left Class-D, set gain = 12 dB - DAC3101_REGWRITE(DAC3101_SPKL_DRVR, 0x0C); - // Unmute Right Class-D, set gain = 12 dB - DAC3101_REGWRITE(DAC3101_SPKR_DRVR, 0x0C); - // Power up output drivers - // HPL and HPR powered up - DAC3101_REGWRITE(DAC3101_HP_DRVR, 0xD4); - // Power-up L and R Class-D drivers - DAC3101_REGWRITE(DAC3101_SPK_AMP, 0xC6); - // Enable HPL output analog volume, set = -9 dB - DAC3101_REGWRITE(DAC3101_HPL_VOL_A, 0x92); - // Enable HPR output analog volume, set = -9 dB - DAC3101_REGWRITE(DAC3101_HPR_VOL_A, 0x92); - // Enable Left Class-D output analog volume, set = -9 dB - DAC3101_REGWRITE(DAC3101_SPKL_VOL_A, 0x92); - // Enable Right Class-D output analog volume, set = -9 dB - DAC3101_REGWRITE(DAC3101_SPKR_VOL_A, 0x92); - - delay_milliseconds(100); - - // Power up DAC - // Set register page to 0 - DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); - // Power up DAC channels and set digital gain - // Powerup DAC left and right channels (soft step enabled) - DAC3101_REGWRITE(DAC3101_DAC_DAT_PATH, 0xD4); - // DAC Left gain = 0dB - DAC3101_REGWRITE(DAC3101_DACL_VOL_D, 0x00); - // DAC Right gain = 0dB - DAC3101_REGWRITE(DAC3101_DACR_VOL_D, 0x00); - // Unmute digital volume control - // Unmute DAC left and right channels - DAC3101_REGWRITE(DAC3101_DAC_VOL, 0x00); - - // Shutdown - //i_i2c[0].shutdown(); - } - } /* par */ } //These are here just to silence compiler warnings diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 8e5fea8e..3acd1bcb 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -10,6 +10,10 @@ #include "i2c.h" #include "gpio.h" +#define DEBUG_UNIT XUA_APP +#define DEBUG_PRINT_ENABLE_XUA_APP 1 +#include "debug_print.h" + // Port declarations. Note, the defines come from the xn file on tile[0]: buffered out port:32 p_i2s_dac[] = {XS1_PORT_1M}; //DAC on tile[0]: buffered in port:32 p_i2s_adc[] = {XS1_PORT_1N}; //Unused currently @@ -17,7 +21,7 @@ on tile[0]: buffered out port:32 p_lrclk = XS1_PORT_1O; //I2S Bit-clo on tile[0]: out port p_bclk = XS1_PORT_1P; //I2S L/R-clock // Master clock for the audio IO tile -on tile[0]: in port p_mclk_in = XS1_PORT_1A; +on tile[0]: in port p_mclk_in = XS1_PORT_1K; // Resources for USB feedback on tile[0]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks @@ -35,6 +39,7 @@ on tile[1]: port p_sda = XS1_PORT_1D; // Clock-block declarations clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_2; // Bit clock clock clk_audio_mclk = on tile[0]: XS1_CLKBLK_3; // Master clock +//XUD uses XS1_CLKBLK_4, XS1_CLKBLK_5 // Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also // if the endpoint wishes to be informed of USB bus resets @@ -79,7 +84,7 @@ int main() XUD_Main(c_ep_out, 2, c_ep_in, 3, c_sof, epTypeTableOut, epTypeTableIn, null, null, -1 , - XUD_SPEED_FS, XUD_PWR_BUS); + (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); // Endpoint 0 core from lib_xua // Note, since we are not using many features we pass in null for quite a few params.. diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 32b9e639..c8b53b73 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -2,11 +2,16 @@ #include "i2c.h" #include "gpio.h" #include "xua.h" +#define DEBUG_UNIT XUA_AUDIO_HUB +#define DEBUG_PRINT_ENABLE_XUA_AUDIO_HUB 1 +#include "debug_print.h" + +void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, - client i2c_master_if i2c, + client i2c_master_if i_i2c, client output_gpio_if dac_reset) { int32_t samples[8] = {0}; // Array used for looping back samples @@ -25,7 +30,8 @@ void AudioHub(server i2s_frame_callback_if i2s, // Take CODECs out of reset dac_reset.output(1); - //reset_codecs(i2c); + AudioHwConfigure(DEFAULT_FREQ, i_i2c); + debug_printf("I2S init\n"); break; case i2s.receive(size_t n_chans, int32_t in_samps[n_chans]): @@ -38,6 +44,7 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping + debug_printf("I2S restart\n"); break; } } diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index 34508910..5ae2a815 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -2,8 +2,10 @@ #include "xua_commands.h" #include "xud.h" #include "testct_byref.h" +#define DEBUG_UNIT XUA_LITE_BUFFER +#define DEBUG_PRINT_ENABLE_XUA_LITE_BUFFER 1 #include "debug_print.h" -#include "xua_conf.h" +#include "xua.h" //#include "fifo_impl.h" //xua_conf.h must be included before hand so that we have FIFO sizes //Currently only single frequency supported @@ -98,6 +100,8 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; + unsigned char buffer_feedback[4]; + unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; @@ -107,7 +111,9 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch unsigned tmp; + XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); + XUD_ep ep_feedback = XUD_InitEp(c_feedback); XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); unsigned num_samples_received_from_host = 0; @@ -116,6 +122,7 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); + XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, 4); // printintln(OUT_AUDIO_BUFFER_SIZE_BYTES); // printintln(MAX_OUT_SAMPLES_PER_SOF_PERIOD); @@ -245,19 +252,22 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch outstanding_samples_to_host += num_samples_received_from_host; int samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD]; unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, samples); - - //Push into fifo for ASRC - //else debug_printf("Push\n"); //Tell ASRC manager what we have just sent - outuint(c_aud_host, num_samples_received_from_host); //We assume this will not block and other side always consumes - num_samples_to_send_to_host = inuint(c_aud_host); //get number of return samples for sending back to host + //outuint(c_aud_host, num_samples_received_from_host); //We assume this will not block and other side always consumes + //num_samples_to_send_to_host = inuint(c_aud_host); //get number of return samples for sending back to host //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); break; + //Send feedback + case XUD_SetData_Select(c_feedback, ep_feedback, result): + debug_printf("ep_feedback\n"); + XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, 4); + break; + //Send samples to host case XUD_SetData_Select(c_aud_in, ep_aud_in, result): //debug_printf("sent data\n"); diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index b3ef87a0..c0a46545 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -297,9 +297,25 @@ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, while(1) { +#if XUA_LITE + unsigned char sbuffer[120]; + unsigned length; + + //XUD_Result_t result = XUD_GetSetupBuffer(ep0_out, sbuffer, &length); //Flattened from xud_device + XUD_Result_t result = XUD_GetSetupData(ep0_out, sbuffer, &length);//Flattened from XUD_EpFunctions.xc + + //Next step: + //void XUD_GetSetupData_Select(chan c,XUD_ep e_out, unsigned &length, XUD_Result_t &result); + + if (result == XUD_RES_OKAY) + { + /* Parse data buffer end populate SetupPacket struct */ + USB_ParseSetupPacket(sbuffer, &sp); + } +#else /* Returns XUD_RES_OKAY for success, XUD_RES_RST for bus reset */ XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, &sp); - +#endif if (result == XUD_RES_OKAY) { result = XUD_RES_ERR; From 35042e742f2a8aecce3846dc340a742ccaf6f2d8 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 26 Oct 2018 11:46:51 +0100 Subject: [PATCH 003/123] Put USB on tile[1] - builds + I2S looping --- examples/xua_lite_example/Makefile | 4 +- examples/xua_lite_example/src/AudioConfig.xc | 9 ++-- examples/xua_lite_example/src/app_xua_lite.xc | 54 ++++++++++--------- examples/xua_lite_example/src/audio_hub.xc | 22 ++++---- examples/xua_lite_example/src/xua_conf.h | 2 + 5 files changed, 46 insertions(+), 45 deletions(-) diff --git a/examples/xua_lite_example/Makefile b/examples/xua_lite_example/Makefile index 508ee2b5..11473aed 100644 --- a/examples/xua_lite_example/Makefile +++ b/examples/xua_lite_example/Makefile @@ -4,9 +4,7 @@ TARGET = RPI_HAT_60QFN.xn # The flags passed to xcc when building the application XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report \ - -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[0] \ - -D XUA_LITE=1 - + -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] #-DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope diff --git a/examples/xua_lite_example/src/AudioConfig.xc b/examples/xua_lite_example/src/AudioConfig.xc index 5f9c92d5..acf1cb9e 100755 --- a/examples/xua_lite_example/src/AudioConfig.xc +++ b/examples/xua_lite_example/src/AudioConfig.xc @@ -57,9 +57,9 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) { - - // Wait for 1ms - delay_milliseconds(1); + + // Wait for 2ms because we apply reset for 1ms from other tile + delay_milliseconds(2); // Set register page to 0 DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); @@ -201,7 +201,8 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) // Unmute digital volume control // Unmute DAC left and right channels DAC3101_REGWRITE(DAC3101_DAC_VOL, 0x00); - + + i_i2c.shutdown(); } //These are here just to silence compiler warnings diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 3acd1bcb..1e48f1c6 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -23,9 +23,6 @@ on tile[0]: out port p_bclk = XS1_PORT_1P; //I2S L/R-clo // Master clock for the audio IO tile on tile[0]: in port p_mclk_in = XS1_PORT_1K; -// Resources for USB feedback -on tile[0]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks - // [0] : DAC_RESET_N // [1] : I2C_INTERRUPT_N // [2] : MUTE_EN @@ -34,12 +31,15 @@ on tile[0]: out port p_gpio = XS1_PORT_4D; on tile[1]: port p_scl = XS1_PORT_1C; on tile[1]: port p_sda = XS1_PORT_1D; +on tile[1]: in port p_mclk_in_usb = XS1_PORT_1A; +on tile[1]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks +on tile[1]: clock clk_usb_mclk = XS1_CLKBLK_3; // Master clock // Clock-block declarations -clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_2; // Bit clock -clock clk_audio_mclk = on tile[0]: XS1_CLKBLK_3; // Master clock -//XUD uses XS1_CLKBLK_4, XS1_CLKBLK_5 +on tile[0]:clock clk_audio_bclk = XS1_CLKBLK_2; // Bit clock +on tile[0]:clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock +//XUD uses XS1_CLKBLK_4, XS1_CLKBLK_5 on tile[1] // Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also // if the endpoint wishes to be informed of USB bus resets @@ -49,7 +49,8 @@ XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_aud_host); [[distributable]] -void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, client i2c_master_if i2c, client output_gpio_if dac_reset); +void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, client i2c_master_if ?i2c, client output_gpio_if dac_reset); +void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); int main() { @@ -73,37 +74,40 @@ int main() par { on tile[0]: { - // Connect master-clock clock-block to clock-block pin - set_clock_src(clk_audio_mclk, p_mclk_in); // Clock clock-block from mclk pin - set_port_clock(p_for_mclk_count, clk_audio_mclk); // Clock the "count" port from the clock block - start_clock(clk_audio_mclk); // Set the clock off running - - par { + + i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); + [[distribute]]AudioHub(i_i2s, c_audio, null, i_gpio[0]); + [[distribute]]output_gpio(i_gpio, 1, p_gpio, null); + } + } + on tile[1]:{ + // Connect master-clock clock-block to clock-block pin + set_clock_src(clk_usb_mclk, p_mclk_in_usb); // Clock clock-block from mclk pin + set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block + start_clock(clk_usb_mclk); // Set the clock off running + + par{ + i2c_master(i_i2c, 1, p_scl, p_sda, 100); + AudioHwConfigure(DEFAULT_FREQ, i_i2c[0]); + } + + par{ // Low level USB device layer core XUD_Main(c_ep_out, 2, c_ep_in, 3, c_sof, epTypeTableOut, epTypeTableIn, null, null, -1 , (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); - + // Endpoint 0 core from lib_xua // Note, since we are not using many features we pass in null for quite a few params.. XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); // Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core XUA_Buffer_lite(c_ep_out[1], c_ep_in[2], c_ep_in[1], c_sof, c_aud_ctl, p_for_mclk_count, c_audio); - - i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); - [[distribute]]AudioHub(i_i2s, c_audio, i_i2c[0], i_gpio[0]); - [[distribute]]output_gpio(i_gpio, 1, p_gpio, null); } - } - on tile[1]:{ - par{ - i2c_master(i_i2c, 1, p_scl, p_sda, 100); - } - } - } + }//Tile[1] + }//Top level par return 0; } diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index c8b53b73..63f3f5ac 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -6,31 +6,28 @@ #define DEBUG_PRINT_ENABLE_XUA_AUDIO_HUB 1 #include "debug_print.h" -void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, - client i2c_master_if i_i2c, + client i2c_master_if ?i_i2c, client output_gpio_if dac_reset) { int32_t samples[8] = {0}; // Array used for looping back samples + + + // Set reset DAC + dac_reset.output(0); + delay_milliseconds(1); + dac_reset.output(1); + + while (1) { select { case i2s.init(i2s_config_t &?i2s_config, tdm_config_t &?tdm_config): i2s_config.mode = I2S_MODE_I2S; i2s_config.mclk_bclk_ratio = (MCLK_48/DEFAULT_FREQ)/64; - // Set CODECs in reset - dac_reset.output(0); - - // Allow reset to assert - delay_milliseconds(1); - - // Take CODECs out of reset - dac_reset.output(1); - - AudioHwConfigure(DEFAULT_FREQ, i_i2c); debug_printf("I2S init\n"); break; @@ -44,7 +41,6 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping - debug_printf("I2S restart\n"); break; } } diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h index d879e272..c0fc419d 100644 --- a/examples/xua_lite_example/src/xua_conf.h +++ b/examples/xua_lite_example/src/xua_conf.h @@ -22,4 +22,6 @@ #define PID_AUDIO_2 2 #define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example */ +#define XUA_LITE 1 + #endif From 6fbbbedc28c8b52ce2aff10096ed11d77db24d48 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 26 Oct 2018 12:20:38 +0100 Subject: [PATCH 004/123] Loopback audio working (no feedback calc yet) --- examples/xua_lite_example/Makefile | 2 +- examples/xua_lite_example/src/app_xua_lite.xc | 6 ++--- examples/xua_lite_example/src/xua_buffer.xc | 26 +++++++++---------- examples/xua_lite_example/src/xua_conf.h | 5 ++-- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/examples/xua_lite_example/Makefile b/examples/xua_lite_example/Makefile index 11473aed..0ca956bf 100644 --- a/examples/xua_lite_example/Makefile +++ b/examples/xua_lite_example/Makefile @@ -3,7 +3,7 @@ APP_NAME = TARGET = RPI_HAT_60QFN.xn # The flags passed to xcc when building the application -XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report \ +XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -Os -report \ -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] #-DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 1e48f1c6..881fffa4 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -75,7 +75,6 @@ int main() { on tile[0]: { par { - i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); [[distribute]]AudioHub(i_i2s, c_audio, null, i_gpio[0]); [[distribute]]output_gpio(i_gpio, 1, p_gpio, null); @@ -87,6 +86,7 @@ int main() set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block start_clock(clk_usb_mclk); // Set the clock off running + //Setup DAC and then return so we do not use a thread par{ i2c_master(i_i2c, 1, p_scl, p_sda, 100); AudioHwConfigure(DEFAULT_FREQ, i_i2c[0]); @@ -104,9 +104,9 @@ int main() XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); // Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core - XUA_Buffer_lite(c_ep_out[1], c_ep_in[2], c_ep_in[1], c_sof, c_aud_ctl, p_for_mclk_count, c_audio); + XUA_Buffer_lite(c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, c_aud_ctl, p_for_mclk_count, c_audio); } - }//Tile[1] + }//Tile[1] par }//Top level par return 0; diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index 5ae2a815..6830debb 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -89,10 +89,8 @@ static inline void pack_samples_to_buff(int input[], const unsigned n_samples, c } } -//Shared memory buffers between buffer task and audio side -int asrc_to_host_sample_buffer[MAX_IN_SAMPLES_PER_SOF_PERIOD] = {0}; -void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_aud_host){ +void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_audio_hub){ debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); @@ -100,7 +98,9 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; - unsigned char buffer_feedback[4]; + + #define FEEDBACK_BUFF_SIZE 4 + unsigned char buffer_feedback[FEEDBACK_BUFF_SIZE]; unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; @@ -122,11 +122,13 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); - XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, 4); + XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); // printintln(OUT_AUDIO_BUFFER_SIZE_BYTES); // printintln(MAX_OUT_SAMPLES_PER_SOF_PERIOD); + int loopback_samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD] = {0}; + while(1){ XUD_Result_t result; unsigned length = 0; @@ -250,13 +252,10 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch num_samples_received_from_host = length / out_subslot_size; //debug_printf("out samps: %d\n", num_samples_received_from_host); outstanding_samples_to_host += num_samples_received_from_host; - int samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD]; - unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, samples); + unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); - //Tell ASRC manager what we have just sent - //outuint(c_aud_host, num_samples_received_from_host); //We assume this will not block and other side always consumes - //num_samples_to_send_to_host = inuint(c_aud_host); //get number of return samples for sending back to host + num_samples_to_send_to_host = num_samples_received_from_host; //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); @@ -264,8 +263,8 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch //Send feedback case XUD_SetData_Select(c_feedback, ep_feedback, result): - debug_printf("ep_feedback\n"); - XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, 4); + //debug_printf("ep_feedback\n"); + XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); break; //Send samples to host @@ -273,8 +272,9 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch //debug_printf("sent data\n"); //Populate the input buffer ready for the next read - pack_samples_to_buff(asrc_to_host_sample_buffer, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); + pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); //Use the number of samples we received last time so we are always balanced (assumes same in/out count) + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback num_samples_to_send_to_host = 0; diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h index c0fc419d..8d7bb157 100644 --- a/examples/xua_lite_example/src/xua_conf.h +++ b/examples/xua_lite_example/src/xua_conf.h @@ -16,12 +16,13 @@ #define VENDOR_STR "XMOS" #define VENDOR_ID 0x20B1 -#define PRODUCT_STR_A2 "XUA Example" -#define PRODUCT_STR_A1 "XUA Example" +#define PRODUCT_STR_A2 "XUA Lite" +#define PRODUCT_STR_A1 "XUA Lite" #define PID_AUDIO_1 1 #define PID_AUDIO_2 2 #define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example */ +#define UAC_FORCE_FEEDBACK_EP 1 #define XUA_LITE 1 #endif From 1db927601a0c112ba2f46bb7bdd7afa58486c957 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 26 Oct 2018 13:39:02 +0100 Subject: [PATCH 005/123] Basic feedback endpoint working for class 2 --- examples/xua_lite_example/src/xua_buffer.xc | 54 ++++++++++++--------- lib_xua/src/core/endpoint0/xua_endpoint0.c | 10 ++-- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index 6830debb..984298b2 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -101,6 +101,7 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch #define FEEDBACK_BUFF_SIZE 4 unsigned char buffer_feedback[FEEDBACK_BUFF_SIZE]; + unsigned int fb_clocks[1] = {0}; unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; @@ -111,6 +112,12 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch unsigned tmp; + unsigned lastClock = 0; + unsigned clocks = 0; + long long clockcounter = 0; + unsigned sof_count=0; + unsigned mod_from_last_time = 0; + XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); XUD_ep ep_feedback = XUD_InitEp(c_feedback); @@ -180,44 +187,38 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch unsigned mclk_port_count = 0; asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_count) : "r" (p_for_mclk_count)); - static unsigned sof_count=0; - sof_count++; - if (sof_count > SOF_FREQ_HZ * 10){ - debug_printf("SOF\n"); - sof_count = 0; - } - /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. * Average over 128 SOFs - 128 x 3072 = 0x60000. */ -#if 0 + unsigned long long feedbackMul = 64ULL; - if(usb_speed != XUD_SPEED_HS) + if(AUDIO_CLASS == 1) feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ - int count = (int) ((short)(u_tmp - lastClock)); + int count = (int) ((short)(mclk_port_count - lastClock)); - unsigned long long full_result = count * feedbackMul * sampleFreq; + unsigned long long full_result = count * feedbackMul * DEFAULT_FREQ; clockcounter += full_result; /* Store MCLK for next time around... */ - lastClock = u_tmp; + lastClock = mclk_port_count; /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ - if(sofCount == 128) + if(sof_count == 128) { - sofCount = 0; + debug_printf("fb\n"); + sof_count = 0; clockcounter += mod_from_last_time; - clocks = clockcounter / masterClockFreq; - mod_from_last_time = clockcounter % masterClockFreq; + clocks = clockcounter / MCLK_48; + mod_from_last_time = clockcounter % MCLK_48; - if(usb_speed == XUD_SPEED_HS) + if(AUDIO_CLASS == 2) { clocks <<= 3; } @@ -230,9 +231,8 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch int usb_speed; asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks - GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed); - if (usb_speed == XUD_SPEED_HS) + if (AUDIO_CLASS == 2) { fb_clocks[0] = clocks; } @@ -241,10 +241,9 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch fb_clocks[0] = clocks >> 2; } } - clockcounter = 0; + clockcounter = 0; } -#endif - + sof_count++; break; //Receive samples from host @@ -264,7 +263,16 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch //Send feedback case XUD_SetData_Select(c_feedback, ep_feedback, result): //debug_printf("ep_feedback\n"); - XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); + //XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); + if (AUDIO_CLASS == 2) + { + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 4); + } + else + { + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 3); + } + break; //Send samples to host diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index c0a46545..eef8323e 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -299,13 +299,15 @@ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, { #if XUA_LITE unsigned char sbuffer[120]; - unsigned length; + unsigned length = 0; + XUD_Result_t result = XUD_RES_ERR; //XUD_Result_t result = XUD_GetSetupBuffer(ep0_out, sbuffer, &length); //Flattened from xud_device - XUD_Result_t result = XUD_GetSetupData(ep0_out, sbuffer, &length);//Flattened from XUD_EpFunctions.xc + result = XUD_GetSetupData(ep0_out, sbuffer, &length);//Flattened from XUD_EpFunctions.xc - //Next step: - //void XUD_GetSetupData_Select(chan c,XUD_ep e_out, unsigned &length, XUD_Result_t &result); + // select{ + // case XUD_GetSetupData_Select(c_ep0_out, ep0_out, &length, &result): + // break; if (result == XUD_RES_OKAY) { From 2405b2f4f1099c4f858138bcd64c5abdcf9b0ae0 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 26 Oct 2018 14:16:17 +0100 Subject: [PATCH 006/123] Basic hook up of audio to buffer (without FIFO) - output audible! --- examples/xua_lite_example/Makefile | 2 -- examples/xua_lite_example/src/app_xua_lite.xc | 6 ++-- examples/xua_lite_example/src/audio_hub.xc | 20 ++++++------ examples/xua_lite_example/src/xua_buffer.xc | 32 ++++++++++++------- examples/xua_lite_example/src/xua_conf.h | 17 +++++----- 5 files changed, 44 insertions(+), 33 deletions(-) diff --git a/examples/xua_lite_example/Makefile b/examples/xua_lite_example/Makefile index 0ca956bf..7118438e 100644 --- a/examples/xua_lite_example/Makefile +++ b/examples/xua_lite_example/Makefile @@ -6,8 +6,6 @@ TARGET = RPI_HAT_60QFN.xn XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -Os -report \ -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] -#-DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope - # The USED_MODULES variable lists other module used by the application. These # modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables. # Modules are expected to be in the directory above the BASE_DIR directory. diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 881fffa4..d1be770d 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -1,11 +1,13 @@ // Copyright (c) 2017-2018, XMOS Ltd, All rights reserved // A very simple *example* of a USB audio application (and as such is un-verified for production) +#include #include #include #include "xua.h" +#include "xud.h" #include "i2s.h" #include "i2c.h" #include "gpio.h" @@ -15,8 +17,8 @@ #include "debug_print.h" // Port declarations. Note, the defines come from the xn file -on tile[0]: buffered out port:32 p_i2s_dac[] = {XS1_PORT_1M}; //DAC -on tile[0]: buffered in port:32 p_i2s_adc[] = {XS1_PORT_1N}; //Unused currently +on tile[0]: buffered out port:32 p_i2s_dac[] = {XS1_PORT_1N}; //DAC +on tile[0]: buffered in port:32 p_i2s_adc[] = {XS1_PORT_1F}; //Unused currently on tile[0]: buffered out port:32 p_lrclk = XS1_PORT_1O; //I2S Bit-clock on tile[0]: out port p_bclk = XS1_PORT_1P; //I2S L/R-clock diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 63f3f5ac..c23f5385 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -9,12 +9,12 @@ [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, - chanend c_aud, + chanend c_audio_hub, client i2c_master_if ?i_i2c, client output_gpio_if dac_reset) { - int32_t samples[8] = {0}; // Array used for looping back samples - + int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; + int32_t samples_in[NUM_USB_CHAN_IN] = {0}; // Set reset DAC dac_reset.output(0); @@ -29,19 +29,21 @@ void AudioHub(server i2s_frame_callback_if i2s, i2s_config.mclk_bclk_ratio = (MCLK_48/DEFAULT_FREQ)/64; debug_printf("I2S init\n"); - break; + break; case i2s.receive(size_t n_chans, int32_t in_samps[n_chans]): - for (int i = 0; i < n_chans; i++) samples[i] = in_samps[i]; // copy samples - break; + for (int i = 0; i < n_chans; i++) samples_in[i] = in_samps[i]; + break; case i2s.send(size_t n_chans, int32_t out_samps[n_chans]): - for (int i = 0; i < n_chans; i++) out_samps[i] = samples[i]; // copy samples - break; + for (int i = 0; i < n_chans; i++) out_samps[i] = samples_out[i]; + break; case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping - break; + for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio_hub <: samples_in[i]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub :> samples_out[i]; + break; } } } diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index 984298b2..ac363331 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -1,4 +1,7 @@ +#include + #include + #include "xua_commands.h" #include "xud.h" #include "testct_byref.h" @@ -135,6 +138,8 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch // printintln(MAX_OUT_SAMPLES_PER_SOF_PERIOD); int loopback_samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD] = {0}; + int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; + int32_t samples_in[NUM_USB_CHAN_IN] = {0}; while(1){ XUD_Result_t result; @@ -218,6 +223,7 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch clocks = clockcounter / MCLK_48; mod_from_last_time = clockcounter % MCLK_48; + //Scale for working out number of samps to take from device for input if(AUDIO_CLASS == 2) { clocks <<= 3; @@ -226,20 +232,16 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch { clocks <<= 6; } + asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks + //Write to feedback EP buffer + if (AUDIO_CLASS == 2) { - int usb_speed; - asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks - - - if (AUDIO_CLASS == 2) - { - fb_clocks[0] = clocks; - } - else - { - fb_clocks[0] = clocks >> 2; - } + fb_clocks[0] = clocks; + } + else + { + fb_clocks[0] = clocks >> 2; } clockcounter = 0; } @@ -287,6 +289,12 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback num_samples_to_send_to_host = 0; break; + + case c_audio_hub :> samples_in[0]: + for (int i = 1; i < NUM_USB_CHAN_IN; i++) c_audio_hub :> samples_in[i]; + // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: loopback_samples[i]; + break; } } } \ No newline at end of file diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h index 8d7bb157..668b4cd4 100644 --- a/examples/xua_lite_example/src/xua_conf.h +++ b/examples/xua_lite_example/src/xua_conf.h @@ -14,15 +14,16 @@ #define EXCLUDE_USB_AUDIO_MAIN -#define VENDOR_STR "XMOS" -#define VENDOR_ID 0x20B1 -#define PRODUCT_STR_A2 "XUA Lite" -#define PRODUCT_STR_A1 "XUA Lite" -#define PID_AUDIO_1 1 -#define PID_AUDIO_2 2 -#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example */ +#define VENDOR_STR "XMOS" +#define VENDOR_ID 0x20B1 +#define PRODUCT_STR_A2 "XUA Lite Class 2" +#define PRODUCT_STR_A1 "XUA Lite Class 1" +#define PID_AUDIO_1 1 +#define PID_AUDIO_2 2 +#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example) */ #define UAC_FORCE_FEEDBACK_EP 1 -#define XUA_LITE 1 +#define XUA_LITE 1 // Use simple/optimised USB buffer tasks +#define AUDIO_CLASS 2 #endif From 78f9e890d62cf591489ab448b37cdb51bd49053e Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 26 Oct 2018 16:24:50 +0100 Subject: [PATCH 007/123] Output FIFO - sounds great! --- examples/xua_lite_example/src/fifo_impl.h | 72 ++++++ examples/xua_lite_example/src/fifo_types.h | 30 +++ examples/xua_lite_example/src/xua_buffer.xc | 272 ++++++++++---------- 3 files changed, 243 insertions(+), 131 deletions(-) create mode 100644 examples/xua_lite_example/src/fifo_impl.h create mode 100644 examples/xua_lite_example/src/fifo_types.h diff --git a/examples/xua_lite_example/src/fifo_impl.h b/examples/xua_lite_example/src/fifo_impl.h new file mode 100644 index 00000000..315b199f --- /dev/null +++ b/examples/xua_lite_example/src/fifo_impl.h @@ -0,0 +1,72 @@ +#ifndef __FIFO__ +#define __FIFO__ +#include //memcpy +#include "fifo_types.h" + +//Asynch FIFO implementaion +//Note these are in the include file to allow the compiler to inline for performance + +/////////////////////////////////////// +//Shared memory FIFO (sample by sample) +//Can be any size +/////////////////////////////////////// + + +static inline unsigned fifo_get_fill(volatile mem_fifo_t * unsafe fifo) { + unsafe{ + unsigned fifo_fill = 0; + if (fifo->write_idx >= fifo->read_idx){ + fifo_fill = fifo->write_idx - fifo->read_idx; + } + else{ + fifo_fill = (fifo->size + fifo->write_idx) - fifo->read_idx; + } + return fifo_fill; + } +} + +#pragma unsafe arrays +static inline fifo_ret_t fifo_block_push(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { + unsafe{ + //check there is a block of space large enough + unsigned space_remaining = fifo->size - fifo_get_fill(fifo) - 1; + if (n > space_remaining) { + return FIFO_FULL; + } + for (int i = 0; i < n; i++){ + unsigned next_idx = fifo->write_idx + 1; + if (next_idx == fifo->size) next_idx = 0; //Check for wrap + fifo->data_base_ptr[fifo->write_idx] = data[i]; + fifo->write_idx = next_idx; + } + return FIFO_SUCCESS; + } +} + +#pragma unsafe arrays +static inline fifo_ret_t fifo_block_pop(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { + unsafe{ + //Check we have a block big enough to send + if (n > fifo_get_fill(fifo)){ + return FIFO_EMPTY; + } + for (int i = 0; i < n; i++){ + data[i] = fifo->data_base_ptr[fifo->read_idx]; + fifo->read_idx++; + if (fifo->read_idx == fifo->size) fifo->read_idx = 0; //Check for wrap + } + return FIFO_SUCCESS; + } +} + + +//Version of above that returns fill level relative to half full +static inline int fifo_get_fill_relative_half(volatile mem_fifo_t * unsafe fifo){ + unsafe{ + int fifo_fill = (int)fifo_get_fill(fifo); + fifo_fill -= (fifo->size / 2); + return fifo_fill; + } +} + +#endif \ No newline at end of file diff --git a/examples/xua_lite_example/src/fifo_types.h b/examples/xua_lite_example/src/fifo_types.h new file mode 100644 index 00000000..159a95ae --- /dev/null +++ b/examples/xua_lite_example/src/fifo_types.h @@ -0,0 +1,30 @@ +#ifndef __ASRC_FIFO_TYPES__ +#define __ASRC_FIFO_TYPES__ +#include + +//Shared FIFO return types +typedef enum fifo_ret_t { + FIFO_SUCCESS = 0, + FIFO_FULL, + FIFO_EMPTY +} fifo_ret_t; + +///////////////////////////////////////////////////////////////////////// +//Shared memory FIFO (sample by sample or block) +//Can be any size +// +//Note that the actual storage for the FIFO is declared externally +//and a reference to the base address of the storage is passed in along +//with the size of the storage. This way, multiple instances may be +//different sizes. +// +///////////////////////////////////////////////////////////////////////// + +typedef struct mem_fifo_t { + const unsigned size; //Size in INTs + int * const unsafe data_base_ptr; //Base of the data array - declared externally so we can have differnt sized FIFOs + unsigned write_idx; + unsigned read_idx; +} mem_fifo_t; + +#endif \ No newline at end of file diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index ac363331..3d4a17fd 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -9,7 +9,7 @@ #define DEBUG_PRINT_ENABLE_XUA_LITE_BUFFER 1 #include "debug_print.h" #include "xua.h" -//#include "fifo_impl.h" //xua_conf.h must be included before hand so that we have FIFO sizes +#include "fifo_impl.h" //Currently only single frequency supported #define NOMINAL_SR_DEVICE DEFAULT_FREQ @@ -93,7 +93,7 @@ static inline void pack_samples_to_buff(int input[], const unsigned n_samples, c } -void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_audio_hub){ +void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_audio_hub) { debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); @@ -134,167 +134,177 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); - // printintln(OUT_AUDIO_BUFFER_SIZE_BYTES); - // printintln(MAX_OUT_SAMPLES_PER_SOF_PERIOD); - int loopback_samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD] = {0}; int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; - while(1){ + unsafe{ + + int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; + mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]) + , host_to_device_fifo_storage, 0, 0}; + volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + XUD_Result_t result; unsigned length = 0; + while(1){ + select{ + //Handle control path from EP0 + case testct_byref(c_aud_ctl, tmp): + //ignore tmp as is used for reboot signalling only + unsigned cmd = inuint(c_aud_ctl); + + debug_printf("c_aud_ctl cmd: %d\n", cmd); + if(cmd == SET_SAMPLE_FREQ){ + unsigned receivedSampleFreq = inuint(c_aud_ctl); + debug_printf("SET_SAMPLE_FREQ: %d\n", receivedSampleFreq); + sampleFreq = receivedSampleFreq; + } - select{ - //Handle control path from EP0 - case testct_byref(c_aud_ctl, tmp): - //ignore tmp as is used for reboot signalling only - unsigned cmd = inuint(c_aud_ctl); - - debug_printf("c_aud_ctl cmd: %d\n", cmd); - if(cmd == SET_SAMPLE_FREQ){ - unsigned receivedSampleFreq = inuint(c_aud_ctl); - debug_printf("SET_SAMPLE_FREQ: %d\n", receivedSampleFreq); - sampleFreq = receivedSampleFreq; - } - - else if(cmd == SET_STREAM_FORMAT_IN){ - unsigned formatChange_DataFormat = inuint(c_aud_ctl); - unsigned formatChange_NumChans = inuint(c_aud_ctl); - unsigned formatChange_SubSlot = inuint(c_aud_ctl); - unsigned formatChange_SampRes = inuint(c_aud_ctl); - debug_printf("SET_STREAM_FORMAT_IN: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); - in_subslot_size = formatChange_SubSlot; - in_num_chan = formatChange_NumChans; - } - - else if (cmd == SET_STREAM_FORMAT_OUT) - { - XUD_BusSpeed_t busSpeed; + else if(cmd == SET_STREAM_FORMAT_IN){ unsigned formatChange_DataFormat = inuint(c_aud_ctl); unsigned formatChange_NumChans = inuint(c_aud_ctl); unsigned formatChange_SubSlot = inuint(c_aud_ctl); unsigned formatChange_SampRes = inuint(c_aud_ctl); - debug_printf("SET_STREAM_FORMAT_OUT: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); - out_subslot_size = formatChange_SubSlot; - out_num_chan = formatChange_NumChans; - } + debug_printf("SET_STREAM_FORMAT_IN: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); + in_subslot_size = formatChange_SubSlot; + in_num_chan = formatChange_NumChans; + } - else{ - debug_printf("Unhandled command\n"); - } - outct(c_aud_ctl, XS1_CT_END); - break; + else if (cmd == SET_STREAM_FORMAT_OUT) + { + XUD_BusSpeed_t busSpeed; + unsigned formatChange_DataFormat = inuint(c_aud_ctl); + unsigned formatChange_NumChans = inuint(c_aud_ctl); + unsigned formatChange_SubSlot = inuint(c_aud_ctl); + unsigned formatChange_SampRes = inuint(c_aud_ctl); + debug_printf("SET_STREAM_FORMAT_OUT: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); + out_subslot_size = formatChange_SubSlot; + out_num_chan = formatChange_NumChans; + } - //SOF - case inuint_byref(c_sof, tmp): - unsigned mclk_port_count = 0; - asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_count) : "r" (p_for_mclk_count)); + else{ + debug_printf("Unhandled command\n"); + } + outct(c_aud_ctl, XS1_CT_END); + break; - /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) - * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. - * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. - * Average over 128 SOFs - 128 x 3072 = 0x60000. - */ + //SOF + case inuint_byref(c_sof, tmp): + unsigned mclk_port_count = 0; + asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_count) : "r" (p_for_mclk_count)); - unsigned long long feedbackMul = 64ULL; - if(AUDIO_CLASS == 1) - feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ + /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) + * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. + * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. + * Average over 128 SOFs - 128 x 3072 = 0x60000. + */ - /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ - int count = (int) ((short)(mclk_port_count - lastClock)); + unsigned long long feedbackMul = 64ULL; + if(AUDIO_CLASS == 1) + feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ - unsigned long long full_result = count * feedbackMul * DEFAULT_FREQ; + /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ + int count = (int) ((short)(mclk_port_count - lastClock)); - clockcounter += full_result; + unsigned long long full_result = count * feedbackMul * DEFAULT_FREQ; - /* Store MCLK for next time around... */ - lastClock = mclk_port_count; + clockcounter += full_result; - /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll - * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ - if(sof_count == 128) - { - debug_printf("fb\n"); - sof_count = 0; + /* Store MCLK for next time around... */ + lastClock = mclk_port_count; - clockcounter += mod_from_last_time; - clocks = clockcounter / MCLK_48; - mod_from_last_time = clockcounter % MCLK_48; + /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll + * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ + if(sof_count == 128) + { + //debug_printf("fb\n"); + sof_count = 0; - //Scale for working out number of samps to take from device for input - if(AUDIO_CLASS == 2) - { - clocks <<= 3; - } - else - { - clocks <<= 6; - } - asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks + clockcounter += mod_from_last_time; + clocks = clockcounter / MCLK_48; + mod_from_last_time = clockcounter % MCLK_48; - //Write to feedback EP buffer - if (AUDIO_CLASS == 2) - { - fb_clocks[0] = clocks; - } - else - { - fb_clocks[0] = clocks >> 2; - } - clockcounter = 0; - } - sof_count++; - break; + //Scale for working out number of samps to take from device for input + if(AUDIO_CLASS == 2) + { + clocks <<= 3; + } + else + { + clocks <<= 6; + } + asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks - //Receive samples from host - case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): - num_samples_received_from_host = length / out_subslot_size; - //debug_printf("out samps: %d\n", num_samples_received_from_host); - outstanding_samples_to_host += num_samples_received_from_host; + //Write to feedback EP buffer + if (AUDIO_CLASS == 2) + { + fb_clocks[0] = clocks; + } + else + { + fb_clocks[0] = clocks >> 2; + } + clockcounter = 0; + } + sof_count++; + break; - unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); + //Receive samples from host + case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): + num_samples_received_from_host = length / out_subslot_size; + //debug_printf("out samps: %d\n", num_samples_received_from_host); + outstanding_samples_to_host += num_samples_received_from_host; - num_samples_to_send_to_host = num_samples_received_from_host; - - //Mark EP as ready for next frame from host - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); - break; + unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); - //Send feedback - case XUD_SetData_Select(c_feedback, ep_feedback, result): - //debug_printf("ep_feedback\n"); - //XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); - if (AUDIO_CLASS == 2) - { - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 4); - } - else - { - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 3); - } + fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); + if (ret != FIFO_SUCCESS) debug_printf("full\n"); - break; + num_samples_to_send_to_host = num_samples_received_from_host; + + //Mark EP as ready for next frame from host + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + break; - //Send samples to host - case XUD_SetData_Select(c_aud_in, ep_aud_in, result): - //debug_printf("sent data\n"); + //Send feedback + case XUD_SetData_Select(c_feedback, ep_feedback, result): + //debug_printf("ep_feedback\n"); + //XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); + if (AUDIO_CLASS == 2) + { + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 4); + } + else + { + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 3); + } - //Populate the input buffer ready for the next read - pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); - //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - - unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback - num_samples_to_send_to_host = 0; - break; + break; - case c_audio_hub :> samples_in[0]: - for (int i = 1; i < NUM_USB_CHAN_IN; i++) c_audio_hub :> samples_in[i]; - // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: loopback_samples[i]; - break; + //Send samples to host + case XUD_SetData_Select(c_aud_in, ep_aud_in, result): + //debug_printf("sent data\n"); + + //Populate the input buffer ready for the next read + pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); + //Use the number of samples we received last time so we are always balanced (assumes same in/out count) + + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback + num_samples_to_send_to_host = 0; + break; + + case c_audio_hub :> samples_in[0]: + for (int i = 1; i < NUM_USB_CHAN_IN; i++) c_audio_hub :> samples_in[i]; + // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; + int out_samps[NUM_USB_CHAN_OUT]; + fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, out_samps, NUM_USB_CHAN_OUT); + if (ret != FIFO_SUCCESS) debug_printf("empty\n"); + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: out_samps[i]; + break; + } } } } \ No newline at end of file From 35b43c07621e120590fb39db05f1ae707296f831 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Sun, 28 Oct 2018 08:29:39 +0000 Subject: [PATCH 008/123] Use select for EP0 handling + split ep0 into init and loop --- examples/xua_lite_example/src/app_xua_lite.xc | 5 +- examples/xua_lite_example/src/xua_buffer.xc | 2 +- lib_xua/src/core/endpoint0/xua_endpoint0.c | 1026 +++++++++-------- lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc | 55 + 4 files changed, 581 insertions(+), 507 deletions(-) create mode 100644 lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index d1be770d..934666aa 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -53,6 +53,8 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, client i2c_master_if ?i2c, client output_gpio_if dac_reset); void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); +void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); int main() { @@ -103,7 +105,8 @@ int main() // Endpoint 0 core from lib_xua // Note, since we are not using many features we pass in null for quite a few params.. - XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); + // XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); + XUA_Endpoint0_select(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); // Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core XUA_Buffer_lite(c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, c_aud_ctl, p_for_mclk_count, c_audio); diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index 3d4a17fd..b6750a84 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -301,7 +301,7 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; int out_samps[NUM_USB_CHAN_OUT]; fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, out_samps, NUM_USB_CHAN_OUT); - if (ret != FIFO_SUCCESS) debug_printf("empty\n"); + //if (ret != FIFO_SUCCESS) debug_printf("empty\n"); for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: out_samps[i]; break; } diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index eef8323e..3bb36f55 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -200,13 +200,14 @@ const unsigned g_chanCount_In_HS[INPUT_FORMAT_COUNT] = {HS_STREAM_FORMAT_I #endif }; -/* Endpoint 0 function. Handles all requests to the device */ -void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, +XUD_ep ep0_out; +XUD_ep ep0_in; + +void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { - USB_SetupPacket_t sp; - XUD_ep ep0_out = XUD_InitEp(c_ep0_out); - XUD_ep ep0_in = XUD_InitEp(c_ep0_in); + ep0_out = XUD_InitEp(c_ep0_out); + ep0_in = XUD_InitEp(c_ep0_in); #if 0 /* Dont need to init globals.. */ @@ -295,6 +296,520 @@ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, } #endif +} + +void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) +{ + if (result == XUD_RES_OKAY) + { + result = XUD_RES_ERR; + + /* Inspect Request type and Receipient and direction */ + switch( (sp.bmRequestType.Direction << 7) | (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) ) + { + case USB_BMREQ_H2D_STANDARD_INT: + + /* Over-riding USB_StandardRequests implementation */ + if(sp.bRequest == USB_SET_INTERFACE) + { + switch (sp.wIndex) + { + /* Check for audio stream from host start/stop */ +#if (NUM_USB_CHAN_OUT > 0) && (AUDIO_CLASS == 2) + case INTERFACE_NUMBER_AUDIO_OUTPUT: + /* Check the alt is in range */ + if(sp.wValue <= OUTPUT_FORMAT_COUNT) + { + /* Alt 0 is stream stop */ + /* Only send change if we need to */ + if((sp.wValue > 0) && (g_curStreamAlt_Out != sp.wValue)) + { + g_curStreamAlt_Out = sp.wValue; + + /* Send format of data onto buffering */ + outuint(c_audioControl, SET_STREAM_FORMAT_OUT); + outuint(c_audioControl, g_dataFormat_Out[sp.wValue-1]); /* Data format (PCM/DSD) */ + + if(g_curUsbSpeed == XUD_SPEED_HS) + { + outuint(c_audioControl, NUM_USB_CHAN_OUT); /* Channel count */ + outuint(c_audioControl, g_subSlot_Out_HS[sp.wValue-1]); /* Subslot */ + outuint(c_audioControl, g_sampRes_Out_HS[sp.wValue-1]); /* Resolution */ + } + else + { + outuint(c_audioControl, NUM_USB_CHAN_OUT_FS); /* Channel count */ + outuint(c_audioControl, g_subSlot_Out_FS[sp.wValue-1]); /* Subslot */ + outuint(c_audioControl, g_sampRes_Out_FS[sp.wValue-1]); /* Resolution */ + } + + /* Handshake */ + chkct(c_audioControl, XS1_CT_END); + } + } + break; +#endif + +#if (NUM_USB_CHAN_IN > 0) && (AUDIO_CLASS == 2) + case INTERFACE_NUMBER_AUDIO_INPUT: + /* Check the alt is in range */ + if(sp.wValue <= INPUT_FORMAT_COUNT) + { + /* Alt 0 is stream stop */ + /* Only send change if we need to */ + if((sp.wValue > 0) && (g_curStreamAlt_In != sp.wValue)) + { + g_curStreamAlt_In = sp.wValue; + + /* Send format of data onto buffering */ + outuint(c_audioControl, SET_STREAM_FORMAT_IN); + outuint(c_audioControl, g_dataFormat_In[sp.wValue-1]); /* Data format (PCM/DSD) */ + + if(g_curUsbSpeed == XUD_SPEED_HS) + { + outuint(c_audioControl, g_chanCount_In_HS[sp.wValue-1]); /* Channel count */ + outuint(c_audioControl, g_subSlot_In_HS[sp.wValue-1]); /* Subslot */ + outuint(c_audioControl, g_sampRes_In_HS[sp.wValue-1]); /* Resolution */ + } + else + { + outuint(c_audioControl, NUM_USB_CHAN_IN_FS); /* Channel count */ + outuint(c_audioControl, g_subSlot_In_FS[sp.wValue-1]); /* Subslot */ + outuint(c_audioControl, g_sampRes_In_FS[sp.wValue-1]); /* Resolution */ + } + + /* Wait for handshake */ + chkct(c_audioControl, XS1_CT_END); + } + } + break; +#endif + +#ifdef IAP_EA_NATIVE_TRANS + case INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS: + /* Check the alt is in range */ + if (sp.wValue <= IAP_EA_NATIVE_TRANS_ALT_COUNT) + { + /* Reset all state of endpoints associated with this interface + * when changing an alternative setting. See USB 2.0 Spec 9.1.1.5 */ + XUD_ResetEpStateByAddr(ENDPOINT_ADDRESS_IN_IAP_EA_NATIVE_TRANS); + XUD_ResetEpStateByAddr(ENDPOINT_ADDRESS_OUT_IAP_EA_NATIVE_TRANS); + + /* Send selected Alt interface number onto EA Native EP manager */ + outuint(c_EANativeTransport_ctrl, (unsigned)sp.wValue); + + /* Wait for handshake */ + chkct(c_EANativeTransport_ctrl, XS1_CT_END); + } + break; +#endif + default: + /* Unhandled interface */ + break; + } + +#if (NUM_USB_CHAN_OUT > 0) && (NUM_USB_CHAN_IN > 0) + if ((sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) || (sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT)) + { + /* Check for stream start stop on output and input audio interfaces */ + if(sp.wValue && !g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT] && !g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]) + { + /* If start and input AND output not currently running */ + UserAudioStreamStart(); + } + else if(((sp.wIndex == 1) && (!sp.wValue)) && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT] && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT])) + { + /* if output stop and output running and input not running */ + UserAudioStreamStop(); + } + else if(((sp.wIndex == 2) && (!sp.wValue)) && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT] && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT])) + { + /* if input stop and input running and output not running */ + UserAudioStreamStop(); + } + } +#elif (NUM_USB_CHAN_OUT > 0) + if(sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) + { + if(sp.wValue && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT])) + { + /* if start and not currently running */ + UserAudioStreamStart(); + } + else if (!sp.wValue && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT]) + { + /* if stop and currently running */ + UserAudioStreamStop(); + } + } +#elif (NUM_USB_CHAN_IN > 0) + if(sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT) + { + if(sp.wValue && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT])) + { + /* if start and not currently running */ + UserAudioStreamStart(); + } + else if (!sp.wValue && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]) + { + /* if stop and currently running */ + UserAudioStreamStop(); + } + } +#endif + } /* if(sp.bRequest == SET_INTERFACE) */ + + break; /* BMREQ_H2D_STANDARD_INT */ + + case USB_BMREQ_D2H_STANDARD_INT: + + switch(sp.bRequest) + { +#ifdef HID_CONTROLS + case USB_GET_DESCRIPTOR: + + /* Check what inteface request is for */ + if(sp.wIndex == INTERFACE_NUMBER_HID) + { + /* High byte of wValue is descriptor type */ + unsigned descriptorType = sp.wValue & 0xff00; + + switch (descriptorType) + { + case HID_HID: + /* Return HID Descriptor */ + result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, + sizeof(hidDescriptor), sp.wLength); + break; + case HID_REPORT: + /* Return HID report descriptor */ + result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptor, + sizeof(hidReportDescriptor), sp.wLength); + break; + } + } + break; +#endif + default: + break; + } + break; + + /* Recipient: Device */ + case USB_BMREQ_H2D_STANDARD_DEV: + + /* Inspect for actual request */ + switch( sp.bRequest ) + { + /* Standard request: SetConfiguration */ + /* Overriding implementation in USB_StandardRequests */ + case USB_SET_CONFIGURATION: + + //if(g_current_config == 1) + { + /* Consider host active with valid driver at this point */ + UserHostActive(1); + } + + /* We want to run USB_StandardsRequests() implementation also. Don't modify result + * and don't call XUD_DoSetRequestStatus() */ + break; + + default: + //Unknown device request" + break; + } + break; + + /* Audio Class 1.0 Sampling Freqency Requests go to Endpoint */ + case USB_BMREQ_H2D_CLASS_EP: + case USB_BMREQ_D2H_CLASS_EP: + { + unsigned epNum = sp.wIndex & 0xff; + + if ((epNum == ENDPOINT_ADDRESS_OUT_AUDIO) || (epNum == ENDPOINT_ADDRESS_IN_AUDIO)) + { +#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) + if(g_curUsbSpeed == XUD_SPEED_FS) + { + result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } +#elif (AUDIO_CLASS==1) + result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#endif + } + + } + break; + + case USB_BMREQ_H2D_CLASS_INT: + case USB_BMREQ_D2H_CLASS_INT: + { + unsigned interfaceNum = sp.wIndex & 0xff; + //unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5); + + /* TODO Check on return value retval = */ +#if (XUA_DFU_EN == 1) + unsigned DFU_IF = INTERFACE_NUMBER_DFU; + + /* DFU interface number changes based on which mode we are currently running in */ + if (DFU_mode_active) + { + DFU_IF = 0; + } + + if (interfaceNum == DFU_IF) + { + int reset = 0; + + /* If running in application mode stop audio */ + /* Don't interupt audio for save and restore cmds */ + if ((DFU_IF == INTERFACE_NUMBER_DFU) && (sp.bRequest != XMOS_DFU_SAVESTATE) && + (sp.bRequest != XMOS_DFU_RESTORESTATE)) + { + // Stop audio + outuint(c_audioControl, SET_SAMPLE_FREQ); + outuint(c_audioControl, AUDIO_STOP_FOR_DFU); + // Handshake + chkct(c_audioControl, XS1_CT_END); + } + + /* This will return 1 if reset requested */ + result = DFUDeviceRequests(ep0_out, &ep0_in, &sp, null, g_interfaceAlt[sp.wIndex], dfuInterface, &reset); + + if(reset) + { + DFUDelay(50000000); + device_reboot(); + } + } +#endif + /* Check for: - Audio CONTROL interface request - always 0, note we check for DFU first + * - Audio STREAMING interface request (In or Out) + * - Audio endpoint request (Audio 1.0 Sampling freq requests are sent to the endpoint) + */ + if(((interfaceNum == 0) || (interfaceNum == 1) || (interfaceNum == 2)) +#if (XUA_DFU_EN == 1) + && !DFU_mode_active +#endif + ) + { +#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) + if(g_curUsbSpeed == XUD_SPEED_HS) + { + result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } + else + { + result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } +#elif (AUDIO_CLASS==2) + result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#else + result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#endif + +#ifdef VENDOR_AUDIO_REQS + /* If result is ERR at this point, then request to audio interface not handled - handle vendor audio reqs */ + if(result == XUD_RES_ERR) + { + result = VendorAudioRequests(ep0_out, ep0_in, sp.bRequest, + sp.wValue >> 8, sp.wValue & 0xff, + sp.wIndex >> 8, sp.bmRequestType.Direction, + c_audioControl, c_mix_ctl, c_clk_ctl); + } +#endif + } + } + break; + + default: + break; + } + + } /* if(result == XUD_RES_OKAY) */ + + { + if(result == XUD_RES_ERR) + { + /* Run vendor defined parsing/processing */ + /* Note, an interface might seem ideal here but this *must* be executed on the same + * core sure to shared memory depandancy */ + result = VendorRequests(ep0_out, ep0_in, &sp VENDOR_REQUESTS_PARAMS_); + } + } + + if(result == XUD_RES_ERR) + { +#if (XUA_DFU_EN == 1) + if (!DFU_mode_active) + { +#endif +#if (AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS != 1) + /* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */ + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), + cfgDesc_Audio1, sizeof(cfgDesc_Audio1), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), + &sp, g_curUsbSpeed); +#elif FULL_SPEED_AUDIO_2 + /* Return Audio 2.0 Descriptors for high_speed and full-speed */ + + /* Unfortunately we need to munge the descriptors a bit between full and high-speed */ + if(g_curUsbSpeed == XUD_SPEED_HS) + { + /* Modify Audio Class 2.0 Config descriptor for High-speed operation */ +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT; +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format.bBitResolution = HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT; +#endif +#if (OUTPUT_FORMAT_COUNT > 1) + cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT; +#endif + +#if (OUTPUT_FORMAT_COUNT > 2) + cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT; +#endif +#endif +#if (NUM_USB_CHAN_IN > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN; + cfgDesc_Audio2.Audio_In_Format.bSubslotSize = HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_In_Format.bBitResolution = HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN; +#endif + } + else + { + /* Modify Audio Class 2.0 Config descriptor for Full-speed operation */ +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT_FS; +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format.bBitResolution = FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif +#if (OUTPUT_FORMAT_COUNT > 1) + cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif + +#if (OUTPUT_FORMAT_COUNT > 2) + cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif +#endif +#if (NUM_USB_CHAN_IN > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN_FS; + cfgDesc_Audio2.Audio_In_Format.bSubslotSize = FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_In_Format.bBitResolution = FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN_FS; +#endif + } + + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + null, 0, + null, 0, +#ifdef __XC__ + g_strTable, sizeof(g_strTable), sp, null, g_curUsbSpeed); +#else + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#endif +#elif (AUDIO_CLASS == 1) + /* Return Audio 1.0 Descriptors in FS, should never be in HS! */ + result = USB_StandardRequests(ep0_out, ep0_in, + null, 0, + null, 0, + (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), + cfgDesc_Audio1, sizeof(cfgDesc_Audio1), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#else + /* Return Audio 2.0 Descriptors with Null device as fallback */ + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + devDesc_Null, sizeof(devDesc_Null), + cfgDesc_Null, sizeof(cfgDesc_Null), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#endif +#if (XUA_DFU_EN == 1) + } + + else + { + /* Running in DFU mode - always return same descs for DFU whether HS or FS */ + result = USB_StandardRequests(ep0_out, ep0_in, + DFUdevDesc, sizeof(DFUdevDesc), + DFUcfgDesc, sizeof(DFUcfgDesc), + null, 0, /* Used same descriptors for full and high-speed */ + null, 0, + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); + } +#endif + } + + if (result == XUD_RES_RST) + { +#ifdef __XC__ + g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, ep0_in); +#else + g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, &ep0_in); +#endif + g_currentConfig = 0; + g_curStreamAlt_Out = 0; + g_curStreamAlt_In = 0; + +#if (XUA_DFU_EN == 1) + if (DFUReportResetState(null)) + { + if (!DFU_mode_active) + { + DFU_mode_active = 1; + } + } + else + { + if (DFU_mode_active) + { + DFU_mode_active = 0; + + /* Send reboot command */ + DFUDelay(5000000); + device_reboot(); + } + } +#endif + } +} + +/* Endpoint 0 function. Handles all requests to the device */ +void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) +{ + USB_SetupPacket_t sp; + XUA_Endpoint0_init(c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); + while(1) { #if XUA_LITE @@ -318,506 +833,7 @@ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, /* Returns XUD_RES_OKAY for success, XUD_RES_RST for bus reset */ XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, &sp); #endif - if (result == XUD_RES_OKAY) - { - result = XUD_RES_ERR; - - /* Inspect Request type and Receipient and direction */ - switch( (sp.bmRequestType.Direction << 7) | (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) ) - { - case USB_BMREQ_H2D_STANDARD_INT: - - /* Over-riding USB_StandardRequests implementation */ - if(sp.bRequest == USB_SET_INTERFACE) - { - switch (sp.wIndex) - { - /* Check for audio stream from host start/stop */ -#if (NUM_USB_CHAN_OUT > 0) && (AUDIO_CLASS == 2) - case INTERFACE_NUMBER_AUDIO_OUTPUT: - /* Check the alt is in range */ - if(sp.wValue <= OUTPUT_FORMAT_COUNT) - { - /* Alt 0 is stream stop */ - /* Only send change if we need to */ - if((sp.wValue > 0) && (g_curStreamAlt_Out != sp.wValue)) - { - g_curStreamAlt_Out = sp.wValue; - - /* Send format of data onto buffering */ - outuint(c_audioControl, SET_STREAM_FORMAT_OUT); - outuint(c_audioControl, g_dataFormat_Out[sp.wValue-1]); /* Data format (PCM/DSD) */ - - if(g_curUsbSpeed == XUD_SPEED_HS) - { - outuint(c_audioControl, NUM_USB_CHAN_OUT); /* Channel count */ - outuint(c_audioControl, g_subSlot_Out_HS[sp.wValue-1]); /* Subslot */ - outuint(c_audioControl, g_sampRes_Out_HS[sp.wValue-1]); /* Resolution */ - } - else - { - outuint(c_audioControl, NUM_USB_CHAN_OUT_FS); /* Channel count */ - outuint(c_audioControl, g_subSlot_Out_FS[sp.wValue-1]); /* Subslot */ - outuint(c_audioControl, g_sampRes_Out_FS[sp.wValue-1]); /* Resolution */ - } - - /* Handshake */ - chkct(c_audioControl, XS1_CT_END); - } - } - break; -#endif - -#if (NUM_USB_CHAN_IN > 0) && (AUDIO_CLASS == 2) - case INTERFACE_NUMBER_AUDIO_INPUT: - /* Check the alt is in range */ - if(sp.wValue <= INPUT_FORMAT_COUNT) - { - /* Alt 0 is stream stop */ - /* Only send change if we need to */ - if((sp.wValue > 0) && (g_curStreamAlt_In != sp.wValue)) - { - g_curStreamAlt_In = sp.wValue; - - /* Send format of data onto buffering */ - outuint(c_audioControl, SET_STREAM_FORMAT_IN); - outuint(c_audioControl, g_dataFormat_In[sp.wValue-1]); /* Data format (PCM/DSD) */ - - if(g_curUsbSpeed == XUD_SPEED_HS) - { - outuint(c_audioControl, g_chanCount_In_HS[sp.wValue-1]); /* Channel count */ - outuint(c_audioControl, g_subSlot_In_HS[sp.wValue-1]); /* Subslot */ - outuint(c_audioControl, g_sampRes_In_HS[sp.wValue-1]); /* Resolution */ - } - else - { - outuint(c_audioControl, NUM_USB_CHAN_IN_FS); /* Channel count */ - outuint(c_audioControl, g_subSlot_In_FS[sp.wValue-1]); /* Subslot */ - outuint(c_audioControl, g_sampRes_In_FS[sp.wValue-1]); /* Resolution */ - } - - /* Wait for handshake */ - chkct(c_audioControl, XS1_CT_END); - } - } - break; -#endif - -#ifdef IAP_EA_NATIVE_TRANS - case INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS: - /* Check the alt is in range */ - if (sp.wValue <= IAP_EA_NATIVE_TRANS_ALT_COUNT) - { - /* Reset all state of endpoints associated with this interface - * when changing an alternative setting. See USB 2.0 Spec 9.1.1.5 */ - XUD_ResetEpStateByAddr(ENDPOINT_ADDRESS_IN_IAP_EA_NATIVE_TRANS); - XUD_ResetEpStateByAddr(ENDPOINT_ADDRESS_OUT_IAP_EA_NATIVE_TRANS); - - /* Send selected Alt interface number onto EA Native EP manager */ - outuint(c_EANativeTransport_ctrl, (unsigned)sp.wValue); - - /* Wait for handshake */ - chkct(c_EANativeTransport_ctrl, XS1_CT_END); - } - break; -#endif - default: - /* Unhandled interface */ - break; - } - -#if (NUM_USB_CHAN_OUT > 0) && (NUM_USB_CHAN_IN > 0) - if ((sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) || (sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT)) - { - /* Check for stream start stop on output and input audio interfaces */ - if(sp.wValue && !g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT] && !g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]) - { - /* If start and input AND output not currently running */ - UserAudioStreamStart(); - } - else if(((sp.wIndex == 1) && (!sp.wValue)) && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT] && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT])) - { - /* if output stop and output running and input not running */ - UserAudioStreamStop(); - } - else if(((sp.wIndex == 2) && (!sp.wValue)) && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT] && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT])) - { - /* if input stop and input running and output not running */ - UserAudioStreamStop(); - } - } -#elif (NUM_USB_CHAN_OUT > 0) - if(sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) - { - if(sp.wValue && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT])) - { - /* if start and not currently running */ - UserAudioStreamStart(); - } - else if (!sp.wValue && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT]) - { - /* if stop and currently running */ - UserAudioStreamStop(); - } - } -#elif (NUM_USB_CHAN_IN > 0) - if(sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT) - { - if(sp.wValue && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT])) - { - /* if start and not currently running */ - UserAudioStreamStart(); - } - else if (!sp.wValue && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]) - { - /* if stop and currently running */ - UserAudioStreamStop(); - } - } -#endif - } /* if(sp.bRequest == SET_INTERFACE) */ - - break; /* BMREQ_H2D_STANDARD_INT */ - - case USB_BMREQ_D2H_STANDARD_INT: - - switch(sp.bRequest) - { -#ifdef HID_CONTROLS - case USB_GET_DESCRIPTOR: - - /* Check what inteface request is for */ - if(sp.wIndex == INTERFACE_NUMBER_HID) - { - /* High byte of wValue is descriptor type */ - unsigned descriptorType = sp.wValue & 0xff00; - - switch (descriptorType) - { - case HID_HID: - /* Return HID Descriptor */ - result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, - sizeof(hidDescriptor), sp.wLength); - break; - case HID_REPORT: - /* Return HID report descriptor */ - result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptor, - sizeof(hidReportDescriptor), sp.wLength); - break; - } - } - break; -#endif - default: - break; - } - break; - - /* Recipient: Device */ - case USB_BMREQ_H2D_STANDARD_DEV: - - /* Inspect for actual request */ - switch( sp.bRequest ) - { - /* Standard request: SetConfiguration */ - /* Overriding implementation in USB_StandardRequests */ - case USB_SET_CONFIGURATION: - - //if(g_current_config == 1) - { - /* Consider host active with valid driver at this point */ - UserHostActive(1); - } - - /* We want to run USB_StandardsRequests() implementation also. Don't modify result - * and don't call XUD_DoSetRequestStatus() */ - break; - - default: - //Unknown device request" - break; - } - break; - - /* Audio Class 1.0 Sampling Freqency Requests go to Endpoint */ - case USB_BMREQ_H2D_CLASS_EP: - case USB_BMREQ_D2H_CLASS_EP: - { - unsigned epNum = sp.wIndex & 0xff; - - if ((epNum == ENDPOINT_ADDRESS_OUT_AUDIO) || (epNum == ENDPOINT_ADDRESS_IN_AUDIO)) - { -#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) - if(g_curUsbSpeed == XUD_SPEED_FS) - { - result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } -#elif (AUDIO_CLASS==1) - result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#endif - } - - } - break; - - case USB_BMREQ_H2D_CLASS_INT: - case USB_BMREQ_D2H_CLASS_INT: - { - unsigned interfaceNum = sp.wIndex & 0xff; - //unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5); - - /* TODO Check on return value retval = */ -#if (XUA_DFU_EN == 1) - unsigned DFU_IF = INTERFACE_NUMBER_DFU; - - /* DFU interface number changes based on which mode we are currently running in */ - if (DFU_mode_active) - { - DFU_IF = 0; - } - - if (interfaceNum == DFU_IF) - { - int reset = 0; - - /* If running in application mode stop audio */ - /* Don't interupt audio for save and restore cmds */ - if ((DFU_IF == INTERFACE_NUMBER_DFU) && (sp.bRequest != XMOS_DFU_SAVESTATE) && - (sp.bRequest != XMOS_DFU_RESTORESTATE)) - { - // Stop audio - outuint(c_audioControl, SET_SAMPLE_FREQ); - outuint(c_audioControl, AUDIO_STOP_FOR_DFU); - // Handshake - chkct(c_audioControl, XS1_CT_END); - } - - /* This will return 1 if reset requested */ - result = DFUDeviceRequests(ep0_out, &ep0_in, &sp, null, g_interfaceAlt[sp.wIndex], dfuInterface, &reset); - - if(reset) - { - DFUDelay(50000000); - device_reboot(); - } - } -#endif - /* Check for: - Audio CONTROL interface request - always 0, note we check for DFU first - * - Audio STREAMING interface request (In or Out) - * - Audio endpoint request (Audio 1.0 Sampling freq requests are sent to the endpoint) - */ - if(((interfaceNum == 0) || (interfaceNum == 1) || (interfaceNum == 2)) -#if (XUA_DFU_EN == 1) - && !DFU_mode_active -#endif - ) - { -#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) - if(g_curUsbSpeed == XUD_SPEED_HS) - { - result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } - else - { - result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } -#elif (AUDIO_CLASS==2) - result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#else - result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#endif - -#ifdef VENDOR_AUDIO_REQS - /* If result is ERR at this point, then request to audio interface not handled - handle vendor audio reqs */ - if(result == XUD_RES_ERR) - { - result = VendorAudioRequests(ep0_out, ep0_in, sp.bRequest, - sp.wValue >> 8, sp.wValue & 0xff, - sp.wIndex >> 8, sp.bmRequestType.Direction, - c_audioControl, c_mix_ctl, c_clk_ctl); - } -#endif - } - } - break; - - default: - break; - } - - } /* if(result == XUD_RES_OKAY) */ - - { - if(result == XUD_RES_ERR) - { - /* Run vendor defined parsing/processing */ - /* Note, an interface might seem ideal here but this *must* be executed on the same - * core sure to shared memory depandancy */ - result = VendorRequests(ep0_out, ep0_in, &sp VENDOR_REQUESTS_PARAMS_); - } - } - - if(result == XUD_RES_ERR) - { -#if (XUA_DFU_EN == 1) - if (!DFU_mode_active) - { -#endif -#if (AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS != 1) - /* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */ - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), - cfgDesc_Audio1, sizeof(cfgDesc_Audio1), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), - &sp, g_curUsbSpeed); -#elif FULL_SPEED_AUDIO_2 - /* Return Audio 2.0 Descriptors for high_speed and full-speed */ - - /* Unfortunately we need to munge the descriptors a bit between full and high-speed */ - if(g_curUsbSpeed == XUD_SPEED_HS) - { - /* Modify Audio Class 2.0 Config descriptor for High-speed operation */ -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT; -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format.bBitResolution = HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT; -#endif -#if (OUTPUT_FORMAT_COUNT > 1) - cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT; -#endif - -#if (OUTPUT_FORMAT_COUNT > 2) - cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT; -#endif -#endif -#if (NUM_USB_CHAN_IN > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN; - cfgDesc_Audio2.Audio_In_Format.bSubslotSize = HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_In_Format.bBitResolution = HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN; -#endif - } - else - { - /* Modify Audio Class 2.0 Config descriptor for Full-speed operation */ -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT_FS; -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format.bBitResolution = FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif -#if (OUTPUT_FORMAT_COUNT > 1) - cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif - -#if (OUTPUT_FORMAT_COUNT > 2) - cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif -#endif -#if (NUM_USB_CHAN_IN > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN_FS; - cfgDesc_Audio2.Audio_In_Format.bSubslotSize = FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_In_Format.bBitResolution = FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN_FS; -#endif - } - - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - null, 0, - null, 0, -#ifdef __XC__ - g_strTable, sizeof(g_strTable), sp, null, g_curUsbSpeed); -#else - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#endif -#elif (AUDIO_CLASS == 1) - /* Return Audio 1.0 Descriptors in FS, should never be in HS! */ - result = USB_StandardRequests(ep0_out, ep0_in, - null, 0, - null, 0, - (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), - cfgDesc_Audio1, sizeof(cfgDesc_Audio1), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#else - /* Return Audio 2.0 Descriptors with Null device as fallback */ - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - devDesc_Null, sizeof(devDesc_Null), - cfgDesc_Null, sizeof(cfgDesc_Null), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#endif -#if (XUA_DFU_EN == 1) - } - - else - { - /* Running in DFU mode - always return same descs for DFU whether HS or FS */ - result = USB_StandardRequests(ep0_out, ep0_in, - DFUdevDesc, sizeof(DFUdevDesc), - DFUcfgDesc, sizeof(DFUcfgDesc), - null, 0, /* Used same descriptors for full and high-speed */ - null, 0, - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); - } -#endif - } - - if (result == XUD_RES_RST) - { -#ifdef __XC__ - g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, ep0_in); -#else - g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, &ep0_in); -#endif - g_currentConfig = 0; - g_curStreamAlt_Out = 0; - g_curStreamAlt_In = 0; - -#if (XUA_DFU_EN == 1) - if (DFUReportResetState(null)) - { - if (!DFU_mode_active) - { - DFU_mode_active = 1; - } - } - else - { - if (DFU_mode_active) - { - DFU_mode_active = 0; - - /* Send reboot command */ - DFUDelay(5000000); - device_reboot(); - } - } -#endif - } + XUA_Endpoint0_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); } } #endif /* XUA_USB_EN*/ diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc new file mode 100644 index 00000000..36152999 --- /dev/null +++ b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc @@ -0,0 +1,55 @@ +#include +#include +#include +#include "xua.h" + +#define DEBUG_UNIT EP0_WRAPPER +#define DEBUG_PRINT_ENABLE_EP0_WRAPPER 1 +#include "debug_print.h" + +#if 1 +void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); +void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); +#pragma select handler +void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Result_t &result); + +extern XUD_ep ep0_out; +extern XUD_ep ep0_in; + + +void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) +{ + + USB_SetupPacket_t sp; + XUA_Endpoint0_init(c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); + unsigned char sbuffer[120]; + XUD_SetReady_Out(ep0_out, sbuffer); + while(1){ + + XUD_Result_t result = XUD_RES_ERR; + unsigned length = 0; + + //XUD_Result_t result = XUD_GetSetupBuffer(ep0_out, sbuffer, &length); //Flattened from xud_device + // result = XUD_GetSetupData(ep0_out, sbuffer, length);//Flattened from XUD_EpFunctions.xc + + select{ + case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): + break; + } + + if (result == XUD_RES_OKAY) + { + /* Parse data buffer end populate SetupPacket struct */ + USB_ParseSetupPacket(sbuffer, sp); + } + debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error + + XUA_Endpoint0_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); + XUD_SetReady_Out(ep0_out, sbuffer); + + } +} +#endif \ No newline at end of file From 491b3936ac6231c7be64712a50315dcbffea762e Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Sun, 28 Oct 2018 08:59:27 +0000 Subject: [PATCH 009/123] WIP feedback calc refactor --- examples/xua_lite_example/src/xua_buffer.xc | 39 ++++++++++++--------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index b6750a84..7dbc78c5 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -93,6 +93,12 @@ static inline void pack_samples_to_buff(int input[], const unsigned n_samples, c } +unsigned do_feedback_calculation(unsigned mclk_port_counter, unsigned mclk_port_counter_old, long long feedback_value, unsigned mod_from_last_time){ + unsigned fb_clock = 0; + + return +} + void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_audio_hub) { debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); @@ -113,13 +119,11 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch unsigned in_num_chan = NUM_USB_CHAN_IN; unsigned out_num_chan = NUM_USB_CHAN_OUT; - unsigned tmp; - - unsigned lastClock = 0; - unsigned clocks = 0; - long long clockcounter = 0; - unsigned sof_count=0; + unsigned sof_count = 0; + unsigned mclk_port_counter_old = 0; + long long feedback_value = 0; unsigned mod_from_last_time = 0; + const unsigned mclk_hz = MCLK_48; XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); @@ -148,6 +152,7 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch XUD_Result_t result; unsigned length = 0; + unsigned tmp; //For select channel input by ref while(1){ select{ //Handle control path from EP0 @@ -192,8 +197,10 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch //SOF case inuint_byref(c_sof, tmp): - unsigned mclk_port_count = 0; - asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_count) : "r" (p_for_mclk_count)); + unsigned mclk_port_counter = 0; + asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); + + //fb_clocks[0] = do_feedback_calculation(mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time); /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. @@ -206,14 +213,14 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ - int count = (int) ((short)(mclk_port_count - lastClock)); + int mclk_ticks_this_sof_period = (int) ((short)(mclk_port_counter - mclk_port_counter_old)); - unsigned long long full_result = count * feedbackMul * DEFAULT_FREQ; + unsigned long long full_result = mclk_ticks_this_sof_period * feedbackMul * DEFAULT_FREQ; - clockcounter += full_result; + feedback_value += full_result; /* Store MCLK for next time around... */ - lastClock = mclk_port_count; + mclk_port_counter_old = mclk_port_counter; /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ @@ -222,9 +229,9 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch //debug_printf("fb\n"); sof_count = 0; - clockcounter += mod_from_last_time; - clocks = clockcounter / MCLK_48; - mod_from_last_time = clockcounter % MCLK_48; + feedback_value += mod_from_last_time; + unsigned clocks = feedback_value / mclk_hz; + mod_from_last_time = feedback_value % mclk_hz; //Scale for working out number of samps to take from device for input if(AUDIO_CLASS == 2) @@ -246,7 +253,7 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch { fb_clocks[0] = clocks >> 2; } - clockcounter = 0; + feedback_value = 0; } sof_count++; break; From f097e0a016a01bc16cfd0ea83db91c9ebc40d927 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Sun, 28 Oct 2018 17:22:20 +0000 Subject: [PATCH 010/123] Add todo list --- examples/xua_lite_example/todo.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 examples/xua_lite_example/todo.txt diff --git a/examples/xua_lite_example/todo.txt b/examples/xua_lite_example/todo.txt new file mode 100644 index 00000000..185faefe --- /dev/null +++ b/examples/xua_lite_example/todo.txt @@ -0,0 +1,6 @@ +- Bring ep0 serivice into xua_buffer select (make control mem) +- Tidy feeback endpoint +- Get UAC1 / FS working +- Add timer to xua_buffer to prepare for exchange with audio (remove banckpressure to audio) +- Adaptive +- DFU \ No newline at end of file From b3fe0cb17207640a58df6ba17f861c40ff94a807 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Sun, 28 Oct 2018 17:27:35 +0000 Subject: [PATCH 011/123] FB calc move to fn --- examples/xua_lite_example/src/xua_buffer.xc | 130 +++++++++----------- 1 file changed, 60 insertions(+), 70 deletions(-) diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index 7dbc78c5..76d85ba7 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -93,10 +93,64 @@ static inline void pack_samples_to_buff(int input[], const unsigned n_samples, c } -unsigned do_feedback_calculation(unsigned mclk_port_counter, unsigned mclk_port_counter_old, long long feedback_value, unsigned mod_from_last_time){ - unsigned fb_clock = 0; +void do_feedback_calculation(unsigned &sof_count + ,const unsigned mclk_hz + ,unsigned mclk_port_counter + ,unsigned &mclk_port_counter_old + ,long long &feedback_value + ,unsigned &mod_from_last_time + ,unsigned fb_clocks[1]){ + /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) + * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. + * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. + * Average over 128 SOFs - 128 x 3072 = 0x60000. */ - return + unsigned long long feedbackMul = 64ULL; + if(AUDIO_CLASS == 1) + feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ + + /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ + int mclk_ticks_this_sof_period = (int) ((short)(mclk_port_counter - mclk_port_counter_old)); + unsigned long long full_result = mclk_ticks_this_sof_period * feedbackMul * DEFAULT_FREQ; + feedback_value += full_result; + + /* Store MCLK for next time around... */ + mclk_port_counter_old = mclk_port_counter; + + /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll + * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ + if(sof_count == 128) + { + //debug_printf("fb\n"); + sof_count = 0; + + feedback_value += mod_from_last_time; + unsigned clocks = feedback_value / mclk_hz; + mod_from_last_time = feedback_value % mclk_hz; + feedback_value = 0; + + + //Scale for working out number of samps to take from device for input + if(AUDIO_CLASS == 2) + { + clocks <<= 3; + } + else + { + clocks <<= 6; + } + asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks + + //Write to feedback EP buffer + if (AUDIO_CLASS == 2) + { + fb_clocks[0] = clocks; + } + else + { + fb_clocks[0] = clocks >> 2; + } + } } void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_audio_hub) { @@ -199,62 +253,7 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch case inuint_byref(c_sof, tmp): unsigned mclk_port_counter = 0; asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); - - //fb_clocks[0] = do_feedback_calculation(mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time); - - /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) - * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. - * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. - * Average over 128 SOFs - 128 x 3072 = 0x60000. - */ - - unsigned long long feedbackMul = 64ULL; - if(AUDIO_CLASS == 1) - feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ - - /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ - int mclk_ticks_this_sof_period = (int) ((short)(mclk_port_counter - mclk_port_counter_old)); - - unsigned long long full_result = mclk_ticks_this_sof_period * feedbackMul * DEFAULT_FREQ; - - feedback_value += full_result; - - /* Store MCLK for next time around... */ - mclk_port_counter_old = mclk_port_counter; - - /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll - * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ - if(sof_count == 128) - { - //debug_printf("fb\n"); - sof_count = 0; - - feedback_value += mod_from_last_time; - unsigned clocks = feedback_value / mclk_hz; - mod_from_last_time = feedback_value % mclk_hz; - - //Scale for working out number of samps to take from device for input - if(AUDIO_CLASS == 2) - { - clocks <<= 3; - } - else - { - clocks <<= 6; - } - asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks - - //Write to feedback EP buffer - if (AUDIO_CLASS == 2) - { - fb_clocks[0] = clocks; - } - else - { - fb_clocks[0] = clocks >> 2; - } - feedback_value = 0; - } + do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); sof_count++; break; @@ -275,19 +274,10 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); break; - //Send feedback + //Send asynch explicit feedback value case XUD_SetData_Select(c_feedback, ep_feedback, result): //debug_printf("ep_feedback\n"); - //XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); - if (AUDIO_CLASS == 2) - { - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 4); - } - else - { - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 3); - } - + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); break; //Send samples to host From 6046dc905ecc977b410481ff31909647953f64a3 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 07:19:47 +0000 Subject: [PATCH 012/123] Update todo --- examples/xua_lite_example/todo.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/xua_lite_example/todo.txt b/examples/xua_lite_example/todo.txt index 185faefe..705b1cf9 100644 --- a/examples/xua_lite_example/todo.txt +++ b/examples/xua_lite_example/todo.txt @@ -1,5 +1,7 @@ - Bring ep0 serivice into xua_buffer select (make control mem) - Tidy feeback endpoint +- Input path + FIFO +- Single input/ouput format - Get UAC1 / FS working - Add timer to xua_buffer to prepare for exchange with audio (remove banckpressure to audio) - Adaptive From 5cfbd550fed6bf20accb452c06d6b66c01883bd1 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 07:20:12 +0000 Subject: [PATCH 013/123] Add initial lit ep0 cutdown versions --- lib_xua/src/core/endpoint0/xua_endpoint0.c | 424 +++++++++++++++++- lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc | 21 +- 2 files changed, 418 insertions(+), 27 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index 3bb36f55..48711656 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -298,6 +298,32 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCont } +void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) +{ + ep0_out = XUD_InitEp(c_ep0_out); + ep0_in = XUD_InitEp(c_ep0_in); + + VendorRequests_Init(VENDOR_REQUESTS_PARAMS); + +#ifdef VENDOR_AUDIO_REQS + VendorAudioRequestsInit(c_audioControl, c_mix_ctl, c_clk_ctl); +#endif + +#if (XUA_DFU_EN == 1) + /* Check if device has started in DFU mode */ + if (DFUReportResetState(null)) + { + /* Stop audio */ + outuint(c_audioControl, SET_SAMPLE_FREQ); + outuint(c_audioControl, AUDIO_STOP_FOR_DFU); + /* No Handshake */ + DFU_mode_active = 1; + } +#endif + +} + void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { @@ -803,6 +829,385 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 } } +void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_ + , unsigned *input_interface_num, unsigned *output_interface_num) +{ + if (result == XUD_RES_OKAY) + { + result = XUD_RES_ERR; + + /* Inspect Request type and Receipient and direction */ + switch( (sp.bmRequestType.Direction << 7) | (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) ) + { + case USB_BMREQ_H2D_STANDARD_INT: + + /* Over-riding USB_StandardRequests implementation */ + if(sp.bRequest == USB_SET_INTERFACE) + { + switch (sp.wIndex) + { + /* Check for audio stream from host start/stop */ +#if (NUM_USB_CHAN_OUT > 0) && (AUDIO_CLASS == 2) + case INTERFACE_NUMBER_AUDIO_OUTPUT: + *output_interface_num = sp.wValue; + break; +#endif + +#if (NUM_USB_CHAN_IN > 0) && (AUDIO_CLASS == 2) + case INTERFACE_NUMBER_AUDIO_INPUT: + *input_interface_num = sp.wValue; + break; +#endif + default: + /* Unhandled interface */ + break; + } + } /* if(sp.bRequest == SET_INTERFACE) */ + + break; /* BMREQ_H2D_STANDARD_INT */ + + case USB_BMREQ_D2H_STANDARD_INT: + + switch(sp.bRequest) + { +#ifdef HID_CONTROLS + case USB_GET_DESCRIPTOR: + + /* Check what inteface request is for */ + if(sp.wIndex == INTERFACE_NUMBER_HID) + { + /* High byte of wValue is descriptor type */ + unsigned descriptorType = sp.wValue & 0xff00; + + switch (descriptorType) + { + case HID_HID: + /* Return HID Descriptor */ + result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, + sizeof(hidDescriptor), sp.wLength); + break; + case HID_REPORT: + /* Return HID report descriptor */ + result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptor, + sizeof(hidReportDescriptor), sp.wLength); + break; + } + } + break; +#endif + default: + break; + } + break; + + /* Recipient: Device */ + case USB_BMREQ_H2D_STANDARD_DEV: + + /* Inspect for actual request */ + switch( sp.bRequest ) + { + /* Standard request: SetConfiguration */ + /* Overriding implementation in USB_StandardRequests */ + case USB_SET_CONFIGURATION: + + //if(g_current_config == 1) + { + /* Consider host active with valid driver at this point */ + UserHostActive(1); + } + + /* We want to run USB_StandardsRequests() implementation also. Don't modify result + * and don't call XUD_DoSetRequestStatus() */ + break; + + default: + //Unknown device request" + break; + } + break; + + /* Audio Class 1.0 Sampling Freqency Requests go to Endpoint */ + case USB_BMREQ_H2D_CLASS_EP: + case USB_BMREQ_D2H_CLASS_EP: + { + unsigned epNum = sp.wIndex & 0xff; + + if ((epNum == ENDPOINT_ADDRESS_OUT_AUDIO) || (epNum == ENDPOINT_ADDRESS_IN_AUDIO)) + { +#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) + if(g_curUsbSpeed == XUD_SPEED_FS) + { + result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } +#elif (AUDIO_CLASS==1) + result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#endif + } + + } + break; + + case USB_BMREQ_H2D_CLASS_INT: + case USB_BMREQ_D2H_CLASS_INT: + { + unsigned interfaceNum = sp.wIndex & 0xff; + //unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5); + + /* TODO Check on return value retval = */ +#if (XUA_DFU_EN == 1) + unsigned DFU_IF = INTERFACE_NUMBER_DFU; + + /* DFU interface number changes based on which mode we are currently running in */ + if (DFU_mode_active) + { + DFU_IF = 0; + } + + if (interfaceNum == DFU_IF) + { + int reset = 0; + + /* If running in application mode stop audio */ + /* Don't interupt audio for save and restore cmds */ + if ((DFU_IF == INTERFACE_NUMBER_DFU) && (sp.bRequest != XMOS_DFU_SAVESTATE) && + (sp.bRequest != XMOS_DFU_RESTORESTATE)) + { + // Stop audio + outuint(c_audioControl, SET_SAMPLE_FREQ); + outuint(c_audioControl, AUDIO_STOP_FOR_DFU); + // Handshake + chkct(c_audioControl, XS1_CT_END); + } + + /* This will return 1 if reset requested */ + result = DFUDeviceRequests(ep0_out, &ep0_in, &sp, null, g_interfaceAlt[sp.wIndex], dfuInterface, &reset); + + if(reset) + { + DFUDelay(50000000); + device_reboot(); + } + } +#endif + /* Check for: - Audio CONTROL interface request - always 0, note we check for DFU first + * - Audio STREAMING interface request (In or Out) + * - Audio endpoint request (Audio 1.0 Sampling freq requests are sent to the endpoint) + */ + if(((interfaceNum == 0) || (interfaceNum == 1) || (interfaceNum == 2)) +#if (XUA_DFU_EN == 1) + && !DFU_mode_active +#endif + ) + { +#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) + if(g_curUsbSpeed == XUD_SPEED_HS) + { + result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } + else + { + result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } +#elif (AUDIO_CLASS==2) + result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#else + result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#endif + +#ifdef VENDOR_AUDIO_REQS + /* If result is ERR at this point, then request to audio interface not handled - handle vendor audio reqs */ + if(result == XUD_RES_ERR) + { + result = VendorAudioRequests(ep0_out, ep0_in, sp.bRequest, + sp.wValue >> 8, sp.wValue & 0xff, + sp.wIndex >> 8, sp.bmRequestType.Direction, + c_audioControl, c_mix_ctl, c_clk_ctl); + } +#endif + } + } + break; + + default: + break; + } + + } /* if(result == XUD_RES_OKAY) */ + + { + if(result == XUD_RES_ERR) + { + /* Run vendor defined parsing/processing */ + /* Note, an interface might seem ideal here but this *must* be executed on the same + * core sure to shared memory depandancy */ + result = VendorRequests(ep0_out, ep0_in, &sp VENDOR_REQUESTS_PARAMS_); + } + } + + if(result == XUD_RES_ERR) + { +#if (XUA_DFU_EN == 1) + if (!DFU_mode_active) + { +#endif +#if (AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS != 1) + /* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */ + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), + cfgDesc_Audio1, sizeof(cfgDesc_Audio1), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), + &sp, g_curUsbSpeed); +#elif FULL_SPEED_AUDIO_2 + /* Return Audio 2.0 Descriptors for high_speed and full-speed */ + + /* Unfortunately we need to munge the descriptors a bit between full and high-speed */ + if(g_curUsbSpeed == XUD_SPEED_HS) + { + /* Modify Audio Class 2.0 Config descriptor for High-speed operation */ +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT; +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format.bBitResolution = HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT; +#endif +#if (OUTPUT_FORMAT_COUNT > 1) + cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT; +#endif + +#if (OUTPUT_FORMAT_COUNT > 2) + cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT; +#endif +#endif +#if (NUM_USB_CHAN_IN > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN; + cfgDesc_Audio2.Audio_In_Format.bSubslotSize = HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_In_Format.bBitResolution = HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN; +#endif + } + else + { + /* Modify Audio Class 2.0 Config descriptor for Full-speed operation */ +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT_FS; +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format.bBitResolution = FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif +#if (OUTPUT_FORMAT_COUNT > 1) + cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif + +#if (OUTPUT_FORMAT_COUNT > 2) + cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif +#endif +#if (NUM_USB_CHAN_IN > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN_FS; + cfgDesc_Audio2.Audio_In_Format.bSubslotSize = FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_In_Format.bBitResolution = FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN_FS; +#endif + } + + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + null, 0, + null, 0, +#ifdef __XC__ + g_strTable, sizeof(g_strTable), sp, null, g_curUsbSpeed); +#else + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#endif +#elif (AUDIO_CLASS == 1) + /* Return Audio 1.0 Descriptors in FS, should never be in HS! */ + result = USB_StandardRequests(ep0_out, ep0_in, + null, 0, + null, 0, + (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), + cfgDesc_Audio1, sizeof(cfgDesc_Audio1), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#else + /* Return Audio 2.0 Descriptors with Null device as fallback */ + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + devDesc_Null, sizeof(devDesc_Null), + cfgDesc_Null, sizeof(cfgDesc_Null), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#endif +#if (XUA_DFU_EN == 1) + } + + else + { + /* Running in DFU mode - always return same descs for DFU whether HS or FS */ + result = USB_StandardRequests(ep0_out, ep0_in, + DFUdevDesc, sizeof(DFUdevDesc), + DFUcfgDesc, sizeof(DFUcfgDesc), + null, 0, /* Used same descriptors for full and high-speed */ + null, 0, + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); + } +#endif + } + + if (result == XUD_RES_RST) + { +#ifdef __XC__ + g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, ep0_in); +#else + g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, &ep0_in); +#endif + g_currentConfig = 0; + g_curStreamAlt_Out = 0; + g_curStreamAlt_In = 0; + +#if (XUA_DFU_EN == 1) + if (DFUReportResetState(null)) + { + if (!DFU_mode_active) + { + DFU_mode_active = 1; + } + } + else + { + if (DFU_mode_active) + { + DFU_mode_active = 0; + + /* Send reboot command */ + DFUDelay(5000000); + device_reboot(); + } + } +#endif + } +} + /* Endpoint 0 function. Handles all requests to the device */ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) @@ -812,27 +1217,8 @@ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, while(1) { -#if XUA_LITE - unsigned char sbuffer[120]; - unsigned length = 0; - XUD_Result_t result = XUD_RES_ERR; - - //XUD_Result_t result = XUD_GetSetupBuffer(ep0_out, sbuffer, &length); //Flattened from xud_device - result = XUD_GetSetupData(ep0_out, sbuffer, &length);//Flattened from XUD_EpFunctions.xc - - // select{ - // case XUD_GetSetupData_Select(c_ep0_out, ep0_out, &length, &result): - // break; - - if (result == XUD_RES_OKAY) - { - /* Parse data buffer end populate SetupPacket struct */ - USB_ParseSetupPacket(sbuffer, &sp); - } -#else /* Returns XUD_RES_OKAY for success, XUD_RES_RST for bus reset */ XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, &sp); -#endif XUA_Endpoint0_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); } } diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc index 36152999..a647d458 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc @@ -7,11 +7,12 @@ #define DEBUG_PRINT_ENABLE_EP0_WRAPPER 1 #include "debug_print.h" -#if 1 -void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); -void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, +extern "C"{ +void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); +void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_, unsigned *input_interface_num, unsigned *output_interface_num); +} #pragma select handler void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Result_t &result); @@ -24,9 +25,14 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCo { USB_SetupPacket_t sp; - XUA_Endpoint0_init(c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); + XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); unsigned char sbuffer[120]; XUD_SetReady_Out(ep0_out, sbuffer); + + unsigned input_interface_num = 0; + unsigned output_interface_num = 0; + + while(1){ XUD_Result_t result = XUD_RES_ERR; @@ -47,9 +53,8 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCo } debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error - XUA_Endpoint0_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); + XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface, &input_interface_num, &output_interface_num); XUD_SetReady_Out(ep0_out, sbuffer); } -} -#endif \ No newline at end of file +} \ No newline at end of file From 44ea92e229e265c47f7ab36c6e572a9bb253eaa9 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 07:27:53 +0000 Subject: [PATCH 014/123] Make c_Audiocontrol nullable --- lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h | 6 +++--- lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h index 16d21b47..ab4c613d 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h @@ -5,13 +5,13 @@ #include -int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), chanend c_audioControl, +int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctl)); -XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), chanend c_audioControl, +XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctl)); -int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), chanend c_audioControl, +int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctl)); diff --git a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc index d10dc437..2fdd434c 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc @@ -273,7 +273,7 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl) * XUD_RES_RST for device reset * else XUD_RES_ERR */ -int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl +int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl ) { unsigned int buffer[32]; @@ -1071,7 +1071,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c #if (AUDIO_CLASS_FALLBACK != 0) || (AUDIO_CLASS == 1) -int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl) +int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl) { /* At this point we know: * bmRequestType.Recipient = Endpoint @@ -1159,7 +1159,7 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp /* Handles the Audio Class 1.0 specific requests */ -XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl +XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl ) { #if (OUTPUT_VOLUME_CONTROL == 1) || (INPUT_VOLUME_CONTROL == 1) From f0c6b22ddc3c18a593c1eaf8bea906487020770b Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 07:37:23 +0000 Subject: [PATCH 015/123] Restrict sample app to single data format --- examples/xua_lite_example/src/xua_conf.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h index 668b4cd4..b24ed76a 100644 --- a/examples/xua_lite_example/src/xua_conf.h +++ b/examples/xua_lite_example/src/xua_conf.h @@ -22,6 +22,11 @@ #define PID_AUDIO_2 2 #define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example) */ +#define INPUT_FORMAT_COUNT 1 +#define STREAM_FORMAT_INPUT_1_RESOLUTION_BITS 16 +#define OUTPUT_FORMAT_COUNT 1 +#define STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS 16 + #define UAC_FORCE_FEEDBACK_EP 1 #define XUA_LITE 1 // Use simple/optimised USB buffer tasks #define AUDIO_CLASS 2 From 4b73f179976063c82073b8e8984c92e814381046 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 08:50:04 +0000 Subject: [PATCH 016/123] First pass combine ep0 into buffer --- examples/xua_lite_example/src/app_xua_lite.xc | 7 +-- examples/xua_lite_example/src/xua_buffer.xc | 52 ++++++++++++++++++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 934666aa..cf0e2a21 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -49,7 +49,7 @@ on tile[0]:clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO}; XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO}; -void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_aud_host); +void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, chanend c_aud_host); [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, client i2c_master_if ?i2c, client output_gpio_if dac_reset); void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); @@ -96,6 +96,7 @@ int main() AudioHwConfigure(DEFAULT_FREQ, i_i2c[0]); } + debug_printf("XUD SPEED: %d\n", (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS); par{ // Low level USB device layer core XUD_Main(c_ep_out, 2, c_ep_in, 3, @@ -106,10 +107,10 @@ int main() // Endpoint 0 core from lib_xua // Note, since we are not using many features we pass in null for quite a few params.. // XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); - XUA_Endpoint0_select(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); + //XUA_Endpoint0_select(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); // Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core - XUA_Buffer_lite(c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, c_aud_ctl, p_for_mclk_count, c_audio); + XUA_Buffer_lite(c_ep_out[0], c_ep_in[0], c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, p_for_mclk_count, c_audio); } }//Tile[1] par }//Top level par diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index 76d85ba7..fde01745 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -153,7 +153,25 @@ void do_feedback_calculation(unsigned &sof_count } } -void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_audio_hub) { +#define SINGLE_XUA_EP_BUFFER 1 + + +#if SINGLE_XUA_EP_BUFFER +extern "C"{ +void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); +void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_, unsigned *input_interface_num, unsigned *output_interface_num); +} +#pragma select handler +void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Result_t &result); + +extern XUD_ep ep0_out; +extern XUD_ep ep0_in; +#endif + + +void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, chanend c_audio_hub) { debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); @@ -196,6 +214,20 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; +#if SINGLE_XUA_EP_BUFFER + #define c_audioControl null + #define dfuInterface null + XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, c_audioControl, null, null, null, dfuInterface); + unsigned char sbuffer[120]; + USB_SetupPacket_t sp; + XUD_SetReady_Out(ep0_out, sbuffer); + + unsigned input_interface_num = 0; + unsigned output_interface_num = 0; + +#endif + + unsafe{ int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; @@ -209,6 +241,8 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch unsigned tmp; //For select channel input by ref while(1){ select{ + +#if !SINGLE_XUA_EP_BUFFER //Handle control path from EP0 case testct_byref(c_aud_ctl, tmp): //ignore tmp as is used for reboot signalling only @@ -248,6 +282,22 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch } outct(c_aud_ctl, XS1_CT_END); break; +#endif + + +#if SINGLE_XUA_EP_BUFFER + case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): + if (result == XUD_RES_OKAY) + { + /* Parse data buffer end populate SetupPacket struct */ + USB_ParseSetupPacket(sbuffer, sp); + } + debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error + + XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); + XUD_SetReady_Out(ep0_out, sbuffer); + break; +#endif //SOF case inuint_byref(c_sof, tmp): From eaf190b4852810cbaa804d9ca7a9ad19463c6ca2 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 11:11:06 +0000 Subject: [PATCH 017/123] Light tidy of single thread EP buffer --- examples/xua_lite_example/src/app_xua_lite.xc | 7 +- examples/xua_lite_example/src/audio_hub.xc | 3 +- examples/xua_lite_example/src/xua_buffer.xc | 94 ++++--------------- lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc | 5 +- 4 files changed, 22 insertions(+), 87 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index cf0e2a21..a0b0d164 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -103,13 +103,8 @@ int main() c_sof, epTypeTableOut, epTypeTableIn, null, null, -1 , (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); - - // Endpoint 0 core from lib_xua - // Note, since we are not using many features we pass in null for quite a few params.. - // XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); - //XUA_Endpoint0_select(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); - // Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core + // Buffering cores - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core XUA_Buffer_lite(c_ep_out[0], c_ep_in[0], c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, p_for_mclk_count, c_audio); } }//Tile[1] par diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index c23f5385..a73827e7 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -16,7 +16,7 @@ void AudioHub(server i2s_frame_callback_if i2s, int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; - // Set reset DAC + // Reset DAC dac_reset.output(0); delay_milliseconds(1); dac_reset.output(1); @@ -43,6 +43,7 @@ void AudioHub(server i2s_frame_callback_if i2s, restart = I2S_NO_RESTART; // Keep on looping for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio_hub <: samples_in[i]; for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub :> samples_out[i]; + delay_microseconds(5); //Test backpressure tolerance break; } } diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index fde01745..d51e34ca 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -180,22 +180,16 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; - #define FEEDBACK_BUFF_SIZE 4 - unsigned char buffer_feedback[FEEDBACK_BUFF_SIZE]; - unsigned int fb_clocks[1] = {0}; - - unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - unsigned in_num_chan = NUM_USB_CHAN_IN; - unsigned out_num_chan = NUM_USB_CHAN_OUT; - + //Asynch feedback calculation unsigned sof_count = 0; unsigned mclk_port_counter_old = 0; long long feedback_value = 0; unsigned mod_from_last_time = 0; const unsigned mclk_hz = MCLK_48; + unsigned int fb_clocks[1] = {0}; XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); @@ -203,103 +197,55 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); unsigned num_samples_received_from_host = 0; - unsigned outstanding_samples_to_host = 0; unsigned num_samples_to_send_to_host = 0; - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); - XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); - int loopback_samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD] = {0}; int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; -#if SINGLE_XUA_EP_BUFFER #define c_audioControl null #define dfuInterface null XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, c_audioControl, null, null, null, dfuInterface); - unsigned char sbuffer[120]; - USB_SetupPacket_t sp; - XUD_SetReady_Out(ep0_out, sbuffer); + unsigned char sbuffer[120]; //Raw buffer for EP0 data + USB_SetupPacket_t sp; //Parsed setup packet from EP0 unsigned input_interface_num = 0; unsigned output_interface_num = 0; -#endif - + //Enable all EPs + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); + XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); + XUD_SetReady_Out(ep0_out, sbuffer); + //Unsafe to allow us to use fifo API unsafe{ int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; - mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]) - , host_to_device_fifo_storage, 0, 0}; + mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + //XUD trasnaction variables XUD_Result_t result; unsigned length = 0; unsigned tmp; //For select channel input by ref while(1){ select{ - -#if !SINGLE_XUA_EP_BUFFER - //Handle control path from EP0 - case testct_byref(c_aud_ctl, tmp): - //ignore tmp as is used for reboot signalling only - unsigned cmd = inuint(c_aud_ctl); - - debug_printf("c_aud_ctl cmd: %d\n", cmd); - if(cmd == SET_SAMPLE_FREQ){ - unsigned receivedSampleFreq = inuint(c_aud_ctl); - debug_printf("SET_SAMPLE_FREQ: %d\n", receivedSampleFreq); - sampleFreq = receivedSampleFreq; - } - - else if(cmd == SET_STREAM_FORMAT_IN){ - unsigned formatChange_DataFormat = inuint(c_aud_ctl); - unsigned formatChange_NumChans = inuint(c_aud_ctl); - unsigned formatChange_SubSlot = inuint(c_aud_ctl); - unsigned formatChange_SampRes = inuint(c_aud_ctl); - debug_printf("SET_STREAM_FORMAT_IN: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); - in_subslot_size = formatChange_SubSlot; - in_num_chan = formatChange_NumChans; - } - - else if (cmd == SET_STREAM_FORMAT_OUT) - { - XUD_BusSpeed_t busSpeed; - unsigned formatChange_DataFormat = inuint(c_aud_ctl); - unsigned formatChange_NumChans = inuint(c_aud_ctl); - unsigned formatChange_SubSlot = inuint(c_aud_ctl); - unsigned formatChange_SampRes = inuint(c_aud_ctl); - debug_printf("SET_STREAM_FORMAT_OUT: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); - out_subslot_size = formatChange_SubSlot; - out_num_chan = formatChange_NumChans; - } - - else{ - debug_printf("Unhandled command\n"); - } - outct(c_aud_ctl, XS1_CT_END); - break; -#endif - - -#if SINGLE_XUA_EP_BUFFER + //Handle EP0 requests case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): if (result == XUD_RES_OKAY) { /* Parse data buffer end populate SetupPacket struct */ USB_ParseSetupPacket(sbuffer, sp); } - debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error + //debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); XUD_SetReady_Out(ep0_out, sbuffer); break; -#endif - //SOF + //SOF handling case inuint_byref(c_sof, tmp): unsigned mclk_port_counter = 0; asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); @@ -311,13 +257,11 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): num_samples_received_from_host = length / out_subslot_size; //debug_printf("out samps: %d\n", num_samples_received_from_host); - outstanding_samples_to_host += num_samples_received_from_host; unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("full\n"); - + if (ret != FIFO_SUCCESS) debug_printf("host_to_device_fifo full\n"); num_samples_to_send_to_host = num_samples_received_from_host; //Mark EP as ready for next frame from host @@ -326,23 +270,21 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //Send asynch explicit feedback value case XUD_SetData_Select(c_feedback, ep_feedback, result): - //debug_printf("ep_feedback\n"); XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); break; //Send samples to host case XUD_SetData_Select(c_aud_in, ep_aud_in, result): - //debug_printf("sent data\n"); - //Populate the input buffer ready for the next read pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback num_samples_to_send_to_host = 0; break; + //Exchange samples with audiohub case c_audio_hub :> samples_in[0]: for (int i = 1; i < NUM_USB_CHAN_IN; i++) c_audio_hub :> samples_in[i]; // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc index a647d458..3846c1c6 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc @@ -4,7 +4,7 @@ #include "xua.h" #define DEBUG_UNIT EP0_WRAPPER -#define DEBUG_PRINT_ENABLE_EP0_WRAPPER 1 +#define DEBUG_PRINT_ENABLE_EP0_WRAPPER 0 #include "debug_print.h" extern "C"{ @@ -38,9 +38,6 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCo XUD_Result_t result = XUD_RES_ERR; unsigned length = 0; - //XUD_Result_t result = XUD_GetSetupBuffer(ep0_out, sbuffer, &length); //Flattened from xud_device - // result = XUD_GetSetupData(ep0_out, sbuffer, length);//Flattened from XUD_EpFunctions.xc - select{ case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): break; From 3f1e612d678862210643cb1270235cd0c6ba1e40 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 11:11:06 +0000 Subject: [PATCH 018/123] Light tidy of single thread EP buffer --- examples/xua_lite_example/src/app_xua_lite.xc | 7 +- examples/xua_lite_example/src/audio_hub.xc | 3 +- examples/xua_lite_example/src/xua_buffer.xc | 101 ++++-------------- lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc | 5 +- 4 files changed, 23 insertions(+), 93 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index cf0e2a21..a0b0d164 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -103,13 +103,8 @@ int main() c_sof, epTypeTableOut, epTypeTableIn, null, null, -1 , (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); - - // Endpoint 0 core from lib_xua - // Note, since we are not using many features we pass in null for quite a few params.. - // XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); - //XUA_Endpoint0_select(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); - // Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core + // Buffering cores - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core XUA_Buffer_lite(c_ep_out[0], c_ep_in[0], c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, p_for_mclk_count, c_audio); } }//Tile[1] par diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index c23f5385..a73827e7 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -16,7 +16,7 @@ void AudioHub(server i2s_frame_callback_if i2s, int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; - // Set reset DAC + // Reset DAC dac_reset.output(0); delay_milliseconds(1); dac_reset.output(1); @@ -43,6 +43,7 @@ void AudioHub(server i2s_frame_callback_if i2s, restart = I2S_NO_RESTART; // Keep on looping for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio_hub <: samples_in[i]; for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub :> samples_out[i]; + delay_microseconds(5); //Test backpressure tolerance break; } } diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index fde01745..32d14d6b 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -180,22 +180,16 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; - #define FEEDBACK_BUFF_SIZE 4 - unsigned char buffer_feedback[FEEDBACK_BUFF_SIZE]; - unsigned int fb_clocks[1] = {0}; - - unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - unsigned in_num_chan = NUM_USB_CHAN_IN; - unsigned out_num_chan = NUM_USB_CHAN_OUT; - + //Asynch feedback calculation unsigned sof_count = 0; unsigned mclk_port_counter_old = 0; long long feedback_value = 0; unsigned mod_from_last_time = 0; const unsigned mclk_hz = MCLK_48; + unsigned int fb_clocks[1] = {0}; XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); @@ -203,103 +197,51 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); unsigned num_samples_received_from_host = 0; - unsigned outstanding_samples_to_host = 0; unsigned num_samples_to_send_to_host = 0; - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); - XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); - int loopback_samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD] = {0}; int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; -#if SINGLE_XUA_EP_BUFFER #define c_audioControl null #define dfuInterface null XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, c_audioControl, null, null, null, dfuInterface); - unsigned char sbuffer[120]; - USB_SetupPacket_t sp; - XUD_SetReady_Out(ep0_out, sbuffer); + unsigned char sbuffer[120]; //Raw buffer for EP0 data + USB_SetupPacket_t sp; //Parsed setup packet from EP0 unsigned input_interface_num = 0; unsigned output_interface_num = 0; -#endif - + //Enable all EPs + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); + XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); + XUD_SetReady_Out(ep0_out, sbuffer); + //Unsafe to allow us to use fifo API unsafe{ int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; - mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]) - , host_to_device_fifo_storage, 0, 0}; + mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + //XUD transaction variables passed in by reference XUD_Result_t result; unsigned length = 0; unsigned tmp; //For select channel input by ref while(1){ select{ - -#if !SINGLE_XUA_EP_BUFFER - //Handle control path from EP0 - case testct_byref(c_aud_ctl, tmp): - //ignore tmp as is used for reboot signalling only - unsigned cmd = inuint(c_aud_ctl); - - debug_printf("c_aud_ctl cmd: %d\n", cmd); - if(cmd == SET_SAMPLE_FREQ){ - unsigned receivedSampleFreq = inuint(c_aud_ctl); - debug_printf("SET_SAMPLE_FREQ: %d\n", receivedSampleFreq); - sampleFreq = receivedSampleFreq; - } - - else if(cmd == SET_STREAM_FORMAT_IN){ - unsigned formatChange_DataFormat = inuint(c_aud_ctl); - unsigned formatChange_NumChans = inuint(c_aud_ctl); - unsigned formatChange_SubSlot = inuint(c_aud_ctl); - unsigned formatChange_SampRes = inuint(c_aud_ctl); - debug_printf("SET_STREAM_FORMAT_IN: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); - in_subslot_size = formatChange_SubSlot; - in_num_chan = formatChange_NumChans; - } - - else if (cmd == SET_STREAM_FORMAT_OUT) - { - XUD_BusSpeed_t busSpeed; - unsigned formatChange_DataFormat = inuint(c_aud_ctl); - unsigned formatChange_NumChans = inuint(c_aud_ctl); - unsigned formatChange_SubSlot = inuint(c_aud_ctl); - unsigned formatChange_SampRes = inuint(c_aud_ctl); - debug_printf("SET_STREAM_FORMAT_OUT: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); - out_subslot_size = formatChange_SubSlot; - out_num_chan = formatChange_NumChans; - } - - else{ - debug_printf("Unhandled command\n"); - } - outct(c_aud_ctl, XS1_CT_END); - break; -#endif - - -#if SINGLE_XUA_EP_BUFFER + //Handle EP0 requests case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): - if (result == XUD_RES_OKAY) - { - /* Parse data buffer end populate SetupPacket struct */ - USB_ParseSetupPacket(sbuffer, sp); - } - debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error + if (result == XUD_RES_OKAY) USB_ParseSetupPacket(sbuffer, sp); //Parse data buffer end populate SetupPacket struct + //debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); XUD_SetReady_Out(ep0_out, sbuffer); break; -#endif - //SOF + //SOF handling case inuint_byref(c_sof, tmp): unsigned mclk_port_counter = 0; asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); @@ -311,13 +253,11 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): num_samples_received_from_host = length / out_subslot_size; //debug_printf("out samps: %d\n", num_samples_received_from_host); - outstanding_samples_to_host += num_samples_received_from_host; unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("full\n"); - + if (ret != FIFO_SUCCESS) debug_printf("host_to_device_fifo full\n"); num_samples_to_send_to_host = num_samples_received_from_host; //Mark EP as ready for next frame from host @@ -326,23 +266,20 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //Send asynch explicit feedback value case XUD_SetData_Select(c_feedback, ep_feedback, result): - //debug_printf("ep_feedback\n"); XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); break; //Send samples to host case XUD_SetData_Select(c_aud_in, ep_aud_in, result): - //debug_printf("sent data\n"); - //Populate the input buffer ready for the next read pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); - //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - + //Use the number of samples we received last time so we are always balanced (assumes same in/out count) unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback num_samples_to_send_to_host = 0; break; + //Exchange samples with audiohub case c_audio_hub :> samples_in[0]: for (int i = 1; i < NUM_USB_CHAN_IN; i++) c_audio_hub :> samples_in[i]; // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc index a647d458..3846c1c6 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc @@ -4,7 +4,7 @@ #include "xua.h" #define DEBUG_UNIT EP0_WRAPPER -#define DEBUG_PRINT_ENABLE_EP0_WRAPPER 1 +#define DEBUG_PRINT_ENABLE_EP0_WRAPPER 0 #include "debug_print.h" extern "C"{ @@ -38,9 +38,6 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCo XUD_Result_t result = XUD_RES_ERR; unsigned length = 0; - //XUD_Result_t result = XUD_GetSetupBuffer(ep0_out, sbuffer, &length); //Flattened from xud_device - // result = XUD_GetSetupData(ep0_out, sbuffer, length);//Flattened from XUD_EpFunctions.xc - select{ case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): break; From 12327505e5243d283683a46b6439a7144b2a96b3 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 13:09:10 +0000 Subject: [PATCH 019/123] Class 1 FS - noise + occasional overflow --- examples/xua_lite_example/src/app_xua_lite.xc | 2 +- examples/xua_lite_example/src/audio_hub.xc | 2 +- examples/xua_lite_example/src/xua_buffer.xc | 3 ++- examples/xua_lite_example/src/xua_conf.h | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index a0b0d164..99e7456c 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -96,7 +96,7 @@ int main() AudioHwConfigure(DEFAULT_FREQ, i_i2c[0]); } - debug_printf("XUD SPEED: %d\n", (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS); + debug_printf("XUD SPEED: %d\n", (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS); //FS = 1, HS = 2 par{ // Low level USB device layer core XUD_Main(c_ep_out, 2, c_ep_in, 3, diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index a73827e7..c3e2a1ff 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -43,7 +43,7 @@ void AudioHub(server i2s_frame_callback_if i2s, restart = I2S_NO_RESTART; // Keep on looping for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio_hub <: samples_in[i]; for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub :> samples_out[i]; - delay_microseconds(5); //Test backpressure tolerance + //delay_microseconds(5); //Test backpressure tolerance break; } } diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index f4ae6c27..e4e68880 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -253,7 +253,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("host_to_device_fifo full\n"); + if (ret != FIFO_SUCCESS) debug_printf("h2f full\n"); num_samples_to_send_to_host = num_samples_received_from_host; //Mark EP as ready for next frame from host @@ -263,6 +263,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //Send asynch explicit feedback value case XUD_SetData_Select(c_feedback, ep_feedback, result): XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); + //debug_printf("0x%x\n", fb_clocks[0]); break; //Send samples to host diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h index b24ed76a..1d81b46d 100644 --- a/examples/xua_lite_example/src/xua_conf.h +++ b/examples/xua_lite_example/src/xua_conf.h @@ -29,6 +29,6 @@ #define UAC_FORCE_FEEDBACK_EP 1 #define XUA_LITE 1 // Use simple/optimised USB buffer tasks -#define AUDIO_CLASS 2 +#define AUDIO_CLASS 1 #endif From 40ea5755898e0b6cc5d2e04920e27021814e9762 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 29 Oct 2018 13:29:19 +0000 Subject: [PATCH 020/123] Fix class 1 noise by using channel buffering --- examples/xua_lite_example/src/audio_hub.xc | 4 ++-- examples/xua_lite_example/src/xua_buffer.xc | 22 +++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index c3e2a1ff..879e89b1 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -41,8 +41,8 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping - for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio_hub <: samples_in[i]; - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub :> samples_out[i]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) samples_out[i] = (int)inuint(c_audio_hub); + for (int i = 0; i < NUM_USB_CHAN_IN; i++) outuint(c_audio_hub, (unsigned)samples_in[i]); //delay_microseconds(5); //Test backpressure tolerance break; } diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index e4e68880..876a5caa 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -214,6 +214,10 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); XUD_SetReady_Out(ep0_out, sbuffer); + //Send initial samples so audiohub is not blocked + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) outuint(c_audio_hub, 0); + + //Unsafe to allow us to use fifo API unsafe{ @@ -224,8 +228,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //XUD transaction variables passed in by reference XUD_Result_t result; unsigned length = 0; - - unsigned tmp; //For select channel input by ref + unsigned u_tmp; //For select channel input by ref while(1){ select{ //Handle EP0 requests @@ -238,7 +241,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha break; //SOF handling - case inuint_byref(c_sof, tmp): + case inuint_byref(c_sof, u_tmp): unsigned mclk_port_counter = 0; asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); @@ -277,14 +280,17 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha num_samples_to_send_to_host = 0; break; - //Exchange samples with audiohub - case c_audio_hub :> samples_in[0]: - for (int i = 1; i < NUM_USB_CHAN_IN; i++) c_audio_hub :> samples_in[i]; - // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; + //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO + case inuint_byref(c_audio_hub, u_tmp): + samples_in[0] = (int)u_tmp; + for (int i = 1; i < NUM_USB_CHAN_IN; i++){ + u_tmp = inuint(c_audio_hub); + samples_in[i] = (int)u_tmp; + } int out_samps[NUM_USB_CHAN_OUT]; fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, out_samps, NUM_USB_CHAN_OUT); //if (ret != FIFO_SUCCESS) debug_printf("empty\n"); - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: out_samps[i]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) outuint(c_audio_hub, (unsigned) out_samps[i]); break; } } From 35468c7d778da21c254424ed5dfbcdc33793689a Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Tue, 30 Oct 2018 11:48:17 +0000 Subject: [PATCH 021/123] Streaming channels to audio --- examples/xua_lite_example/src/app_xua_lite.xc | 10 +++----- examples/xua_lite_example/src/audio_hub.xc | 10 +++++--- .../src/{xua_buffer.xc => xua_buffer_lite.xc} | 25 ++++++++++++++++--- 3 files changed, 30 insertions(+), 15 deletions(-) rename examples/xua_lite_example/src/{xua_buffer.xc => xua_buffer_lite.xc} (95%) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 99e7456c..d098caa1 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -49,9 +49,9 @@ on tile[0]:clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO}; XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO}; -void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, chanend c_aud_host); +void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_aud_host); [[distributable]] -void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, client i2c_master_if ?i2c, client output_gpio_if dac_reset); +void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_aud, client i2c_master_if ?i2c, client output_gpio_if dac_reset); void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); @@ -69,11 +69,7 @@ int main() interface i2c_master_if i_i2c[1]; interface output_gpio_if i_gpio[1]; - chan c_audio; - - - // Channel for communicating control messages from EP0 to the rest of the device (via the buffering cores) - chan c_aud_ctl; + streaming chan c_audio; //We use the channel buffering (48B across switch each way) par { diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 879e89b1..62054967 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -9,7 +9,7 @@ [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, - chanend c_audio_hub, + streaming chanend c_audio_hub, client i2c_master_if ?i_i2c, client output_gpio_if dac_reset) { @@ -41,9 +41,11 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) samples_out[i] = (int)inuint(c_audio_hub); - for (int i = 0; i < NUM_USB_CHAN_IN; i++) outuint(c_audio_hub, (unsigned)samples_in[i]); - //delay_microseconds(5); //Test backpressure tolerance + timer tmr; int t0, t1; tmr :> t0; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub :> samples_out[i]; + for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio_hub <: samples_in[i]; + //tmr :> t1; debug_printf("%d\n", t1 - t0); + //delay_microseconds(10); //Test backpressure tolerance break; } } diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc similarity index 95% rename from examples/xua_lite_example/src/xua_buffer.xc rename to examples/xua_lite_example/src/xua_buffer_lite.xc index 876a5caa..3a96746b 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -167,12 +167,10 @@ extern XUD_ep ep0_out; extern XUD_ep ep0_in; -void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, chanend c_audio_hub) { +void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); - unsigned sampleFreq = DEFAULT_FREQ; - unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; @@ -215,7 +213,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha XUD_SetReady_Out(ep0_out, sbuffer); //Send initial samples so audiohub is not blocked - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) outuint(c_audio_hub, 0); + for (int i = 0; i < NUM_USB_CHAN_OUT * 5; i++) outuint(c_audio_hub, 0); //Unsafe to allow us to use fifo API @@ -233,23 +231,32 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha select{ //Handle EP0 requests case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): + timer tmr; int t0, t1; tmr :> t0; + if (result == XUD_RES_OKAY) USB_ParseSetupPacket(sbuffer, sp); //Parse data buffer end populate SetupPacket struct //debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); XUD_SetReady_Out(ep0_out, sbuffer); + tmr :> t1; debug_printf("c%d\n", t1 - t0); + break; //SOF handling case inuint_byref(c_sof, u_tmp): + timer tmr; int t0, t1; tmr :> t0; unsigned mclk_port_counter = 0; asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); sof_count++; + tmr :> t1; debug_printf("s%d\n", t1 - t0); + break; //Receive samples from host case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): + timer tmr; int t0, t1; tmr :> t0; + num_samples_received_from_host = length / out_subslot_size; //debug_printf("out samps: %d\n", num_samples_received_from_host); @@ -261,16 +268,24 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + tmr :> t1; debug_printf("o%d\n", t1 - t0); + break; //Send asynch explicit feedback value case XUD_SetData_Select(c_feedback, ep_feedback, result): + timer tmr; int t0, t1; tmr :> t0; + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); //debug_printf("0x%x\n", fb_clocks[0]); + tmr :> t1; debug_printf("f%d\n", t1 - t0); + break; //Send samples to host case XUD_SetData_Select(c_aud_in, ep_aud_in, result): + timer tmr; int t0, t1; tmr :> t0; + //Populate the input buffer ready for the next read pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); //Use the number of samples we received last time so we are always balanced (assumes same in/out count) @@ -278,6 +293,8 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback num_samples_to_send_to_host = 0; + tmr :> t1; debug_printf("i%d\n", t1 - t0); + break; //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO From 5643d2b6756c4b0abcff1d169fd4a704dcf03303 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 31 Oct 2018 13:25:46 +0000 Subject: [PATCH 022/123] Add ddr pdm mics --- examples/xua_lite_example/Makefile | 5 +- examples/xua_lite_example/src/app_xua_lite.xc | 37 +++++++-- examples/xua_lite_example/src/audio_hub.xc | 52 ++++++++++--- examples/xua_lite_example/src/pdm_mic.xc | 75 +++++++++++++++++++ examples/xua_lite_example/src/xua_conf.h | 10 ++- 5 files changed, 157 insertions(+), 22 deletions(-) create mode 100644 examples/xua_lite_example/src/pdm_mic.xc diff --git a/examples/xua_lite_example/Makefile b/examples/xua_lite_example/Makefile index 7118438e..85c75385 100644 --- a/examples/xua_lite_example/Makefile +++ b/examples/xua_lite_example/Makefile @@ -4,12 +4,13 @@ TARGET = RPI_HAT_60QFN.xn # The flags passed to xcc when building the application XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -Os -report \ - -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] + -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] \ + -D MIC_ARRAY_CH0=PIN0 -D MIC_ARRAY_CH1=PIN4 # The USED_MODULES variable lists other module used by the application. These # modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables. # Modules are expected to be in the directory above the BASE_DIR directory. -USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_gpio +USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_mic_array_ddr #============================================================================= # The following part of the Makefile includes the common build infrastructure diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index d098caa1..42806591 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -11,6 +11,7 @@ #include "i2s.h" #include "i2c.h" #include "gpio.h" +#include "mic_array.h" #define DEBUG_UNIT XUA_APP #define DEBUG_PRINT_ENABLE_XUA_APP 1 @@ -37,12 +38,19 @@ on tile[1]: in port p_mclk_in_usb = XS1_PORT_1A; on tile[1]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks on tile[1]: clock clk_usb_mclk = XS1_CLKBLK_3; // Master clock - // Clock-block declarations -on tile[0]:clock clk_audio_bclk = XS1_CLKBLK_2; // Bit clock -on tile[0]:clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock +on tile[0]: clock clk_audio_bclk = XS1_CLKBLK_2; // Bit clock +on tile[0]: clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock //XUD uses XS1_CLKBLK_4, XS1_CLKBLK_5 on tile[1] +//Mic array resources +on tile[0]: out port p_pdm_clk = XS1_PORT_1L; +on tile[0]: in buffered port:32 p_pdm_mics = XS1_PORT_4E; + +on tile[0]: clock pdmclk = XS1_CLKBLK_4; +on tile[0]: clock pdmclk6 = XS1_CLKBLK_5; + + // Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also // if the endpoint wishes to be informed of USB bus resets @@ -51,10 +59,12 @@ XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_aud_host); [[distributable]] -void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_aud, client i2c_master_if ?i2c, client output_gpio_if dac_reset); +void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_audio, streaming chanend (&?c_ds_output)[1]); +void setup_audio_gpio(out port p_gpio); void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); +void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics); int main() { @@ -67,17 +77,26 @@ int main() interface i2s_frame_callback_if i_i2s; interface i2c_master_if i_i2c[1]; - interface output_gpio_if i_gpio[1]; streaming chan c_audio; //We use the channel buffering (48B across switch each way) + streaming chan c_ds_output[1]; par { on tile[0]: { + //Set the GPIOs needed for audio + setup_audio_gpio(p_gpio); + c_audio <: 0; //Signal that we can now do i2c setup + c_audio :> int _; //Now wait until i2c has finished mclk setup + + const unsigned micDiv = MCLK_48/3072000; + mic_array_setup_ddr(pdmclk, pdmclk6, p_mclk_in, p_pdm_clk, p_pdm_mics, micDiv); + par { i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); - [[distribute]]AudioHub(i_i2s, c_audio, null, i_gpio[0]); - [[distribute]]output_gpio(i_gpio, 1, p_gpio, null); + [[distribute]]AudioHub(i_i2s, c_audio, c_ds_output); + pdm_mic(c_ds_output[0], p_pdm_mics); + } } on tile[1]:{ @@ -86,11 +105,13 @@ int main() set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block start_clock(clk_usb_mclk); // Set the clock off running - //Setup DAC and then return so we do not use a thread + //Setup DAC over i2c and then return so we do not use a thread + c_audio :> int _; //Wait for reset asserted from other tile to complete par{ i2c_master(i_i2c, 1, p_scl, p_sda, 100); AudioHwConfigure(DEFAULT_FREQ, i_i2c[0]); } + c_audio <: 0; //Signal to tile[0] that clock is good debug_printf("XUD SPEED: %d\n", (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS); //FS = 1, HS = 2 par{ diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 62054967..6b112863 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -5,21 +5,47 @@ #define DEBUG_UNIT XUA_AUDIO_HUB #define DEBUG_PRINT_ENABLE_XUA_AUDIO_HUB 1 #include "debug_print.h" +#include "mic_array.h" +void mic_array_decimator_set_samprate(const unsigned samplerate, int fir_gain_compen[], int * unsafe fir_coefs[], int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]); + + +void setup_audio_gpio(out port p_gpio){ + // Reset DAC and disable MUTE + p_gpio <: 0x0; + delay_milliseconds(1); + p_gpio <: 0x1; + delay_milliseconds(1); +} + + +//Globally declared for 64b alignment +int mic_decimator_fir_data_array[8][THIRD_STAGE_COEFS_PER_STAGE * PDM_MAX_DECIMATION] = {{0}}; +mic_array_frame_time_domain mic_audio_frame[2]; + [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, - streaming chanend c_audio_hub, - client i2c_master_if ?i_i2c, - client output_gpio_if dac_reset) + streaming chanend c_audio, + streaming chanend (&?c_ds_output)[1]) { int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; - // Reset DAC - dac_reset.output(0); - delay_milliseconds(1); - dac_reset.output(1); +#if XUA_NUM_PDM_MICS > 0 + unsigned buffer; + int output[XUA_NUM_PDM_MICS] = {0}; + const unsigned decimatorCount = 1; // Supports up to 4 mics + mic_array_decimator_conf_common_t dcc; + int * unsafe fir_coefs[7]; + mic_array_decimator_config_t dc[1]; + int fir_gain_compen[7]; + mic_array_frame_time_domain * unsafe current; + + mic_array_decimator_set_samprate(DEFAULT_FREQ, fir_gain_compen, fir_coefs, mic_decimator_fir_data_array[0], &dcc, dc); + mic_array_decimator_configure(c_ds_output, decimatorCount, dc); + mic_array_init_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); +#endif while (1) { @@ -42,10 +68,16 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub :> samples_out[i]; - for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio_hub <: samples_in[i]; + // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; + // for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: samples_in[i]; //tmr :> t1; debug_printf("%d\n", t1 - t0); - //delay_microseconds(10); //Test backpressure tolerance + //delay_microseconds(15); //Test backpressure tolerance + + current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); + unsafe { + samples_out[0] = current->data[0][0]; + samples_out[1] = current->data[1][0]; + } break; } } diff --git a/examples/xua_lite_example/src/pdm_mic.xc b/examples/xua_lite_example/src/pdm_mic.xc new file mode 100644 index 00000000..1bae32d9 --- /dev/null +++ b/examples/xua_lite_example/src/pdm_mic.xc @@ -0,0 +1,75 @@ +#include "xua.h" +#if (XUA_NUM_PDM_MICS > 0) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mic_array.h" + + +void mic_array_decimator_set_samprate(const unsigned samplerate, int fir_gain_compen[], int * unsafe fir_coefs[], int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]) +{ + unsigned decimationfactor = 96000/samplerate; + unsafe + { + fir_gain_compen[0] = 0; + fir_gain_compen[1] = FIR_COMPENSATOR_DIV_2; //48kHz + fir_gain_compen[2] = FIR_COMPENSATOR_DIV_4; + fir_gain_compen[3] = FIR_COMPENSATOR_DIV_6; //16kHz + fir_gain_compen[4] = FIR_COMPENSATOR_DIV_8; + fir_gain_compen[5] = 0; + fir_gain_compen[6] = FIR_COMPENSATOR_DIV_12; + + fir_coefs[0] = 0; + fir_coefs[1] = (int * unsafe)g_third_stage_div_2_fir; + fir_coefs[2] = (int * unsafe)g_third_stage_div_4_fir; + fir_coefs[3] = (int * unsafe)g_third_stage_div_6_fir; + fir_coefs[4] = (int * unsafe)g_third_stage_div_8_fir; + fir_coefs[5] = 0; + fir_coefs[6] = (int * unsafe)g_third_stage_div_12_fir; + + //dcc = {MIC_ARRAY_MAX_FRAME_SIZE_LOG2, 1, 0, 0, decimationfactor, fir_coefs[decimationfactor/2], 0, 0, DECIMATOR_NO_FRAME_OVERLAP, 2}; + dcc->frame_size_log2 = MIC_ARRAY_MAX_FRAME_SIZE_LOG2; + dcc->apply_dc_offset_removal = 1; + dcc->index_bit_reversal = 0; + dcc->windowing_function = null; + dcc->output_decimation_factor = decimationfactor; + dcc->coefs = fir_coefs[decimationfactor/2]; + dcc->apply_mic_gain_compensation = 0; + dcc->fir_gain_compensation = fir_gain_compen[decimationfactor/2]; + dcc->buffering_type = DECIMATOR_NO_FRAME_OVERLAP; + dcc->number_of_frame_buffers = 2; + + //dc[0] = {&dcc, mic_decimator_fir_data[0], {0, 0, 0, 0}, 4}; + dc[0].dcc = dcc; + dc[0].data = mic_decimator_fir_data_array; + dc[0].mic_gain_compensation[0]=0; + dc[0].mic_gain_compensation[1]=0; + dc[0].mic_gain_compensation[2]=0; + dc[0].mic_gain_compensation[3]=0; + dc[0].channel_count = 4; + } +} + +#if MAX_FREQ > 48000 +#error MAX_FREQ > 48000 NOT CURRENTLY SUPPORTED +#endif + +void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics) +{ + streaming chan c_4x_pdm_mic_0; + assert((MCLK_48 / 3072000) == (MCLK_441 / 2822400)); + par + { + mic_array_pdm_rx(p_pdm_mics, c_4x_pdm_mic_0, null); + mic_array_decimate_to_pcm_4ch(c_4x_pdm_mic_0, c_ds_output, MIC_ARRAY_NO_INTERNAL_CHANS); + + } +} +#endif diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h index 1d81b46d..d80ae813 100644 --- a/examples/xua_lite_example/src/xua_conf.h +++ b/examples/xua_lite_example/src/xua_conf.h @@ -20,15 +20,21 @@ #define PRODUCT_STR_A1 "XUA Lite Class 1" #define PID_AUDIO_1 1 #define PID_AUDIO_2 2 -#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example) */ +#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example) */ #define INPUT_FORMAT_COUNT 1 #define STREAM_FORMAT_INPUT_1_RESOLUTION_BITS 16 #define OUTPUT_FORMAT_COUNT 1 #define STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS 16 +#define OUTPUT_VOLUME_CONTROL 0 +#define INPUT_VOLUME_CONTROL 0 + #define UAC_FORCE_FEEDBACK_EP 1 -#define XUA_LITE 1 // Use simple/optimised USB buffer tasks +#define XUA_LITE 1 // Use simple/optimised USB buffer tasks #define AUDIO_CLASS 1 +#define XUA_NUM_PDM_MICS 4 // It's actually 2 but we run 4ch and ignore 2 +#define PDM_MAX_DECIMATION (96000/(MIN_FREQ)) + #endif From c0d80b665a96ebf7b44ab193552354e5a6940551 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 31 Oct 2018 13:26:30 +0000 Subject: [PATCH 023/123] Optimisations to xud select cases --- examples/xua_lite_example/src/fifo_impl.h | 33 +++++++++++++++++++ .../xua_lite_example/src/xua_buffer_lite.xc | 21 +++++++----- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/examples/xua_lite_example/src/fifo_impl.h b/examples/xua_lite_example/src/fifo_impl.h index 315b199f..181d4f18 100644 --- a/examples/xua_lite_example/src/fifo_impl.h +++ b/examples/xua_lite_example/src/fifo_impl.h @@ -43,6 +43,24 @@ static inline fifo_ret_t fifo_block_push(volatile mem_fifo_t * unsafe fifo, int } } +#pragma unsafe arrays +static inline fifo_ret_t fifo_block_push_short_pairs(volatile mem_fifo_t * unsafe fifo, short data[], unsigned n) { + unsafe{ + //check there is a block of space large enough + unsigned space_remaining = fifo->size - fifo_get_fill(fifo) - 1; + if (n > space_remaining) { + return FIFO_FULL; + } + for (int i = 0; i < n; i++){ + unsigned next_idx = fifo->write_idx + 1; + if (next_idx == fifo->size) next_idx = 0; //Check for wrap + fifo->data_base_ptr[fifo->write_idx] = data[i] << 16; + fifo->write_idx = next_idx; + } + return FIFO_SUCCESS; + } +} + #pragma unsafe arrays static inline fifo_ret_t fifo_block_pop(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { unsafe{ @@ -59,6 +77,21 @@ static inline fifo_ret_t fifo_block_pop(volatile mem_fifo_t * unsafe fifo, int d } } +#pragma unsafe arrays +static inline fifo_ret_t fifo_block_pop_short_pairs(volatile mem_fifo_t * unsafe fifo, short data[], unsigned n) { + unsafe{ + //Check we have a block big enough to send + if (n > fifo_get_fill(fifo)){ + return FIFO_EMPTY; + } + for (int i = 0; i < n; i++){ + data[i] = fifo->data_base_ptr[fifo->read_idx] >> 16; + fifo->read_idx++; + if (fifo->read_idx == fifo->size) fifo->read_idx = 0; //Check for wrap + } + return FIFO_SUCCESS; + } +} //Version of above that returns fill level relative to half full static inline int fifo_get_fill_relative_half(volatile mem_fifo_t * unsafe fifo){ diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 3a96746b..52c35969 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -30,6 +30,7 @@ #define IN_AUDIO_BUFFER_SIZE_BYTES (MAX_IN_SAMPLES_PER_SOF_PERIOD * MAX_INPUT_SLOT_SIZE) //Helper to disassemble USB packets into 32b left aligned audio samples +#pragma unsafe arrays static inline void unpack_buff_to_samples(unsigned char input[], const unsigned n_samples, const unsigned slot_size, int output[]){ switch(slot_size){ case 4: @@ -57,6 +58,7 @@ static inline void unpack_buff_to_samples(unsigned char input[], const unsigned } //Helper to assemble USB packets from 32b left aligned audio samples +#pragma unsafe arrays static inline void pack_samples_to_buff(int input[], const unsigned n_samples, const unsigned slot_size, unsigned char output[]){ switch(slot_size){ case 4: @@ -213,7 +215,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha XUD_SetReady_Out(ep0_out, sbuffer); //Send initial samples so audiohub is not blocked - for (int i = 0; i < NUM_USB_CHAN_OUT * 5; i++) outuint(c_audio_hub, 0); + for (int i = 0; i < NUM_USB_CHAN_OUT * 6; i++) c_audio_hub <: 0; //Unsafe to allow us to use fifo API @@ -260,9 +262,10 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha num_samples_received_from_host = length / out_subslot_size; //debug_printf("out samps: %d\n", num_samples_received_from_host); - unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); + //unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); - fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); + //fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, (short *)buffer_aud_out, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2f full\n"); num_samples_to_send_to_host = num_samples_received_from_host; @@ -298,16 +301,18 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha break; //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO - case inuint_byref(c_audio_hub, u_tmp): - samples_in[0] = (int)u_tmp; + case c_audio_hub :> samples_in[0]: + timer tmr; int t0, t1; tmr :> t0; + for (int i = 1; i < NUM_USB_CHAN_IN; i++){ - u_tmp = inuint(c_audio_hub); - samples_in[i] = (int)u_tmp; + c_audio_hub :> samples_in[i]; } int out_samps[NUM_USB_CHAN_OUT]; fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, out_samps, NUM_USB_CHAN_OUT); //if (ret != FIFO_SUCCESS) debug_printf("empty\n"); - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) outuint(c_audio_hub, (unsigned) out_samps[i]); + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: out_samps[i]; + tmr :> t1; debug_printf("a%d\n", t1 - t0); + break; } } From 239f9b9cb7a9b1dd1732aa44cc84bc8f380cb880 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 31 Oct 2018 14:10:28 +0000 Subject: [PATCH 024/123] Enable USB input path (from mics) --- examples/xua_lite_example/src/app_xua_lite.xc | 10 ++++----- examples/xua_lite_example/src/audio_hub.xc | 10 ++++----- examples/xua_lite_example/src/pdm_mic.xc | 2 +- .../xua_lite_example/src/xua_buffer_lite.xc | 22 ++++++++++++------- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 42806591..5a016aa4 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -96,24 +96,22 @@ int main() i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); [[distribute]]AudioHub(i_i2s, c_audio, c_ds_output); pdm_mic(c_ds_output[0], p_pdm_mics); - } } on tile[1]:{ - // Connect master-clock clock-block to clock-block pin + // Connect master-clock input clock-block to clock-block pin set_clock_src(clk_usb_mclk, p_mclk_in_usb); // Clock clock-block from mclk pin set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block start_clock(clk_usb_mclk); // Set the clock off running //Setup DAC over i2c and then return so we do not use a thread - c_audio :> int _; //Wait for reset asserted from other tile to complete + c_audio :> int _; //Wait for reset to be asserted/deasserted by other tile par{ i2c_master(i_i2c, 1, p_scl, p_sda, 100); AudioHwConfigure(DEFAULT_FREQ, i_i2c[0]); } - c_audio <: 0; //Signal to tile[0] that clock is good + c_audio <: 0; //Signal to tile[0] that mclk is now good - debug_printf("XUD SPEED: %d\n", (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS); //FS = 1, HS = 2 par{ // Low level USB device layer core XUD_Main(c_ep_out, 2, c_ep_in, 3, @@ -121,7 +119,7 @@ int main() null, null, -1 , (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); - // Buffering cores - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core + // Buffering core - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core XUA_Buffer_lite(c_ep_out[0], c_ep_in[0], c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, p_for_mclk_count, c_audio); } }//Tile[1] par diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 6b112863..faf53f5e 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -34,7 +34,7 @@ void AudioHub(server i2s_frame_callback_if i2s, #if XUA_NUM_PDM_MICS > 0 unsigned buffer; - int output[XUA_NUM_PDM_MICS] = {0}; + int raw_mics[XUA_NUM_PDM_MICS] = {0}; const unsigned decimatorCount = 1; // Supports up to 4 mics mic_array_decimator_conf_common_t dcc; int * unsafe fir_coefs[7]; @@ -68,15 +68,15 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; - // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; - // for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: samples_in[i]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; + for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: raw_mics[i]; //tmr :> t1; debug_printf("%d\n", t1 - t0); //delay_microseconds(15); //Test backpressure tolerance current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); unsafe { - samples_out[0] = current->data[0][0]; - samples_out[1] = current->data[1][0]; + raw_mics[0] = current->data[0][0]; + raw_mics[1] = current->data[1][0]; } break; } diff --git a/examples/xua_lite_example/src/pdm_mic.xc b/examples/xua_lite_example/src/pdm_mic.xc index 1bae32d9..3f2dd0ad 100644 --- a/examples/xua_lite_example/src/pdm_mic.xc +++ b/examples/xua_lite_example/src/pdm_mic.xc @@ -64,7 +64,7 @@ void mic_array_decimator_set_samprate(const unsigned samplerate, int fir_gain_co void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics) { streaming chan c_4x_pdm_mic_0; - assert((MCLK_48 / 3072000) == (MCLK_441 / 2822400)); + assert((MCLK_48 / 3072000) == (MCLK_441 / 2822400)); //Make sure mic clock is achievable from MCLK par { mic_array_pdm_rx(p_pdm_mics, c_4x_pdm_mic_0, null); diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 52c35969..660ac996 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -195,9 +195,8 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha unsigned num_samples_received_from_host = 0; unsigned num_samples_to_send_to_host = 0; - int loopback_samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD] = {0}; - int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; - int32_t samples_in[NUM_USB_CHAN_IN] = {0}; + int samples_out[NUM_USB_CHAN_OUT] = {0}; + int samples_in[NUM_USB_CHAN_IN] = {0}; #define c_audioControl null #define dfuInterface null @@ -221,9 +220,13 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //Unsafe to allow us to use fifo API unsafe{ + //FIFOs from EP buffers to audio int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; + int device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; + mem_fifo_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + volatile mem_fifo_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; //XUD transaction variables passed in by reference XUD_Result_t result; @@ -266,7 +269,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, (short *)buffer_aud_out, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("h2f full\n"); + if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; //Mark EP as ready for next frame from host @@ -289,8 +292,11 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha case XUD_SetData_Select(c_aud_in, ep_aud_in, result): timer tmr; int t0, t1; tmr :> t0; + fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, (short *)buffer_aud_in, num_samples_received_from_host); + if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); + //Populate the input buffer ready for the next read - pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); + //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); //Use the number of samples we received last time so we are always balanced (assumes same in/out count) unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; @@ -307,11 +313,11 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha for (int i = 1; i < NUM_USB_CHAN_IN; i++){ c_audio_hub :> samples_in[i]; } - int out_samps[NUM_USB_CHAN_OUT]; - fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, out_samps, NUM_USB_CHAN_OUT); + fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); //if (ret != FIFO_SUCCESS) debug_printf("empty\n"); - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: out_samps[i]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; tmr :> t1; debug_printf("a%d\n", t1 - t0); + ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); break; } From 9be45c7e89865c5eeb093b93ec3036c9bfba44af Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 31 Oct 2018 14:43:03 +0000 Subject: [PATCH 025/123] Add burn threads --- examples/xua_lite_example/src/app_xua_lite.xc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 5a016aa4..7dbd3dd0 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -66,6 +66,15 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCo chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics); +void burn_normal_priority(void){ + while(1); +} + +void burn_high_priority(void){ + set_core_high_priority_on(); + while(1); +} + int main() { // Channels for lib_xud @@ -84,7 +93,7 @@ int main() par { on tile[0]: { - //Set the GPIOs needed for audio + //Set the GPIOs needed for audio (reset and mute) setup_audio_gpio(p_gpio); c_audio <: 0; //Signal that we can now do i2c setup c_audio :> int _; //Now wait until i2c has finished mclk setup @@ -96,6 +105,9 @@ int main() i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); [[distribute]]AudioHub(i_i2s, c_audio, c_ds_output); pdm_mic(c_ds_output[0], p_pdm_mics); + + par (int i = 0; i < 5; i++) burn_normal_priority(); + par (int i = 0; i < 0; i++) burn_high_priority(); } } on tile[1]:{ @@ -121,6 +133,9 @@ int main() // Buffering core - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core XUA_Buffer_lite(c_ep_out[0], c_ep_in[0], c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, p_for_mclk_count, c_audio); + + par (int i = 0; i < 4; i++) burn_normal_priority(); + par (int i = 0; i < 2; i++) burn_high_priority(); } }//Tile[1] par }//Top level par From 90d1a60595eb696c97305651a51c720b9cf2c80b Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 31 Oct 2018 14:43:58 +0000 Subject: [PATCH 026/123] Remove unnecessary arguments --- examples/xua_lite_example/src/audio_hub.xc | 6 ++---- examples/xua_lite_example/src/pdm_mic.xc | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index faf53f5e..5382ec94 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -8,7 +8,7 @@ #include "mic_array.h" -void mic_array_decimator_set_samprate(const unsigned samplerate, int fir_gain_compen[], int * unsafe fir_coefs[], int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]); +void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]); void setup_audio_gpio(out port p_gpio){ @@ -37,12 +37,10 @@ void AudioHub(server i2s_frame_callback_if i2s, int raw_mics[XUA_NUM_PDM_MICS] = {0}; const unsigned decimatorCount = 1; // Supports up to 4 mics mic_array_decimator_conf_common_t dcc; - int * unsafe fir_coefs[7]; mic_array_decimator_config_t dc[1]; - int fir_gain_compen[7]; mic_array_frame_time_domain * unsafe current; - mic_array_decimator_set_samprate(DEFAULT_FREQ, fir_gain_compen, fir_coefs, mic_decimator_fir_data_array[0], &dcc, dc); + mic_array_decimator_set_samprate(DEFAULT_FREQ, mic_decimator_fir_data_array[0], &dcc, dc); mic_array_decimator_configure(c_ds_output, decimatorCount, dc); mic_array_init_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); #endif diff --git a/examples/xua_lite_example/src/pdm_mic.xc b/examples/xua_lite_example/src/pdm_mic.xc index 3f2dd0ad..eb6227d1 100644 --- a/examples/xua_lite_example/src/pdm_mic.xc +++ b/examples/xua_lite_example/src/pdm_mic.xc @@ -13,9 +13,11 @@ #include "mic_array.h" -void mic_array_decimator_set_samprate(const unsigned samplerate, int fir_gain_compen[], int * unsafe fir_coefs[], int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]) +void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]) { unsigned decimationfactor = 96000/samplerate; + int fir_gain_compen[7]; + int * unsafe fir_coefs[7]; unsafe { fir_gain_compen[0] = 0; From c352a08c55d9ea9a66a38e20092fdea49ed23265 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 31 Oct 2018 14:45:16 +0000 Subject: [PATCH 027/123] Send fixed number of samples when no output stream (not correct for asynch) --- examples/xua_lite_example/src/audio_hub.xc | 6 ++++-- examples/xua_lite_example/src/xua_buffer_lite.xc | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 5382ec94..562731f0 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -63,19 +63,21 @@ void AudioHub(server i2s_frame_callback_if i2s, for (int i = 0; i < n_chans; i++) out_samps[i] = samples_out[i]; break; + //Exchange samples with mics & host case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: raw_mics[i]; - //tmr :> t1; debug_printf("%d\n", t1 - t0); - //delay_microseconds(15); //Test backpressure tolerance + //Grab mics current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); unsafe { raw_mics[0] = current->data[0][0]; raw_mics[1] = current->data[1][0]; } + //tmr :> t1; debug_printf("%d\n", t1 - t0); + delay_microseconds(15); //Test backpressure tolerance break; } } diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 660ac996..be3bb1bf 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -292,6 +292,8 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha case XUD_SetData_Select(c_aud_in, ep_aud_in, result): timer tmr; int t0, t1; tmr :> t0; + if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; + fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, (short *)buffer_aud_in, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); @@ -314,11 +316,11 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha c_audio_hub :> samples_in[i]; } fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); - //if (ret != FIFO_SUCCESS) debug_printf("empty\n"); + if (ret != FIFO_SUCCESS && output_interface_num) debug_printf("h2s empty\n"); for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; tmr :> t1; debug_printf("a%d\n", t1 - t0); ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); - + if (ret != FIFO_SUCCESS && input_interface_num) debug_printf("d2h full\n"); break; } } From a49aad644e3475a38bf2d8dc73a83ede48877e1b Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 5 Nov 2018 10:05:39 +0000 Subject: [PATCH 028/123] Manuallay apply adaptive descriptors from asrc_usb branch --- .../src/core/endpoint0/xua_ep0_descriptors.h | 75 ++++++++++++++----- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index b8d02afd..5e1b6464 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -28,6 +28,12 @@ #define STR_TABLE_ENTRY(name) char *name +#define ISO_EP_ATTRIBUTES_ASYNCH 0x05 //ISO, ASYNCH, DATA EP +#define ISO_EP_ATTRIBUTES_ADAPTIVE 0x09 //ISO, ADAPTIVE, DATA EP +#define ISO_EP_IMPL_ATTRIBUTES_ASYNCH 0x25 //ISO, ASYNCH, IMPLICIT FB DATA EP +#define ISO_EP_IMPL_ATTRIBUTES_ADAPTIVE 0x29 //ISO, ADAPTIVE, IMPLICIT FB DATA EP + + #if __STDC__ typedef struct { @@ -1448,7 +1454,11 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bLength = sizeof(USB_Descriptor_Endpoint_t), .bDescriptorType = USB_DESCTYPE_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_OUT_AUDIO, - .bmAttributes = 0x05, /* (bitmap) */ +#ifdef XUA_ADAPTIVE + .bmAttributes = ISO_EP_ATTRIBUTES_ADAPTIVE, /* (bitmap) */ +#else + .bmAttributes = ISO_EP_ATTRIBUTES_ASYNCH, /* (bitmap) */ +#endif .wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE, .bInterval = 1, }, @@ -1526,7 +1536,11 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bLength = sizeof(USB_Descriptor_Endpoint_t), .bDescriptorType = USB_DESCTYPE_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_OUT_AUDIO, - .bmAttributes = 0x05, +#ifdef XUA_ADAPTIVE + .bmAttributes = ISO_EP_ATTRIBUTES_ADAPTIVE, /* (bitmap) */ +#else + .bmAttributes = ISO_EP_ATTRIBUTES_ASYNCH, /* (bitmap) */ +#endif .wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE, .bInterval = 1, }, @@ -1606,8 +1620,11 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bLength = 0x07, .bDescriptorType = USB_DESCTYPE_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_OUT_AUDIO, - .bmAttributes = 0x05, - .wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE, +#ifdef XUA_ADAPTIVE + .bmAttributes = ISO_EP_ATTRIBUTES_ADAPTIVE, /* (bitmap) */ +#else + .bmAttributes = ISO_EP_ATTRIBUTES_ASYNCH, /* (bitmap) */ +#endif .wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE, .bInterval = 1, }, @@ -1700,9 +1717,13 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bDescriptorType = USB_DESCTYPE_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_IN_AUDIO, #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) - .bmAttributes = 0x05, /* Iso, async, data endpoint */ + .bmAttributes = ISO_EP_ATTRIBUTES_ASYNCH, /* Iso, async, data endpoint */ #else - .bmAttributes = 0x25, /* Iso, async, implicit feedback data endpoint */ + #ifdef XUA_ADAPTIVE + .bmAttributes = ISO_EP_ATTRIBUTES_ADAPTIVE, + #else + .bmAttributes = ISO_EP_IMPL_ATTRIBUTES_ASYNCH, /* Feedback data endpoint */ + #endif #endif .wMaxPacketSize = HS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE, .bInterval = 0x01, @@ -1768,9 +1789,13 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bDescriptorType = USB_DESCTYPE_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_IN_AUDIO, #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) - .bmAttributes = 0x05, /* Iso, async, data endpoint */ + .bmAttributes = ISO_EP_ATTRIBUTES_ASYNCH, /* Iso, async, data endpoint */ #else - .bmAttributes = 0x25, /* Iso, async, implicit feedback data endpoint */ + #ifdef XUA_ADAPTIVE + .bmAttributes = ISO_EP_ATTRIBUTES_ADAPTIVE, + #else + .bmAttributes = ISO_EP_IMPL_ATTRIBUTES_ASYNCH, /* Feedback data endpoint */ + #endif #endif .wMaxPacketSize = HS_STREAM_FORMAT_INPUT_2_MAXPACKETSIZE, .bInterval = 0x01, @@ -1837,9 +1862,13 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bDescriptorType = USB_DESCTYPE_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_IN_AUDIO, #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) - .bmAttributes = 0x05, /* Iso, async, data endpoint */ + .bmAttributes = ISO_EP_ATTRIBUTES_ASYNCH, /* Iso, async, data endpoint */ #else - .bmAttributes = 0x25, /* Iso, async, implicit feedback data endpoint */ + #ifdef XUA_ADAPTIVE + .bmAttributes = ISO_EP_ATTRIBUTES_ADAPTIVE, + #else + .bmAttributes = ISO_EP_IMPL_ATTRIBUTES_ASYNCH, /* Feedback data endpoint */ + #endif #endif .wMaxPacketSize = HS_STREAM_FORMAT_INPUT_3_MAXPACKETSIZE, .bInterval = 0x01, @@ -2599,15 +2628,23 @@ unsigned char cfgDesc_Audio1[] = 0x09, 0x05, /* ENDPOINT */ 0x01, /* endpointAddress - D7, direction (0 OUT, 1 IN). D6..4 reserved (0). D3..0 endpoint no. */ - 0x05, /* attributes - isochronous async */ +#ifdef XUA_ADAPTIVE + ISO_EP_ATTRIBUTES_ADAPTIVE, +#else + ISO_EP_ATTRIBUTES_ASYNCH, +#endif (FS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE&0xff), /* 4 wMaxPacketSize (Typically 294 bytes)*/ (FS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE&0xff00)>>8, /* 5 wMaxPacketSize */ 0x01, /* bInterval */ - 0x00, /* bRefresh */ + 0x00, /* bRefresh */ #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) ENDPOINT_ADDRESS_IN_FEEDBACK, /* bSynchAdddress - address of EP used to communicate sync info */ +#else /* Bi-directional in/out device */ +#ifdef XUA_ADAPTIVE + 0, /* OUT */ #else ENDPOINT_ADDRESS_IN_AUDIO, +#endif #endif /* CS_Endpoint Descriptor ?? */ @@ -2616,7 +2653,7 @@ unsigned char cfgDesc_Audio1[] = 0x01, /* subtype - GENERAL */ 0x01, /* attributes. D[0]: sample freq ctrl. */ 0x02, /* bLockDelayUnits */ - 0x00, 0x00, /* bLockDelay */ + 0x08, 0x00, /* bLockDelay */ #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) /* Feedback EP */ @@ -2728,9 +2765,13 @@ unsigned char cfgDesc_Audio1[] = 0x05, /* ENDPOINT */ ENDPOINT_ADDRESS_IN_AUDIO, /* EndpointAddress */ #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) - 0x05, /* Iso, async, data endpoint */ + ISO_EP_ATTRIBUTES_ASYNCH, /* Iso, async, data endpoint */ #else - 0x25, /* Iso, async, implicit feedback data endpoint */ + #ifdef XUA_ADAPTIVE + ISO_EP_ATTRIBUTES_ADAPTIVE, + #else + ISO_EP_IMPL_ATTRIBUTES_ASYNCH, /* Feedback data endpoint */ + #endif #endif FS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE&0xff, /* 4 wMaxPacketSize (Typically 294 bytes)*/ (FS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE&0xff00)>>8, /* 5 wMaxPacketSize */ @@ -2743,8 +2784,8 @@ unsigned char cfgDesc_Audio1[] = 0x25, /* CS_ENDPOINT */ 0x01, /* Subtype - GENERAL */ 0x01, /* Attributes. D[0]: sample freq ctrl. */ - 0x00, /* Unused */ - 0x00, 0x00, /* Unused */ + 0x02, /* Lock Delay units PCM samples*/ + 0x08, 0x00, /* No lock delay */ #endif #if (XUA_DFU_EN == 1) && (FORCE_UAC1_DFU == 1) From 05f16da222513824862874abd3474841a78821ab Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 5 Nov 2018 10:06:13 +0000 Subject: [PATCH 029/123] Minor tidy and todo.txt update --- examples/xua_lite_example/src/app_xua_lite.xc | 1 - examples/xua_lite_example/src/audio_hub.xc | 1 - .../xua_lite_example/src/xua_buffer_lite.xc | 18 ++++++------- examples/xua_lite_example/todo.txt | 25 +++++++++++++------ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 7dbd3dd0..0b7e38da 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -10,7 +10,6 @@ #include "xud.h" #include "i2s.h" #include "i2c.h" -#include "gpio.h" #include "mic_array.h" #define DEBUG_UNIT XUA_APP diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 562731f0..9516c262 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -1,6 +1,5 @@ #include "i2s.h" #include "i2c.h" -#include "gpio.h" #include "xua.h" #define DEBUG_UNIT XUA_AUDIO_HUB #define DEBUG_PRINT_ENABLE_XUA_AUDIO_HUB 1 diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index be3bb1bf..2b684fb5 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -243,7 +243,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); XUD_SetReady_Out(ep0_out, sbuffer); - tmr :> t1; debug_printf("c%d\n", t1 - t0); + //tmr :> t1; debug_printf("c%d\n", t1 - t0); break; @@ -254,7 +254,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); sof_count++; - tmr :> t1; debug_printf("s%d\n", t1 - t0); + //tmr :> t1; debug_printf("s%d\n", t1 - t0); break; @@ -263,18 +263,14 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha timer tmr; int t0, t1; tmr :> t0; num_samples_received_from_host = length / out_subslot_size; - //debug_printf("out samps: %d\n", num_samples_received_from_host); - - //unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); - - //fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, (short *)buffer_aud_out, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); - tmr :> t1; debug_printf("o%d\n", t1 - t0); + //tmr :> t1; debug_printf("o%d\n", t1 - t0); break; @@ -284,7 +280,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); //debug_printf("0x%x\n", fb_clocks[0]); - tmr :> t1; debug_printf("f%d\n", t1 - t0); + //tmr :> t1; debug_printf("f%d\n", t1 - t0); break; @@ -304,7 +300,7 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback num_samples_to_send_to_host = 0; - tmr :> t1; debug_printf("i%d\n", t1 - t0); + //tmr :> t1; debug_printf("i%d\n", t1 - t0); break; @@ -318,9 +314,9 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); if (ret != FIFO_SUCCESS && output_interface_num) debug_printf("h2s empty\n"); for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; - tmr :> t1; debug_printf("a%d\n", t1 - t0); ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); if (ret != FIFO_SUCCESS && input_interface_num) debug_printf("d2h full\n"); + //tmr :> t1; debug_printf("a%d\n", t1 - t0); break; } } diff --git a/examples/xua_lite_example/todo.txt b/examples/xua_lite_example/todo.txt index 705b1cf9..4a0fe729 100644 --- a/examples/xua_lite_example/todo.txt +++ b/examples/xua_lite_example/todo.txt @@ -1,8 +1,17 @@ -- Bring ep0 serivice into xua_buffer select (make control mem) -- Tidy feeback endpoint -- Input path + FIFO -- Single input/ouput format -- Get UAC1 / FS working -- Add timer to xua_buffer to prepare for exchange with audio (remove banckpressure to audio) -- Adaptive -- DFU \ No newline at end of file +- Bring ep0 serivice into xua_buffer select (make control mem) (DONE) +- Tidy feeback endpoint (DONE) +- Input path + FIFO (DONE) +- Function prototypes into includes +- Single input/ouput format (DONE) +- Get UAC1 / FS working (DONE) +- Optimised EP buffer (either triple block or block FIFO) +- Fix output gain issue +- Add timer to xua_buffer to prepare for exchange with audio (remove backpressure to audio) (WONT DO) +- Adaptive endpoint EP and descriptors +- Adpative clock control +- Switchable MICS using define +- DFU +- Combinable EP0 +- Interrupt EP0 option +- Control processing + From 0709860f48966181d027cd8b76910909c2301ffa Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 5 Nov 2018 11:14:03 +0000 Subject: [PATCH 030/123] Ensure behaviour is correct when UAC_FORCE_FEEDBACK_EP and XUA_ADAPTIVE features defined as 0 --- lib_xua/api/xua_conf_default.h | 4 ++++ lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index d2908342..677fad9e 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -1158,6 +1158,10 @@ #endif +#if (defined(UAC_FORCE_FEEDBACK_EP) && UAC_FORCE_FEEDBACK_EP == 0) +#undef UAC_FORCE_FEEDBACK_EP +#endif + #ifndef __ASSEMBLER__ /* Endpoint addresses enums */ enum USBEndpointNumber_In diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 5e1b6464..a0a8703f 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -33,6 +33,9 @@ #define ISO_EP_IMPL_ATTRIBUTES_ASYNCH 0x25 //ISO, ASYNCH, IMPLICIT FB DATA EP #define ISO_EP_IMPL_ATTRIBUTES_ADAPTIVE 0x29 //ISO, ADAPTIVE, IMPLICIT FB DATA EP +#if (defined(XUA_ADAPTIVE) && (XUA_ADAPTIVE == 0)) +#undef XUA_ADAPTIVE +#endif #if __STDC__ typedef struct From 3214d4ea9ff89954075e7ccd64838dd890c694bc Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 5 Nov 2018 11:16:21 +0000 Subject: [PATCH 031/123] Remove magic numbers from endpoint numbers so switch between asynch/adaptive handled --- examples/xua_lite_example/src/app_xua_lite.xc | 15 ++++++++++----- examples/xua_lite_example/src/xua_buffer_lite.xc | 12 +++++++----- examples/xua_lite_example/src/xua_conf.h | 3 ++- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 0b7e38da..d33daf09 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -56,7 +56,7 @@ on tile[0]: clock pdmclk6 = XS1_CLKBLK_5; XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO}; XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO}; -void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_aud_host); +void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_aud_host); [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_audio, streaming chanend (&?c_ds_output)[1]); void setup_audio_gpio(out port p_gpio); @@ -77,8 +77,8 @@ void burn_high_priority(void){ int main() { // Channels for lib_xud - chan c_ep_out[2]; - chan c_ep_in[3]; + chan c_ep_out[XUA_ENDPOINT_COUNT_OUT]; + chan c_ep_in[XUA_ENDPOINT_COUNT_IN]; // Channel for communicating SOF notifications from XUD to the Buffering cores chan c_sof; @@ -125,13 +125,18 @@ int main() par{ // Low level USB device layer core - XUD_Main(c_ep_out, 2, c_ep_in, 3, + XUD_Main(c_ep_out, XUA_ENDPOINT_COUNT_OUT, c_ep_in, XUA_ENDPOINT_COUNT_IN, c_sof, epTypeTableOut, epTypeTableIn, null, null, -1 , (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); // Buffering core - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core - XUA_Buffer_lite(c_ep_out[0], c_ep_in[0], c_ep_out[1], c_ep_in[1], c_ep_in[2], c_sof, p_for_mclk_count, c_audio); + XUA_Buffer_lite(c_ep_out[0], + c_ep_in[0], + c_ep_out[1], + null, //c_ep_in[XUA_ENDPOINT_COUNT_IN - 2],/*feedback*/ + c_ep_in[XUA_ENDPOINT_COUNT_IN - 1], + c_sof, p_for_mclk_count, c_audio); par (int i = 0; i < 4; i++) burn_normal_priority(); par (int i = 0; i < 2; i++) burn_high_priority(); diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 2b684fb5..adda73c4 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -169,7 +169,7 @@ extern XUD_ep ep0_out; extern XUD_ep ep0_in; -void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { +void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); @@ -189,8 +189,9 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); - XUD_ep ep_feedback = XUD_InitEp(c_feedback); XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); + XUD_ep ep_feedback = 0; + if (!isnull(c_feedback)) ep_feedback = XUD_InitEp(c_feedback); unsigned num_samples_received_from_host = 0; unsigned num_samples_to_send_to_host = 0; @@ -210,8 +211,9 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //Enable all EPs XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); - XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); XUD_SetReady_Out(ep0_out, sbuffer); + if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); + //Send initial samples so audiohub is not blocked for (int i = 0; i < NUM_USB_CHAN_OUT * 6; i++) c_audio_hub <: 0; @@ -274,8 +276,8 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha break; - //Send asynch explicit feedback value - case XUD_SetData_Select(c_feedback, ep_feedback, result): + //Send asynch explicit feedback value, but only if enabled + case !isnull(c_feedback) => XUD_SetData_Select(c_feedback, ep_feedback, result): timer tmr; int t0, t1; tmr :> t0; XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h index d80ae813..62274619 100644 --- a/examples/xua_lite_example/src/xua_conf.h +++ b/examples/xua_lite_example/src/xua_conf.h @@ -30,7 +30,8 @@ #define OUTPUT_VOLUME_CONTROL 0 #define INPUT_VOLUME_CONTROL 0 -#define UAC_FORCE_FEEDBACK_EP 1 +#define UAC_FORCE_FEEDBACK_EP 0 +#define XUA_ADAPTIVE 1 #define XUA_LITE 1 // Use simple/optimised USB buffer tasks #define AUDIO_CLASS 1 From c662acaa3b8a2f2252a006d3c4075d14de85e481 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Mon, 5 Nov 2018 13:46:01 +0000 Subject: [PATCH 032/123] WIP Adaptive with PLL nudge (demo working) --- examples/xua_lite_example/src/AudioConfig.h | 11 +-- examples/xua_lite_example/src/AudioConfig.xc | 75 ++++++++++++++++--- examples/xua_lite_example/src/app_xua_lite.xc | 6 +- examples/xua_lite_example/src/audio_hub.xc | 12 ++- examples/xua_lite_example/src/pdm_mic.xc | 32 ++++++++ .../xua_lite_example/src/xua_buffer_lite.xc | 34 ++++++++- 6 files changed, 144 insertions(+), 26 deletions(-) diff --git a/examples/xua_lite_example/src/AudioConfig.h b/examples/xua_lite_example/src/AudioConfig.h index 9843cb1d..a4fe9270 100755 --- a/examples/xua_lite_example/src/AudioConfig.h +++ b/examples/xua_lite_example/src/AudioConfig.h @@ -1,15 +1,8 @@ #ifndef _AUDIO_CONFIG_ #define _AUDIO_CONFIG_ -void ConfigAudioPorts(unsigned divide); +void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); +void pll_nudge(int nudge); -void AudioHwInit(); - -void PLL_Init(void); - -/* Configures master clock and codc for passed sample freq */ -void AudioHwConfig(unsigned samFreq); - -void ConfigCodec24576(unsigned samFeq); #endif diff --git a/examples/xua_lite_example/src/AudioConfig.xc b/examples/xua_lite_example/src/AudioConfig.xc index acf1cb9e..a1dde227 100755 --- a/examples/xua_lite_example/src/AudioConfig.xc +++ b/examples/xua_lite_example/src/AudioConfig.xc @@ -4,7 +4,10 @@ #include #include #include "i2c.h" - +#include "xua.h" +#define DEBUG_UNIT AUDIO_CFG +#define DEBUG_PRINT_ENABLE_AUDIO_CFG 1 +#include "debug_print.h" // TLV320DAC3101 Device I2C Address @@ -45,16 +48,39 @@ #define DAC3101_SPKR_DRVR 0x2B // Register 43 - Right Class-D Speaker Driver // TLV320DAC3101 easy register access defines -//#define DAC3101_REGREAD(reg, data) {data[0] = 0xAA; i2c_master_read_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);} -//#define DAC3101_REGWRITE(reg, val) {data[0] = val; i2c_master_write_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);} - -//#define DAC3101_REGWRITE(reg, val) {i_i2c[0].write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);} - -// TLV320DAC3101 easy register access defines -//#define DAC3101_REGWRITE(reg, val) {data[0] = val; i2c_master_write_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);} #define DAC3101_REGWRITE(reg, val) {i_i2c.write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);} + +static void set_node_pll_reg(tileref tile_ref, unsigned reg_val){ + write_sswitch_reg(get_tile_id(tile_ref), XS1_SSWITCH_PLL_CTL_NUM, reg_val); +} + +// Nominal setting is ref div = 25, fb_div = 1024, op_div = 2 +// PCF Freq 0.96MHz + +enum clock_nudge{ + PLL_SLOWER = -1, + PLL_NOMINAL = 0, + PLL_FASTER = 1 +}; + +#define PLL_LOW 0xC003FE18 // This is 3.069MHz +#define PLL_NOM 0xC003FF18 // This is 3.072MHz +#define PLL_HIGH 0xC0040018 // This is 3.075MHz + +int old_nudge = 0; +void pll_nudge(int nudge) { + if (nudge > 0){ + set_node_pll_reg(tile[0], PLL_HIGH); + } + else if (nudge < 0){ + set_node_pll_reg(tile[0], PLL_LOW); + } + set_node_pll_reg(tile[0], PLL_NOM); + if(nudge != old_nudge && nudge){debug_printf("nudge: %d\n", nudge); }old_nudge = nudge; +} + void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) { @@ -101,6 +127,34 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) // DAC_MOD_CLK = DAC_CLK / 4 = 5.6448MHz. // DAC_FS = DAC_MOD_CLK / 128 = 44.1kHz. +#if XUA_ADAPTIVE + //Set nominal clock speed on PLL + write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_NOM); + + // We are assuming 48kHz family only and we generate MCLK + // Set PLL J Value to 7 + DAC3101_REGWRITE(DAC3101_PLL_J, 0x07); + // Set PLL D to 0 ... + // Set PLL D MSB Value to 0x00 + DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x07); + // Set PLL D LSB Value to 0x00 + DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x80); + + delay_milliseconds(1); + + // Set PLL_CLKIN = BCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) + DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x07); + + // Set PLL P and R values and power up. + DAC3101_REGWRITE(DAC3101_PLL_P_R, 0x94); + // Set NDAC clock divider to 2 and power up. + DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x82); + // Set MDAC clock divider to 7 and power up. + DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x87); + // Set OSR clock divider to 128. + DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80); + +#else /* Sample frequency dependent register settings */ if ((samFreq % 11025) == 0) { @@ -143,7 +197,9 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x84); // Set OSR clock divider to 128. DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80); - + +#endif + // Set CLKOUT Mux to DAC_CLK DAC3101_REGWRITE(DAC3101_CLKOUT_MUX, 0x04); // Set CLKOUT M divider to 1 and power up. @@ -205,6 +261,7 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) i_i2c.shutdown(); } + //These are here just to silence compiler warnings void AudioHwInit(){} void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC){} \ No newline at end of file diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index d33daf09..94115c54 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -64,6 +64,7 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics); +void mic_array_setup_ddr_xcore(clock pdmclk, clock pdmclk6, out port p_pdm_clk, buffered in port:32 p_pdm_data, int divide); void burn_normal_priority(void){ while(1); @@ -98,7 +99,8 @@ int main() c_audio :> int _; //Now wait until i2c has finished mclk setup const unsigned micDiv = MCLK_48/3072000; - mic_array_setup_ddr(pdmclk, pdmclk6, p_mclk_in, p_pdm_clk, p_pdm_mics, micDiv); + if (XUA_ADAPTIVE) mic_array_setup_ddr_xcore(pdmclk, pdmclk6, p_pdm_clk, p_pdm_mics, micDiv); + else mic_array_setup_ddr(pdmclk, pdmclk6, p_mclk_in, p_pdm_clk, p_pdm_mics, micDiv); par { i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); @@ -110,7 +112,7 @@ int main() } } on tile[1]:{ - // Connect master-clock input clock-block to clock-block pin + // Connect master-clock input clock-block to clock-block pin for asnch feedback calculation set_clock_src(clk_usb_mclk, p_mclk_in_usb); // Clock clock-block from mclk pin set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block start_clock(clk_usb_mclk); // Set the clock off running diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 9516c262..42c1cdd9 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -5,6 +5,7 @@ #define DEBUG_PRINT_ENABLE_XUA_AUDIO_HUB 1 #include "debug_print.h" #include "mic_array.h" +#include "AudioConfig.h" void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]); @@ -31,6 +32,8 @@ void AudioHub(server i2s_frame_callback_if i2s, int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; + int32_t clock_nudge = 0; + #if XUA_NUM_PDM_MICS > 0 unsigned buffer; int raw_mics[XUA_NUM_PDM_MICS] = {0}; @@ -66,8 +69,9 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; - for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: raw_mics[i]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; + if (XUA_ADAPTIVE) c_audio :> clock_nudge; + for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: raw_mics[i]; //Grab mics current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); @@ -75,8 +79,10 @@ void AudioHub(server i2s_frame_callback_if i2s, raw_mics[0] = current->data[0][0]; raw_mics[1] = current->data[1][0]; } + + pll_nudge(clock_nudge); //tmr :> t1; debug_printf("%d\n", t1 - t0); - delay_microseconds(15); //Test backpressure tolerance + //delay_microseconds(10); //Test backpressure tolerance break; } } diff --git a/examples/xua_lite_example/src/pdm_mic.xc b/examples/xua_lite_example/src/pdm_mic.xc index eb6227d1..bc2fd263 100644 --- a/examples/xua_lite_example/src/pdm_mic.xc +++ b/examples/xua_lite_example/src/pdm_mic.xc @@ -74,4 +74,36 @@ void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics) } } + +void mic_array_setup_ddr_xcore(clock pdmclk, + clock pdmclk6, + out port p_pdm_clk, + buffered in port:32 p_pdm_data, + int divide) { + configure_clock_xcore(pdmclk, 80); + //configure_clock_src_divide(pdmclk, p_mclk, divide/2); + + configure_clock_xcore(pdmclk6, 40); + //configure_clock_src_divide(pdmclk6, p_mclk, divide/4); + + configure_port_clock_output(p_pdm_clk, pdmclk); + configure_in_port(p_pdm_data, pdmclk6); + + /* start the faster capture clock */ + start_clock(pdmclk6); + /* wait for a rising edge on the capture clock */ + partin(p_pdm_data, 4); + /* start the slower output clock */ + start_clock(pdmclk); + + /* + * this results in the rising edge of the capture clock + * leading the rising edge of the output clock by one period + * of p_mclk, which is about 40.7 ns for the typical frequency + * of 24.576 megahertz. + * This should fall within the data valid window. + */ + +} + #endif diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index adda73c4..03c832e2 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -155,6 +155,27 @@ void do_feedback_calculation(unsigned &sof_count } } +void fill_level_process(int fill_level, int &clock_nudge){ + const int trigger_high_upper = 6; + const int trigger_high_lower = 8; + + const int trigger_low_upper = -6; + const int trigger_low_lower = -8; + + if (fill_level >= trigger_high_upper){ + clock_nudge = 1; + //debug_printf("Nudge down\n"); + } + else if (fill_level <= trigger_low_upper){ + //debug_printf("Nudge up\n"); + clock_nudge = -1; + } + else clock_nudge = 0; + //debug_printf("%d\n", clock_nudge); + + static unsigned counter; counter++; if (counter>SOF_FREQ_HZ){counter = 0; debug_printf("f: %d\n",fill_level);} +} + extern "C"{ void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, @@ -187,7 +208,10 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha const unsigned mclk_hz = MCLK_48; unsigned int fb_clocks[1] = {0}; - + //Adapative device clock control + int clock_nudge = 0; + + //Endpoints XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); XUD_ep ep_feedback = 0; @@ -270,6 +294,9 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; + int fill_level = fifo_get_fill_relative_half(host_to_device_fifo_ptr); + fill_level_process(fill_level, clock_nudge); + //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); //tmr :> t1; debug_printf("o%d\n", t1 - t0); @@ -314,10 +341,11 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha c_audio_hub :> samples_in[i]; } fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); - if (ret != FIFO_SUCCESS && output_interface_num) debug_printf("h2s empty\n"); + if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; + if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); - if (ret != FIFO_SUCCESS && input_interface_num) debug_printf("d2h full\n"); + if (ret != FIFO_SUCCESS && input_interface_num != 0) debug_printf("d2h full\n"); //tmr :> t1; debug_printf("a%d\n", t1 - t0); break; } From 54f42a37feea6455a7d4140ac6e49ad7f7136092 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Tue, 6 Nov 2018 14:37:47 +0000 Subject: [PATCH 033/123] Add visual indication for PLL nudge --- examples/xua_lite_example/src/AudioConfig.xc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/xua_lite_example/src/AudioConfig.xc b/examples/xua_lite_example/src/AudioConfig.xc index a1dde227..fc9efad0 100755 --- a/examples/xua_lite_example/src/AudioConfig.xc +++ b/examples/xua_lite_example/src/AudioConfig.xc @@ -69,13 +69,21 @@ enum clock_nudge{ #define PLL_NOM 0xC003FF18 // This is 3.072MHz #define PLL_HIGH 0xC0040018 // This is 3.075MHz +on tile[0]: out port p_leds = XS1_PORT_4F; + int old_nudge = 0; void pll_nudge(int nudge) { if (nudge > 0){ set_node_pll_reg(tile[0], PLL_HIGH); + p_leds <: 0xf; } else if (nudge < 0){ set_node_pll_reg(tile[0], PLL_LOW); + p_leds <: 0xf; + + } + else { + p_leds <: 0x0; } set_node_pll_reg(tile[0], PLL_NOM); if(nudge != old_nudge && nudge){debug_printf("nudge: %d\n", nudge); }old_nudge = nudge; From 409da256d68d12e426a4b12dd3b2b189b1afa8a8 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Tue, 6 Nov 2018 14:38:15 +0000 Subject: [PATCH 034/123] Always parse SP for EP0 --- examples/xua_lite_example/src/xua_buffer_lite.xc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 03c832e2..1eb91963 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -264,9 +264,9 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): timer tmr; int t0, t1; tmr :> t0; - if (result == XUD_RES_OKAY) USB_ParseSetupPacket(sbuffer, sp); //Parse data buffer end populate SetupPacket struct - //debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error - + debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error + USB_ParseSetupPacket(sbuffer, sp); //Parse data buffer end populate SetupPacket struct + XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); XUD_SetReady_Out(ep0_out, sbuffer); //tmr :> t1; debug_printf("c%d\n", t1 - t0); @@ -300,7 +300,6 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); //tmr :> t1; debug_printf("o%d\n", t1 - t0); - break; //Send asynch explicit feedback value, but only if enabled From a72885634d18d12e18995c7f2de85141a1626608 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Tue, 6 Nov 2018 14:38:31 +0000 Subject: [PATCH 035/123] Work around for I2S shift --- examples/xua_lite_example/src/audio_hub.xc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 42c1cdd9..fe8b68b5 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -53,8 +53,9 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.init(i2s_config_t &?i2s_config, tdm_config_t &?tdm_config): i2s_config.mode = I2S_MODE_I2S; i2s_config.mclk_bclk_ratio = (MCLK_48/DEFAULT_FREQ)/64; - debug_printf("I2S init\n"); + delay_milliseconds(500); //Work around to ensure I2S does not start until enumeration complete so timing does not break for exchange + //This should be ideally done by set config by the host (via xua_buffer) to know we are enumerated break; case i2s.receive(size_t n_chans, int32_t in_samps[n_chans]): From 3debc9fef43d85d239952ff5e5e3fdb4ff9442a8 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Tue, 6 Nov 2018 16:15:46 +0000 Subject: [PATCH 036/123] combinable ep0 task --- examples/xua_lite_example/src/AudioConfig.xc | 2 +- examples/xua_lite_example/src/app_xua_lite.xc | 24 +- .../xua_lite_example/src/xua_buffer_lite.h | 8 + .../xua_lite_example/src/xua_buffer_lite.xc | 340 +++++++++++++----- lib_xua/src/core/endpoint0/xua_ep0_wrapper.h | 27 ++ lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc | 62 ++-- 6 files changed, 322 insertions(+), 141 deletions(-) create mode 100644 examples/xua_lite_example/src/xua_buffer_lite.h create mode 100644 lib_xua/src/core/endpoint0/xua_ep0_wrapper.h diff --git a/examples/xua_lite_example/src/AudioConfig.xc b/examples/xua_lite_example/src/AudioConfig.xc index fc9efad0..1bb907c5 100755 --- a/examples/xua_lite_example/src/AudioConfig.xc +++ b/examples/xua_lite_example/src/AudioConfig.xc @@ -86,7 +86,7 @@ void pll_nudge(int nudge) { p_leds <: 0x0; } set_node_pll_reg(tile[0], PLL_NOM); - if(nudge != old_nudge && nudge){debug_printf("nudge: %d\n", nudge); }old_nudge = nudge; + //if(nudge != old_nudge && nudge){debug_printf("nudge: %d\n", nudge); }old_nudge = nudge; } void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 94115c54..618e7308 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -11,6 +11,8 @@ #include "i2s.h" #include "i2c.h" #include "mic_array.h" +#include "XUA_Buffer_lite.h" +#include "xua_ep0_wrapper.h" #define DEBUG_UNIT XUA_APP #define DEBUG_PRINT_ENABLE_XUA_APP 1 @@ -56,13 +58,10 @@ on tile[0]: clock pdmclk6 = XS1_CLKBLK_5; XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO}; XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO}; -void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_aud_host); [[distributable]] void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_audio, streaming chanend (&?c_ds_output)[1]); void setup_audio_gpio(out port p_gpio); void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); -void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics); void mic_array_setup_ddr_xcore(clock pdmclk, clock pdmclk6, out port p_pdm_clk, buffered in port:32 p_pdm_data, int divide); @@ -90,6 +89,8 @@ int main() streaming chan c_audio; //We use the channel buffering (48B across switch each way) streaming chan c_ds_output[1]; + interface ep0_control_if i_ep0_ctl; + par { on tile[0]: { @@ -111,7 +112,7 @@ int main() par (int i = 0; i < 0; i++) burn_high_priority(); } } - on tile[1]:{ + on tile[1]:unsafe{ // Connect master-clock input clock-block to clock-block pin for asnch feedback calculation set_clock_src(clk_usb_mclk, p_mclk_in_usb); // Clock clock-block from mclk pin set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block @@ -132,15 +133,22 @@ int main() null, null, -1 , (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); - // Buffering core - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core - XUA_Buffer_lite(c_ep_out[0], - c_ep_in[0], + // // Buffering core - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core + // XUA_Buffer_lite(c_ep_out[0], + // c_ep_in[0], + // c_ep_out[1], + // null, //c_ep_in[XUA_ENDPOINT_COUNT_IN - 2],/*feedback*/ + // c_ep_in[XUA_ENDPOINT_COUNT_IN - 1], + // c_sof, p_for_mclk_count, c_audio); + + XUA_Buffer_lite2(i_ep0_ctl, c_ep_out[1], null, //c_ep_in[XUA_ENDPOINT_COUNT_IN - 2],/*feedback*/ c_ep_in[XUA_ENDPOINT_COUNT_IN - 1], c_sof, p_for_mclk_count, c_audio); + XUA_Endpoint0_select(c_ep_out[0], c_ep_in[0], i_ep0_ctl, null VENDOR_REQUESTS_PARAMS_DEC_); - par (int i = 0; i < 4; i++) burn_normal_priority(); + par (int i = 0; i < 3; i++) burn_normal_priority(); par (int i = 0; i < 2; i++) burn_high_priority(); } }//Tile[1] par diff --git a/examples/xua_lite_example/src/xua_buffer_lite.h b/examples/xua_lite_example/src/xua_buffer_lite.h new file mode 100644 index 00000000..5ad972de --- /dev/null +++ b/examples/xua_lite_example/src/xua_buffer_lite.h @@ -0,0 +1,8 @@ +#include +#include "xua_ep0_wrapper.h" + + +[[combinable]] +unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); +[[combinable]] +unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); \ No newline at end of file diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 1eb91963..8649d5a3 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -10,6 +10,7 @@ #include "debug_print.h" #include "xua.h" #include "fifo_impl.h" +#include "xua_ep0_wrapper.h" //Currently only single frequency supported #define NOMINAL_SR_DEVICE DEFAULT_FREQ @@ -95,7 +96,7 @@ static inline void pack_samples_to_buff(int input[], const unsigned n_samples, c } -void do_feedback_calculation(unsigned &sof_count +static void do_feedback_calculation(unsigned &sof_count ,const unsigned mclk_hz ,unsigned mclk_port_counter ,unsigned &mclk_port_counter_old @@ -189,8 +190,9 @@ void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Resu extern XUD_ep ep0_out; extern XUD_ep ep0_in; - -void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { +[[combinable]] +//Unsafe to allow us to use fifo API without local unsafe scope +unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); @@ -241,113 +243,259 @@ void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, cha //Send initial samples so audiohub is not blocked for (int i = 0; i < NUM_USB_CHAN_OUT * 6; i++) c_audio_hub <: 0; + + //FIFOs from EP buffers to audio + int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; + int device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; + mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; + mem_fifo_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; + volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + volatile mem_fifo_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; + + //XUD transaction variables passed in by reference + XUD_Result_t result; + unsigned length = 0; + unsigned u_tmp; //For select channel input by ref + while(1){ + select{ + //Handle EP0 requests + case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): + timer tmr; int t0, t1; tmr :> t0; + + debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error + USB_ParseSetupPacket(sbuffer, sp); //Parse data buffer end populate SetupPacket struct + + XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); + XUD_SetReady_Out(ep0_out, sbuffer); + //tmr :> t1; debug_printf("c%d\n", t1 - t0); + + break; + + //SOF handling + case inuint_byref(c_sof, u_tmp): + timer tmr; int t0, t1; tmr :> t0; + unsigned mclk_port_counter = 0; + asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); + if (!isnull(c_feedback)) do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); + sof_count++; + //tmr :> t1; debug_printf("s%d\n", t1 - t0); + + break; + + //Receive samples from host + case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): + timer tmr; int t0, t1; tmr :> t0; + + num_samples_received_from_host = length / out_subslot_size; + + fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, (short *)buffer_aud_out, num_samples_received_from_host); + if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); + num_samples_to_send_to_host = num_samples_received_from_host; + + int fill_level = fifo_get_fill_relative_half(host_to_device_fifo_ptr); + fill_level_process(fill_level, clock_nudge); + + //Mark EP as ready for next frame from host + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + //tmr :> t1; debug_printf("o%d\n", t1 - t0); + break; + + //Send asynch explicit feedback value, but only if enabled + case !isnull(c_feedback) => XUD_SetData_Select(c_feedback, ep_feedback, result): + timer tmr; int t0, t1; tmr :> t0; + + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); + //debug_printf("0x%x\n", fb_clocks[0]); + //tmr :> t1; debug_printf("f%d\n", t1 - t0); + + break; + + //Send samples to host + case XUD_SetData_Select(c_aud_in, ep_aud_in, result): + timer tmr; int t0, t1; tmr :> t0; + + if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; + + fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, (short *)buffer_aud_in, num_samples_received_from_host); + if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); + + //Populate the input buffer ready for the next read + //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); + //Use the number of samples we received last time so we are always balanced (assumes same in/out count) + + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback + num_samples_to_send_to_host = 0; + //tmr :> t1; debug_printf("i%d\n", t1 - t0); + + break; + + //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO + case c_audio_hub :> samples_in[0]: + timer tmr; int t0, t1; tmr :> t0; + + for (int i = 1; i < NUM_USB_CHAN_IN; i++){ + c_audio_hub :> samples_in[i]; + } + fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); + if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; + if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; + ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); + if (ret != FIFO_SUCCESS && input_interface_num != 0) debug_printf("d2h full\n"); + //tmr :> t1; debug_printf("a%d\n", t1 - t0); + break; + } + } +} + +[[combinable]] +//Unsafe to allow us to use fifo API without local unsafe scope +unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { + + debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); + + unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; + unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; + + unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; + unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; + + //Asynch feedback calculation + unsigned sof_count = 0; + unsigned mclk_port_counter_old = 0; + long long feedback_value = 0; + unsigned mod_from_last_time = 0; + const unsigned mclk_hz = MCLK_48; + unsigned int fb_clocks[1] = {0}; + + //Adapative device clock control + int clock_nudge = 0; + + //Endpoints + XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); + XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); + XUD_ep ep_feedback = 0; + if (!isnull(c_feedback)) ep_feedback = XUD_InitEp(c_feedback); + + unsigned num_samples_received_from_host = 0; + unsigned num_samples_to_send_to_host = 0; + + int samples_out[NUM_USB_CHAN_OUT] = {0}; + int samples_in[NUM_USB_CHAN_IN] = {0}; + + unsigned input_interface_num = 0; + unsigned output_interface_num = 0; + + //Enable all EPs + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); + if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); - //Unsafe to allow us to use fifo API - unsafe{ + //Send initial samples so audiohub is not blocked + for (int i = 0; i < NUM_USB_CHAN_OUT * 6; i++) c_audio_hub <: 0; - //FIFOs from EP buffers to audio - int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; - int device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; - mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; - mem_fifo_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; - volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; - volatile mem_fifo_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; + //FIFOs from EP buffers to audio + int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; + int device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; + mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; + mem_fifo_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; + volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + volatile mem_fifo_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; - //XUD transaction variables passed in by reference - XUD_Result_t result; - unsigned length = 0; - unsigned u_tmp; //For select channel input by ref - while(1){ - select{ - //Handle EP0 requests - case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): - timer tmr; int t0, t1; tmr :> t0; + //XUD transaction variables passed in by reference + XUD_Result_t result; + unsigned length = 0; + unsigned u_tmp; //For select channel input by ref + while(1){ + select{ + //Handle EP0 requests + case i_ep0_ctl.set_output_interface(unsigned num): + output_interface_num = num; + break; - debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error - USB_ParseSetupPacket(sbuffer, sp); //Parse data buffer end populate SetupPacket struct - - XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); - XUD_SetReady_Out(ep0_out, sbuffer); - //tmr :> t1; debug_printf("c%d\n", t1 - t0); + case i_ep0_ctl.set_input_interface(unsigned num): + input_interface_num = num; + break; - break; + case i_ep0_ctl.set_host_active(unsigned active): + break; - //SOF handling - case inuint_byref(c_sof, u_tmp): - timer tmr; int t0, t1; tmr :> t0; - unsigned mclk_port_counter = 0; - asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); - do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); - sof_count++; - //tmr :> t1; debug_printf("s%d\n", t1 - t0); + //SOF handling + case inuint_byref(c_sof, u_tmp): + timer tmr; int t0, t1; tmr :> t0; + unsigned mclk_port_counter = 0; + asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); + if (!isnull(c_feedback)) do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); + sof_count++; + //tmr :> t1; debug_printf("s%d\n", t1 - t0); - break; + break; - //Receive samples from host - case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): - timer tmr; int t0, t1; tmr :> t0; + //Receive samples from host + case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): + timer tmr; int t0, t1; tmr :> t0; - num_samples_received_from_host = length / out_subslot_size; + num_samples_received_from_host = length / out_subslot_size; + + fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, (short *)buffer_aud_out, num_samples_received_from_host); + if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); + num_samples_to_send_to_host = num_samples_received_from_host; + + int fill_level = fifo_get_fill_relative_half(host_to_device_fifo_ptr); + fill_level_process(fill_level, clock_nudge); + + //Mark EP as ready for next frame from host + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + //tmr :> t1; debug_printf("o%d\n", t1 - t0); + break; + + //Send asynch explicit feedback value, but only if enabled + case !isnull(c_feedback) => XUD_SetData_Select(c_feedback, ep_feedback, result): + timer tmr; int t0, t1; tmr :> t0; + + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); + //debug_printf("0x%x\n", fb_clocks[0]); + //tmr :> t1; debug_printf("f%d\n", t1 - t0); + + break; + + //Send samples to host + case XUD_SetData_Select(c_aud_in, ep_aud_in, result): + timer tmr; int t0, t1; tmr :> t0; + + if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; + + fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, (short *)buffer_aud_in, num_samples_received_from_host); + if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); + + //Populate the input buffer ready for the next read + //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); + //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, (short *)buffer_aud_out, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); - num_samples_to_send_to_host = num_samples_received_from_host; - - int fill_level = fifo_get_fill_relative_half(host_to_device_fifo_ptr); - fill_level_process(fill_level, clock_nudge); + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback + num_samples_to_send_to_host = 0; + //tmr :> t1; debug_printf("i%d\n", t1 - t0); - //Mark EP as ready for next frame from host - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); - //tmr :> t1; debug_printf("o%d\n", t1 - t0); - break; + break; - //Send asynch explicit feedback value, but only if enabled - case !isnull(c_feedback) => XUD_SetData_Select(c_feedback, ep_feedback, result): - timer tmr; int t0, t1; tmr :> t0; + //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO + case c_audio_hub :> samples_in[0]: + timer tmr; int t0, t1; tmr :> t0; - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); - //debug_printf("0x%x\n", fb_clocks[0]); - //tmr :> t1; debug_printf("f%d\n", t1 - t0); - - break; - - //Send samples to host - case XUD_SetData_Select(c_aud_in, ep_aud_in, result): - timer tmr; int t0, t1; tmr :> t0; - - if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; - - fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, (short *)buffer_aud_in, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); - - //Populate the input buffer ready for the next read - //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); - //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - - unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback - num_samples_to_send_to_host = 0; - //tmr :> t1; debug_printf("i%d\n", t1 - t0); - - break; - - //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO - case c_audio_hub :> samples_in[0]: - timer tmr; int t0, t1; tmr :> t0; - - for (int i = 1; i < NUM_USB_CHAN_IN; i++){ - c_audio_hub :> samples_in[i]; - } - fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); - if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; - if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; - ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); - if (ret != FIFO_SUCCESS && input_interface_num != 0) debug_printf("d2h full\n"); - //tmr :> t1; debug_printf("a%d\n", t1 - t0); - break; - } + for (int i = 1; i < NUM_USB_CHAN_IN; i++){ + c_audio_hub :> samples_in[i]; + } + fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); + if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; + if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; + ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); + if (ret != FIFO_SUCCESS && input_interface_num != 0) debug_printf("d2h full\n"); + //tmr :> t1; debug_printf("a%d\n", t1 - t0); + break; } } } \ No newline at end of file diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.h b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.h new file mode 100644 index 00000000..8015b95e --- /dev/null +++ b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.h @@ -0,0 +1,27 @@ +#ifndef _EP0_WRAPPER_ +#define _EP0_WRAPPER_ + +#include +#include +#include +#include "xua.h" + +typedef interface ep0_control_if{ + void set_output_interface(unsigned num); + void set_input_interface(unsigned num); + void set_host_active(unsigned num); +}ep0_control_if; + +extern "C"{ +void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); +void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_, unsigned *input_interface_num, unsigned *output_interface_num); +} +#pragma select handler +void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Result_t &result); + +[[combinable]] +void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, client ep0_control_if i_ep0_ctl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); + +#endif \ No newline at end of file diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc index 3846c1c6..14a5148b 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc @@ -2,56 +2,46 @@ #include #include #include "xua.h" +#include "xua_ep0_wrapper.h" #define DEBUG_UNIT EP0_WRAPPER #define DEBUG_PRINT_ENABLE_EP0_WRAPPER 0 #include "debug_print.h" -extern "C"{ -void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); -void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_, unsigned *input_interface_num, unsigned *output_interface_num); -} -#pragma select handler -void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Result_t &result); - extern XUD_ep ep0_out; extern XUD_ep ep0_in; - -void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) +[[combinable]] +void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, client ep0_control_if i_ep0_ctl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { - USB_SetupPacket_t sp; - XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); - unsigned char sbuffer[120]; - XUD_SetReady_Out(ep0_out, sbuffer); + USB_SetupPacket_t sp; + XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, null, null, null, null, dfuInterface); + unsigned char sbuffer[120]; + XUD_SetReady_Out(ep0_out, sbuffer); - unsigned input_interface_num = 0; - unsigned output_interface_num = 0; + unsigned input_interface_num = 0; + unsigned output_interface_num = 0; + XUD_Result_t result = XUD_RES_ERR; + unsigned length = 0; - while(1){ + while(1){ + select{ + case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): + if (result == XUD_RES_OKAY) + { + /* Parse data buffer end populate SetupPacket struct */ + USB_ParseSetupPacket(sbuffer, sp); + } + debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error - XUD_Result_t result = XUD_RES_ERR; - unsigned length = 0; - - select{ - case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): - break; - } - - if (result == XUD_RES_OKAY) - { - /* Parse data buffer end populate SetupPacket struct */ - USB_ParseSetupPacket(sbuffer, sp); - } - debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error - - XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface, &input_interface_num, &output_interface_num); - XUD_SetReady_Out(ep0_out, sbuffer); + XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, null, null, null, null, dfuInterface, &input_interface_num, &output_interface_num); + i_ep0_ctl.set_output_interface(output_interface_num); + i_ep0_ctl.set_input_interface(input_interface_num); + XUD_SetReady_Out(ep0_out, sbuffer); + break; } + } } \ No newline at end of file From f014922e98348ad945656bd9a0474536fb0b9c8b Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Thu, 8 Nov 2018 14:38:52 +0000 Subject: [PATCH 037/123] Move function prototypes to headers --- examples/xua_lite_example/src/app_xua_lite.xc | 10 +++------- .../src/{AudioConfig.h => audio_config.h} | 2 +- .../src/{AudioConfig.xc => audio_config.xc} | 10 ++++++++-- examples/xua_lite_example/src/audio_hub.h | 4 ++++ examples/xua_lite_example/src/audio_hub.xc | 16 ++-------------- examples/xua_lite_example/src/pdm_mic.h | 10 ++++++++++ examples/xua_lite_example/src/pdm_mic.xc | 4 ---- 7 files changed, 28 insertions(+), 28 deletions(-) rename examples/xua_lite_example/src/{AudioConfig.h => audio_config.h} (79%) rename examples/xua_lite_example/src/{AudioConfig.xc => audio_config.xc} (98%) create mode 100644 examples/xua_lite_example/src/audio_hub.h create mode 100644 examples/xua_lite_example/src/pdm_mic.h diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 618e7308..0976810d 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -13,6 +13,9 @@ #include "mic_array.h" #include "XUA_Buffer_lite.h" #include "xua_ep0_wrapper.h" +#include "pdm_mic.h" +#include "audio_config.h" +#include "audio_hub.h" #define DEBUG_UNIT XUA_APP #define DEBUG_PRINT_ENABLE_XUA_APP 1 @@ -58,13 +61,6 @@ on tile[0]: clock pdmclk6 = XS1_CLKBLK_5; XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO}; XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO}; -[[distributable]] -void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_audio, streaming chanend (&?c_ds_output)[1]); -void setup_audio_gpio(out port p_gpio); -void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); -void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics); -void mic_array_setup_ddr_xcore(clock pdmclk, clock pdmclk6, out port p_pdm_clk, buffered in port:32 p_pdm_data, int divide); - void burn_normal_priority(void){ while(1); } diff --git a/examples/xua_lite_example/src/AudioConfig.h b/examples/xua_lite_example/src/audio_config.h similarity index 79% rename from examples/xua_lite_example/src/AudioConfig.h rename to examples/xua_lite_example/src/audio_config.h index a4fe9270..6b7c079b 100755 --- a/examples/xua_lite_example/src/AudioConfig.h +++ b/examples/xua_lite_example/src/audio_config.h @@ -3,6 +3,6 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); void pll_nudge(int nudge); - +void setup_audio_gpio(out port p_gpio); #endif diff --git a/examples/xua_lite_example/src/AudioConfig.xc b/examples/xua_lite_example/src/audio_config.xc similarity index 98% rename from examples/xua_lite_example/src/AudioConfig.xc rename to examples/xua_lite_example/src/audio_config.xc index 1bb907c5..53719b10 100755 --- a/examples/xua_lite_example/src/AudioConfig.xc +++ b/examples/xua_lite_example/src/audio_config.xc @@ -50,8 +50,6 @@ // TLV320DAC3101 easy register access defines #define DAC3101_REGWRITE(reg, val) {i_i2c.write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);} - - static void set_node_pll_reg(tileref tile_ref, unsigned reg_val){ write_sswitch_reg(get_tile_id(tile_ref), XS1_SSWITCH_PLL_CTL_NUM, reg_val); } @@ -89,6 +87,14 @@ void pll_nudge(int nudge) { //if(nudge != old_nudge && nudge){debug_printf("nudge: %d\n", nudge); }old_nudge = nudge; } +void setup_audio_gpio(out port p_gpio){ + // Reset DAC and disable MUTE + p_gpio <: 0x0; + delay_milliseconds(1); + p_gpio <: 0x1; + delay_milliseconds(1); +} + void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) { diff --git a/examples/xua_lite_example/src/audio_hub.h b/examples/xua_lite_example/src/audio_hub.h new file mode 100644 index 00000000..b7f1b7f9 --- /dev/null +++ b/examples/xua_lite_example/src/audio_hub.h @@ -0,0 +1,4 @@ +#include "i2s.h" + +[[distributable]] +void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_audio, streaming chanend (&?c_ds_output)[1]); \ No newline at end of file diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index fe8b68b5..015ecc2c 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -5,20 +5,8 @@ #define DEBUG_PRINT_ENABLE_XUA_AUDIO_HUB 1 #include "debug_print.h" #include "mic_array.h" -#include "AudioConfig.h" - - -void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]); - - -void setup_audio_gpio(out port p_gpio){ - // Reset DAC and disable MUTE - p_gpio <: 0x0; - delay_milliseconds(1); - p_gpio <: 0x1; - delay_milliseconds(1); -} - +#include "audio_config.h" +#include "pdm_mic.h" //Globally declared for 64b alignment int mic_decimator_fir_data_array[8][THIRD_STAGE_COEFS_PER_STAGE * PDM_MAX_DECIMATION] = {{0}}; diff --git a/examples/xua_lite_example/src/pdm_mic.h b/examples/xua_lite_example/src/pdm_mic.h new file mode 100644 index 00000000..2b00567d --- /dev/null +++ b/examples/xua_lite_example/src/pdm_mic.h @@ -0,0 +1,10 @@ +#ifndef _PDM_MIC_H_ +#define _PDM_MIC_H_ + +#include "mic_array.h" + +void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]); +void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics); +void mic_array_setup_ddr_xcore(clock pdmclk, clock pdmclk6, out port p_pdm_clk, buffered in port:32 p_pdm_data, int divide); + +#endif diff --git a/examples/xua_lite_example/src/pdm_mic.xc b/examples/xua_lite_example/src/pdm_mic.xc index bc2fd263..417d6eb4 100644 --- a/examples/xua_lite_example/src/pdm_mic.xc +++ b/examples/xua_lite_example/src/pdm_mic.xc @@ -1,6 +1,4 @@ #include "xua.h" -#if (XUA_NUM_PDM_MICS > 0) - #include #include #include @@ -105,5 +103,3 @@ void mic_array_setup_ddr_xcore(clock pdmclk, */ } - -#endif From 1251425ee6d45a27b2a356710f48dbef8c0b2118 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Thu, 8 Nov 2018 16:20:34 +0000 Subject: [PATCH 038/123] Correct MCLK settings (24.576MHz) solves noise issue --- examples/xua_lite_example/src/audio_config.xc | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/examples/xua_lite_example/src/audio_config.xc b/examples/xua_lite_example/src/audio_config.xc index 53719b10..d1c126e1 100755 --- a/examples/xua_lite_example/src/audio_config.xc +++ b/examples/xua_lite_example/src/audio_config.xc @@ -50,6 +50,8 @@ // TLV320DAC3101 easy register access defines #define DAC3101_REGWRITE(reg, val) {i_i2c.write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);} + + static void set_node_pll_reg(tileref tile_ref, unsigned reg_val){ write_sswitch_reg(get_tile_id(tile_ref), XS1_SSWITCH_PLL_CTL_NUM, reg_val); } @@ -145,26 +147,26 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) //Set nominal clock speed on PLL write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_NOM); - // We are assuming 48kHz family only and we generate MCLK - // Set PLL J Value to 7 - DAC3101_REGWRITE(DAC3101_PLL_J, 0x07); + // We are assuming 48kHz family only and we generate MCLK in the DAC from BLCK supplied by XCORE + // Set PLL J Value to 8 + DAC3101_REGWRITE(DAC3101_PLL_J, 0x08); // Set PLL D to 0 ... // Set PLL D MSB Value to 0x00 - DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x07); + DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x00); // Set PLL D LSB Value to 0x00 - DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x80); + DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x00); delay_milliseconds(1); // Set PLL_CLKIN = BCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x07); - // Set PLL P and R values and power up. + // Set PLL P=1 and R=4 values and power up. DAC3101_REGWRITE(DAC3101_PLL_P_R, 0x94); - // Set NDAC clock divider to 2 and power up. - DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x82); - // Set MDAC clock divider to 7 and power up. - DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x87); + // Set NDAC clock divider to 4 and power up. + DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x84); + // Set MDAC clock divider to 4 and power up. + DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x84); // Set OSR clock divider to 128. DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80); From 4d5049a47a49095a3f576a756a04194fc4fb86a8 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Thu, 8 Nov 2018 17:12:38 +0000 Subject: [PATCH 039/123] Minor tidy --- examples/xua_lite_example/src/audio_hub.xc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 015ecc2c..8318f254 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -22,7 +22,7 @@ void AudioHub(server i2s_frame_callback_if i2s, int32_t clock_nudge = 0; -#if XUA_NUM_PDM_MICS > 0 + //PDM mic and decimator unsigned buffer; int raw_mics[XUA_NUM_PDM_MICS] = {0}; const unsigned decimatorCount = 1; // Supports up to 4 mics @@ -33,7 +33,6 @@ void AudioHub(server i2s_frame_callback_if i2s, mic_array_decimator_set_samprate(DEFAULT_FREQ, mic_decimator_fir_data_array[0], &dcc, dc); mic_array_decimator_configure(c_ds_output, decimatorCount, dc); mic_array_init_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); -#endif while (1) { @@ -65,8 +64,7 @@ void AudioHub(server i2s_frame_callback_if i2s, //Grab mics current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); unsafe { - raw_mics[0] = current->data[0][0]; - raw_mics[1] = current->data[1][0]; + for (int i = 0; i < XUA_NUM_PDM_MICS; i++) raw_mics[i] = current->data[i][0]; } pll_nudge(clock_nudge); From 4262cc81ac3023b84a1ba161aae013855f1cf9a1 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Thu, 8 Nov 2018 17:13:06 +0000 Subject: [PATCH 040/123] Remove compiler warning and risk of alignment for EP buffers --- .../xua_lite_example/src/xua_buffer_lite.xc | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 8649d5a3..6d8cd6de 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -196,8 +196,17 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); - unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; - unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; + //These buffers are unions so we can access them as different types + union buffer_aud_out{ + unsigned char bytes[OUT_AUDIO_BUFFER_SIZE_BYTES]; + short short_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 2]; + long long_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 4]; + }buffer_aud_out; + union buffer_aud_in{ + unsigned char bytes[IN_AUDIO_BUFFER_SIZE_BYTES]; + short short_words[IN_AUDIO_BUFFER_SIZE_BYTES / 2]; + unsigned long long_words[IN_AUDIO_BUFFER_SIZE_BYTES / 4]; + }buffer_aud_in; unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; @@ -235,8 +244,8 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o unsigned output_interface_num = 0; //Enable all EPs - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, num_samples_to_send_to_host); XUD_SetReady_Out(ep0_out, sbuffer); if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); @@ -288,7 +297,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o num_samples_received_from_host = length / out_subslot_size; - fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, (short *)buffer_aud_out, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; @@ -296,7 +305,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o fill_level_process(fill_level, clock_nudge); //Mark EP as ready for next frame from host - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); //tmr :> t1; debug_printf("o%d\n", t1 - t0); break; @@ -316,7 +325,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; - fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, (short *)buffer_aud_in, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); //Populate the input buffer ready for the next read @@ -324,7 +333,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o //Use the number of samples we received last time so we are always balanced (assumes same in/out count) unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, input_buffer_size); //loopback num_samples_to_send_to_host = 0; //tmr :> t1; debug_printf("i%d\n", t1 - t0); @@ -355,8 +364,17 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); - unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES]; - unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES]; + //These buffers are unions so we can access them as different types + union buffer_aud_out{ + unsigned char bytes[OUT_AUDIO_BUFFER_SIZE_BYTES]; + short short_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 2]; + long long_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 4]; + }buffer_aud_out; + union buffer_aud_in{ + unsigned char bytes[IN_AUDIO_BUFFER_SIZE_BYTES]; + short short_words[IN_AUDIO_BUFFER_SIZE_BYTES / 2]; + unsigned long long_words[IN_AUDIO_BUFFER_SIZE_BYTES / 4]; + }buffer_aud_in; unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; @@ -388,8 +406,8 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, unsigned output_interface_num = 0; //Enable all EPs - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, num_samples_to_send_to_host); if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); @@ -439,7 +457,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, num_samples_received_from_host = length / out_subslot_size; - fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, (short *)buffer_aud_out, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; @@ -447,7 +465,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, fill_level_process(fill_level, clock_nudge); //Mark EP as ready for next frame from host - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); //tmr :> t1; debug_printf("o%d\n", t1 - t0); break; @@ -467,7 +485,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; - fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, (short *)buffer_aud_in, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); //Populate the input buffer ready for the next read @@ -475,7 +493,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, //Use the number of samples we received last time so we are always balanced (assumes same in/out count) unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, input_buffer_size); //loopback num_samples_to_send_to_host = 0; //tmr :> t1; debug_printf("i%d\n", t1 - t0); From 7af92668f5f60d087f2568ccc4f56e58022b176a Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 9 Nov 2018 17:31:31 +0000 Subject: [PATCH 041/123] Update todo --- examples/xua_lite_example/todo.txt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/xua_lite_example/todo.txt b/examples/xua_lite_example/todo.txt index 4a0fe729..d97eaa02 100644 --- a/examples/xua_lite_example/todo.txt +++ b/examples/xua_lite_example/todo.txt @@ -5,13 +5,15 @@ - Single input/ouput format (DONE) - Get UAC1 / FS working (DONE) - Optimised EP buffer (either triple block or block FIFO) -- Fix output gain issue -- Add timer to xua_buffer to prepare for exchange with audio (remove backpressure to audio) (WONT DO) -- Adaptive endpoint EP and descriptors -- Adpative clock control -- Switchable MICS using define +- Fix output gain issue (IN PROGRESS) +- Add timer to xua_buffer to prepare for exchange with audio (remove backpressure to audio) (WONT DO - use port buffer and reduce case overhead) +- Adaptive endpoint EP and descriptors (DONE) +- Adpative clock control (IN PROGRESS) +- Switchable MICS using define (WONT DO - separate app) - DFU -- Combinable EP0 +- Combinable EP0 (DONE) - Interrupt EP0 option - Control processing - +- Fix cast warning (DONE) +- Work out why no clock drift on Android / OSX (drift seen on Linux and Win) +- Tidy/cut down EP0 handling From e93901f0ccbc59a46d6c8d6dc74ca188ca9187f7 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 9 Nov 2018 17:32:32 +0000 Subject: [PATCH 042/123] Update FIFO to use true shorts + add/use fast block fifo API --- examples/xua_lite_example/src/app_xua_lite.xc | 4 +- examples/xua_lite_example/src/audio_hub.xc | 2 + examples/xua_lite_example/src/fifo_impl.h | 105 +++++++++++++++- examples/xua_lite_example/src/fifo_types.h | 7 ++ .../xua_lite_example/src/xua_buffer_lite.h | 2 - .../xua_lite_example/src/xua_buffer_lite.xc | 117 +++++++++++------- 6 files changed, 182 insertions(+), 55 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 0976810d..a53982ca 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -137,13 +137,15 @@ int main() // c_ep_in[XUA_ENDPOINT_COUNT_IN - 1], // c_sof, p_for_mclk_count, c_audio); + //[[combine]] + par{ XUA_Buffer_lite2(i_ep0_ctl, c_ep_out[1], null, //c_ep_in[XUA_ENDPOINT_COUNT_IN - 2],/*feedback*/ c_ep_in[XUA_ENDPOINT_COUNT_IN - 1], c_sof, p_for_mclk_count, c_audio); XUA_Endpoint0_select(c_ep_out[0], c_ep_in[0], i_ep0_ctl, null VENDOR_REQUESTS_PARAMS_DEC_); - + } par (int i = 0; i < 3; i++) burn_normal_priority(); par (int i = 0; i < 2; i++) burn_high_priority(); } diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 8318f254..f83f3e2c 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -57,6 +57,8 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; + + //Transfer samples for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; if (XUA_ADAPTIVE) c_audio :> clock_nudge; for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: raw_mics[i]; diff --git a/examples/xua_lite_example/src/fifo_impl.h b/examples/xua_lite_example/src/fifo_impl.h index 181d4f18..3341f32a 100644 --- a/examples/xua_lite_example/src/fifo_impl.h +++ b/examples/xua_lite_example/src/fifo_impl.h @@ -25,6 +25,19 @@ static inline unsigned fifo_get_fill(volatile mem_fifo_t * unsafe fifo) { } } +static inline unsigned fifo_get_fill_short(volatile mem_fifo_short_t * unsafe fifo) { + unsafe{ + unsigned fifo_fill = 0; + if (fifo->write_idx >= fifo->read_idx){ + fifo_fill = fifo->write_idx - fifo->read_idx; + } + else{ + fifo_fill = (fifo->size + fifo->write_idx) - fifo->read_idx; + } + return fifo_fill; + } +} + #pragma unsafe arrays static inline fifo_ret_t fifo_block_push(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { unsafe{ @@ -44,23 +57,58 @@ static inline fifo_ret_t fifo_block_push(volatile mem_fifo_t * unsafe fifo, int } #pragma unsafe arrays -static inline fifo_ret_t fifo_block_push_short_pairs(volatile mem_fifo_t * unsafe fifo, short data[], unsigned n) { +static inline fifo_ret_t fifo_block_push_short(volatile mem_fifo_short_t * unsafe fifo, short data[], unsigned n) { unsafe{ //check there is a block of space large enough - unsigned space_remaining = fifo->size - fifo_get_fill(fifo) - 1; + unsigned space_remaining = fifo->size - fifo_get_fill_short(fifo) - 1; if (n > space_remaining) { return FIFO_FULL; } for (int i = 0; i < n; i++){ unsigned next_idx = fifo->write_idx + 1; if (next_idx == fifo->size) next_idx = 0; //Check for wrap - fifo->data_base_ptr[fifo->write_idx] = data[i] << 16; + fifo->data_base_ptr[fifo->write_idx] = data[i]; fifo->write_idx = next_idx; } return FIFO_SUCCESS; } } +#pragma unsafe arrays +static inline fifo_ret_t fifo_block_push_short_fast(volatile mem_fifo_short_t * unsafe fifo, short data[], unsigned n) { + unsafe{ + //check there is a block of space large enough + unsigned space_remaining = fifo->size - fifo_get_fill_short(fifo) - 1; + if (n > space_remaining) { + return FIFO_FULL; + } + //We will write either one or two blocks depending on wrap + unsigned first_block_size = 0; + unsigned second_block_size = 0; + + //See if we need to wrap during block writes + unsigned space_left_at_top = fifo->size - fifo->write_idx; + //printf("space_left_at_top %d\n", space_left_at_top); + //Yes, we do need to wrap + if (n > space_left_at_top){ + first_block_size = space_left_at_top; + second_block_size = n - space_left_at_top; + memcpy(&fifo->data_base_ptr[fifo->write_idx], &data[0], first_block_size * sizeof(short)); + memcpy(&fifo->data_base_ptr[0], &data[first_block_size], second_block_size * sizeof(short)); + fifo->write_idx = second_block_size; + } + //No wrap, do all in one go + else{ + first_block_size = n; + second_block_size = 0; + memcpy(&fifo->data_base_ptr[fifo->write_idx], &data[0], first_block_size * sizeof(short)); + fifo->write_idx += first_block_size; + } + + return FIFO_SUCCESS; + } +} + #pragma unsafe arrays static inline fifo_ret_t fifo_block_pop(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { unsafe{ @@ -78,14 +126,14 @@ static inline fifo_ret_t fifo_block_pop(volatile mem_fifo_t * unsafe fifo, int d } #pragma unsafe arrays -static inline fifo_ret_t fifo_block_pop_short_pairs(volatile mem_fifo_t * unsafe fifo, short data[], unsigned n) { +static inline fifo_ret_t fifo_block_pop_short(volatile mem_fifo_short_t * unsafe fifo, short data[], unsigned n) { unsafe{ //Check we have a block big enough to send - if (n > fifo_get_fill(fifo)){ + if (n > fifo_get_fill_short(fifo)){ return FIFO_EMPTY; } for (int i = 0; i < n; i++){ - data[i] = fifo->data_base_ptr[fifo->read_idx] >> 16; + data[i] = fifo->data_base_ptr[fifo->read_idx]; fifo->read_idx++; if (fifo->read_idx == fifo->size) fifo->read_idx = 0; //Check for wrap } @@ -93,6 +141,43 @@ static inline fifo_ret_t fifo_block_pop_short_pairs(volatile mem_fifo_t * unsafe } } +#pragma unsafe arrays +static inline fifo_ret_t fifo_block_pop_short_fast(volatile mem_fifo_short_t * unsafe fifo, short data[], unsigned n) { + unsafe{ + //Check we have a block big enough to send + if (n > fifo_get_fill_short(fifo)){ + return FIFO_EMPTY; + } + //We will read either one or two blocks depending on wrap + unsigned first_block_size = 0; + unsigned second_block_size = 0; + + //See if we need to wrap during block read + unsigned num_read_at_top = fifo->size - fifo->read_idx; + // printf("num_read_at_top %d\n", num_read_at_top); + //Yes, we do need to wrap + if (n > num_read_at_top){ + first_block_size = num_read_at_top; + second_block_size = n - num_read_at_top; + memcpy(&data[0], &fifo->data_base_ptr[fifo->read_idx], first_block_size * sizeof(short)); + memcpy( &data[first_block_size], &fifo->data_base_ptr[0], second_block_size * sizeof(short)); + fifo->read_idx = second_block_size; + // printf("wrap\n"); + } + //No wrap, do all in one go + else{ + first_block_size = n; + second_block_size = 0; + memcpy(&data[0], &fifo->data_base_ptr[fifo->read_idx], first_block_size * sizeof(short)); + fifo->read_idx += first_block_size; + // printf("no wrap\n"); + + } + + return FIFO_SUCCESS; + } +} + //Version of above that returns fill level relative to half full static inline int fifo_get_fill_relative_half(volatile mem_fifo_t * unsafe fifo){ unsafe{ @@ -102,4 +187,12 @@ static inline int fifo_get_fill_relative_half(volatile mem_fifo_t * unsafe fifo) } } +//Version of above that returns fill level relative to half full +static inline int fifo_get_fill_relative_half_short(volatile mem_fifo_short_t * unsafe fifo){ + unsafe{ + int fifo_fill = (int)fifo_get_fill_short(fifo); + fifo_fill -= (fifo->size / 2); + return fifo_fill; + } +} #endif \ No newline at end of file diff --git a/examples/xua_lite_example/src/fifo_types.h b/examples/xua_lite_example/src/fifo_types.h index 159a95ae..5bc5248a 100644 --- a/examples/xua_lite_example/src/fifo_types.h +++ b/examples/xua_lite_example/src/fifo_types.h @@ -27,4 +27,11 @@ typedef struct mem_fifo_t { unsigned read_idx; } mem_fifo_t; +typedef struct mem_fifo_short_t { + const unsigned size; //Size in SHORTs + short * const unsafe data_base_ptr; //Base of the data array - declared externally so we can have differnt sized FIFOs + unsigned write_idx; + unsigned read_idx; +} mem_fifo_short_t; + #endif \ No newline at end of file diff --git a/examples/xua_lite_example/src/xua_buffer_lite.h b/examples/xua_lite_example/src/xua_buffer_lite.h index 5ad972de..0a5a3366 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.h +++ b/examples/xua_lite_example/src/xua_buffer_lite.h @@ -1,8 +1,6 @@ #include #include "xua_ep0_wrapper.h" - -[[combinable]] unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); [[combinable]] unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); \ No newline at end of file diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 6d8cd6de..8b1d832d 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -158,10 +158,10 @@ static void do_feedback_calculation(unsigned &sof_count void fill_level_process(int fill_level, int &clock_nudge){ const int trigger_high_upper = 6; - const int trigger_high_lower = 8; + //const int trigger_high_lower = 8; const int trigger_low_upper = -6; - const int trigger_low_lower = -8; + //const int trigger_low_lower = -8; if (fill_level >= trigger_high_upper){ clock_nudge = 1; @@ -190,7 +190,6 @@ void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Resu extern XUD_ep ep0_out; extern XUD_ep ep0_in; -[[combinable]] //Unsafe to allow us to use fifo API without local unsafe scope unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { @@ -231,8 +230,8 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o unsigned num_samples_received_from_host = 0; unsigned num_samples_to_send_to_host = 0; - int samples_out[NUM_USB_CHAN_OUT] = {0}; - int samples_in[NUM_USB_CHAN_IN] = {0}; + short samples_in_short[NUM_USB_CHAN_IN] = {0}; + short samples_out_short[NUM_USB_CHAN_OUT] = {0}; #define c_audioControl null #define dfuInterface null @@ -251,21 +250,22 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o //Send initial samples so audiohub is not blocked - for (int i = 0; i < NUM_USB_CHAN_OUT * 6; i++) c_audio_hub <: 0; + for (int i = 0; i < NUM_USB_CHAN_OUT * 2; i++) c_audio_hub <: 0; //FIFOs from EP buffers to audio - int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; - int device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; - mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; - mem_fifo_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; - volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; - volatile mem_fifo_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; + short host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; + short device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; + mem_fifo_short_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; + mem_fifo_short_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; + volatile mem_fifo_short_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + volatile mem_fifo_short_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; //XUD transaction variables passed in by reference XUD_Result_t result; unsigned length = 0; unsigned u_tmp; //For select channel input by ref while(1){ + #pragma ordered select{ //Handle EP0 requests case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): @@ -276,7 +276,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); XUD_SetReady_Out(ep0_out, sbuffer); - //tmr :> t1; debug_printf("c%d\n", t1 - t0); + tmr :> t1; debug_printf("c%d\n", t1 - t0); break; @@ -287,7 +287,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); if (!isnull(c_feedback)) do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); sof_count++; - //tmr :> t1; debug_printf("s%d\n", t1 - t0); + tmr :> t1; debug_printf("s%d\n", t1 - t0); break; @@ -297,16 +297,16 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o num_samples_received_from_host = length / out_subslot_size; - fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_push_short(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; - int fill_level = fifo_get_fill_relative_half(host_to_device_fifo_ptr); + int fill_level = fifo_get_fill_relative_half_short(host_to_device_fifo_ptr); fill_level_process(fill_level, clock_nudge); //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); - //tmr :> t1; debug_printf("o%d\n", t1 - t0); + tmr :> t1; debug_printf("o%d\n", t1 - t0); break; //Send asynch explicit feedback value, but only if enabled @@ -315,7 +315,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); //debug_printf("0x%x\n", fb_clocks[0]); - //tmr :> t1; debug_printf("f%d\n", t1 - t0); + tmr :> t1; debug_printf("f%d\n", t1 - t0); break; @@ -325,7 +325,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; - fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_pop_short(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); //Populate the input buffer ready for the next read @@ -335,28 +335,30 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, input_buffer_size); //loopback num_samples_to_send_to_host = 0; - //tmr :> t1; debug_printf("i%d\n", t1 - t0); + tmr :> t1; debug_printf("i%d\n", t1 - t0); break; //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO - case c_audio_hub :> samples_in[0]: + case c_audio_hub :> u_tmp: timer tmr; int t0, t1; tmr :> t0; - + samples_in_short[0] = (int)u_tmp >> 16; for (int i = 1; i < NUM_USB_CHAN_IN; i++){ - c_audio_hub :> samples_in[i]; + c_audio_hub :> u_tmp; + samples_in_short[i] = (int)u_tmp >> 16; } - fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); + fifo_ret_t ret = fifo_block_pop_short(host_to_device_fifo_ptr, samples_out_short, NUM_USB_CHAN_OUT); if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: (int)samples_out_short[i] << 16; if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; - ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); + ret = fifo_block_push_short(device_to_host_fifo_ptr, samples_in_short, NUM_USB_CHAN_IN); if (ret != FIFO_SUCCESS && input_interface_num != 0) debug_printf("d2h full\n"); - //tmr :> t1; debug_printf("a%d\n", t1 - t0); + tmr :> t1; debug_printf("a%d\n", t1 - t0); break; } } } +extern port p_sda; [[combinable]] //Unsafe to allow us to use fifo API without local unsafe scope @@ -399,9 +401,6 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, unsigned num_samples_received_from_host = 0; unsigned num_samples_to_send_to_host = 0; - int samples_out[NUM_USB_CHAN_OUT] = {0}; - int samples_in[NUM_USB_CHAN_IN] = {0}; - unsigned input_interface_num = 0; unsigned output_interface_num = 0; @@ -410,17 +409,30 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, num_samples_to_send_to_host); if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); + short samples_in_short[NUM_USB_CHAN_IN] = {0}; + short samples_out_short[NUM_USB_CHAN_OUT] = {0}; + //Send initial samples so audiohub is not blocked for (int i = 0; i < NUM_USB_CHAN_OUT * 6; i++) c_audio_hub <: 0; //FIFOs from EP buffers to audio - int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; - int device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; - mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; - mem_fifo_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; - volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; - volatile mem_fifo_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; + short host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; + short device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; + mem_fifo_short_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; + mem_fifo_short_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; + volatile mem_fifo_short_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + volatile mem_fifo_short_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; + + //debug + const unsigned trig_period = 100000000; //1s + timer tmr; + unsigned sc = 0; + unsigned ac = 0; + unsigned hc = 0; + unsigned tmr_trig; + tmr :> tmr_trig; + tmr_trig += trig_period; //XUD transaction variables passed in by reference XUD_Result_t result; @@ -448,7 +460,9 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, if (!isnull(c_feedback)) do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); sof_count++; //tmr :> t1; debug_printf("s%d\n", t1 - t0); - + p_sda <: 1; + p_sda <: 0; + sc++; break; //Receive samples from host @@ -456,12 +470,13 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, timer tmr; int t0, t1; tmr :> t0; num_samples_received_from_host = length / out_subslot_size; + hc += num_samples_received_from_host / NUM_USB_CHAN_OUT; - fifo_ret_t ret = fifo_block_push_short_pairs(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_push_short_fast(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; - int fill_level = fifo_get_fill_relative_half(host_to_device_fifo_ptr); + int fill_level = fifo_get_fill_relative_half_short(host_to_device_fifo_ptr); fill_level_process(fill_level, clock_nudge); //Mark EP as ready for next frame from host @@ -483,9 +498,10 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, case XUD_SetData_Select(c_aud_in, ep_aud_in, result): timer tmr; int t0, t1; tmr :> t0; + //If host is not streaming out, then send a fixed number of samples to host if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; - fifo_ret_t ret = fifo_block_pop_short_pairs(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); + fifo_ret_t ret = fifo_block_pop_short_fast(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); //Populate the input buffer ready for the next read @@ -496,21 +512,30 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, input_buffer_size); //loopback num_samples_to_send_to_host = 0; //tmr :> t1; debug_printf("i%d\n", t1 - t0); + break; + case tmr when timerafter(tmr_trig) :> int _: + tmr_trig += trig_period; + debug_printf("HOST: %d SAMP: %d SOF: %d\n", ac, hc, sc); + sc = 0; + ac = 0; + hc = 0; break; //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO - case c_audio_hub :> samples_in[0]: + case c_audio_hub :> u_tmp: timer tmr; int t0, t1; tmr :> t0; - + samples_in_short[0] = (int)u_tmp >> 16; + ac++; for (int i = 1; i < NUM_USB_CHAN_IN; i++){ - c_audio_hub :> samples_in[i]; + c_audio_hub :> u_tmp; + samples_in_short[i] = (int)u_tmp >> 16; } - fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, samples_out, NUM_USB_CHAN_OUT); + fifo_ret_t ret = fifo_block_pop_short(host_to_device_fifo_ptr, samples_out_short, NUM_USB_CHAN_OUT); if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[i]; + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: (int)samples_out_short[i] << 16; if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; - ret = fifo_block_push(device_to_host_fifo_ptr, samples_in, NUM_USB_CHAN_IN); + ret = fifo_block_push_short(device_to_host_fifo_ptr, samples_in_short, NUM_USB_CHAN_IN); if (ret != FIFO_SUCCESS && input_interface_num != 0) debug_printf("d2h full\n"); //tmr :> t1; debug_printf("a%d\n", t1 - t0); break; From 8dd33cf33bb13299c22743339707485160a12be8 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 9 Nov 2018 17:32:43 +0000 Subject: [PATCH 043/123] Unit tests for fifo --- examples/xua_lite_example/test/Makefile | 35 ++++++ examples/xua_lite_example/test/test_fifoxc | 139 +++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 examples/xua_lite_example/test/Makefile create mode 100644 examples/xua_lite_example/test/test_fifoxc diff --git a/examples/xua_lite_example/test/Makefile b/examples/xua_lite_example/test/Makefile new file mode 100644 index 00000000..b3bbbe69 --- /dev/null +++ b/examples/xua_lite_example/test/Makefile @@ -0,0 +1,35 @@ +# Copyright (c) 2018, XMOS Ltd, All rights reserved + +#Note no xcommon included - we are going bareback here because xcommon not good +#at dealing excluding/including source directories out of normal structure. +#We want to have a test app here using some source files from sw_vocalfusion (delay estimator) + + +BUILD_FLAGS = -O3 -g +XCC_FLAGS = $(BUILD_FLAGS) + +INCLUDE_DIRS = \ + -I ../src/ \ + -I . \ + +COMMON = \ + -O2 -g -report \ + -target=XCORE-200-EXPLORER \ + +SOURCES = \ + ./test_fifo.xc \ + +BINARY=bin/test_fifo.xe \ + + +all: + mkdir -p bin; \ + mv test_fifoxc test_fifo.xc; \ + xcc $(SOURCES) $(COMMON) $(INCLUDE_DIRS) -D AUDIO_DELAY_SAMPLES=$$DELAY -o $(BINARY); \ + mv test_fifo.xc test_fifoxc; \ + +sim: + xsim $(BINARY) + +clean: + rm -rf bin/* diff --git a/examples/xua_lite_example/test/test_fifoxc b/examples/xua_lite_example/test/test_fifoxc new file mode 100644 index 00000000..befb966b --- /dev/null +++ b/examples/xua_lite_example/test/test_fifoxc @@ -0,0 +1,139 @@ +#include +#include "fifo_impl.h" + +typedef enum test_t{ + FAIL=0, + PASS=1 +}test_t; + +#define FIFO_SIZE 4 + +unsafe test_t test_is_empty(mem_fifo_short_t * unsafe fifo){ + unsigned fill = fifo_get_fill_short(fifo); + short data[1]; + fifo_ret_t ret = fifo_block_pop_short(fifo, data, 1); + if (fill == 0 && ret == FIFO_EMPTY) return PASS; + return FAIL; +} + +unsafe test_t test_push_one(mem_fifo_short_t * unsafe fifo){ + unsigned fill_0 = fifo_get_fill_short(fifo); + short data[] = {123}; + fifo_ret_t ret = fifo_block_push_short(fifo, data, 1); + unsigned fill_1 = fifo_get_fill_short(fifo); + + if (ret != FIFO_SUCCESS || fill_0 + 1 != fill_1) return FAIL; + return PASS; +} + +unsafe test_t test_partial_fill(mem_fifo_short_t * unsafe fifo){ + unsigned fill_0 = fifo_get_fill_short(fifo); + short data[] = {80, 90, 100}; + fifo_ret_t ret = fifo_block_push_short(fifo, data, 3); + unsigned fill_1 = fifo_get_fill_short(fifo); + + if (ret != FIFO_SUCCESS || fill_0 != 0 || fill_1 != 3) return FAIL; + return PASS; +} + +unsafe test_t test_fill_level(mem_fifo_short_t * unsafe fifo){ + unsigned fill = fifo_get_fill_short(fifo); + if (fill != 3) return FAIL; + return PASS; +} + +unsafe test_t test_pop_one(mem_fifo_short_t * unsafe fifo, short expect){ + unsigned fill_0 = fifo_get_fill_short(fifo); + short data[1] = {0xffff}; + fifo_ret_t ret = fifo_block_pop_short(fifo, data, 1); + unsigned fill_1 = fifo_get_fill_short(fifo); + if (ret != FIFO_SUCCESS || fill_0 != fill_1 + 1 || data[0] != expect) { + printf("grr %d\n", data[0]); + return FAIL; + } + return PASS; +} + +unsafe test_t test_pop_three_fail(mem_fifo_short_t * unsafe fifo){ + unsigned fill_0 = fifo_get_fill_short(fifo); + short data[3] = {0xffff, 0xffff, 0xffff}; + fifo_ret_t ret = fifo_block_pop_short(fifo, data, 3); + unsigned fill_1 = fifo_get_fill_short(fifo); + if (ret == FIFO_SUCCESS || fill_0 != 2 || fill_1 != 2) return FAIL; + return PASS; +} + +unsafe test_t test_partial_fill_fast(mem_fifo_short_t * unsafe fifo){ + unsigned fill_0 = fifo_get_fill_short(fifo); + short data[] = {20, 30, 40}; + fifo_ret_t ret = fifo_block_push_short_fast(fifo, data, 3); + unsigned fill_1 = fifo_get_fill_short(fifo); + + if (ret != FIFO_SUCCESS || fill_0 != 0 || fill_1 != 3) return FAIL; + return PASS; +} + +unsafe test_t test_pop_block_fast(mem_fifo_short_t * unsafe fifo, short expect[], unsigned n){ + unsigned fill_0 = fifo_get_fill_short(fifo); + short data[10] = {0xffff}; + fifo_ret_t ret = fifo_block_pop_short_fast(fifo, data, n); + unsigned fill_1 = fifo_get_fill_short(fifo); + unsigned data_ok = memcmp(data, expect, n * sizeof(short)) == 0; + if (ret != FIFO_SUCCESS || fill_0 != fill_1 + n || !data_ok) return FAIL; + return PASS; +} + +unsafe void print_fifo(mem_fifo_short_t * unsafe fifo){ + for (int i = fifo->size - 1; i >= 0; i--){ + printf("FIFO[%d]: %hd %s %s\n", i, fifo->data_base_ptr[i], fifo->read_idx == i ? "RD" : "", fifo->write_idx == i ? "WR" : ""); + } +} + + +int main(void){ + unsafe{ + short test_fifo_storage[FIFO_SIZE]; + mem_fifo_short_t test_fifo = {sizeof(test_fifo_storage)/sizeof(test_fifo_storage[0]), test_fifo_storage, 0, 0}; + volatile mem_fifo_short_t * unsafe test_fifo_ptr = &test_fifo; + + // print_fifo(test_fifo_ptr); + printf("test_is_empty: %d\n", test_is_empty(test_fifo_ptr)); + printf("test_partial_fill: %d\n", test_partial_fill(test_fifo_ptr)); + // print_fifo(test_fifo_ptr); + + printf("test_fill_level: %d\n", test_fill_level(test_fifo_ptr)); + printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 80)); + printf("test_pop_three_fail: %d\n", test_pop_three_fail(test_fifo_ptr)); + printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 90)); + printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 100)); + printf("test_is_empty: %d\n", test_is_empty(test_fifo_ptr)); + + printf("test_partial_fill_fast: %d\n", test_partial_fill_fast(test_fifo_ptr)); + + printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 20)); + // print_fifo(test_fifo_ptr); + + short td[] = {30, 40}; + + printf("test_pop_block_fast: %d\n", test_pop_block_fast(test_fifo_ptr, td, 2)); //no wrap + + printf("test_is_empty: %d\n", test_is_empty(test_fifo_ptr)); + printf("test_push_one: %d\n", test_push_one(test_fifo_ptr)); + printf("test_push_one: %d\n", test_push_one(test_fifo_ptr)); + printf("test_pop_three_fail: %d\n", test_pop_three_fail(test_fifo_ptr)); + printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 123)); + printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 123)); + + printf("test_partial_fill_fast: %d\n", test_partial_fill_fast(test_fifo_ptr)); //no wrap + short te[] = {20, 30, 40}; + printf("test_pop_block_fast: %d\n", test_pop_block_fast(test_fifo_ptr, te, 3));// no wrap + printf("test_partial_fill_fast: %d\n", test_partial_fill_fast(test_fifo_ptr)); //wrap + printf("test_pop_block_fast: %d\n", test_pop_block_fast(test_fifo_ptr, te, 3));// wrap + // print_fifo(test_fifo_ptr); + + + + + return 0; + } +} \ No newline at end of file From ca7ee58883db02ee546ee763726ddb6caad142c2 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 14 Nov 2018 10:04:39 +0000 Subject: [PATCH 044/123] Fix buffer level calcs (now locks over & under) --- examples/xua_lite_example/src/audio_config.xc | 11 +- examples/xua_lite_example/src/audio_hub.xc | 2 +- .../xua_lite_example/src/xua_buffer_lite.xc | 101 +++++++----------- 3 files changed, 44 insertions(+), 70 deletions(-) diff --git a/examples/xua_lite_example/src/audio_config.xc b/examples/xua_lite_example/src/audio_config.xc index d1c126e1..5a523156 100755 --- a/examples/xua_lite_example/src/audio_config.xc +++ b/examples/xua_lite_example/src/audio_config.xc @@ -74,19 +74,18 @@ on tile[0]: out port p_leds = XS1_PORT_4F; int old_nudge = 0; void pll_nudge(int nudge) { if (nudge > 0){ - set_node_pll_reg(tile[0], PLL_HIGH); - p_leds <: 0xf; + write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_HIGH); + p_leds <: 0x02; //LED B } else if (nudge < 0){ - set_node_pll_reg(tile[0], PLL_LOW); - p_leds <: 0xf; + write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_LOW); + p_leds <: 0x01; //LED A } else { p_leds <: 0x0; } - set_node_pll_reg(tile[0], PLL_NOM); - //if(nudge != old_nudge && nudge){debug_printf("nudge: %d\n", nudge); }old_nudge = nudge; + write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_NOM); } void setup_audio_gpio(out port p_gpio){ diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index f83f3e2c..863d8505 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -70,7 +70,7 @@ void AudioHub(server i2s_frame_callback_if i2s, } pll_nudge(clock_nudge); - //tmr :> t1; debug_printf("%d\n", t1 - t0); + //tmr :> t1; if (t1-t0 > 500) debug_printf("*%d\n", t1 - t0); //delay_microseconds(10); //Test backpressure tolerance break; } diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 8b1d832d..b784691c 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -103,27 +103,25 @@ static void do_feedback_calculation(unsigned &sof_count ,long long &feedback_value ,unsigned &mod_from_last_time ,unsigned fb_clocks[1]){ - /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) - * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. - * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. - * Average over 128 SOFs - 128 x 3072 = 0x60000. */ + // Assuming 48kHz from a 24.576 master clock (0.0407uS period) + // MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. + // expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. + // Average over 128 SOFs - 128 x 3072 = 0x60000. unsigned long long feedbackMul = 64ULL; - if(AUDIO_CLASS == 1) - feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ + if(AUDIO_CLASS == 1) feedbackMul = 8ULL; // TODO Use 4 instead of 8 to avoid windows LSB issues? - /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ + // Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) int mclk_ticks_this_sof_period = (int) ((short)(mclk_port_counter - mclk_port_counter_old)); unsigned long long full_result = mclk_ticks_this_sof_period * feedbackMul * DEFAULT_FREQ; feedback_value += full_result; - /* Store MCLK for next time around... */ + // Store MCLK for next time around... mclk_port_counter_old = mclk_port_counter; - /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll - * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ - if(sof_count == 128) - { + // Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll + // We always count 128 SOFs, so 16ms @ HS, 128ms @ FS + if(sof_count == 128){ //debug_printf("fb\n"); sof_count = 0; @@ -132,36 +130,31 @@ static void do_feedback_calculation(unsigned &sof_count mod_from_last_time = feedback_value % mclk_hz; feedback_value = 0; - //Scale for working out number of samps to take from device for input - if(AUDIO_CLASS == 2) - { + if(AUDIO_CLASS == 2){ clocks <<= 3; } - else - { + else{ clocks <<= 6; } asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks //Write to feedback EP buffer - if (AUDIO_CLASS == 2) - { + if (AUDIO_CLASS == 2){ fb_clocks[0] = clocks; } - else - { + else{ fb_clocks[0] = clocks >> 2; } } } void fill_level_process(int fill_level, int &clock_nudge){ - const int trigger_high_upper = 6; - //const int trigger_high_lower = 8; + //Because we always check level after USB has produced a block, and total FIFO size is 2x max, half full is at 3/4 + const int half_full_out = ((MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2) * 3) / 4; - const int trigger_low_upper = -6; - //const int trigger_low_lower = -8; + const int trigger_high_upper = half_full_out + 4; + const int trigger_low_upper = half_full_out - 4; if (fill_level >= trigger_high_upper){ clock_nudge = 1; @@ -250,7 +243,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o //Send initial samples so audiohub is not blocked - for (int i = 0; i < NUM_USB_CHAN_OUT * 2; i++) c_audio_hub <: 0; + for (int i = 0; i < 2 * (NUM_USB_CHAN_OUT + (XUA_ADAPTIVE != 0 ? 1 : 0)); i++) c_audio_hub <: 0; //FIFOs from EP buffers to audio short host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; @@ -263,7 +256,8 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o //XUD transaction variables passed in by reference XUD_Result_t result; unsigned length = 0; - unsigned u_tmp; //For select channel input by ref + unsigned u_tmp; //For select channel input by ref on EP0 + int s_tmp; //For select on channel from audiohub while(1){ #pragma ordered select{ @@ -301,7 +295,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; - int fill_level = fifo_get_fill_relative_half_short(host_to_device_fifo_ptr); + int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); fill_level_process(fill_level, clock_nudge); //Mark EP as ready for next frame from host @@ -340,12 +334,12 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o break; //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO - case c_audio_hub :> u_tmp: + case c_audio_hub :> s_tmp: timer tmr; int t0, t1; tmr :> t0; - samples_in_short[0] = (int)u_tmp >> 16; + samples_in_short[0] = s_tmp >> 16; for (int i = 1; i < NUM_USB_CHAN_IN; i++){ - c_audio_hub :> u_tmp; - samples_in_short[i] = (int)u_tmp >> 16; + c_audio_hub :> s_tmp; + samples_in_short[i] = s_tmp >> 16; } fifo_ret_t ret = fifo_block_pop_short(host_to_device_fifo_ptr, samples_out_short, NUM_USB_CHAN_OUT); if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); @@ -414,7 +408,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, //Send initial samples so audiohub is not blocked - for (int i = 0; i < NUM_USB_CHAN_OUT * 6; i++) c_audio_hub <: 0; + for (int i = 0; i < 2 * (NUM_USB_CHAN_OUT + (XUA_ADAPTIVE != 0 ? 1 : 0)); i++) c_audio_hub <: 0; //FIFOs from EP buffers to audio short host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; @@ -424,29 +418,22 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, volatile mem_fifo_short_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; volatile mem_fifo_short_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; - //debug - const unsigned trig_period = 100000000; //1s - timer tmr; - unsigned sc = 0; - unsigned ac = 0; - unsigned hc = 0; - unsigned tmr_trig; - tmr :> tmr_trig; - tmr_trig += trig_period; - //XUD transaction variables passed in by reference XUD_Result_t result; unsigned length = 0; - unsigned u_tmp; //For select channel input by ref + unsigned u_tmp; //For select channel input by ref on EP0 + int s_tmp; //For select on channel from audiohub while(1){ select{ //Handle EP0 requests case i_ep0_ctl.set_output_interface(unsigned num): output_interface_num = num; + debug_printf("output_interface_num: %d\n", num); break; case i_ep0_ctl.set_input_interface(unsigned num): input_interface_num = num; + debug_printf("input_interface_num: %d\n", num); break; case i_ep0_ctl.set_host_active(unsigned active): @@ -460,9 +447,6 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, if (!isnull(c_feedback)) do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); sof_count++; //tmr :> t1; debug_printf("s%d\n", t1 - t0); - p_sda <: 1; - p_sda <: 0; - sc++; break; //Receive samples from host @@ -470,13 +454,14 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, timer tmr; int t0, t1; tmr :> t0; num_samples_received_from_host = length / out_subslot_size; - hc += num_samples_received_from_host / NUM_USB_CHAN_OUT; + + if (num_samples_received_from_host != 96) debug_printf("hs: %d\n", num_samples_received_from_host); fifo_ret_t ret = fifo_block_push_short_fast(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; - int fill_level = fifo_get_fill_relative_half_short(host_to_device_fifo_ptr); + int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); fill_level_process(fill_level, clock_nudge); //Mark EP as ready for next frame from host @@ -491,7 +476,6 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); //debug_printf("0x%x\n", fb_clocks[0]); //tmr :> t1; debug_printf("f%d\n", t1 - t0); - break; //Send samples to host @@ -514,22 +498,13 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, //tmr :> t1; debug_printf("i%d\n", t1 - t0); break; - case tmr when timerafter(tmr_trig) :> int _: - tmr_trig += trig_period; - debug_printf("HOST: %d SAMP: %d SOF: %d\n", ac, hc, sc); - sc = 0; - ac = 0; - hc = 0; - break; - //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO - case c_audio_hub :> u_tmp: + case c_audio_hub :> s_tmp: timer tmr; int t0, t1; tmr :> t0; - samples_in_short[0] = (int)u_tmp >> 16; - ac++; + samples_in_short[0] = s_tmp >> 16; for (int i = 1; i < NUM_USB_CHAN_IN; i++){ - c_audio_hub :> u_tmp; - samples_in_short[i] = (int)u_tmp >> 16; + c_audio_hub :> s_tmp; + samples_in_short[i] = s_tmp >> 16; } fifo_ret_t ret = fifo_block_pop_short(host_to_device_fifo_ptr, samples_out_short, NUM_USB_CHAN_OUT); if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); From 6333ca562124bfbcd214fa0216141bb096f1df1d Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 14 Nov 2018 10:05:00 +0000 Subject: [PATCH 045/123] Move pack/unpack to external helper --- .../xua_lite_example/src/xua_buffer_lite.xc | 65 ------------------- .../xua_lite_example/src/xua_buffer_pack.h | 65 +++++++++++++++++++ 2 files changed, 65 insertions(+), 65 deletions(-) create mode 100644 examples/xua_lite_example/src/xua_buffer_pack.h diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index b784691c..eeffb5bc 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -30,71 +30,6 @@ #define OUT_AUDIO_BUFFER_SIZE_BYTES (MAX_OUT_SAMPLES_PER_SOF_PERIOD * MAX_OUTPUT_SLOT_SIZE) #define IN_AUDIO_BUFFER_SIZE_BYTES (MAX_IN_SAMPLES_PER_SOF_PERIOD * MAX_INPUT_SLOT_SIZE) -//Helper to disassemble USB packets into 32b left aligned audio samples -#pragma unsafe arrays -static inline void unpack_buff_to_samples(unsigned char input[], const unsigned n_samples, const unsigned slot_size, int output[]){ - switch(slot_size){ - case 4: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 4; - output[i] = (input[base + 3] << 24) | (input[base + 2] << 16) | (input[base + 1] << 8) | input[base + 0]; - } - break; - case 3: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 3; - output[i] = (input[base + 2] << 24) | (input[base + 1] << 16) | (input[base + 0] << 8); - } - break; - case 2: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 2; - output[i] = (input[base + 1] << 24) | (input[base + 0] << 16); - } - break; - default: - debug_printf("Invalid slot_size\n"); - break; - } -} - -//Helper to assemble USB packets from 32b left aligned audio samples -#pragma unsafe arrays -static inline void pack_samples_to_buff(int input[], const unsigned n_samples, const unsigned slot_size, unsigned char output[]){ - switch(slot_size){ - case 4: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 4; - unsigned in_word = (unsigned)input[i]; - output[base + 0] = in_word & 0xff; - output[base + 1] = (in_word & 0xff00) >> 8; - output[base + 2] = (in_word & 0xff0000) >> 16; - output[base + 3] = (in_word) >> 24; - } - break; - case 3: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 3; - unsigned in_word = (unsigned)input[i]; - output[base + 0] = (in_word & 0xff00) >> 8; - output[base + 1] = (in_word & 0xff0000) >> 16; - output[base + 2] = (in_word) >> 24; - } - break; - case 2: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 2; - unsigned in_word = (unsigned)input[i]; - output[base + 0] = (in_word & 0xff0000) >> 16; - output[base + 1] = (in_word) >> 24; - } - break; - default: - debug_printf("Invalid slot_size\n"); - break; - } -} - static void do_feedback_calculation(unsigned &sof_count ,const unsigned mclk_hz diff --git a/examples/xua_lite_example/src/xua_buffer_pack.h b/examples/xua_lite_example/src/xua_buffer_pack.h new file mode 100644 index 00000000..36fc2f33 --- /dev/null +++ b/examples/xua_lite_example/src/xua_buffer_pack.h @@ -0,0 +1,65 @@ +//Helper to disassemble USB packets into 32b left aligned audio samples +#pragma unsafe arrays +static inline void unpack_buff_to_samples(unsigned char input[], const unsigned n_samples, const unsigned slot_size, int output[]){ + switch(slot_size){ + case 4: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 4; + output[i] = (input[base + 3] << 24) | (input[base + 2] << 16) | (input[base + 1] << 8) | input[base + 0]; + } + break; + case 3: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 3; + output[i] = (input[base + 2] << 24) | (input[base + 1] << 16) | (input[base + 0] << 8); + } + break; + case 2: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 2; + output[i] = (input[base + 1] << 24) | (input[base + 0] << 16); + } + break; + default: + debug_printf("Invalid slot_size\n"); + break; + } +} + +//Helper to assemble USB packets from 32b left aligned audio samples +#pragma unsafe arrays +static inline void pack_samples_to_buff(int input[], const unsigned n_samples, const unsigned slot_size, unsigned char output[]){ + switch(slot_size){ + case 4: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 4; + unsigned in_word = (unsigned)input[i]; + output[base + 0] = in_word & 0xff; + output[base + 1] = (in_word & 0xff00) >> 8; + output[base + 2] = (in_word & 0xff0000) >> 16; + output[base + 3] = (in_word) >> 24; + } + break; + case 3: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 3; + unsigned in_word = (unsigned)input[i]; + output[base + 0] = (in_word & 0xff00) >> 8; + output[base + 1] = (in_word & 0xff0000) >> 16; + output[base + 2] = (in_word) >> 24; + } + break; + case 2: + for (int i = 0; i < n_samples; i++){ + unsigned base = i * 2; + unsigned in_word = (unsigned)input[i]; + output[base + 0] = (in_word & 0xff0000) >> 16; + output[base + 1] = (in_word) >> 24; + } + break; + default: + debug_printf("Invalid slot_size\n"); + break; + } +} + From d92614ced9afb5d599b7323180722316ae2f9d5f Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 14 Nov 2018 10:13:29 +0000 Subject: [PATCH 046/123] Interface number now passed back to app from EP0 --- lib_xua/src/core/endpoint0/xua_endpoint0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index 48711656..0304369e 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -848,13 +848,13 @@ void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend switch (sp.wIndex) { /* Check for audio stream from host start/stop */ -#if (NUM_USB_CHAN_OUT > 0) && (AUDIO_CLASS == 2) +#if (NUM_USB_CHAN_OUT > 0) case INTERFACE_NUMBER_AUDIO_OUTPUT: *output_interface_num = sp.wValue; break; #endif -#if (NUM_USB_CHAN_IN > 0) && (AUDIO_CLASS == 2) +#if (NUM_USB_CHAN_IN > 0) case INTERFACE_NUMBER_AUDIO_INPUT: *input_interface_num = sp.wValue; break; From ad5c2e858340b3da13631afe05d3e965e6174e30 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 14 Nov 2018 10:13:50 +0000 Subject: [PATCH 047/123] Underflow now provides zeros --- examples/xua_lite_example/src/xua_buffer_lite.xc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index eeffb5bc..14cc38d5 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -421,7 +421,10 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; fifo_ret_t ret = fifo_block_pop_short_fast(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); + if (ret != FIFO_SUCCESS) { + memset(buffer_aud_in.short_words, 0, sizeof(buffer_aud_in.short_words)); + debug_printf("d2h empty\n"); + } //Populate the input buffer ready for the next read //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); @@ -442,7 +445,10 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, samples_in_short[i] = s_tmp >> 16; } fifo_ret_t ret = fifo_block_pop_short(host_to_device_fifo_ptr, samples_out_short, NUM_USB_CHAN_OUT); - if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); + if (ret != FIFO_SUCCESS && output_interface_num != 0) { + memset(samples_out_short, 0, sizeof(samples_out_short)); + debug_printf("h2d empty\n"); + } for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: (int)samples_out_short[i] << 16; if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; ret = fifo_block_push_short(device_to_host_fifo_ptr, samples_in_short, NUM_USB_CHAN_IN); From 436e8f4bd4cc9c7e5677d0a29f362ffabaa43b9a Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 14 Nov 2018 10:36:10 +0000 Subject: [PATCH 048/123] Reduce backpressure on pll_nudge --- examples/xua_lite_example/src/audio_config.xc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/examples/xua_lite_example/src/audio_config.xc b/examples/xua_lite_example/src/audio_config.xc index 5a523156..92506acf 100755 --- a/examples/xua_lite_example/src/audio_config.xc +++ b/examples/xua_lite_example/src/audio_config.xc @@ -51,11 +51,6 @@ #define DAC3101_REGWRITE(reg, val) {i_i2c.write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);} - -static void set_node_pll_reg(tileref tile_ref, unsigned reg_val){ - write_sswitch_reg(get_tile_id(tile_ref), XS1_SSWITCH_PLL_CTL_NUM, reg_val); -} - // Nominal setting is ref div = 25, fb_div = 1024, op_div = 2 // PCF Freq 0.96MHz @@ -71,21 +66,22 @@ enum clock_nudge{ on tile[0]: out port p_leds = XS1_PORT_4F; -int old_nudge = 0; +//Note use of no_ack write to prevent backpressure. There is enough buffering to +//store both writes so we can move on without blocking void pll_nudge(int nudge) { if (nudge > 0){ - write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_HIGH); + write_sswitch_reg_no_ack(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_HIGH); p_leds <: 0x02; //LED B } else if (nudge < 0){ - write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_LOW); + write_sswitch_reg_no_ack(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_LOW); p_leds <: 0x01; //LED A } else { p_leds <: 0x0; } - write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_NOM); + write_sswitch_reg_no_ack(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_NOM); } void setup_audio_gpio(out port p_gpio){ From 25f94fe43056176a10477c909d29300d3c57a8fd Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 14 Nov 2018 10:36:43 +0000 Subject: [PATCH 049/123] reduce deadband on buffer level + debug --- examples/xua_lite_example/src/xua_buffer_lite.xc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index 14cc38d5..f2dde808 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -88,8 +88,8 @@ void fill_level_process(int fill_level, int &clock_nudge){ //Because we always check level after USB has produced a block, and total FIFO size is 2x max, half full is at 3/4 const int half_full_out = ((MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2) * 3) / 4; - const int trigger_high_upper = half_full_out + 4; - const int trigger_low_upper = half_full_out - 4; + const int trigger_high_upper = half_full_out + 2; + const int trigger_low_upper = half_full_out - 2; if (fill_level >= trigger_high_upper){ clock_nudge = 1; @@ -382,6 +382,9 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, if (!isnull(c_feedback)) do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); sof_count++; //tmr :> t1; debug_printf("s%d\n", t1 - t0); + uint16_t port_counter; + p_sda <: 1 @ port_counter; + p_sda @ port_counter + 10 <: 0; break; //Receive samples from host From 8e7e1bfc511007cc1f7b4fc7ace8636e43ad92d1 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Wed, 14 Nov 2018 11:40:22 +0000 Subject: [PATCH 050/123] Make channel preload more clear --- examples/xua_lite_example/src/xua_buffer_lite.xc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index f2dde808..bf0ceecc 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -343,7 +343,8 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, //Send initial samples so audiohub is not blocked - for (int i = 0; i < 2 * (NUM_USB_CHAN_OUT + (XUA_ADAPTIVE != 0 ? 1 : 0)); i++) c_audio_hub <: 0; + const unsigned n_sample_periods_to_preload = 2; + for (int i = 0; i < n_sample_periods_to_preload * (NUM_USB_CHAN_OUT + (XUA_ADAPTIVE != 0 ? 1 : 0)); i++) c_audio_hub <: 0; //FIFOs from EP buffers to audio short host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; From 19e6dca4458f63751b0a0e1d41b42a5a4e3a7a2b Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Tue, 20 Nov 2018 14:07:33 +0000 Subject: [PATCH 051/123] Initial PID implementation --- examples/xua_lite_example/src/audio_config.xc | 3 +- examples/xua_lite_example/src/audio_hub.xc | 10 +- .../xua_lite_example/src/xua_buffer_lite.xc | 122 +++++++++++++++++- examples/xua_lite_example/todo.txt | 3 +- 4 files changed, 126 insertions(+), 12 deletions(-) diff --git a/examples/xua_lite_example/src/audio_config.xc b/examples/xua_lite_example/src/audio_config.xc index 92506acf..9e1dcb82 100755 --- a/examples/xua_lite_example/src/audio_config.xc +++ b/examples/xua_lite_example/src/audio_config.xc @@ -60,6 +60,7 @@ enum clock_nudge{ PLL_FASTER = 1 }; +//These steps provide just under +-0.1% frequency jumps #define PLL_LOW 0xC003FE18 // This is 3.069MHz #define PLL_NOM 0xC003FF18 // This is 3.072MHz #define PLL_HIGH 0xC0040018 // This is 3.075MHz @@ -273,6 +274,6 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) } -//These are here just to silence compiler warnings +//These are here just to silence compiler warnings about unimplemented xua callbacks (not needed in xua lite) void AudioHwInit(){} void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC){} \ No newline at end of file diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 863d8505..1fb3c4f0 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -58,19 +58,23 @@ void AudioHub(server i2s_frame_callback_if i2s, restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; - //Transfer samples + //Transfer samples. Takes about 25 ticks for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; if (XUA_ADAPTIVE) c_audio :> clock_nudge; for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: raw_mics[i]; - //Grab mics + //Grab mics. Takes about 200 ticks currently current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); + //50 ticks unsafe { for (int i = 0; i < XUA_NUM_PDM_MICS; i++) raw_mics[i] = current->data[i][0]; } + //Taking about 160 ticks when adjusting, 100 when not + tmr :> t0; pll_nudge(clock_nudge); - //tmr :> t1; if (t1-t0 > 500) debug_printf("*%d\n", t1 - t0); + tmr :> t1; + if (t1-t0 > 500) debug_printf("*%d\n", t1 - t0); //delay_microseconds(10); //Test backpressure tolerance break; } diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index bf0ceecc..b31f35ef 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -1,5 +1,5 @@ #include - +#include #include #include "xua_commands.h" @@ -84,12 +84,119 @@ static void do_feedback_calculation(unsigned &sof_count } } -void fill_level_process(int fill_level, int &clock_nudge){ - //Because we always check level after USB has produced a block, and total FIFO size is 2x max, half full is at 3/4 - const int half_full_out = ((MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2) * 3) / 4; +#define CONTROL_LOOP 1 - const int trigger_high_upper = half_full_out + 2; - const int trigger_low_upper = half_full_out - 2; +typedef int32_t xua_lite_fixed_point_t; +#define XUA_LIGHT_FIXED_POINT_Q_BITS 10 //Including sign bit +#define XUA_LIGHT_FIXED_POINT_FRAC_BITS (32 - XUA_LIGHT_FIXED_POINT_Q_BITS) +#define XUA_LIGHT_FIXED_POINT_TOTAL_BITS (XUA_LIGHT_FIXED_POINT_Q_BITS + XUA_LIGHT_FIXED_POINT_FRAC_BITS) +#define XUA_LIGHT_FIXED_POINT_ONE (1 << XUA_LIGHT_FIXED_POINT_FRAC_BITS) +#define XUA_LIGHT_FIXED_POINT_MINUS_ONE (-XUA_LIGHT_FIXED_POINT_ONE) + +#define FIFO_LEVEL_EMA_COEFF 0.98 //Proportion of signal from y[-1] +#define FIFO_LEVEL_A_COEFF ((int32_t)(INT_MAX * FIFO_LEVEL_EMA_COEFF)) //Scale to signed 1.31 format +#define FIFO_LEVEL_B_COEFF (INT_MAX - FIFO_LEVEL_A_COEFF) + +#define RANDOMISATION_PERCENT 0 //How much noise to inject in percent of existing signal amplitude +#define RANDOMISATION_COEFF_A ((INT_MAX / 100) * (100 - RANDOMISATION_PERCENT)) + +#define PI_CONTROL_P_TERM 3.0 +#define PI_CONTROL_I_TERM 1.5 +#define PI_CONTROL_P_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * PI_CONTROL_P_TERM)) //scale to fixed point +#define PI_CONTROL_I_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * PI_CONTROL_I_TERM)) //scale to fixed point + + +xua_lite_fixed_point_t do_fifo_depth_lowpass_filter(xua_lite_fixed_point_t old, int fifo_depth){ + //we grow from 32b to 64b for intermediate + int64_t intermediate = ((int64_t)(fifo_depth << XUA_LIGHT_FIXED_POINT_FRAC_BITS) * (int64_t)FIFO_LEVEL_B_COEFF) + ((int64_t)old * (int64_t)FIFO_LEVEL_A_COEFF); + xua_lite_fixed_point_t new_fifo_depth = (xua_lite_fixed_point_t)( intermediate >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); //-1 because signed int + return new_fifo_depth; +} + +static int32_t get_random_number(void) +{ + static const unsigned random_poly = 0xEDB88320; + static unsigned random = 0x12345678; + crc32(random, -1, random_poly); + return (int32_t) random; +} + +static xua_lite_fixed_point_t add_noise(xua_lite_fixed_point_t input){ + //Note the input number cannot be bigger than 2 ^ (FIXED_POINT_Q_BITS - 1) * (1 + PERCENT) else we could oveflow + //Eg. if Q bits = 10 then biggest input value is 255.9999 + int32_t random = get_random_number(); + int32_t input_fraction = ((int64_t)input * (int64_t)RANDOMISATION_COEFF_A) >> (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1); + int64_t output_64 = ((int64_t)input << (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)) + ((int64_t)input_fraction * (int64_t)random); + return (xua_lite_fixed_point_t)( output_64 >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); +} + +static void fill_level_process(int fill_level, int &clock_nudge){ + //Because we always check level after USB has produced a block, and total FIFO size is 2x max, half full is at 3/4 + const int half_full = ((MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2) * 3) / 4; + +#if CONTROL_LOOP + static xua_lite_fixed_point_t fifo_level_filtered = 0; + static xua_lite_fixed_point_t fifo_level_filtered_old = 0; + static xua_lite_fixed_point_t fifo_level_integrated = 0; + int fill_level_wrt_half = fill_level - half_full; //Will be +ve for more than half full and negative for less than half full + + //Do PI control + //Low pass filter fill level and get error w.r.t. to set point which is depth = 0 (relative to half full) + fifo_level_filtered = do_fifo_depth_lowpass_filter(fifo_level_filtered_old , fill_level_wrt_half); + //debug_printf("o: %d n: %d\n", fifo_level_filtered_old, fifo_level_filtered); + //Calculate integral term which is the accumulated fill level error + xua_lite_fixed_point_t i_term_pre_clip = fifo_level_integrated + fifo_level_filtered; + + //clip the I term. Check to see if overflow (which will change sign) + if (fifo_level_integrated > 0){ //If it was positive before, ensure it still is else clip to positive + if (i_term_pre_clip < 0){ + fifo_level_integrated = INT_MAX; + } + else{ + fifo_level_integrated = i_term_pre_clip; + } + } + else{ //Value was negative so ensure it still is else clip negative + if (i_term_pre_clip > 0){ + fifo_level_integrated = INT_MIN; + } + else{ + fifo_level_integrated = i_term_pre_clip; + } + } + + //Do PID calculation + xua_lite_fixed_point_t p_term = (((int64_t) fifo_level_filtered * (int64_t)PI_CONTROL_P_TERM_COEFF)) >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS + 2); + xua_lite_fixed_point_t i_term = (((int64_t) fifo_level_integrated * (int64_t)PI_CONTROL_I_TERM_COEFF)) >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS + 2); + debug_printf("p: %d i: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS); + + //Sum and scale to +- 1.0 (important it does not exceed these values for following step) + //xua_lite_fixed_point_t controller_out = (p_term + i_term) >> (XUA_LIGHT_FIXED_POINT_Q_BITS - 1); + xua_lite_fixed_point_t controller_out = p_term + i_term; + + static xua_lite_fixed_point_t nudge_accumulator = 0; + nudge_accumulator += controller_out; + //nudge_accumulator = add_noise(nudge_accumulator); + + //debug_printf("na: %d -1: %d\n", nudge_accumulator, XUA_LIGHT_FIXED_POINT_MINUS_ONE); + + if (nudge_accumulator >= XUA_LIGHT_FIXED_POINT_ONE){ + clock_nudge = 1; + nudge_accumulator -= XUA_LIGHT_FIXED_POINT_ONE; + } + else if (nudge_accumulator <= XUA_LIGHT_FIXED_POINT_MINUS_ONE){ + nudge_accumulator -= XUA_LIGHT_FIXED_POINT_MINUS_ONE; + clock_nudge = -1; + } + else{ + clock_nudge = 0; + } + + fifo_level_filtered_old = fifo_level_filtered; + //debug_printf("filtered: %d raw: %d\n", fifo_level_filtered >> 22, fill_level_wrt_half); +#else + const int trigger_high_upper = half_full + 2; + const int trigger_low_upper = half_full - 2; if (fill_level >= trigger_high_upper){ clock_nudge = 1; @@ -101,6 +208,7 @@ void fill_level_process(int fill_level, int &clock_nudge){ } else clock_nudge = 0; //debug_printf("%d\n", clock_nudge); +#endif static unsigned counter; counter++; if (counter>SOF_FREQ_HZ){counter = 0; debug_printf("f: %d\n",fill_level);} } @@ -385,7 +493,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, //tmr :> t1; debug_printf("s%d\n", t1 - t0); uint16_t port_counter; p_sda <: 1 @ port_counter; - p_sda @ port_counter + 10 <: 0; + p_sda @ port_counter + 100 <: 0; break; //Receive samples from host diff --git a/examples/xua_lite_example/todo.txt b/examples/xua_lite_example/todo.txt index d97eaa02..6c483267 100644 --- a/examples/xua_lite_example/todo.txt +++ b/examples/xua_lite_example/todo.txt @@ -1,7 +1,7 @@ - Bring ep0 serivice into xua_buffer select (make control mem) (DONE) - Tidy feeback endpoint (DONE) - Input path + FIFO (DONE) -- Function prototypes into includes +- Function prototypes into includes (DONE) - Single input/ouput format (DONE) - Get UAC1 / FS working (DONE) - Optimised EP buffer (either triple block or block FIFO) @@ -9,6 +9,7 @@ - Add timer to xua_buffer to prepare for exchange with audio (remove backpressure to audio) (WONT DO - use port buffer and reduce case overhead) - Adaptive endpoint EP and descriptors (DONE) - Adpative clock control (IN PROGRESS) +- Proper control loop w/filtering - Switchable MICS using define (WONT DO - separate app) - DFU - Combinable EP0 (DONE) From d7c96c717a1754cc2c52b54ad65b7492b6643822 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Tue, 20 Nov 2018 15:15:28 +0000 Subject: [PATCH 052/123] Fix saturating logic in PI controller --- .../xua_lite_example/src/xua_buffer_lite.xc | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index b31f35ef..fd2323ff 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -97,11 +97,11 @@ typedef int32_t xua_lite_fixed_point_t; #define FIFO_LEVEL_A_COEFF ((int32_t)(INT_MAX * FIFO_LEVEL_EMA_COEFF)) //Scale to signed 1.31 format #define FIFO_LEVEL_B_COEFF (INT_MAX - FIFO_LEVEL_A_COEFF) -#define RANDOMISATION_PERCENT 0 //How much noise to inject in percent of existing signal amplitude -#define RANDOMISATION_COEFF_A ((INT_MAX / 100) * (100 - RANDOMISATION_PERCENT)) +#define RANDOMISATION_PERCENT 50 //How much noise to inject in percent of existing signal amplitude +#define RANDOMISATION_COEFF_A ((INT_MAX / 100) * RANDOMISATION_PERCENT) -#define PI_CONTROL_P_TERM 3.0 -#define PI_CONTROL_I_TERM 1.5 +#define PI_CONTROL_P_TERM 15.0 +#define PI_CONTROL_I_TERM 1.1 #define PI_CONTROL_P_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * PI_CONTROL_P_TERM)) //scale to fixed point #define PI_CONTROL_I_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * PI_CONTROL_I_TERM)) //scale to fixed point @@ -148,35 +148,39 @@ static void fill_level_process(int fill_level, int &clock_nudge){ xua_lite_fixed_point_t i_term_pre_clip = fifo_level_integrated + fifo_level_filtered; //clip the I term. Check to see if overflow (which will change sign) - if (fifo_level_integrated > 0){ //If it was positive before, ensure it still is else clip to positive - if (i_term_pre_clip < 0){ - fifo_level_integrated = INT_MAX; + if (fifo_level_filtered > 0){ //If it was positive before, ensure it still is else clip to positive + if (i_term_pre_clip > fifo_level_integrated){ + fifo_level_integrated = i_term_pre_clip; } else{ - fifo_level_integrated = i_term_pre_clip; + fifo_level_integrated = INT_MAX; + debug_printf("clip+ %d\n", fifo_level_integrated); } } else{ //Value was negative so ensure it still is else clip negative - if (i_term_pre_clip > 0){ - fifo_level_integrated = INT_MIN; + if (i_term_pre_clip < fifo_level_integrated){ + fifo_level_integrated = i_term_pre_clip; } else{ - fifo_level_integrated = i_term_pre_clip; + fifo_level_integrated = INT_MIN; + debug_printf("clip- %d %d\n", fifo_level_integrated, fifo_level_filtered); } } //Do PID calculation xua_lite_fixed_point_t p_term = (((int64_t) fifo_level_filtered * (int64_t)PI_CONTROL_P_TERM_COEFF)) >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS + 2); xua_lite_fixed_point_t i_term = (((int64_t) fifo_level_integrated * (int64_t)PI_CONTROL_I_TERM_COEFF)) >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS + 2); - debug_printf("p: %d i: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS); + debug_printf("p: %d i: %d f: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, fill_level_wrt_half); //Sum and scale to +- 1.0 (important it does not exceed these values for following step) //xua_lite_fixed_point_t controller_out = (p_term + i_term) >> (XUA_LIGHT_FIXED_POINT_Q_BITS - 1); - xua_lite_fixed_point_t controller_out = p_term + i_term; + xua_lite_fixed_point_t controller_out = (p_term + i_term); + + controller_out = add_noise(controller_out); + static xua_lite_fixed_point_t nudge_accumulator = 0; nudge_accumulator += controller_out; - //nudge_accumulator = add_noise(nudge_accumulator); //debug_printf("na: %d -1: %d\n", nudge_accumulator, XUA_LIGHT_FIXED_POINT_MINUS_ONE); From 0b2839c9fc88018f2b6f4ffc0e530df290b9962c Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 23 Nov 2018 11:45:26 +0000 Subject: [PATCH 053/123] Update todo list --- examples/xua_lite_example/todo.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/xua_lite_example/todo.txt b/examples/xua_lite_example/todo.txt index 6c483267..4d0ab456 100644 --- a/examples/xua_lite_example/todo.txt +++ b/examples/xua_lite_example/todo.txt @@ -1,20 +1,22 @@ - Bring ep0 serivice into xua_buffer select (make control mem) (DONE) -- Tidy feeback endpoint (DONE) +- Tidy feedback endpoint (DONE) - Input path + FIFO (DONE) - Function prototypes into includes (DONE) - Single input/ouput format (DONE) - Get UAC1 / FS working (DONE) -- Optimised EP buffer (either triple block or block FIFO) +- Optimised EP buffer (either triple block or block FIFO) (DONE) - Fix output gain issue (IN PROGRESS) - Add timer to xua_buffer to prepare for exchange with audio (remove backpressure to audio) (WONT DO - use port buffer and reduce case overhead) - Adaptive endpoint EP and descriptors (DONE) - Adpative clock control (IN PROGRESS) -- Proper control loop w/filtering +- Proper control loop w/filtering (IN PROGRESS) - Switchable MICS using define (WONT DO - separate app) - DFU - Combinable EP0 (DONE) - Interrupt EP0 option - Control processing - Fix cast warning (DONE) -- Work out why no clock drift on Android / OSX (drift seen on Linux and Win) +- Work out why no clock drift on Android / OSX (drift seen on Linux and Win) (DONE) - Tidy/cut down EP0 handling +- Broader host testing (Android, W10, MAC) (IN PROGRESS) +- Peer review From 45d84a2b84a861083d61482cebb48ef3e9a77690 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 30 Nov 2018 10:14:34 +0000 Subject: [PATCH 054/123] PID loop development + move rate control to own source files --- examples/xua_lite_example/src/fifo_impl.h | 8 + .../xua_lite_example/src/rate_controller.h | 17 ++ .../xua_lite_example/src/rate_controller.xc | 190 +++++++++++++++ .../xua_lite_example/src/xua_buffer_lite.h | 19 ++ .../xua_lite_example/src/xua_buffer_lite.xc | 216 +----------------- 5 files changed, 243 insertions(+), 207 deletions(-) create mode 100644 examples/xua_lite_example/src/rate_controller.h create mode 100644 examples/xua_lite_example/src/rate_controller.xc diff --git a/examples/xua_lite_example/src/fifo_impl.h b/examples/xua_lite_example/src/fifo_impl.h index 3341f32a..32c297dd 100644 --- a/examples/xua_lite_example/src/fifo_impl.h +++ b/examples/xua_lite_example/src/fifo_impl.h @@ -38,6 +38,14 @@ static inline unsigned fifo_get_fill_short(volatile mem_fifo_short_t * unsafe fi } } +static inline void fifo_init_short(volatile mem_fifo_short_t * unsafe fifo) { + unsafe{ + fifo->write_idx = 0; + fifo->read_idx = (fifo->size * 2) / 4; + memset(fifo->data_base_ptr , 0, fifo->size * sizeof(short)); + } +} + #pragma unsafe arrays static inline fifo_ret_t fifo_block_push(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { unsafe{ diff --git a/examples/xua_lite_example/src/rate_controller.h b/examples/xua_lite_example/src/rate_controller.h new file mode 100644 index 00000000..23afa87f --- /dev/null +++ b/examples/xua_lite_example/src/rate_controller.h @@ -0,0 +1,17 @@ +#include +#include + +typedef int32_t xua_lite_fixed_point_t; + +typedef struct pid_state_t{ + xua_lite_fixed_point_t fifo_level_filtered_old; + xua_lite_fixed_point_t fifo_level_accum; +} pid_state_t; + + +//USB Adaptive mode helper +void do_rate_control(int fill_level, pid_state_t *pid_state, int *clock_nudge); + +//USB Asynch mode helper +void do_feedback_calculation(unsigned &sof_count, const unsigned mclk_hz, unsigned mclk_port_counter,unsigned &mclk_port_counter_old + ,long long &feedback_value, unsigned &mod_from_last_time, unsigned fb_clocks[1]); \ No newline at end of file diff --git a/examples/xua_lite_example/src/rate_controller.xc b/examples/xua_lite_example/src/rate_controller.xc new file mode 100644 index 00000000..e381cacb --- /dev/null +++ b/examples/xua_lite_example/src/rate_controller.xc @@ -0,0 +1,190 @@ +#include +#include "xua_buffer_lite.h" +#include "rate_controller.h" +#define DEBUG_UNIT XUA_RATE_CONTROL +#define DEBUG_PRINT_ENABLE_XUA_RATE_CONTROL 1 +#include "debug_print.h" + +#define XUA_LIGHT_FIXED_POINT_Q_BITS 10 //Including sign bit. 10b gets us to +511.999999 to -512.000000 +#define XUA_LIGHT_FIXED_POINT_TOTAL_BITS (sizeof(xua_lite_fixed_point_t) * 8) +#define XUA_LIGHT_FIXED_POINT_FRAC_BITS (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - XUA_LIGHT_FIXED_POINT_Q_BITS) +#define XUA_LIGHT_FIXED_POINT_ONE (1 << XUA_LIGHT_FIXED_POINT_FRAC_BITS) +#define XUA_LIGHT_FIXED_POINT_MINUS_ONE (-XUA_LIGHT_FIXED_POINT_ONE) + +#define FIFO_LEVEL_EMA_COEFF 0.8 //Proportion of signal from y[-1] +#define FIFO_LEVEL_A_COEFF ((int32_t)(INT_MAX * FIFO_LEVEL_EMA_COEFF)) //Scale to signed 1.31 format +#define FIFO_LEVEL_B_COEFF (INT_MAX - FIFO_LEVEL_A_COEFF) + +#define RANDOMISATION_PERCENT 50 //How much noise to inject in percent of existing signal amplitude +#define RANDOMISATION_COEFF_A ((INT_MAX / 100) * RANDOMISATION_PERCENT) + +#define PID_CONTROL_P_TERM 6.0 +#define PID_CONTROL_I_TERM 0.0 +#define PID_CONTROL_D_TERM 0.0 + +#define PID_RATE_MULTIPLIER SOF_FREQ_HZ + +#define PID_CONTROL_P_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * (float)PID_CONTROL_P_TERM)) //scale to fixed point +#define PID_CONTROL_I_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * (float)PID_CONTROL_I_TERM / PID_RATE_MULTIPLIER)) //scale to fixed point +#define PID_CONTROL_D_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * (float)PID_CONTROL_D_TERM)) //scale to fixed point + +#define PID_CALC_OVERHEAD_BITS 6 //Allow large P,I or D constants, up to 2^(this number) + +static inline xua_lite_fixed_point_t do_fifo_depth_lowpass_filter(xua_lite_fixed_point_t old, int fifo_depth){ + //we grow from 32b to 64b for intermediate + int64_t intermediate = ((int64_t)(fifo_depth << XUA_LIGHT_FIXED_POINT_FRAC_BITS) * (int64_t)FIFO_LEVEL_B_COEFF) + ((int64_t)old * (int64_t)FIFO_LEVEL_A_COEFF); + xua_lite_fixed_point_t new_fifo_depth = (xua_lite_fixed_point_t)( intermediate >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); //-1 because signed int + return new_fifo_depth; +} + +static inline int32_t get_random_number(void) +{ + static const unsigned random_poly = 0xEDB88320; + static unsigned random = 0x12345678; + crc32(random, -1, random_poly); + return (int32_t) random; +} + +static inline xua_lite_fixed_point_t add_noise(xua_lite_fixed_point_t input){ + //Note the input number cannot be bigger than 2 ^ (FIXED_POINT_Q_BITS - 1) * (1 + PERCENT) else we could oveflow + //Eg. if Q bits = 10 then biggest input value is 255.9999 + int32_t random = get_random_number(); + int32_t input_fraction = ((int64_t)input * (int64_t)RANDOMISATION_COEFF_A) >> (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1); + int64_t output_64 = ((int64_t)input << (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)) + ((int64_t)input_fraction * (int64_t)random); + return (xua_lite_fixed_point_t)( output_64 >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); +} + +//Do PI control and modulation for adaptive USB audio +void do_rate_control(int fill_level, pid_state_t *pid_state, int *clock_nudge){ + + //We always check the FIFO level after USB has produced a block, and total FIFO size is 2x max, so half full is at 3/4 + const int half_full = ((MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2) * 3) / 4; + int fill_level_wrt_half = fill_level - half_full; //Will be +ve for more than half full and negative for less than half full + + //Low pass filter fill level and get error w.r.t. to set point which is depth = 0 (relative to half full) + xua_lite_fixed_point_t fifo_level_filtered = do_fifo_depth_lowpass_filter(pid_state->fifo_level_filtered_old , fill_level_wrt_half); + //printf("old fill_level: %f fill_level: %f\n", (float)pid_state->fifo_level_filtered_old/(1<fifo_level_accum + fifo_level_filtered; + + //clip the I term (which can wind up) to maximum fixed point representation. Check to see if overflow (which will change sign) + if (fifo_level_filtered >= 0){ //If it was positive before, ensure it still is else clip to positive + if (i_term_pre_clip >= pid_state->fifo_level_accum){ + //debug_printf("grow %d %d\n", (int32_t)i_term_pre_clip, (int32_t)pid_state->fifo_level_accum); + pid_state->fifo_level_accum = i_term_pre_clip; + } + else{ + pid_state->fifo_level_accum = INT_MAX; + //debug_printf("clip+ %d\n", pid_state->fifo_level_accum); + } + } + else{ //Value was negative so ensure it still is else clip negative + if (i_term_pre_clip <= pid_state->fifo_level_accum){ + pid_state->fifo_level_accum = i_term_pre_clip; + } + else{ + pid_state->fifo_level_accum = INT_MIN; + //debug_printf("clip- %d %d\n", pid_state->fifo_level_accum, fifo_level_filtered); + } + } + + //Calculate D term. No clipping required because it can never be larger than the D term, + //which is already scaled to fit within the fixed point representation + xua_lite_fixed_point_t fifo_level_delta = fifo_level_filtered - pid_state->fifo_level_filtered_old; + + + //Do PID calculation. Note there is an implicit cast back to xua_lite_fixed_point_t before assignment + const unsigned pid_mul_r_shift_bits = XUA_LIGHT_FIXED_POINT_FRAC_BITS + PID_CALC_OVERHEAD_BITS; + xua_lite_fixed_point_t p_term = (((int64_t) fifo_level_filtered * (int64_t)PID_CONTROL_P_TERM_COEFF)) >> pid_mul_r_shift_bits; + xua_lite_fixed_point_t i_term = (((int64_t) pid_state->fifo_level_accum * (int64_t)PID_CONTROL_I_TERM_COEFF)) >> pid_mul_r_shift_bits; + xua_lite_fixed_point_t d_term = (((int64_t) fifo_level_delta * (int64_t)PID_CONTROL_D_TERM_COEFF)) >> pid_mul_r_shift_bits; + + //debug_printf("p: %d i: %d f: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, fill_level_wrt_half); + //printf("p: %f i: %f d: %f filtered: %f integrated: %f\n", (float)p_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)i_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)d_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)fifo_level_filtered/(1<fifo_level_accum/(1<> (XUA_LIGHT_FIXED_POINT_Q_BITS - 1 - PID_CALC_OVERHEAD_BITS); + + //Randomise - add a proportion of rectangular probability distribution noise to spread the spectrum + controller_out = add_noise(controller_out); + + //Convert to pulse density modulation (sigma-delta) + static xua_lite_fixed_point_t nudge_accumulator = 0; + nudge_accumulator += controller_out; //Note no overflow check as if we reach XUA_LIGHT_FIXED_POINT_Q_BITS + //something is very wrong + //printf("co: %d ratio: %f \n", controller_out, (float)controller_out/XUA_LIGHT_FIXED_POINT_ONE); + if (nudge_accumulator >= XUA_LIGHT_FIXED_POINT_ONE){ + *clock_nudge = 1; + nudge_accumulator -= XUA_LIGHT_FIXED_POINT_ONE; + } + else if (nudge_accumulator <= XUA_LIGHT_FIXED_POINT_MINUS_ONE){ + nudge_accumulator -= XUA_LIGHT_FIXED_POINT_MINUS_ONE; + *clock_nudge = -1; + } + else{ + *clock_nudge = 0; + } + + pid_state->fifo_level_filtered_old = fifo_level_filtered; + //debug_printf("filtered: %d raw: %d\n", fifo_level_filtered >> 22, fill_level_wrt_half); + + static unsigned counter; counter++; if (counter>100){counter = 0; debug_printf("f: %d\n",fill_level_wrt_half);} +} + + +//Calculate feedback for asynchronous USB audio +void do_feedback_calculation(unsigned &sof_count + ,const unsigned mclk_hz + ,unsigned mclk_port_counter + ,unsigned &mclk_port_counter_old + ,long long &feedback_value + ,unsigned &mod_from_last_time + ,unsigned fb_clocks[1]){ + // Assuming 48kHz from a 24.576 master clock (0.0407uS period) + // MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. + // expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. + // Average over 128 SOFs - 128 x 3072 = 0x60000. + + unsigned long long feedbackMul = 64ULL; + if(AUDIO_CLASS == 1) feedbackMul = 8ULL; // TODO Use 4 instead of 8 to avoid windows LSB issues? + + // Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) + int mclk_ticks_this_sof_period = (int) ((short)(mclk_port_counter - mclk_port_counter_old)); + unsigned long long full_result = mclk_ticks_this_sof_period * feedbackMul * DEFAULT_FREQ; + feedback_value += full_result; + + // Store MCLK for next time around... + mclk_port_counter_old = mclk_port_counter; + + // Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll + // We always count 128 SOFs, so 16ms @ HS, 128ms @ FS + if(sof_count == 128){ + //debug_printf("fb\n"); + sof_count = 0; + + feedback_value += mod_from_last_time; + unsigned clocks = feedback_value / mclk_hz; + mod_from_last_time = feedback_value % mclk_hz; + feedback_value = 0; + + //Scale for working out number of samps to take from device for input + if(AUDIO_CLASS == 2){ + clocks <<= 3; + } + else{ + clocks <<= 6; + } + asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks + + //Write to feedback EP buffer + if (AUDIO_CLASS == 2){ + fb_clocks[0] = clocks; + } + else{ + fb_clocks[0] = clocks >> 2; + } + } +} + diff --git a/examples/xua_lite_example/src/xua_buffer_lite.h b/examples/xua_lite_example/src/xua_buffer_lite.h index 0a5a3366..0436b29c 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.h +++ b/examples/xua_lite_example/src/xua_buffer_lite.h @@ -1,5 +1,24 @@ #include #include "xua_ep0_wrapper.h" +#include "xua.h" + +//Currently only single frequency supported +#define NOMINAL_SR_DEVICE DEFAULT_FREQ +#define NOMINAL_SR_HOST DEFAULT_FREQ + +#define DIV_ROUND_UP(n, d) (n / d + 1) //Always rounds up to the next integer. Needed for 48001Hz case etc. +#define BIGGEST(a, b) (a > b ? a : b) + +#define SOF_FREQ_HZ (8000 - ((2 - AUDIO_CLASS) * 7000) ) //1000 for FS or 8000 for HS + +//Defines for endpoint buffer sizes. Samples is total number of samples across all channels +#define MAX_OUT_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_OUT) +#define MAX_IN_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_IN) +#define MAX_OUTPUT_SLOT_SIZE 4 +#define MAX_INPUT_SLOT_SIZE 4 + +#define OUT_AUDIO_BUFFER_SIZE_BYTES (MAX_OUT_SAMPLES_PER_SOF_PERIOD * MAX_OUTPUT_SLOT_SIZE) +#define IN_AUDIO_BUFFER_SIZE_BYTES (MAX_IN_SAMPLES_PER_SOF_PERIOD * MAX_INPUT_SLOT_SIZE) unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); [[combinable]] diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index fd2323ff..bed8e0ab 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -11,211 +11,8 @@ #include "xua.h" #include "fifo_impl.h" #include "xua_ep0_wrapper.h" - -//Currently only single frequency supported -#define NOMINAL_SR_DEVICE DEFAULT_FREQ -#define NOMINAL_SR_HOST DEFAULT_FREQ - -#define DIV_ROUND_UP(n, d) (n / d + 1) //Always rounds up to the next integer. Needed for 48001Hz case etc. -#define BIGGEST(a, b) (a > b ? a : b) - -#define SOF_FREQ_HZ (8000 - ((2 - AUDIO_CLASS) * 7000) ) - -//Defines for endpoint buffer sizes. Samples is total number of samples across all channels -#define MAX_OUT_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_OUT) -#define MAX_IN_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_IN) -#define MAX_OUTPUT_SLOT_SIZE 4 -#define MAX_INPUT_SLOT_SIZE 4 - -#define OUT_AUDIO_BUFFER_SIZE_BYTES (MAX_OUT_SAMPLES_PER_SOF_PERIOD * MAX_OUTPUT_SLOT_SIZE) -#define IN_AUDIO_BUFFER_SIZE_BYTES (MAX_IN_SAMPLES_PER_SOF_PERIOD * MAX_INPUT_SLOT_SIZE) - - -static void do_feedback_calculation(unsigned &sof_count - ,const unsigned mclk_hz - ,unsigned mclk_port_counter - ,unsigned &mclk_port_counter_old - ,long long &feedback_value - ,unsigned &mod_from_last_time - ,unsigned fb_clocks[1]){ - // Assuming 48kHz from a 24.576 master clock (0.0407uS period) - // MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. - // expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. - // Average over 128 SOFs - 128 x 3072 = 0x60000. - - unsigned long long feedbackMul = 64ULL; - if(AUDIO_CLASS == 1) feedbackMul = 8ULL; // TODO Use 4 instead of 8 to avoid windows LSB issues? - - // Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) - int mclk_ticks_this_sof_period = (int) ((short)(mclk_port_counter - mclk_port_counter_old)); - unsigned long long full_result = mclk_ticks_this_sof_period * feedbackMul * DEFAULT_FREQ; - feedback_value += full_result; - - // Store MCLK for next time around... - mclk_port_counter_old = mclk_port_counter; - - // Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll - // We always count 128 SOFs, so 16ms @ HS, 128ms @ FS - if(sof_count == 128){ - //debug_printf("fb\n"); - sof_count = 0; - - feedback_value += mod_from_last_time; - unsigned clocks = feedback_value / mclk_hz; - mod_from_last_time = feedback_value % mclk_hz; - feedback_value = 0; - - //Scale for working out number of samps to take from device for input - if(AUDIO_CLASS == 2){ - clocks <<= 3; - } - else{ - clocks <<= 6; - } - asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks - - //Write to feedback EP buffer - if (AUDIO_CLASS == 2){ - fb_clocks[0] = clocks; - } - else{ - fb_clocks[0] = clocks >> 2; - } - } -} - -#define CONTROL_LOOP 1 - -typedef int32_t xua_lite_fixed_point_t; -#define XUA_LIGHT_FIXED_POINT_Q_BITS 10 //Including sign bit -#define XUA_LIGHT_FIXED_POINT_FRAC_BITS (32 - XUA_LIGHT_FIXED_POINT_Q_BITS) -#define XUA_LIGHT_FIXED_POINT_TOTAL_BITS (XUA_LIGHT_FIXED_POINT_Q_BITS + XUA_LIGHT_FIXED_POINT_FRAC_BITS) -#define XUA_LIGHT_FIXED_POINT_ONE (1 << XUA_LIGHT_FIXED_POINT_FRAC_BITS) -#define XUA_LIGHT_FIXED_POINT_MINUS_ONE (-XUA_LIGHT_FIXED_POINT_ONE) - -#define FIFO_LEVEL_EMA_COEFF 0.98 //Proportion of signal from y[-1] -#define FIFO_LEVEL_A_COEFF ((int32_t)(INT_MAX * FIFO_LEVEL_EMA_COEFF)) //Scale to signed 1.31 format -#define FIFO_LEVEL_B_COEFF (INT_MAX - FIFO_LEVEL_A_COEFF) - -#define RANDOMISATION_PERCENT 50 //How much noise to inject in percent of existing signal amplitude -#define RANDOMISATION_COEFF_A ((INT_MAX / 100) * RANDOMISATION_PERCENT) - -#define PI_CONTROL_P_TERM 15.0 -#define PI_CONTROL_I_TERM 1.1 -#define PI_CONTROL_P_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * PI_CONTROL_P_TERM)) //scale to fixed point -#define PI_CONTROL_I_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * PI_CONTROL_I_TERM)) //scale to fixed point - - -xua_lite_fixed_point_t do_fifo_depth_lowpass_filter(xua_lite_fixed_point_t old, int fifo_depth){ - //we grow from 32b to 64b for intermediate - int64_t intermediate = ((int64_t)(fifo_depth << XUA_LIGHT_FIXED_POINT_FRAC_BITS) * (int64_t)FIFO_LEVEL_B_COEFF) + ((int64_t)old * (int64_t)FIFO_LEVEL_A_COEFF); - xua_lite_fixed_point_t new_fifo_depth = (xua_lite_fixed_point_t)( intermediate >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); //-1 because signed int - return new_fifo_depth; -} - -static int32_t get_random_number(void) -{ - static const unsigned random_poly = 0xEDB88320; - static unsigned random = 0x12345678; - crc32(random, -1, random_poly); - return (int32_t) random; -} - -static xua_lite_fixed_point_t add_noise(xua_lite_fixed_point_t input){ - //Note the input number cannot be bigger than 2 ^ (FIXED_POINT_Q_BITS - 1) * (1 + PERCENT) else we could oveflow - //Eg. if Q bits = 10 then biggest input value is 255.9999 - int32_t random = get_random_number(); - int32_t input_fraction = ((int64_t)input * (int64_t)RANDOMISATION_COEFF_A) >> (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1); - int64_t output_64 = ((int64_t)input << (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)) + ((int64_t)input_fraction * (int64_t)random); - return (xua_lite_fixed_point_t)( output_64 >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); -} - -static void fill_level_process(int fill_level, int &clock_nudge){ - //Because we always check level after USB has produced a block, and total FIFO size is 2x max, half full is at 3/4 - const int half_full = ((MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2) * 3) / 4; - -#if CONTROL_LOOP - static xua_lite_fixed_point_t fifo_level_filtered = 0; - static xua_lite_fixed_point_t fifo_level_filtered_old = 0; - static xua_lite_fixed_point_t fifo_level_integrated = 0; - int fill_level_wrt_half = fill_level - half_full; //Will be +ve for more than half full and negative for less than half full - - //Do PI control - //Low pass filter fill level and get error w.r.t. to set point which is depth = 0 (relative to half full) - fifo_level_filtered = do_fifo_depth_lowpass_filter(fifo_level_filtered_old , fill_level_wrt_half); - //debug_printf("o: %d n: %d\n", fifo_level_filtered_old, fifo_level_filtered); - //Calculate integral term which is the accumulated fill level error - xua_lite_fixed_point_t i_term_pre_clip = fifo_level_integrated + fifo_level_filtered; - - //clip the I term. Check to see if overflow (which will change sign) - if (fifo_level_filtered > 0){ //If it was positive before, ensure it still is else clip to positive - if (i_term_pre_clip > fifo_level_integrated){ - fifo_level_integrated = i_term_pre_clip; - } - else{ - fifo_level_integrated = INT_MAX; - debug_printf("clip+ %d\n", fifo_level_integrated); - } - } - else{ //Value was negative so ensure it still is else clip negative - if (i_term_pre_clip < fifo_level_integrated){ - fifo_level_integrated = i_term_pre_clip; - } - else{ - fifo_level_integrated = INT_MIN; - debug_printf("clip- %d %d\n", fifo_level_integrated, fifo_level_filtered); - } - } - - //Do PID calculation - xua_lite_fixed_point_t p_term = (((int64_t) fifo_level_filtered * (int64_t)PI_CONTROL_P_TERM_COEFF)) >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS + 2); - xua_lite_fixed_point_t i_term = (((int64_t) fifo_level_integrated * (int64_t)PI_CONTROL_I_TERM_COEFF)) >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS + 2); - debug_printf("p: %d i: %d f: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, fill_level_wrt_half); - - //Sum and scale to +- 1.0 (important it does not exceed these values for following step) - //xua_lite_fixed_point_t controller_out = (p_term + i_term) >> (XUA_LIGHT_FIXED_POINT_Q_BITS - 1); - xua_lite_fixed_point_t controller_out = (p_term + i_term); - - controller_out = add_noise(controller_out); - - - static xua_lite_fixed_point_t nudge_accumulator = 0; - nudge_accumulator += controller_out; - - //debug_printf("na: %d -1: %d\n", nudge_accumulator, XUA_LIGHT_FIXED_POINT_MINUS_ONE); - - if (nudge_accumulator >= XUA_LIGHT_FIXED_POINT_ONE){ - clock_nudge = 1; - nudge_accumulator -= XUA_LIGHT_FIXED_POINT_ONE; - } - else if (nudge_accumulator <= XUA_LIGHT_FIXED_POINT_MINUS_ONE){ - nudge_accumulator -= XUA_LIGHT_FIXED_POINT_MINUS_ONE; - clock_nudge = -1; - } - else{ - clock_nudge = 0; - } - - fifo_level_filtered_old = fifo_level_filtered; - //debug_printf("filtered: %d raw: %d\n", fifo_level_filtered >> 22, fill_level_wrt_half); -#else - const int trigger_high_upper = half_full + 2; - const int trigger_low_upper = half_full - 2; - - if (fill_level >= trigger_high_upper){ - clock_nudge = 1; - //debug_printf("Nudge down\n"); - } - else if (fill_level <= trigger_low_upper){ - //debug_printf("Nudge up\n"); - clock_nudge = -1; - } - else clock_nudge = 0; - //debug_printf("%d\n", clock_nudge); -#endif - - static unsigned counter; counter++; if (counter>SOF_FREQ_HZ){counter = 0; debug_printf("f: %d\n",fill_level);} -} +#include "rate_controller.h" +#include "xua_buffer_lite.h" extern "C"{ @@ -260,6 +57,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o //Adapative device clock control int clock_nudge = 0; + pid_state_t pid_state = {0, 0}; //Endpoints XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); @@ -343,7 +141,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o num_samples_to_send_to_host = num_samples_received_from_host; int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); - fill_level_process(fill_level, clock_nudge); + if (isnull(c_feedback)) do_rate_control(fill_level, &pid_state, &clock_nudge); //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); @@ -432,6 +230,8 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, //Adapative device clock control int clock_nudge = 0; + pid_state_t pid_state = {0, 0}; + //Endpoints XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); @@ -475,6 +275,8 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, select{ //Handle EP0 requests case i_ep0_ctl.set_output_interface(unsigned num): + //Reset output FIFO if moving from idle to streaming + if (num != 0 && output_interface_num == 0) fifo_init_short(host_to_device_fifo_ptr); output_interface_num = num; debug_printf("output_interface_num: %d\n", num); break; @@ -513,7 +315,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, num_samples_to_send_to_host = num_samples_received_from_host; int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); - fill_level_process(fill_level, clock_nudge); + if (isnull(c_feedback)) do_rate_control(fill_level, &pid_state, &clock_nudge); //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); From abd3141b0de1409d5f60ec5ecd64730f74cdc7dc Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 30 Nov 2018 11:43:55 +0000 Subject: [PATCH 055/123] PID tuning (with gnuplot script to display fifo level printed) --- examples/xua_lite_example/plot_fill_level.sh | 1 + .../xua_lite_example/src/rate_controller.xc | 32 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 examples/xua_lite_example/plot_fill_level.sh diff --git a/examples/xua_lite_example/plot_fill_level.sh b/examples/xua_lite_example/plot_fill_level.sh new file mode 100644 index 00000000..8adfd632 --- /dev/null +++ b/examples/xua_lite_example/plot_fill_level.sh @@ -0,0 +1 @@ +grep f: dump.txt | grep -Eo "\-?\d+" > proc.txt&& gnuplot -p -e 'set term png; plot "proc.txt" with lines' > plot.png && open plot.png \ No newline at end of file diff --git a/examples/xua_lite_example/src/rate_controller.xc b/examples/xua_lite_example/src/rate_controller.xc index e381cacb..6638f535 100644 --- a/examples/xua_lite_example/src/rate_controller.xc +++ b/examples/xua_lite_example/src/rate_controller.xc @@ -11,24 +11,28 @@ #define XUA_LIGHT_FIXED_POINT_ONE (1 << XUA_LIGHT_FIXED_POINT_FRAC_BITS) #define XUA_LIGHT_FIXED_POINT_MINUS_ONE (-XUA_LIGHT_FIXED_POINT_ONE) -#define FIFO_LEVEL_EMA_COEFF 0.8 //Proportion of signal from y[-1] +#define FIFO_LEVEL_EMA_COEFF 0.949 //Proportion of signal from y[-1]. + //0.939 gives ~10Hz 3db cutoff low pass filter for filter rate of 1kHz + //dsp.stackexchange.com/questions/40462/exponential-moving-average-cut-off-frequency/40465 #define FIFO_LEVEL_A_COEFF ((int32_t)(INT_MAX * FIFO_LEVEL_EMA_COEFF)) //Scale to signed 1.31 format #define FIFO_LEVEL_B_COEFF (INT_MAX - FIFO_LEVEL_A_COEFF) -#define RANDOMISATION_PERCENT 50 //How much noise to inject in percent of existing signal amplitude +#define RANDOMISATION_PERCENT 20 //How much radnom noise to inject in percent of existing signal amplitude #define RANDOMISATION_COEFF_A ((INT_MAX / 100) * RANDOMISATION_PERCENT) -#define PID_CONTROL_P_TERM 6.0 -#define PID_CONTROL_I_TERM 0.0 -#define PID_CONTROL_D_TERM 0.0 +#define PID_CALC_OVERHEAD_BITS 6 //Allow large P,I or D constants, up to 2^(this number) + + +#define PID_CONTROL_P_TERM 10.0 +#define PID_CONTROL_I_TERM 150.0 +#define PID_CONTROL_D_TERM 1.0 #define PID_RATE_MULTIPLIER SOF_FREQ_HZ -#define PID_CONTROL_P_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * (float)PID_CONTROL_P_TERM)) //scale to fixed point -#define PID_CONTROL_I_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * (float)PID_CONTROL_I_TERM / PID_RATE_MULTIPLIER)) //scale to fixed point -#define PID_CONTROL_D_TERM_COEFF ((xua_lite_fixed_point_t)(XUA_LIGHT_FIXED_POINT_ONE * (float)PID_CONTROL_D_TERM)) //scale to fixed point +#define PID_CONTROL_P_TERM_COEFF ((xua_lite_fixed_point_t)((XUA_LIGHT_FIXED_POINT_ONE >> PID_CALC_OVERHEAD_BITS) * (float)PID_CONTROL_P_TERM)) //scale to fixed point +#define PID_CONTROL_I_TERM_COEFF ((xua_lite_fixed_point_t)((XUA_LIGHT_FIXED_POINT_ONE >> PID_CALC_OVERHEAD_BITS) * (float)PID_CONTROL_I_TERM / PID_RATE_MULTIPLIER)) //scale to fixed point +#define PID_CONTROL_D_TERM_COEFF ((xua_lite_fixed_point_t)((XUA_LIGHT_FIXED_POINT_ONE >> PID_CALC_OVERHEAD_BITS) * (float)PID_CONTROL_D_TERM * PID_RATE_MULTIPLIER)) //scale to fixed point -#define PID_CALC_OVERHEAD_BITS 6 //Allow large P,I or D constants, up to 2^(this number) static inline xua_lite_fixed_point_t do_fifo_depth_lowpass_filter(xua_lite_fixed_point_t old, int fifo_depth){ //we grow from 32b to 64b for intermediate @@ -95,15 +99,13 @@ void do_rate_control(int fill_level, pid_state_t *pid_state, int *clock_nudge){ //Do PID calculation. Note there is an implicit cast back to xua_lite_fixed_point_t before assignment - const unsigned pid_mul_r_shift_bits = XUA_LIGHT_FIXED_POINT_FRAC_BITS + PID_CALC_OVERHEAD_BITS; - xua_lite_fixed_point_t p_term = (((int64_t) fifo_level_filtered * (int64_t)PID_CONTROL_P_TERM_COEFF)) >> pid_mul_r_shift_bits; - xua_lite_fixed_point_t i_term = (((int64_t) pid_state->fifo_level_accum * (int64_t)PID_CONTROL_I_TERM_COEFF)) >> pid_mul_r_shift_bits; - xua_lite_fixed_point_t d_term = (((int64_t) fifo_level_delta * (int64_t)PID_CONTROL_D_TERM_COEFF)) >> pid_mul_r_shift_bits; + xua_lite_fixed_point_t p_term = (((int64_t) fifo_level_filtered * (int64_t)PID_CONTROL_P_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; + xua_lite_fixed_point_t i_term = (((int64_t) pid_state->fifo_level_accum * (int64_t)PID_CONTROL_I_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; + xua_lite_fixed_point_t d_term = (((int64_t) fifo_level_delta * (int64_t)PID_CONTROL_D_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; //debug_printf("p: %d i: %d f: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, fill_level_wrt_half); //printf("p: %f i: %f d: %f filtered: %f integrated: %f\n", (float)p_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)i_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)d_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)fifo_level_filtered/(1<fifo_level_accum/(1<> (XUA_LIGHT_FIXED_POINT_Q_BITS - 1 - PID_CALC_OVERHEAD_BITS); @@ -130,7 +132,7 @@ void do_rate_control(int fill_level, pid_state_t *pid_state, int *clock_nudge){ pid_state->fifo_level_filtered_old = fifo_level_filtered; //debug_printf("filtered: %d raw: %d\n", fifo_level_filtered >> 22, fill_level_wrt_half); - static unsigned counter; counter++; if (counter>100){counter = 0; debug_printf("f: %d\n",fill_level_wrt_half);} + static unsigned counter; counter++; if (counter>100){counter = 0; debug_printf("f: %d\n",fifo_level_filtered >> (XUA_LIGHT_FIXED_POINT_FRAC_BITS - 10));} } From a8fa2742306b46ee73ca21894078db5795df1ba3 Mon Sep 17 00:00:00 2001 From: Ed Clarke Date: Fri, 30 Nov 2018 14:00:55 +0000 Subject: [PATCH 056/123] Separate out pdm from rate calc --- examples/xua_lite_example/plot_fill_level.sh | 2 +- .../xua_lite_example/src/rate_controller.h | 6 +- .../xua_lite_example/src/rate_controller.xc | 59 +++++++++++-------- .../xua_lite_example/src/xua_buffer_lite.xc | 4 +- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/examples/xua_lite_example/plot_fill_level.sh b/examples/xua_lite_example/plot_fill_level.sh index 8adfd632..bb2ad5a3 100644 --- a/examples/xua_lite_example/plot_fill_level.sh +++ b/examples/xua_lite_example/plot_fill_level.sh @@ -1 +1 @@ -grep f: dump.txt | grep -Eo "\-?\d+" > proc.txt&& gnuplot -p -e 'set term png; plot "proc.txt" with lines' > plot.png && open plot.png \ No newline at end of file +grep pid: dump.txt | grep -Eo "\-?\d+" > proc.txt && gnuplot -p -e 'set term png; plot "proc.txt" with lines' > plot.png && open plot.png \ No newline at end of file diff --git a/examples/xua_lite_example/src/rate_controller.h b/examples/xua_lite_example/src/rate_controller.h index 23afa87f..8dee3f75 100644 --- a/examples/xua_lite_example/src/rate_controller.h +++ b/examples/xua_lite_example/src/rate_controller.h @@ -10,7 +10,11 @@ typedef struct pid_state_t{ //USB Adaptive mode helper -void do_rate_control(int fill_level, pid_state_t *pid_state, int *clock_nudge); +xua_lite_fixed_point_t do_rate_control(int fill_level, pid_state_t *pid_state); + +//PDM modulator for clock control +void do_clock_nudge_pdm(xua_lite_fixed_point_t controller_out, int *clock_nudge); + //USB Asynch mode helper void do_feedback_calculation(unsigned &sof_count, const unsigned mclk_hz, unsigned mclk_port_counter,unsigned &mclk_port_counter_old diff --git a/examples/xua_lite_example/src/rate_controller.xc b/examples/xua_lite_example/src/rate_controller.xc index 6638f535..c6bc348b 100644 --- a/examples/xua_lite_example/src/rate_controller.xc +++ b/examples/xua_lite_example/src/rate_controller.xc @@ -11,7 +11,7 @@ #define XUA_LIGHT_FIXED_POINT_ONE (1 << XUA_LIGHT_FIXED_POINT_FRAC_BITS) #define XUA_LIGHT_FIXED_POINT_MINUS_ONE (-XUA_LIGHT_FIXED_POINT_ONE) -#define FIFO_LEVEL_EMA_COEFF 0.949 //Proportion of signal from y[-1]. +#define FIFO_LEVEL_EMA_COEFF 0.939 //Proportion of signal from y[-1]. //0.939 gives ~10Hz 3db cutoff low pass filter for filter rate of 1kHz //dsp.stackexchange.com/questions/40462/exponential-moving-average-cut-off-frequency/40465 #define FIFO_LEVEL_A_COEFF ((int32_t)(INT_MAX * FIFO_LEVEL_EMA_COEFF)) //Scale to signed 1.31 format @@ -20,7 +20,7 @@ #define RANDOMISATION_PERCENT 20 //How much radnom noise to inject in percent of existing signal amplitude #define RANDOMISATION_COEFF_A ((INT_MAX / 100) * RANDOMISATION_PERCENT) -#define PID_CALC_OVERHEAD_BITS 6 //Allow large P,I or D constants, up to 2^(this number) +#define PID_CALC_OVERHEAD_BITS 2 //Allow large P,I or D constants, up to 2^(this number) #define PID_CONTROL_P_TERM 10.0 @@ -58,8 +58,33 @@ static inline xua_lite_fixed_point_t add_noise(xua_lite_fixed_point_t input){ return (xua_lite_fixed_point_t)( output_64 >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); } +//Convert the control input into a pdm output (dither) with optional noise +void do_clock_nudge_pdm(xua_lite_fixed_point_t controller_out, int *clock_nudge){ + + //Randomise - add a proportion of rectangular probability distribution noise to spread the spectrum + controller_out = add_noise(controller_out); + + //Convert to pulse density modulation (sigma-delta) + static xua_lite_fixed_point_t nudge_accumulator = 0; + nudge_accumulator += controller_out; //Note no overflow check as if we reach XUA_LIGHT_FIXED_POINT_Q_BITS + //something is very wrong + //printf("co: %d ratio: %f \n", controller_out, (float)controller_out/XUA_LIGHT_FIXED_POINT_ONE); + if (nudge_accumulator >= XUA_LIGHT_FIXED_POINT_ONE){ + *clock_nudge = 1; + nudge_accumulator -= XUA_LIGHT_FIXED_POINT_ONE; + } + else if (nudge_accumulator <= XUA_LIGHT_FIXED_POINT_MINUS_ONE){ + nudge_accumulator -= XUA_LIGHT_FIXED_POINT_MINUS_ONE; + *clock_nudge = -1; + } + else{ + *clock_nudge = 0; + } +} + + //Do PI control and modulation for adaptive USB audio -void do_rate_control(int fill_level, pid_state_t *pid_state, int *clock_nudge){ +xua_lite_fixed_point_t do_rate_control(int fill_level, pid_state_t *pid_state){ //We always check the FIFO level after USB has produced a block, and total FIFO size is 2x max, so half full is at 3/4 const int half_full = ((MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2) * 3) / 4; @@ -97,42 +122,26 @@ void do_rate_control(int fill_level, pid_state_t *pid_state, int *clock_nudge){ //which is already scaled to fit within the fixed point representation xua_lite_fixed_point_t fifo_level_delta = fifo_level_filtered - pid_state->fifo_level_filtered_old; + //Save to struct for next iteration + pid_state->fifo_level_filtered_old = fifo_level_filtered; //Do PID calculation. Note there is an implicit cast back to xua_lite_fixed_point_t before assignment xua_lite_fixed_point_t p_term = (((int64_t) fifo_level_filtered * (int64_t)PID_CONTROL_P_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; xua_lite_fixed_point_t i_term = (((int64_t) pid_state->fifo_level_accum * (int64_t)PID_CONTROL_I_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; xua_lite_fixed_point_t d_term = (((int64_t) fifo_level_delta * (int64_t)PID_CONTROL_D_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; - //debug_printf("p: %d i: %d f: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, fill_level_wrt_half); + //debug_printf("p: %d i: %d f: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, fifo_level_filtered >> (XUA_LIGHT_FIXED_POINT_FRAC_BITS - 10)); //printf("p: %f i: %f d: %f filtered: %f integrated: %f\n", (float)p_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)i_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)d_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)fifo_level_filtered/(1<fifo_level_accum/(1<> (XUA_LIGHT_FIXED_POINT_Q_BITS - 1 - PID_CALC_OVERHEAD_BITS); - //Randomise - add a proportion of rectangular probability distribution noise to spread the spectrum - controller_out = add_noise(controller_out); - //Convert to pulse density modulation (sigma-delta) - static xua_lite_fixed_point_t nudge_accumulator = 0; - nudge_accumulator += controller_out; //Note no overflow check as if we reach XUA_LIGHT_FIXED_POINT_Q_BITS - //something is very wrong - //printf("co: %d ratio: %f \n", controller_out, (float)controller_out/XUA_LIGHT_FIXED_POINT_ONE); - if (nudge_accumulator >= XUA_LIGHT_FIXED_POINT_ONE){ - *clock_nudge = 1; - nudge_accumulator -= XUA_LIGHT_FIXED_POINT_ONE; - } - else if (nudge_accumulator <= XUA_LIGHT_FIXED_POINT_MINUS_ONE){ - nudge_accumulator -= XUA_LIGHT_FIXED_POINT_MINUS_ONE; - *clock_nudge = -1; - } - else{ - *clock_nudge = 0; - } - - pid_state->fifo_level_filtered_old = fifo_level_filtered; //debug_printf("filtered: %d raw: %d\n", fifo_level_filtered >> 22, fill_level_wrt_half); - static unsigned counter; counter++; if (counter>100){counter = 0; debug_printf("f: %d\n",fifo_level_filtered >> (XUA_LIGHT_FIXED_POINT_FRAC_BITS - 10));} + //static unsigned counter; counter++; if (counter>100){counter = 0; debug_printf("pid: %d\n",i_term >> (XUA_LIGHT_FIXED_POINT_FRAC_BITS - 10));} + debug_printf("co: %d\n", controller_out >> XUA_LIGHT_FIXED_POINT_FRAC_BITS); + return controller_out; } diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index bed8e0ab..d86cdf38 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -141,7 +141,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o num_samples_to_send_to_host = num_samples_received_from_host; int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); - if (isnull(c_feedback)) do_rate_control(fill_level, &pid_state, &clock_nudge); + if (isnull(c_feedback)) do_clock_nudge_pdm(do_rate_control(fill_level, &pid_state), &clock_nudge); //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); @@ -315,7 +315,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, num_samples_to_send_to_host = num_samples_received_from_host; int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); - if (isnull(c_feedback)) do_rate_control(fill_level, &pid_state, &clock_nudge); + if (isnull(c_feedback)) do_clock_nudge_pdm(do_rate_control(fill_level, &pid_state), &clock_nudge); //Mark EP as ready for next frame from host XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); From 86b4ab89ea031f7df279bc838ded367843454b86 Mon Sep 17 00:00:00 2001 From: Oscar Bailey Date: Tue, 26 Feb 2019 16:59:29 +0000 Subject: [PATCH 057/123] Change version of lib_mic_array; Fix synchronous endpoint behaviour The device now adjusts it's clock to the USB clock when host is not pushing data to device. --- examples/xua_lite_example/Makefile | 2 +- examples/xua_lite_example/src/app_xua_lite.xc | 7 +++--- examples/xua_lite_example/src/audio_hub.xc | 8 ++++++- examples/xua_lite_example/src/pdm_mic.h | 4 +++- examples/xua_lite_example/src/pdm_mic.xc | 21 ++++++++++------ .../xua_lite_example/src/xua_buffer_lite.xc | 12 +++++++--- examples/xua_lite_example/wscript | 24 +++++++++++++++++++ lib_xua/src/core/pdm_mics/pdm_mic.xc | 2 +- 8 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 examples/xua_lite_example/wscript diff --git a/examples/xua_lite_example/Makefile b/examples/xua_lite_example/Makefile index 85c75385..daa7dc5f 100644 --- a/examples/xua_lite_example/Makefile +++ b/examples/xua_lite_example/Makefile @@ -10,7 +10,7 @@ XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -Os -report \ # The USED_MODULES variable lists other module used by the application. These # modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables. # Modules are expected to be in the directory above the BASE_DIR directory. -USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_mic_array_ddr +USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_mic_array #============================================================================= # The following part of the Makefile includes the common build infrastructure diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index a53982ca..2616914a 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -11,7 +11,7 @@ #include "i2s.h" #include "i2c.h" #include "mic_array.h" -#include "XUA_Buffer_lite.h" +#include "xua_buffer_lite.h" #include "xua_ep0_wrapper.h" #include "pdm_mic.h" #include "audio_config.h" @@ -96,12 +96,11 @@ int main() c_audio :> int _; //Now wait until i2c has finished mclk setup const unsigned micDiv = MCLK_48/3072000; - if (XUA_ADAPTIVE) mic_array_setup_ddr_xcore(pdmclk, pdmclk6, p_pdm_clk, p_pdm_mics, micDiv); - else mic_array_setup_ddr(pdmclk, pdmclk6, p_mclk_in, p_pdm_clk, p_pdm_mics, micDiv); + mic_array_setup_ddr(pdmclk, pdmclk6, p_mclk_in, p_pdm_clk, p_pdm_mics, micDiv); par { i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); - [[distribute]]AudioHub(i_i2s, c_audio, c_ds_output); + [[distribute]] AudioHub(i_i2s, c_audio, c_ds_output); pdm_mic(c_ds_output[0], p_pdm_mics); par (int i = 0; i < 5; i++) burn_normal_priority(); diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 1fb3c4f0..06fd32dc 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -1,3 +1,4 @@ +#include #include "i2s.h" #include "i2c.h" #include "xua.h" @@ -34,6 +35,8 @@ void AudioHub(server i2s_frame_callback_if i2s, mic_array_decimator_configure(c_ds_output, decimatorCount, dc); mic_array_init_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); + // Used for debug + //int saw = 0; while (1) { select { @@ -57,7 +60,7 @@ void AudioHub(server i2s_frame_callback_if i2s, case i2s.restart_check() -> i2s_restart_t restart: restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; - + //Transfer samples. Takes about 25 ticks for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; if (XUA_ADAPTIVE) c_audio :> clock_nudge; @@ -70,6 +73,9 @@ void AudioHub(server i2s_frame_callback_if i2s, for (int i = 0; i < XUA_NUM_PDM_MICS; i++) raw_mics[i] = current->data[i][0]; } + //memset(raw_mics, saw, sizeof(int) * XUA_NUM_PDM_MICS); + //saw += 500; + //Taking about 160 ticks when adjusting, 100 when not tmr :> t0; pll_nudge(clock_nudge); diff --git a/examples/xua_lite_example/src/pdm_mic.h b/examples/xua_lite_example/src/pdm_mic.h index 2b00567d..04b13c3f 100644 --- a/examples/xua_lite_example/src/pdm_mic.h +++ b/examples/xua_lite_example/src/pdm_mic.h @@ -5,6 +5,8 @@ void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]); void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics); -void mic_array_setup_ddr_xcore(clock pdmclk, clock pdmclk6, out port p_pdm_clk, buffered in port:32 p_pdm_data, int divide); +void mic_array_setup_ddr(clock pdmclk, clock pdmclk6, in port p_mclk, + out port p_pdm_clk, buffered in port:32 p_pdm_data, + int divide); #endif diff --git a/examples/xua_lite_example/src/pdm_mic.xc b/examples/xua_lite_example/src/pdm_mic.xc index 417d6eb4..59d506be 100644 --- a/examples/xua_lite_example/src/pdm_mic.xc +++ b/examples/xua_lite_example/src/pdm_mic.xc @@ -35,7 +35,7 @@ void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimat fir_coefs[6] = (int * unsafe)g_third_stage_div_12_fir; //dcc = {MIC_ARRAY_MAX_FRAME_SIZE_LOG2, 1, 0, 0, decimationfactor, fir_coefs[decimationfactor/2], 0, 0, DECIMATOR_NO_FRAME_OVERLAP, 2}; - dcc->frame_size_log2 = MIC_ARRAY_MAX_FRAME_SIZE_LOG2; + dcc->len = MIC_ARRAY_MAX_FRAME_SIZE_LOG2; dcc->apply_dc_offset_removal = 1; dcc->index_bit_reversal = 0; dcc->windowing_function = null; @@ -73,17 +73,24 @@ void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics) } } -void mic_array_setup_ddr_xcore(clock pdmclk, +void mic_array_setup_ddr(clock pdmclk, clock pdmclk6, + in port p_mclk, /*used only in I2S slave case*/ out port p_pdm_clk, buffered in port:32 p_pdm_data, int divide) { - configure_clock_xcore(pdmclk, 80); - //configure_clock_src_divide(pdmclk, p_mclk, divide/2); - configure_clock_xcore(pdmclk6, 40); - //configure_clock_src_divide(pdmclk6, p_mclk, divide/4); - + +#if !XUA_ADAPTIVE //i2s slave + //p_mclk coming from the Pi is 24.576 MHz + configure_clock_src_divide(pdmclk, p_mclk, 4); //3.072 = 24.576 / 8 + configure_clock_src_divide(pdmclk6, p_mclk, 2); //6.144 = 24.576 / 4 + +#else + configure_clock_xcore(pdmclk, 80); // 3.072 + configure_clock_xcore(pdmclk6, 40); // 6.144 +#endif + configure_port_clock_output(p_pdm_clk, pdmclk); configure_in_port(p_pdm_data, pdmclk6); diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index d86cdf38..b0253955 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -27,6 +27,7 @@ void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Resu extern XUD_ep ep0_out; extern XUD_ep ep0_in; +#if 0 //Unsafe to allow us to use fifo API without local unsafe scope unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { @@ -197,6 +198,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o } } } +#endif extern port p_sda; [[combinable]] @@ -336,7 +338,11 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, timer tmr; int t0, t1; tmr :> t0; //If host is not streaming out, then send a fixed number of samples to host - if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; + if (output_interface_num == 0) { + num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; + int fill_level = fifo_get_fill_short(device_to_host_fifo_ptr); + if (isnull(c_feedback)) do_clock_nudge_pdm(-do_rate_control(fill_level, &pid_state), &clock_nudge); + } fifo_ret_t ret = fifo_block_pop_short_fast(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) { @@ -349,7 +355,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, //Use the number of samples we received last time so we are always balanced (assumes same in/out count) unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, input_buffer_size); //loopback + XUD_SetReady_InPtr(ep_aud_in, (unsigned) buffer_aud_in.long_words, input_buffer_size); //loopback num_samples_to_send_to_host = 0; //tmr :> t1; debug_printf("i%d\n", t1 - t0); break; @@ -375,4 +381,4 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, break; } } -} \ No newline at end of file +} diff --git a/examples/xua_lite_example/wscript b/examples/xua_lite_example/wscript new file mode 100644 index 00000000..7373dcd9 --- /dev/null +++ b/examples/xua_lite_example/wscript @@ -0,0 +1,24 @@ +def options(ctx): + ctx.add_option('--target', action='store', default='xua_lite_example.xe') + ctx.add_option('--debug', action='store_true') + + +def configure(conf): + conf.load('xwaf.compiler_xcc') + conf.env.PROJECT_ROOT = '../../..' + +def build(bld): + target_path = 'bin/' + bld.options.target + bld.env.TARGET_ARCH ='src/RPI_HAT_60QFN.xn' + bld.env.XSCOPE = bld.path.find_resource('config.xscope') + depends_on = ['lib_xua','lib_i2s','lib_xud','lib_mic_array', 'lib_i2c'] + #bld.env.XCC_FLAGS = ['-O2', '-g', '-Wall', '-fcmdline-buffer-bytes=512', '-report', '-DDISABLE_STAGE_C'] + bld.env.XCC_FLAGS = ['-fcomment-asm','-Xmapper','--map','-Xmapper','MAPFILE', + '-Os','-report','-g','-Wno-unused-function','-Wno-timing', + '-DXUD_SERIES_SUPPORT=XUD_X200_SERIES','-DUSB_TILE=tile[1]', + '-DMIC_ARRAY_CH0=PIN0','-DMIC_ARRAY_CH1=PIN4', '-DDEBUG_PRINT_ENABLE=1'] + if bld.options.debug: + bld.env.XCC_FLAGS.append('-DDEBUG') + + source = bld.path.ant_glob(['src/**/*.xc', 'src/**/*.c']) + bld.program(source=source, depends_on=depends_on,target=target_path) diff --git a/lib_xua/src/core/pdm_mics/pdm_mic.xc b/lib_xua/src/core/pdm_mics/pdm_mic.xc index 2221d1f7..dabfb794 100644 --- a/lib_xua/src/core/pdm_mics/pdm_mic.xc +++ b/lib_xua/src/core/pdm_mics/pdm_mic.xc @@ -88,7 +88,7 @@ void XUA_PdmBuffer(streaming chanend c_ds_output[2], chanend c_audio) fir_coefs[6] = g_third_stage_div_12_fir; //dcc = {MIC_ARRAY_MAX_FRAME_SIZE_LOG2, 1, 0, 0, decimationfactor, fir_coefs[decimationfactor/2], 0, 0, DECIMATOR_NO_FRAME_OVERLAP, 2}; - dcc.frame_size_log2 = MIC_ARRAY_MAX_FRAME_SIZE_LOG2; + dcc.len = MIC_ARRAY_MAX_FRAME_SIZE_LOG2; dcc.apply_dc_offset_removal = 1; dcc.index_bit_reversal = 0; dcc.windowing_function = null; From b12aeac26413b91789518096bca95c32e426133d Mon Sep 17 00:00:00 2001 From: Oscar Bailey Date: Tue, 26 Feb 2019 17:18:02 +0000 Subject: [PATCH 058/123] Whitespace changes --- examples/xua_lite_example/src/app_xua_lite.xc | 44 +++++++++---------- examples/xua_lite_example/src/audio_config.xc | 28 ++++++------ examples/xua_lite_example/src/audio_hub.xc | 4 ++ examples/xua_lite_example/src/fifo_impl.h | 6 +-- examples/xua_lite_example/src/fifo_types.h | 4 +- .../xua_lite_example/src/rate_controller.xc | 12 ++--- .../xua_lite_example/src/xua_buffer_lite.xc | 34 +++++++------- examples/xua_lite_example/src/xua_conf.h | 6 +-- 8 files changed, 71 insertions(+), 67 deletions(-) diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc index 2616914a..64830667 100644 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ b/examples/xua_lite_example/src/app_xua_lite.xc @@ -21,13 +21,13 @@ #define DEBUG_PRINT_ENABLE_XUA_APP 1 #include "debug_print.h" -// Port declarations. Note, the defines come from the xn file +// Port declarations. Note, the defines come from the xn file on tile[0]: buffered out port:32 p_i2s_dac[] = {XS1_PORT_1N}; //DAC on tile[0]: buffered in port:32 p_i2s_adc[] = {XS1_PORT_1F}; //Unused currently -on tile[0]: buffered out port:32 p_lrclk = XS1_PORT_1O; //I2S Bit-clock -on tile[0]: out port p_bclk = XS1_PORT_1P; //I2S L/R-clock +on tile[0]: buffered out port:32 p_lrclk = XS1_PORT_1O; //I2S Bit-clock +on tile[0]: out port p_bclk = XS1_PORT_1P; //I2S L/R-clock -// Master clock for the audio IO tile +// Master clock for the audio IO tile on tile[0]: in port p_mclk_in = XS1_PORT_1K; // [0] : DAC_RESET_N @@ -39,12 +39,12 @@ on tile[0]: out port p_gpio = XS1_PORT_4D; on tile[1]: port p_scl = XS1_PORT_1C; on tile[1]: port p_sda = XS1_PORT_1D; on tile[1]: in port p_mclk_in_usb = XS1_PORT_1A; -on tile[1]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks -on tile[1]: clock clk_usb_mclk = XS1_CLKBLK_3; // Master clock +on tile[1]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks +on tile[1]: clock clk_usb_mclk = XS1_CLKBLK_3; // Master clock -// Clock-block declarations -on tile[0]: clock clk_audio_bclk = XS1_CLKBLK_2; // Bit clock -on tile[0]: clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock +// Clock-block declarations +on tile[0]: clock clk_audio_bclk = XS1_CLKBLK_2; // Bit clock +on tile[0]: clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock //XUD uses XS1_CLKBLK_4, XS1_CLKBLK_5 on tile[1] //Mic array resources @@ -56,7 +56,7 @@ on tile[0]: clock pdmclk6 = XS1_CLKBLK_5; // Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also -// if the endpoint wishes to be informed of USB bus resets +// if the endpoint wishes to be informed of USB bus resets XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO}; XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO}; @@ -72,11 +72,11 @@ void burn_high_priority(void){ int main() { - // Channels for lib_xud + // Channels for lib_xud chan c_ep_out[XUA_ENDPOINT_COUNT_OUT]; chan c_ep_in[XUA_ENDPOINT_COUNT_IN]; - // Channel for communicating SOF notifications from XUD to the Buffering cores + // Channel for communicating SOF notifications from XUD to the Buffering cores chan c_sof; interface i2s_frame_callback_if i_i2s; @@ -94,7 +94,7 @@ int main() setup_audio_gpio(p_gpio); c_audio <: 0; //Signal that we can now do i2c setup c_audio :> int _; //Now wait until i2c has finished mclk setup - + const unsigned micDiv = MCLK_48/3072000; mic_array_setup_ddr(pdmclk, pdmclk6, p_mclk_in, p_pdm_clk, p_pdm_mics, micDiv); @@ -109,9 +109,9 @@ int main() } on tile[1]:unsafe{ // Connect master-clock input clock-block to clock-block pin for asnch feedback calculation - set_clock_src(clk_usb_mclk, p_mclk_in_usb); // Clock clock-block from mclk pin - set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block - start_clock(clk_usb_mclk); // Set the clock off running + set_clock_src(clk_usb_mclk, p_mclk_in_usb); // Clock clock-block from mclk pin + set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block + start_clock(clk_usb_mclk); // Set the clock off running //Setup DAC over i2c and then return so we do not use a thread c_audio :> int _; //Wait for reset to be asserted/deasserted by other tile @@ -121,14 +121,14 @@ int main() } c_audio <: 0; //Signal to tile[0] that mclk is now good - par{ - // Low level USB device layer core + par { + // Low level USB device layer core XUD_Main(c_ep_out, XUA_ENDPOINT_COUNT_OUT, c_ep_in, XUA_ENDPOINT_COUNT_IN, - c_sof, epTypeTableOut, epTypeTableIn, - null, null, -1 , + c_sof, epTypeTableOut, epTypeTableIn, + null, null, -1 , (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); - // // Buffering core - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core + // // Buffering core - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core // XUA_Buffer_lite(c_ep_out[0], // c_ep_in[0], // c_ep_out[1], @@ -150,7 +150,7 @@ int main() } }//Tile[1] par }//Top level par - + return 0; } diff --git a/examples/xua_lite_example/src/audio_config.xc b/examples/xua_lite_example/src/audio_config.xc index 9e1dcb82..3235387d 100755 --- a/examples/xua_lite_example/src/audio_config.xc +++ b/examples/xua_lite_example/src/audio_config.xc @@ -98,21 +98,21 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) // Wait for 2ms because we apply reset for 1ms from other tile delay_milliseconds(2); - + // Set register page to 0 DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); // Initiate SW reset (PLL is powered off as part of reset) DAC3101_REGWRITE(DAC3101_SW_RST, 0x01); - + // so I've got 24MHz in to PLL, I want 24.576MHz or 22.5792MHz out. - + // I will always be using fractional-N (D != 0) so we must set R = 1 // PLL_CLKIN/P must be between 10 and 20MHz so we must set P = 2 - + // PLL_CLK = CLKIN * ((RxJ.D)/P) // We know R = 1, P = 2. // PLL_CLK = CLKIN * (J.D / 2) - + // For 24.576MHz: // J = 8 // D = 1920 @@ -125,7 +125,7 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) // DAC_CLK = PLL_CLK / 4 = 24.576MHz. // DAC_MOD_CLK = DAC_CLK / 4 = 6.144MHz. // DAC_FS = DAC_MOD_CLK / 128 = 48kHz. - + // For 22.5792MHz: // J = 7 // D = 5264 @@ -153,10 +153,10 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x00); delay_milliseconds(1); - + // Set PLL_CLKIN = BCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x07); - + // Set PLL P=1 and R=4 values and power up. DAC3101_REGWRITE(DAC3101_PLL_P_R, 0x94); // Set NDAC clock divider to 4 and power up. @@ -197,10 +197,10 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) } delay_milliseconds(1); - + // Set PLL_CLKIN = MCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x03); - + // Set PLL P and R values and power up. DAC3101_REGWRITE(DAC3101_PLL_P_R, 0xA1); // Set NDAC clock divider to 4 and power up. @@ -218,7 +218,7 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) DAC3101_REGWRITE(DAC3101_CLKOUT_M_VAL, 0x81); // Set GPIO1 output to come from CLKOUT output. DAC3101_REGWRITE(DAC3101_GPIO1_IO, 0x10); - + // Set CODEC interface mode: I2S, 24 bit, slave mode (BCLK, WCLK both inputs). DAC3101_REGWRITE(DAC3101_CODEC_IF, 0x20); // Set register page to 1 @@ -253,7 +253,7 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) DAC3101_REGWRITE(DAC3101_SPKL_VOL_A, 0x92); // Enable Right Class-D output analog volume, set = -9 dB DAC3101_REGWRITE(DAC3101_SPKR_VOL_A, 0x92); - + delay_milliseconds(100); // Power up DAC @@ -269,11 +269,11 @@ void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) // Unmute digital volume control // Unmute DAC left and right channels DAC3101_REGWRITE(DAC3101_DAC_VOL, 0x00); - + i_i2c.shutdown(); } //These are here just to silence compiler warnings about unimplemented xua callbacks (not needed in xua lite) void AudioHwInit(){} -void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC){} \ No newline at end of file +void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC){} diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 06fd32dc..668ed033 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -35,6 +35,8 @@ void AudioHub(server i2s_frame_callback_if i2s, mic_array_decimator_configure(c_ds_output, decimatorCount, dc); mic_array_init_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); + UserBufferManagementInit(); + // Used for debug //int saw = 0; @@ -61,6 +63,8 @@ void AudioHub(server i2s_frame_callback_if i2s, restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; + UserBufferManagement((unsigned *) raw_mics, (unsigned *) samples_out); + //Transfer samples. Takes about 25 ticks for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; if (XUA_ADAPTIVE) c_audio :> clock_nudge; diff --git a/examples/xua_lite_example/src/fifo_impl.h b/examples/xua_lite_example/src/fifo_impl.h index 32c297dd..080f3c95 100644 --- a/examples/xua_lite_example/src/fifo_impl.h +++ b/examples/xua_lite_example/src/fifo_impl.h @@ -112,7 +112,7 @@ static inline fifo_ret_t fifo_block_push_short_fast(volatile mem_fifo_short_t * memcpy(&fifo->data_base_ptr[fifo->write_idx], &data[0], first_block_size * sizeof(short)); fifo->write_idx += first_block_size; } - + return FIFO_SUCCESS; } } @@ -181,7 +181,7 @@ static inline fifo_ret_t fifo_block_pop_short_fast(volatile mem_fifo_short_t * u // printf("no wrap\n"); } - + return FIFO_SUCCESS; } } @@ -203,4 +203,4 @@ static inline int fifo_get_fill_relative_half_short(volatile mem_fifo_short_t * return fifo_fill; } } -#endif \ No newline at end of file +#endif diff --git a/examples/xua_lite_example/src/fifo_types.h b/examples/xua_lite_example/src/fifo_types.h index 5bc5248a..af7994e7 100644 --- a/examples/xua_lite_example/src/fifo_types.h +++ b/examples/xua_lite_example/src/fifo_types.h @@ -15,7 +15,7 @@ typedef enum fifo_ret_t { // //Note that the actual storage for the FIFO is declared externally //and a reference to the base address of the storage is passed in along -//with the size of the storage. This way, multiple instances may be +//with the size of the storage. This way, multiple instances may be //different sizes. // ///////////////////////////////////////////////////////////////////////// @@ -34,4 +34,4 @@ typedef struct mem_fifo_short_t { unsigned read_idx; } mem_fifo_short_t; -#endif \ No newline at end of file +#endif diff --git a/examples/xua_lite_example/src/rate_controller.xc b/examples/xua_lite_example/src/rate_controller.xc index c6bc348b..58fddf48 100644 --- a/examples/xua_lite_example/src/rate_controller.xc +++ b/examples/xua_lite_example/src/rate_controller.xc @@ -58,7 +58,7 @@ static inline xua_lite_fixed_point_t add_noise(xua_lite_fixed_point_t input){ return (xua_lite_fixed_point_t)( output_64 >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); } -//Convert the control input into a pdm output (dither) with optional noise +//Convert the control input into a pdm output (dither) with optional noise void do_clock_nudge_pdm(xua_lite_fixed_point_t controller_out, int *clock_nudge){ //Randomise - add a proportion of rectangular probability distribution noise to spread the spectrum @@ -96,7 +96,7 @@ xua_lite_fixed_point_t do_rate_control(int fill_level, pid_state_t *pid_state){ //Calculate the value for the integral term which is the accumulated fill level error xua_lite_fixed_point_t i_term_pre_clip = pid_state->fifo_level_accum + fifo_level_filtered; - + //clip the I term (which can wind up) to maximum fixed point representation. Check to see if overflow (which will change sign) if (fifo_level_filtered >= 0){ //If it was positive before, ensure it still is else clip to positive if (i_term_pre_clip >= pid_state->fifo_level_accum){ @@ -159,18 +159,18 @@ void do_feedback_calculation(unsigned &sof_count // Average over 128 SOFs - 128 x 3072 = 0x60000. unsigned long long feedbackMul = 64ULL; - if(AUDIO_CLASS == 1) feedbackMul = 8ULL; // TODO Use 4 instead of 8 to avoid windows LSB issues? + if(AUDIO_CLASS == 1) feedbackMul = 8ULL; // TODO Use 4 instead of 8 to avoid windows LSB issues? - // Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) + // Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) int mclk_ticks_this_sof_period = (int) ((short)(mclk_port_counter - mclk_port_counter_old)); unsigned long long full_result = mclk_ticks_this_sof_period * feedbackMul * DEFAULT_FREQ; feedback_value += full_result; - // Store MCLK for next time around... + // Store MCLK for next time around... mclk_port_counter_old = mclk_port_counter; // Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll - // We always count 128 SOFs, so 16ms @ HS, 128ms @ FS + // We always count 128 SOFs, so 16ms @ HS, 128ms @ FS if(sof_count == 128){ //debug_printf("fb\n"); sof_count = 0; diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/src/xua_buffer_lite.xc index b0253955..597cb938 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.xc +++ b/examples/xua_lite_example/src/xua_buffer_lite.xc @@ -37,14 +37,14 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o union buffer_aud_out{ unsigned char bytes[OUT_AUDIO_BUFFER_SIZE_BYTES]; short short_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 2]; - long long_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 4]; + long long_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 4]; }buffer_aud_out; union buffer_aud_in{ unsigned char bytes[IN_AUDIO_BUFFER_SIZE_BYTES]; short short_words[IN_AUDIO_BUFFER_SIZE_BYTES / 2]; - unsigned long long_words[IN_AUDIO_BUFFER_SIZE_BYTES / 4]; + unsigned long long_words[IN_AUDIO_BUFFER_SIZE_BYTES / 4]; }buffer_aud_in; - + unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; @@ -54,7 +54,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o long long feedback_value = 0; unsigned mod_from_last_time = 0; const unsigned mclk_hz = MCLK_48; - unsigned int fb_clocks[1] = {0}; + unsigned int fb_clocks[1] = {0}; //Adapative device clock control int clock_nudge = 0; @@ -86,7 +86,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, num_samples_to_send_to_host); XUD_SetReady_Out(ep0_out, sbuffer); if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); - + //Send initial samples so audiohub is not blocked for (int i = 0; i < 2 * (NUM_USB_CHAN_OUT + (XUA_ADAPTIVE != 0 ? 1 : 0)); i++) c_audio_hub <: 0; @@ -113,7 +113,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error USB_ParseSetupPacket(sbuffer, sp); //Parse data buffer end populate SetupPacket struct - + XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); XUD_SetReady_Out(ep0_out, sbuffer); tmr :> t1; debug_printf("c%d\n", t1 - t0); @@ -136,11 +136,11 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o timer tmr; int t0, t1; tmr :> t0; num_samples_received_from_host = length / out_subslot_size; - + fifo_ret_t ret = fifo_block_push_short(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; - + int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); if (isnull(c_feedback)) do_clock_nudge_pdm(do_rate_control(fill_level, &pid_state), &clock_nudge); @@ -171,7 +171,7 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o //Populate the input buffer ready for the next read //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, input_buffer_size); //loopback num_samples_to_send_to_host = 0; @@ -211,14 +211,14 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, union buffer_aud_out{ unsigned char bytes[OUT_AUDIO_BUFFER_SIZE_BYTES]; short short_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 2]; - long long_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 4]; + long long_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 4]; }buffer_aud_out; union buffer_aud_in{ unsigned char bytes[IN_AUDIO_BUFFER_SIZE_BYTES]; short short_words[IN_AUDIO_BUFFER_SIZE_BYTES / 2]; - unsigned long long_words[IN_AUDIO_BUFFER_SIZE_BYTES / 4]; + unsigned long long_words[IN_AUDIO_BUFFER_SIZE_BYTES / 4]; }buffer_aud_in; - + unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; @@ -228,7 +228,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, long long feedback_value = 0; unsigned mod_from_last_time = 0; const unsigned mclk_hz = MCLK_48; - unsigned int fb_clocks[1] = {0}; + unsigned int fb_clocks[1] = {0}; //Adapative device clock control int clock_nudge = 0; @@ -251,7 +251,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, num_samples_to_send_to_host); if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); - + short samples_in_short[NUM_USB_CHAN_IN] = {0}; short samples_out_short[NUM_USB_CHAN_OUT] = {0}; @@ -311,11 +311,11 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, num_samples_received_from_host = length / out_subslot_size; if (num_samples_received_from_host != 96) debug_printf("hs: %d\n", num_samples_received_from_host); - + fifo_ret_t ret = fifo_block_push_short_fast(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); num_samples_to_send_to_host = num_samples_received_from_host; - + int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); if (isnull(c_feedback)) do_clock_nudge_pdm(do_rate_control(fill_level, &pid_state), &clock_nudge); @@ -353,7 +353,7 @@ unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, //Populate the input buffer ready for the next read //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; XUD_SetReady_InPtr(ep_aud_in, (unsigned) buffer_aud_in.long_words, input_buffer_size); //loopback num_samples_to_send_to_host = 0; diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/src/xua_conf.h index 62274619..ae9de112 100644 --- a/examples/xua_lite_example/src/xua_conf.h +++ b/examples/xua_lite_example/src/xua_conf.h @@ -1,6 +1,6 @@ // Copyright (c) 2017-2018, XMOS Ltd, All rights reserved -#ifndef _XUA_CONF_H_ +#ifndef _XUA_CONF_H_ #define _XUA_CONF_H_ #define NUM_USB_CHAN_OUT 2 /* Number of channels from host to device */ @@ -18,7 +18,7 @@ #define VENDOR_ID 0x20B1 #define PRODUCT_STR_A2 "XUA Lite Class 2" #define PRODUCT_STR_A1 "XUA Lite Class 1" -#define PID_AUDIO_1 1 +#define PID_AUDIO_1 1 #define PID_AUDIO_2 2 #define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example) */ @@ -28,7 +28,7 @@ #define STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS 16 #define OUTPUT_VOLUME_CONTROL 0 -#define INPUT_VOLUME_CONTROL 0 +#define INPUT_VOLUME_CONTROL 0 #define UAC_FORCE_FEEDBACK_EP 0 #define XUA_ADAPTIVE 1 From 0b926fd9074a0bbf0169775947505faf527f2c3c Mon Sep 17 00:00:00 2001 From: Oscar Bailey Date: Wed, 27 Feb 2019 11:05:25 +0000 Subject: [PATCH 059/123] Refactor: Separate XUA lite and app code --- .../{src => config}/RPI_HAT_60QFN.xn | 0 examples/xua_lite_example/{src => config}/xua_conf.h | 0 examples/xua_lite_example/{src => config}/xud_conf.h | 0 examples/xua_lite_example/src/audio_hub.xc | 10 ++-------- examples/xua_lite_example/wscript | 8 +++++--- .../{src => xua_lite/rate_control}/fifo_impl.h | 0 .../{src => xua_lite/rate_control}/fifo_types.h | 0 .../{src => xua_lite/rate_control}/rate_controller.h | 0 .../rate_control}/rate_controller.xc | 0 .../{src => xua_lite}/xua_buffer_lite.h | 12 +++++++++++- .../{src => xua_lite}/xua_buffer_lite.xc | 0 .../{src => xua_lite}/xua_buffer_pack.h | 0 12 files changed, 18 insertions(+), 12 deletions(-) rename examples/xua_lite_example/{src => config}/RPI_HAT_60QFN.xn (100%) rename examples/xua_lite_example/{src => config}/xua_conf.h (100%) rename examples/xua_lite_example/{src => config}/xud_conf.h (100%) rename examples/xua_lite_example/{src => xua_lite/rate_control}/fifo_impl.h (100%) rename examples/xua_lite_example/{src => xua_lite/rate_control}/fifo_types.h (100%) rename examples/xua_lite_example/{src => xua_lite/rate_control}/rate_controller.h (100%) rename examples/xua_lite_example/{src => xua_lite/rate_control}/rate_controller.xc (100%) rename examples/xua_lite_example/{src => xua_lite}/xua_buffer_lite.h (73%) rename examples/xua_lite_example/{src => xua_lite}/xua_buffer_lite.xc (100%) rename examples/xua_lite_example/{src => xua_lite}/xua_buffer_pack.h (100%) diff --git a/examples/xua_lite_example/src/RPI_HAT_60QFN.xn b/examples/xua_lite_example/config/RPI_HAT_60QFN.xn similarity index 100% rename from examples/xua_lite_example/src/RPI_HAT_60QFN.xn rename to examples/xua_lite_example/config/RPI_HAT_60QFN.xn diff --git a/examples/xua_lite_example/src/xua_conf.h b/examples/xua_lite_example/config/xua_conf.h similarity index 100% rename from examples/xua_lite_example/src/xua_conf.h rename to examples/xua_lite_example/config/xua_conf.h diff --git a/examples/xua_lite_example/src/xud_conf.h b/examples/xua_lite_example/config/xud_conf.h similarity index 100% rename from examples/xua_lite_example/src/xud_conf.h rename to examples/xua_lite_example/config/xud_conf.h diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc index 668ed033..bec765a1 100644 --- a/examples/xua_lite_example/src/audio_hub.xc +++ b/examples/xua_lite_example/src/audio_hub.xc @@ -8,6 +8,7 @@ #include "mic_array.h" #include "audio_config.h" #include "pdm_mic.h" +#include "xua_buffer_lite.h" //Globally declared for 64b alignment int mic_decimator_fir_data_array[8][THIRD_STAGE_COEFS_PER_STAGE * PDM_MAX_DECIMATION] = {{0}}; @@ -35,8 +36,6 @@ void AudioHub(server i2s_frame_callback_if i2s, mic_array_decimator_configure(c_ds_output, decimatorCount, dc); mic_array_init_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); - UserBufferManagementInit(); - // Used for debug //int saw = 0; @@ -63,12 +62,7 @@ void AudioHub(server i2s_frame_callback_if i2s, restart = I2S_NO_RESTART; // Keep on looping timer tmr; int t0, t1; tmr :> t0; - UserBufferManagement((unsigned *) raw_mics, (unsigned *) samples_out); - - //Transfer samples. Takes about 25 ticks - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i]; - if (XUA_ADAPTIVE) c_audio :> clock_nudge; - for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: raw_mics[i]; + XUA_transfer_samples(c_audio, (unsigned *) samples_out, (unsigned *) raw_mics, (clock_nudge, int)); //Grab mics. Takes about 200 ticks currently current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); diff --git a/examples/xua_lite_example/wscript b/examples/xua_lite_example/wscript index 7373dcd9..5d6de68c 100644 --- a/examples/xua_lite_example/wscript +++ b/examples/xua_lite_example/wscript @@ -9,7 +9,7 @@ def configure(conf): def build(bld): target_path = 'bin/' + bld.options.target - bld.env.TARGET_ARCH ='src/RPI_HAT_60QFN.xn' + bld.env.TARGET_ARCH ='config/RPI_HAT_60QFN.xn' bld.env.XSCOPE = bld.path.find_resource('config.xscope') depends_on = ['lib_xua','lib_i2s','lib_xud','lib_mic_array', 'lib_i2c'] #bld.env.XCC_FLAGS = ['-O2', '-g', '-Wall', '-fcmdline-buffer-bytes=512', '-report', '-DDISABLE_STAGE_C'] @@ -20,5 +20,7 @@ def build(bld): if bld.options.debug: bld.env.XCC_FLAGS.append('-DDEBUG') - source = bld.path.ant_glob(['src/**/*.xc', 'src/**/*.c']) - bld.program(source=source, depends_on=depends_on,target=target_path) + source = bld.path.ant_glob(['src/**/*.xc', 'src/**/*.c', + 'xua_lite/**/*.xc', 'xua_lite/**/*.c']) + includes = ['config'] + bld.program(source=source, includes=includes, depends_on=depends_on,target=target_path) diff --git a/examples/xua_lite_example/src/fifo_impl.h b/examples/xua_lite_example/xua_lite/rate_control/fifo_impl.h similarity index 100% rename from examples/xua_lite_example/src/fifo_impl.h rename to examples/xua_lite_example/xua_lite/rate_control/fifo_impl.h diff --git a/examples/xua_lite_example/src/fifo_types.h b/examples/xua_lite_example/xua_lite/rate_control/fifo_types.h similarity index 100% rename from examples/xua_lite_example/src/fifo_types.h rename to examples/xua_lite_example/xua_lite/rate_control/fifo_types.h diff --git a/examples/xua_lite_example/src/rate_controller.h b/examples/xua_lite_example/xua_lite/rate_control/rate_controller.h similarity index 100% rename from examples/xua_lite_example/src/rate_controller.h rename to examples/xua_lite_example/xua_lite/rate_control/rate_controller.h diff --git a/examples/xua_lite_example/src/rate_controller.xc b/examples/xua_lite_example/xua_lite/rate_control/rate_controller.xc similarity index 100% rename from examples/xua_lite_example/src/rate_controller.xc rename to examples/xua_lite_example/xua_lite/rate_control/rate_controller.xc diff --git a/examples/xua_lite_example/src/xua_buffer_lite.h b/examples/xua_lite_example/xua_lite/xua_buffer_lite.h similarity index 73% rename from examples/xua_lite_example/src/xua_buffer_lite.h rename to examples/xua_lite_example/xua_lite/xua_buffer_lite.h index 0436b29c..72e17396 100644 --- a/examples/xua_lite_example/src/xua_buffer_lite.h +++ b/examples/xua_lite_example/xua_lite/xua_buffer_lite.h @@ -22,4 +22,14 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); [[combinable]] -unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); \ No newline at end of file +unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); + +static inline void XUA_transfer_samples(streaming chanend c_audio, + unsigned sampsFromUsbToAudio[], + unsigned sampsFromAudioToUsb[], + int &clock_nudge) { + //Transfer samples. Takes about 25 ticks + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> sampsFromUsbToAudio[i]; + if (XUA_ADAPTIVE) c_audio :> clock_nudge; + for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: sampsFromAudioToUsb[i]; +} diff --git a/examples/xua_lite_example/src/xua_buffer_lite.xc b/examples/xua_lite_example/xua_lite/xua_buffer_lite.xc similarity index 100% rename from examples/xua_lite_example/src/xua_buffer_lite.xc rename to examples/xua_lite_example/xua_lite/xua_buffer_lite.xc diff --git a/examples/xua_lite_example/src/xua_buffer_pack.h b/examples/xua_lite_example/xua_lite/xua_buffer_pack.h similarity index 100% rename from examples/xua_lite_example/src/xua_buffer_pack.h rename to examples/xua_lite_example/xua_lite/xua_buffer_pack.h From 0588ea2d185222677d84b8fc7443d2ae60d34d70 Mon Sep 17 00:00:00 2001 From: Oscar Bailey Date: Wed, 27 Feb 2019 17:07:36 +0000 Subject: [PATCH 060/123] Fix XUA lite when using VENDOR_REQUESTS_PARAMS --- .../xua_lite_example/xua_lite/xua_buffer_lite.h | 13 +++++++++++++ lib_xua/src/core/endpoint0/xua_endpoint0.c | 4 ++-- lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc | 7 ++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/examples/xua_lite_example/xua_lite/xua_buffer_lite.h b/examples/xua_lite_example/xua_lite/xua_buffer_lite.h index 72e17396..8ac52765 100644 --- a/examples/xua_lite_example/xua_lite/xua_buffer_lite.h +++ b/examples/xua_lite_example/xua_lite/xua_buffer_lite.h @@ -24,6 +24,19 @@ unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_o [[combinable]] unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); +/** Transfer samples to/from XUA. Should be called at the current USB rate. + * This function is non-blocking. + * + * \param[in,out] c_audio Channel to XUA. + * + * \param[out] sampsFromUsbToAudio Samples sent from host to device. + * + * \param[in] sampsFromAudioToUsb Samples to send from device to host. + * + * \param[out] clock_nudge Notification that the device is running + * too slowly/quickly. Only used when in + * adaptive endpoint mode. + */ static inline void XUA_transfer_samples(streaming chanend c_audio, unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[], diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index 0304369e..11833693 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -1213,13 +1213,13 @@ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { USB_SetupPacket_t sp; - XUA_Endpoint0_init(c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); + XUA_Endpoint0_init(c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_); while(1) { /* Returns XUD_RES_OKAY for success, XUD_RES_RST for bus reset */ XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, &sp); - XUA_Endpoint0_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface); + XUA_Endpoint0_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_); } } #endif /* XUA_USB_EN*/ diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc index 14a5148b..306fc26a 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc @@ -16,7 +16,7 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, client ep0_contro { USB_SetupPacket_t sp; - XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, null, null, null, null, dfuInterface); + XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, null, null, null, null, dfuInterface VENDOR_REQUESTS_PARAMS_); unsigned char sbuffer[120]; XUD_SetReady_Out(ep0_out, sbuffer); @@ -36,7 +36,8 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, client ep0_contro } debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error - XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, null, null, null, null, dfuInterface, &input_interface_num, &output_interface_num); + XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, null, null, null, null, dfuInterface + VENDOR_REQUESTS_PARAMS_, &input_interface_num, &output_interface_num); i_ep0_ctl.set_output_interface(output_interface_num); i_ep0_ctl.set_input_interface(input_interface_num); @@ -44,4 +45,4 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, client ep0_contro break; } } -} \ No newline at end of file +} From 7339ceca19071a50262ec5373db94c1cca1644b8 Mon Sep 17 00:00:00 2001 From: Oscar Bailey Date: Thu, 28 Mar 2019 17:11:05 +0000 Subject: [PATCH 061/123] Fix asynch mode not working on Windows --- lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 68de9533..93dd78c1 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -2656,7 +2656,11 @@ unsigned char cfgDesc_Audio1[] = 0x01, /* subtype - GENERAL */ 0x01, /* attributes. D[0]: sample freq ctrl. */ 0x02, /* bLockDelayUnits */ +#ifdef XUA_ADAPTIVE 0x08, 0x00, /* bLockDelay */ +#else + 0x00, 0x00, /* bLockDelay */ +#endif #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) /* Feedback EP */ @@ -2787,8 +2791,13 @@ unsigned char cfgDesc_Audio1[] = 0x25, /* CS_ENDPOINT */ 0x01, /* Subtype - GENERAL */ 0x01, /* Attributes. D[0]: sample freq ctrl. */ +#ifdef XUA_ADAPTIVE 0x02, /* Lock Delay units PCM samples*/ 0x08, 0x00, /* No lock delay */ +#else + 0x00, /* Lock Delay units PCM samples*/ + 0x00, 0x00, /* No lock delay */ +#endif // XUA_ADAPTIVE #endif #if (XUA_DFU_EN == 1) && (FORCE_UAC1_DFU == 1) From 786ce134c6cd5b14ac3cfd58314bb5167e11b847 Mon Sep 17 00:00:00 2001 From: Oscar Bailey Date: Thu, 28 Mar 2019 17:26:04 +0000 Subject: [PATCH 062/123] Update comments in xua_ep0_descriptors.h --- lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 93dd78c1..b3129ac0 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -2659,7 +2659,7 @@ unsigned char cfgDesc_Audio1[] = #ifdef XUA_ADAPTIVE 0x08, 0x00, /* bLockDelay */ #else - 0x00, 0x00, /* bLockDelay */ + 0x00, 0x00, /* Not used */ #endif #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) @@ -2795,8 +2795,8 @@ unsigned char cfgDesc_Audio1[] = 0x02, /* Lock Delay units PCM samples*/ 0x08, 0x00, /* No lock delay */ #else - 0x00, /* Lock Delay units PCM samples*/ - 0x00, 0x00, /* No lock delay */ + 0x00, /* Undefined */ + 0x00, 0x00, /* Not used */ #endif // XUA_ADAPTIVE #endif From 37ef88a6020f71171bd4e6daa0cf2121bd015102 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 29 Apr 2019 11:04:20 +0100 Subject: [PATCH 063/123] Fix build error when USB not enabled #ifdeffing the whole source as is the way in lib_xua --- lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc index 306fc26a..092345a0 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc @@ -2,6 +2,8 @@ #include #include #include "xua.h" + +#if XUA_USB_EN #include "xua_ep0_wrapper.h" #define DEBUG_UNIT EP0_WRAPPER @@ -46,3 +48,4 @@ void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, client ep0_contro } } } +#endif From 8ff44c553c82de73cad845f61c8752adfe702601 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 23 Sep 2019 15:36:35 +0100 Subject: [PATCH 064/123] Add the specific directory that contains user_hid.h. Apparently xwaf doesn't recursively descend directory trees the way xmake does. --- lib_xua/module_build_info | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/module_build_info b/lib_xua/module_build_info index 2a36dedf..f13abe6b 100644 --- a/lib_xua/module_build_info +++ b/lib_xua/module_build_info @@ -17,7 +17,7 @@ VERSION = 0.2.0 DEPENDENT_MODULES = lib_logging(>=2.1.0) lib_xassert(>=2.0.0) lib_xud(>=0.1.0) lib_spdif(>=3.0.0) -INCLUDE_DIRS = api src/* +INCLUDE_DIRS = api src/* src/core/user #ignore host dir SOURCE_DIRS = src/* From bb5757e099b9a71ab54ff0a8c815f1d8914e33ec Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 23 Sep 2019 17:29:39 +0100 Subject: [PATCH 065/123] Initial implementation of HID. --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 2 +- lib_xua/src/core/user/user_hid.h | 4 +++- lib_xua/src/core/user/user_hid.xc | 12 ++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 lib_xua/src/core/user/user_hid.xc diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index e510d37a..b9c01d6b 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -880,7 +880,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, case XUD_SetData_Select(c_hid, ep_hid, result): { g_hidData[0]=0; - UserReadHIDButtons(g_hidData); + UserReadHIDData(g_hidData); XUD_SetReady_In(ep_hid, g_hidData, 1); } break; diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index b2530d0f..6620c7dd 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -9,5 +9,7 @@ #define HID_CONTROL_VOLDN_SHIFT 0x04 #define HID_CONTROL_MUTE_SHIFT 0x05 -void UserReadHIDButtons(unsigned char hidData[]); +#define HID_DATA_SIZE 1 + +void UserReadHIDData(unsigned char hidData[HID_DATA_SIZE]); diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc new file mode 100644 index 00000000..61466360 --- /dev/null +++ b/lib_xua/src/core/user/user_hid.xc @@ -0,0 +1,12 @@ +// Copyright (c) 2019, XMOS Ltd, All rights reserved +#include +#include +#include +#include "user_hid.h" + +void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]) +{ + for( unsigned idx = 0; idx < HID_DATA_SIZE; ++idx ) { + hidData[ idx ] = 1; + } +} \ No newline at end of file From 017d937ec7e74ae618d8d8540e7bce09d284ffa7 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 25 Sep 2019 11:39:48 +0100 Subject: [PATCH 066/123] Add comments to match #endif directives to their corresponding #if or #ifdef directive. Added to aid reading. --- .../src/core/endpoint0/xua_ep0_descriptors.h | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index b3129ac0..ea34ac2b 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -1084,7 +1084,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= }, 0, /* 60 iFeature */ }, -#endif +#endif /* (OUTPUT_VOLUME_CONTROL == 1) */ /* Output Terminal Descriptor (Audio) */ .Audio_Out_OutputTerminal = @@ -1104,7 +1104,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= 0x0000, /* 9 bmControls */ 0, /* 11 iTerminal */ }, -#endif +#endif /* (NUM_USB_CHAN_OUT > 0) */ @@ -1259,7 +1259,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= }, 0, /* 60 iFeature */ }, -#endif +#endif /* (INPUT_VOLUME_CONTROL == 1) */ .Audio_In_OutputTerminal = { @@ -1280,7 +1280,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bmControls = 0x0000, .iTerminal = offsetof(StringDescTable_t, usbOutputTermStr_Audio2)/sizeof(char *) }, -#endif +#endif /* (NUM_USB_CHAN_IN > 0) */ #if defined(MIXER) && (MAX_MIX_COUNT > 0) /* Extension Unit Descriptor (4.7.2.12) */ @@ -1374,7 +1374,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= 0x00, /* bmControls */ 0 /* Mixer unit string descriptor index */ }, -#endif +#endif /* defined(MIXER) && (MAX_MIX_COUNT > 0) */ #if (SPDIF_RX) || (ADAT_RX) /* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */ @@ -1571,7 +1571,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= 4, /* 6 bInterval. Only values <= 1 frame (4) supported by MS */ }, #endif -#endif +#endif /* OUTPUT_FORMAT_COUNT > 1 */ #if (OUTPUT_FORMAT_COUNT > 2) /* Standard AS Interface Descriptor (4.9.1) (Alt) */ .Audio_Out_StreamInterface_Alt3 = @@ -1815,7 +1815,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bLockDelayUnits = 0x02, .wLockDelay = 0x0008, }, -#endif +#endif /* (INPUT_FORMAT_COUNT > 1) */ #if (INPUT_FORMAT_COUNT > 2) /* Alternative 3 */ /* Standard AS Interface Descriptor (4.9.1) (Alt) */ @@ -1888,7 +1888,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bLockDelayUnits = 0x02, .wLockDelay = 0x0008, }, -#endif +#endif /* (INPUT_FORMAT_COUNT > 2) */ #endif /* #if(NUM_USB_CHAN_IN > 0) */ #ifdef MIDI @@ -2044,7 +2044,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= 0x10, /* 7 bcdDFUVersion */ 0x01}, /* 7 bcdDFUVersion */ #endif -#endif +#endif /* (XUA_DFU_EN == 1) */ #ifdef IAP /* Interface descriptor */ @@ -2192,7 +2192,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= #endif }; -#endif +#endif /* (AUDIO_CLASS == 2) */ #ifdef HID_CONTROLS unsigned char hidDescriptor[] = From 75422de6d18a126af5fe52fc66457f676f0e16f6 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 25 Sep 2019 11:42:59 +0100 Subject: [PATCH 067/123] Replace existing #ifdef HID_CONTROLS with #if( 0 < HID_CONTROLS ) to move to best practice regarding compile-time switches. --- lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index ea34ac2b..0f762d61 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -547,7 +547,7 @@ unsigned char devQualDesc_Null[] = #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) unsigned char hidReportDescriptor[] = { 0x05, 0x0c, /* Usage Page (Consumer Device) */ @@ -769,7 +769,7 @@ typedef struct #endif #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) USB_Descriptor_Interface_t HID_Interface; unsigned char hidDesc[9]; //TODO ideally we would have a struct for this. USB_Descriptor_Endpoint_t HID_In_Endpoint; @@ -2153,7 +2153,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= #endif #endif /* IAP */ -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) .HID_Interface = { 9, /* 0 bLength : Size of descriptor in Bytes */ @@ -2194,7 +2194,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= }; #endif /* (AUDIO_CLASS == 2) */ -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) unsigned char hidDescriptor[] = { 9, /* 0 bLength : Size of descriptor in Bytes */ From 35393d37395bd6d49c3f54236e2dfd81f7b256f5 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 25 Sep 2019 11:44:43 +0100 Subject: [PATCH 068/123] Remove duplicate definitions. --- lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 0f762d61..d6eac320 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -2309,18 +2309,6 @@ const unsigned num_freqs_a1 = MAX(3, (0 #define DFU_INTERFACES_A1 0 #endif -/* Total number of bytes returned for the class-specific AudioControl interface descriptor. - * Includes the combined length of this descriptor header and all Unit and Terminal descriptors - * For us this is IT -> FU -> OT * 2 and a header */ -#define AC_TOTAL_LENGTH (AC_LENGTH + \ - (INPUT_INTERFACES_A1 * (12 + ( (8 + NUM_USB_CHAN_IN_FS) * INPUT_VOLUME_CONTROL) + 9)) +\ - (OUTPUT_INTERFACES_A1 * (12 + ( (8 + NUM_USB_CHAN_OUT_FS) * OUTPUT_VOLUME_CONTROL) + 9))) - -#define STREAMING_INTERFACES (INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1) - -//#if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) -//#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (58 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES) -//#endif /* Total number of bytes returned for the class-specific AudioControl interface descriptor. * Includes the combined length of this descriptor header and all Unit and Terminal descriptors From 958d52b5eb0e0a35eee4f998bf9b3b537c62b8cf Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 25 Sep 2019 11:45:40 +0100 Subject: [PATCH 069/123] Consistently use hex when defining descriptor values. --- lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index d6eac320..3cc81862 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -2197,12 +2197,12 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= #if( 0 < HID_CONTROLS ) unsigned char hidDescriptor[] = { - 9, /* 0 bLength : Size of descriptor in Bytes */ + 0x09, /* 0 bLength : Size of descriptor in Bytes */ 0x21, /* 1 bDescriptorType (HID) */ 0x10, /* 2 bcdHID */ 0x01, /* 3 bcdHID */ - 0, /* 4 bCountryCode */ - 1, /* 5 bNumDescriptors */ + 0x00, /* 4 bCountryCode */ + 0x01, /* 5 bNumDescriptors */ 0x22, /* 6 bDescriptorType[0] (Report) */ sizeof(hidReportDescriptor) & 0xff, /* 7 wDescriptorLength[0] */ sizeof(hidReportDescriptor) >> 8, /* 8 wDescriptorLength[0] */ From 3131b89a1d9691eb175f3cb51e564ffca5a150dd Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 25 Sep 2019 11:46:16 +0100 Subject: [PATCH 070/123] Add HID descriptors for UAC1. --- .../src/core/endpoint0/xua_ep0_descriptors.h | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 3cc81862..61ba05d7 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -2309,6 +2309,13 @@ const unsigned num_freqs_a1 = MAX(3, (0 #define DFU_INTERFACES_A1 0 #endif +#if( 0 < HID_CONTROLS ) +#define HID_INTERFACE_BYTES ( 9 + 9 + 7 ) +#define HID_INTERFACES_A1 1 +#else +#define HID_INTERFACE_BYTES 0 +#define HID_INTERFACES_A1 0 +#endif /* Total number of bytes returned for the class-specific AudioControl interface descriptor. * Includes the combined length of this descriptor header and all Unit and Terminal descriptors @@ -2321,12 +2328,12 @@ const unsigned num_freqs_a1 = MAX(3, (0 /* Number of interfaces for Audio 1.0 (+1 for control ) */ /* Note, this is different that INTERFACE_COUNT since we dont support items such as MIDI, iAP etc in UAC1 mode */ -#define NUM_INTERFACES_A1 (1+INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1+NUM_CONTROL_USB_INTERFACES+DFU_INTERFACES_A1) +#define NUM_INTERFACES_A1 (1 + INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1 + NUM_CONTROL_USB_INTERFACES + DFU_INTERFACES_A1 + HID_INTERFACES_A1) #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) -#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (58 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES) +#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (58 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + HID_INTERFACE_BYTES) #else -#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES) +#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + HID_INTERFACE_BYTES) #endif #define CHARIFY_SR(x) (x & 0xff),((x & 0xff00)>> 8),((x & 0xff0000)>> 16) @@ -2828,6 +2835,38 @@ unsigned char cfgDesc_Audio1[] = offsetof(StringDescTable_t, ctrlStr)/sizeof(char *), /* 8 iInterface */ #endif +#if( 0 < HID_CONTROLS ) + /* HID interface descriptor */ + 0x09, /* 0 bLength : Size of descriptor in Bytes */ + 0x04, /* 1 bDescriptorType (Interface: 0x04)*/ + INTERFACE_NUMBER_HID, /* 2 bInterfaceNumber : Number of interface */ + 0x00, /* 3 bAlternateSetting : Value used alternate interfaces using SetInterface Request */ + 0x01, /* 4: bNumEndpoints : Number of endpoitns for this interface (excluding 0) */ + 0x03, /* 5: bInterfaceClass */ + 0x00, /* 6: bInterfaceSubClass - no boot device */ + 0x00, /* 7: bInterfaceProtocol*/ + 0x00, /* 8 iInterface */ + + /* HID descriptor */ + 0x09, /* 0 bLength : Size of descriptor in Bytes */ + 0x21, /* 1 bDescriptorType (HID) */ + 0x10, /* 2 bcdHID */ + 0x01, /* 3 bcdHID */ + 0x00, /* 4 bCountryCode */ + 0x01, /* 5 bNumDescriptors */ + 0x22, /* 6 bDescriptorType[0] (Report) */ + 0x21, /* 7 wDescriptorLength[0] */ + 0x00, /* 8 wDescriptorLength[0] */ + + /* HID Endpoint descriptor (IN) */ + 0x07, /* 0 bLength */ + 0x05, /* 1 bDescriptorType */ + ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */ + 0x03, /* 3 bmAttributes (INTERRUPT) */ + 64, /* 4 wMaxPacketSize */ + 0x08, /* 6 bInterval */ +#endif + }; #endif #endif From 960333ca091b7bd8fa20c82c83c1a700477d8fce Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 25 Sep 2019 14:38:17 +0100 Subject: [PATCH 071/123] Add the missing MSB of the maximum packet size and use hex values instead of decimal. --- lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 61ba05d7..ae7ef76a 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -2863,7 +2863,8 @@ unsigned char cfgDesc_Audio1[] = 0x05, /* 1 bDescriptorType */ ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */ 0x03, /* 3 bmAttributes (INTERRUPT) */ - 64, /* 4 wMaxPacketSize */ + 0x40, /* 4 wMaxPacketSize */ + 0x00, /* 5 wMaxPacketSize */ 0x08, /* 6 bInterval */ #endif From d491eb2da91efd9b8b4beafdb218eb4e5e10dac1 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 25 Sep 2019 16:12:59 +0100 Subject: [PATCH 072/123] Change HID Report descriptor to contain one variable bit in the lsb position. This bit reports the interrupt. The remaining seven bits are constant at zero. --- lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index ae7ef76a..bd95078e 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -556,15 +556,10 @@ unsigned char hidReportDescriptor[] = 0x15, 0x00, /* Logical Minimum (0) */ 0x25, 0x01, /* Logical Maximum (1) */ 0x09, 0xb0, /* Usage (Play) */ - 0x09, 0xb5, /* Usage (Scan Next Track) */ - 0x09, 0xb6, /* Usage (Scan Previous Track) */ - 0x09, 0xe9, /* Usage (Volume Up) */ - 0x09, 0xea, /* Usage (Volume Down) */ - 0x09, 0xe2, /* Usage (Mute) */ 0x75, 0x01, /* Report Size (1) */ - 0x95, 0x06, /* Report Count (6) */ + 0x95, 0x01, /* Report Count (1) */ 0x81, 0x02, /* Input (Data, Var, Abs) */ - 0x95, 0x02, /* Report Count (2) */ + 0x95, 0x07, /* Report Count (7) */ 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ 0xc0 /* End collection */ }; @@ -2855,7 +2850,7 @@ unsigned char cfgDesc_Audio1[] = 0x00, /* 4 bCountryCode */ 0x01, /* 5 bNumDescriptors */ 0x22, /* 6 bDescriptorType[0] (Report) */ - 0x21, /* 7 wDescriptorLength[0] */ + 0x17, /* 7 wDescriptorLength[0] */ 0x00, /* 8 wDescriptorLength[0] */ /* HID Endpoint descriptor (IN) */ From 3c86da7c092c5c0c1a2a3fe16682c9fd3ca9b332 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 25 Sep 2019 16:13:46 +0100 Subject: [PATCH 073/123] Add demo HID code that simulates an interrupt roughly every 10 seconds. --- lib_xua/src/core/user/user_hid.xc | 35 ++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc index 61466360..d27d6914 100644 --- a/lib_xua/src/core/user/user_hid.xc +++ b/lib_xua/src/core/user/user_hid.xc @@ -4,9 +4,38 @@ #include #include "user_hid.h" +#define HID_INTERRUPT_COUNT 1000000000 +#define HID_REPORT_DATA 0x01 + +static unsigned char initialised = 0; + +static unsigned int curr_time = 0; +static unsigned int last_time = 0; +static unsigned int tick_count = 0; + void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]) { - for( unsigned idx = 0; idx < HID_DATA_SIZE; ++idx ) { - hidData[ idx ] = 1; + timer tmr; + + if( !initialised ) { + tmr :> last_time; + initialised = 1; + } else { + tmr :> curr_time; + tick_count += ( last_time < curr_time ) ? curr_time - last_time : curr_time + ( UINT_MAX - last_time ); + + if( HID_INTERRUPT_COUNT <= tick_count ) { + for( unsigned idx = 0; idx < HID_DATA_SIZE; ++idx ) { + hidData[ idx ] = HID_REPORT_DATA; + } + + tick_count = 0; + } else { + for( unsigned idx = 0; idx < HID_DATA_SIZE; ++idx ) { + hidData[ idx ] = 0x00; + } + } + + last_time = curr_time; } -} \ No newline at end of file +} From 9472bd7dcef7db405ebf02a3cfa87e180054b9fe Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Thu, 26 Sep 2019 14:22:17 +0100 Subject: [PATCH 074/123] Change HID usage from Play On-Off Control (OOC) to Voice Command One-Shot Control (OSC). OSC requires relative data. --- lib_xua/src/core/endpoint0/xua_ep0_descriptors.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index bd95078e..e6c56aa9 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -555,10 +555,10 @@ unsigned char hidReportDescriptor[] = 0xa1, 0x01, /* Collection (Application) */ 0x15, 0x00, /* Logical Minimum (0) */ 0x25, 0x01, /* Logical Maximum (1) */ - 0x09, 0xb0, /* Usage (Play) */ + 0x09, 0xcf, /* Usage (Voice Command), use 0xcd for (Play/Pause OSC) */ 0x75, 0x01, /* Report Size (1) */ 0x95, 0x01, /* Report Count (1) */ - 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x81, 0x06, /* Input (Data, Var, Rel) */ 0x95, 0x07, /* Report Count (7) */ 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ 0xc0 /* End collection */ From ba666fb314e96c8655688ca6925fbdf6f30597c7 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Thu, 26 Sep 2019 14:27:20 +0100 Subject: [PATCH 075/123] Add a 100 ms assertion period when this demonstration code signals an NDP100 interrupt. When testing with the Play/Pause Usage (0xCD) with a Mac as USB Host, adding in this assertion period produced reliable playing and pausing of the iTunes app every 10 seconds. Without an explicit assertion period, i.e. sending only one report with the lsb set to 1b followed by many reports with the lsb set to 0b, the iTunes app behaved as though it did not see many of the Play/Pause signals. The inclusion of an assertion period may or may not help when reporting Voice Command events on Andriod. --- lib_xua/src/core/user/user_hid.xc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc index d27d6914..4319bf43 100644 --- a/lib_xua/src/core/user/user_hid.xc +++ b/lib_xua/src/core/user/user_hid.xc @@ -4,6 +4,7 @@ #include #include "user_hid.h" +#define HID_DEASSERT_COUNT 10000000 #define HID_INTERRUPT_COUNT 1000000000 #define HID_REPORT_DATA 0x01 @@ -24,16 +25,18 @@ void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]) tmr :> curr_time; tick_count += ( last_time < curr_time ) ? curr_time - last_time : curr_time + ( UINT_MAX - last_time ); - if( HID_INTERRUPT_COUNT <= tick_count ) { + if(( HID_INTERRUPT_COUNT <= tick_count ) && ( tick_count <= ( HID_INTERRUPT_COUNT + HID_DEASSERT_COUNT ))) { for( unsigned idx = 0; idx < HID_DATA_SIZE; ++idx ) { hidData[ idx ] = HID_REPORT_DATA; } - - tick_count = 0; } else { for( unsigned idx = 0; idx < HID_DATA_SIZE; ++idx ) { hidData[ idx ] = 0x00; - } + } + + if (( HID_INTERRUPT_COUNT + HID_DEASSERT_COUNT ) <= tick_count ) { + tick_count = 0; + } } last_time = curr_time; From 37bbea3726e4bebc2a0ebdb9ef5cd269593cbf9b Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Thu, 26 Sep 2019 14:45:17 +0100 Subject: [PATCH 076/123] Use a consistent method to interpret the HID_CONTROLS pre-processor symbol throughout the code base. --- lib_xua/api/xua_buffer.h | 4 ++-- lib_xua/api/xua_conf_default.h | 6 +----- lib_xua/src/core/buffer/decouple/decouple.xc | 2 +- lib_xua/src/core/buffer/ep/ep_buffer.xc | 14 +++++++------- lib_xua/src/core/endpoint0/descriptor_defs.h | 2 +- lib_xua/src/core/endpoint0/xua_endpoint0.c | 6 +++--- lib_xua/src/core/main.xc | 4 ++-- 7 files changed, 17 insertions(+), 21 deletions(-) diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index eaaef881..93ca3219 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -58,7 +58,7 @@ void XUA_Buffer( chanend c_sof, chanend c_aud_ctl, in port p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , chanend c_hid #endif , chanend c_aud @@ -97,7 +97,7 @@ void XUA_Buffer_Ep(chanend c_aud_out, chanend c_sof, chanend c_aud_ctl, in port p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , chanend c_hid #endif #ifdef CHAN_BUFF_CTRL diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 677fad9e..5e311e9f 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -425,10 +425,6 @@ #define HID_CONTROLS (0) #endif -#if defined(HID_CONTROLS) && (HID_CONTROLS == 0) -#undef HID_CONTROLS -#endif - /* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks) * * 0: XMOS is I2S master. 1: CODEC is I2s master. @@ -1177,7 +1173,7 @@ enum USBEndpointNumber_In #ifdef MIDI ENDPOINT_NUMBER_IN_MIDI, #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) ENDPOINT_NUMBER_IN_HID, #endif #ifdef IAP diff --git a/lib_xua/src/core/buffer/decouple/decouple.xc b/lib_xua/src/core/buffer/decouple/decouple.xc index e503ab71..8e291aef 100644 --- a/lib_xua/src/core/buffer/decouple/decouple.xc +++ b/lib_xua/src/core/buffer/decouple/decouple.xc @@ -12,7 +12,7 @@ #include "usbaudio20.h" /* Defines from the USB Audio 2.0 Specifications */ #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) #include "user_hid.h" #endif #define MAX(x,y) ((x)>(y) ? (x) : (y)) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index b9c01d6b..5916da17 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -19,7 +19,7 @@ #include "xud.h" #include "testct_byref.h" -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) #include "user_hid.h" unsigned char g_hidData[1] = {0}; #endif @@ -120,7 +120,7 @@ void XUA_Buffer( chanend c_sof, chanend c_aud_ctl, in port p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , chanend c_hid #endif , chanend c_aud @@ -164,7 +164,7 @@ void XUA_Buffer( c_clk_int, #endif c_sof, c_aud_ctl, p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , c_hid #endif #ifdef CHAN_BUFF_CTRL @@ -223,7 +223,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, chanend c_sof, chanend c_aud_ctl, in port p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , chanend c_hid #endif #ifdef CHAN_BUFF_CTRL @@ -260,7 +260,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, XUD_ep ep_int = XUD_InitEp(c_ep_int); #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) XUD_ep ep_hid = XUD_InitEp(c_hid); #endif unsigned u_tmp; @@ -364,7 +364,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) XUD_SetReady_In(ep_hid, g_hidData, 1); #endif @@ -875,7 +875,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) /* HID Report Data */ case XUD_SetData_Select(c_hid, ep_hid, result): { diff --git a/lib_xua/src/core/endpoint0/descriptor_defs.h b/lib_xua/src/core/endpoint0/descriptor_defs.h index 1985d910..b348d6f1 100644 --- a/lib_xua/src/core/endpoint0/descriptor_defs.h +++ b/lib_xua/src/core/endpoint0/descriptor_defs.h @@ -54,7 +54,7 @@ enum USBInterfaceNumber INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS, #endif #endif -#if defined(HID_CONTROLS) && (HID_CONTROLS != 0) +#if( 0 < HID_CONTROLS ) INTERFACE_NUMBER_HID, #endif INTERFACE_COUNT /* End marker */ diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index 11833693..b5d1d8b7 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -21,7 +21,7 @@ #include "vendorrequests.h" #include "xc_ptr.h" #include "xua_ep0_uacreqs.h" -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) #include "hid.h" #endif #if DSD_CHANS_DAC > 0 @@ -492,7 +492,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 switch(sp.bRequest) { -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) case USB_GET_DESCRIPTOR: /* Check what inteface request is for */ @@ -871,7 +871,7 @@ void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend switch(sp.bRequest) { -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) case USB_GET_DESCRIPTOR: /* Check what inteface request is for */ diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index cb9d8af7..5a7aace0 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -259,7 +259,7 @@ XUD_EpType epTypeTableIn[ENDPOINT_COUNT_IN] = { XUD_EPTYPE_CTL | XUD_STATUS_ENAB #ifdef MIDI XUD_EPTYPE_BUL, #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) XUD_EPTYPE_INT, #endif #ifdef IAP @@ -400,7 +400,7 @@ VENDOR_REQUESTS_PARAMS_DEC_ c_clk_int, #endif c_sof, c_aud_ctl, p_for_mclk_count -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , c_xud_in[ENDPOINT_NUMBER_IN_HID] #endif #ifdef CHAN_BUFF_CTRL From b68c192ad9f49257aa41f69764b1754be1b89e4d Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Thu, 26 Sep 2019 16:29:53 +0100 Subject: [PATCH 077/123] Updated change log --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a5b83a91..35c363bc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,11 @@ lib_xua Change Log ================== +0.2.0_demo +---------- + * ADDED: UAC1 HID support with simulated Voice Command detection reported + every 10 seconds + 0.2.0 ----- From d7be8419d8b213798768f986402b4df2bd75ea81 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 30 Sep 2019 13:52:22 +0100 Subject: [PATCH 078/123] Add a 1b port for receiving the NDP10x interrupt. --- lib_xua/api/xua_buffer.h | 2 ++ lib_xua/src/core/buffer/ep/ep_buffer.xc | 5 ++++- lib_xua/src/core/user/user_hid.h | 2 +- lib_xua/src/core/user/user_hid.xc | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index 93ca3219..5e7f65e4 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -60,6 +60,7 @@ void XUA_Buffer( in port p_off_mclk #if( 0 < HID_CONTROLS ) , chanend c_hid + , in port p_int #endif , chanend c_aud ); @@ -99,6 +100,7 @@ void XUA_Buffer_Ep(chanend c_aud_out, in port p_off_mclk #if( 0 < HID_CONTROLS ) , chanend c_hid + , in port p_int #endif #ifdef CHAN_BUFF_CTRL , chanend c_buff_ctrl diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 5916da17..b3c28856 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -122,6 +122,7 @@ void XUA_Buffer( in port p_off_mclk #if( 0 < HID_CONTROLS ) , chanend c_hid + , in port p_int #endif , chanend c_aud ) @@ -166,6 +167,7 @@ void XUA_Buffer( c_sof, c_aud_ctl, p_off_mclk #if( 0 < HID_CONTROLS ) , c_hid + , p_int #endif #ifdef CHAN_BUFF_CTRL , c_buff_ctrl @@ -225,6 +227,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, in port p_off_mclk #if( 0 < HID_CONTROLS ) , chanend c_hid + , in port p_int #endif #ifdef CHAN_BUFF_CTRL , chanend c_buff_ctrl @@ -880,7 +883,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, case XUD_SetData_Select(c_hid, ep_hid, result): { g_hidData[0]=0; - UserReadHIDData(g_hidData); + UserReadHIDData(p_int, g_hidData); XUD_SetReady_In(ep_hid, g_hidData, 1); } break; diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index 6620c7dd..736ab13a 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -11,5 +11,5 @@ #define HID_DATA_SIZE 1 -void UserReadHIDData(unsigned char hidData[HID_DATA_SIZE]); +void UserReadHIDData(in port p_int, unsigned char hidData[HID_DATA_SIZE]); diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc index 4319bf43..1306a892 100644 --- a/lib_xua/src/core/user/user_hid.xc +++ b/lib_xua/src/core/user/user_hid.xc @@ -14,7 +14,7 @@ static unsigned int curr_time = 0; static unsigned int last_time = 0; static unsigned int tick_count = 0; -void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]) +void UserReadHIDData( in port p_int, unsigned char hidData[ HID_DATA_SIZE ]) { timer tmr; From 660b483d1e129f6e8c587aebe35dd2f9127250bc Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 30 Sep 2019 16:12:16 +0100 Subject: [PATCH 079/123] Clean up whitespace, no functional change. --- lib_xua/src/core/user/user_hid.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index 736ab13a..9c135744 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -2,12 +2,12 @@ /* These defines relate to the HID report desc - do not mod */ -#define HID_CONTROL_PLAYPAUSE_SHIFT 0x00 -#define HID_CONTROL_NEXT_SHIFT 0x01 -#define HID_CONTROL_PREV_SHIFT 0x02 -#define HID_CONTROL_VOLUP_SHIFT 0x03 -#define HID_CONTROL_VOLDN_SHIFT 0x04 -#define HID_CONTROL_MUTE_SHIFT 0x05 +#define HID_CONTROL_PLAYPAUSE_SHIFT 0x00 +#define HID_CONTROL_NEXT_SHIFT 0x01 +#define HID_CONTROL_PREV_SHIFT 0x02 +#define HID_CONTROL_VOLUP_SHIFT 0x03 +#define HID_CONTROL_VOLDN_SHIFT 0x04 +#define HID_CONTROL_MUTE_SHIFT 0x05 #define HID_DATA_SIZE 1 From e1b72c47bcb43b608bd1914b95783695f9c46755 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 30 Sep 2019 16:14:16 +0100 Subject: [PATCH 080/123] Add a version of UserReadHIDData() which uses a signal on a port to set the Voice Command bit in the HID Report data. This commit preserves the ability to simulate the NDP100 entirely, i.e. without using a port for input. --- lib_xua/src/core/user/user_hid.h | 29 +++++++++++++++++++++++++++++ lib_xua/src/core/user/user_hid.xc | 24 ++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index 9c135744..edf4ebda 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -11,5 +11,34 @@ #define HID_DATA_SIZE 1 +#ifndef HID_SIMULATE_INTERRUPTS +#define HID_SIMULATE_INTERRUPTS 0 +#endif + +#ifndef HID_SIMULATE_NDP10X +#define HID_SIMULATE_NDP10X 0 +#endif + +#ifndef NDP_ASSERT_HIGH +#define NDP_ASSERT_HIGH 0 +#endif + +#if( 0 < HID_CONTROLS ) + +#if( 0 < NDP_ASSERT_HIGH ) +#define NDP100_ASSERT_LEVEL 1 +#define NDP100_DEASSERT_LEVEL 0 +#else +#define NDP100_ASSERT_LEVEL 0 +#define NDP100_DEASSERT_LEVEL 1 +#endif + +#if(( 0 < HID_SIMULATE_INTERRUPTS ) || ( 0 < HID_SIMULATE_NDP10X )) +#define HID_DEASSERT_COUNT 10000000 +#define HID_INTERRUPT_COUNT 1000000000 +#endif + +#endif /* ( 0 < HID_CONTROLS ) */ + void UserReadHIDData(in port p_int, unsigned char hidData[HID_DATA_SIZE]); diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc index 1306a892..79d4cb76 100644 --- a/lib_xua/src/core/user/user_hid.xc +++ b/lib_xua/src/core/user/user_hid.xc @@ -4,8 +4,9 @@ #include #include "user_hid.h" -#define HID_DEASSERT_COUNT 10000000 -#define HID_INTERRUPT_COUNT 1000000000 +#if( 0 < HID_CONTROLS ) +#if( 0 < HID_SIMULATE_NDP10X ) + #define HID_REPORT_DATA 0x01 static unsigned char initialised = 0; @@ -42,3 +43,22 @@ void UserReadHIDData( in port p_int, unsigned char hidData[ HID_DATA_SIZE ]) last_time = curr_time; } } +#else /* ( 0 < HID_SIMULATE_NDP10X ) */ + +#define HID_REPORT_INTERRUPT_ASSERTED 0x01 +#define HID_REPORT_INTERRUPT_DEASSERTED 0x00 + +void UserReadHIDData( in port p_int, unsigned char hidData[ HID_DATA_SIZE ]) +{ + unsigned curr_val; + + p_int :> curr_val; + hidData[ 0 ] = ( curr_val == NDP100_ASSERT_LEVEL ) ? HID_REPORT_INTERRUPT_ASSERTED : HID_REPORT_INTERRUPT_DEASSERTED; + + for( unsigned idx = 1; idx < HID_DATA_SIZE; ++idx ) { + hidData[ idx ] = 0U; + } +} + +#endif /* ( 0 < HID_SIMULATE_NDP10X ) */ +#endif /* ( 0 < HID_CONTROLS ) */ From d32235d0f03901167605ee7c118b7737af500fef Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 1 Oct 2019 11:57:54 +0100 Subject: [PATCH 081/123] Final clean-up of HID -- NDP10x Interrupt integration. --- lib_xua/src/core/user/user_hid.h | 20 ++++++-------- lib_xua/src/core/user/user_hid.xc | 43 +------------------------------ 2 files changed, 9 insertions(+), 54 deletions(-) diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index edf4ebda..ca0fcf93 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -15,25 +15,21 @@ #define HID_SIMULATE_INTERRUPTS 0 #endif -#ifndef HID_SIMULATE_NDP10X -#define HID_SIMULATE_NDP10X 0 -#endif - -#ifndef NDP_ASSERT_HIGH -#define NDP_ASSERT_HIGH 0 +#ifndef NDP_ASSERT_LEVEL +#define NDP_ASSERT_LEVEL 0 #endif #if( 0 < HID_CONTROLS ) -#if( 0 < NDP_ASSERT_HIGH ) -#define NDP100_ASSERT_LEVEL 1 -#define NDP100_DEASSERT_LEVEL 0 +#if( 0 < NDP_ASSERT_LEVEL ) +#define NDP10X_ASSERT_LEVEL 1 +#define NDP10X_DEASSERT_LEVEL 0 #else -#define NDP100_ASSERT_LEVEL 0 -#define NDP100_DEASSERT_LEVEL 1 +#define NDP10X_ASSERT_LEVEL 0 +#define NDP10X_DEASSERT_LEVEL 1 #endif -#if(( 0 < HID_SIMULATE_INTERRUPTS ) || ( 0 < HID_SIMULATE_NDP10X )) +#if( 0 < HID_SIMULATE_INTERRUPTS ) #define HID_DEASSERT_COUNT 10000000 #define HID_INTERRUPT_COUNT 1000000000 #endif diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc index 79d4cb76..d10960cf 100644 --- a/lib_xua/src/core/user/user_hid.xc +++ b/lib_xua/src/core/user/user_hid.xc @@ -5,46 +5,6 @@ #include "user_hid.h" #if( 0 < HID_CONTROLS ) -#if( 0 < HID_SIMULATE_NDP10X ) - -#define HID_REPORT_DATA 0x01 - -static unsigned char initialised = 0; - -static unsigned int curr_time = 0; -static unsigned int last_time = 0; -static unsigned int tick_count = 0; - -void UserReadHIDData( in port p_int, unsigned char hidData[ HID_DATA_SIZE ]) -{ - timer tmr; - - if( !initialised ) { - tmr :> last_time; - initialised = 1; - } else { - tmr :> curr_time; - tick_count += ( last_time < curr_time ) ? curr_time - last_time : curr_time + ( UINT_MAX - last_time ); - - if(( HID_INTERRUPT_COUNT <= tick_count ) && ( tick_count <= ( HID_INTERRUPT_COUNT + HID_DEASSERT_COUNT ))) { - for( unsigned idx = 0; idx < HID_DATA_SIZE; ++idx ) { - hidData[ idx ] = HID_REPORT_DATA; - } - } else { - for( unsigned idx = 0; idx < HID_DATA_SIZE; ++idx ) { - hidData[ idx ] = 0x00; - } - - if (( HID_INTERRUPT_COUNT + HID_DEASSERT_COUNT ) <= tick_count ) { - tick_count = 0; - } - } - - last_time = curr_time; - } -} -#else /* ( 0 < HID_SIMULATE_NDP10X ) */ - #define HID_REPORT_INTERRUPT_ASSERTED 0x01 #define HID_REPORT_INTERRUPT_DEASSERTED 0x00 @@ -53,12 +13,11 @@ void UserReadHIDData( in port p_int, unsigned char hidData[ HID_DATA_SIZE ]) unsigned curr_val; p_int :> curr_val; - hidData[ 0 ] = ( curr_val == NDP100_ASSERT_LEVEL ) ? HID_REPORT_INTERRUPT_ASSERTED : HID_REPORT_INTERRUPT_DEASSERTED; + hidData[ 0 ] = ( curr_val == NDP10X_ASSERT_LEVEL ) ? HID_REPORT_INTERRUPT_ASSERTED : HID_REPORT_INTERRUPT_DEASSERTED; for( unsigned idx = 1; idx < HID_DATA_SIZE; ++idx ) { hidData[ idx ] = 0U; } } -#endif /* ( 0 < HID_SIMULATE_NDP10X ) */ #endif /* ( 0 < HID_CONTROLS ) */ From 2fb0bdfcc22494b558b52b4e24732d5924134fb6 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 1 Oct 2019 13:52:08 +0100 Subject: [PATCH 082/123] A slightly different way of saying the same thing. I've changed to an if - else construct to make it easy to add in debugging print statements if needed. --- lib_xua/src/core/user/user_hid.xc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc index d10960cf..2c907f16 100644 --- a/lib_xua/src/core/user/user_hid.xc +++ b/lib_xua/src/core/user/user_hid.xc @@ -13,7 +13,12 @@ void UserReadHIDData( in port p_int, unsigned char hidData[ HID_DATA_SIZE ]) unsigned curr_val; p_int :> curr_val; - hidData[ 0 ] = ( curr_val == NDP10X_ASSERT_LEVEL ) ? HID_REPORT_INTERRUPT_ASSERTED : HID_REPORT_INTERRUPT_DEASSERTED; + + if( curr_val == NDP10X_ASSERT_LEVEL ) { + hidData[ 0 ] = HID_REPORT_INTERRUPT_ASSERTED; + } else { + hidData[ 0 ] = HID_REPORT_INTERRUPT_DEASSERTED; + } for( unsigned idx = 1; idx < HID_DATA_SIZE; ++idx ) { hidData[ idx ] = 0U; From 17317093d588625733c695d298c54ab144215e8a Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 1 Oct 2019 17:04:13 +0100 Subject: [PATCH 083/123] Rework HID data processing. Move port handling up into XUA_Buffer_lite2() to take advantage of its select operator. Add functions to initialise and set the HID data. --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 2 +- lib_xua/src/core/user/user_hid.h | 9 +++++---- lib_xua/src/core/user/user_hid.xc | 26 ++++++++++++++++--------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index b3c28856..53244092 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -883,7 +883,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, case XUD_SetData_Select(c_hid, ep_hid, result): { g_hidData[0]=0; - UserReadHIDData(p_int, g_hidData); + UserReadHIDData(g_hidData); XUD_SetReady_In(ep_hid, g_hidData, 1); } break; diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index ca0fcf93..24699c14 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -30,11 +30,12 @@ #endif #if( 0 < HID_SIMULATE_INTERRUPTS ) -#define HID_DEASSERT_COUNT 10000000 +#define HID_DEASSERT_COUNT 10000 #define HID_INTERRUPT_COUNT 1000000000 #endif +void UserInitHIDData(void); +void UserReadHIDData(unsigned char hidData[ HID_DATA_SIZE ]); +void UserSetHIDData(const unsigned hidData); + #endif /* ( 0 < HID_CONTROLS ) */ - -void UserReadHIDData(in port p_int, unsigned char hidData[HID_DATA_SIZE]); - diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc index 2c907f16..dfba7fed 100644 --- a/lib_xua/src/core/user/user_hid.xc +++ b/lib_xua/src/core/user/user_hid.xc @@ -8,20 +8,28 @@ #define HID_REPORT_INTERRUPT_ASSERTED 0x01 #define HID_REPORT_INTERRUPT_DEASSERTED 0x00 -void UserReadHIDData( in port p_int, unsigned char hidData[ HID_DATA_SIZE ]) +static unsigned char s_hidData; + +void UserInitHIDData( void ) { - unsigned curr_val; + s_hidData = HID_REPORT_INTERRUPT_DEASSERTED; +} - p_int :> curr_val; +void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]) +{ + hidData[ 0 ] = s_hidData; - if( curr_val == NDP10X_ASSERT_LEVEL ) { - hidData[ 0 ] = HID_REPORT_INTERRUPT_ASSERTED; - } else { - hidData[ 0 ] = HID_REPORT_INTERRUPT_DEASSERTED; + for( unsigned i = 1; i < HID_DATA_SIZE; ++i ) { + hidData[ i ] = 0U; } +} - for( unsigned idx = 1; idx < HID_DATA_SIZE; ++idx ) { - hidData[ idx ] = 0U; +void UserSetHIDData( const unsigned hidData ) +{ + if( hidData == NDP10X_ASSERT_LEVEL ) { + s_hidData = HID_REPORT_INTERRUPT_ASSERTED; + } else { + s_hidData = HID_REPORT_INTERRUPT_DEASSERTED; } } From 0440020c2f2de5cf693e5cf5afead62e17b521c3 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 2 Oct 2019 15:24:28 +0100 Subject: [PATCH 084/123] Change pre-processor symbol names to make them generic. --- lib_xua/src/core/user/user_hid.h | 12 ++++++------ lib_xua/src/core/user/user_hid.xc | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index 24699c14..afcbb2e9 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -15,18 +15,18 @@ #define HID_SIMULATE_INTERRUPTS 0 #endif -#ifndef NDP_ASSERT_LEVEL -#define NDP_ASSERT_LEVEL 0 +#ifndef INTERRUPT_ASSERT_LEVEL +#define INTERRUPT_ASSERT_LEVEL 0 #endif #if( 0 < HID_CONTROLS ) #if( 0 < NDP_ASSERT_LEVEL ) -#define NDP10X_ASSERT_LEVEL 1 -#define NDP10X_DEASSERT_LEVEL 0 +#define INT_ASSERT_LEVEL 1 +#define INT_DEASSERT_LEVEL 0 #else -#define NDP10X_ASSERT_LEVEL 0 -#define NDP10X_DEASSERT_LEVEL 1 +#define INT_ASSERT_LEVEL 0 +#define INT_DEASSERT_LEVEL 1 #endif #if( 0 < HID_SIMULATE_INTERRUPTS ) diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc index dfba7fed..75cb8df6 100644 --- a/lib_xua/src/core/user/user_hid.xc +++ b/lib_xua/src/core/user/user_hid.xc @@ -26,7 +26,7 @@ void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]) void UserSetHIDData( const unsigned hidData ) { - if( hidData == NDP10X_ASSERT_LEVEL ) { + if( hidData == INT_ASSERT_LEVEL ) { s_hidData = HID_REPORT_INTERRUPT_ASSERTED; } else { s_hidData = HID_REPORT_INTERRUPT_DEASSERTED; From ce24c73dc0b85a35e84c45aa960e339c59d0936f Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 2 Oct 2019 16:51:46 +0100 Subject: [PATCH 085/123] Change pre-processor symbol names to make them generic. --- lib_xua/src/core/user/user_hid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index afcbb2e9..f0894d65 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -21,7 +21,7 @@ #if( 0 < HID_CONTROLS ) -#if( 0 < NDP_ASSERT_LEVEL ) +#if( 0 < INTERRUPT_ASSERT_LEVEL ) #define INT_ASSERT_LEVEL 1 #define INT_DEASSERT_LEVEL 0 #else From e7e8b58275f37337e01b31655c4a94fc4d79ac67 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 2 Oct 2019 16:54:38 +0100 Subject: [PATCH 086/123] Move user_hid.xc from lib_xua to the application (sw_xvf3510). --- lib_xua/src/core/user/user_hid.xc | 36 ------------------------------- 1 file changed, 36 deletions(-) delete mode 100644 lib_xua/src/core/user/user_hid.xc diff --git a/lib_xua/src/core/user/user_hid.xc b/lib_xua/src/core/user/user_hid.xc deleted file mode 100644 index 75cb8df6..00000000 --- a/lib_xua/src/core/user/user_hid.xc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2019, XMOS Ltd, All rights reserved -#include -#include -#include -#include "user_hid.h" - -#if( 0 < HID_CONTROLS ) -#define HID_REPORT_INTERRUPT_ASSERTED 0x01 -#define HID_REPORT_INTERRUPT_DEASSERTED 0x00 - -static unsigned char s_hidData; - -void UserInitHIDData( void ) -{ - s_hidData = HID_REPORT_INTERRUPT_DEASSERTED; -} - -void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]) -{ - hidData[ 0 ] = s_hidData; - - for( unsigned i = 1; i < HID_DATA_SIZE; ++i ) { - hidData[ i ] = 0U; - } -} - -void UserSetHIDData( const unsigned hidData ) -{ - if( hidData == INT_ASSERT_LEVEL ) { - s_hidData = HID_REPORT_INTERRUPT_ASSERTED; - } else { - s_hidData = HID_REPORT_INTERRUPT_DEASSERTED; - } -} - -#endif /* ( 0 < HID_CONTROLS ) */ From 74564edde86f186858f5f2d1633183d277d0b075 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 2 Oct 2019 16:55:42 +0100 Subject: [PATCH 087/123] Add HID trigger function. --- lib_xua/src/core/user/user_hid.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index f0894d65..687b2445 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -34,8 +34,9 @@ #define HID_INTERRUPT_COUNT 1000000000 #endif -void UserInitHIDData(void); -void UserReadHIDData(unsigned char hidData[ HID_DATA_SIZE ]); -void UserSetHIDData(const unsigned hidData); +select UserHIDTrigger( unsigned* hidValueLatched ); +void UserInitHIDData( void ); +void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]); +void UserSetHIDData( const unsigned hidData ); #endif /* ( 0 < HID_CONTROLS ) */ From 211a49f26fcbcf9c472ff35334fe85b043cca7f8 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 2 Oct 2019 16:57:42 +0100 Subject: [PATCH 088/123] Remove unnecessary port parameters passed through XUA Buffer (whether the traditional one or the Lite version). --- lib_xua/api/xua_buffer.h | 2 -- lib_xua/src/core/buffer/ep/ep_buffer.xc | 3 --- 2 files changed, 5 deletions(-) diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index 5e7f65e4..93ca3219 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -60,7 +60,6 @@ void XUA_Buffer( in port p_off_mclk #if( 0 < HID_CONTROLS ) , chanend c_hid - , in port p_int #endif , chanend c_aud ); @@ -100,7 +99,6 @@ void XUA_Buffer_Ep(chanend c_aud_out, in port p_off_mclk #if( 0 < HID_CONTROLS ) , chanend c_hid - , in port p_int #endif #ifdef CHAN_BUFF_CTRL , chanend c_buff_ctrl diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 53244092..5916da17 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -122,7 +122,6 @@ void XUA_Buffer( in port p_off_mclk #if( 0 < HID_CONTROLS ) , chanend c_hid - , in port p_int #endif , chanend c_aud ) @@ -167,7 +166,6 @@ void XUA_Buffer( c_sof, c_aud_ctl, p_off_mclk #if( 0 < HID_CONTROLS ) , c_hid - , p_int #endif #ifdef CHAN_BUFF_CTRL , c_buff_ctrl @@ -227,7 +225,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, in port p_off_mclk #if( 0 < HID_CONTROLS ) , chanend c_hid - , in port p_int #endif #ifdef CHAN_BUFF_CTRL , chanend c_buff_ctrl From 5b87efb5a770a4122d61a24f1f3b2b769b0d49b9 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 7 Oct 2019 12:35:23 +0100 Subject: [PATCH 089/123] Change the HID Report Descriptor to use the AC Search Usage instead of Voice Command. --- .../src/core/endpoint0/xua_ep0_descriptors.h | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index e6c56aa9..976daff8 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -548,6 +548,7 @@ unsigned char devQualDesc_Null[] = #if( 0 < HID_CONTROLS ) +#if 0 unsigned char hidReportDescriptor[] = { 0x05, 0x0c, /* Usage Page (Consumer Device) */ @@ -563,6 +564,26 @@ unsigned char hidReportDescriptor[] = 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ 0xc0 /* End collection */ }; +#else +unsigned char hidReportDescriptor[] = +{ + 0x15, 0x01, /* Logical Minimum (1) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x05, 0x0c, /* Usage Page (Consumer Device) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x0a, 0x00, 0x02, /* Usage (Generic GUI Application Controls) */ + 0xa1, 0x02, /* Collection (Logical) */ + 0x0a, 0x21, 0x02, /* Usage (AC Search) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x40, /* Input (Data, Ary, Abs, Nul) */ + 0x95, 0x07, /* Report Count (7) */ + 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ + 0xc0, /* End collection (Logical) */ + 0xc0 /* End collection (Application) */ +}; +#endif #endif /* Max packet sizes: @@ -2850,7 +2871,7 @@ unsigned char cfgDesc_Audio1[] = 0x00, /* 4 bCountryCode */ 0x01, /* 5 bNumDescriptors */ 0x22, /* 6 bDescriptorType[0] (Report) */ - 0x17, /* 7 wDescriptorLength[0] */ + 0x1E, /* 7 wDescriptorLength[0] */ 0x00, /* 8 wDescriptorLength[0] */ /* HID Endpoint descriptor (IN) */ From 34ebbc8509a4f4ae0ef8d167bf34e3f5d0814130 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 7 Oct 2019 12:35:23 +0100 Subject: [PATCH 090/123] Change the HID Report Descriptor to use the AC Search Usage instead of Voice Command. --- .../src/core/endpoint0/xua_ep0_descriptors.h | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index e6c56aa9..cf50c8eb 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -548,7 +548,8 @@ unsigned char devQualDesc_Null[] = #if( 0 < HID_CONTROLS ) -unsigned char hidReportDescriptor[] = +#if 0 +unsigned char hidReportDescriptor[] = /* Voice Command usage as per request #HUTRR45 */ { 0x05, 0x0c, /* Usage Page (Consumer Device) */ 0x09, 0x01, /* Usage (Consumer Control) */ @@ -563,6 +564,26 @@ unsigned char hidReportDescriptor[] = 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ 0xc0 /* End collection */ }; +#else +unsigned char hidReportDescriptor[] = /* GUI AC Search usage */ +{ + 0x15, 0x01, /* Logical Minimum (1) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x05, 0x0c, /* Usage Page (Consumer Device) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x0a, 0x00, 0x02, /* Usage (Generic GUI Application Controls) */ + 0xa1, 0x02, /* Collection (Logical) */ + 0x0a, 0x21, 0x02, /* Usage (AC Search) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x40, /* Input (Data, Ary, Abs, Nul) */ + 0x95, 0x07, /* Report Count (7) */ + 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ + 0xc0, /* End collection (Logical) */ + 0xc0 /* End collection (Application) */ +}; +#endif #endif /* Max packet sizes: @@ -2850,7 +2871,7 @@ unsigned char cfgDesc_Audio1[] = 0x00, /* 4 bCountryCode */ 0x01, /* 5 bNumDescriptors */ 0x22, /* 6 bDescriptorType[0] (Report) */ - 0x17, /* 7 wDescriptorLength[0] */ + 0x1E, /* 7 wDescriptorLength[0] */ 0x00, /* 8 wDescriptorLength[0] */ /* HID Endpoint descriptor (IN) */ From 75fea9ed84c5726f9a27b1ffccf5ecc929395a46 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 8 Oct 2019 13:44:04 +0100 Subject: [PATCH 091/123] Change the simulated interrupt pulse width from 100 us to 100 ms. --- lib_xua/src/core/user/user_hid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h index 687b2445..5688c7c6 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/user_hid.h @@ -30,7 +30,7 @@ #endif #if( 0 < HID_SIMULATE_INTERRUPTS ) -#define HID_DEASSERT_COUNT 10000 +#define HID_DEASSERT_COUNT 10000000 #define HID_INTERRUPT_COUNT 1000000000 #endif From 1690c4eff6adbbccdacb7819081d1087e3d9e684 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 8 Oct 2019 13:45:20 +0100 Subject: [PATCH 092/123] Remove the USB HID Report descriptor with the Voice Command Usage. This commit also contains a small amount of whitespace clean-up. --- .../src/core/endpoint0/xua_ep0_descriptors.h | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 976daff8..97685679 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -546,25 +546,7 @@ unsigned char devQualDesc_Null[] = #define MIXER_LENGTH (0) #endif - #if( 0 < HID_CONTROLS ) -#if 0 -unsigned char hidReportDescriptor[] = -{ - 0x05, 0x0c, /* Usage Page (Consumer Device) */ - 0x09, 0x01, /* Usage (Consumer Control) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x09, 0xcf, /* Usage (Voice Command), use 0xcd for (Play/Pause OSC) */ - 0x75, 0x01, /* Report Size (1) */ - 0x95, 0x01, /* Report Count (1) */ - 0x81, 0x06, /* Input (Data, Var, Rel) */ - 0x95, 0x07, /* Report Count (7) */ - 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ - 0xc0 /* End collection */ -}; -#else unsigned char hidReportDescriptor[] = { 0x15, 0x01, /* Logical Minimum (1) */ @@ -575,7 +557,7 @@ unsigned char hidReportDescriptor[] = 0xa1, 0x01, /* Collection (Application) */ 0x0a, 0x00, 0x02, /* Usage (Generic GUI Application Controls) */ 0xa1, 0x02, /* Collection (Logical) */ - 0x0a, 0x21, 0x02, /* Usage (AC Search) */ + 0x0a, 0x21, 0x02, /* Usage (AC Search) */ 0x95, 0x01, /* Report Count (1) */ 0x81, 0x40, /* Input (Data, Ary, Abs, Nul) */ 0x95, 0x07, /* Report Count (7) */ @@ -584,7 +566,6 @@ unsigned char hidReportDescriptor[] = 0xc0 /* End collection (Application) */ }; #endif -#endif /* Max packet sizes: * Samples per channel. e.g (192000+7999/8000) = 24 From 2a960700c5607a3c605ce1d144889a0ac57d1a5b Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 8 Oct 2019 13:54:16 +0100 Subject: [PATCH 093/123] Remove the duplicate USB HID Report Descriptor that Git, for some unknown reason, produced at the last merge. --- .../src/core/endpoint0/xua_ep0_descriptors.h | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 8bd24bb0..0c2c3eb5 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -547,7 +547,6 @@ unsigned char devQualDesc_Null[] = #endif #if( 0 < HID_CONTROLS ) -#if 0 unsigned char hidReportDescriptor[] = /* Voice Command usage as per request #HUTRR45 */ { 0x15, 0x01, /* Logical Minimum (1) */ @@ -566,26 +565,6 @@ unsigned char hidReportDescriptor[] = /* Voice Command usage as per request #HUT 0xc0, /* End collection (Logical) */ 0xc0 /* End collection (Application) */ }; -#else -unsigned char hidReportDescriptor[] = /* GUI AC Search usage */ -{ - 0x15, 0x01, /* Logical Minimum (1) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x75, 0x01, /* Report Size (1) */ - 0x05, 0x0c, /* Usage Page (Consumer Device) */ - 0x09, 0x01, /* Usage (Consumer Control) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x0a, 0x00, 0x02, /* Usage (Generic GUI Application Controls) */ - 0xa1, 0x02, /* Collection (Logical) */ - 0x0a, 0x21, 0x02, /* Usage (AC Search) */ - 0x95, 0x01, /* Report Count (1) */ - 0x81, 0x40, /* Input (Data, Ary, Abs, Nul) */ - 0x95, 0x07, /* Report Count (7) */ - 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ - 0xc0, /* End collection (Logical) */ - 0xc0 /* End collection (Application) */ -}; -#endif #endif /* Max packet sizes: From b592c943f8e4a7f7c881ffd0aaa8f05f5d082765 Mon Sep 17 00:00:00 2001 From: Larry Snizek Date: Tue, 8 Oct 2019 21:16:33 +0100 Subject: [PATCH 094/123] Set_Idle request handled (incomplete reports sent instead of NAK) --- lib_xua/src/core/endpoint0/xua_endpoint0.c | 12 +++++++++- lib_xua/src/hid/hid.xc | 26 ++++++++++++++++++++++ lib_xua/src/hid/xua_hid.h | 9 ++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 lib_xua/src/hid/hid.xc create mode 100644 lib_xua/src/hid/xua_hid.h diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index b5d1d8b7..c59886c6 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -60,6 +60,10 @@ extern void device_reboot(void); #endif +#if HID_CONTROLS +#include "xua_hid.h" +#endif + unsigned int DFU_mode_active = 0; // 0 - App active, 1 - DFU active /* Global volume and mute tables */ @@ -321,7 +325,6 @@ void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audi DFU_mode_active = 1; } #endif - } void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, @@ -989,12 +992,19 @@ void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend device_reboot(); } } +#endif +#if HID_CONTROLS + if (interfaceNum == INTERFACE_NUMBER_HID) + { + result = HidInterfaceClassRequests(ep0_out, ep0_in, &sp); + } #endif /* Check for: - Audio CONTROL interface request - always 0, note we check for DFU first * - Audio STREAMING interface request (In or Out) * - Audio endpoint request (Audio 1.0 Sampling freq requests are sent to the endpoint) */ if(((interfaceNum == 0) || (interfaceNum == 1) || (interfaceNum == 2)) + && result == XUD_RES_ERR #if (XUA_DFU_EN == 1) && !DFU_mode_active #endif diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc new file mode 100644 index 00000000..d7cda428 --- /dev/null +++ b/lib_xua/src/hid/hid.xc @@ -0,0 +1,26 @@ +#include +#include "xud.h" +#include "hid.h" +#include "xud_std_requests.h" +#include "xua_hid.h" + +static unsigned hidSetIdle = 0; + +unsigned HidIsSetIdleSilenced(void) +{ + return hidSetIdle; +} + +XUD_Result_t HidInterfaceClassRequests(XUD_ep c_ep0_out, XUD_ep c_ep0_in, + USB_SetupPacket_t &sp) +{ + switch (sp.bRequest) { + case HID_SET_IDLE: + printstrln("HID_SET_IDLE\n"); + hidSetIdle = 1; // TODO implement duration + return XUD_DoSetRequestStatus(c_ep0_in); + default: + break; + } + return XUD_RES_ERR; +} diff --git a/lib_xua/src/hid/xua_hid.h b/lib_xua/src/hid/xua_hid.h new file mode 100644 index 00000000..df89dc55 --- /dev/null +++ b/lib_xua/src/hid/xua_hid.h @@ -0,0 +1,9 @@ +#include +#include +#include "xud.h" +#include "xud_std_requests.h" + +XUD_Result_t HidInterfaceClassRequests(XUD_ep c_ep0_out, XUD_ep c_ep0_in, + REFERENCE_PARAM(USB_SetupPacket_t, sp)); + +unsigned HidIsSetIdleSilenced(void); From 8ba9a0064cb6d00d4e7fd74469b5329f84050cdb Mon Sep 17 00:00:00 2001 From: Larry Snizek Date: Wed, 9 Oct 2019 16:45:50 +0100 Subject: [PATCH 095/123] Cosmetic --- lib_xua/src/hid/hid.xc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index d7cda428..fd7cb32b 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -16,7 +16,7 @@ XUD_Result_t HidInterfaceClassRequests(XUD_ep c_ep0_out, XUD_ep c_ep0_in, { switch (sp.bRequest) { case HID_SET_IDLE: - printstrln("HID_SET_IDLE\n"); + printstr("HID_SET_IDLE\n"); hidSetIdle = 1; // TODO implement duration return XUD_DoSetRequestStatus(c_ep0_in); default: From 1808d7affac01baa37e203cd7d32aeb0607b3238 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Thu, 10 Oct 2019 17:21:21 +0100 Subject: [PATCH 096/123] Initial implementation of the USB HID Set_Idle Request. This code builds successfully. It has not been tested even a little. --- lib_xua/src/core/endpoint0/descriptor_defs.h | 4 + .../src/core/endpoint0/xua_ep0_descriptors.h | 4 +- lib_xua/src/hid/hid.xc | 196 ++++++++++++++++-- lib_xua/src/hid/xua_hid.h | 12 +- 4 files changed, 196 insertions(+), 20 deletions(-) diff --git a/lib_xua/src/core/endpoint0/descriptor_defs.h b/lib_xua/src/core/endpoint0/descriptor_defs.h index b348d6f1..53ba28ed 100644 --- a/lib_xua/src/core/endpoint0/descriptor_defs.h +++ b/lib_xua/src/core/endpoint0/descriptor_defs.h @@ -60,4 +60,8 @@ enum USBInterfaceNumber INTERFACE_COUNT /* End marker */ }; +#if( 0 < HID_CONTROLS ) +#define ENDPOINT_INT_INTERVAL_IN_HID 0x08 +#endif + #endif diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 0c2c3eb5..066319f4 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -2184,7 +2184,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */ 3, /* 3 bmAttributes (INTERRUPT) */ 64, /* 4 wMaxPacketSize */ - 8, /* 6 bInterval */ + ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */ } #endif @@ -2862,7 +2862,7 @@ unsigned char cfgDesc_Audio1[] = 0x03, /* 3 bmAttributes (INTERRUPT) */ 0x40, /* 4 wMaxPacketSize */ 0x00, /* 5 wMaxPacketSize */ - 0x08, /* 6 bInterval */ + ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */ #endif }; diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index fd7cb32b..1e92e283 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -1,26 +1,192 @@ #include -#include "xud.h" +#include "descriptor_defs.h" #include "hid.h" +#include "xud.h" #include "xud_std_requests.h" #include "xua_hid.h" -static unsigned hidSetIdle = 0; +#define MS_IN_TICKS 100000U -unsigned HidIsSetIdleSilenced(void) +static unsigned s_hidIdleActive = 0; +static unsigned s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; +static unsigned s_hidNextReportTime = 0; +static unsigned s_hidReportTime = 0; + +/** + * \brief Calculate the difference between two points in time + * + * This function calculates the difference between two two points in time. + * It always returns a positive value even if the timer used to obtain the two + * time measurements has wrapped around. + * + * \warning If time values have been obtained from a timer that has wrapped + * more than once in between the two measurements, this function returns an + * incorrect value. + * + * \param[in] earlierTime -- A value from a timer + * \param[in] laterTime -- A value from a timer taken after \a earlierTime + * + * \return The interval between the two points in time + */ +static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ) { - return hidSetIdle; + return ( earlierTime < laterTime ) ? laterTime - earlierTime : UINT_MAX - earlierTime + laterTime; } -XUD_Result_t HidInterfaceClassRequests(XUD_ep c_ep0_out, XUD_ep c_ep0_in, - USB_SetupPacket_t &sp) +/** + * \brief Calculate the time interval between the most recent HID Report and a subsequent Set Idle Request + * + * \warning For this function to produce an accurate interval measument, it must be called without delay + * upon receiving a Set Idle Request from the USB Host. + * + * \param[in] reportTime -- The time at which the last HID Report was sent + * + * \return The time interval between receiving the Set Idle Request and sending the most recent HID Report + */ +static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ) { - switch (sp.bRequest) { - case HID_SET_IDLE: - printstr("HID_SET_IDLE\n"); - hidSetIdle = 1; // TODO implement duration - return XUD_DoSetRequestStatus(c_ep0_in); - default: - break; - } - return XUD_RES_ERR; + timer tmr; + unsigned setIdleTime; + + tmr :> setIdleTime; + unsigned result = HidTimeDiff( reportTime, setIdleTime ); + return result; +} + +/** + * \brief Indicate if activation of the Set Idle Request happens at the previous or next HID Report + * + * Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human Interface + * Devices (HID) Version 1.11 makes two statements about the activation point for starting the + * duration of the request: + * - 'A new request will be executed as if it were issued immediately after the last report, if + * the new request is received at least 4 milliseconds before the end of the currently executing + * period.' + * - 'If the new request is received within 4 milliseconds of the end of the current period, then + * the new request will have no effect until after the report.' + * + * \param[in] currentPeriod -- The duration of the current period + * \param[in] timeWithinPeriod -- The current point in time relative to the current period + * + * \return A Boolean indicating where the activation of the Set Idle Request Duration occurs. + * \retval 1 -- Activate immediately after the next HID Report + * \retval 0 -- Activate immediately after the previous HID Report + */ +static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ) +{ + unsigned result = (( currentPeriod - timeWithinPeriod ) < ( 4U * MS_IN_TICKS )) ? 1 : 0; + + return result; +} + +/** + * \brief Calculate the timer value for sending the next HID Report. + * + * With regard to Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human + * Interface Devices (HID) Version 1.11, I've interpreted 'currently executing period' and + * 'current period' to mean the previously established Set Idle duration if one has been + * established or the polling interval from the HID Report Descriptor if a Set Idle duration + * has not been established. + * + * \param[in] currentPeriod -- The duration of the current period in timer ticks + * \param[in] reportTime -- The time at which the last HID Report was sent + * \param[in] reportToSetIdleInterval -- The time interval between receiving the Set Idle Request + * and sending the most recent HID Report + * \param[in] nextPeriod -- The new period value in timer ticks + * + * \return The time at which the next HID Report should be sent + */ +static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned nextPeriod ) +{ + unsigned nextReportTime = 0; + + if( HidFindSetIdleActivationPoint( currentPeriod, reportToSetIdleInterval )) { + /* Activate immediately after sending the next HID Report */ + nextReportTime = reportTime + currentPeriod; + } else { + /* Activate immediately after sending the most recent HID Report */ + nextReportTime = reportTime + nextPeriod; + } + + return nextReportTime; +} + +void HidCalcNextReportTime( void ) +{ + s_hidNextReportTime = s_hidReportTime + s_hidCurrentPeriod; +} + +void HidCaptureReportTime( void ) +{ + timer tmr; + tmr :> s_hidReportTime; +} + +XUD_Result_t HidInterfaceClassRequests( + XUD_ep c_ep0_out, + XUD_ep c_ep0_in, + USB_SetupPacket_t &sp ) +{ + XUD_Result_t result = XUD_RES_ERR; + + switch ( sp.bRequest ) { + case HID_SET_IDLE: + printstr("HID_SET_IDLE\n"); + /* + The Set Idle request wValue field contains two sub-fields: + - Duration in the MSB; and + - Report ID in the LSB. + + The Duration field specifies how long the USB Device responds with NAK provided the HID data hasn't changed. + Zero means indefinitely. + The value is in units of 4ms. + + The Report ID identifies the HID report that the USB Host wishes to silence. + + The Set Idle request xIndex field contains the interface number. + */ + uint8_t duration = ( sp.wValue & 0xFF00 ) >> 6; // Transform into units of 1ms. + uint8_t reportId = sp.wValue & 0x00FF; + uint16_t interfaceNum = ( sp.wIndex & 0xFF00 ) >> 8; + + /* + As long as our HID Report Descriptor does not include a Report ID, any Report ID value other than zero + indicates an error by the USB Host (see xua_ep0_descriptors.h for the definition of the HID + Report Descriptor). + + Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host. + */ + if(( 0U == reportId ) && ( interfaceNum == INTERFACE_NUMBER_HID )) { + s_hidIdleActive = !(( 0 < duration ) && ( duration < ENDPOINT_INT_INTERVAL_IN_HID )); + + if( s_hidIdleActive ) { + unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( s_hidReportTime ); + s_hidNextReportTime = HidCalcNewReportTime( s_hidCurrentPeriod, s_hidReportTime, reportToSetIdleInterval, duration * MS_IN_TICKS ); + s_hidCurrentPeriod = duration * MS_IN_TICKS; + } else { + s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; + } + + result = XUD_DoSetRequestStatus( c_ep0_in ); + } + break; + + default: + break; + } + + return result; +} + +unsigned HidIsSetIdleSilenced( void ) +{ + unsigned isSilenced = s_hidIdleActive; + + if( s_hidIdleActive ) { + unsigned currentTime; + asm volatile( "gettime %0" : "=r" ( currentTime )); // Use inline assembly to access the time without creating a side-effect + isSilenced = timeafter( s_hidNextReportTime, currentTime ); + } + + return isSilenced; } diff --git a/lib_xua/src/hid/xua_hid.h b/lib_xua/src/hid/xua_hid.h index df89dc55..c3dfcc66 100644 --- a/lib_xua/src/hid/xua_hid.h +++ b/lib_xua/src/hid/xua_hid.h @@ -3,7 +3,13 @@ #include "xud.h" #include "xud_std_requests.h" -XUD_Result_t HidInterfaceClassRequests(XUD_ep c_ep0_out, XUD_ep c_ep0_in, - REFERENCE_PARAM(USB_SetupPacket_t, sp)); +void HidCalcNextReportTime( void ); -unsigned HidIsSetIdleSilenced(void); +void HidCaptureReportTime( void ); + +XUD_Result_t HidInterfaceClassRequests( + XUD_ep c_ep0_out, + XUD_ep c_ep0_in, + REFERENCE_PARAM( USB_SetupPacket_t, sp )); + +unsigned HidIsSetIdleSilenced( void ); From 9f98e13342b2b4fb4bfe19da9da3e0e8df7bc9e2 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 14 Oct 2019 16:42:34 +0100 Subject: [PATCH 097/123] Use the HID_CONTROLS pre-processor symbol consistently. --- lib_xua/src/core/endpoint0/xua_endpoint0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index c59886c6..7b42909b 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -60,7 +60,7 @@ extern void device_reboot(void); #endif -#if HID_CONTROLS +#if( 0 < HID_CONTROLS ) #include "xua_hid.h" #endif @@ -993,7 +993,7 @@ void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend } } #endif -#if HID_CONTROLS +#if( 0 < HID_CONTROLS ) if (interfaceNum == INTERFACE_NUMBER_HID) { result = HidInterfaceClassRequests(ep0_out, ep0_in, &sp); From 962e91adeca2238307e5e30eb2c71512754fb24b Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 14 Oct 2019 16:47:59 +0100 Subject: [PATCH 098/123] Include xua.h to pick up the NUM_USB_CHAN_IN and NUM_USB_CHAN_OUT pre-processor symbols. They're used further down in the file. If not present through an #include of xua_h outside of and before the #include of descriptor_defs.h or through definition in the Make file, the enumeration of interface numbers silently mis-assigns values. --- lib_xua/src/core/endpoint0/descriptor_defs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib_xua/src/core/endpoint0/descriptor_defs.h b/lib_xua/src/core/endpoint0/descriptor_defs.h index 53ba28ed..1f29d58e 100644 --- a/lib_xua/src/core/endpoint0/descriptor_defs.h +++ b/lib_xua/src/core/endpoint0/descriptor_defs.h @@ -3,6 +3,11 @@ #ifndef __DESCRIPTOR_DEFS_H__ #define __DESCRIPTOR_DEFS_H__ +/* + Include xua.h to pick up the #defines of NUM_USB_CHAN_IN and NUM_USB_CHAN_OUT. + */ +#include "xua.h" + #if (NUM_USB_CHAN_IN > 0) && (NUM_USB_CHAN_OUT > 0) #define AUDIO_INTERFACE_COUNT 3 #elif (NUM_USB_CHAN_IN > 0) || (NUM_USB_CHAN_OUT > 0) From 97e32331203f7f590d8ae33f80d2df691a724d22 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 15 Oct 2019 10:42:33 +0100 Subject: [PATCH 099/123] Rename parameter to a less ambiguous name. --- lib_xua/src/hid/hid.xc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index 1e92e283..972158ff 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -92,11 +92,11 @@ static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, con * \param[in] reportTime -- The time at which the last HID Report was sent * \param[in] reportToSetIdleInterval -- The time interval between receiving the Set Idle Request * and sending the most recent HID Report - * \param[in] nextPeriod -- The new period value in timer ticks + * \param[in] newPeriod -- The new period value in timer ticks * * \return The time at which the next HID Report should be sent */ -static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned nextPeriod ) +static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ) { unsigned nextReportTime = 0; @@ -105,7 +105,7 @@ static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsign nextReportTime = reportTime + currentPeriod; } else { /* Activate immediately after sending the most recent HID Report */ - nextReportTime = reportTime + nextPeriod; + nextReportTime = reportTime + newPeriod; } return nextReportTime; From aeb1d58bf347bed3008dbd76d76ce1720fcc6608 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 15 Oct 2019 10:44:34 +0100 Subject: [PATCH 100/123] The interface number occupies the entire sp.wIndex field. --- lib_xua/src/hid/hid.xc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index 972158ff..0152b071 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -147,7 +147,7 @@ XUD_Result_t HidInterfaceClassRequests( */ uint8_t duration = ( sp.wValue & 0xFF00 ) >> 6; // Transform into units of 1ms. uint8_t reportId = sp.wValue & 0x00FF; - uint16_t interfaceNum = ( sp.wIndex & 0xFF00 ) >> 8; + uint16_t interfaceNum = sp.wIndex; /* As long as our HID Report Descriptor does not include a Report ID, any Report ID value other than zero From 3331c9e97bc168753b97a48bb04ed41aad421b8f Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 15 Oct 2019 10:45:20 +0100 Subject: [PATCH 101/123] Add handling for an indefinite duration. --- lib_xua/src/hid/hid.xc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index 0152b071..794e244b 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -9,6 +9,7 @@ static unsigned s_hidIdleActive = 0; static unsigned s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; +static unsigned s_hidIndefiniteDuration = 0; static unsigned s_hidNextReportTime = 0; static unsigned s_hidReportTime = 0; @@ -163,8 +164,10 @@ XUD_Result_t HidInterfaceClassRequests( unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( s_hidReportTime ); s_hidNextReportTime = HidCalcNewReportTime( s_hidCurrentPeriod, s_hidReportTime, reportToSetIdleInterval, duration * MS_IN_TICKS ); s_hidCurrentPeriod = duration * MS_IN_TICKS; + s_hidIndefiniteDuration = ( 0U == duration ); } else { s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; + s_hidIndefiniteDuration = 0; } result = XUD_DoSetRequestStatus( c_ep0_in ); @@ -185,7 +188,7 @@ unsigned HidIsSetIdleSilenced( void ) if( s_hidIdleActive ) { unsigned currentTime; asm volatile( "gettime %0" : "=r" ( currentTime )); // Use inline assembly to access the time without creating a side-effect - isSilenced = timeafter( s_hidNextReportTime, currentTime ); + isSilenced = ( s_hidIndefiniteDuration || ( timeafter( s_hidNextReportTime, currentTime ))); } return isSilenced; From e4f0b73a88928bc004dcdc029722930298e5fb59 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 15 Oct 2019 15:38:16 +0100 Subject: [PATCH 102/123] Explicitly label assignment of zero as unsigned when used with unsigned variables. --- lib_xua/src/hid/hid.xc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index 794e244b..88ced493 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -7,11 +7,11 @@ #define MS_IN_TICKS 100000U -static unsigned s_hidIdleActive = 0; +static unsigned s_hidIdleActive = 0U; static unsigned s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; -static unsigned s_hidIndefiniteDuration = 0; -static unsigned s_hidNextReportTime = 0; -static unsigned s_hidReportTime = 0; +static unsigned s_hidIndefiniteDuration = 0U; +static unsigned s_hidNextReportTime = 0U; +static unsigned s_hidReportTime = 0U; /** * \brief Calculate the difference between two points in time @@ -167,7 +167,7 @@ XUD_Result_t HidInterfaceClassRequests( s_hidIndefiniteDuration = ( 0U == duration ); } else { s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; - s_hidIndefiniteDuration = 0; + s_hidIndefiniteDuration = 0U; } result = XUD_DoSetRequestStatus( c_ep0_in ); From a5f17c46fc3d7a22b2a547236aa576e4326b934c Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 15 Oct 2019 15:39:14 +0100 Subject: [PATCH 103/123] Use a variable large enough to hold the Set Idle duration in ms without overflow. --- lib_xua/src/hid/hid.xc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index 88ced493..40014575 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -146,7 +146,7 @@ XUD_Result_t HidInterfaceClassRequests( The Set Idle request xIndex field contains the interface number. */ - uint8_t duration = ( sp.wValue & 0xFF00 ) >> 6; // Transform into units of 1ms. + uint16_t duration = ( sp.wValue & 0xFF00 ) >> 6; // Transform from units of 4ms into units of 1ms. uint8_t reportId = sp.wValue & 0x00FF; uint16_t interfaceNum = sp.wIndex; From 5caca37177cfc34e88f1b903f196dcbc9ff3f705 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 15 Oct 2019 15:40:26 +0100 Subject: [PATCH 104/123] Change the representation, but not the logic, of a multi-part conditional expression to make it easier to understand. --- lib_xua/src/hid/hid.xc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index 40014575..cee8d49a 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -158,7 +158,7 @@ XUD_Result_t HidInterfaceClassRequests( Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host. */ if(( 0U == reportId ) && ( interfaceNum == INTERFACE_NUMBER_HID )) { - s_hidIdleActive = !(( 0 < duration ) && ( duration < ENDPOINT_INT_INTERVAL_IN_HID )); + s_hidIdleActive = (( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration )); if( s_hidIdleActive ) { unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( s_hidReportTime ); From 6afb4ab7e452175791ec43ec2f78a8cd5bd31d29 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 15 Oct 2019 15:43:05 +0100 Subject: [PATCH 105/123] Remove debugging print. --- lib_xua/src/hid/hid.xc | 1 - 1 file changed, 1 deletion(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index cee8d49a..606349b2 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -132,7 +132,6 @@ XUD_Result_t HidInterfaceClassRequests( switch ( sp.bRequest ) { case HID_SET_IDLE: - printstr("HID_SET_IDLE\n"); /* The Set Idle request wValue field contains two sub-fields: - Duration in the MSB; and From 8820ddf2699e9635f03f5e45f9b7f157bc2dd863 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 16 Oct 2019 11:37:27 +0100 Subject: [PATCH 106/123] Add documentation. --- lib_xua/src/hid/xua_hid.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib_xua/src/hid/xua_hid.h b/lib_xua/src/hid/xua_hid.h index c3dfcc66..ab8b2e05 100644 --- a/lib_xua/src/hid/xua_hid.h +++ b/lib_xua/src/hid/xua_hid.h @@ -3,8 +3,31 @@ #include "xud.h" #include "xud_std_requests.h" +/** + * \brief Calculate the next time to respond with a HID Report. + * + * If the USB Host has previously sent a valid HID Set_Idle request with + * a duration of zero or greater than the default reporting interval, + * the device sends HID Reports periodically or when the value of the + * payload has changed. + * + * This function calculates the time for sending the next periodic + * HID Report. + */ void HidCalcNextReportTime( void ); +/** + * \brief Capture the time of sending the current HID Report. + * + * If the USB Host has previously sent a valid HID Set_Idle request with + * a duration of zero or greater than the default reporting interval, + * the device sends HID Reports periodically or when the value of the + * payload has changed. + * + * This function captures the time when the HID Report was sent so that + * a subsequent call to HidCalNextReportTime() can calculate the time + * to send the next periodic HID Report. + */ void HidCaptureReportTime( void ); XUD_Result_t HidInterfaceClassRequests( @@ -12,4 +35,20 @@ XUD_Result_t HidInterfaceClassRequests( XUD_ep c_ep0_in, REFERENCE_PARAM( USB_SetupPacket_t, sp )); +/** + * \brief Indicate whether to send a HID Report based on elapsed time. + * + * If the USB Host has previously sent a valid HID Set_Idle request with + * a duration of zero or greater than the default reporting interval, + * the device sends HID Reports periodically or when the value of the + * payload has changed. + * + * This function monitors the passage of time and reports to the caller + * whether or not the time to send the next periodic HID Report has + * elapsed. + * + * \return A Boolean value indicating whether or not to send the HID Report. + * \retval 1 -- Do not send the HID Report + * \retval 0 -- Send the HID Report + */ unsigned HidIsSetIdleSilenced( void ); From 9a7c2d85b20ff9f76ea25935e8f528e767c5351c Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 16 Oct 2019 11:47:32 +0100 Subject: [PATCH 107/123] Reorganise file layout for easier maintenance and reading. --- lib_xua/src/hid/hid.xc | 201 +++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 98 deletions(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index 606349b2..da4f5c78 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -13,104 +13,10 @@ static unsigned s_hidIndefiniteDuration = 0U; static unsigned s_hidNextReportTime = 0U; static unsigned s_hidReportTime = 0U; -/** - * \brief Calculate the difference between two points in time - * - * This function calculates the difference between two two points in time. - * It always returns a positive value even if the timer used to obtain the two - * time measurements has wrapped around. - * - * \warning If time values have been obtained from a timer that has wrapped - * more than once in between the two measurements, this function returns an - * incorrect value. - * - * \param[in] earlierTime -- A value from a timer - * \param[in] laterTime -- A value from a timer taken after \a earlierTime - * - * \return The interval between the two points in time - */ -static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ) -{ - return ( earlierTime < laterTime ) ? laterTime - earlierTime : UINT_MAX - earlierTime + laterTime; -} - -/** - * \brief Calculate the time interval between the most recent HID Report and a subsequent Set Idle Request - * - * \warning For this function to produce an accurate interval measument, it must be called without delay - * upon receiving a Set Idle Request from the USB Host. - * - * \param[in] reportTime -- The time at which the last HID Report was sent - * - * \return The time interval between receiving the Set Idle Request and sending the most recent HID Report - */ -static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ) -{ - timer tmr; - unsigned setIdleTime; - - tmr :> setIdleTime; - unsigned result = HidTimeDiff( reportTime, setIdleTime ); - return result; -} - -/** - * \brief Indicate if activation of the Set Idle Request happens at the previous or next HID Report - * - * Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human Interface - * Devices (HID) Version 1.11 makes two statements about the activation point for starting the - * duration of the request: - * - 'A new request will be executed as if it were issued immediately after the last report, if - * the new request is received at least 4 milliseconds before the end of the currently executing - * period.' - * - 'If the new request is received within 4 milliseconds of the end of the current period, then - * the new request will have no effect until after the report.' - * - * \param[in] currentPeriod -- The duration of the current period - * \param[in] timeWithinPeriod -- The current point in time relative to the current period - * - * \return A Boolean indicating where the activation of the Set Idle Request Duration occurs. - * \retval 1 -- Activate immediately after the next HID Report - * \retval 0 -- Activate immediately after the previous HID Report - */ -static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ) -{ - unsigned result = (( currentPeriod - timeWithinPeriod ) < ( 4U * MS_IN_TICKS )) ? 1 : 0; - - return result; -} - -/** - * \brief Calculate the timer value for sending the next HID Report. - * - * With regard to Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human - * Interface Devices (HID) Version 1.11, I've interpreted 'currently executing period' and - * 'current period' to mean the previously established Set Idle duration if one has been - * established or the polling interval from the HID Report Descriptor if a Set Idle duration - * has not been established. - * - * \param[in] currentPeriod -- The duration of the current period in timer ticks - * \param[in] reportTime -- The time at which the last HID Report was sent - * \param[in] reportToSetIdleInterval -- The time interval between receiving the Set Idle Request - * and sending the most recent HID Report - * \param[in] newPeriod -- The new period value in timer ticks - * - * \return The time at which the next HID Report should be sent - */ -static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ) -{ - unsigned nextReportTime = 0; - - if( HidFindSetIdleActivationPoint( currentPeriod, reportToSetIdleInterval )) { - /* Activate immediately after sending the next HID Report */ - nextReportTime = reportTime + currentPeriod; - } else { - /* Activate immediately after sending the most recent HID Report */ - nextReportTime = reportTime + newPeriod; - } - - return nextReportTime; -} +static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ); +static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ); +static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ); +static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ); void HidCalcNextReportTime( void ) { @@ -192,3 +98,102 @@ unsigned HidIsSetIdleSilenced( void ) return isSilenced; } + +/** + * \brief Calculate the timer value for sending the next HID Report. + * + * With regard to Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human + * Interface Devices (HID) Version 1.11, I've interpreted 'currently executing period' and + * 'current period' to mean the previously established Set Idle duration if one has been + * established or the polling interval from the HID Report Descriptor if a Set Idle duration + * has not been established. + * + * \param[in] currentPeriod -- The duration of the current period in timer ticks + * \param[in] reportTime -- The time at which the last HID Report was sent + * \param[in] reportToSetIdleInterval -- The time interval between receiving the Set Idle Request + * and sending the most recent HID Report + * \param[in] newPeriod -- The new period value in timer ticks + * + * \return The time at which the next HID Report should be sent + */ +static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ) +{ + unsigned nextReportTime = 0; + + if( HidFindSetIdleActivationPoint( currentPeriod, reportToSetIdleInterval )) { + /* Activate immediately after sending the next HID Report */ + nextReportTime = reportTime + currentPeriod; + } else { + /* Activate immediately after sending the most recent HID Report */ + nextReportTime = reportTime + newPeriod; + } + + return nextReportTime; +} + +/** + * \brief Calculate the time interval between the most recent HID Report and a subsequent Set Idle Request + * + * \warning For this function to produce an accurate interval measument, it must be called without delay + * upon receiving a Set Idle Request from the USB Host. + * + * \param[in] reportTime -- The time at which the last HID Report was sent + * + * \return The time interval between receiving the Set Idle Request and sending the most recent HID Report + */ +static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ) +{ + timer tmr; + unsigned setIdleTime; + + tmr :> setIdleTime; + unsigned result = HidTimeDiff( reportTime, setIdleTime ); + return result; +} + +/** + * \brief Indicate if activation of the Set Idle Request happens at the previous or next HID Report + * + * Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human Interface + * Devices (HID) Version 1.11 makes two statements about the activation point for starting the + * duration of the request: + * - 'A new request will be executed as if it were issued immediately after the last report, if + * the new request is received at least 4 milliseconds before the end of the currently executing + * period.' + * - 'If the new request is received within 4 milliseconds of the end of the current period, then + * the new request will have no effect until after the report.' + * + * \param[in] currentPeriod -- The duration of the current period + * \param[in] timeWithinPeriod -- The current point in time relative to the current period + * + * \return A Boolean indicating where the activation of the Set Idle Request Duration occurs. + * \retval 1 -- Activate immediately after the next HID Report + * \retval 0 -- Activate immediately after the previous HID Report + */ +static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ) +{ + unsigned result = (( currentPeriod - timeWithinPeriod ) < ( 4U * MS_IN_TICKS )) ? 1 : 0; + + return result; +} + +/** + * \brief Calculate the difference between two points in time + * + * This function calculates the difference between two two points in time. + * It always returns a positive value even if the timer used to obtain the two + * time measurements has wrapped around. + * + * \warning If time values have been obtained from a timer that has wrapped + * more than once in between the two measurements, this function returns an + * incorrect value. + * + * \param[in] earlierTime -- A value from a timer + * \param[in] laterTime -- A value from a timer taken after \a earlierTime + * + * \return The interval between the two points in time + */ +static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ) +{ + return ( earlierTime < laterTime ) ? laterTime - earlierTime : UINT_MAX - earlierTime + laterTime; +} From 21ec3cf7bdb7169733634342a628263387714f86 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 16 Oct 2019 12:18:50 +0100 Subject: [PATCH 108/123] Put the processing of the Set Idle request in a static function. This reorganisation prepares this file for adding other HID Class-specific requests without the --- lib_xua/src/hid/hid.xc | 105 ++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index da4f5c78..dd988f9c 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -13,10 +13,11 @@ static unsigned s_hidIndefiniteDuration = 0U; static unsigned s_hidNextReportTime = 0U; static unsigned s_hidReportTime = 0U; -static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ); -static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ); -static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ); -static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ); +static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ); +static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ); +static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ); +static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t &sp ); +static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ); void HidCalcNextReportTime( void ) { @@ -38,45 +39,7 @@ XUD_Result_t HidInterfaceClassRequests( switch ( sp.bRequest ) { case HID_SET_IDLE: - /* - The Set Idle request wValue field contains two sub-fields: - - Duration in the MSB; and - - Report ID in the LSB. - - The Duration field specifies how long the USB Device responds with NAK provided the HID data hasn't changed. - Zero means indefinitely. - The value is in units of 4ms. - - The Report ID identifies the HID report that the USB Host wishes to silence. - - The Set Idle request xIndex field contains the interface number. - */ - uint16_t duration = ( sp.wValue & 0xFF00 ) >> 6; // Transform from units of 4ms into units of 1ms. - uint8_t reportId = sp.wValue & 0x00FF; - uint16_t interfaceNum = sp.wIndex; - - /* - As long as our HID Report Descriptor does not include a Report ID, any Report ID value other than zero - indicates an error by the USB Host (see xua_ep0_descriptors.h for the definition of the HID - Report Descriptor). - - Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host. - */ - if(( 0U == reportId ) && ( interfaceNum == INTERFACE_NUMBER_HID )) { - s_hidIdleActive = (( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration )); - - if( s_hidIdleActive ) { - unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( s_hidReportTime ); - s_hidNextReportTime = HidCalcNewReportTime( s_hidCurrentPeriod, s_hidReportTime, reportToSetIdleInterval, duration * MS_IN_TICKS ); - s_hidCurrentPeriod = duration * MS_IN_TICKS; - s_hidIndefiniteDuration = ( 0U == duration ); - } else { - s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; - s_hidIndefiniteDuration = 0U; - } - - result = XUD_DoSetRequestStatus( c_ep0_in ); - } + result = HidProcessSetIdleRequest( c_ep0_out, c_ep0_in, sp ); break; default: @@ -177,6 +140,62 @@ static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, con return result; } +/** + * \brief Process a Set Idle request + * + * \param[in] c_ep0_out -- the channel that carries data from Endpoint 0 + * \param[in] c_ep0_in -- the channel that carries data for Endpoint 0 + * \param[in] sp -- a structure containing the Set Idle data + * + * \return An XUD status value + */ +static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t &sp ) +{ + XUD_Result_t result = XUD_RES_ERR; + + /* + The Set Idle request wValue field contains two sub-fields: + - Duration in the MSB; and + - Report ID in the LSB. + + The Duration field specifies how long the USB Device responds with NAK provided the HID data hasn't changed. + Zero means indefinitely. + The value is in units of 4ms. + + The Report ID identifies the HID report that the USB Host wishes to silence. + + The Set Idle request xIndex field contains the interface number. + */ + uint16_t duration = ( sp.wValue & 0xFF00 ) >> 6; // Transform from units of 4ms into units of 1ms. + uint8_t reportId = sp.wValue & 0x00FF; + uint16_t interfaceNum = sp.wIndex; + + /* + As long as our HID Report Descriptor does not include a Report ID, any Report ID value other than zero + indicates an error by the USB Host (see xua_ep0_descriptors.h for the definition of the HID + Report Descriptor). + + Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host. + */ + if(( 0U == reportId ) && ( interfaceNum == INTERFACE_NUMBER_HID )) { + s_hidIdleActive = (( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration )); + + if( s_hidIdleActive ) { + unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( s_hidReportTime ); + s_hidNextReportTime = HidCalcNewReportTime( s_hidCurrentPeriod, s_hidReportTime, reportToSetIdleInterval, duration * MS_IN_TICKS ); + s_hidCurrentPeriod = duration * MS_IN_TICKS; + s_hidIndefiniteDuration = ( 0U == duration ); + } else { + s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; + s_hidIndefiniteDuration = 0U; + } + + result = XUD_DoSetRequestStatus( c_ep0_in ); + } + + return result; +} + /** * \brief Calculate the difference between two points in time * From 024c0304f1008a49f628ac8c4139ce56e1855c63 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 16 Oct 2019 14:57:33 +0100 Subject: [PATCH 109/123] Reverse the order of operands in an equals comparison to allow the compiler to catch a mistaken use of '=' instead of '=='. --- lib_xua/src/hid/hid.xc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index dd988f9c..72a4fea6 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -177,7 +177,7 @@ static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host. */ - if(( 0U == reportId ) && ( interfaceNum == INTERFACE_NUMBER_HID )) { + if(( 0U == reportId ) && ( INTERFACE_NUMBER_HID == interfaceNum )) { s_hidIdleActive = (( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration )); if( s_hidIdleActive ) { From a7c0ac623420344d20b919ad0d93a9d8efb6934b Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 16 Oct 2019 15:58:06 +0100 Subject: [PATCH 110/123] Protect configurations that do not include HID functionality from HID code. --- lib_xua/src/hid/hid.xc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index 72a4fea6..bdd5aef3 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -5,6 +5,7 @@ #include "xud_std_requests.h" #include "xua_hid.h" +#if( 0 < HID_CONTROLS ) #define MS_IN_TICKS 100000U static unsigned s_hidIdleActive = 0U; @@ -216,3 +217,5 @@ static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTim { return ( earlierTime < laterTime ) ? laterTime - earlierTime : UINT_MAX - earlierTime + laterTime; } + +#endif /* ( 0 < HID_CONTROLS ) */ From a6f3daf5817d6ff3da694086fa511dd52620e4a2 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 16 Oct 2019 16:03:52 +0100 Subject: [PATCH 111/123] Update change log. --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 35c363bc..e3d99159 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,7 @@ lib_xua Change Log ---------- * ADDED: UAC1 HID support with simulated Voice Command detection reported every 10 seconds + * ADDED: Support for USB HID Set Idle request 0.2.0 ----- From 102d1b4e3abe880f67263d55369620cf13862099 Mon Sep 17 00:00:00 2001 From: Larry Snizek Date: Wed, 23 Oct 2019 14:26:49 +0100 Subject: [PATCH 112/123] Tidy up HID --- lib_xua/module_build_info | 2 +- lib_xua/src/core/user/{ => hid}/user_hid.h | 25 +--------------------- 2 files changed, 2 insertions(+), 25 deletions(-) rename lib_xua/src/core/user/{ => hid}/user_hid.h (50%) diff --git a/lib_xua/module_build_info b/lib_xua/module_build_info index f13abe6b..be92c565 100644 --- a/lib_xua/module_build_info +++ b/lib_xua/module_build_info @@ -17,7 +17,7 @@ VERSION = 0.2.0 DEPENDENT_MODULES = lib_logging(>=2.1.0) lib_xassert(>=2.0.0) lib_xud(>=0.1.0) lib_spdif(>=3.0.0) -INCLUDE_DIRS = api src/* src/core/user +INCLUDE_DIRS = api src/* src/core/* src/core/user/hid #ignore host dir SOURCE_DIRS = src/* diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/hid/user_hid.h similarity index 50% rename from lib_xua/src/core/user/user_hid.h rename to lib_xua/src/core/user/hid/user_hid.h index 5688c7c6..88165b2a 100644 --- a/lib_xua/src/core/user/user_hid.h +++ b/lib_xua/src/core/user/hid/user_hid.h @@ -1,5 +1,4 @@ -// Copyright (c) 2013-2018, XMOS Ltd, All rights reserved - +// Copyright (c) 2013-2019, XMOS Ltd, All rights reserved /* These defines relate to the HID report desc - do not mod */ #define HID_CONTROL_PLAYPAUSE_SHIFT 0x00 @@ -11,30 +10,8 @@ #define HID_DATA_SIZE 1 -#ifndef HID_SIMULATE_INTERRUPTS -#define HID_SIMULATE_INTERRUPTS 0 -#endif - -#ifndef INTERRUPT_ASSERT_LEVEL -#define INTERRUPT_ASSERT_LEVEL 0 -#endif - #if( 0 < HID_CONTROLS ) -#if( 0 < INTERRUPT_ASSERT_LEVEL ) -#define INT_ASSERT_LEVEL 1 -#define INT_DEASSERT_LEVEL 0 -#else -#define INT_ASSERT_LEVEL 0 -#define INT_DEASSERT_LEVEL 1 -#endif - -#if( 0 < HID_SIMULATE_INTERRUPTS ) -#define HID_DEASSERT_COUNT 10000000 -#define HID_INTERRUPT_COUNT 1000000000 -#endif - -select UserHIDTrigger( unsigned* hidValueLatched ); void UserInitHIDData( void ); void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]); void UserSetHIDData( const unsigned hidData ); From 75abc71cd78995c0563ce22bb8683f418c7a6986 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Tue, 29 Oct 2019 16:45:03 +0000 Subject: [PATCH 113/123] Cleaning up a previous merge conflict. --- lib_xua/src/core/endpoint0/xua_endpoint0.c | 71 ++++++++++------------ 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index 0f7f766f..4a4e8882 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -439,55 +439,48 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 } #if (NUM_USB_CHAN_OUT > 0) && (NUM_USB_CHAN_IN > 0) + unsigned num_input_interfaces = g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]; + unsigned num_output_interfaces = g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT]; + if (sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT) { - unsigned num_input_interfaces = g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]; - unsigned num_output_interfaces = g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT]; - if (sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT) + // in: 0 -> 1 + if (sp.wValue && !num_input_interfaces) { - // in: 0 -> 1 - if (sp.wValue && !num_input_interfaces) + UserAudioInputStreamStart(); + if (!num_output_interfaces) { - UserAudioInputStreamStart(); - if (!num_output_interfaces) - { - UserAudioStreamStart(); - } - } - // in: 1 -> 0 - else if (!sp.wValue && num_input_interfaces) - { - UserAudioInputStreamStop(); - if (!num_output_interfaces) - { - UserAudioStreamStop(); - } + UserAudioStreamStart(); } } - else if (sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) + // in: 1 -> 0 + else if (!sp.wValue && num_input_interfaces) { - // out: 0 -> 1 - if (sp.wValue && !num_output_interfaces) + UserAudioInputStreamStop(); + if (!num_output_interfaces) { - UserAudioOutputStreamStart(); - if (!num_input_interfaces) - { - UserAudioStreamStart(); - } - } - // out: 1 -> 0 - else if (!sp.wValue && num_output_interfaces) - { - UserAudioOutputStreamStop(); - if (!num_input_interfaces) - { - UserAudioStreamStop(); - } + UserAudioStreamStop(); } } - else if(((sp.wIndex == 2) && (!sp.wValue)) && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT] && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT])) + } + else if (sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) + { + // out: 0 -> 1 + if (sp.wValue && !num_output_interfaces) { - /* if input stop and input running and output not running */ - UserAudioStreamStop(); + UserAudioOutputStreamStart(); + if (!num_input_interfaces) + { + UserAudioStreamStart(); + } + } + // out: 1 -> 0 + else if (!sp.wValue && num_output_interfaces) + { + UserAudioOutputStreamStop(); + if (!num_input_interfaces) + { + UserAudioStreamStop(); + } } } #elif (NUM_USB_CHAN_OUT > 0) From 92019d851a92db5e442e3fe2947e500356aa015a Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 6 Nov 2019 14:58:34 +0000 Subject: [PATCH 114/123] Remove xua_lite examples. Requested by Oscar Bailey as part of github.com/xmos/lib_xua Pull Request #103. --- examples/xua_lite_example/Makefile | 21 - examples/xua_lite_example/config.xscope | 3 - .../xua_lite_example/config/RPI_HAT_60QFN.xn | 66 --- examples/xua_lite_example/config/xua_conf.h | 41 -- examples/xua_lite_example/config/xud_conf.h | 7 - examples/xua_lite_example/plot_fill_level.sh | 1 - examples/xua_lite_example/src/app_xua_lite.xc | 157 ------- examples/xua_lite_example/src/audio_config.h | 8 - examples/xua_lite_example/src/audio_config.xc | 279 ------------- examples/xua_lite_example/src/audio_hub.h | 4 - examples/xua_lite_example/src/audio_hub.xc | 86 ---- examples/xua_lite_example/src/pdm_mic.h | 12 - examples/xua_lite_example/src/pdm_mic.xc | 112 ----- examples/xua_lite_example/test/Makefile | 35 -- examples/xua_lite_example/test/test_fifoxc | 139 ------- examples/xua_lite_example/todo.txt | 22 - examples/xua_lite_example/wscript | 26 -- .../xua_lite/rate_control/fifo_impl.h | 206 ---------- .../xua_lite/rate_control/fifo_types.h | 37 -- .../xua_lite/rate_control/rate_controller.h | 21 - .../xua_lite/rate_control/rate_controller.xc | 201 --------- .../xua_lite/xua_buffer_lite.h | 48 --- .../xua_lite/xua_buffer_lite.xc | 384 ------------------ .../xua_lite/xua_buffer_pack.h | 65 --- 24 files changed, 1981 deletions(-) delete mode 100644 examples/xua_lite_example/Makefile delete mode 100644 examples/xua_lite_example/config.xscope delete mode 100644 examples/xua_lite_example/config/RPI_HAT_60QFN.xn delete mode 100644 examples/xua_lite_example/config/xua_conf.h delete mode 100644 examples/xua_lite_example/config/xud_conf.h delete mode 100644 examples/xua_lite_example/plot_fill_level.sh delete mode 100644 examples/xua_lite_example/src/app_xua_lite.xc delete mode 100755 examples/xua_lite_example/src/audio_config.h delete mode 100755 examples/xua_lite_example/src/audio_config.xc delete mode 100644 examples/xua_lite_example/src/audio_hub.h delete mode 100644 examples/xua_lite_example/src/audio_hub.xc delete mode 100644 examples/xua_lite_example/src/pdm_mic.h delete mode 100644 examples/xua_lite_example/src/pdm_mic.xc delete mode 100644 examples/xua_lite_example/test/Makefile delete mode 100644 examples/xua_lite_example/test/test_fifoxc delete mode 100644 examples/xua_lite_example/todo.txt delete mode 100644 examples/xua_lite_example/wscript delete mode 100644 examples/xua_lite_example/xua_lite/rate_control/fifo_impl.h delete mode 100644 examples/xua_lite_example/xua_lite/rate_control/fifo_types.h delete mode 100644 examples/xua_lite_example/xua_lite/rate_control/rate_controller.h delete mode 100644 examples/xua_lite_example/xua_lite/rate_control/rate_controller.xc delete mode 100644 examples/xua_lite_example/xua_lite/xua_buffer_lite.h delete mode 100644 examples/xua_lite_example/xua_lite/xua_buffer_lite.xc delete mode 100644 examples/xua_lite_example/xua_lite/xua_buffer_pack.h diff --git a/examples/xua_lite_example/Makefile b/examples/xua_lite_example/Makefile deleted file mode 100644 index daa7dc5f..00000000 --- a/examples/xua_lite_example/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -APP_NAME = - -TARGET = RPI_HAT_60QFN.xn - -# The flags passed to xcc when building the application -XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -Os -report \ - -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] \ - -D MIC_ARRAY_CH0=PIN0 -D MIC_ARRAY_CH1=PIN4 - -# The USED_MODULES variable lists other module used by the application. These -# modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables. -# Modules are expected to be in the directory above the BASE_DIR directory. -USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_mic_array - -#============================================================================= -# The following part of the Makefile includes the common build infrastructure -# for compiling XMOS applications. You should not need to edit below here. - -XMOS_MAKE_PATH ?= ../.. -include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common - diff --git a/examples/xua_lite_example/config.xscope b/examples/xua_lite_example/config.xscope deleted file mode 100644 index f336ddac..00000000 --- a/examples/xua_lite_example/config.xscope +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/examples/xua_lite_example/config/RPI_HAT_60QFN.xn b/examples/xua_lite_example/config/RPI_HAT_60QFN.xn deleted file mode 100644 index c0c3f85c..00000000 --- a/examples/xua_lite_example/config/RPI_HAT_60QFN.xn +++ /dev/null @@ -1,66 +0,0 @@ - - - Device - XVF3510 Device - - - tileref tile[2] - tileref usb_tile - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/xua_lite_example/config/xua_conf.h b/examples/xua_lite_example/config/xua_conf.h deleted file mode 100644 index ae9de112..00000000 --- a/examples/xua_lite_example/config/xua_conf.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved - -#ifndef _XUA_CONF_H_ -#define _XUA_CONF_H_ - -#define NUM_USB_CHAN_OUT 2 /* Number of channels from host to device */ -#define NUM_USB_CHAN_IN 2 /* Number of channels from device to host */ -#define I2S_CHANS_DAC 2 /* Number of I2S channels out of xCORE */ -#define I2S_CHANS_ADC 2 /* Number of I2S channels in to xCORE */ -#define MCLK_441 (512 * 44100) /* 44.1kHz family master clock frequency */ -#define MCLK_48 (512 * 48000) /* 48kHz family master clock frequency */ -#define MIN_FREQ 48000 /* Minimum sample rate */ -#define MAX_FREQ 48000 /* Maximum sample rate */ - -#define EXCLUDE_USB_AUDIO_MAIN - -#define VENDOR_STR "XMOS" -#define VENDOR_ID 0x20B1 -#define PRODUCT_STR_A2 "XUA Lite Class 2" -#define PRODUCT_STR_A1 "XUA Lite Class 1" -#define PID_AUDIO_1 1 -#define PID_AUDIO_2 2 -#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example) */ - -#define INPUT_FORMAT_COUNT 1 -#define STREAM_FORMAT_INPUT_1_RESOLUTION_BITS 16 -#define OUTPUT_FORMAT_COUNT 1 -#define STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS 16 - -#define OUTPUT_VOLUME_CONTROL 0 -#define INPUT_VOLUME_CONTROL 0 - -#define UAC_FORCE_FEEDBACK_EP 0 -#define XUA_ADAPTIVE 1 -#define XUA_LITE 1 // Use simple/optimised USB buffer tasks -#define AUDIO_CLASS 1 - -#define XUA_NUM_PDM_MICS 4 // It's actually 2 but we run 4ch and ignore 2 -#define PDM_MAX_DECIMATION (96000/(MIN_FREQ)) - -#endif diff --git a/examples/xua_lite_example/config/xud_conf.h b/examples/xua_lite_example/config/xud_conf.h deleted file mode 100644 index c14d64a8..00000000 --- a/examples/xua_lite_example/config/xud_conf.h +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved - -#include "xua_conf.h" - -/* TODO */ -#define XUD_UAC_NUM_USB_CHAN_OUT NUM_USB_CHAN_OUT -#define XUD_UAC_NUM_USB_CHAN_IN NUM_USB_CHAN_IN diff --git a/examples/xua_lite_example/plot_fill_level.sh b/examples/xua_lite_example/plot_fill_level.sh deleted file mode 100644 index bb2ad5a3..00000000 --- a/examples/xua_lite_example/plot_fill_level.sh +++ /dev/null @@ -1 +0,0 @@ -grep pid: dump.txt | grep -Eo "\-?\d+" > proc.txt && gnuplot -p -e 'set term png; plot "proc.txt" with lines' > plot.png && open plot.png \ No newline at end of file diff --git a/examples/xua_lite_example/src/app_xua_lite.xc b/examples/xua_lite_example/src/app_xua_lite.xc deleted file mode 100644 index 64830667..00000000 --- a/examples/xua_lite_example/src/app_xua_lite.xc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved - -// A very simple *example* of a USB audio application (and as such is un-verified for production) -#include - -#include -#include - -#include "xua.h" -#include "xud.h" -#include "i2s.h" -#include "i2c.h" -#include "mic_array.h" -#include "xua_buffer_lite.h" -#include "xua_ep0_wrapper.h" -#include "pdm_mic.h" -#include "audio_config.h" -#include "audio_hub.h" - -#define DEBUG_UNIT XUA_APP -#define DEBUG_PRINT_ENABLE_XUA_APP 1 -#include "debug_print.h" - -// Port declarations. Note, the defines come from the xn file -on tile[0]: buffered out port:32 p_i2s_dac[] = {XS1_PORT_1N}; //DAC -on tile[0]: buffered in port:32 p_i2s_adc[] = {XS1_PORT_1F}; //Unused currently -on tile[0]: buffered out port:32 p_lrclk = XS1_PORT_1O; //I2S Bit-clock -on tile[0]: out port p_bclk = XS1_PORT_1P; //I2S L/R-clock - -// Master clock for the audio IO tile -on tile[0]: in port p_mclk_in = XS1_PORT_1K; - -// [0] : DAC_RESET_N -// [1] : I2C_INTERRUPT_N -// [2] : MUTE_EN -// [3] : LED -on tile[0]: out port p_gpio = XS1_PORT_4D; - -on tile[1]: port p_scl = XS1_PORT_1C; -on tile[1]: port p_sda = XS1_PORT_1D; -on tile[1]: in port p_mclk_in_usb = XS1_PORT_1A; -on tile[1]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks -on tile[1]: clock clk_usb_mclk = XS1_CLKBLK_3; // Master clock - -// Clock-block declarations -on tile[0]: clock clk_audio_bclk = XS1_CLKBLK_2; // Bit clock -on tile[0]: clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock -//XUD uses XS1_CLKBLK_4, XS1_CLKBLK_5 on tile[1] - -//Mic array resources -on tile[0]: out port p_pdm_clk = XS1_PORT_1L; -on tile[0]: in buffered port:32 p_pdm_mics = XS1_PORT_4E; - -on tile[0]: clock pdmclk = XS1_CLKBLK_4; -on tile[0]: clock pdmclk6 = XS1_CLKBLK_5; - - -// Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also -// if the endpoint wishes to be informed of USB bus resets - -XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO}; -XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO}; - -void burn_normal_priority(void){ - while(1); -} - -void burn_high_priority(void){ - set_core_high_priority_on(); - while(1); -} - -int main() -{ - // Channels for lib_xud - chan c_ep_out[XUA_ENDPOINT_COUNT_OUT]; - chan c_ep_in[XUA_ENDPOINT_COUNT_IN]; - - // Channel for communicating SOF notifications from XUD to the Buffering cores - chan c_sof; - - interface i2s_frame_callback_if i_i2s; - interface i2c_master_if i_i2c[1]; - - streaming chan c_audio; //We use the channel buffering (48B across switch each way) - streaming chan c_ds_output[1]; - - interface ep0_control_if i_ep0_ctl; - - par - { - on tile[0]: { - //Set the GPIOs needed for audio (reset and mute) - setup_audio_gpio(p_gpio); - c_audio <: 0; //Signal that we can now do i2c setup - c_audio :> int _; //Now wait until i2c has finished mclk setup - - const unsigned micDiv = MCLK_48/3072000; - mic_array_setup_ddr(pdmclk, pdmclk6, p_mclk_in, p_pdm_clk, p_pdm_mics, micDiv); - - par { - i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk); - [[distribute]] AudioHub(i_i2s, c_audio, c_ds_output); - pdm_mic(c_ds_output[0], p_pdm_mics); - - par (int i = 0; i < 5; i++) burn_normal_priority(); - par (int i = 0; i < 0; i++) burn_high_priority(); - } - } - on tile[1]:unsafe{ - // Connect master-clock input clock-block to clock-block pin for asnch feedback calculation - set_clock_src(clk_usb_mclk, p_mclk_in_usb); // Clock clock-block from mclk pin - set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block - start_clock(clk_usb_mclk); // Set the clock off running - - //Setup DAC over i2c and then return so we do not use a thread - c_audio :> int _; //Wait for reset to be asserted/deasserted by other tile - par{ - i2c_master(i_i2c, 1, p_scl, p_sda, 100); - AudioHwConfigure(DEFAULT_FREQ, i_i2c[0]); - } - c_audio <: 0; //Signal to tile[0] that mclk is now good - - par { - // Low level USB device layer core - XUD_Main(c_ep_out, XUA_ENDPOINT_COUNT_OUT, c_ep_in, XUA_ENDPOINT_COUNT_IN, - c_sof, epTypeTableOut, epTypeTableIn, - null, null, -1 , - (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS, XUD_PWR_BUS); - - // // Buffering core - handles audio and control data to/from EP's and gives/gets data to/from the audio I/O core - // XUA_Buffer_lite(c_ep_out[0], - // c_ep_in[0], - // c_ep_out[1], - // null, //c_ep_in[XUA_ENDPOINT_COUNT_IN - 2],/*feedback*/ - // c_ep_in[XUA_ENDPOINT_COUNT_IN - 1], - // c_sof, p_for_mclk_count, c_audio); - - //[[combine]] - par{ - XUA_Buffer_lite2(i_ep0_ctl, - c_ep_out[1], - null, //c_ep_in[XUA_ENDPOINT_COUNT_IN - 2],/*feedback*/ - c_ep_in[XUA_ENDPOINT_COUNT_IN - 1], - c_sof, p_for_mclk_count, c_audio); - XUA_Endpoint0_select(c_ep_out[0], c_ep_in[0], i_ep0_ctl, null VENDOR_REQUESTS_PARAMS_DEC_); - } - par (int i = 0; i < 3; i++) burn_normal_priority(); - par (int i = 0; i < 2; i++) burn_high_priority(); - } - }//Tile[1] par - }//Top level par - - return 0; -} - - diff --git a/examples/xua_lite_example/src/audio_config.h b/examples/xua_lite_example/src/audio_config.h deleted file mode 100755 index 6b7c079b..00000000 --- a/examples/xua_lite_example/src/audio_config.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _AUDIO_CONFIG_ -#define _AUDIO_CONFIG_ - -void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c); -void pll_nudge(int nudge); -void setup_audio_gpio(out port p_gpio); - -#endif diff --git a/examples/xua_lite_example/src/audio_config.xc b/examples/xua_lite_example/src/audio_config.xc deleted file mode 100755 index 3235387d..00000000 --- a/examples/xua_lite_example/src/audio_config.xc +++ /dev/null @@ -1,279 +0,0 @@ -#include -#include -#include -#include -#include -#include "i2c.h" -#include "xua.h" -#define DEBUG_UNIT AUDIO_CFG -#define DEBUG_PRINT_ENABLE_AUDIO_CFG 1 -#include "debug_print.h" - - -// TLV320DAC3101 Device I2C Address -#define DAC3101_I2C_DEVICE_ADDR 0x18 - -// TLV320DAC3101 Register Addresses -// Page 0 -#define DAC3101_PAGE_CTRL 0x00 // Register 0 - Page Control -#define DAC3101_SW_RST 0x01 // Register 1 - Software Reset -#define DAC3101_CLK_GEN_MUX 0x04 // Register 4 - Clock-Gen Muxing -#define DAC3101_PLL_P_R 0x05 // Register 5 - PLL P and R Values -#define DAC3101_PLL_J 0x06 // Register 6 - PLL J Value -#define DAC3101_PLL_D_MSB 0x07 // Register 7 - PLL D Value (MSB) -#define DAC3101_PLL_D_LSB 0x08 // Register 8 - PLL D Value (LSB) -#define DAC3101_NDAC_VAL 0x0B // Register 11 - NDAC Divider Value -#define DAC3101_MDAC_VAL 0x0C // Register 12 - MDAC Divider Value -#define DAC3101_DOSR_VAL_LSB 0x0E // Register 14 - DOSR Divider Value (LS Byte) -#define DAC3101_CLKOUT_MUX 0x19 // Register 25 - CLKOUT MUX -#define DAC3101_CLKOUT_M_VAL 0x1A // Register 26 - CLKOUT M_VAL -#define DAC3101_CODEC_IF 0x1B // Register 27 - CODEC Interface Control -#define DAC3101_DAC_DAT_PATH 0x3F // Register 63 - DAC Data Path Setup -#define DAC3101_DAC_VOL 0x40 // Register 64 - DAC Vol Control -#define DAC3101_DACL_VOL_D 0x41 // Register 65 - DAC Left Digital Vol Control -#define DAC3101_DACR_VOL_D 0x42 // Register 66 - DAC Right Digital Vol Control -#define DAC3101_GPIO1_IO 0x33 // Register 51 - GPIO1 In/Out Pin Control -// Page 1 -#define DAC3101_HP_DRVR 0x1F // Register 31 - Headphone Drivers -#define DAC3101_SPK_AMP 0x20 // Register 32 - Class-D Speaker Amp -#define DAC3101_HP_DEPOP 0x21 // Register 33 - Headphone Driver De-pop -#define DAC3101_DAC_OP_MIX 0x23 // Register 35 - DAC_L and DAC_R Output Mixer Routing -#define DAC3101_HPL_VOL_A 0x24 // Register 36 - Analog Volume to HPL -#define DAC3101_HPR_VOL_A 0x25 // Register 37 - Analog Volume to HPR -#define DAC3101_SPKL_VOL_A 0x26 // Register 38 - Analog Volume to Left Speaker -#define DAC3101_SPKR_VOL_A 0x27 // Register 39 - Analog Volume to Right Speaker -#define DAC3101_HPL_DRVR 0x28 // Register 40 - Headphone Left Driver -#define DAC3101_HPR_DRVR 0x29 // Register 41 - Headphone Right Driver -#define DAC3101_SPKL_DRVR 0x2A // Register 42 - Left Class-D Speaker Driver -#define DAC3101_SPKR_DRVR 0x2B // Register 43 - Right Class-D Speaker Driver - -// TLV320DAC3101 easy register access defines -#define DAC3101_REGWRITE(reg, val) {i_i2c.write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);} - - -// Nominal setting is ref div = 25, fb_div = 1024, op_div = 2 -// PCF Freq 0.96MHz - -enum clock_nudge{ - PLL_SLOWER = -1, - PLL_NOMINAL = 0, - PLL_FASTER = 1 -}; - -//These steps provide just under +-0.1% frequency jumps -#define PLL_LOW 0xC003FE18 // This is 3.069MHz -#define PLL_NOM 0xC003FF18 // This is 3.072MHz -#define PLL_HIGH 0xC0040018 // This is 3.075MHz - -on tile[0]: out port p_leds = XS1_PORT_4F; - -//Note use of no_ack write to prevent backpressure. There is enough buffering to -//store both writes so we can move on without blocking -void pll_nudge(int nudge) { - if (nudge > 0){ - write_sswitch_reg_no_ack(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_HIGH); - p_leds <: 0x02; //LED B - } - else if (nudge < 0){ - write_sswitch_reg_no_ack(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_LOW); - p_leds <: 0x01; //LED A - - } - else { - p_leds <: 0x0; - } - write_sswitch_reg_no_ack(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_NOM); -} - -void setup_audio_gpio(out port p_gpio){ - // Reset DAC and disable MUTE - p_gpio <: 0x0; - delay_milliseconds(1); - p_gpio <: 0x1; - delay_milliseconds(1); -} - -void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c) -{ - - // Wait for 2ms because we apply reset for 1ms from other tile - delay_milliseconds(2); - - // Set register page to 0 - DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); - // Initiate SW reset (PLL is powered off as part of reset) - DAC3101_REGWRITE(DAC3101_SW_RST, 0x01); - - // so I've got 24MHz in to PLL, I want 24.576MHz or 22.5792MHz out. - - // I will always be using fractional-N (D != 0) so we must set R = 1 - // PLL_CLKIN/P must be between 10 and 20MHz so we must set P = 2 - - // PLL_CLK = CLKIN * ((RxJ.D)/P) - // We know R = 1, P = 2. - // PLL_CLK = CLKIN * (J.D / 2) - - // For 24.576MHz: - // J = 8 - // D = 1920 - // So PLL_CLK = 24 * (8.192/2) = 24 x 4.096 = 98.304MHz - // Then: - // NDAC = 4 - // MDAC = 4 - // DOSR = 128 - // So: - // DAC_CLK = PLL_CLK / 4 = 24.576MHz. - // DAC_MOD_CLK = DAC_CLK / 4 = 6.144MHz. - // DAC_FS = DAC_MOD_CLK / 128 = 48kHz. - - // For 22.5792MHz: - // J = 7 - // D = 5264 - // So PLL_CLK = 24 * (7.5264/2) = 24 x 3.7632 = 90.3168MHz - // Then: - // NDAC = 4 - // MDAC = 4 - // DOSR = 128 - // So: - // DAC_CLK = PLL_CLK / 4 = 22.5792MHz. - // DAC_MOD_CLK = DAC_CLK / 4 = 5.6448MHz. - // DAC_FS = DAC_MOD_CLK / 128 = 44.1kHz. - -#if XUA_ADAPTIVE - //Set nominal clock speed on PLL - write_sswitch_reg(get_tile_id(tile[0]), XS1_SSWITCH_PLL_CTL_NUM, PLL_NOM); - - // We are assuming 48kHz family only and we generate MCLK in the DAC from BLCK supplied by XCORE - // Set PLL J Value to 8 - DAC3101_REGWRITE(DAC3101_PLL_J, 0x08); - // Set PLL D to 0 ... - // Set PLL D MSB Value to 0x00 - DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x00); - // Set PLL D LSB Value to 0x00 - DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x00); - - delay_milliseconds(1); - - // Set PLL_CLKIN = BCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) - DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x07); - - // Set PLL P=1 and R=4 values and power up. - DAC3101_REGWRITE(DAC3101_PLL_P_R, 0x94); - // Set NDAC clock divider to 4 and power up. - DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x84); - // Set MDAC clock divider to 4 and power up. - DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x84); - // Set OSR clock divider to 128. - DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80); - -#else - /* Sample frequency dependent register settings */ - if ((samFreq % 11025) == 0) - { - // MCLK = 22.5792MHz (44.1,88.2,176.4kHz) - // Set PLL J Value to 7 - DAC3101_REGWRITE(DAC3101_PLL_J, 0x07); - // Set PLL D to 5264 ... (0x1490) - // Set PLL D MSB Value to 0x14 - DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x14); - // Set PLL D LSB Value to 0x90 - DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x90); - - } - else if ((samFreq % 8000) == 0) - { - // MCLK = 24.576MHz (48,96,192kHz) - // Set PLL J Value to 8 - DAC3101_REGWRITE(DAC3101_PLL_J, 0x08); - // Set PLL D to 1920 ... (0x780) - // Set PLL D MSB Value to 0x07 - DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x07); - // Set PLL D LSB Value to 0x80 - DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x80); - } - else - { - //debug_printf("Unrecognised sample freq of %d in ConfigCodec\n", samFreq); - } - - delay_milliseconds(1); - - // Set PLL_CLKIN = MCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip) - DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x03); - - // Set PLL P and R values and power up. - DAC3101_REGWRITE(DAC3101_PLL_P_R, 0xA1); - // Set NDAC clock divider to 4 and power up. - DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x84); - // Set MDAC clock divider to 4 and power up. - DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x84); - // Set OSR clock divider to 128. - DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80); - -#endif - - // Set CLKOUT Mux to DAC_CLK - DAC3101_REGWRITE(DAC3101_CLKOUT_MUX, 0x04); - // Set CLKOUT M divider to 1 and power up. - DAC3101_REGWRITE(DAC3101_CLKOUT_M_VAL, 0x81); - // Set GPIO1 output to come from CLKOUT output. - DAC3101_REGWRITE(DAC3101_GPIO1_IO, 0x10); - - // Set CODEC interface mode: I2S, 24 bit, slave mode (BCLK, WCLK both inputs). - DAC3101_REGWRITE(DAC3101_CODEC_IF, 0x20); - // Set register page to 1 - DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x01); - // Program common-mode voltage to mid scale 1.65V. - DAC3101_REGWRITE(DAC3101_HP_DRVR, 0x14); - // Program headphone-specific depop settings. - // De-pop, Power on = 800 ms, Step time = 4 ms - DAC3101_REGWRITE(DAC3101_HP_DEPOP, 0x4E); - // Program routing of DAC output to the output amplifier (headphone/lineout or speaker) - // LDAC routed to left channel mixer amp, RDAC routed to right channel mixer amp - DAC3101_REGWRITE(DAC3101_DAC_OP_MIX, 0x44); - // Unmute and set gain of output driver - // Unmute HPL, set gain = 0 db - DAC3101_REGWRITE(DAC3101_HPL_DRVR, 0x06); - // Unmute HPR, set gain = 0 dB - DAC3101_REGWRITE(DAC3101_HPR_DRVR, 0x06); - // Unmute Left Class-D, set gain = 12 dB - DAC3101_REGWRITE(DAC3101_SPKL_DRVR, 0x0C); - // Unmute Right Class-D, set gain = 12 dB - DAC3101_REGWRITE(DAC3101_SPKR_DRVR, 0x0C); - // Power up output drivers - // HPL and HPR powered up - DAC3101_REGWRITE(DAC3101_HP_DRVR, 0xD4); - // Power-up L and R Class-D drivers - DAC3101_REGWRITE(DAC3101_SPK_AMP, 0xC6); - // Enable HPL output analog volume, set = -9 dB - DAC3101_REGWRITE(DAC3101_HPL_VOL_A, 0x92); - // Enable HPR output analog volume, set = -9 dB - DAC3101_REGWRITE(DAC3101_HPR_VOL_A, 0x92); - // Enable Left Class-D output analog volume, set = -9 dB - DAC3101_REGWRITE(DAC3101_SPKL_VOL_A, 0x92); - // Enable Right Class-D output analog volume, set = -9 dB - DAC3101_REGWRITE(DAC3101_SPKR_VOL_A, 0x92); - - delay_milliseconds(100); - - // Power up DAC - // Set register page to 0 - DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00); - // Power up DAC channels and set digital gain - // Powerup DAC left and right channels (soft step enabled) - DAC3101_REGWRITE(DAC3101_DAC_DAT_PATH, 0xD4); - // DAC Left gain = 0dB - DAC3101_REGWRITE(DAC3101_DACL_VOL_D, 0x00); - // DAC Right gain = 0dB - DAC3101_REGWRITE(DAC3101_DACR_VOL_D, 0x00); - // Unmute digital volume control - // Unmute DAC left and right channels - DAC3101_REGWRITE(DAC3101_DAC_VOL, 0x00); - - i_i2c.shutdown(); -} - - -//These are here just to silence compiler warnings about unimplemented xua callbacks (not needed in xua lite) -void AudioHwInit(){} -void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC){} diff --git a/examples/xua_lite_example/src/audio_hub.h b/examples/xua_lite_example/src/audio_hub.h deleted file mode 100644 index b7f1b7f9..00000000 --- a/examples/xua_lite_example/src/audio_hub.h +++ /dev/null @@ -1,4 +0,0 @@ -#include "i2s.h" - -[[distributable]] -void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_audio, streaming chanend (&?c_ds_output)[1]); \ No newline at end of file diff --git a/examples/xua_lite_example/src/audio_hub.xc b/examples/xua_lite_example/src/audio_hub.xc deleted file mode 100644 index bec765a1..00000000 --- a/examples/xua_lite_example/src/audio_hub.xc +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include "i2s.h" -#include "i2c.h" -#include "xua.h" -#define DEBUG_UNIT XUA_AUDIO_HUB -#define DEBUG_PRINT_ENABLE_XUA_AUDIO_HUB 1 -#include "debug_print.h" -#include "mic_array.h" -#include "audio_config.h" -#include "pdm_mic.h" -#include "xua_buffer_lite.h" - -//Globally declared for 64b alignment -int mic_decimator_fir_data_array[8][THIRD_STAGE_COEFS_PER_STAGE * PDM_MAX_DECIMATION] = {{0}}; -mic_array_frame_time_domain mic_audio_frame[2]; - -[[distributable]] -void AudioHub(server i2s_frame_callback_if i2s, - streaming chanend c_audio, - streaming chanend (&?c_ds_output)[1]) -{ - int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; - int32_t samples_in[NUM_USB_CHAN_IN] = {0}; - - int32_t clock_nudge = 0; - - //PDM mic and decimator - unsigned buffer; - int raw_mics[XUA_NUM_PDM_MICS] = {0}; - const unsigned decimatorCount = 1; // Supports up to 4 mics - mic_array_decimator_conf_common_t dcc; - mic_array_decimator_config_t dc[1]; - mic_array_frame_time_domain * unsafe current; - - mic_array_decimator_set_samprate(DEFAULT_FREQ, mic_decimator_fir_data_array[0], &dcc, dc); - mic_array_decimator_configure(c_ds_output, decimatorCount, dc); - mic_array_init_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); - - // Used for debug - //int saw = 0; - - while (1) { - select { - case i2s.init(i2s_config_t &?i2s_config, tdm_config_t &?tdm_config): - i2s_config.mode = I2S_MODE_I2S; - i2s_config.mclk_bclk_ratio = (MCLK_48/DEFAULT_FREQ)/64; - debug_printf("I2S init\n"); - delay_milliseconds(500); //Work around to ensure I2S does not start until enumeration complete so timing does not break for exchange - //This should be ideally done by set config by the host (via xua_buffer) to know we are enumerated - break; - - case i2s.receive(size_t n_chans, int32_t in_samps[n_chans]): - for (int i = 0; i < n_chans; i++) samples_in[i] = in_samps[i]; - break; - - case i2s.send(size_t n_chans, int32_t out_samps[n_chans]): - for (int i = 0; i < n_chans; i++) out_samps[i] = samples_out[i]; - break; - - //Exchange samples with mics & host - case i2s.restart_check() -> i2s_restart_t restart: - restart = I2S_NO_RESTART; // Keep on looping - timer tmr; int t0, t1; tmr :> t0; - - XUA_transfer_samples(c_audio, (unsigned *) samples_out, (unsigned *) raw_mics, (clock_nudge, int)); - - //Grab mics. Takes about 200 ticks currently - current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc); - //50 ticks - unsafe { - for (int i = 0; i < XUA_NUM_PDM_MICS; i++) raw_mics[i] = current->data[i][0]; - } - - //memset(raw_mics, saw, sizeof(int) * XUA_NUM_PDM_MICS); - //saw += 500; - - //Taking about 160 ticks when adjusting, 100 when not - tmr :> t0; - pll_nudge(clock_nudge); - tmr :> t1; - if (t1-t0 > 500) debug_printf("*%d\n", t1 - t0); - //delay_microseconds(10); //Test backpressure tolerance - break; - } - } -} diff --git a/examples/xua_lite_example/src/pdm_mic.h b/examples/xua_lite_example/src/pdm_mic.h deleted file mode 100644 index 04b13c3f..00000000 --- a/examples/xua_lite_example/src/pdm_mic.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _PDM_MIC_H_ -#define _PDM_MIC_H_ - -#include "mic_array.h" - -void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]); -void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics); -void mic_array_setup_ddr(clock pdmclk, clock pdmclk6, in port p_mclk, - out port p_pdm_clk, buffered in port:32 p_pdm_data, - int divide); - -#endif diff --git a/examples/xua_lite_example/src/pdm_mic.xc b/examples/xua_lite_example/src/pdm_mic.xc deleted file mode 100644 index 59d506be..00000000 --- a/examples/xua_lite_example/src/pdm_mic.xc +++ /dev/null @@ -1,112 +0,0 @@ -#include "xua.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mic_array.h" - - -void mic_array_decimator_set_samprate(const unsigned samplerate, int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]) -{ - unsigned decimationfactor = 96000/samplerate; - int fir_gain_compen[7]; - int * unsafe fir_coefs[7]; - unsafe - { - fir_gain_compen[0] = 0; - fir_gain_compen[1] = FIR_COMPENSATOR_DIV_2; //48kHz - fir_gain_compen[2] = FIR_COMPENSATOR_DIV_4; - fir_gain_compen[3] = FIR_COMPENSATOR_DIV_6; //16kHz - fir_gain_compen[4] = FIR_COMPENSATOR_DIV_8; - fir_gain_compen[5] = 0; - fir_gain_compen[6] = FIR_COMPENSATOR_DIV_12; - - fir_coefs[0] = 0; - fir_coefs[1] = (int * unsafe)g_third_stage_div_2_fir; - fir_coefs[2] = (int * unsafe)g_third_stage_div_4_fir; - fir_coefs[3] = (int * unsafe)g_third_stage_div_6_fir; - fir_coefs[4] = (int * unsafe)g_third_stage_div_8_fir; - fir_coefs[5] = 0; - fir_coefs[6] = (int * unsafe)g_third_stage_div_12_fir; - - //dcc = {MIC_ARRAY_MAX_FRAME_SIZE_LOG2, 1, 0, 0, decimationfactor, fir_coefs[decimationfactor/2], 0, 0, DECIMATOR_NO_FRAME_OVERLAP, 2}; - dcc->len = MIC_ARRAY_MAX_FRAME_SIZE_LOG2; - dcc->apply_dc_offset_removal = 1; - dcc->index_bit_reversal = 0; - dcc->windowing_function = null; - dcc->output_decimation_factor = decimationfactor; - dcc->coefs = fir_coefs[decimationfactor/2]; - dcc->apply_mic_gain_compensation = 0; - dcc->fir_gain_compensation = fir_gain_compen[decimationfactor/2]; - dcc->buffering_type = DECIMATOR_NO_FRAME_OVERLAP; - dcc->number_of_frame_buffers = 2; - - //dc[0] = {&dcc, mic_decimator_fir_data[0], {0, 0, 0, 0}, 4}; - dc[0].dcc = dcc; - dc[0].data = mic_decimator_fir_data_array; - dc[0].mic_gain_compensation[0]=0; - dc[0].mic_gain_compensation[1]=0; - dc[0].mic_gain_compensation[2]=0; - dc[0].mic_gain_compensation[3]=0; - dc[0].channel_count = 4; - } -} - -#if MAX_FREQ > 48000 -#error MAX_FREQ > 48000 NOT CURRENTLY SUPPORTED -#endif - -void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics) -{ - streaming chan c_4x_pdm_mic_0; - assert((MCLK_48 / 3072000) == (MCLK_441 / 2822400)); //Make sure mic clock is achievable from MCLK - par - { - mic_array_pdm_rx(p_pdm_mics, c_4x_pdm_mic_0, null); - mic_array_decimate_to_pcm_4ch(c_4x_pdm_mic_0, c_ds_output, MIC_ARRAY_NO_INTERNAL_CHANS); - - } -} - -void mic_array_setup_ddr(clock pdmclk, - clock pdmclk6, - in port p_mclk, /*used only in I2S slave case*/ - out port p_pdm_clk, - buffered in port:32 p_pdm_data, - int divide) { - - -#if !XUA_ADAPTIVE //i2s slave - //p_mclk coming from the Pi is 24.576 MHz - configure_clock_src_divide(pdmclk, p_mclk, 4); //3.072 = 24.576 / 8 - configure_clock_src_divide(pdmclk6, p_mclk, 2); //6.144 = 24.576 / 4 - -#else - configure_clock_xcore(pdmclk, 80); // 3.072 - configure_clock_xcore(pdmclk6, 40); // 6.144 -#endif - - configure_port_clock_output(p_pdm_clk, pdmclk); - configure_in_port(p_pdm_data, pdmclk6); - - /* start the faster capture clock */ - start_clock(pdmclk6); - /* wait for a rising edge on the capture clock */ - partin(p_pdm_data, 4); - /* start the slower output clock */ - start_clock(pdmclk); - - /* - * this results in the rising edge of the capture clock - * leading the rising edge of the output clock by one period - * of p_mclk, which is about 40.7 ns for the typical frequency - * of 24.576 megahertz. - * This should fall within the data valid window. - */ - -} diff --git a/examples/xua_lite_example/test/Makefile b/examples/xua_lite_example/test/Makefile deleted file mode 100644 index b3bbbe69..00000000 --- a/examples/xua_lite_example/test/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2018, XMOS Ltd, All rights reserved - -#Note no xcommon included - we are going bareback here because xcommon not good -#at dealing excluding/including source directories out of normal structure. -#We want to have a test app here using some source files from sw_vocalfusion (delay estimator) - - -BUILD_FLAGS = -O3 -g -XCC_FLAGS = $(BUILD_FLAGS) - -INCLUDE_DIRS = \ - -I ../src/ \ - -I . \ - -COMMON = \ - -O2 -g -report \ - -target=XCORE-200-EXPLORER \ - -SOURCES = \ - ./test_fifo.xc \ - -BINARY=bin/test_fifo.xe \ - - -all: - mkdir -p bin; \ - mv test_fifoxc test_fifo.xc; \ - xcc $(SOURCES) $(COMMON) $(INCLUDE_DIRS) -D AUDIO_DELAY_SAMPLES=$$DELAY -o $(BINARY); \ - mv test_fifo.xc test_fifoxc; \ - -sim: - xsim $(BINARY) - -clean: - rm -rf bin/* diff --git a/examples/xua_lite_example/test/test_fifoxc b/examples/xua_lite_example/test/test_fifoxc deleted file mode 100644 index befb966b..00000000 --- a/examples/xua_lite_example/test/test_fifoxc +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include "fifo_impl.h" - -typedef enum test_t{ - FAIL=0, - PASS=1 -}test_t; - -#define FIFO_SIZE 4 - -unsafe test_t test_is_empty(mem_fifo_short_t * unsafe fifo){ - unsigned fill = fifo_get_fill_short(fifo); - short data[1]; - fifo_ret_t ret = fifo_block_pop_short(fifo, data, 1); - if (fill == 0 && ret == FIFO_EMPTY) return PASS; - return FAIL; -} - -unsafe test_t test_push_one(mem_fifo_short_t * unsafe fifo){ - unsigned fill_0 = fifo_get_fill_short(fifo); - short data[] = {123}; - fifo_ret_t ret = fifo_block_push_short(fifo, data, 1); - unsigned fill_1 = fifo_get_fill_short(fifo); - - if (ret != FIFO_SUCCESS || fill_0 + 1 != fill_1) return FAIL; - return PASS; -} - -unsafe test_t test_partial_fill(mem_fifo_short_t * unsafe fifo){ - unsigned fill_0 = fifo_get_fill_short(fifo); - short data[] = {80, 90, 100}; - fifo_ret_t ret = fifo_block_push_short(fifo, data, 3); - unsigned fill_1 = fifo_get_fill_short(fifo); - - if (ret != FIFO_SUCCESS || fill_0 != 0 || fill_1 != 3) return FAIL; - return PASS; -} - -unsafe test_t test_fill_level(mem_fifo_short_t * unsafe fifo){ - unsigned fill = fifo_get_fill_short(fifo); - if (fill != 3) return FAIL; - return PASS; -} - -unsafe test_t test_pop_one(mem_fifo_short_t * unsafe fifo, short expect){ - unsigned fill_0 = fifo_get_fill_short(fifo); - short data[1] = {0xffff}; - fifo_ret_t ret = fifo_block_pop_short(fifo, data, 1); - unsigned fill_1 = fifo_get_fill_short(fifo); - if (ret != FIFO_SUCCESS || fill_0 != fill_1 + 1 || data[0] != expect) { - printf("grr %d\n", data[0]); - return FAIL; - } - return PASS; -} - -unsafe test_t test_pop_three_fail(mem_fifo_short_t * unsafe fifo){ - unsigned fill_0 = fifo_get_fill_short(fifo); - short data[3] = {0xffff, 0xffff, 0xffff}; - fifo_ret_t ret = fifo_block_pop_short(fifo, data, 3); - unsigned fill_1 = fifo_get_fill_short(fifo); - if (ret == FIFO_SUCCESS || fill_0 != 2 || fill_1 != 2) return FAIL; - return PASS; -} - -unsafe test_t test_partial_fill_fast(mem_fifo_short_t * unsafe fifo){ - unsigned fill_0 = fifo_get_fill_short(fifo); - short data[] = {20, 30, 40}; - fifo_ret_t ret = fifo_block_push_short_fast(fifo, data, 3); - unsigned fill_1 = fifo_get_fill_short(fifo); - - if (ret != FIFO_SUCCESS || fill_0 != 0 || fill_1 != 3) return FAIL; - return PASS; -} - -unsafe test_t test_pop_block_fast(mem_fifo_short_t * unsafe fifo, short expect[], unsigned n){ - unsigned fill_0 = fifo_get_fill_short(fifo); - short data[10] = {0xffff}; - fifo_ret_t ret = fifo_block_pop_short_fast(fifo, data, n); - unsigned fill_1 = fifo_get_fill_short(fifo); - unsigned data_ok = memcmp(data, expect, n * sizeof(short)) == 0; - if (ret != FIFO_SUCCESS || fill_0 != fill_1 + n || !data_ok) return FAIL; - return PASS; -} - -unsafe void print_fifo(mem_fifo_short_t * unsafe fifo){ - for (int i = fifo->size - 1; i >= 0; i--){ - printf("FIFO[%d]: %hd %s %s\n", i, fifo->data_base_ptr[i], fifo->read_idx == i ? "RD" : "", fifo->write_idx == i ? "WR" : ""); - } -} - - -int main(void){ - unsafe{ - short test_fifo_storage[FIFO_SIZE]; - mem_fifo_short_t test_fifo = {sizeof(test_fifo_storage)/sizeof(test_fifo_storage[0]), test_fifo_storage, 0, 0}; - volatile mem_fifo_short_t * unsafe test_fifo_ptr = &test_fifo; - - // print_fifo(test_fifo_ptr); - printf("test_is_empty: %d\n", test_is_empty(test_fifo_ptr)); - printf("test_partial_fill: %d\n", test_partial_fill(test_fifo_ptr)); - // print_fifo(test_fifo_ptr); - - printf("test_fill_level: %d\n", test_fill_level(test_fifo_ptr)); - printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 80)); - printf("test_pop_three_fail: %d\n", test_pop_three_fail(test_fifo_ptr)); - printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 90)); - printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 100)); - printf("test_is_empty: %d\n", test_is_empty(test_fifo_ptr)); - - printf("test_partial_fill_fast: %d\n", test_partial_fill_fast(test_fifo_ptr)); - - printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 20)); - // print_fifo(test_fifo_ptr); - - short td[] = {30, 40}; - - printf("test_pop_block_fast: %d\n", test_pop_block_fast(test_fifo_ptr, td, 2)); //no wrap - - printf("test_is_empty: %d\n", test_is_empty(test_fifo_ptr)); - printf("test_push_one: %d\n", test_push_one(test_fifo_ptr)); - printf("test_push_one: %d\n", test_push_one(test_fifo_ptr)); - printf("test_pop_three_fail: %d\n", test_pop_three_fail(test_fifo_ptr)); - printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 123)); - printf("test_pop_one: %d\n", test_pop_one(test_fifo_ptr, 123)); - - printf("test_partial_fill_fast: %d\n", test_partial_fill_fast(test_fifo_ptr)); //no wrap - short te[] = {20, 30, 40}; - printf("test_pop_block_fast: %d\n", test_pop_block_fast(test_fifo_ptr, te, 3));// no wrap - printf("test_partial_fill_fast: %d\n", test_partial_fill_fast(test_fifo_ptr)); //wrap - printf("test_pop_block_fast: %d\n", test_pop_block_fast(test_fifo_ptr, te, 3));// wrap - // print_fifo(test_fifo_ptr); - - - - - return 0; - } -} \ No newline at end of file diff --git a/examples/xua_lite_example/todo.txt b/examples/xua_lite_example/todo.txt deleted file mode 100644 index 4d0ab456..00000000 --- a/examples/xua_lite_example/todo.txt +++ /dev/null @@ -1,22 +0,0 @@ -- Bring ep0 serivice into xua_buffer select (make control mem) (DONE) -- Tidy feedback endpoint (DONE) -- Input path + FIFO (DONE) -- Function prototypes into includes (DONE) -- Single input/ouput format (DONE) -- Get UAC1 / FS working (DONE) -- Optimised EP buffer (either triple block or block FIFO) (DONE) -- Fix output gain issue (IN PROGRESS) -- Add timer to xua_buffer to prepare for exchange with audio (remove backpressure to audio) (WONT DO - use port buffer and reduce case overhead) -- Adaptive endpoint EP and descriptors (DONE) -- Adpative clock control (IN PROGRESS) -- Proper control loop w/filtering (IN PROGRESS) -- Switchable MICS using define (WONT DO - separate app) -- DFU -- Combinable EP0 (DONE) -- Interrupt EP0 option -- Control processing -- Fix cast warning (DONE) -- Work out why no clock drift on Android / OSX (drift seen on Linux and Win) (DONE) -- Tidy/cut down EP0 handling -- Broader host testing (Android, W10, MAC) (IN PROGRESS) -- Peer review diff --git a/examples/xua_lite_example/wscript b/examples/xua_lite_example/wscript deleted file mode 100644 index 5d6de68c..00000000 --- a/examples/xua_lite_example/wscript +++ /dev/null @@ -1,26 +0,0 @@ -def options(ctx): - ctx.add_option('--target', action='store', default='xua_lite_example.xe') - ctx.add_option('--debug', action='store_true') - - -def configure(conf): - conf.load('xwaf.compiler_xcc') - conf.env.PROJECT_ROOT = '../../..' - -def build(bld): - target_path = 'bin/' + bld.options.target - bld.env.TARGET_ARCH ='config/RPI_HAT_60QFN.xn' - bld.env.XSCOPE = bld.path.find_resource('config.xscope') - depends_on = ['lib_xua','lib_i2s','lib_xud','lib_mic_array', 'lib_i2c'] - #bld.env.XCC_FLAGS = ['-O2', '-g', '-Wall', '-fcmdline-buffer-bytes=512', '-report', '-DDISABLE_STAGE_C'] - bld.env.XCC_FLAGS = ['-fcomment-asm','-Xmapper','--map','-Xmapper','MAPFILE', - '-Os','-report','-g','-Wno-unused-function','-Wno-timing', - '-DXUD_SERIES_SUPPORT=XUD_X200_SERIES','-DUSB_TILE=tile[1]', - '-DMIC_ARRAY_CH0=PIN0','-DMIC_ARRAY_CH1=PIN4', '-DDEBUG_PRINT_ENABLE=1'] - if bld.options.debug: - bld.env.XCC_FLAGS.append('-DDEBUG') - - source = bld.path.ant_glob(['src/**/*.xc', 'src/**/*.c', - 'xua_lite/**/*.xc', 'xua_lite/**/*.c']) - includes = ['config'] - bld.program(source=source, includes=includes, depends_on=depends_on,target=target_path) diff --git a/examples/xua_lite_example/xua_lite/rate_control/fifo_impl.h b/examples/xua_lite_example/xua_lite/rate_control/fifo_impl.h deleted file mode 100644 index 080f3c95..00000000 --- a/examples/xua_lite_example/xua_lite/rate_control/fifo_impl.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef __FIFO__ -#define __FIFO__ -#include //memcpy -#include "fifo_types.h" - -//Asynch FIFO implementaion -//Note these are in the include file to allow the compiler to inline for performance - -/////////////////////////////////////// -//Shared memory FIFO (sample by sample) -//Can be any size -/////////////////////////////////////// - - -static inline unsigned fifo_get_fill(volatile mem_fifo_t * unsafe fifo) { - unsafe{ - unsigned fifo_fill = 0; - if (fifo->write_idx >= fifo->read_idx){ - fifo_fill = fifo->write_idx - fifo->read_idx; - } - else{ - fifo_fill = (fifo->size + fifo->write_idx) - fifo->read_idx; - } - return fifo_fill; - } -} - -static inline unsigned fifo_get_fill_short(volatile mem_fifo_short_t * unsafe fifo) { - unsafe{ - unsigned fifo_fill = 0; - if (fifo->write_idx >= fifo->read_idx){ - fifo_fill = fifo->write_idx - fifo->read_idx; - } - else{ - fifo_fill = (fifo->size + fifo->write_idx) - fifo->read_idx; - } - return fifo_fill; - } -} - -static inline void fifo_init_short(volatile mem_fifo_short_t * unsafe fifo) { - unsafe{ - fifo->write_idx = 0; - fifo->read_idx = (fifo->size * 2) / 4; - memset(fifo->data_base_ptr , 0, fifo->size * sizeof(short)); - } -} - -#pragma unsafe arrays -static inline fifo_ret_t fifo_block_push(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { - unsafe{ - //check there is a block of space large enough - unsigned space_remaining = fifo->size - fifo_get_fill(fifo) - 1; - if (n > space_remaining) { - return FIFO_FULL; - } - for (int i = 0; i < n; i++){ - unsigned next_idx = fifo->write_idx + 1; - if (next_idx == fifo->size) next_idx = 0; //Check for wrap - fifo->data_base_ptr[fifo->write_idx] = data[i]; - fifo->write_idx = next_idx; - } - return FIFO_SUCCESS; - } -} - -#pragma unsafe arrays -static inline fifo_ret_t fifo_block_push_short(volatile mem_fifo_short_t * unsafe fifo, short data[], unsigned n) { - unsafe{ - //check there is a block of space large enough - unsigned space_remaining = fifo->size - fifo_get_fill_short(fifo) - 1; - if (n > space_remaining) { - return FIFO_FULL; - } - for (int i = 0; i < n; i++){ - unsigned next_idx = fifo->write_idx + 1; - if (next_idx == fifo->size) next_idx = 0; //Check for wrap - fifo->data_base_ptr[fifo->write_idx] = data[i]; - fifo->write_idx = next_idx; - } - return FIFO_SUCCESS; - } -} - -#pragma unsafe arrays -static inline fifo_ret_t fifo_block_push_short_fast(volatile mem_fifo_short_t * unsafe fifo, short data[], unsigned n) { - unsafe{ - //check there is a block of space large enough - unsigned space_remaining = fifo->size - fifo_get_fill_short(fifo) - 1; - if (n > space_remaining) { - return FIFO_FULL; - } - //We will write either one or two blocks depending on wrap - unsigned first_block_size = 0; - unsigned second_block_size = 0; - - //See if we need to wrap during block writes - unsigned space_left_at_top = fifo->size - fifo->write_idx; - //printf("space_left_at_top %d\n", space_left_at_top); - //Yes, we do need to wrap - if (n > space_left_at_top){ - first_block_size = space_left_at_top; - second_block_size = n - space_left_at_top; - memcpy(&fifo->data_base_ptr[fifo->write_idx], &data[0], first_block_size * sizeof(short)); - memcpy(&fifo->data_base_ptr[0], &data[first_block_size], second_block_size * sizeof(short)); - fifo->write_idx = second_block_size; - } - //No wrap, do all in one go - else{ - first_block_size = n; - second_block_size = 0; - memcpy(&fifo->data_base_ptr[fifo->write_idx], &data[0], first_block_size * sizeof(short)); - fifo->write_idx += first_block_size; - } - - return FIFO_SUCCESS; - } -} - -#pragma unsafe arrays -static inline fifo_ret_t fifo_block_pop(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { - unsafe{ - //Check we have a block big enough to send - if (n > fifo_get_fill(fifo)){ - return FIFO_EMPTY; - } - for (int i = 0; i < n; i++){ - data[i] = fifo->data_base_ptr[fifo->read_idx]; - fifo->read_idx++; - if (fifo->read_idx == fifo->size) fifo->read_idx = 0; //Check for wrap - } - return FIFO_SUCCESS; - } -} - -#pragma unsafe arrays -static inline fifo_ret_t fifo_block_pop_short(volatile mem_fifo_short_t * unsafe fifo, short data[], unsigned n) { - unsafe{ - //Check we have a block big enough to send - if (n > fifo_get_fill_short(fifo)){ - return FIFO_EMPTY; - } - for (int i = 0; i < n; i++){ - data[i] = fifo->data_base_ptr[fifo->read_idx]; - fifo->read_idx++; - if (fifo->read_idx == fifo->size) fifo->read_idx = 0; //Check for wrap - } - return FIFO_SUCCESS; - } -} - -#pragma unsafe arrays -static inline fifo_ret_t fifo_block_pop_short_fast(volatile mem_fifo_short_t * unsafe fifo, short data[], unsigned n) { - unsafe{ - //Check we have a block big enough to send - if (n > fifo_get_fill_short(fifo)){ - return FIFO_EMPTY; - } - //We will read either one or two blocks depending on wrap - unsigned first_block_size = 0; - unsigned second_block_size = 0; - - //See if we need to wrap during block read - unsigned num_read_at_top = fifo->size - fifo->read_idx; - // printf("num_read_at_top %d\n", num_read_at_top); - //Yes, we do need to wrap - if (n > num_read_at_top){ - first_block_size = num_read_at_top; - second_block_size = n - num_read_at_top; - memcpy(&data[0], &fifo->data_base_ptr[fifo->read_idx], first_block_size * sizeof(short)); - memcpy( &data[first_block_size], &fifo->data_base_ptr[0], second_block_size * sizeof(short)); - fifo->read_idx = second_block_size; - // printf("wrap\n"); - } - //No wrap, do all in one go - else{ - first_block_size = n; - second_block_size = 0; - memcpy(&data[0], &fifo->data_base_ptr[fifo->read_idx], first_block_size * sizeof(short)); - fifo->read_idx += first_block_size; - // printf("no wrap\n"); - - } - - return FIFO_SUCCESS; - } -} - -//Version of above that returns fill level relative to half full -static inline int fifo_get_fill_relative_half(volatile mem_fifo_t * unsafe fifo){ - unsafe{ - int fifo_fill = (int)fifo_get_fill(fifo); - fifo_fill -= (fifo->size / 2); - return fifo_fill; - } -} - -//Version of above that returns fill level relative to half full -static inline int fifo_get_fill_relative_half_short(volatile mem_fifo_short_t * unsafe fifo){ - unsafe{ - int fifo_fill = (int)fifo_get_fill_short(fifo); - fifo_fill -= (fifo->size / 2); - return fifo_fill; - } -} -#endif diff --git a/examples/xua_lite_example/xua_lite/rate_control/fifo_types.h b/examples/xua_lite_example/xua_lite/rate_control/fifo_types.h deleted file mode 100644 index af7994e7..00000000 --- a/examples/xua_lite_example/xua_lite/rate_control/fifo_types.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __ASRC_FIFO_TYPES__ -#define __ASRC_FIFO_TYPES__ -#include - -//Shared FIFO return types -typedef enum fifo_ret_t { - FIFO_SUCCESS = 0, - FIFO_FULL, - FIFO_EMPTY -} fifo_ret_t; - -///////////////////////////////////////////////////////////////////////// -//Shared memory FIFO (sample by sample or block) -//Can be any size -// -//Note that the actual storage for the FIFO is declared externally -//and a reference to the base address of the storage is passed in along -//with the size of the storage. This way, multiple instances may be -//different sizes. -// -///////////////////////////////////////////////////////////////////////// - -typedef struct mem_fifo_t { - const unsigned size; //Size in INTs - int * const unsafe data_base_ptr; //Base of the data array - declared externally so we can have differnt sized FIFOs - unsigned write_idx; - unsigned read_idx; -} mem_fifo_t; - -typedef struct mem_fifo_short_t { - const unsigned size; //Size in SHORTs - short * const unsafe data_base_ptr; //Base of the data array - declared externally so we can have differnt sized FIFOs - unsigned write_idx; - unsigned read_idx; -} mem_fifo_short_t; - -#endif diff --git a/examples/xua_lite_example/xua_lite/rate_control/rate_controller.h b/examples/xua_lite_example/xua_lite/rate_control/rate_controller.h deleted file mode 100644 index 8dee3f75..00000000 --- a/examples/xua_lite_example/xua_lite/rate_control/rate_controller.h +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -typedef int32_t xua_lite_fixed_point_t; - -typedef struct pid_state_t{ - xua_lite_fixed_point_t fifo_level_filtered_old; - xua_lite_fixed_point_t fifo_level_accum; -} pid_state_t; - - -//USB Adaptive mode helper -xua_lite_fixed_point_t do_rate_control(int fill_level, pid_state_t *pid_state); - -//PDM modulator for clock control -void do_clock_nudge_pdm(xua_lite_fixed_point_t controller_out, int *clock_nudge); - - -//USB Asynch mode helper -void do_feedback_calculation(unsigned &sof_count, const unsigned mclk_hz, unsigned mclk_port_counter,unsigned &mclk_port_counter_old - ,long long &feedback_value, unsigned &mod_from_last_time, unsigned fb_clocks[1]); \ No newline at end of file diff --git a/examples/xua_lite_example/xua_lite/rate_control/rate_controller.xc b/examples/xua_lite_example/xua_lite/rate_control/rate_controller.xc deleted file mode 100644 index 58fddf48..00000000 --- a/examples/xua_lite_example/xua_lite/rate_control/rate_controller.xc +++ /dev/null @@ -1,201 +0,0 @@ -#include -#include "xua_buffer_lite.h" -#include "rate_controller.h" -#define DEBUG_UNIT XUA_RATE_CONTROL -#define DEBUG_PRINT_ENABLE_XUA_RATE_CONTROL 1 -#include "debug_print.h" - -#define XUA_LIGHT_FIXED_POINT_Q_BITS 10 //Including sign bit. 10b gets us to +511.999999 to -512.000000 -#define XUA_LIGHT_FIXED_POINT_TOTAL_BITS (sizeof(xua_lite_fixed_point_t) * 8) -#define XUA_LIGHT_FIXED_POINT_FRAC_BITS (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - XUA_LIGHT_FIXED_POINT_Q_BITS) -#define XUA_LIGHT_FIXED_POINT_ONE (1 << XUA_LIGHT_FIXED_POINT_FRAC_BITS) -#define XUA_LIGHT_FIXED_POINT_MINUS_ONE (-XUA_LIGHT_FIXED_POINT_ONE) - -#define FIFO_LEVEL_EMA_COEFF 0.939 //Proportion of signal from y[-1]. - //0.939 gives ~10Hz 3db cutoff low pass filter for filter rate of 1kHz - //dsp.stackexchange.com/questions/40462/exponential-moving-average-cut-off-frequency/40465 -#define FIFO_LEVEL_A_COEFF ((int32_t)(INT_MAX * FIFO_LEVEL_EMA_COEFF)) //Scale to signed 1.31 format -#define FIFO_LEVEL_B_COEFF (INT_MAX - FIFO_LEVEL_A_COEFF) - -#define RANDOMISATION_PERCENT 20 //How much radnom noise to inject in percent of existing signal amplitude -#define RANDOMISATION_COEFF_A ((INT_MAX / 100) * RANDOMISATION_PERCENT) - -#define PID_CALC_OVERHEAD_BITS 2 //Allow large P,I or D constants, up to 2^(this number) - - -#define PID_CONTROL_P_TERM 10.0 -#define PID_CONTROL_I_TERM 150.0 -#define PID_CONTROL_D_TERM 1.0 - -#define PID_RATE_MULTIPLIER SOF_FREQ_HZ - -#define PID_CONTROL_P_TERM_COEFF ((xua_lite_fixed_point_t)((XUA_LIGHT_FIXED_POINT_ONE >> PID_CALC_OVERHEAD_BITS) * (float)PID_CONTROL_P_TERM)) //scale to fixed point -#define PID_CONTROL_I_TERM_COEFF ((xua_lite_fixed_point_t)((XUA_LIGHT_FIXED_POINT_ONE >> PID_CALC_OVERHEAD_BITS) * (float)PID_CONTROL_I_TERM / PID_RATE_MULTIPLIER)) //scale to fixed point -#define PID_CONTROL_D_TERM_COEFF ((xua_lite_fixed_point_t)((XUA_LIGHT_FIXED_POINT_ONE >> PID_CALC_OVERHEAD_BITS) * (float)PID_CONTROL_D_TERM * PID_RATE_MULTIPLIER)) //scale to fixed point - - -static inline xua_lite_fixed_point_t do_fifo_depth_lowpass_filter(xua_lite_fixed_point_t old, int fifo_depth){ - //we grow from 32b to 64b for intermediate - int64_t intermediate = ((int64_t)(fifo_depth << XUA_LIGHT_FIXED_POINT_FRAC_BITS) * (int64_t)FIFO_LEVEL_B_COEFF) + ((int64_t)old * (int64_t)FIFO_LEVEL_A_COEFF); - xua_lite_fixed_point_t new_fifo_depth = (xua_lite_fixed_point_t)( intermediate >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); //-1 because signed int - return new_fifo_depth; -} - -static inline int32_t get_random_number(void) -{ - static const unsigned random_poly = 0xEDB88320; - static unsigned random = 0x12345678; - crc32(random, -1, random_poly); - return (int32_t) random; -} - -static inline xua_lite_fixed_point_t add_noise(xua_lite_fixed_point_t input){ - //Note the input number cannot be bigger than 2 ^ (FIXED_POINT_Q_BITS - 1) * (1 + PERCENT) else we could oveflow - //Eg. if Q bits = 10 then biggest input value is 255.9999 - int32_t random = get_random_number(); - int32_t input_fraction = ((int64_t)input * (int64_t)RANDOMISATION_COEFF_A) >> (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1); - int64_t output_64 = ((int64_t)input << (XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)) + ((int64_t)input_fraction * (int64_t)random); - return (xua_lite_fixed_point_t)( output_64 >> (64 - XUA_LIGHT_FIXED_POINT_TOTAL_BITS - 1)); -} - -//Convert the control input into a pdm output (dither) with optional noise -void do_clock_nudge_pdm(xua_lite_fixed_point_t controller_out, int *clock_nudge){ - - //Randomise - add a proportion of rectangular probability distribution noise to spread the spectrum - controller_out = add_noise(controller_out); - - //Convert to pulse density modulation (sigma-delta) - static xua_lite_fixed_point_t nudge_accumulator = 0; - nudge_accumulator += controller_out; //Note no overflow check as if we reach XUA_LIGHT_FIXED_POINT_Q_BITS - //something is very wrong - //printf("co: %d ratio: %f \n", controller_out, (float)controller_out/XUA_LIGHT_FIXED_POINT_ONE); - if (nudge_accumulator >= XUA_LIGHT_FIXED_POINT_ONE){ - *clock_nudge = 1; - nudge_accumulator -= XUA_LIGHT_FIXED_POINT_ONE; - } - else if (nudge_accumulator <= XUA_LIGHT_FIXED_POINT_MINUS_ONE){ - nudge_accumulator -= XUA_LIGHT_FIXED_POINT_MINUS_ONE; - *clock_nudge = -1; - } - else{ - *clock_nudge = 0; - } -} - - -//Do PI control and modulation for adaptive USB audio -xua_lite_fixed_point_t do_rate_control(int fill_level, pid_state_t *pid_state){ - - //We always check the FIFO level after USB has produced a block, and total FIFO size is 2x max, so half full is at 3/4 - const int half_full = ((MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2) * 3) / 4; - int fill_level_wrt_half = fill_level - half_full; //Will be +ve for more than half full and negative for less than half full - - //Low pass filter fill level and get error w.r.t. to set point which is depth = 0 (relative to half full) - xua_lite_fixed_point_t fifo_level_filtered = do_fifo_depth_lowpass_filter(pid_state->fifo_level_filtered_old , fill_level_wrt_half); - //printf("old fill_level: %f fill_level: %f\n", (float)pid_state->fifo_level_filtered_old/(1<fifo_level_accum + fifo_level_filtered; - - //clip the I term (which can wind up) to maximum fixed point representation. Check to see if overflow (which will change sign) - if (fifo_level_filtered >= 0){ //If it was positive before, ensure it still is else clip to positive - if (i_term_pre_clip >= pid_state->fifo_level_accum){ - //debug_printf("grow %d %d\n", (int32_t)i_term_pre_clip, (int32_t)pid_state->fifo_level_accum); - pid_state->fifo_level_accum = i_term_pre_clip; - } - else{ - pid_state->fifo_level_accum = INT_MAX; - //debug_printf("clip+ %d\n", pid_state->fifo_level_accum); - } - } - else{ //Value was negative so ensure it still is else clip negative - if (i_term_pre_clip <= pid_state->fifo_level_accum){ - pid_state->fifo_level_accum = i_term_pre_clip; - } - else{ - pid_state->fifo_level_accum = INT_MIN; - //debug_printf("clip- %d %d\n", pid_state->fifo_level_accum, fifo_level_filtered); - } - } - - //Calculate D term. No clipping required because it can never be larger than the D term, - //which is already scaled to fit within the fixed point representation - xua_lite_fixed_point_t fifo_level_delta = fifo_level_filtered - pid_state->fifo_level_filtered_old; - - //Save to struct for next iteration - pid_state->fifo_level_filtered_old = fifo_level_filtered; - - //Do PID calculation. Note there is an implicit cast back to xua_lite_fixed_point_t before assignment - xua_lite_fixed_point_t p_term = (((int64_t) fifo_level_filtered * (int64_t)PID_CONTROL_P_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; - xua_lite_fixed_point_t i_term = (((int64_t) pid_state->fifo_level_accum * (int64_t)PID_CONTROL_I_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; - xua_lite_fixed_point_t d_term = (((int64_t) fifo_level_delta * (int64_t)PID_CONTROL_D_TERM_COEFF)) >> XUA_LIGHT_FIXED_POINT_FRAC_BITS; - - //debug_printf("p: %d i: %d f: %d\n", p_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, i_term >> XUA_LIGHT_FIXED_POINT_Q_BITS, fifo_level_filtered >> (XUA_LIGHT_FIXED_POINT_FRAC_BITS - 10)); - //printf("p: %f i: %f d: %f filtered: %f integrated: %f\n", (float)p_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)i_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)d_term / (1<<(XUA_LIGHT_FIXED_POINT_FRAC_BITS-PID_CALC_OVERHEAD_BITS)), (float)fifo_level_filtered/(1<fifo_level_accum/(1<> (XUA_LIGHT_FIXED_POINT_Q_BITS - 1 - PID_CALC_OVERHEAD_BITS); - - - //debug_printf("filtered: %d raw: %d\n", fifo_level_filtered >> 22, fill_level_wrt_half); - - //static unsigned counter; counter++; if (counter>100){counter = 0; debug_printf("pid: %d\n",i_term >> (XUA_LIGHT_FIXED_POINT_FRAC_BITS - 10));} - debug_printf("co: %d\n", controller_out >> XUA_LIGHT_FIXED_POINT_FRAC_BITS); - return controller_out; -} - - -//Calculate feedback for asynchronous USB audio -void do_feedback_calculation(unsigned &sof_count - ,const unsigned mclk_hz - ,unsigned mclk_port_counter - ,unsigned &mclk_port_counter_old - ,long long &feedback_value - ,unsigned &mod_from_last_time - ,unsigned fb_clocks[1]){ - // Assuming 48kHz from a 24.576 master clock (0.0407uS period) - // MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. - // expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. - // Average over 128 SOFs - 128 x 3072 = 0x60000. - - unsigned long long feedbackMul = 64ULL; - if(AUDIO_CLASS == 1) feedbackMul = 8ULL; // TODO Use 4 instead of 8 to avoid windows LSB issues? - - // Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) - int mclk_ticks_this_sof_period = (int) ((short)(mclk_port_counter - mclk_port_counter_old)); - unsigned long long full_result = mclk_ticks_this_sof_period * feedbackMul * DEFAULT_FREQ; - feedback_value += full_result; - - // Store MCLK for next time around... - mclk_port_counter_old = mclk_port_counter; - - // Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll - // We always count 128 SOFs, so 16ms @ HS, 128ms @ FS - if(sof_count == 128){ - //debug_printf("fb\n"); - sof_count = 0; - - feedback_value += mod_from_last_time; - unsigned clocks = feedback_value / mclk_hz; - mod_from_last_time = feedback_value % mclk_hz; - feedback_value = 0; - - //Scale for working out number of samps to take from device for input - if(AUDIO_CLASS == 2){ - clocks <<= 3; - } - else{ - clocks <<= 6; - } - asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks - - //Write to feedback EP buffer - if (AUDIO_CLASS == 2){ - fb_clocks[0] = clocks; - } - else{ - fb_clocks[0] = clocks >> 2; - } - } -} - diff --git a/examples/xua_lite_example/xua_lite/xua_buffer_lite.h b/examples/xua_lite_example/xua_lite/xua_buffer_lite.h deleted file mode 100644 index 8ac52765..00000000 --- a/examples/xua_lite_example/xua_lite/xua_buffer_lite.h +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include "xua_ep0_wrapper.h" -#include "xua.h" - -//Currently only single frequency supported -#define NOMINAL_SR_DEVICE DEFAULT_FREQ -#define NOMINAL_SR_HOST DEFAULT_FREQ - -#define DIV_ROUND_UP(n, d) (n / d + 1) //Always rounds up to the next integer. Needed for 48001Hz case etc. -#define BIGGEST(a, b) (a > b ? a : b) - -#define SOF_FREQ_HZ (8000 - ((2 - AUDIO_CLASS) * 7000) ) //1000 for FS or 8000 for HS - -//Defines for endpoint buffer sizes. Samples is total number of samples across all channels -#define MAX_OUT_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_OUT) -#define MAX_IN_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_IN) -#define MAX_OUTPUT_SLOT_SIZE 4 -#define MAX_INPUT_SLOT_SIZE 4 - -#define OUT_AUDIO_BUFFER_SIZE_BYTES (MAX_OUT_SAMPLES_PER_SOF_PERIOD * MAX_OUTPUT_SLOT_SIZE) -#define IN_AUDIO_BUFFER_SIZE_BYTES (MAX_IN_SAMPLES_PER_SOF_PERIOD * MAX_INPUT_SLOT_SIZE) - -unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); -[[combinable]] -unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub); - -/** Transfer samples to/from XUA. Should be called at the current USB rate. - * This function is non-blocking. - * - * \param[in,out] c_audio Channel to XUA. - * - * \param[out] sampsFromUsbToAudio Samples sent from host to device. - * - * \param[in] sampsFromAudioToUsb Samples to send from device to host. - * - * \param[out] clock_nudge Notification that the device is running - * too slowly/quickly. Only used when in - * adaptive endpoint mode. - */ -static inline void XUA_transfer_samples(streaming chanend c_audio, - unsigned sampsFromUsbToAudio[], - unsigned sampsFromAudioToUsb[], - int &clock_nudge) { - //Transfer samples. Takes about 25 ticks - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> sampsFromUsbToAudio[i]; - if (XUA_ADAPTIVE) c_audio :> clock_nudge; - for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: sampsFromAudioToUsb[i]; -} diff --git a/examples/xua_lite_example/xua_lite/xua_buffer_lite.xc b/examples/xua_lite_example/xua_lite/xua_buffer_lite.xc deleted file mode 100644 index 597cb938..00000000 --- a/examples/xua_lite_example/xua_lite/xua_buffer_lite.xc +++ /dev/null @@ -1,384 +0,0 @@ -#include -#include -#include - -#include "xua_commands.h" -#include "xud.h" -#include "testct_byref.h" -#define DEBUG_UNIT XUA_LITE_BUFFER -#define DEBUG_PRINT_ENABLE_XUA_LITE_BUFFER 1 -#include "debug_print.h" -#include "xua.h" -#include "fifo_impl.h" -#include "xua_ep0_wrapper.h" -#include "rate_controller.h" -#include "xua_buffer_lite.h" - - -extern "C"{ -void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); -void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_, unsigned *input_interface_num, unsigned *output_interface_num); -} -#pragma select handler -void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Result_t &result); - -extern XUD_ep ep0_out; -extern XUD_ep ep0_in; - -#if 0 -//Unsafe to allow us to use fifo API without local unsafe scope -unsafe void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { - - debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); - - //These buffers are unions so we can access them as different types - union buffer_aud_out{ - unsigned char bytes[OUT_AUDIO_BUFFER_SIZE_BYTES]; - short short_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 2]; - long long_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 4]; - }buffer_aud_out; - union buffer_aud_in{ - unsigned char bytes[IN_AUDIO_BUFFER_SIZE_BYTES]; - short short_words[IN_AUDIO_BUFFER_SIZE_BYTES / 2]; - unsigned long long_words[IN_AUDIO_BUFFER_SIZE_BYTES / 4]; - }buffer_aud_in; - - unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; - unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - - //Asynch feedback calculation - unsigned sof_count = 0; - unsigned mclk_port_counter_old = 0; - long long feedback_value = 0; - unsigned mod_from_last_time = 0; - const unsigned mclk_hz = MCLK_48; - unsigned int fb_clocks[1] = {0}; - - //Adapative device clock control - int clock_nudge = 0; - pid_state_t pid_state = {0, 0}; - - //Endpoints - XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); - XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); - XUD_ep ep_feedback = 0; - if (!isnull(c_feedback)) ep_feedback = XUD_InitEp(c_feedback); - - unsigned num_samples_received_from_host = 0; - unsigned num_samples_to_send_to_host = 0; - - short samples_in_short[NUM_USB_CHAN_IN] = {0}; - short samples_out_short[NUM_USB_CHAN_OUT] = {0}; - - #define c_audioControl null - #define dfuInterface null - XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, c_audioControl, null, null, null, dfuInterface); - unsigned char sbuffer[120]; //Raw buffer for EP0 data - USB_SetupPacket_t sp; //Parsed setup packet from EP0 - - unsigned input_interface_num = 0; - unsigned output_interface_num = 0; - - //Enable all EPs - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, num_samples_to_send_to_host); - XUD_SetReady_Out(ep0_out, sbuffer); - if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); - - - //Send initial samples so audiohub is not blocked - for (int i = 0; i < 2 * (NUM_USB_CHAN_OUT + (XUA_ADAPTIVE != 0 ? 1 : 0)); i++) c_audio_hub <: 0; - - //FIFOs from EP buffers to audio - short host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; - short device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; - mem_fifo_short_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; - mem_fifo_short_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; - volatile mem_fifo_short_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; - volatile mem_fifo_short_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; - - //XUD transaction variables passed in by reference - XUD_Result_t result; - unsigned length = 0; - unsigned u_tmp; //For select channel input by ref on EP0 - int s_tmp; //For select on channel from audiohub - while(1){ - #pragma ordered - select{ - //Handle EP0 requests - case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): - timer tmr; int t0, t1; tmr :> t0; - - debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error - USB_ParseSetupPacket(sbuffer, sp); //Parse data buffer end populate SetupPacket struct - - XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, null/*mix*/, null/*clk*/, null/*EA*/, dfuInterface, &input_interface_num, &output_interface_num); - XUD_SetReady_Out(ep0_out, sbuffer); - tmr :> t1; debug_printf("c%d\n", t1 - t0); - - break; - - //SOF handling - case inuint_byref(c_sof, u_tmp): - timer tmr; int t0, t1; tmr :> t0; - unsigned mclk_port_counter = 0; - asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); - if (!isnull(c_feedback)) do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); - sof_count++; - tmr :> t1; debug_printf("s%d\n", t1 - t0); - - break; - - //Receive samples from host - case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): - timer tmr; int t0, t1; tmr :> t0; - - num_samples_received_from_host = length / out_subslot_size; - - fifo_ret_t ret = fifo_block_push_short(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); - num_samples_to_send_to_host = num_samples_received_from_host; - - int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); - if (isnull(c_feedback)) do_clock_nudge_pdm(do_rate_control(fill_level, &pid_state), &clock_nudge); - - //Mark EP as ready for next frame from host - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); - tmr :> t1; debug_printf("o%d\n", t1 - t0); - break; - - //Send asynch explicit feedback value, but only if enabled - case !isnull(c_feedback) => XUD_SetData_Select(c_feedback, ep_feedback, result): - timer tmr; int t0, t1; tmr :> t0; - - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); - //debug_printf("0x%x\n", fb_clocks[0]); - tmr :> t1; debug_printf("f%d\n", t1 - t0); - - break; - - //Send samples to host - case XUD_SetData_Select(c_aud_in, ep_aud_in, result): - timer tmr; int t0, t1; tmr :> t0; - - if (output_interface_num == 0) num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; - - fifo_ret_t ret = fifo_block_pop_short(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("d2h empty\n"); - - //Populate the input buffer ready for the next read - //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); - //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - - unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, input_buffer_size); //loopback - num_samples_to_send_to_host = 0; - tmr :> t1; debug_printf("i%d\n", t1 - t0); - - break; - - //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO - case c_audio_hub :> s_tmp: - timer tmr; int t0, t1; tmr :> t0; - samples_in_short[0] = s_tmp >> 16; - for (int i = 1; i < NUM_USB_CHAN_IN; i++){ - c_audio_hub :> s_tmp; - samples_in_short[i] = s_tmp >> 16; - } - fifo_ret_t ret = fifo_block_pop_short(host_to_device_fifo_ptr, samples_out_short, NUM_USB_CHAN_OUT); - if (ret != FIFO_SUCCESS && output_interface_num != 0) debug_printf("h2d empty\n"); - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: (int)samples_out_short[i] << 16; - if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; - ret = fifo_block_push_short(device_to_host_fifo_ptr, samples_in_short, NUM_USB_CHAN_IN); - if (ret != FIFO_SUCCESS && input_interface_num != 0) debug_printf("d2h full\n"); - tmr :> t1; debug_printf("a%d\n", t1 - t0); - break; - } - } -} -#endif -extern port p_sda; - -[[combinable]] -//Unsafe to allow us to use fifo API without local unsafe scope -unsafe void XUA_Buffer_lite2(server ep0_control_if i_ep0_ctl, chanend c_aud_out, chanend ?c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_audio_hub) { - - debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); - - //These buffers are unions so we can access them as different types - union buffer_aud_out{ - unsigned char bytes[OUT_AUDIO_BUFFER_SIZE_BYTES]; - short short_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 2]; - long long_words[OUT_AUDIO_BUFFER_SIZE_BYTES / 4]; - }buffer_aud_out; - union buffer_aud_in{ - unsigned char bytes[IN_AUDIO_BUFFER_SIZE_BYTES]; - short short_words[IN_AUDIO_BUFFER_SIZE_BYTES / 2]; - unsigned long long_words[IN_AUDIO_BUFFER_SIZE_BYTES / 4]; - }buffer_aud_in; - - unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; - unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - - //Asynch feedback calculation - unsigned sof_count = 0; - unsigned mclk_port_counter_old = 0; - long long feedback_value = 0; - unsigned mod_from_last_time = 0; - const unsigned mclk_hz = MCLK_48; - unsigned int fb_clocks[1] = {0}; - - //Adapative device clock control - int clock_nudge = 0; - pid_state_t pid_state = {0, 0}; - - - //Endpoints - XUD_ep ep_aud_out = XUD_InitEp(c_aud_out); - XUD_ep ep_aud_in = XUD_InitEp(c_aud_in); - XUD_ep ep_feedback = 0; - if (!isnull(c_feedback)) ep_feedback = XUD_InitEp(c_feedback); - - unsigned num_samples_received_from_host = 0; - unsigned num_samples_to_send_to_host = 0; - - unsigned input_interface_num = 0; - unsigned output_interface_num = 0; - - //Enable all EPs - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in.long_words, num_samples_to_send_to_host); - if (!isnull(c_feedback)) XUD_SetReady_InPtr(ep_feedback, (unsigned)fb_clocks, (AUDIO_CLASS == 2) ? 4 : 3); - - short samples_in_short[NUM_USB_CHAN_IN] = {0}; - short samples_out_short[NUM_USB_CHAN_OUT] = {0}; - - - //Send initial samples so audiohub is not blocked - const unsigned n_sample_periods_to_preload = 2; - for (int i = 0; i < n_sample_periods_to_preload * (NUM_USB_CHAN_OUT + (XUA_ADAPTIVE != 0 ? 1 : 0)); i++) c_audio_hub <: 0; - - //FIFOs from EP buffers to audio - short host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; - short device_to_host_fifo_storage[MAX_IN_SAMPLES_PER_SOF_PERIOD * 2]; - mem_fifo_short_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]), host_to_device_fifo_storage, 0, 0}; - mem_fifo_short_t device_to_host_fifo = {sizeof(device_to_host_fifo_storage)/sizeof(device_to_host_fifo_storage[0]), device_to_host_fifo_storage, 0, 0}; - volatile mem_fifo_short_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; - volatile mem_fifo_short_t * unsafe device_to_host_fifo_ptr = &device_to_host_fifo; - - //XUD transaction variables passed in by reference - XUD_Result_t result; - unsigned length = 0; - unsigned u_tmp; //For select channel input by ref on EP0 - int s_tmp; //For select on channel from audiohub - while(1){ - select{ - //Handle EP0 requests - case i_ep0_ctl.set_output_interface(unsigned num): - //Reset output FIFO if moving from idle to streaming - if (num != 0 && output_interface_num == 0) fifo_init_short(host_to_device_fifo_ptr); - output_interface_num = num; - debug_printf("output_interface_num: %d\n", num); - break; - - case i_ep0_ctl.set_input_interface(unsigned num): - input_interface_num = num; - debug_printf("input_interface_num: %d\n", num); - break; - - case i_ep0_ctl.set_host_active(unsigned active): - break; - - //SOF handling - case inuint_byref(c_sof, u_tmp): - timer tmr; int t0, t1; tmr :> t0; - unsigned mclk_port_counter = 0; - asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_counter) : "r" (p_for_mclk_count)); - if (!isnull(c_feedback)) do_feedback_calculation(sof_count, mclk_hz, mclk_port_counter, mclk_port_counter_old, feedback_value, mod_from_last_time, fb_clocks); - sof_count++; - //tmr :> t1; debug_printf("s%d\n", t1 - t0); - uint16_t port_counter; - p_sda <: 1 @ port_counter; - p_sda @ port_counter + 100 <: 0; - break; - - //Receive samples from host - case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): - timer tmr; int t0, t1; tmr :> t0; - - num_samples_received_from_host = length / out_subslot_size; - - if (num_samples_received_from_host != 96) debug_printf("hs: %d\n", num_samples_received_from_host); - - fifo_ret_t ret = fifo_block_push_short_fast(host_to_device_fifo_ptr, buffer_aud_out.short_words, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) debug_printf("h2d full\n"); - num_samples_to_send_to_host = num_samples_received_from_host; - - int fill_level = fifo_get_fill_short(host_to_device_fifo_ptr); - if (isnull(c_feedback)) do_clock_nudge_pdm(do_rate_control(fill_level, &pid_state), &clock_nudge); - - //Mark EP as ready for next frame from host - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out.long_words); - //tmr :> t1; debug_printf("o%d\n", t1 - t0); - break; - - //Send asynch explicit feedback value, but only if enabled - case !isnull(c_feedback) => XUD_SetData_Select(c_feedback, ep_feedback, result): - timer tmr; int t0, t1; tmr :> t0; - - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), (AUDIO_CLASS == 2) ? 4 : 3); - //debug_printf("0x%x\n", fb_clocks[0]); - //tmr :> t1; debug_printf("f%d\n", t1 - t0); - break; - - //Send samples to host - case XUD_SetData_Select(c_aud_in, ep_aud_in, result): - timer tmr; int t0, t1; tmr :> t0; - - //If host is not streaming out, then send a fixed number of samples to host - if (output_interface_num == 0) { - num_samples_to_send_to_host = (DEFAULT_FREQ / SOF_FREQ_HZ) * NUM_USB_CHAN_IN; - int fill_level = fifo_get_fill_short(device_to_host_fifo_ptr); - if (isnull(c_feedback)) do_clock_nudge_pdm(-do_rate_control(fill_level, &pid_state), &clock_nudge); - } - - fifo_ret_t ret = fifo_block_pop_short_fast(device_to_host_fifo_ptr, buffer_aud_in.short_words, num_samples_received_from_host); - if (ret != FIFO_SUCCESS) { - memset(buffer_aud_in.short_words, 0, sizeof(buffer_aud_in.short_words)); - debug_printf("d2h empty\n"); - } - - //Populate the input buffer ready for the next read - //pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); - //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - - unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; - XUD_SetReady_InPtr(ep_aud_in, (unsigned) buffer_aud_in.long_words, input_buffer_size); //loopback - num_samples_to_send_to_host = 0; - //tmr :> t1; debug_printf("i%d\n", t1 - t0); - break; - - //Exchange samples with audiohub. Note we are using channel buffering here to act as a FIFO - case c_audio_hub :> s_tmp: - timer tmr; int t0, t1; tmr :> t0; - samples_in_short[0] = s_tmp >> 16; - for (int i = 1; i < NUM_USB_CHAN_IN; i++){ - c_audio_hub :> s_tmp; - samples_in_short[i] = s_tmp >> 16; - } - fifo_ret_t ret = fifo_block_pop_short(host_to_device_fifo_ptr, samples_out_short, NUM_USB_CHAN_OUT); - if (ret != FIFO_SUCCESS && output_interface_num != 0) { - memset(samples_out_short, 0, sizeof(samples_out_short)); - debug_printf("h2d empty\n"); - } - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: (int)samples_out_short[i] << 16; - if (XUA_ADAPTIVE) c_audio_hub <: clock_nudge; - ret = fifo_block_push_short(device_to_host_fifo_ptr, samples_in_short, NUM_USB_CHAN_IN); - if (ret != FIFO_SUCCESS && input_interface_num != 0) debug_printf("d2h full\n"); - //tmr :> t1; debug_printf("a%d\n", t1 - t0); - break; - } - } -} diff --git a/examples/xua_lite_example/xua_lite/xua_buffer_pack.h b/examples/xua_lite_example/xua_lite/xua_buffer_pack.h deleted file mode 100644 index 36fc2f33..00000000 --- a/examples/xua_lite_example/xua_lite/xua_buffer_pack.h +++ /dev/null @@ -1,65 +0,0 @@ -//Helper to disassemble USB packets into 32b left aligned audio samples -#pragma unsafe arrays -static inline void unpack_buff_to_samples(unsigned char input[], const unsigned n_samples, const unsigned slot_size, int output[]){ - switch(slot_size){ - case 4: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 4; - output[i] = (input[base + 3] << 24) | (input[base + 2] << 16) | (input[base + 1] << 8) | input[base + 0]; - } - break; - case 3: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 3; - output[i] = (input[base + 2] << 24) | (input[base + 1] << 16) | (input[base + 0] << 8); - } - break; - case 2: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 2; - output[i] = (input[base + 1] << 24) | (input[base + 0] << 16); - } - break; - default: - debug_printf("Invalid slot_size\n"); - break; - } -} - -//Helper to assemble USB packets from 32b left aligned audio samples -#pragma unsafe arrays -static inline void pack_samples_to_buff(int input[], const unsigned n_samples, const unsigned slot_size, unsigned char output[]){ - switch(slot_size){ - case 4: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 4; - unsigned in_word = (unsigned)input[i]; - output[base + 0] = in_word & 0xff; - output[base + 1] = (in_word & 0xff00) >> 8; - output[base + 2] = (in_word & 0xff0000) >> 16; - output[base + 3] = (in_word) >> 24; - } - break; - case 3: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 3; - unsigned in_word = (unsigned)input[i]; - output[base + 0] = (in_word & 0xff00) >> 8; - output[base + 1] = (in_word & 0xff0000) >> 16; - output[base + 2] = (in_word) >> 24; - } - break; - case 2: - for (int i = 0; i < n_samples; i++){ - unsigned base = i * 2; - unsigned in_word = (unsigned)input[i]; - output[base + 0] = (in_word & 0xff0000) >> 16; - output[base + 1] = (in_word) >> 24; - } - break; - default: - debug_printf("Invalid slot_size\n"); - break; - } -} - From 28cce8b51cb0143b430dad35abfc033b4d910bdb Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Wed, 6 Nov 2019 15:12:21 +0000 Subject: [PATCH 115/123] Remove xua_ep0_wrapper.h and xua_ep0_wrapper.xc. Requested by Oscar Bailey as part of github.com/xmos/lib_xua Pull Request #103. --- lib_xua/src/core/endpoint0/xua_ep0_wrapper.h | 27 ---------- lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc | 51 ------------------- 2 files changed, 78 deletions(-) delete mode 100644 lib_xua/src/core/endpoint0/xua_ep0_wrapper.h delete mode 100644 lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.h b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.h deleted file mode 100644 index 8015b95e..00000000 --- a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _EP0_WRAPPER_ -#define _EP0_WRAPPER_ - -#include -#include -#include -#include "xua.h" - -typedef interface ep0_control_if{ - void set_output_interface(unsigned num); - void set_input_interface(unsigned num); - void set_host_active(unsigned num); -}ep0_control_if; - -extern "C"{ -void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); -void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_, unsigned *input_interface_num, unsigned *output_interface_num); -} -#pragma select handler -void XUD_GetSetupData_Select(chanend c, XUD_ep e_out, unsigned &length, XUD_Result_t &result); - -[[combinable]] -void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, client ep0_control_if i_ep0_ctl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_); - -#endif \ No newline at end of file diff --git a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc b/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc deleted file mode 100644 index 092345a0..00000000 --- a/lib_xua/src/core/endpoint0/xua_ep0_wrapper.xc +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include "xua.h" - -#if XUA_USB_EN -#include "xua_ep0_wrapper.h" - -#define DEBUG_UNIT EP0_WRAPPER -#define DEBUG_PRINT_ENABLE_EP0_WRAPPER 0 -#include "debug_print.h" - -extern XUD_ep ep0_out; -extern XUD_ep ep0_in; - -[[combinable]] -void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, client ep0_control_if i_ep0_ctl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) -{ - - USB_SetupPacket_t sp; - XUA_Endpoint0_lite_init(c_ep0_out, c_ep0_in, null, null, null, null, dfuInterface VENDOR_REQUESTS_PARAMS_); - unsigned char sbuffer[120]; - XUD_SetReady_Out(ep0_out, sbuffer); - - unsigned input_interface_num = 0; - unsigned output_interface_num = 0; - - XUD_Result_t result = XUD_RES_ERR; - unsigned length = 0; - - while(1){ - select{ - case XUD_GetSetupData_Select(c_ep0_out, ep0_out, length, result): - if (result == XUD_RES_OKAY) - { - /* Parse data buffer end populate SetupPacket struct */ - USB_ParseSetupPacket(sbuffer, sp); - } - debug_printf("ep0, result: %d, length: %d\n", result, length); //-1 reset, 0 ok, 1 error - - XUA_Endpoint0_lite_loop(result, sp, c_ep0_out, c_ep0_in, null, null, null, null, dfuInterface - VENDOR_REQUESTS_PARAMS_, &input_interface_num, &output_interface_num); - i_ep0_ctl.set_output_interface(output_interface_num); - i_ep0_ctl.set_input_interface(input_interface_num); - - XUD_SetReady_Out(ep0_out, sbuffer); - break; - } - } -} -#endif From a865f4bc51ed39322ba1f5d18fe83d29eac72e44 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Fri, 8 Nov 2019 14:50:01 +0000 Subject: [PATCH 116/123] Add src/hid to the list of source directories. --- lib_xua/module_build_info | 1 + 1 file changed, 1 insertion(+) diff --git a/lib_xua/module_build_info b/lib_xua/module_build_info index edb13e76..f57e59ef 100644 --- a/lib_xua/module_build_info +++ b/lib_xua/module_build_info @@ -62,6 +62,7 @@ SOURCE_DIRS = src/core \ src/core/user/hostactive \ src/core/xuduser \ src/dfu \ + src/hid \ src/midi EXCLUDE_FILES += descriptors_2.rst From 94afffe517cefcd713e7615500b3c21567888c60 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 11 Nov 2019 09:59:02 +0000 Subject: [PATCH 117/123] Corrected change log information and version numbering. --- CHANGELOG.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 21b53f06..c9e8cd07 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,17 +1,17 @@ lib_xua Change Log ================== +0.3.0 +---------- + * ADDED: UAC1 HID support with simulated Voice Command detection reported + every 10 seconds + * ADDED: Support for USB HID Set Idle request + 0.2.1 ----- * HOTFIX: Fix descriptors for XUA_ADAPTIVE -0.2.0_demo ----------- - * ADDED: UAC1 HID support with simulated Voice Command detection reported - every 10 seconds - * ADDED: Support for USB HID Set Idle request - 0.2.0 ----- From 861d20827be636d7aa90bf36996b8e49ee5217d9 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 11 Nov 2019 11:09:30 +0000 Subject: [PATCH 118/123] Change version to 0.3.0 to match change log. --- lib_xua/module_build_info | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/module_build_info b/lib_xua/module_build_info index f57e59ef..b41fc2ff 100644 --- a/lib_xua/module_build_info +++ b/lib_xua/module_build_info @@ -1,4 +1,4 @@ -VERSION = 0.2.1 +VERSION = 0.3.0 DEPENDENT_MODULES = lib_logging(>=3.0.0) \ lib_xassert(>=4.0.0) \ From 41654b17a9a0f3bc8680c44eec3c9dd1fc3c6ae8 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 11 Nov 2019 11:17:48 +0000 Subject: [PATCH 119/123] Fixed bad formatting. --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c9e8cd07..ae7d7c01 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,7 +2,7 @@ lib_xua Change Log ================== 0.3.0 ----------- +----- * ADDED: UAC1 HID support with simulated Voice Command detection reported every 10 seconds * ADDED: Support for USB HID Set Idle request From c7cce77fb2055368c505319d93091e99218cc1c7 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 11 Nov 2019 11:28:13 +0000 Subject: [PATCH 120/123] Added empty line demanded by Jenkins checks. --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ae7d7c01..498faf1e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,7 @@ lib_xua Change Log 0.3.0 ----- + * ADDED: UAC1 HID support with simulated Voice Command detection reported every 10 seconds * ADDED: Support for USB HID Set Idle request From 3f03dae23d8d687c62e8688e7833eab7d5fa23ae Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 11 Nov 2019 13:40:47 +0000 Subject: [PATCH 121/123] Add missing copyright notices. --- lib_xua/src/hid/hid.xc | 1 + lib_xua/src/hid/xua_hid.h | 1 + 2 files changed, 2 insertions(+) diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index bdd5aef3..478bfea5 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -1,3 +1,4 @@ +// Copyright (c) 2019, XMOS Ltd, All rights reserved #include #include "descriptor_defs.h" #include "hid.h" diff --git a/lib_xua/src/hid/xua_hid.h b/lib_xua/src/hid/xua_hid.h index ab8b2e05..23d507e0 100644 --- a/lib_xua/src/hid/xua_hid.h +++ b/lib_xua/src/hid/xua_hid.h @@ -1,3 +1,4 @@ +// Copyright (c) 2019, XMOS Ltd, All rights reserved #include #include #include "xud.h" From b0a26351ce636ec0b0ba5d85002160e7f85912e2 Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Mon, 11 Nov 2019 13:41:07 +0000 Subject: [PATCH 122/123] Update copyright notices. --- lib_xua/api/xua_buffer.h | 2 +- lib_xua/api/xua_conf_default.h | 2 +- lib_xua/src/core/buffer/decouple/decouple.xc | 2 +- lib_xua/src/core/buffer/ep/ep_buffer.xc | 2 +- lib_xua/src/core/endpoint0/descriptor_defs.h | 2 +- lib_xua/src/core/main.xc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index 93ca3219..d351ddc1 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2011-2019, XMOS Ltd, All rights reserved #ifndef __XUA_BUFFER_H__ #define __XUA_BUFFER_H__ diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 5e311e9f..b7bd71cf 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2011-2019, XMOS Ltd, All rights reserved /* * @brief Defines relating to device configuration and customisation of lib_xua * @author Ross Owen, XMOS Limited diff --git a/lib_xua/src/core/buffer/decouple/decouple.xc b/lib_xua/src/core/buffer/decouple/decouple.xc index 8e291aef..297dff8d 100644 --- a/lib_xua/src/core/buffer/decouple/decouple.xc +++ b/lib_xua/src/core/buffer/decouple/decouple.xc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2011-2019, XMOS Ltd, All rights reserved #include "xua.h" #if XUA_USB_EN diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 5916da17..45e08da3 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2011-2019, XMOS Ltd, All rights reserved #include "xua.h" #if XUA_USB_EN #include diff --git a/lib_xua/src/core/endpoint0/descriptor_defs.h b/lib_xua/src/core/endpoint0/descriptor_defs.h index 1f29d58e..0a5a94fd 100644 --- a/lib_xua/src/core/endpoint0/descriptor_defs.h +++ b/lib_xua/src/core/endpoint0/descriptor_defs.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2015-2019, XMOS Ltd, All rights reserved #ifndef __DESCRIPTOR_DEFS_H__ #define __DESCRIPTOR_DEFS_H__ diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 5a7aace0..afc819c4 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2012-2019, XMOS Ltd, All rights reserved #include "xua.h" /* Device specific defines */ #ifndef EXCLUDE_USB_AUDIO_MAIN From ec396961be46e6bdb80e9f0d43ca7debe3fede0a Mon Sep 17 00:00:00 2001 From: Michael Banther Date: Thu, 14 Nov 2019 14:19:51 +0000 Subject: [PATCH 123/123] Remove XUA_Endpoint0_lite_init() and XUA_Endpoint0_lite_loop() functions which are not used. --- lib_xua/src/core/endpoint0/xua_endpoint0.c | 411 --------------------- 1 file changed, 411 deletions(-) diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index 4a4e8882..3c92defa 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -302,31 +302,6 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCont } -void XUA_Endpoint0_lite_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) -{ - ep0_out = XUD_InitEp(c_ep0_out); - ep0_in = XUD_InitEp(c_ep0_in); - - VendorRequests_Init(VENDOR_REQUESTS_PARAMS); - -#ifdef VENDOR_AUDIO_REQS - VendorAudioRequestsInit(c_audioControl, c_mix_ctl, c_clk_ctl); -#endif - -#if (XUA_DFU_EN == 1) - /* Check if device has started in DFU mode */ - if (DFUReportResetState(null)) - { - /* Stop audio */ - outuint(c_audioControl, SET_SAMPLE_FREQ); - outuint(c_audioControl, AUDIO_STOP_FOR_DFU); - /* No Handshake */ - DFU_mode_active = 1; - } -#endif -} - void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { @@ -861,392 +836,6 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 } } -void XUA_Endpoint0_lite_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, - chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_ - , unsigned *input_interface_num, unsigned *output_interface_num) -{ - if (result == XUD_RES_OKAY) - { - result = XUD_RES_ERR; - - /* Inspect Request type and Receipient and direction */ - switch( (sp.bmRequestType.Direction << 7) | (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) ) - { - case USB_BMREQ_H2D_STANDARD_INT: - - /* Over-riding USB_StandardRequests implementation */ - if(sp.bRequest == USB_SET_INTERFACE) - { - switch (sp.wIndex) - { - /* Check for audio stream from host start/stop */ -#if (NUM_USB_CHAN_OUT > 0) - case INTERFACE_NUMBER_AUDIO_OUTPUT: - *output_interface_num = sp.wValue; - break; -#endif - -#if (NUM_USB_CHAN_IN > 0) - case INTERFACE_NUMBER_AUDIO_INPUT: - *input_interface_num = sp.wValue; - break; -#endif - default: - /* Unhandled interface */ - break; - } - } /* if(sp.bRequest == SET_INTERFACE) */ - - break; /* BMREQ_H2D_STANDARD_INT */ - - case USB_BMREQ_D2H_STANDARD_INT: - - switch(sp.bRequest) - { -#if( 0 < HID_CONTROLS ) - case USB_GET_DESCRIPTOR: - - /* Check what inteface request is for */ - if(sp.wIndex == INTERFACE_NUMBER_HID) - { - /* High byte of wValue is descriptor type */ - unsigned descriptorType = sp.wValue & 0xff00; - - switch (descriptorType) - { - case HID_HID: - /* Return HID Descriptor */ - result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, - sizeof(hidDescriptor), sp.wLength); - break; - case HID_REPORT: - /* Return HID report descriptor */ - result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptor, - sizeof(hidReportDescriptor), sp.wLength); - break; - } - } - break; -#endif - default: - break; - } - break; - - /* Recipient: Device */ - case USB_BMREQ_H2D_STANDARD_DEV: - - /* Inspect for actual request */ - switch( sp.bRequest ) - { - /* Standard request: SetConfiguration */ - /* Overriding implementation in USB_StandardRequests */ - case USB_SET_CONFIGURATION: - - //if(g_current_config == 1) - { - /* Consider host active with valid driver at this point */ - UserHostActive(1); - } - - /* We want to run USB_StandardsRequests() implementation also. Don't modify result - * and don't call XUD_DoSetRequestStatus() */ - break; - - default: - //Unknown device request" - break; - } - break; - - /* Audio Class 1.0 Sampling Freqency Requests go to Endpoint */ - case USB_BMREQ_H2D_CLASS_EP: - case USB_BMREQ_D2H_CLASS_EP: - { - unsigned epNum = sp.wIndex & 0xff; - - if ((epNum == ENDPOINT_ADDRESS_OUT_AUDIO) || (epNum == ENDPOINT_ADDRESS_IN_AUDIO)) - { -#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) - if(g_curUsbSpeed == XUD_SPEED_FS) - { - result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } -#elif (AUDIO_CLASS==1) - result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#endif - } - - } - break; - - case USB_BMREQ_H2D_CLASS_INT: - case USB_BMREQ_D2H_CLASS_INT: - { - unsigned interfaceNum = sp.wIndex & 0xff; - //unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5); - - /* TODO Check on return value retval = */ -#if (XUA_DFU_EN == 1) - unsigned DFU_IF = INTERFACE_NUMBER_DFU; - - /* DFU interface number changes based on which mode we are currently running in */ - if (DFU_mode_active) - { - DFU_IF = 0; - } - - if (interfaceNum == DFU_IF) - { - int reset = 0; - - /* If running in application mode stop audio */ - /* Don't interupt audio for save and restore cmds */ - if ((DFU_IF == INTERFACE_NUMBER_DFU) && (sp.bRequest != XMOS_DFU_SAVESTATE) && - (sp.bRequest != XMOS_DFU_RESTORESTATE)) - { - // Stop audio - outuint(c_audioControl, SET_SAMPLE_FREQ); - outuint(c_audioControl, AUDIO_STOP_FOR_DFU); - // Handshake - chkct(c_audioControl, XS1_CT_END); - } - - /* This will return 1 if reset requested */ - result = DFUDeviceRequests(ep0_out, &ep0_in, &sp, null, g_interfaceAlt[sp.wIndex], dfuInterface, &reset); - - if(reset) - { - DFUDelay(50000000); - device_reboot(); - } - } -#endif -#if( 0 < HID_CONTROLS ) - if (interfaceNum == INTERFACE_NUMBER_HID) - { - result = HidInterfaceClassRequests(ep0_out, ep0_in, &sp); - } -#endif - /* Check for: - Audio CONTROL interface request - always 0, note we check for DFU first - * - Audio STREAMING interface request (In or Out) - * - Audio endpoint request (Audio 1.0 Sampling freq requests are sent to the endpoint) - */ - if(((interfaceNum == 0) || (interfaceNum == 1) || (interfaceNum == 2)) - && result == XUD_RES_ERR -#if (XUA_DFU_EN == 1) - && !DFU_mode_active -#endif - ) - { -#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) - if(g_curUsbSpeed == XUD_SPEED_HS) - { - result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } - else - { - result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } -#elif (AUDIO_CLASS==2) - result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#else - result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#endif - -#ifdef VENDOR_AUDIO_REQS - /* If result is ERR at this point, then request to audio interface not handled - handle vendor audio reqs */ - if(result == XUD_RES_ERR) - { - result = VendorAudioRequests(ep0_out, ep0_in, sp.bRequest, - sp.wValue >> 8, sp.wValue & 0xff, - sp.wIndex >> 8, sp.bmRequestType.Direction, - c_audioControl, c_mix_ctl, c_clk_ctl); - } -#endif - } - } - break; - - default: - break; - } - - } /* if(result == XUD_RES_OKAY) */ - - { - if(result == XUD_RES_ERR) - { - /* Run vendor defined parsing/processing */ - /* Note, an interface might seem ideal here but this *must* be executed on the same - * core sure to shared memory depandancy */ - result = VendorRequests(ep0_out, ep0_in, &sp VENDOR_REQUESTS_PARAMS_); - } - } - - if(result == XUD_RES_ERR) - { -#if (XUA_DFU_EN == 1) - if (!DFU_mode_active) - { -#endif -#if (AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS != 1) - /* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */ - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), - cfgDesc_Audio1, sizeof(cfgDesc_Audio1), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), - &sp, g_curUsbSpeed); -#elif FULL_SPEED_AUDIO_2 - /* Return Audio 2.0 Descriptors for high_speed and full-speed */ - - /* Unfortunately we need to munge the descriptors a bit between full and high-speed */ - if(g_curUsbSpeed == XUD_SPEED_HS) - { - /* Modify Audio Class 2.0 Config descriptor for High-speed operation */ -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT; -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format.bBitResolution = HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT; -#endif -#if (OUTPUT_FORMAT_COUNT > 1) - cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT; -#endif - -#if (OUTPUT_FORMAT_COUNT > 2) - cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT; -#endif -#endif -#if (NUM_USB_CHAN_IN > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN; - cfgDesc_Audio2.Audio_In_Format.bSubslotSize = HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_In_Format.bBitResolution = HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN; -#endif - } - else - { - /* Modify Audio Class 2.0 Config descriptor for Full-speed operation */ -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT_FS; -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format.bBitResolution = FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif -#if (OUTPUT_FORMAT_COUNT > 1) - cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif - -#if (OUTPUT_FORMAT_COUNT > 2) - cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif -#endif -#if (NUM_USB_CHAN_IN > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN_FS; - cfgDesc_Audio2.Audio_In_Format.bSubslotSize = FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_In_Format.bBitResolution = FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN_FS; -#endif - } - - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - null, 0, - null, 0, -#ifdef __XC__ - g_strTable, sizeof(g_strTable), sp, null, g_curUsbSpeed); -#else - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#endif -#elif (AUDIO_CLASS == 1) - /* Return Audio 1.0 Descriptors in FS, should never be in HS! */ - result = USB_StandardRequests(ep0_out, ep0_in, - null, 0, - null, 0, - (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), - cfgDesc_Audio1, sizeof(cfgDesc_Audio1), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#else - /* Return Audio 2.0 Descriptors with Null device as fallback */ - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - devDesc_Null, sizeof(devDesc_Null), - cfgDesc_Null, sizeof(cfgDesc_Null), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#endif -#if (XUA_DFU_EN == 1) - } - - else - { - /* Running in DFU mode - always return same descs for DFU whether HS or FS */ - result = USB_StandardRequests(ep0_out, ep0_in, - DFUdevDesc, sizeof(DFUdevDesc), - DFUcfgDesc, sizeof(DFUcfgDesc), - null, 0, /* Used same descriptors for full and high-speed */ - null, 0, - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); - } -#endif - } - - if (result == XUD_RES_RST) - { -#ifdef __XC__ - g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, ep0_in); -#else - g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, &ep0_in); -#endif - g_currentConfig = 0; - g_curStreamAlt_Out = 0; - g_curStreamAlt_In = 0; - -#if (XUA_DFU_EN == 1) - if (DFUReportResetState(null)) - { - if (!DFU_mode_active) - { - DFU_mode_active = 1; - } - } - else - { - if (DFU_mode_active) - { - DFU_mode_active = 0; - - /* Send reboot command */ - DFUDelay(5000000); - device_reboot(); - } - } -#endif - } -} - /* Endpoint 0 function. Handles all requests to the device */ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_)