├── .gitignore ├── firmware ├── libxud.a ├── xscope.xmt ├── dsp.h ├── pll.h ├── audioports.h ├── i2c.h ├── get_adc_counts.c ├── clocking.xc ├── codec.h ├── audiostream.h ├── audiostream.xc ├── decouple.h ├── audio.h ├── xc_ptr.h ├── dbcalc.h ├── endpoint0.h ├── clockcmds.h ├── mixer.h ├── Makefile ├── SpdifReceive.h ├── clocking.h ├── usb_buffer.h ├── pll.xc ├── DescriptorRequests.h ├── XUD_UIFM_Ports.xc ├── fastmix.S ├── biquad.S ├── dsp_router.xc ├── dsp.xc ├── customdefines.h ├── codec.xc ├── audioports.xc ├── audio.xn ├── dbcalc.xc ├── mixer.xc ├── XUD_EpFunctions.xc ├── usb.h ├── interrupt.h ├── usbaudio20.h ├── DescriptorRequests.xc ├── devicedefines.h ├── i2c.xc ├── main.xc ├── repeat.h ├── usb_buffer.xc ├── XUD_EpFuncs.S ├── mkdescriptors.py └── endpoint0.xc ├── EULA ├── README └── client └── setdsp.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.bin 3 | tt 4 | auto_descriptors.h 5 | map.txt 6 | -------------------------------------------------------------------------------- /firmware/libxud.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcan/xmos-speaker-dsp/HEAD/firmware/libxud.a -------------------------------------------------------------------------------- /firmware/xscope.xmt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /firmware/dsp.h: -------------------------------------------------------------------------------- 1 | #ifndef DSP_H 2 | #define DSP_H 3 | 4 | #define FRACTIONALBITS 28 5 | #define HEADROOMBITS 4 6 | #define LFE_HEADROOMBITS 0 7 | 8 | #ifdef __XC__ 9 | 10 | #define DSP_CH 6 11 | #define DSP_EXT_CH 5 12 | #define DSP_FILTERS 15 13 | 14 | #define DELAY_BITS 10 15 | #define DELAY_BUF ((1< mClkFreq */ 33 | PllMult(mClkFreq/300); 34 | } 35 | -------------------------------------------------------------------------------- /firmware/codec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v0 4 | * Build: a5a29cb961dbeda79384d1319b2a9dc4f8f6efca 5 | * File: codec.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef _CODEC_H_ 21 | #define _CODEC_H_ 22 | 23 | /* These functions must be implemented for the CODEC/ADC/DAC arrangement of a specific design */ 24 | 25 | /* TODO Are the channel args required? */ 26 | 27 | /* Any required CODEC initialisation - run once at start up */ 28 | void CodecInit(chanend ?c_codec); 29 | 30 | /* Configure condec for a specific mClk/Sample frquency - run on every sample frequency change */ 31 | void CodecConfig(unsigned samFreq, unsigned mClk, chanend ?c_codec); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /firmware/audiostream.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v1 4 | * Build: c94813789b307c33f0bdf39ef72362df7ec27ce3 5 | * File: audiostream.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef _AUDIOSTREAM_H_ 21 | #define _AUDIOSTREAM_H_ 22 | 23 | /* Functions that handle functions that must occur on stream start/stop e.g. DAC mute/un-mute 24 | * 25 | * THESE NEED IMPLEMENTING FOR A SPECIFIC DESIGN 26 | * 27 | * */ 28 | 29 | /* Any actions required for stream start e.g. DAC un-mute - run every stream start */ 30 | void AudioStreamStart(void); 31 | 32 | /* Any actions required on stream stop e.g. DAC mute - run every steam stop */ 33 | void AudioStreamStop(void); 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /firmware/audiostream.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: app_usb_aud_l2 3 | * Version: 5v00 4 | * Build: bdb0bad2e22d60206c570bfea8758095c46d1519 5 | * File: audiostream.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef _AUDIOSTREAM_H_ 21 | #define _AUDIOSTREAM_H_ 22 | 23 | /* Functions that handle functions that must occur on stream start/stop e.g. DAC mute/un-mute 24 | * These need implementing for a specific design. 25 | * 26 | * Implementations for the L2 USB Audio Reference Design 27 | */ 28 | 29 | /* Any actions required for stream start e.g. DAC un-mute - run every stream start 30 | */ 31 | void AudioStreamStart(void) 32 | { 33 | // Do nothing... 34 | } 35 | 36 | /* Any actions required on stream stop e.g. DAC mute - run every steam stop 37 | */ 38 | void AudioStreamStop(void) 39 | { 40 | // Do nothing... 41 | } 42 | #endif 43 | 44 | -------------------------------------------------------------------------------- /firmware/decouple.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v3 4 | * Build: e7a385b28d1c8c508ddaa0746176088124c18651 5 | * File: decouple.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef __decouple_h__ 21 | #define __decouple_h__ 22 | 23 | 24 | /** Manage the data transfer between the USB audio buffer and the 25 | * Audio I/O driver. 26 | * 27 | * \param c_audio_out Channel connected to the audio() or mixer() threads 28 | * \param c_led Optional chanend connected to an led driver thread for 29 | * debugging purposes 30 | * \param c_midi Optional chanend connect to usb_midi() thread if present 31 | * \param c_clk_int Optional chanend connected to the clockGen() thread if present 32 | */ 33 | void decouple(chanend c_audio_out, 34 | chanend ?c_clk_int, chanend ?c_led); 35 | 36 | #endif // __decouple_h__ 37 | -------------------------------------------------------------------------------- /firmware/audio.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta14 4 | * Build: 396662e655a947309bcc1f260c601ec64836abc1 5 | * File: audio.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef __audio_h__ 21 | #define __audio_h__ 22 | 23 | /** The audio driver thread. 24 | * 25 | * This function drives I2S ports and handles samples to/from other digital 26 | * I/O threads. 27 | * 28 | * \param c_in Audio sample channel connected to the mixer() thread or the 29 | * decouple() thread 30 | * \param c_dig channel connected to the clockGen() thread for 31 | * receiving/transmitting samples 32 | * \param c_config An optional channel that will be passed on to the 33 | * CODEC configuration functions. 34 | */ 35 | void audio(chanend c_in, chanend ?c_dig, chanend ?c_config, chanend ?c_peaks); 36 | 37 | #endif // __audio_h__ 38 | -------------------------------------------------------------------------------- /firmware/xc_ptr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v0 4 | * Build: c0b2e34218aec54736ad1259d95377c59ed03dd3 5 | * File: xc_ptr.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef __xc_ptr__ 21 | #define __xc_ptr__ 22 | 23 | typedef unsigned int xc_ptr; 24 | 25 | inline xc_ptr array_to_xc_ptr(unsigned a[]) { 26 | xc_ptr x; 27 | asm("mov %0, %1":"=r"(x):"r"(a)); 28 | return x; 29 | } 30 | 31 | #define write_via_xc_ptr(p,x) asm("stw %0, %1[0]"::"r"(x),"r"(p)) 32 | 33 | #define write_via_xc_ptr_indexed(p,i,x) asm("stw %0, %1[%2]"::"r"(x),"r"(p),"r"(i)) 34 | 35 | #define read_via_xc_ptr(x,p) asm("ldw %0, %1[0]":"=r"(x):"r"(p)); 36 | 37 | #define read_via_xc_ptr_indexed(x,p,i) asm("ldw %0, %1[%2]":"=r"(x):"r"(p),"r"(i)); 38 | 39 | #define GET_SHARED_GLOBAL(x, g) asm("ldw %0, dp[" #g "]":"=r"(x)) 40 | #define SET_SHARED_GLOBAL(g, v) asm("stw %0, dp[" #g "]"::"r"(v)) 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /firmware/dbcalc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta10 4 | * Build: f542ddaaa188ea8357dea7b588dca0ca2bdb2343 5 | * File: dbcalc.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef __dbcalc_h__ 21 | #define __dbcalc_h__ 22 | 23 | /* Function: db_to_mult 24 | 25 | This function converts decibels into a volume multiplier. It uses a fixed-point polynomial approximation 26 | to 10^(db/10). 27 | 28 | Parameters: 29 | db - The db value to convert. 30 | db_frac_bits - The number of binary fractional bits in the supplied decibel value 31 | result_frac_bits - The number of required fractional bits in the result. 32 | 33 | Returns: 34 | The multiplier value as a fixed point value with the number of fractional bits as specified by 35 | the result_frac_bits parameter. 36 | */ 37 | unsigned db_to_mult(int db, int db_frac_bits, int result_frac_bits); 38 | 39 | #endif // __dbcalc_h__ 40 | -------------------------------------------------------------------------------- /EULA: -------------------------------------------------------------------------------- 1 | Software License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal with 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | • Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimers. 12 | 13 | • Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimers in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | • Neither the name of XMOS, nor the names of its contributors may be used to 18 | endorse or promote products derived from this Software without specific 19 | prior written permission. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE 27 | SOFTWARE. 28 | -------------------------------------------------------------------------------- /firmware/endpoint0.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta12 4 | * Build: 51aff4f427c5b2c11624d86ac8ca955d8976bfb2 5 | * File: endpoint0.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | 21 | #ifndef _ENDPOINT0_H_ 22 | #define _ENDPOINT0_H_ 23 | 24 | /** Function implementing Endpoint 0 for enumeration, control and configuration 25 | * of USB audio devices. It uses the descriptors defined in ``descriptors_2.h``. 26 | * 27 | * \param c_ep0_out Chanend connected to the XUD_Manager() out endpoint array 28 | * \param c_ep0_in Chanend connected to the XUD_Manager() in endpoint array 29 | * \param c_audioCtrl Chanend connected to the decouple thread for control 30 | * audio (sample rate changes etc.) 31 | * \param c_mix_ctl Optional chanend to be connected to the mixer thread if 32 | * present 33 | * \param c_clk_ctl Optional chanend to be connected to the clockgen thread if 34 | * present. 35 | */ 36 | void Endpoint0( chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCtrl, chanend ?c_mix_ctl,chanend ?c_clk_ctl, chanend c_dsp_ctl 37 | ); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /firmware/clockcmds.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v1 4 | * Build: 46c8812cb5039bfd815b3bdf58043aab3d251b83 5 | * File: clockcmds.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | 21 | #include "devicedefines.h" 22 | 23 | /* Clocking commands - c_clk_ctl */ 24 | #define GET_SEL 0 /* Get value of clock selector */ 25 | #define SET_SEL 1 /* Set value of clock selector */ 26 | #define GET_FREQ 2 /* Get current freq */ 27 | #define GET_VALID 3 /* Get current validity */ 28 | 29 | #define CLOCK_INTERNAL 1 30 | #define CLOCK_SPDIF 2 31 | #ifdef SPDIF_RX 32 | #define CLOCK_ADAT 3 33 | #else 34 | #define CLOCK_ADAT 2 35 | #endif 36 | 37 | #define CLOCK_INTERNAL_INDEX (CLOCK_INTERNAL - 1) 38 | #define CLOCK_ADAT_INDEX (CLOCK_ADAT - 1) 39 | #define CLOCK_SPDIF_INDEX (CLOCK_SPDIF - 1) 40 | 41 | #define SET_SMUX 7 42 | 43 | /* c_audioControl */ 44 | #define SET_SAMPLE_FREQ 4 45 | #define SET_CHAN_COUNT_IN 5 46 | #define SET_CHAN_COUNT_OUT 6 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /firmware/mixer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta12 4 | * Build: 782797bf7a66eb5078d3ad6655b9f2ce768f1274 5 | * File: mixer.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef __mixer_h__ 21 | #define __mixer_h__ 22 | 23 | enum mix_ctl_cmd { 24 | SET_SAMPLES_TO_HOST_MAP, 25 | SET_SAMPLES_TO_DEVICE_MAP, 26 | SET_MIX_MULT, 27 | SET_MIX_MAP, 28 | SET_MIX_IN_VOL, 29 | SET_MIX_OUT_VOL, 30 | GET_INPUT_LEVELS, 31 | GET_STREAM_LEVELS, 32 | GET_OUTPUT_LEVELS 33 | }; 34 | 35 | 36 | /** Digital sample mixer. 37 | * 38 | * This thread mixes audio streams between the decouple() thread and 39 | * the audio() thread. 40 | * 41 | * \param c_to_host a chanend connected to the decouple() thread for 42 | * receiving/transmitting samples 43 | * \param c_to_audio a chanend connected to the audio() thread for 44 | * receiving/transmitting samples 45 | * \param c_mix_ctl a chanend connected to the Endpoint0() thread for 46 | * receiving control commands 47 | * 48 | */ 49 | void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /firmware/Makefile: -------------------------------------------------------------------------------- 1 | XCC := xcc 2 | XCFLAGS := -Wall -W -O2 audio.xn -Wno-switch-fallthrough -report -Wno-timing 3 | LD := xmap 4 | LDFLAGS := 5 | 6 | 7 | # Build with "V=1" to see the commands executed; be quiet otherwise. 8 | 9 | ifeq ($(V),1) 10 | Q := 11 | else 12 | Q := @ 13 | endif 14 | 15 | 16 | OBJS := main.o 17 | OBJS += endpoint0.o DescriptorRequests.o audiorequests.o audiostream.o 18 | OBJS += decouple.o audio.o clocking.o usb_buffer.o clockgen.o codec.o 19 | OBJS += mixer.o fastmix.o i2c.o codec.o pll.o audioports.o get_adc_counts.o 20 | OBJS += XUD_EpFunctions.o XUD_UIFM_Ports.o XUD_EpFuncs.o dbcalc.o dsp.o 21 | OBJS += dsp_router.o biquad.o SpdifReceive.o 22 | 23 | LIBS := libxud.a 24 | 25 | .PHONY: all 26 | all: tt 27 | 28 | 29 | 30 | tt: $(OBJS) 31 | @echo " LINK $@" 32 | $(Q)$(XCC) $(XCFLAGS) -o $@ $^ $(LIBS) -Wm,--map,map.txt 33 | 34 | %.o: %.xc *.h auto_descriptors.h Makefile audio.xn 35 | @echo " COMPILE $@" 36 | $(Q)$(XCC) $(XCFLAGS) -o $@ -c $< 37 | 38 | %.o: %.c *.h auto_descriptors.h Makefile audio.xn 39 | @echo " COMPILE $@" 40 | $(Q)$(XCC) $(XCFLAGS) -o $@ -c $< 41 | 42 | %.s: %.c *.h auto_descriptors.h Makefile audio.xn 43 | @echo " COMPILE $@" 44 | $(Q)$(XCC) $(XCFLAGS) -o $@ -S $< 45 | 46 | %.o: %.S *.h auto_descriptors.h Makefile audio.xn 47 | @echo " ASSEMBLE $@" 48 | $(Q)$(XCC) $(XCFLAGS) -o $@ -c $< 49 | 50 | auto_descriptors.h: mkdescriptors.py 51 | @echo " GEN $@" 52 | $(Q)python $< > $@ 53 | 54 | .version: FORCE 55 | $(Q)./describe.sh > .$@-tmp 56 | $(Q)cmp -s $@ .$@-tmp || cp .$@-tmp $@ 57 | $(Q)rm .$@-tmp 58 | 59 | version.c: .version 60 | @echo " VERSION $@" 61 | $(Q)echo "const char version[] = \"`cat $^` (`whoami`@`hostname -s`)\";" > $@ 62 | 63 | FORCE: 64 | 65 | .PHONY: clean 66 | clean: 67 | -rm -f tt $(OBJS) .version version.c auto_descriptors.h 68 | -------------------------------------------------------------------------------- /firmware/SpdifReceive.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_spdif_rx 3 | * Version: 1v25 4 | * Build: 99e666ad7d70a85054d0d489ebc2917b9b90ed04 5 | * File: SpdifReceive.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef _SpdifReceive_h_ 21 | #define _SpdifReceive_h_ 22 | #include 23 | 24 | #define FRAME_X 9 // Left 25 | #define FRAME_Y 5 // Right 26 | #define FRAME_Z 3 // Left (start of frame) 27 | 28 | 29 | /** S/PDIF receiver. 30 | * 31 | * This function needs 1 thread and no memory other 32 | * than ~2800 bytes of program code. It can do 11025, 12000, 22050, 24000, 33 | * 44100, 48000, 88200, 96000, and 192000 kHz.w 34 | * 35 | * For a 100MHz reference clock, use a divider 36 | * of 1 for 192000, 2 for 96000/88200, 4 for 48000/44100 on clock b. 37 | * When the decoder 38 | * encounters a long series of zeros it will lower the divider; when it 39 | * encounters a short series of 0-1 transitions it will increase the divider. 40 | * 41 | * Output: whole word with bits 0-3 set to preamble. 42 | * 43 | * \param p S/PDIF output port 44 | * \param c channel to output samples to 45 | * \param initial_divider initial divide for initial estimate of sample rate 46 | * \param b clock block set to 100MHz 47 | **/ 48 | void SpdifReceive(in buffered port:4 p, streaming chanend c, int initial_divider, clock b); 49 | 50 | #endif // _SpdifReceive_h_ 51 | -------------------------------------------------------------------------------- /firmware/clocking.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta14 4 | * Build: 396662e655a947309bcc1f260c601ec64836abc1 5 | * File: clocking.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | 21 | #ifndef _CLOCKING_H_ 22 | #define _CLOCKING_H_ 23 | 24 | /* Functions that handle master clock generation. These need modifying for an existing design */ 25 | 26 | /* Any initialisation required for master clock generation - run once at start up */ 27 | void ClockingInit(void); 28 | 29 | /* Configuration for a specific master clock frequency - run every sample frequency change */ 30 | void ClockingConfig(unsigned mClkFreq); 31 | 32 | 33 | /** Clock generation and digital audio I/O handling. 34 | * 35 | * \param c_spdif_rx channel connected to S/PDIF receive thread 36 | * \param c_adat_rx channel connect to ADAT receive thread 37 | * \param p port to output clock signal to drive external frequency synthesizer 38 | * \param c_audio channel connected to the audio() thread 39 | * \param c_clk_ctl channel connected to Endpoint0() for configuration of the 40 | * clock 41 | * \param c_clk_int channel connected to the decouple() thread for clock 42 | interrupts 43 | */ 44 | void clockGen (streaming chanend c_spdif_rx, chanend c_adat_rx, out port p, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int); 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /firmware/usb_buffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta12 4 | * Build: a3e26005ac327c50f978224d03666749aea1c70a 5 | * File: usb_buffer.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef __usb_buffer_h__ 21 | #define __usb_buffer_h__ 22 | /** USB Audio Buffering Thread. 23 | * 24 | * This function buffers USB audio data between the XUD layer and the decouple 25 | * thread. Most of the chanend parameters to the function should be connected to 26 | * XUD_Manager() 27 | * 28 | * \param c_aud_out Audio OUT endpoint channel connected to the XUD 29 | * \param c_aud_in Audio IN endpoint channel connected to the XUD 30 | * \param c_aud_fb Audio feedback endpoint channel connected to the XUD 31 | * \param c_midi_from_host MIDI OUT endpoint channel connected to the XUD 32 | * \param c_midi_to_host MIDI IN endpoint channel connected to the XUD 33 | * \param c_int Audio clocking interrupt endpoint channel connected to the XUD 34 | * \param c_sof Start of frame channel connected to the XUD 35 | * \param c_aud_ctl Audio control channel connected to Endpoint0() 36 | * \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself) 37 | */ 38 | void buffer(chanend c_aud_out, chanend c_aud_in, chanend c_aud_fb, 39 | chanend c_int, 40 | chanend c_sof, 41 | chanend c_aud_ctl, 42 | in port p_off_mclk); 43 | 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is my own firmware for the XMOS USB 2.0 Multichannel Reference Design 2 | board, which I use to drive my 5.1 speakers (Logitech Z-680 with the crappy 3 | original DSP frontend box removed). It is based on the original reference 4 | firmware by XMOS, but with a lot of horribleness removed (and a lot left - 5 | here be dragons, and don't blame me for it). 6 | 7 | I had to ask to get a copy of the original reference firmware, but it was 8 | provided to me with the EULA file that is in this repo, which I interpret to 9 | mean that the whole thing is licensed under the permissive BSD-like license 10 | which it contains, and therefore I am allowed to redistribute it. 11 | 12 | You need the aforementioned XMOS USB 2.0 MC Reference board, and also an XK-1A 13 | (or modified XK-1 to fix the xlink pinout) plugged into the JTAG/XLink port. 14 | You'll either have to power the XK-1A externally or modify the main board to 15 | back-feed power to it. The XK-1 provides additional DSP power. 16 | 17 | This firmware implements a fairly flexible mixer (tested and designed to 18 | work well with the Linux ALSA sound drivers; no idea how other OSes will 19 | interpret the mixer controls available) plus a fully configurable 15 biquad DSP 20 | filters for each of the 6 output channels for equalization, all running at 21 | (hardcoded) 96kHz sample rate and 24 bit depth (with a 32-bit processing path). 22 | Notable features include the ability to use stereo inputs as soft-differential 23 | (subtraction in software), and also rotate the mapping between stereo inputs 24 | and the 5.1ch output (so that, for example, the left channel can be mapped to 25 | the front speakers and the right to the rear speakers, creating a 90° rotation). 26 | The first stereo output is a headphones output that carries a downmixed version 27 | of the final 5.1ch mix, while the next 3 are the 5.1ch outputs. There is 28 | built-in downmixing of the 5ch into the .1 subwoofer channel - no hardcoded 29 | crossover (by default it's full range), but you can trivially configure one 30 | with the biquad filters. The input LFE channel is mixed at +10dB relative to 31 | the other channels into the .1 output, per the Dolby Digital spec. 32 | 33 | I think USB audio capture is broken but I've been too lazy to debug it. 34 | -------------------------------------------------------------------------------- /firmware/pll.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: app_usb_aud_l2 3 | * Version: 5v00 4 | * Build: 4ecd7ef5e1e14be120ba7c10316070b643809339 5 | * File: pll.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #include 21 | #include 22 | 23 | #include "i2c.h" 24 | 25 | #define DEV_ADR 0x9C 26 | 27 | #define PLL_REGRD(reg) I2cRegRead(DEV_ADR, reg, p_i2c_scl, p_i2c_sda) 28 | #define PLL_REGWR(reg, val) I2cRegWrite(DEV_ADR, reg, val, p_i2c_scl, p_i2c_sda) 29 | 30 | /* I2C ports */ 31 | extern port p_i2c_sda; 32 | extern port p_i2c_scl; 33 | 34 | /* Init of CS2300 */ 35 | void PllInit(void) 36 | { 37 | /* Enable init */ 38 | //PLL_REGWR(0x1e, 0b01110000); // increase pll bandwidth to reduce lock time 39 | PLL_REGWR(0x03, 0x07); 40 | PLL_REGWR(0x05, 0x01); 41 | PLL_REGWR(0x16, 0x10); 42 | // PLL_REGWR(0x17, 0x10); //0x10 for always gen clock even when unlocked 43 | PLL_REGWR(0x17, 0x00); //0x10 for always gen clock even when unlocked 44 | 45 | 46 | /* Check */ 47 | assert(PLL_REGRD(0x03) == 0x07); 48 | assert(PLL_REGRD(0x05) == 0x01); 49 | assert(PLL_REGRD(0x16) == 0x10); 50 | assert(PLL_REGRD(0x17) == 0x00); 51 | //assert(PLL_REGRD(0x1e) == 0b01110000); 52 | } 53 | 54 | /* Setup PLL multiplier */ 55 | void PllMult(unsigned mult) 56 | { 57 | /* Multiplier is translated to 20.12 format by shifting left by 12 */ 58 | PLL_REGWR(0x06, (mult >> 12) & 0xFF); 59 | PLL_REGWR(0x07, (mult >> 4) & 0xFF); 60 | PLL_REGWR(0x08, (mult << 4) & 0xFF); 61 | PLL_REGWR(0x09, 0x00); 62 | 63 | /* Check */ 64 | assert(PLL_REGRD(0x06) == ((mult >> 12) & 0xFF)); 65 | assert(PLL_REGRD(0x07) == ((mult >> 4) & 0xFF)); 66 | assert(PLL_REGRD(0x08) == ((mult << 4) & 0xFF)); 67 | assert(PLL_REGRD(0x09) == 0x00); 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /firmware/DescriptorRequests.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_shared 3 | * Version: 1v14 4 | * Build: 2653f22a66739162bd368f5c7d50da8bd7417fd7 5 | * File: DescriptorRequests.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** 21 | * @file DescriptorRequests.h 22 | * @brief DescriptorRequestsi() prototype 23 | * @author Ross Owen, XMOS Limited 24 | * @version 1.0 25 | */ 26 | 27 | 28 | /** DescriptorRequests() 29 | * @brief This function performs some of the common USB standard descriptor requests. 30 | * 31 | * @param c_out Channel to XUD (ep 0) 32 | * @param c_in Channel from XUD (ep 0) 33 | * @param devDesc Device descriptor 34 | * @param devDescLength Length of device descriptor in bytes 35 | * @param cfgDesc Configuration descriptor 36 | * @param cfgDescLength Length of config descriptor in bytes 37 | * @param devQualDesc Device Qualification Descriptor 38 | * @param sp SetupPacket (passed by ref) in which the setup data is returned 39 | * @return 1 if dealt with else 40 | * 41 | * This function handles the following standard requests appropriately using values passed to it: 42 | * 43 | * - Get Device Descriptor (Using devDesc argument) 44 | * - Get Configuration Descriptor (Using cfgDesc argument) 45 | * - String requests (using strDesc argument) 46 | * - Get Micro$oft OS String Descriptor (Usings product ID string) 47 | * - Get Device_Qualifier Descriptor 48 | * - Get Other-Speed Configuration Descriptor (using oSpeedCfgDesc argument) 49 | * 50 | * This function returns 1 if the request has been dealt with successfully, 0 if not. The SetupPacket 51 | * structure should then be examined for device specific requests. 52 | 53 | */ 54 | int DescriptorRequests(XUD_ep c, XUD_ep c_in, uint8 devDesc[], int devDescLength, uint8 cfgDesc[], int cfgDescLength, 55 | uint8 devQualDesc[], int devQualDescLength, uint8 oSpeedCfgDesc[], int oSpeedCfgDescLength, uint8 strDescs[][40], SetupPacket &sp); 56 | -------------------------------------------------------------------------------- /firmware/XUD_UIFM_Ports.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_xud 3 | * Version: 0v60 4 | * Build: 5749c99b7821363ba858462b29442d52f62eafe2 5 | * File: XUD_UIFM_Ports.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #include 21 | #include 22 | 23 | #ifdef UIFM_USB_CLK_PORT 24 | // Port defines already made (probably in XN file) 25 | in port p_usb_clk = UIFM_USB_CLK_PORT; 26 | out port reg_write_port = UIFM_REG_WRITE_PORT; 27 | in port reg_read_port = UIFM_REG_READ_PORT; 28 | in port flag0_port = UIFM_FLAG_0_PORT; 29 | in port flag1_port = UIFM_FLAG_1_PORT; 30 | in port flag2_port = UIFM_FLAG_2_PORT; 31 | out port p_usb_txd = UIFM_TX_DATA_PORT; 32 | port p_usb_rxd = UIFM_RX_DATA_PORT; 33 | #else 34 | 35 | // We need to know what core the USB ports are on 36 | 37 | #ifndef USB_CORE 38 | //#error "Must define USB_CORE to core number with USB interface" 39 | #else 40 | 41 | #define UIFM_USB_CLK_PORT XS1_PORT_1H 42 | 43 | #define UIFM_REG_WRITE_PORT XS1_PORT_8C 44 | #define UIFM_REG_READ_PORT XS1_PORT_8D 45 | #define UIFM_FLAG_0_PORT XS1_PORT_1N 46 | #define UIFM_FLAG_1_PORT XS1_PORT_1O 47 | #define UIFM_FLAG_2_PORT XS1_PORT_1P 48 | #define UIFM_TX_DATA_PORT XS1_PORT_8A 49 | #define UIFM_RX_DATA_PORT XS1_PORT_8B 50 | #define UIFM_STP_SUS_PORT XS1_PORT_1E 51 | #define UIFM_LS_PORT XS1_PORT_4D 52 | 53 | #endif 54 | 55 | on stdcore[USB_CORE]:in port p_usb_clk = UIFM_USB_CLK_PORT; 56 | on stdcore[USB_CORE]:out port reg_write_port = UIFM_REG_WRITE_PORT; 57 | on stdcore[USB_CORE]:in port reg_read_port = UIFM_REG_READ_PORT; 58 | on stdcore[USB_CORE]:in port flag0_port = UIFM_FLAG_0_PORT; 59 | on stdcore[USB_CORE]:in port flag1_port = UIFM_FLAG_1_PORT; 60 | on stdcore[USB_CORE]:in port flag2_port = UIFM_FLAG_2_PORT; 61 | on stdcore[USB_CORE]:out port p_usb_txd = UIFM_TX_DATA_PORT; 62 | on stdcore[USB_CORE]: port p_usb_rxd = UIFM_RX_DATA_PORT; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /firmware/fastmix.S: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta14 4 | * Build: 828cd13ccba5efa7d63ff5d0c967357ccd0c8ad4 5 | * File: fastmix.S 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | 21 | #include "devicedefines.h" 22 | 23 | #define DOMIX_TOP(i) \ 24 | .cc_top doMix##i.function,doMix##i; \ 25 | .align 4 ;\ 26 | .globl doMix##i ;\ 27 | .globl doMix##i##.nstackwords ;\ 28 | .globl doMix##i##.maxthreads ; \ 29 | .globl doMix##i##.maxtimers ; \ 30 | .globl doMix##i##.maxchanends ; \ 31 | .globl doMix##i##.maxsync ;\ 32 | .linkset doMix##i##.locnoside, 1; \ 33 | .linkset doMix##i##.locnochandec, 1;\ 34 | .linkset doMix##i##.nstackwords, 0 ;\ 35 | .linkset doMix##i##.maxchanends, 0 ;\ 36 | .linkset doMix##i##.maxtimers, 0 ;\ 37 | .linkset doMix##i##.maxthreads, 1; \ 38 | doMix##i##: ;\ 39 | set cp, r0; \ 40 | set dp, r1; \ 41 | lsub r0, r1, r0, r0, r0;\ 42 | 43 | #define DOMIX_BOT(i) \ 44 | ldap r11, _dp; \ 45 | set dp, r11;\ 46 | ldap r11, _cp;\ 47 | set cp, r11;\ 48 | \ 49 | mov r0, r1;\ 50 | ldc r2, 0x19;\ 51 | sext r0, r2;\ 52 | eq r0, r0, r1;\ 53 | bf r0, .L20; \ 54 | \ 55 | shl r0, r1, 0x7;\ 56 | retsp 0x0;\ 57 | \ 58 | \ 59 | .cc_bottom doMix##i##.function; 60 | 61 | #define BODY(i) \ 62 | ldw r2, cp[i]; \ 63 | ldw r11, dp[i]; \ 64 | maccs r1, r0, r2, r11; 65 | 66 | 67 | .text 68 | 69 | .L20:\ 70 | lss r0, r1, r3;\ 71 | bt r0, .L16; \ 72 | ldw r0, cp[.LC0];\ 73 | retsp 0x0; \ 74 | .L16:\ 75 | ldw r0, cp[.LC1];\ 76 | retsp 0x0; \ 77 | 78 | 79 | 80 | 81 | #define N MIX_INPUTS 82 | DOMIX_TOP(_out) 83 | #include "repeat.h" 84 | DOMIX_BOT(_out) 85 | 86 | #undef N 87 | #define N AUX_COUNT 88 | DOMIX_TOP(_in) 89 | #include "repeat.h" 90 | DOMIX_BOT(_in) 91 | 92 | .section .cp.const4, "acM", @progbits, 4 93 | .LC0: 94 | .align 4 95 | .int 0x7fffff00 96 | .LC1: 97 | .int 0x80000000 98 | 99 | #undef N 100 | #undef BODY 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /firmware/biquad.S: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, XMOS Ltd, All rights reserved 2 | // This software is freely distributable under a derivative of the 3 | // University of Illinois/NCSA Open Source License posted in 4 | // LICENSE.txt and at 5 | 6 | #include "dsp.h" 7 | 8 | #define NWORDS 7 9 | 10 | .globl biquad_cascade 11 | .globl biquad_cascade.nstackwords 12 | .linkset biquad_cascade.nstackwords,NWORDS 13 | .align 4 14 | biquad_cascade: 15 | entsp NWORDS 16 | stw r4, sp[0] 17 | stw r5, sp[1] 18 | stw r6, sp[2] 19 | stw r7, sp[3] 20 | stw r8, sp[4] 21 | stw r9, sp[5] 22 | stw r10, sp[6] 23 | 24 | mov r10, r3 25 | 26 | // r0: xn 27 | // r1: count 28 | // r2: biquads 29 | // r3: xn1 30 | // r4: xn2 31 | // r5: tmp 32 | // r6: FRACTIONALBITS 33 | // r7: 1<<(FRACTIONALBITS-1) 34 | // r8: accl 35 | // r9: acch 36 | // r10: headroombits 37 | 38 | ldc r6, FRACTIONALBITS 39 | 40 | ldw r3, r2[0] 41 | 42 | ashr r0, r0, r10 43 | 44 | ldc r9, 0 45 | ldc r7, 1 46 | ldw r4, r2[1] 47 | shl r7, r7, r6 48 | shr r7, r7, 1 49 | 50 | loop: 51 | mov r8, r7 52 | ldw r5, r2[2] // Coefficient b0 53 | maccs r9, r8, r5, r0 // Multiply by xn 54 | ldw r5, r2[3] // Coefficient b1 55 | maccs r9, r8, r5, r3 // Multiply by xn1 56 | ldw r5, r2[4] // Coefficient b2 57 | maccs r9, r8, r5, r4 // Multiply by xn2 58 | 59 | stw r0, r2[0] // Save xn into xn1 60 | stw r3, r2[1] // Save xn1 into xn2 61 | 62 | ldw r5, r2[5] // Coefficient a1 63 | ldw r3, r2[7] // Load yn1 (next filter xn1) 64 | maccs r9, r8, r5, r3 65 | ldw r5, r2[6] // Coefficient a2 66 | ldw r4, r2[8] // Load yn2 (next filter xn2) 67 | maccs r9, r8, r5, r4 68 | 69 | ldaw r2, r2[7] // Advance to next biquad 70 | 71 | mov r5, r9 // copy r9 into r5, to check for overflow 72 | sext r5, r6 // because sext sign extends in place 73 | eq r5, r9, r5 // If sext makes no change, result is ok 74 | bt r5, resultFits 75 | ldc r0, 0x80 // not ok, create MININT or MAXINT 76 | shl r0, r0, 24 77 | lss r5, r5, r9 78 | sub r0, r0, r5 79 | bu resultDone 80 | 81 | resultFits: 82 | ldc r5, 32-FRACTIONALBITS // Merge two halves 83 | shl r9, r9, r5 // By shifting both halves and oring them together. 84 | shr r8, r8, r6 85 | or r0, r9, r8 86 | 87 | resultDone: 88 | sub r1, r1, 1 // Dec counter 89 | eq r9, r1, 0 // Last bank? 90 | bf r9, loop // If not, jump, this clears r9 91 | 92 | stw r0, r2[0] // store yn1 93 | stw r3, r2[1] // store yn2 94 | 95 | ldc r1, 32 96 | sub r1, r1, r10 97 | mov r2, r0 98 | sext r2, r1 99 | eq r2, r0, r2 // If sext makes no change, result is ok 100 | bt r2, finalResultFits 101 | ldc r1, 0x80 // not ok, create MININT or MAXINT 102 | shl r1, r1, 24 103 | lss r2, r2, r0 104 | sub r0, r1, r2 105 | bu allDone 106 | 107 | finalResultFits: 108 | shl r0, r0, r10 109 | 110 | allDone: // Now just restore all registers. 111 | 112 | ldw r4, sp[0] 113 | ldw r5, sp[1] 114 | ldw r6, sp[2] 115 | ldw r7, sp[3] 116 | ldw r8, sp[4] 117 | ldw r9, sp[5] 118 | ldw r10, sp[6] 119 | retsp NWORDS 120 | -------------------------------------------------------------------------------- /firmware/dsp_router.xc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mixer.h" 5 | #include "devicedefines.h" 6 | #include "dsp.h" 7 | 8 | #define LDW(dest, array, index) asm("ldw %0, %1[%2]":"=r"(dest):"r"(array),"r"(index)) 9 | #define STW(array, index, value) asm("stw %0, %1[%2]"::"r"(value),"r"(array),"r"(index)) 10 | 11 | static int dsp_in_samples[I2S_CHANS_DAC]; 12 | static int dsp_out_samples[I2S_CHANS_DAC]; 13 | static int in_samples[IN_CHANNELS]; 14 | 15 | static struct biquad lfe_biquads[DSP_FILTERS+1] = { 16 | {0,0,DB10,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 17 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 18 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 19 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,0,0,0,0,0}, 20 | }; 21 | 22 | static int audiobuf[DELAY_BUF]; 23 | static int p_write; 24 | static int lfe_delay; 25 | 26 | #pragma unsafe arrays 27 | static void giveSamplesToDevice(chanend c) 28 | { 29 | outuint(c, dsp_in_samples[0]); 30 | outuint(c, dsp_in_samples[1]); 31 | outuint(c, dsp_out_samples[2]); 32 | outuint(c, dsp_out_samples[3]); 33 | outuint(c, dsp_out_samples[4]); 34 | outuint(c, dsp_out_samples[5]); 35 | outuint(c, dsp_out_samples[6]); 36 | outuint(c, dsp_out_samples[7]); 37 | } 38 | 39 | #pragma unsafe arrays 40 | static void getSamplesFromDevice(chanend c) 41 | { 42 | #pragma loop unroll 43 | for (int i = 0; i < IN_CHANNELS; i++) 44 | STW(in_samples, i, inuint(c)); 45 | } 46 | 47 | #pragma unsafe arrays 48 | static void giveSamplesToMixer(chanend c) 49 | { 50 | #pragma loop unroll 51 | for (int i = 0; i < IN_CHANNELS; i++) 52 | outuint(c, in_samples[i]); 53 | } 54 | 55 | #pragma unsafe arrays 56 | static void getSamplesFromMixer(chanend c) 57 | { 58 | #pragma loop unroll 59 | for (int i = 0; i < I2S_CHANS_DAC; i++) 60 | STW(dsp_in_samples, i, inuint(c)); 61 | } 62 | 63 | #pragma unsafe arrays 64 | static void giveSamplesToDSP(chanend c) 65 | { 66 | #pragma loop unroll 67 | for (int i = 0; i < DSP_EXT_CH; i++) 68 | outuint(c, dsp_in_samples[2+i]); 69 | } 70 | 71 | #pragma unsafe arrays 72 | static void getSamplesFromDSP(chanend c) 73 | { 74 | #pragma loop unroll 75 | for (int i = 0; i < DSP_EXT_CH; i++) 76 | STW(dsp_out_samples, 2+i, inuint(c)); 77 | } 78 | 79 | #pragma unsafe arrays 80 | void dsp_router(chanend c_mixer, chanend c_audio, chanend c_dsp, chanend c_dsp_ctl) 81 | { 82 | int result = 0; 83 | unsigned char ct; 84 | while(1) { 85 | inuint(c_audio); 86 | giveSamplesToDevice(c_audio); 87 | getSamplesFromDevice(c_audio); 88 | outuint(c_mixer, 0); 89 | getSamplesFromMixer(c_mixer); 90 | giveSamplesToMixer(c_mixer); 91 | 92 | select { 93 | case inct_byref(c_dsp_ctl, ct): { 94 | int ch, i; 95 | switch (ct) { 96 | case SET_DSP_BIQUAD: 97 | ch = inuint(c_dsp_ctl); 98 | if (ch == DSP_EXT_CH) { 99 | i = inuint(c_dsp_ctl); 100 | lfe_biquads[i].xn1 = 0; 101 | lfe_biquads[i].xn2 = 0; 102 | lfe_biquads[i].b0 = inuint(c_dsp_ctl); 103 | lfe_biquads[i].b1 = inuint(c_dsp_ctl); 104 | lfe_biquads[i].b2 = inuint(c_dsp_ctl); 105 | lfe_biquads[i].a1 = inuint(c_dsp_ctl); 106 | lfe_biquads[i].a2 = inuint(c_dsp_ctl); 107 | } else { 108 | outct(c_dsp, SET_DSP_BIQUAD); 109 | outuint(c_dsp, ch); 110 | outuint(c_dsp, inuint(c_dsp_ctl)); 111 | outuint(c_dsp, inuint(c_dsp_ctl)); 112 | outuint(c_dsp, inuint(c_dsp_ctl)); 113 | outuint(c_dsp, inuint(c_dsp_ctl)); 114 | outuint(c_dsp, inuint(c_dsp_ctl)); 115 | outuint(c_dsp, inuint(c_dsp_ctl)); 116 | } 117 | break; 118 | case SET_DSP_DELAY: 119 | ch = inuint(c_dsp_ctl); 120 | if (ch == DSP_EXT_CH) { 121 | lfe_delay = inuint(c_dsp_ctl); 122 | } else { 123 | outct(c_dsp, SET_DSP_DELAY); 124 | outuint(c_dsp, ch); 125 | outuint(c_dsp, inuint(c_dsp_ctl)); 126 | } 127 | break; 128 | } 129 | chkct(c_dsp_ctl, XS1_CT_END); 130 | break; 131 | } 132 | default: 133 | break; 134 | } 135 | outuint(c_dsp, 0); 136 | getSamplesFromDSP(c_dsp); 137 | STW(dsp_out_samples, 2+DSP_EXT_CH, result); 138 | giveSamplesToDSP(c_dsp); 139 | p_write = (p_write + 1) & MAX_DELAY; 140 | result = biquad_cascade(dsp_in_samples[2+DSP_EXT_CH], DSP_FILTERS, lfe_biquads, LFE_HEADROOMBITS); 141 | STW(audiobuf, p_write, result); 142 | result = audiobuf[(p_write - lfe_delay) & MAX_DELAY]; 143 | 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /firmware/dsp.xc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mixer.h" 5 | #include "devicedefines.h" 6 | #include "dsp.h" 7 | 8 | #define LDW(dest, array, index) asm("ldw %0, %1[%2]":"=r"(dest):"r"(array),"r"(index)) 9 | #define STW(array, index, value) asm("stw %0, %1[%2]"::"r"(value),"r"(array),"r"(index)) 10 | 11 | static struct biquad biquads[DSP_EXT_CH][DSP_FILTERS+1] = { 12 | { 13 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 14 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 15 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 16 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,0,0,0,0,0}, 17 | }, 18 | { 19 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 20 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 21 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 22 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,0,0,0,0,0}, 23 | }, 24 | { 25 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 26 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 27 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 28 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,0,0,0,0,0}, 29 | }, 30 | { 31 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 32 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 33 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 34 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,0,0,0,0,0}, 35 | }, 36 | { 37 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 38 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 39 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0}, 40 | {0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,ONE,0,0,0,0},{0,0,0,0,0,0,0}, 41 | }, 42 | }; 43 | 44 | static int audiobuf[DSP_EXT_CH][DELAY_BUF]; 45 | static int delay[DSP_EXT_CH]; 46 | static int p_write[DSP_EXT_CH]; 47 | 48 | static int dsp_out_samples[DSP_EXT_CH]; 49 | 50 | #pragma unsafe arrays 51 | static void giveSamplesToDevice(chanend c) 52 | { 53 | #pragma loop unroll 54 | for (int i = 0; i < DSP_EXT_CH; i++) 55 | outuint(c, dsp_out_samples[i]); 56 | } 57 | #pragma unsafe arrays 58 | static void getSamplesFromMixer(chanend c) 59 | { 60 | #pragma loop unroll 61 | for (int i = 0; i < DSP_EXT_CH; i++) 62 | STW(dsp_out_samples, i, inuint(c)); 63 | } 64 | 65 | void dsp_sub(int ch, chanend c, const struct biquad bq[]) 66 | { 67 | int result; 68 | while(1) { 69 | int p; 70 | inuint(c); 71 | p = (p_write[ch] + 1) & MAX_DELAY; 72 | STW(p_write, ch, p); 73 | result = biquad_cascade(dsp_out_samples[ch], DSP_FILTERS, bq, HEADROOMBITS); 74 | STW(audiobuf[ch], p, result); 75 | result = audiobuf[ch][(p - delay[ch]) & MAX_DELAY]; 76 | STW(dsp_out_samples, ch, result); 77 | outuint(c, 0); 78 | } 79 | } 80 | 81 | void dsp_main(chanend c_dsp, chanend c1, chanend c2, chanend c3, chanend c4) 82 | { 83 | int result; 84 | set_thread_fast_mode_on(); 85 | while (1) { 86 | int p; 87 | if (testct(c_dsp)) { 88 | int ch, i, cmd; 89 | cmd = inct(c_dsp); 90 | switch (cmd) { 91 | case SET_DSP_BIQUAD: 92 | ch = inuint(c_dsp); 93 | i = inuint(c_dsp); 94 | biquads[ch][i].xn1 = 0; 95 | biquads[ch][i].xn2 = 0; 96 | biquads[ch][i].b0 = inuint(c_dsp); 97 | biquads[ch][i].b1 = inuint(c_dsp); 98 | biquads[ch][i].b2 = inuint(c_dsp); 99 | biquads[ch][i].a1 = inuint(c_dsp); 100 | biquads[ch][i].a2 = inuint(c_dsp); 101 | break; 102 | case SET_DSP_DELAY: 103 | ch = inuint(c_dsp); 104 | STW(delay, ch, inuint(c_dsp)); 105 | break; 106 | } 107 | } 108 | inuint(c_dsp); 109 | giveSamplesToDevice(c_dsp); 110 | getSamplesFromMixer(c_dsp); 111 | p = (p_write[0] + 1) & MAX_DELAY; 112 | STW(p_write, 0, p); 113 | outuint(c1, 0); 114 | outuint(c2, 0); 115 | outuint(c3, 0); 116 | outuint(c4, 0); 117 | result = biquad_cascade(dsp_out_samples[0], DSP_FILTERS, biquads[0], HEADROOMBITS); 118 | STW(audiobuf[0], p, result); 119 | result = audiobuf[0][(p - delay[0]) & MAX_DELAY]; 120 | STW(dsp_out_samples, 0, result); 121 | inuint(c1); 122 | inuint(c2); 123 | inuint(c3); 124 | inuint(c4); 125 | } 126 | } 127 | 128 | #pragma unsafe arrays 129 | void dsp(chanend c_dsp) 130 | { 131 | chan c1, c2, c3, c4; 132 | par { 133 | dsp_main(c_dsp, c1, c2, c3, c4); 134 | dsp_sub(1, c1, biquads[1]); 135 | dsp_sub(2, c2, biquads[2]); 136 | dsp_sub(3, c3, biquads[3]); 137 | dsp_sub(4, c4, biquads[4]); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /firmware/customdefines.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: app_usb_aud_l2 3 | * Version: 5v3rc0 4 | * Build: c653036bf3addcd9dae8deb06615fc62ae14ac93 5 | * File: customdefines.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** 21 | * @file customdefines.h 22 | * @brief Defines relating to device configuration and customisation. 23 | * @author Ross Owen, XMOS Limited 24 | */ 25 | #ifndef _CUSTOMDEFINES_H_ 26 | #define _CUSTOMDEFINES_H_ 27 | 28 | //#define XUD_DEBUG_VERSION 29 | //#define DEBUG 30 | 31 | #ifdef DEBUG 32 | #define dprintf printf 33 | #else 34 | #define dprintf(...) while(0) 35 | #endif 36 | 37 | #define DEBUG_LEDS 38 | 39 | /***** Device configuration option defines. Build can be customised but changing these defines *****/ 40 | 41 | /* Audio Class Version */ 42 | #define AUDIO_CLASS 2 43 | 44 | /* Defines relating to channel count and channel arrangement (0 for disable) */ 45 | /* Number of USB streaming channels */ 46 | #define NUM_USB_CHAN_IN (2) /* Device to Host */ 47 | #define NUM_USB_CHAN_OUT (6) /* Host to Device */ 48 | 49 | #define OUT_VOLUME_IN_MIXER 0 50 | #define IN_VOLUME_IN_MIXER 0 51 | #define OUT_VOLUME_AFTER_MIX 0 52 | #define IN_VOLUME_AFTER_MIX 0 53 | 54 | #define MAX_MIX_COUNT 8 55 | 56 | /* Define to enable S/PDIF Rx. Note, this also effects glock gen thread and clock unit descriptors */ 57 | #if defined(SPDIF_RX) && (SPDIF_RX==0) 58 | #undef SPDIF_RX 59 | #else 60 | // Enabled by default 61 | #define SPDIF_RX 1 62 | #endif 63 | 64 | #define SELF_POWERED 1 65 | 66 | /* Define for CODEC operation mode (i.e. slave/master)*/ 67 | #if defined(CODEC_SLAVE) && (CODEC_SLAVE==0) 68 | #undef CODEC_SLAVE 69 | #else 70 | // Enabled by default 71 | #define CODEC_SLAVE 1 72 | #endif 73 | 74 | /* Define for enabling mixer interface */ 75 | #if defined(MIXER) && (MIXER==0) 76 | #undef MIXER 77 | #else 78 | // Enabled by default 79 | #define MIXER 80 | #endif 81 | 82 | /* Number of IS2 chans to DAC..*/ 83 | #define I2S_CHANS_DAC (8) 84 | 85 | /* Number of I2S chans from ADC */ 86 | #define I2S_CHANS_ADC (6) 87 | 88 | /* Master clock defines (in Hz) */ 89 | #define MCLK_441 (256*44100) /* 44.1, 88.2 etc */ 90 | #define MCLK_48 (256*48000) /* 48, 96 etc */ 91 | 92 | /* Maximum frequency device runs at */ 93 | #define MAX_FREQ (96000) 94 | 95 | /* Default frequency device reports as running at */ 96 | #define DEFAULT_FREQ (MAX_FREQ) 97 | 98 | /***** Defines relating to USB descriptors etc *****/ 99 | #define VENDOR_STR "XMOS " 100 | #define VENDOR_ID (0x20B1) /* XMOS VID */ 101 | #define PID_AUDIO_1 (0x0005) 102 | #define PID_AUDIO_2 (0x0004) 103 | #ifndef BCD_DEVICE 104 | #define BCD_DEVICE (0x0530) /* Device release number in BCD: 0xJJMN 105 | * JJ: Major, M: Minor, N: Sub-minor */ 106 | #endif 107 | 108 | //#define LEVEL_METER_PROCESSING 1 109 | //#define LEVEL_METER_LEDS 1 /* Enables call to VendorLedRefresh() */ 110 | //#define CLOCK_VALIDITY_CALL 1 /* Enables calls to VendorClockValidity(int valid) */ 111 | #define HOST_ACTIVE_CALL 1 /* Enabled call to VendorHostActive(int active); */ 112 | 113 | #ifdef HOST_ACTIVE_CALL /* L2 ref design board uses audio core reqs for host active */ 114 | /* 115 | #ifndef VENDOR_AUDCORE_REQS 116 | #define VENDOR_AUDCORE_REQS 1 117 | #endif 118 | 119 | #ifndef VENDOR_AUDIO_REQS 120 | #define VENDOR_AUDIO_REQS 1 121 | #endif 122 | */ 123 | #endif 124 | 125 | //#define MAX_MIX_OUTPUTS 0 126 | 127 | 128 | #ifdef SPDIF_RX 129 | # define SPDIF_RX_INDEX 6 130 | # define SPDIF_CHANS 2 131 | # define SPDIF_CLOCKS 1 132 | #else 133 | # define SPDIF_CHANS 0 134 | # define SPDIF_CLOCKS 0 135 | #endif 136 | 137 | #define MIX_INPUTS (NUM_USB_CHAN_OUT + I2S_CHANS_ADC + SPDIF_CHANS) 138 | #define IN_CHANNELS (I2S_CHANS_ADC + SPDIF_CHANS) 139 | #define AUX_COUNT (IN_CHANNELS / 2) 140 | #define NUM_CLOCKS (1 + SPDIF_CLOCKS) 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /firmware/codec.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: app_usb_aud_l2 3 | * Version: 3v00 4 | * Build: 89ae0a5f3b92ea061d7202203563a40eef315ca4 5 | * File: codec.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #include "devicedefines.h" 21 | #include "i2c.h" 22 | #include 23 | 24 | /* I2C ports */ 25 | extern port p_i2c_sda; 26 | extern port p_i2c_scl; 27 | 28 | extern out port p_aud_cfg; 29 | 30 | #define COD_DEV_ADRS 0x90 31 | #define SYNC_DEV_ADRS 0x9C 32 | 33 | /* CODEC initialisation for Cirrus Logic CS42448 */ 34 | void CodecInit(chanend ?c_codec) 35 | { 36 | unsigned tmp; 37 | 38 | /* Clock buffers and CODEC out of reset */ 39 | #ifdef CODEC_SLAVE 40 | p_aud_cfg <: 0b0000 @ tmp; 41 | tmp += 1000; 42 | p_aud_cfg @ tmp <: 0b1000; 43 | #else 44 | p_aud_cfg <: 0b0010 @ tmp; 45 | tmp += 1000; 46 | p_aud_cfg @ tmp <: 0b1010; 47 | #endif 48 | 49 | /* Power Control Register (Address 02h) */ 50 | /* 0 Power Down (PDN) = 1 Enable, 0 Disable */ 51 | /* 1:4 Power Down DAC Pairs (PDN_DACX) = 1 Enable, 0 Disable */ 52 | /* 5:7 Power Down ADC Pairs (PDN_ADCX) = 1 Enable, 0 Disable */ 53 | tmp = 0x01; 54 | I2cRegWrite(COD_DEV_ADRS, 0x2, tmp, p_i2c_scl, p_i2c_sda); 55 | 56 | /* Interface Formats Register (Address 04h) */ 57 | /* 0 Freeze Controls (FREEZE) = 0, */ 58 | /* 1 Auxiliary Digital Interface Format (AUX_DIF) = 0, */ 59 | /* 2:4 DAC Digital Interface Format (DAC_DIF) = 001 (I2S) */ 60 | /* 5:7 ADC Digital Interface Format (ADC_DIF) = 001 (I2S) */ 61 | tmp = 0x09; 62 | I2cRegWrite(COD_DEV_ADRS, 0x4, tmp, p_i2c_scl, p_i2c_sda); 63 | 64 | tmp = (-12) & 0xff; 65 | I2cRegWrite(COD_DEV_ADRS, 0x11, tmp, p_i2c_scl, p_i2c_sda); 66 | I2cRegWrite(COD_DEV_ADRS, 0x12, tmp, p_i2c_scl, p_i2c_sda); 67 | I2cRegWrite(COD_DEV_ADRS, 0x13, tmp, p_i2c_scl, p_i2c_sda); 68 | I2cRegWrite(COD_DEV_ADRS, 0x14, tmp, p_i2c_scl, p_i2c_sda); 69 | I2cRegWrite(COD_DEV_ADRS, 0x15, tmp, p_i2c_scl, p_i2c_sda); 70 | I2cRegWrite(COD_DEV_ADRS, 0x16, tmp, p_i2c_scl, p_i2c_sda); 71 | 72 | /* ADC Control & DAC De-Emphasis (Address 05h) */ 73 | /* 0 ADC1-2_HPF FREEZE = 0, */ 74 | /* 1 ADC3_HPF FREEZE = 0, */ 75 | /* 2 DAC_DEM = 0, */ 76 | /* 3 ADC1_SINGLE = 1(single ended), */ 77 | /* 4 ADC2_SINGLE = 1, */ 78 | /* 5 ADC3_SINGLE = 1, */ 79 | /* 6 AIN5_MUX = 0, */ 80 | /* 7 AIN6_MUX = 0 */ 81 | tmp = 0x1C; 82 | I2cRegWrite(COD_DEV_ADRS, 0x5, tmp, p_i2c_scl, p_i2c_sda); 83 | 84 | /* Power Control Register (Address 02h) - PDN disable */ 85 | tmp = 0x00; 86 | I2cRegWrite(COD_DEV_ADRS, 0x2, tmp, p_i2c_scl, p_i2c_sda); 87 | 88 | } 89 | 90 | /* CODEC configuration for sample frequency change for Cirrus Logic CS42448 */ 91 | void CodecConfig(unsigned samFreq, unsigned mClk, chanend ?c_codec) 92 | { 93 | unsigned tmp; 94 | 95 | /* Functional Mode (Address 03h) */ 96 | /* 0:1 DAC Functional Mode Slave:Auto-detect samp rate 11 */ 97 | /* 2:3 ADC Functional Mode Slave:Auto -detect samp rate 11 */ 98 | /* Master: Single 00 */ 99 | /* Master: Double 01 */ 100 | /* Master: Quad 10 */ 101 | /* 4:6 MCLK Frequency 256/128/64 : 000 */ 102 | /* 512/256/128: 010 */ 103 | /* 7 Reserved */ 104 | #ifdef CODEC_SLAVE 105 | tmp = 0b11110000; /* Autodetect */ 106 | #else 107 | if(samFreq < 50000) 108 | { 109 | tmp = 0b00000000; 110 | } 111 | else if(samFreq < 100000) 112 | { 113 | tmp = 0b01010000; 114 | } 115 | else 116 | { 117 | tmp = 0b10100000; 118 | } 119 | #endif 120 | if(mClk < 15000000) 121 | { 122 | tmp |= 0; // 256/128/64 123 | } 124 | else if(mClk < 25000000) 125 | { 126 | tmp |= 0b00000100; // 512/256/128 127 | } 128 | else 129 | { 130 | printstrln("Err: MCLK currently not supported"); 131 | } 132 | 133 | I2cRegWrite(COD_DEV_ADRS, 0x3, tmp, p_i2c_scl, p_i2c_sda); 134 | } 135 | 136 | -------------------------------------------------------------------------------- /firmware/audioports.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v1 4 | * Build: 16d27b9745fbee4dd7f17ad8d31813326cea9187 5 | * File: audioports.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #include 21 | #include "devicedefines.h" 22 | #include "audioports.h" 23 | 24 | /* Audio IOs */ 25 | 26 | #if (I2S_CHANS_DAC != 0) 27 | extern buffered out port:32 p_i2s_dac[I2S_WIRES_DAC]; 28 | #endif 29 | 30 | #if (I2S_CHANS_ADC != 0) 31 | extern buffered in port:32 p_i2s_adc[I2S_WIRES_ADC]; 32 | #endif 33 | 34 | #if (I2S_CHANS_DAC != 0) || (I2S_CHANS_ADC != 0) 35 | #ifdef CODEC_SLAVE 36 | extern buffered out port:32 p_lrclk; 37 | extern buffered out port:32 p_bclk; 38 | #else 39 | extern in port p_lrclk; 40 | extern in port p_bclk; 41 | #endif 42 | #endif 43 | 44 | extern port p_mclk; 45 | 46 | extern clock clk_audio_mclk; 47 | extern clock clk_audio_bclk; 48 | 49 | void ConfigAudioPorts(unsigned int divide) 50 | { 51 | 52 | #ifdef CODEC_SLAVE 53 | /* Output 0 on BCLK to ensure clock is low 54 | * Required as stop_clock will only complete when the clock is low 55 | */ 56 | configure_out_port_no_ready(p_bclk, clk_audio_mclk, 0); 57 | p_bclk <: 0; 58 | 59 | /* Stop bit and master clock blocks and clear port buffers */ 60 | stop_clock(clk_audio_bclk); 61 | stop_clock(clk_audio_mclk); 62 | 63 | clearbuf(p_lrclk); 64 | clearbuf(p_bclk); 65 | 66 | #if (I2S_CHANS_ADC != 0) 67 | for(int i = 0; i < I2S_WIRES_ADC; i++) 68 | { 69 | clearbuf(p_i2s_adc[i]); 70 | } 71 | #endif 72 | 73 | #if (I2S_CHANS_DAC != 0) 74 | for(int i = 0; i < I2S_WIRES_DAC; i++) 75 | { 76 | clearbuf(p_i2s_dac[i]); 77 | } 78 | #endif 79 | 80 | /* Clock master clock-block from master-clock port */ 81 | configure_clock_src(clk_audio_mclk, p_mclk); 82 | 83 | /* For a divide of one (i.e. bitclock == master-clock) BClk is set to clock_output mode. 84 | * In this mode it outputs an edge clock on every tick of itsassociated clock_block. 85 | * 86 | * For all other divides, BClk is clocked by the master clock and data 87 | * will be output to p_bclk to generate the bit clock. 88 | */ 89 | if (divide == 1) /* e.g. 176.4KHz from 11.2896 */ 90 | { 91 | configure_port_clock_output(p_bclk, clk_audio_mclk); 92 | } 93 | else 94 | { 95 | /* bit clock port from master clock clock-clock block */ 96 | configure_out_port_no_ready(p_bclk, clk_audio_mclk, 0); 97 | } 98 | 99 | /* Generate bit clock block from pin */ 100 | configure_clock_src(clk_audio_bclk, p_bclk); 101 | 102 | 103 | #if (I2S_CHANS_DAC != 0) 104 | /* Clock I2S output data ports from clock block */ 105 | for(int i = 0; i < I2S_WIRES_DAC; i++) 106 | { 107 | configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0); 108 | } 109 | #endif 110 | 111 | #if (I2S_CHANS_ADC != 0) 112 | /* Clock I2S input data ports from clock block */ 113 | for(int i = 0; i < I2S_WIRES_ADC; i++) 114 | { 115 | configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk); 116 | } 117 | #endif 118 | 119 | /* Clock LR clock from bit clock-block */ 120 | configure_out_port_no_ready(p_lrclk, clk_audio_bclk, 0); 121 | 122 | /* Start clock blocks ticking */ 123 | start_clock(clk_audio_mclk); 124 | start_clock(clk_audio_bclk); 125 | 126 | /* bclk initial state needs to be high */ 127 | p_bclk <: 0xFFFFFFFF; 128 | 129 | /* Pause until output completes */ 130 | sync(p_bclk); 131 | 132 | #else 133 | /* Stop bit and master clock blocks and clear port buffers */ 134 | stop_clock(clk_audio_bclk); 135 | stop_clock(clk_audio_mclk); 136 | 137 | /* Clock bclk clock-block from bclk pin */ 138 | configure_clock_src(clk_audio_bclk, p_bclk); 139 | 140 | /* Clock I2S output data ports from b-clock clock block */ 141 | for(int i = 0; i < I2S_WIRES_DAC; i++) 142 | { 143 | configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0); 144 | } 145 | 146 | /* Clock I2S input data ports from clock block */ 147 | for(int i = 0; i < I2S_WIRES_ADC; i++) 148 | { 149 | configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk); 150 | } 151 | 152 | configure_in_port_no_ready(p_lrclk, clk_audio_bclk); 153 | 154 | start_clock(clk_audio_bclk); 155 | 156 | #endif 157 | } 158 | -------------------------------------------------------------------------------- /firmware/audio.xn: -------------------------------------------------------------------------------- 1 | 2 | 5 | Board 6 | USB 2.0 MC + DSP 7 | 8 | 9 | core stdcore[3] 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /firmware/dbcalc.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta10 4 | * Build: d009d5bec140a80ab4e4bcbdb79b157bd8f6a4ea 5 | * File: dbcalc.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #include 21 | #include 22 | /* The coefficients of the chebychev polynomial to approximate 10^x in the interval [-1,1]. 23 | This polynomial was calculated using the mpmath library in Python: 24 | 25 | from mpmath import * 26 | mp.dps = 15 27 | mp.pretty = True 28 | poly, err = chebyfit(lambda x: pow(10,x), [-1,1], 14, error=True) 29 | nprint([int(x * pow(2,28)) for x in poly]) 30 | */ 31 | #define COEF_PREC 28 32 | static unsigned coef[14] = {2407, 13778, 64588, 308051, 1346110, 5261991, 18277531, 55564576, 144789513, 314406484, 546179875, 711608713, 618095479, 268435456}; 33 | 34 | #define DB_CALC_PREC 28 35 | 36 | /* Function: db_to_mult 37 | 38 | This function converts decibels into a volume multiplier. It uses a fixed-point polynomial approximation 39 | to 10^(db/10). 40 | 41 | Parameters: 42 | db - The db value to convert. 43 | db_frac_bits - The number of binary fractional bits in the supplied decibel value 44 | result_frac_bits - The number of required fractional bits in the result. 45 | 46 | Returns: 47 | The multiplier value as a fixed point value with the number of fractional bits as specified by 48 | the result_frac_bits parameter. 49 | */ 50 | unsigned db_to_mult(int db, int db_frac_bits, int result_frac_bits) 51 | { 52 | int intpart; 53 | int val = 0; 54 | int val0=0; 55 | unsigned ret; 56 | unsigned mask = ~((1<> DB_CALC_PREC; 78 | 79 | if (intpart) { 80 | val0 = 1 << DB_CALC_PREC; 81 | for (int i=0;i> DB_CALC_PREC; 89 | if (intpart) { 90 | val0 = 1 << DB_CALC_PREC; 91 | for (int i=0;i> DB_CALC_PREC); 106 | val += coef[i] >> (COEF_PREC - DB_CALC_PREC); 107 | } 108 | 109 | /* Finally multiply by the integer power (if there was an integer part) */ 110 | if (val0) { 111 | int hi=0; 112 | unsigned lo=0; 113 | 114 | {hi, lo} = macs(val0,val,hi,lo); 115 | val = (hi << (32-DB_CALC_PREC)) | (lo >> DB_CALC_PREC); 116 | } 117 | 118 | 119 | /* We now have the result, just need to scale it to the required precision */ 120 | ret = val; 121 | 122 | if (result_frac_bits > DB_CALC_PREC) { 123 | return ret<<(result_frac_bits-DB_CALC_PREC); 124 | } 125 | else { 126 | return ret>>(DB_CALC_PREC-result_frac_bits); 127 | } 128 | } 129 | 130 | #ifdef TEST_DBCALC 131 | #include 132 | 133 | int main() { 134 | 135 | /* Check that we don't overflow up to 9db 136 | Should give a value just under 0x80000 */ 137 | printhexln(db_to_mult(9,0,16)); 138 | 139 | /* This test recreates the old db lookup table */ 140 | printuintln(0xffffffff); 141 | for (int i=1;i<128;i++) { 142 | printuintln(db_to_mult(-i,0,32)); 143 | } 144 | return 0; 145 | } 146 | #endif 147 | -------------------------------------------------------------------------------- /firmware/mixer.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v3 4 | * Build: b8b701010296296860417a33c03ee283d2b4ad97 5 | * File: mixer.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | 21 | 22 | #include 23 | #include 24 | #include 25 | #include "mixer.h" 26 | #include "devicedefines.h" 27 | 28 | #define LDW(dest, array, index) asm("ldw %0, %1[%2]":"=r"(dest):"r"(array),"r"(index)) 29 | #define STW(array, index, value) asm("stw %0, %1[%2]"::"r"(value),"r"(array),"r"(index)) 30 | 31 | #ifdef MIXER 32 | 33 | #define FAST_MIXER 1 34 | 35 | static int mix_in_samples[MIX_INPUTS]; 36 | static int mix_out_samples[MAX_MIX_COUNT]; 37 | static int aux_in_samples[2][AUX_COUNT]; 38 | static int usb_in_samples[NUM_USB_CHAN_IN]; 39 | 40 | static int mix_mult[MAX_MIX_COUNT][MIX_INPUTS]; 41 | static int in_mix_mult[2][AUX_COUNT]; 42 | static int aux_balanced[AUX_COUNT]; 43 | 44 | static int input_map[NUM_USB_CHAN_OUT] = { 45 | 0, 1, 4, 5, 2, 3, 46 | }; 47 | 48 | static int output_map[MAX_MIX_COUNT] = { 49 | 6, 7, 0, 1, 2, 3, 4, 5, 50 | }; 51 | 52 | int doMix_out(const int samples[], int mult[]); 53 | int doMix_in(const int samples[], int mult[]); 54 | 55 | #pragma unsafe arrays 56 | void giveSamplesToHost(chanend c) 57 | { 58 | #pragma loop unroll 59 | for (int i = 0; i < NUM_USB_CHAN_IN; i++) 60 | outuint(c, usb_in_samples[i]); 61 | } 62 | 63 | #pragma unsafe arrays 64 | static void getSamplesFromHost(chanend c) 65 | { 66 | #pragma loop unroll 67 | for (int i = 0; i < NUM_USB_CHAN_OUT; i++) 68 | STW(mix_in_samples, input_map[i], inuint(c)); 69 | } 70 | 71 | #pragma unsafe arrays 72 | static void giveSamplesToDevice(chanend c) 73 | { 74 | #pragma loop unroll 75 | for (int i = 0; i < MAX_MIX_COUNT; i++) 76 | outuint(c, mix_out_samples[output_map[i]]); 77 | } 78 | 79 | #pragma unsafe arrays 80 | static void getSamplesFromDevice(chanend c) 81 | { 82 | #pragma loop unroll 83 | for (int i = 0; i < IN_CHANNELS; i++) 84 | STW(mix_in_samples, i + NUM_USB_CHAN_OUT, inuint(c)); 85 | } 86 | 87 | #pragma unsafe arrays 88 | void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2) 89 | { 90 | int mixed; 91 | unsigned cmd; 92 | 93 | while (1) { 94 | inuint(c_mixer2); 95 | 96 | /* Request data from decouple thread */ 97 | outuint(c_host, 0); 98 | 99 | /* Between request to decouple and respose ~ 400nS latency for interrupt to fire */ 100 | select 101 | { 102 | case inuint_byref(c_mix_ctl, cmd): 103 | { 104 | int mix, index, val; 105 | switch (cmd) 106 | { 107 | case SET_MIX_MULT: 108 | for (int i = 0; i < MAX_MIX_COUNT; i++) { 109 | for (int j = 0; j < MIX_INPUTS; j++) { 110 | STW(mix_mult[i], j, inuint(c_mix_ctl)); 111 | } 112 | } 113 | for (int i = 0; i < 2; i++) { 114 | for (int j = 0; j < AUX_COUNT; j++) { 115 | STW(in_mix_mult[i], j, inuint(c_mix_ctl)); 116 | } 117 | } 118 | for (int i = 0; i < AUX_COUNT; i++) { 119 | STW(aux_balanced, i, inuint(c_mix_ctl)); 120 | } 121 | inct(c_mix_ctl); 122 | break; 123 | } 124 | break; 125 | } 126 | default: 127 | /* Select default */ 128 | break; 129 | } 130 | 131 | inuint(c_host); 132 | outuint(c_mixer2, 0); 133 | giveSamplesToHost(c_host); 134 | 135 | outuint(c_mixer2, 0); 136 | inuint(c_mixer2); 137 | getSamplesFromHost(c_host); 138 | outuint(c_mixer2, 0); 139 | inuint(c_mixer2); 140 | 141 | mixed = doMix_out(mix_in_samples, mix_mult[0]); 142 | STW(mix_out_samples, 0, mixed); 143 | #if MAX_MIX_COUNT > 2 144 | mixed = doMix_out(mix_in_samples, mix_mult[2]); 145 | STW(mix_out_samples, 2, mixed); 146 | #endif 147 | #if MAX_MIX_COUNT > 4 148 | mixed = doMix_out(mix_in_samples, mix_mult[4]); 149 | STW(mix_out_samples, 4, mixed); 150 | #endif 151 | #if MAX_MIX_COUNT > 6 152 | mixed = doMix_out(mix_in_samples, mix_mult[6]); 153 | STW(mix_out_samples, 6, mixed); 154 | #endif 155 | for (int i = 0; i < AUX_COUNT; i++) 156 | STW(aux_in_samples[0], i, mix_in_samples[6 + i * 2]); 157 | mixed = doMix_in(aux_in_samples[0], in_mix_mult[0]); 158 | STW(usb_in_samples, 0, mixed); 159 | } 160 | } 161 | 162 | #pragma unsafe arrays 163 | void mixer2(chanend c_mixer1, chanend c_audio) 164 | { 165 | int mixed; 166 | 167 | while (1) { 168 | outuint(c_mixer1, 0); 169 | inuint(c_audio); 170 | (void) inuint(c_mixer1); 171 | giveSamplesToDevice(c_audio); 172 | inuint(c_mixer1); 173 | outuint(c_mixer1, 0); 174 | getSamplesFromDevice(c_audio); 175 | #pragma loop unroll 176 | for (int i = 0; i < AUX_COUNT; i++) { 177 | int off = i*2 + NUM_USB_CHAN_OUT; 178 | if (aux_balanced[i]) { 179 | int p = mix_in_samples[off] >> 1; 180 | int m = mix_in_samples[off+1] >> 1; 181 | int r = p - m; 182 | STW(mix_in_samples, off, r); 183 | STW(mix_in_samples, off+1, r); 184 | } 185 | } 186 | inuint(c_mixer1); 187 | outuint(c_mixer1, 0); 188 | 189 | #if MAX_MIX_COUNT > 1 190 | mixed = doMix_out(mix_in_samples, mix_mult[1]); 191 | STW(mix_out_samples, 1, mixed); 192 | #endif 193 | #if MAX_MIX_COUNT > 3 194 | mixed = doMix_out(mix_in_samples, mix_mult[3]); 195 | STW(mix_out_samples, 3, mixed); 196 | #endif 197 | #if MAX_MIX_COUNT > 5 198 | mixed = doMix_out(mix_in_samples, mix_mult[5]); 199 | STW(mix_out_samples, 5, mixed); 200 | #endif 201 | #if MAX_MIX_COUNT > 7 202 | mixed = doMix_out(mix_in_samples, mix_mult[7]); 203 | STW(mix_out_samples, 7, mixed); 204 | #endif 205 | for (int i = 0; i < AUX_COUNT; i++) 206 | STW(aux_in_samples[1], i, mix_in_samples[7 + i * 2]); 207 | mixed = doMix_in(aux_in_samples[1], in_mix_mult[1]); 208 | STW(usb_in_samples, 1, mixed); 209 | } 210 | } 211 | 212 | void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl) 213 | { 214 | chan c; 215 | for (int i = 0; i < MIX_INPUTS; i++) 216 | mix_in_samples[i] = 0; 217 | for (int i = 0; i < MAX_MIX_COUNT; i++) 218 | mix_out_samples[i] = 0; 219 | for (int i = 0; i < NUM_USB_CHAN_IN; i++) 220 | usb_in_samples[i] = 0; 221 | 222 | for (int i = 0; i < MAX_MIX_COUNT; i++) { 223 | for (int j = 0;j < MIX_INPUTS; j++) { 224 | mix_mult[i][j] = 0; 225 | } 226 | } 227 | for (int i = 0; i < 2; i++) { 228 | for (int j = 0; j < AUX_COUNT; j++) { 229 | in_mix_mult[i][j] = 0; 230 | } 231 | } 232 | for (int i = 0; i < AUX_COUNT; i++) 233 | aux_balanced[i] = 0; 234 | par { 235 | mixer1(c_mix_in, c_mix_ctl, c); 236 | mixer2(c, c_mix_out); 237 | } 238 | } 239 | 240 | #endif 241 | -------------------------------------------------------------------------------- /firmware/XUD_EpFunctions.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_xud 3 | * Version: 0v28 4 | * Build: 82d90eaec387c8d8d70f373b60f30ed4792d7bbd 5 | * File: XUD_EpFunctions.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** @file XUD_EPFunctions.xc 21 | * @brief Implementation of user API fuctions. See xud.h for documentation. 22 | * @author Ross Owen, XMOS Limited 23 | * @version 0.9 24 | **/ 25 | 26 | #include 27 | #include 28 | 29 | #include "xud.h" 30 | #include "usb.h" 31 | 32 | #if 0 33 | #pragma xta command "analyse path XUD_SetData_DataRdy XUD_SetData_OutputLoop_Out" 34 | #pragma xta command "set required - 266 ns" 35 | 36 | #endif 37 | 38 | 39 | static int min(int x, int y) 40 | { 41 | if (x < y) 42 | return x; 43 | return y; 44 | } 45 | 46 | void XUD_ParseSetupPacket(unsigned char b[], SetupPacket &p) 47 | { 48 | // Byte 0: bmRequestType. 49 | p.bmRequestType.Recipient = b[0] & 0x1f; 50 | p.bmRequestType.Type = (b[0] & 0x60) >> 5; 51 | p.bmRequestType.Direction = b[0] >> 7; 52 | 53 | // Byte 1: bRequest 54 | p.bRequest = b[1]; 55 | 56 | // Bytes [2:3] wValue 57 | p.wValue = (b[3] << 8) | (b[2]); 58 | 59 | // Bytes [4:5] wIndex 60 | p.wIndex = (b[5] << 8) | (b[4]); 61 | 62 | // Bytes [6:7] wLength 63 | p.wLength = (b[7] << 8) | (b[6]); 64 | 65 | } 66 | 67 | void XUD_PrintSetupPacket(SetupPacket sp) 68 | { 69 | printstr("Setup data\n"); 70 | printstr("bmRequestType.Recipient: "); 71 | printhexln(sp.bmRequestType.Recipient); 72 | printstr("bmRequestType.Type: "); 73 | printhexln(sp.bmRequestType.Type); 74 | printstr("bmRequestType.Direction: "); 75 | printhexln(sp.bmRequestType.Direction); 76 | printstr("bRequest: "); 77 | printhexln(sp.bRequest); 78 | printstr("bmRequestType.wValue: "); 79 | printhexln(sp.wValue); 80 | printstr("bmRequestType.wIndex: "); 81 | printhexln(sp.wIndex); 82 | printstr("bmRequestType.wLength: "); 83 | printhexln(sp.wLength); 84 | } 85 | 86 | /** XUD_GetBuffer_() 87 | * @brief Requests data from the endpoint related to the passed channel 88 | * @param c Channel to USB I/O thread for this endpoint 89 | * @param buffer Buffer for returned data 90 | * @return datalength of received data in bytes 91 | **/ 92 | int XUD_GetBuffer(XUD_ep c, unsigned char buffer[]) 93 | { 94 | return XUD_GetData(c, buffer); 95 | } 96 | 97 | 98 | /** XUD_GetSetupBuffer() 99 | * @brief Request setup data from usb buffer for a specific EP, pauses until data is available. 100 | * @param c Data channel to/from XUD 101 | * @param c_ctl Control channel from XUD 102 | * @param epNum EP number 103 | * @param buffer char buffer passed by ref into which data is returned 104 | * @return datalength in bytes (always 8), -1 if kill received 105 | **/ 106 | int XUD_GetSetupBuffer(XUD_ep c_out, unsigned char buffer[]) 107 | { 108 | return XUD_GetSetupData(c_out, buffer); 109 | } 110 | 111 | 112 | 113 | 114 | /** XUD_SetBuffer_ResetPid(() 115 | * @brief Sends USB data with PID reset to specified 116 | * @param c 117 | * @param epNum 118 | * @param buffer 119 | * @param datalengh in bytes! 120 | **/ 121 | int XUD_SetBuffer_ResetPid(XUD_ep c, unsigned char buffer[], unsigned datalength, unsigned char pid) 122 | { 123 | return XUD_SetData(c, buffer, datalength, 0, pid); 124 | } 125 | 126 | int XUD_SetBuffer(XUD_ep c, unsigned char buffer[], unsigned datalength) 127 | { 128 | /* No PID reset, 0 start index */ 129 | return XUD_SetData(c, buffer, datalength, 0, 0); 130 | } 131 | 132 | 133 | 134 | 135 | /* Datalength in bytes */ 136 | int XUD_SetBuffer_ResetPid_EpMax(XUD_ep c, unsigned epNum, unsigned char buffer[], 137 | unsigned datalength, unsigned epMax, unsigned char pid) 138 | { 139 | int i = 0; 140 | 141 | /* Note: We could encompass this in the SetData function */ 142 | if(datalength <= epMax) 143 | { 144 | /* Datalength is less than the maximum per transaction of the EP, so just send */ 145 | return XUD_SetData(c, buffer, datalength, 0, pid); 146 | } 147 | else 148 | { 149 | /* Send first packet out and reset PID */ 150 | if (XUD_SetData(c, buffer, epMax, 0, pid) < 0) return -1; 151 | i+= epMax; 152 | datalength-=epMax; 153 | 154 | while(1) 155 | { 156 | 157 | if(datalength > epMax) 158 | { 159 | /* PID Automatically toggled */ 160 | if (XUD_SetData(c, buffer, epMax, i, 0) < 0) return -1; 161 | 162 | datalength-=epMax; 163 | i += epMax; 164 | } 165 | else 166 | { 167 | /* PID automatically toggled */ 168 | if (XUD_SetData(c, buffer, datalength, i, 0) < 0) return -1; 169 | 170 | break; //out of while loop 171 | } 172 | } 173 | } 174 | 175 | return 0; 176 | } 177 | 178 | 179 | 180 | /* TODO Should take ep max length as a param - currently hardcoded as 64 */ 181 | int XUD_DoGetRequest(XUD_ep c, XUD_ep c_in, uint8 buffer[], unsigned length, unsigned requested) 182 | { 183 | unsigned char tmpBuffer[1024]; 184 | 185 | if (XUD_SetBuffer_ResetPid_EpMax(c_in, 0, buffer, min(length, requested), 64, PIDn_DATA1) < 0) 186 | { 187 | return -1; 188 | } 189 | 190 | /* USB 2.0 8.5.3.2 */ 191 | if((requested > length) && (length % 64) == 0) 192 | { 193 | XUD_SetBuffer(c_in, tmpBuffer, 0); 194 | } 195 | 196 | /* Status stage */ 197 | return XUD_GetData(c, tmpBuffer); 198 | } 199 | 200 | 201 | /* Send 0 length status 202 | * Simply sends a 0 length packet */ 203 | //TODO dont need epNum 204 | int XUD_DoSetRequestStatus(XUD_ep c, unsigned epNum) 205 | { 206 | unsigned char tmp[8]; 207 | 208 | return XUD_SetData(c, tmp, 0, 0, PIDn_DATA1); 209 | } 210 | 211 | #ifdef XUD_DEBUG_VERSION 212 | void XUD_Error(char errString[]) 213 | { 214 | printstr("XUD Err: "); 215 | printstr(errString); 216 | } 217 | 218 | void XUD_Error_hex(char errString[], int i_err) 219 | { 220 | printstr("XUD Err: "); 221 | printstr(errString); 222 | printhexln(i_err); 223 | } 224 | #endif 225 | 226 | 227 | //??? 228 | int XUD_ResetEndpoint0(chanend one, chanend ?two) 229 | { 230 | int busStateCt; 231 | int busSpeed; 232 | 233 | 234 | 235 | outct(one, XS1_CT_END); 236 | busStateCt = inct(one); 237 | 238 | if (!isnull(two)) 239 | { 240 | outct(two, XS1_CT_END); 241 | inct(two); 242 | } 243 | 244 | /* Inspect for reset, if so we expect a CT with speed */ 245 | if(busStateCt == USB_RESET_TOKEN) 246 | { 247 | busSpeed = inuint(one); 248 | if(!isnull(two)) 249 | { 250 | inuint(two); 251 | } 252 | 253 | return busSpeed; 254 | } 255 | else 256 | { 257 | /* Suspend cond */ 258 | /* TODO Currently suspend condition is never communicated */ 259 | return XUD_SUSPEND; 260 | } 261 | } 262 | 263 | XUD_ep XUD_Init_Ep(chanend c) 264 | { 265 | XUD_ep ep = inuint(c); 266 | return ep; 267 | } 268 | 269 | 270 | -------------------------------------------------------------------------------- /firmware/usb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_shared 3 | * Version: 1v15 4 | * Build: ba2d74b0702e5e78a497515f08dfb1ebe601cd36 5 | * File: usb.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** @file usb.h 21 | * @brief Defines from the Universal Serial Bus Specification Revision 2.0 22 | * @author Ross Owen, XMOS Limited 23 | * @version 1.0 24 | **/ 25 | 26 | /* USB Class Codes (from usb.org) */ 27 | #define USE_CLASS 0x00 /* Use class information in the interface descriptors */ 28 | #define AUDIO 0x01 29 | #define COMMUNICATIONS 0x02 30 | #define HID 0x03 31 | #define PHYSICAL 0x05 32 | #define IMAGE 0x06 33 | #define PRINTER 0x07 34 | #define MASS_STORAGE 0x08 35 | #define HUB 0x09 36 | #define CDC_DATA 0x0A 37 | #define SMART_CARD 0x0B 38 | #define CONTENT_SECURITY 0x0D 39 | #define VIDEO 0x0E 40 | //... 41 | #define VENDOR_SPECIFIC 0x00 42 | 43 | 44 | /* Table 8-1. PID Types */ 45 | #define OUT 0x1 /* Tokens */ 46 | #define IN 0x9 47 | #define SOF 0x5 48 | #define SETUP 0xD 49 | #define DATA0 0x3 /* Data packet PID even */ 50 | #define DATA1 0xB /* Data packet PID odd */ 51 | #define DATA2 0x7 /* Data packet PID high-speed, high bandwidth isoc transaction in a microframe */ 52 | #define MDATA 0xF /* Data packet PID high-speed and high bandwidth isoc transactions */ 53 | #define ACK 0x2 /* Receiver accepts error-free data packet */ 54 | #define NAK 0xA /* Receiving device cannot accept data of transmitting device cannot send data */ 55 | #define STALL 0xE /* Endpoint is halted or a control pipe request is not supported */ 56 | #define PRE 0xC 57 | #define ERR 0xC 58 | #define SPLIT 0x8 59 | #define PING 0x4 /* Hign-speed flow control probe for bulk/control endpoint */ 60 | 61 | 62 | /* 9.3 USB Device Requests: Table 9-2 Format of Setup Data */ 63 | /* bmRequestType: */ 64 | #define BM_REQTYPE_DIRECTION_OUT 0 /* Host to device */ 65 | #define BM_REQTYPE_DIRECTION_IN 1 /* Device to host */ 66 | 67 | #define BM_REQTYPE_TYPE_STANDARD 0x00 68 | #define BM_REQTYPE_TYPE_CLASS 0x01 69 | #define BM_REQTYPE_TYPE_VENDOR 0x02 70 | 71 | #define BM_REQTYPE_RECIP_DEV 0x00 72 | #define BM_REQTYPE_RECIP_INTER 0x01 73 | #define BM_REQTYPE_RECIP_EP 0x02 74 | #define BM_REQTYPE_RECIP_OTHER 0x03 75 | 76 | 77 | /* Table 9-4. Standard Request Codes */ 78 | /* bRequest */ 79 | #define GET_STATUS 0x00 80 | #define CLEAR_FEATURE 0x01 81 | #define SET_FEATURE 0x03 82 | #define SET_ADDRESS 0x05 83 | #define GET_DESCRIPTOR 0x06 84 | #define SET_DESCRIPTOR 0x07 85 | #define GET_CONFIGURATION 0x08 86 | #define SET_CONFIGURATION 0x09 87 | #define GET_INTERFACE 0x0A 88 | #define SET_INTERFACE 0x0B 89 | #define SYNCH_FRAME 0x0C 90 | 91 | 92 | /* Table 9-5. Descriptor Types */ 93 | #define DEVICE 0x01 94 | #define CONFIGURATION 0x02 95 | #define STRING 0x03 96 | #define INTERFACE 0x04 97 | #define ENDPOINT 0x05 98 | #define DEVICE_QUALIFIER 0x06 99 | #define OTHER_SPEED_CONFIGURATION 0x07 100 | #define INTERFACE_POWER 0x08 101 | 102 | 103 | /* Table 9-6. Standard Feature Selectors */ 104 | #define DEVICE_REMOTE_WAKEUP 0x01 /* Recipient: Device */ 105 | #define ENDPOINT_HALT 0x00 /* Recipient: Endpoint */ 106 | #define TEST_MODE 0x02 /* Recipient: Device */ 107 | 108 | #define STANDARD_DEVICE_REQUEST 0x00 109 | #define STANDARD_INTERFACE_REQUEST 0x01 110 | #define STANDARD_ENDPOINT_REQUEST 0x02 111 | #define VENDOR_DEVICE_REQUEST 0x40 112 | #define VENDOR_ENDPOINT_REQUEST 0x42 113 | #define CLASS_INTERFACE_REQUEST 0x21 114 | #define CLASS_ENDPOINT_REQUEST 0x22 115 | 116 | 117 | 118 | #define WVAL_EP_HALT 0 119 | 120 | 121 | 122 | // Audio 123 | #define B_REQ_SET_CUR 0x01 124 | #define B_REQ_GET_CUR 0x81 125 | #define B_REQ_GET_MIN 0x82 126 | #define B_REQ_GET_MAX 0x83 127 | #define B_REQ_GET_RES 0x84 128 | 129 | /* wValue for Get Descriptor (indicates required descriptor) 130 | * Note: top byte used only 131 | */ 132 | #define WVALUE_GETDESC_DEV (DEVICE << 8) 133 | #define WVALUE_GETDESC_CONFIG (CONFIGURATION << 8) 134 | #define WVALUE_GETDESC_STRING (STRING << 8) 135 | #define WVALUE_GETDESC_INTER (INTERFACE << 8) 136 | #define WVALUE_GETDESC_DEVQUAL (DEVICE_QUALIFIER << 8) 137 | #define WVALUE_GETDESC_OSPEED_CFG (OTHER_SPEED_CONFIGURATION << 8) 138 | 139 | // Low byte values: 140 | #define WVALUE_GETDESC_STRING_LANGIDS 0x0 141 | #define WVALUE_GETDESC_STRING_IPRODUCT 0x2 142 | 143 | //bDeviceClass 144 | #define XUD_DESC_DEV_B_DEVCLASS_INTER 0x0 // Interface descriptor speicifies class 145 | #define XUD_DESC_DEV_B_DEVCLASS_COMMS 0x2 // Communications 146 | 147 | // Defines for Test mode 148 | #define WINDEX_TEST_J 0x1 149 | #define WINDEX_TEST_K 0x2 150 | #define WINDEX_TEST_SE0_NAK 0x3 151 | #define WINDEX_TEST_PACKET 0x4 152 | #define WINDEX_TEST_FORCE_ENABLE 0x5 153 | 154 | //* DEPRECATED DEFINES: 155 | // TODO rm these defines 156 | // Raw PIDs 157 | #define PID_OUT 0x01 158 | #define PID_ACK 0x02 159 | #define PID_IN 0x09 160 | #define PID_SOF 0x05 161 | #define PID_SETUP 0x0d 162 | #define PID_PING 0x04 163 | 164 | // PIDs with error check 165 | // Token 166 | #define PIDn_OUT 0xe1 167 | #define PIDn_IN 0x69 168 | #define PIDn_SOF 0xa5 169 | #define PIDn_SETUP 0x2d 170 | 171 | // Data PIDs 172 | #define PIDn_DATA0 0xc3 173 | #define PIDn_DATA1 0x4b 174 | #define PID_DATA0 0x3 175 | #define PID_DATA1 0xb 176 | 177 | #define PIDn_ACK 0xd2 178 | #define PIDn_NAK 0x5a 179 | #define PIDn_STALL 0x1e 180 | 181 | #if 0 182 | //bRequest 183 | #define B_REQ_GETSTATUS 0x00 184 | #define B_REQ_SETFEATURE 0x03 185 | #define B_REQ_CLEARFEATURE 0x01 186 | #define B_REQ_GETDESC 0x06 187 | #define B_REQ_SETADDR 0x05 188 | #define B_REQ_GETCONFIG 0x08 189 | #define B_REQ_SETCONFIG 0x09 190 | #define B_REQ_GETINTER 0x0a 191 | #define B_REQ_SETINTER 0x0b 192 | #endif 193 | 194 | #if 0 195 | ////////// 196 | // Descriptor types: 197 | #define XUD_DESC_DEV_B_DESCTYPE_DEVICE 0x1 198 | #define XUD_DESC_DEV_B_DESCTYPE_CONFIG 0x2 199 | #define XUD_DESC_DEV_B_DESCTYPE_STRING 0x3 200 | #define XUD_DESC_DEV_B_DESCTYPE_INTER 0x4 201 | #define XUD_DESC_DEV_B_DESCTYPE_EP 0x5 202 | #define XUD_DESC_DEV_B_DESCTYPE_DEVQUAL 0x6 203 | #define XUD_DESC_DEV_B_DESCTYPE_OSPEED_CFG 0x7 204 | 205 | #define XUD_DESC_DEV_B_DESCTYPE_HID 0x21 206 | #endif 207 | -------------------------------------------------------------------------------- /client/setdsp.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from math import cos, sin, pi, sqrt 3 | import struct 4 | import usb.core 5 | import usb.util 6 | 7 | CHANNELS = 6 8 | FRACTIONALBITS = 28 9 | SET_DSP_BIQUAD = 1 10 | SET_DSP_DELAY = 2 11 | DSP_FILTERS = 15 12 | FS = 96000.0 13 | 14 | class Biquad(object): 15 | def __init__(self, b0, b1, b2, a0, a1, a2): 16 | self.b0 = b0 / a0 17 | self.b1 = b1 / a0 18 | self.b2 = b2 / a0 19 | self.a1 = a1 / a0 20 | self.a2 = a2 / a0 21 | @property 22 | def coefs(self): 23 | return (self.b0, self.b1, self.b2, -self.a1, -self.a2) 24 | def apply_gain(self, gain): 25 | v = 10 ** (gain / 20.0) 26 | self.b0 *= v 27 | self.b1 *= v 28 | self.b2 *= v 29 | def __str__(self): 30 | return 'Biquad<%.03f %.03f %.03f %.03f %.03f>' % self.coefs 31 | 32 | class SimpleBiquad(Biquad): 33 | def __init__(self, f0, Q): 34 | self.f0 = f0 35 | self.Q = Q 36 | self.build() 37 | Biquad.__init__(self, self.b0, self.b1, self.b2, self.a0, self.a1, self.a2) 38 | @property 39 | def w0(self): 40 | return 2 * pi * self.f0 / FS 41 | @property 42 | def alpha(self): 43 | return sin(self.w0) / (2.0 * self.Q) 44 | def __str__(self): 45 | return '%s(f0=%.03f, Q=%.03f)' % (self.__class__.__name__, self.f0, self.Q) 46 | 47 | class GainBiquad(SimpleBiquad): 48 | def __init__(self, f0, Q, gain): 49 | self.gain = gain 50 | SimpleBiquad.__init__(self, f0, Q) 51 | @property 52 | def A(self): 53 | return 10 ** (self.gain / 40.0) 54 | def __str__(self): 55 | return '%s(f0=%.03f, Q=%.03f, gain=%.02f)' % (self.__class__.__name__, self.f0, self.Q, self.gain) 56 | 57 | class LPF(SimpleBiquad): 58 | def build(self): 59 | self.b0 = (1 - cos(self.w0))/2 60 | self.b1 = 1 - cos(self.w0) 61 | self.b2 = (1 - cos(self.w0))/2 62 | self.a0 = 1 + self.alpha 63 | self.a1 = -2*cos(self.w0) 64 | self.a2 = 1 - self.alpha 65 | 66 | class HPF(SimpleBiquad): 67 | def build(self): 68 | self.b0 = (1 + cos(self.w0))/2 69 | self.b1 = -(1 + cos(self.w0)) 70 | self.b2 = (1 + cos(self.w0))/2 71 | self.a0 = 1 + self.alpha 72 | self.a1 = -2*cos(self.w0) 73 | self.a2 = 1 - self.alpha 74 | 75 | class BPFSkirt(SimpleBiquad): 76 | def build(self): 77 | self.b0 = sin(self.w0)/2 78 | self.b1 = 0 79 | self.b2 = -sin(self.w0)/2 80 | self.a0 = 1 + self.alpha 81 | self.a1 = -2*cos(self.w0) 82 | self.a2 = 1 - self.alpha 83 | 84 | class BPFPeak(SimpleBiquad): 85 | def build(self): 86 | self.b0 = self.alpha 87 | self.b1 = 0 88 | self.b2 = -self.alpha 89 | self.a0 = 1 + self.alpha 90 | self.a1 = -2*cos(self.w0) 91 | self.a2 = 1 - self.alpha 92 | 93 | class notch(SimpleBiquad): 94 | def build(self): 95 | self.b0 = 1 96 | self.b1 = -2*cos(self.w0) 97 | self.b2 = 1 98 | self.a0 = 1 + self.alpha 99 | self.a1 = -2*cos(self.w0) 100 | self.a2 = 1 - self.alpha 101 | 102 | class APF(SimpleBiquad): 103 | def build(self): 104 | self.b0 = 1 - self.alpha 105 | self.b1 = -2*cos(self.w0) 106 | self.b2 = 1 + self.alpha 107 | self.a0 = 1 + self.alpha 108 | self.a1 = -2*cos(self.w0) 109 | self.a2 = 1 - self.alpha 110 | 111 | class PeakingEQ(GainBiquad): 112 | def build(self): 113 | self.b0 = 1 + self.alpha*self.A 114 | self.b1 = -2*cos(self.w0) 115 | self.b2 = 1 - self.alpha*self.A 116 | self.a0 = 1 + self.alpha/self.A 117 | self.a1 = -2*cos(self.w0) 118 | self.a2 = 1 - self.alpha/self.A 119 | 120 | class LowShelf(GainBiquad): 121 | def build(self): 122 | A = self.A 123 | self.b0 = A*( (A+1) - (A-1)*cos(self.w0) + 2*sqrt(A)*self.alpha ) 124 | self.b1 = 2*A*( (A-1) - (A+1)*cos(self.w0) ) 125 | self.b2 = A*( (A+1) - (A-1)*cos(self.w0) - 2*sqrt(A)*self.alpha ) 126 | self.a0 = (A+1) + (A-1)*cos(self.w0) + 2*sqrt(A)*self.alpha 127 | self.a1 = -2*( (A-1) + (A+1)*cos(self.w0) ) 128 | self.a2 = (A+1) + (A-1)*cos(self.w0) - 2*sqrt(A)*self.alpha 129 | 130 | class HighShelf(GainBiquad): 131 | def build(self): 132 | A = self.A 133 | self.b0 = A*( (A+1) + (A-1)*cos(self.w0) + 2*sqrt(A)*self.alpha ) 134 | self.b1 = -2*A*( (A-1) + (A+1)*cos(self.w0) ) 135 | self.b2 = A*( (A+1) + (A-1)*cos(self.w0) - 2*sqrt(A)*self.alpha ) 136 | self.a0 = (A+1) - (A-1)*cos(self.w0) + 2*sqrt(A)*self.alpha 137 | self.a1 = 2*( (A-1) - (A+1)*cos(self.w0) ) 138 | self.a2 = (A+1) - (A-1)*cos(self.w0) - 2*sqrt(A)*self.alpha 139 | 140 | class LowShelfS(LowShelf): 141 | def __init__(self, f0, S, gain): 142 | self.gain = gain 143 | Q = 1.0/sqrt((self.A + 1.0/self.A)*(1.0/S - 1.0) + 2.0) 144 | LowShelf.__init__(self, f0, Q, gain) 145 | 146 | class HighShelfS(HighShelf): 147 | def __init__(self, f0, S, gain): 148 | self.gain = gain 149 | Q = 1.0/sqrt((self.A + 1.0/self.A)*(1.0/S - 1.0) + 2.0) 150 | HighShelf.__init__(self, f0, Q, gain) 151 | 152 | class AudioInterface(object): 153 | def __init__(self): 154 | self.dev = usb.core.find(idVendor=0x20b1, idProduct=0x0004) 155 | if self.dev is None: 156 | raise Exception('Device not found') 157 | 158 | def set_biquad(self, channel, index, biquad): 159 | params = [int(i*(1< 4: 227 | gain = float(sys.argv[4]) 228 | data.biquads[-1].apply_gain(gain) 229 | dev.reset_channel(channel) 230 | for i,biquad in enumerate(data.biquads): 231 | print '%d: %s' % (i, biquad) 232 | dev.set_biquad(channel, i, biquad) 233 | elif cmd == 'reset': 234 | if len(sys.argv) > 2: 235 | dev.reset_channel(int(sys.argv[2])) 236 | else: 237 | dev.reset() 238 | elif cmd == 'set': 239 | channel = int(sys.argv[2]) 240 | idx = int(sys.argv[3]) 241 | args = map(float, sys.argv[4:]) 242 | dev.set_biquad(channel, idx, Biquad(*args)) 243 | elif cmd == 'delay': 244 | channel = int(sys.argv[2]) 245 | delay = float(sys.argv[3]) 246 | dev.set_delay(channel, delay) 247 | else: 248 | print "Unknown command" 249 | -------------------------------------------------------------------------------- /firmware/interrupt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v0 4 | * Build: c0b2e34218aec54736ad1259d95377c59ed03dd3 5 | * File: interrupt.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef __interrupt_h__ 21 | #define __interrupt_h__ 22 | 23 | #define store_args0(c) \ 24 | asm("kentsp 19; stw %0, sp[1]; krestsp 19"::"r"(c)); 25 | 26 | #define store_args1(c,x) \ 27 | asm("kentsp 20; stw %0, sp[1]; stw %1, sp[2]; krestsp 20"::"r"(c),"r"(x)); 28 | 29 | #define store_args2(c,x0,x1) \ 30 | asm("kentsp 21; stw %0, sp[1];" \ 31 | "stw %1, sp[2];" \ 32 | "stw %2, sp[3];" \ 33 | " krestsp 21"::"r"(c),"r"(x0),"r"(x1)); 34 | 35 | #define store_args3(c,x0,x1,x2) \ 36 | asm("kentsp 22; stw %0, sp[1];" \ 37 | "stw %1, sp[2];" \ 38 | "stw %2, sp[3];" \ 39 | "stw %3, sp[4];" \ 40 | " krestsp 22"::"r"(c),"r"(x0),"r"(x1),"r"(x2)); 41 | 42 | #define store_args4(c,x0,x1,x2,x3) \ 43 | asm("kentsp 23; stw %4, sp[1];" \ 44 | "stw %0, sp[2];" \ 45 | "stw %1, sp[3];" \ 46 | "stw %2, sp[4];" \ 47 | "stw %3, sp[5];" \ 48 | " krestsp 23"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3)); 49 | 50 | #define store_args5(c,x0,x1,x2,x3,x4) \ 51 | asm("kentsp 24;" \ 52 | "stw %4, sp[1];" \ 53 | "stw %5, sp[2];" \ 54 | "stw %0, sp[3];" \ 55 | "stw %1, sp[4];" \ 56 | "stw %2, sp[5];" \ 57 | "stw %3, sp[6];" \ 58 | " krestsp 24"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4)); 59 | 60 | #define store_args6(c,x0,x1,x2,x3,x4,x5) \ 61 | asm("kentsp 25;" \ 62 | "stw %4, sp[1];" \ 63 | "stw %5, sp[2];" \ 64 | "stw %6, sp[3];" \ 65 | "stw %0, sp[4];" \ 66 | "stw %1, sp[5];" \ 67 | "stw %2, sp[6];" \ 68 | "stw %3, sp[7];" \ 69 | " krestsp 25"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5)); 70 | 71 | #define store_args7(c,x0,x1,x2,x3,x4,x5,x6) \ 72 | asm("kentsp 26;" \ 73 | "stw %4, sp[1];" \ 74 | "stw %5, sp[2];" \ 75 | "stw %6, sp[3];" \ 76 | "stw %7, sp[4];" \ 77 | "stw %0, sp[5];" \ 78 | "stw %1, sp[6];" \ 79 | "stw %2, sp[7];" \ 80 | "stw %3, sp[8];" \ 81 | " krestsp 26"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5),"r"(x6)); 82 | 83 | #define store_args8(c,x0,x1,x2,x3,x4,x5,x6,x7) \ 84 | asm("kentsp 27;" \ 85 | "stw %4, sp[1];" \ 86 | "stw %5, sp[2];" \ 87 | "stw %6, sp[3];" \ 88 | "stw %7, sp[4];" \ 89 | "stw %8, sp[5];" \ 90 | "stw %0, sp[6];" \ 91 | "stw %1, sp[7];" \ 92 | "stw %2, sp[8];" \ 93 | "stw %3, sp[9];" \ 94 | " krestsp 27"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5),"r"(x6),"r"(x7)); 95 | 96 | 97 | 98 | 99 | #define load_args0(f) \ 100 | "ldw r0, sp[1]\n" 101 | 102 | #define load_args1(f)\ 103 | "ldw r0, sp[1]\n" \ 104 | "ldw r1, sp[2]\n" 105 | 106 | #define load_args2(f)\ 107 | "ldw r0, sp[1]\n" \ 108 | "ldw r1, sp[2]\n" \ 109 | "ldw r2, sp[3]\n" 110 | 111 | #define load_args3(f)\ 112 | "ldw r0, sp[1]\n" \ 113 | "ldw r1, sp[2]\n" \ 114 | "ldw r2, sp[3]\n" \ 115 | "ldw r3, sp[4]\n" 116 | 117 | #define load_argsn(f, args) \ 118 | ".linkset __"#f"_handler_arg0, "#args"-2\n"\ 119 | "ldw r0, sp[" "__"#f"_handler_arg0" "]\n" \ 120 | ".linkset __"#f"_handler_arg1, "#args"-1\n"\ 121 | "ldw r1, sp[" "__"#f"_handler_arg1" "]\n" \ 122 | ".linkset __"#f"_handler_arg2, "#args"-0\n"\ 123 | "ldw r2, sp[" "__"#f"_handler_arg2" "]\n" \ 124 | ".linkset __"#f"_handler_arg3, "#args"+1\n"\ 125 | "ldw r3, sp[" "__"#f"_handler_arg3" "]\n" 126 | 127 | #define load_args4(f) load_argsn(f,4) 128 | #define load_args5(f) load_argsn(f,5) 129 | #define load_args6(f) load_argsn(f,6) 130 | #define load_args7(f) load_argsn(f,7) 131 | #define load_args8(f) load_argsn(f,8) 132 | 133 | #define save_state(f,args) \ 134 | ".linkset __"#f"_handler_r0_save, "#args"+12\n" \ 135 | "stw r0, sp[" "__"#f"_handler_r0_save" "]\n" \ 136 | ".linkset __"#f"_handler_r1_save, "#args"+13\n" \ 137 | "stw r1, sp[" "__"#f"_handler_r1_save" "]\n" \ 138 | ".linkset __"#f"_handler_r2_save, "#args"+2\n" \ 139 | "stw r2, sp[" "__"#f"_handler_r2_save" "]\n" \ 140 | ".linkset __"#f"_handler_r3_save, "#args"+3\n" \ 141 | "stw r3, sp[" "__"#f"_handler_r3_save" "]\n" \ 142 | ".linkset __"#f"_handler_r4_save, "#args"+4\n" \ 143 | "stw r4, sp[" "__"#f"_handler_r4_save" "]\n" \ 144 | ".linkset __"#f"_handler_r5_save, "#args"+5\n" \ 145 | "stw r5, sp[" "__"#f"_handler_r5_save" "]\n" \ 146 | ".linkset __"#f"_handler_r6_save, "#args"+6\n" \ 147 | "stw r6, sp[" "__"#f"_handler_r6_save" "]\n" \ 148 | ".linkset __"#f"_handler_r7_save, "#args"+7\n" \ 149 | "stw r7, sp[" "__"#f"_handler_r7_save" "]\n" \ 150 | ".linkset __"#f"_handler_r8_save, "#args"+8\n" \ 151 | "stw r8, sp[" "__"#f"_handler_r8_save" "]\n" \ 152 | ".linkset __"#f"_handler_r9_save, "#args"+9\n" \ 153 | "stw r9, sp[" "__"#f"_handler_r9_save" "]\n" \ 154 | ".linkset __"#f"_handler_r10_save, "#args"+10\n" \ 155 | "stw r10, sp[" "__"#f"_handler_r10_save" "]\n" \ 156 | ".linkset __"#f"_handler_r11_save, "#args"+11\n" \ 157 | "stw r11, sp[" "__"#f"_handler_r11_save" "]\n" \ 158 | ".linkset __"#f"_handler_lr_save, "#args"+14\n" \ 159 | "stw lr, sp[" "__"#f"_handler_lr_save" "]\n" 160 | 161 | #define restore_state(f,args) \ 162 | "ldw r0, sp[" "__"#f"_handler_r0_save" "]\n" \ 163 | "ldw r1, sp[" "__"#f"_handler_r1_save" "]\n" \ 164 | "ldw r2, sp[" "__"#f"_handler_r2_save" "]\n" \ 165 | "ldw r3, sp[" "__"#f"_handler_r3_save" "]\n" \ 166 | "ldw r4, sp[" "__"#f"_handler_r4_save" "]\n" \ 167 | "ldw r5, sp[" "__"#f"_handler_r5_save" "]\n" \ 168 | "ldw r6, sp[" "__"#f"_handler_r6_save" "]\n" \ 169 | "ldw r7, sp[" "__"#f"_handler_r7_save" "]\n" \ 170 | "ldw r8, sp[" "__"#f"_handler_r8_save" "]\n" \ 171 | "ldw r9, sp[" "__"#f"_handler_r9_save" "]\n" \ 172 | "ldw r10, sp[" "__"#f"_handler_r10_save" "]\n" \ 173 | "ldw r11, sp[" "__"#f"_handler_r11_save" "]\n" \ 174 | "ldw lr, sp[" "__"#f"_handler_lr_save" "]\n" 175 | 176 | 177 | #define STRINGIFY0(x) #x 178 | #define STRINGIFY(x) STRINGIFY0(x) 179 | 180 | #define ENABLE_INTERRUPTS() asm("setsr " STRINGIFY(XS1_SR_IEBLE_SET(0, 1))) 181 | 182 | #define DISABLE_INTERRUPTS() asm("clrsr " STRINGIFY(XS1_SR_IEBLE_SET(0, 1))) 183 | 184 | //int ksp_enter, ksp_exit, r11_store; 185 | 186 | #define do_interrupt_handler(f,args) \ 187 | asm("bu .L__" #f "_handler_skip;\n" \ 188 | "__" #f "_handler:\n" \ 189 | "kentsp " #args " + 19\n" \ 190 | "__kent:" \ 191 | save_state(f,args) \ 192 | load_args ## args (f) \ 193 | "bl " #f "\n" \ 194 | restore_state(f,args) \ 195 | "krestsp " #args " + 19 \n" \ 196 | "__kret:\n" \ 197 | "kret\n" \ 198 | ".L__" #f "_handler_skip:\n"); 199 | 200 | #define set_interrupt_handler(f, nstackwords, args, c, ...) \ 201 | asm (" .section .dp.data, \"adw\", @progbits\n" \ 202 | " .align 4\n" \ 203 | "__" #f "_kernel_stack:\n" \ 204 | " .space " #nstackwords ", 0\n" \ 205 | " .text\n"); \ 206 | asm("mov r10, %0; ldaw r11, dp[__" #f "_kernel_stack];add r11, r11, r10;ldaw r10, sp[0]; "\ 207 | "set sp,r11;stw r10, sp[0]; krestsp 0"::"r"(nstackwords-8):"r10","r11"); \ 208 | store_args ## args(c, __VA_ARGS__) \ 209 | do_interrupt_handler(f, args) \ 210 | asm("ldap r11, __" #f "_handler; setv res[%0],r11"::"r"(c):"r11"); \ 211 | asm("setc res[%0], 0xa; eeu res[%0]"::"r"(c)); \ 212 | asm("setsr (((0) & ~(((1 << 0x1) - 1) << 0x1)) | (((1) << 0x1) & (((1 << 0x1) - 1) << 0x1)))"); 213 | 214 | 215 | 216 | #endif 217 | 218 | -------------------------------------------------------------------------------- /firmware/usbaudio20.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_shared 3 | * Version: 1v15 4 | * Build: 5f54bab9944b48e1ccf265e572562e2be9746401 5 | * File: usbaudio20.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** 21 | * @file usbaudio20.h 22 | * @brief Defines from the USB Audio 2.0 Specifications 23 | * @author Ross Owen, XMOS Limited 24 | * @version 0.9 25 | */ 26 | 27 | #include "usb.h" 28 | 29 | /***********************************************************************/ 30 | /* USB Audio 2.0 Class Specification */ 31 | 32 | /* A.1 Audio Function Class Code */ 33 | #define AUDIO_FUNCTION AUDIO 34 | 35 | /* A.2 Audio Function Subclass Codes */ 36 | #define FUNCTION_SUBCLASS_UNDEFINED 0x00 37 | 38 | /* A.3 Audio Function Protocol Codes */ 39 | #define FUNCTION_PROTOCOL_UNDEFINED 0x00 40 | #define AF_VERSION_02_00 IP_VERSION_02_00 41 | 42 | /* A.4 Audio Interface Class Code */ 43 | #define AUDIO 0x01 44 | 45 | /* A.5 Audio Interface Subclass Codes */ 46 | #define AUDIOCONTROL 0x01 47 | #define AUDIOSTREAMING 0x02 48 | #define MIDISTREAMING 0x03 49 | 50 | /* A.6 Audo Interface Protocol Codes */ 51 | #define IP_VERSION_02_00 0x20 52 | 53 | /* A.7 Audio Function Category Codes */ 54 | #define FUNCTION_SUBCLASS_UNDEFINED 0x00 55 | #define DESKTOP_SPEAKER 0x01 56 | #define HOME_THEATER 0x02 57 | #define MICROPHONE 0x03 58 | #define HEADSET 0x04 59 | #define TELEPHONE 0x05 60 | #define CONVERTER 0x06 61 | #define VOICE_SOUND_RECORDER 0x07 62 | #define IO_BOX 0x08 63 | #define MUSICAL_INTRUMENT 0x09 64 | #define PRO_AUDIO 0x0A 65 | #define AUDIO_VIDEO 0x0B 66 | #define CONTROL_PANEL 0x0C 67 | #define OTHER 0xFF 68 | 69 | /* A.8 Audio Class-Specific Descriptor Types */ 70 | #define CS_UNDEFINED 0x20 71 | #define CS_DEVICE 0x21 72 | #define CS_CONFIGURATION 0x22 73 | #define CS_STRING 0x23 74 | #define CS_INTERFACE 0x24 75 | #define CS_ENDPOINT 0x25 76 | 77 | /* A.9 Audio Class-Specific AC Interface Descriptor Subtypes */ 78 | #define AC_DESCRIPTOR_UNDEFINED 0x00 79 | #define HEADER 0x01 80 | #define INPUT_TERMINAL 0x02 81 | #define OUTPUT_TERMINAL 0x03 82 | #define MIXER_UNIT 0x04 83 | #define SELECTOR_UNIT 0x05 84 | #define FEATURE_UNIT 0x06 85 | #define EFFECT_UNIT 0x07 86 | #define PROCESSING_UNIT 0x08 87 | #define EXTENSION_UNIT 0x09 88 | #define CLOCK_SOURCE 0x0A 89 | #define CLOCK_SELECTOR 0x0B 90 | #define CLOCK_MULTIPLIER 0x0C 91 | #define SAMPLE_RATE_CONVERTER 0x0D 92 | 93 | /* A.10 Audio Class Specific AS Interface Descriptor Subtypes */ 94 | #define AS_DESCRIPTOR_UNDEFINED 0x00 95 | #define AS_GENERAL 0x01 96 | #define FORMAT_TYPE 0x02 97 | #define ENCODER 0x03 98 | #define DECODER 0x04 99 | 100 | /* A.11 Effect Unit Effect Types */ 101 | #define EFFECT_UNDEFINED 0x00 102 | #define PARAM_EQ_SECTION_EFFECT 0x01 103 | #define REVERBERATION_EFFECT 0x02 104 | #define MOD_DELAY_EFFECT 0x03 105 | #define DYN_RANGE_COMP_EFFECT 0x04 106 | 107 | /* A.12 Processing Unit Process Types */ 108 | #define PROCESS_UNDEFINED 0x00 109 | #define UP_DOWNMIX_PROCESS 0x01 110 | #define DOLBY_PROLOGIC_PROCESS 0x02 111 | #define STEREO_EXTENDER_PROCESS 0x03 112 | 113 | /* A.13 Audio Class-Specific Endpoint Descriptor Subtypes */ 114 | #define DESCRIPTOR_UNDEFINED 0x00 115 | #define EP_GENERAL 0x01 116 | 117 | /* A.14 Audio Class-Specific Request Codes */ 118 | #define REQUEST_CODE_UNDEFINED 0x00 119 | #define CUR 0x01 120 | #define RANGE 0x02 121 | #define MEM 0x03 122 | 123 | /* A.15 Encoder Type Codes */ 124 | #define ENCODER_UNDEFINED 0x00 125 | #define OTHER_ENCODER 0x01 126 | #define MPEG_ENCODER 0x02 127 | #define AC_3_ENCODER 0x03 128 | #define WMA_ENCODER 0x04 129 | #define DTS_ENCODER 0x05 130 | 131 | /* A.17 Control Selector Codes */ 132 | /* A.17.1 Clock Source Control Selectors */ 133 | #define CS_CONTROL_UNDEFINED 0x00 134 | #define CS_SAM_FREQ_CONTROL 0x01 135 | #define CS_CLOCK_VALID_CONTROL 0x02 136 | 137 | /* A.17.2 Clock Selector Control Selectors */ 138 | #define CX_CONTROL_UNDEFINED 0x00 139 | #define CX_CLOCK_SELECTOR_CONTROL 0x01 140 | 141 | /* A.17.7 Feature Unit Control Selectors */ 142 | #define FU_CONTROL_UNDEFINED 0x00 143 | #define FU_MUTE_CONTROL 0x01 144 | #define FU_VOLUME_CONTROL 0x02 145 | 146 | /* A.17.6 Feature Unit Control Selectors */ 147 | #define SU_CONTROL_UNDEFINED 0x00 148 | #define SU_SELECTOR_CONTROL 0x01 149 | 150 | /* Audio Class-Specific Descriptor Types */ 151 | #define CS_INTERFACE 0x24 152 | #define CS_ENDPOINT 0x25 153 | 154 | 155 | /* Audio Class-Specific AS Interface Descriptor Subtypes */ 156 | #define FORMAT_TYPE 0x02 157 | 158 | 159 | /***********************************************************************/ 160 | /* Universal Serial Bus Device Class Definition for Audio Data Formats */ 161 | 162 | /* A.1 Format Type Codes */ 163 | #define FORMAT_TYPE_UNDEFINED 0x00 164 | #define FORMAT_TYPE_I 0x01 165 | #define FORMAT_TYPE_II 0x02 166 | #define FORMAT_TYPE_III 0x03 167 | #define FORMAT_TYPE_IV 0x04 168 | #define EXT_FORMAT_TYPE_I 0x81 169 | #define EXT_FORMAT_TYPE_II 0x82 170 | #define EXT_FORMAT_TYPE_III 0x83 171 | 172 | /* A.3 Side Band Protocol Codes */ 173 | #define PROTOCOL_UNDEFINED 0x00 174 | #define PRESS_TIMESTAMP_PROTOCOL 0x01 175 | 176 | 177 | /***********************************************************************/ 178 | /* Univeral Serial Bus Device Class Definition for Terminal Types */ 179 | 180 | /* 2.1 USB Terminal Types */ 181 | /* Terminal Types that describe Terminals that handle signals carried over USB */ 182 | #define USB_UNDEFINED 0x0100 183 | #define USB_STREAMING 0x0101 184 | #define USB_VENDOR_SPECIFIC 0x01FF 185 | 186 | /* 2.2 Input Terminal Types */ 187 | /* Terminal Types that describe Terminals that are designed to record sounds */ 188 | #define INPUT_UDEFINED 0x0200 189 | #define MICROPHONE_ 0x0201 190 | #define DESKTOP_MICROPHONE 0x0202 191 | #define PERSONAL_MICROPHONE 0x0203 192 | #define OMNIDIRECTIONAL_MICROPHONE 0x0204 193 | #define MICROPHONE_ARRAY 0x0205 194 | #define PROCESSING_MICROPHONE_ARRAY 0x0206 195 | 196 | /* 2.3 Output Terminal Types */ 197 | /* These Terminal Types describe Terminals that produce audible signals that are intended to 198 | * be heard by the user of the audio function */ 199 | #define SPEAKER 0x0301 200 | #define HEADPHONES 0x0302 201 | #define HEAD_MOUNTED_DISPLAY 0x0303 202 | #define DESKTOPSPEAKER 0x0304 203 | #define ROOM_SPEAKER 0x0305 204 | #define COMMUNICATION_SPEAKER 0x0306 205 | #define LOW_FREQ_EFFECTS_SPEAKER 0x0307 206 | 207 | 208 | #define FORMAT_TYPE_I 0x01 209 | 210 | /* A.2 AudioData Format Bit Allocation in the bmFormats field */ 211 | /* A.2.1 Audio Data Format Type I Bit Allocations */ 212 | #define PCM 0x01 213 | #define PCM8 0x02 214 | #define IEEE_FLOAT 0x04 215 | -------------------------------------------------------------------------------- /firmware/DescriptorRequests.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_shared 3 | * Version: 1v2 4 | * Build: bb814601fea4422bae7e88cb0fd65289443c217c 5 | * File: DescriptorRequests.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** 21 | * @file DescriptorRequests.xc 22 | * @brief DescriptorRequests implementation 23 | * @author Ross Owen, XMOS Limited 24 | * @version 1.0 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "xud.h" /* XUD Functions and defines */ 32 | #include "usb.h" /* Defines related to the USB 2.0 Spec */ 33 | 34 | #if 0 35 | /** @brief Returns min of two values 36 | * @param a int 37 | * @param b int 38 | * @return min of the two passed int values 39 | */ 40 | int min(int a, int b) 41 | { 42 | if (a > b) 43 | return b; 44 | else 45 | return a; 46 | } 47 | #endif 48 | 49 | extern int min(int a, int b); 50 | 51 | 52 | /* See DescriptorRequests.h for documentation */ 53 | #pragma unsafe arrays 54 | int DescriptorRequests(XUD_ep c, XUD_ep c_in, uint8 devDesc[], int devDescLength, uint8 cfgDesc[], int cfgDescLength, 55 | uint8 devQualDesc[], int devQualDescLength, uint8 oSpeedCfgDesc[], int oSpeedCfgDescLength, uint8 strDescs[][40], SetupPacket &sp) 56 | { 57 | /* Return value */ 58 | int datalength; 59 | int stringID = 0; 60 | 61 | /* Buffer for Setup data */ 62 | uint8 buffer[120]; 63 | 64 | /* Wait for Setup data */ 65 | if (XUD_GetSetupBuffer(c, buffer) < 0) 66 | { 67 | return -1; 68 | } else { 69 | 70 | /* Parse data buffer end populate SetupPacket struct */ 71 | XUD_ParseSetupPacket(buffer, sp); 72 | 73 | /* Inspect for recipent */ 74 | switch(sp.bmRequestType.Recipient) 75 | { 76 | /* Recipient: Device */ 77 | case BM_REQTYPE_RECIP_DEV: 78 | 79 | /* Inspect for request type */ 80 | switch(sp.bmRequestType.Type) 81 | { 82 | /* Request Type: Standard Request */ 83 | case BM_REQTYPE_TYPE_STANDARD: 84 | 85 | /* Inspect for actual request */ 86 | switch(sp.bRequest) 87 | { 88 | 89 | /* Request: Get Descriptor */ 90 | case GET_DESCRIPTOR: 91 | 92 | /* Inspect for which descriptor is required (high byte of wValue) */ 93 | switch(sp.wValue & 0xff00) 94 | { 95 | /* Device descriptor */ 96 | case WVALUE_GETDESC_DEV: 97 | 98 | /* Do get request (send descriptor then 0 length status stage) */ 99 | return XUD_DoGetRequest(c, c_in, devDesc, devDescLength, sp.wLength); 100 | break; 101 | 102 | /* Configuration Descriptor */ 103 | case WVALUE_GETDESC_CONFIG: 104 | 105 | /* Do get request (send descriptor then 0 length status stage) */ 106 | return XUD_DoGetRequest(c, c_in, cfgDesc, cfgDescLength, sp.wLength); 107 | break; 108 | 109 | /* Device qualifier descriptor */ 110 | case WVALUE_GETDESC_DEVQUAL: 111 | 112 | /* Do get request (send descriptor then 0 length status stage) */ 113 | return XUD_DoGetRequest(c, c_in, devQualDesc, devQualDescLength, sp.wLength); 114 | break; 115 | 116 | /* Other Speed Configiration Descriptor */ 117 | case WVALUE_GETDESC_OSPEED_CFG: 118 | return XUD_DoGetRequest(c, c_in, oSpeedCfgDesc, oSpeedCfgDescLength, sp.wLength); 119 | break; 120 | 121 | 122 | /* String Descriptor */ 123 | case WVALUE_GETDESC_STRING: 124 | 125 | /* Set descriptor type */ 126 | buffer[1] = STRING; 127 | 128 | /* Send the string that was requested (low byte of wValue) */ 129 | /* First, generate valid descriptor from string */ 130 | /* TODO Bounds check */ 131 | stringID = sp.wValue & 0xff; 132 | 133 | /* Microsoft OS String special case, send product ID string */ 134 | if ( sp.wValue == 0x03ee) 135 | { 136 | stringID = 2; 137 | } 138 | 139 | datalength = safestrlen(strDescs[ stringID ] ); 140 | 141 | /* String 0 (LangIDs) is a special case*/ 142 | if( stringID == 0 ) 143 | { 144 | buffer[0] = datalength + 2; 145 | if( sp.wLength < datalength + 2 ) 146 | datalength = sp.wLength - 2; 147 | 148 | for(int i = 0; i < datalength; i += 1 ) 149 | { 150 | buffer[i+2] = strDescs[stringID][i]; 151 | } 152 | } 153 | else 154 | { 155 | /* Datalength *= 2 due to unicode */ 156 | datalength <<= 1; 157 | 158 | /* Set data length in descriptor (+2 due to 2 byte datalength)*/ 159 | buffer[0] = datalength + 2; 160 | 161 | if(sp.wLength < datalength + 2) 162 | datalength = sp.wLength - 2; 163 | 164 | /* Add zero bytes for unicode.. */ 165 | for(int i = 0; i < datalength; i+=2) 166 | { 167 | buffer[i+2] = strDescs[ stringID ][i>>1]; 168 | buffer[i+3] = 0; 169 | } 170 | 171 | } 172 | 173 | /* Send back string */ 174 | 175 | return XUD_DoGetRequest(c, c_in, buffer, datalength + 2, sp.wLength); 176 | break; 177 | default: 178 | break; 179 | 180 | } 181 | break; 182 | 183 | default: 184 | break; 185 | 186 | } 187 | break; 188 | 189 | default: 190 | break; 191 | } 192 | break; 193 | 194 | default: 195 | break; 196 | } 197 | } 198 | return 1; 199 | } 200 | -------------------------------------------------------------------------------- /firmware/devicedefines.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v4 4 | * Build: 0d7477798fc2c4749eec66c9d1555b9dd2c3fe8a 5 | * File: devicedefines.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** 21 | * @file internaldefines.h 22 | * @brief Defines relating to device configuration and customisation. 23 | * @author Ross Owen, XMOS Limited 24 | */ 25 | 26 | #ifndef _DEVICEDEFINES_H_ 27 | #define _DEVICEDEFINES_H_ 28 | 29 | #include "customdefines.h" 30 | 31 | /* Tidy up historical INPUT/OUTPUT defines. INPUT/OUTPUT now enabled based on channel count defines */ 32 | #if !defined(NUM_USB_CHAN_IN) 33 | #error NUM_USB_CHAN_IN must be defined! 34 | #else 35 | #if (NUM_USB_CHAN_IN == 0) 36 | #undef INPUT 37 | #else 38 | #define INPUT 1 39 | #endif 40 | #endif 41 | 42 | #if !defined(NUM_USB_CHAN_OUT) 43 | #error NUM_USB_CHAN_OUT must be defined! 44 | #else 45 | #if (NUM_USB_CHAN_OUT == 0) 46 | #undef OUTPUT 47 | #else 48 | #define OUTPUT 1 49 | #endif 50 | #endif 51 | 52 | #if defined(INPUT) && (INPUT == 0) 53 | #undef INPUT 54 | #endif 55 | 56 | #if defined(OUTPUT) && (OUTPUT == 0) 57 | #undef OUTPUT 58 | #endif 59 | 60 | #if defined(CODEC_SLAVE) && (CODEC_SLAVE == 0) 61 | #undef CODEC_SLAVE 62 | #endif 63 | 64 | #if defined(LEVEL_METER_LEDS) && !defined(LEVEL_UPDATE_RATE) 65 | #define LEVEL_UPDATE_RATE 400000 66 | #endif 67 | 68 | #define AUDIO_CLASS 2 69 | 70 | /* Number of IS2 chans to DAC */ 71 | #ifndef I2S_CHANS_DAC 72 | #error I2S_CHANS_DAC not defined 73 | #else 74 | #define I2S_WIRES_DAC (I2S_CHANS_DAC >> 1) 75 | #endif 76 | 77 | /* Number of I2S chans from ADC */ 78 | #ifndef I2S_CHANS_ADC 79 | #error I2S_CHANS_ADC not defined 80 | #else 81 | #define I2S_WIRES_ADC (I2S_CHANS_ADC >> 1) 82 | #endif 83 | 84 | /* Max supported freq for device */ 85 | #ifndef MAX_FREQ 86 | #warning MAX_FREQ not defined! Using 48000 87 | #define MAX_FREQ (48000) 88 | #endif 89 | 90 | /* Default device freq */ 91 | #ifndef DEFAULT_FREQ 92 | #warning DEFAULT not defined! Using MAX_FREQ 93 | #define DEFAULT_FREQ (MAX_FREQ) 94 | #endif 95 | 96 | /* Master clock defines (in Hz) */ 97 | #ifndef MCLK_441 98 | #error MCLK_441 not defined 99 | #endif 100 | 101 | #ifndef MCLK_48 102 | #error MCLK_441 not defined 103 | #endif 104 | 105 | /* The number of clock ticks to wait for the audio PLL to lock */ 106 | #define AUDIO_PLL_LOCK_DELAY (40000000) 107 | 108 | /* Vendor/Product strings */ 109 | #ifndef VENDOR_STR 110 | #define VENDOR_STR "XMOS " 111 | //#warning VENDOR_STR not defined. Using XMOS 112 | #endif 113 | 114 | #ifndef VENDOR_ID 115 | #warning VENDOR_ID not defined. Using XMOS vendor ID 116 | #define VENDOR_ID (0x20B1) /* XMOS VID */ 117 | #endif 118 | 119 | #ifndef PID_AUDIO_1 120 | #define PID_AUDIO_1 (0x0001) 121 | #warning PRODUCT_ID not defined. Using 0x0001 122 | #endif 123 | 124 | #ifndef PID_AUDIO_2 125 | #define PID_AUDIO_2 (0x0001) 126 | #warning PRODUCT_ID not defined. Using 0x0001 127 | #endif 128 | 129 | /* Device release number in BCD: 0xJJMNi */ 130 | #ifndef BCD_DEVICE 131 | #define BCD_DEVICE (0x0000) 132 | #warning BCD_DEVICE not defined. Using 0x0000 133 | #endif 134 | 135 | /* Addition interfaces based on defines */ 136 | #if defined(DFU) && DFU != 0 137 | #define DFU_INTERFACES (1) /* DFU interface count */ 138 | #else 139 | #define DFU_INTERFACES (0) 140 | #endif 141 | 142 | #ifdef INPUT 143 | #define INPUT_INTERFACES (1) 144 | #else 145 | #define INPUT_INTERFACES (0) 146 | #endif 147 | 148 | #if defined(OUTPUT) && OUTPUT != 0 149 | #define OUTPUT_INTERFACES (1) 150 | #else 151 | #define OUTPUT_INTERFACES (0) 152 | #endif 153 | 154 | 155 | #if defined(MIDI) 156 | #define MIDI_INTERFACES (2) 157 | #else 158 | #define MIDI_INTERFACES (0) 159 | #endif 160 | 161 | #define AUDIO_STOP_FOR_DFU (0x12345678) 162 | #define AUDIO_START_FROM_DFU (0x87654321) 163 | #define AUDIO_REBOOT_FROM_DFU (0xa5a5a5a5) 164 | 165 | 166 | #define MAX_VOL (0x20000000) 167 | 168 | #define NUM_EP_OUT 2 /* Max number of device endpoints used */ 169 | #define NUM_EP_IN 4 170 | /* Length of clock unit/clock-selector units */ 171 | 172 | 173 | /* Total number of USB interfaces this device implements (+1 for required control interface) */ 174 | #define NUM_INTERFACES INPUT_INTERFACES + OUTPUT_INTERFACES + DFU_INTERFACES + MIDI_INTERFACES + 1 175 | 176 | #ifndef SERIAL_STR 177 | #define SERIAL_STR "0000" /* Serial number string */ 178 | #endif 179 | 180 | #define SERIAL_STR_INDEX 0x03 181 | #define MANUFACTURER_STR_INDEX 0x01 182 | #define PRODUCT_STR_INDEX 0x02 183 | 184 | /* Mixer defines */ 185 | #ifndef MIX_INPUTS 186 | #define MIX_INPUTS 18 187 | #endif 188 | 189 | #ifndef MAX_MIX_COUNT 190 | #define MAX_MIX_COUNT 8 191 | #endif 192 | 193 | 194 | /* Volume defines */ 195 | 196 | #ifndef MIN_VOLUME 197 | /* The minimum volume setting above -inf. This is a signed 8.8 fixed point 198 | number that must be strictly greater than -128 (0x8000) */ 199 | /* Default min volume is -127db */ 200 | #define MIN_VOLUME (0x8100) 201 | #endif 202 | 203 | #ifndef MAX_VOLUME 204 | /* The maximum volume setting. This is a signed 8.8 fixed point number. */ 205 | /* Default max volume is 0db */ 206 | #define MAX_VOLUME (0x0000) 207 | #endif 208 | 209 | #ifndef VOLUME_RES 210 | /* The resolution of the volume control in db as a 8.8 fixed point number */ 211 | /* Default volume resolution 1db */ 212 | #define VOLUME_RES (0x100) 213 | #endif 214 | 215 | 216 | #ifndef MIN_MIXER_VOLUME 217 | /* The minimum volume setting for the mixer unit above -inf. 218 | This is a signed 8.8 fixed point 219 | number that must be strictly greater than -128 (0x8000) */ 220 | /* Default min volume is -127db */ 221 | #define MIN_MIXER_VOLUME (0x8100) 222 | #endif 223 | 224 | #ifndef MAX_MIXER_VOLUME 225 | /* The maximum volume setting for the mixer. 226 | This is a signed 8.8 fixed point number. */ 227 | /* Default max volume is 0db */ 228 | #define MAX_MIXER_VOLUME (0x0000) 229 | #endif 230 | 231 | #ifndef VOLUME_RES_MIXER 232 | /* The resolution of the volume control in db as a 8.8 fixed point number */ 233 | /* Default volume resolution 1db */ 234 | #define VOLUME_RES_MIXER (0x100) 235 | #endif 236 | 237 | /* Handle out volume control in the mixer */ 238 | #if defined(OUT_VOLUME_IN_MIXER) && (OUT_VOLUME_IN_MIXER==0) 239 | #undef OUT_VOLUME_IN_MIXER 240 | #else 241 | #if defined(MIXER) 242 | // Enabled by default 243 | #define OUT_VOLUME_IN_MIXER 244 | #endif 245 | #endif 246 | 247 | /* Apply out volume controls after the mix */ 248 | #if defined(OUT_VOLUME_AFTER_MIX) && (OUT_VOLUME_AFTER_MIX==0) 249 | #undef OUT_VOLUME_AFTER_MIX 250 | #else 251 | #if defined(MIXER) && defined(OUT_VOLUME_IN_MIXER) 252 | // Enabled by default 253 | #define OUT_VOLUME_AFTER_MIX 254 | #endif 255 | #endif 256 | 257 | /* Define for reporting as self or bus-powered to the host */ 258 | #if defined(SELF_POWERED) && (SELF_POWERED==0) 259 | #undef SELF_POWERED 260 | #endif 261 | 262 | /* Handle in volume control in the mixer */ 263 | #if defined(IN_VOLUME_IN_MIXER) && (IN_VOLUME_IN_MIXER==0) 264 | #undef IN_VOLUME_IN_MIXER 265 | #else 266 | #if defined(MIXER) 267 | /* Enabled by default */ 268 | #define IN_VOLUME_IN_MIXER 269 | #endif 270 | #endif 271 | 272 | /* Apply in volume controls after the mix */ 273 | #if defined(IN_VOLUME_AFTER_MIX) && (IN_VOLUME_AFTER_MIX==0) 274 | #undef IN_VOLUME_AFTER_MIX 275 | #else 276 | #if defined(MIXER) && defined(IN_VOLUME_IN_MIXER) 277 | // Enabled by default 278 | #define IN_VOLUME_AFTER_MIX 279 | #endif 280 | #endif 281 | 282 | #if defined(AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS_FALLBACK==0) 283 | #undef AUDIO_CLASS_FALLBACK 284 | #endif 285 | 286 | /* Defines for DFU */ 287 | #ifndef PID_DFU 288 | #define PID_DFU PID_AUDIO_2 289 | #endif 290 | 291 | #define DFU_VENDOR_ID VENDOR_ID 292 | #define DFU_BCD_DEVICE BCD_DEVICE 293 | #define DFU_SERIAL_STR_INDEX SERIAL_STR_INDEX 294 | #define DFU_MANUFACTURER_INDEX MANUFACTURER_STR_INDEX 295 | #define DFU_PRODUCT_INDEX PRODUCT_STR_INDEX 296 | #endif 297 | -------------------------------------------------------------------------------- /firmware/i2c.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v0 4 | * Build: 334eaf5834c010b803eaca46139f6c8c8412879c 5 | * File: i2c.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #include 21 | #include 22 | 23 | int I2cRegRead(int device, int addr, port scl, port sda) 24 | { 25 | //int Result; 26 | timer gt; 27 | unsigned time; 28 | int Temp, CtlAdrsData, i; 29 | // three device ACK 30 | int ack[3]; 31 | int rdData; 32 | 33 | // initial values. 34 | scl <: 1; 35 | sda <: 1; 36 | sync(sda); 37 | gt :> time; 38 | time += 1000 + 1000; 39 | gt when timerafter(time) :> int _; 40 | // start bit on SDI 41 | scl <: 1; 42 | sda <: 0; 43 | gt :> time; 44 | time += 1000; 45 | gt when timerafter(time) :> int _; 46 | scl <: 0; 47 | // shift 7bits of address and 1bit R/W (fixed to write). 48 | // WARNING: Assume MSB first. 49 | for (i = 0; i < 8; i += 1) 50 | { 51 | Temp = (device >> (7 - i)) & 0x1; 52 | sda <: Temp; 53 | gt :> time; 54 | time += 1000; 55 | gt when timerafter(time) :> int _; 56 | scl <: 1; 57 | gt :> time; 58 | time += 1000; 59 | gt when timerafter(time) :> int _; 60 | scl <: 0; 61 | } 62 | // turn the data to input 63 | sda :> Temp; 64 | gt :> time; 65 | time += 1000; 66 | gt when timerafter(time) :> int _; 67 | scl <: 1; 68 | // sample first ACK. 69 | sda :> ack[0]; 70 | gt :> time; 71 | time += 1000; 72 | gt when timerafter(time) :> int _; 73 | scl <: 0; 74 | 75 | CtlAdrsData = (addr & 0xFF); 76 | // shift first 8 bits. 77 | for (i = 0; i < 8; i += 1) 78 | { 79 | Temp = (CtlAdrsData >> (7 - i)) & 0x1; 80 | sda <: Temp; 81 | gt :> time; 82 | time += 1000; 83 | gt when timerafter(time) :> int _; 84 | scl <: 1; 85 | gt :> time; 86 | time += 1000; 87 | gt when timerafter(time) :> int _; 88 | scl <: 0; 89 | } 90 | // turn the data to input 91 | sda :> Temp; 92 | gt :> time; 93 | time += 1000; 94 | gt when timerafter(time) :> int _; 95 | scl <: 1; 96 | // sample second ACK. 97 | sda :> ack[1]; 98 | gt :> time; 99 | time += 1000; 100 | gt when timerafter(time) :> int _; 101 | scl <: 0; 102 | 103 | 104 | // stop bit 105 | gt :> time; 106 | time += 1000 + 1000; 107 | gt when timerafter(time) :> int _; 108 | // start bit on SDI 109 | scl <: 1; 110 | sda <: 1; 111 | time += 1000 + 1000; 112 | gt when timerafter(time) :> int _; 113 | scl <: 0; 114 | time += 1000 + 1000; 115 | gt when timerafter(time) :> int _; 116 | 117 | 118 | // send address and read 119 | scl <: 1; 120 | sda <: 1; 121 | sync(sda); 122 | gt :> time; 123 | time += 1000 + 1000; 124 | gt when timerafter(time) :> int _; 125 | // start bit on SDI 126 | scl <: 1; 127 | sda <: 0; 128 | gt :> time; 129 | time += 1000; 130 | gt when timerafter(time) :> int _; 131 | scl <: 0; 132 | // shift 7bits of address and 1bit R/W (fixed to write). 133 | // WARNING: Assume MSB first. 134 | for (i = 0; i < 8; i += 1) 135 | { 136 | int deviceAddr = device | 1; 137 | Temp = (deviceAddr >> (7 - i)) & 0x1; 138 | sda <: Temp; 139 | gt :> time; 140 | time += 1000; 141 | gt when timerafter(time) :> int _; 142 | scl <: 1; 143 | gt :> time; 144 | time += 1000; 145 | gt when timerafter(time) :> int _; 146 | scl <: 0; 147 | } 148 | // turn the data to input 149 | sda :> Temp; 150 | gt :> time; 151 | time += 1000; 152 | gt when timerafter(time) :> int _; 153 | scl <: 1; 154 | // sample first ACK. 155 | sda :> ack[0]; 156 | gt :> time; 157 | time += 1000; 158 | gt when timerafter(time) :> int _; 159 | scl <: 0; 160 | 161 | 162 | rdData = 0; 163 | // shift second 8 bits. 164 | for (i = 0; i < 8; i += 1) 165 | { 166 | 167 | gt :> time; 168 | time += 1000; 169 | gt when timerafter(time) :> int _; 170 | scl <: 1; 171 | 172 | sda :> Temp; 173 | rdData = (rdData << 1) | (Temp & 1); 174 | 175 | gt :> time; 176 | time += 1000; 177 | gt when timerafter(time) :> int _; 178 | scl <: 0; 179 | } 180 | 181 | // turn the data to input 182 | sda :> Temp; 183 | gt :> time; 184 | time += 1000; 185 | gt when timerafter(time) :> int _; 186 | scl <: 1; 187 | // sample second ACK. 188 | sda :> ack[2]; 189 | gt :> time; 190 | time += 1000; 191 | gt when timerafter(time) :> int _; 192 | scl <: 0; 193 | gt :> time; 194 | time += 1000; 195 | gt when timerafter(time) :> int _; 196 | scl <: 1; 197 | // put the data to a good value for next round. 198 | sda <: 1; 199 | // validate all items are ACK properly. 200 | //Result = 0; 201 | //for (i = 0; i < 3; i += 1) 202 | //{ 203 | //if ((ack[i]&1) != 0) 204 | //{ 205 | //Result = Result | (1 << i); 206 | //} 207 | //} 208 | 209 | return rdData; 210 | } 211 | 212 | void I2cRegWrite(int device, int addr, int data, port scl, port sda) 213 | { 214 | //int Result; 215 | timer gt; 216 | unsigned time; 217 | int Temp, CtlAdrsData, i; 218 | // three device ACK 219 | int ack[3]; 220 | 221 | // initial values. 222 | scl <: 1; 223 | sda <: 1; 224 | sync(sda); 225 | 226 | gt :> time; 227 | time += 1000 + 1000; 228 | gt when timerafter(time) :> void; 229 | 230 | // start bit on SDI 231 | scl <: 1; 232 | sda <: 0; 233 | gt :> time; 234 | time += 1000; 235 | gt when timerafter(time) :> void; 236 | scl <: 0; 237 | 238 | // shift 7bits of address and 1bit R/W (fixed to write). 239 | // WARNING: Assume MSB first. 240 | for (i = 0; i < 8; i += 1) 241 | { 242 | Temp = (device >> (7 - i)) & 0x1; 243 | sda <: Temp; 244 | gt :> time; 245 | time += 1000; 246 | gt when timerafter(time) :> void; 247 | scl <: 1; 248 | gt :> time; 249 | time += 1000; 250 | gt when timerafter(time) :> void; 251 | scl <: 0; 252 | } 253 | 254 | // turn the data to input 255 | sda :> Temp; 256 | gt :> time; 257 | time += 1000; 258 | gt when timerafter(time) :> void; 259 | scl <: 1; 260 | 261 | // sample first ACK. 262 | sda :> ack[0]; 263 | gt :> time; 264 | time += 1000; 265 | gt when timerafter(time) :> void; 266 | scl <: 0; 267 | 268 | CtlAdrsData = (addr & 0xFF); 269 | 270 | // shift first 8 bits. 271 | for (i = 0; i < 8; i += 1) 272 | { 273 | Temp = (CtlAdrsData >> (7 - i)) & 0x1; 274 | sda <: Temp; 275 | gt :> time; 276 | time += 1000; 277 | gt when timerafter(time) :> void; 278 | scl <: 1; 279 | gt :> time; 280 | time += 1000; 281 | gt when timerafter(time) :> void; 282 | scl <: 0; 283 | } 284 | // turn the data to input 285 | sda :> Temp; 286 | gt :> time; 287 | time += 1000; 288 | gt when timerafter(time) :> void; 289 | scl <: 1; 290 | // sample second ACK. 291 | sda :> ack[1]; 292 | gt :> time; 293 | time += 1000; 294 | gt when timerafter(time) :> void; 295 | scl <: 0; 296 | 297 | CtlAdrsData = (data & 0xFF); 298 | // shift second 8 bits. 299 | for (i = 0; i < 8; i += 1) 300 | { 301 | Temp = (CtlAdrsData >> (7 - i)) & 0x1; 302 | sda <: Temp; 303 | gt :> time; 304 | time += 1000; 305 | gt when timerafter(time) :> void; 306 | scl <: 1; 307 | gt :> time; 308 | time += 1000; 309 | gt when timerafter(time) :> void; 310 | scl <: 0; 311 | } 312 | // turn the data to input 313 | sda :> Temp; 314 | gt :> time; 315 | time += 1000; 316 | gt when timerafter(time) :> void; 317 | scl <: 1; 318 | // sample second ACK. 319 | sda :> ack[2]; 320 | gt :> time; 321 | time += 1000; 322 | gt when timerafter(time) :> void; 323 | scl <: 0; 324 | gt :> time; 325 | time += 1000; 326 | gt when timerafter(time) :> void; 327 | scl <: 1; 328 | // put the data to a good value for next round. 329 | sda <: 1; 330 | // validate all items are ACK properly. 331 | //Result = 0; 332 | //for (i = 0; i < 3; i += 1) 333 | //{ 334 | //if ((ack[i]&1) != 0) 335 | //{ 336 | //Result = Result | (1 << i); 337 | //} 338 | //} 339 | //return(Result); 340 | } 341 | -------------------------------------------------------------------------------- /firmware/main.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: app_usb_aud_l2 3 | * Version: 5v3rc0 4 | * Build: ac6a4e693026146f3f2e1eb14f33e54ebc385068 5 | * File: main.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** 21 | * @file main.xc 22 | * @brief XMOS L2 USB 2.0 Audio 2.0 Reference Design. Top level. 23 | * @author Ross Owen, XMOS Semiconductor Ltd 24 | * @version 1.4 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "xud.h" /* XMOS USB Device Layer defines and functions */ 36 | #include "usb.h" /* Defines from the USB 2.0 Specification */ 37 | 38 | 39 | #include "customdefines.h" 40 | #include "devicedefines.h" /* Device specific defines */ 41 | #include "endpoint0.h" 42 | #include "usb_buffer.h" 43 | #include "decouple.h" 44 | #include "audio.h" 45 | #ifdef SPDIF_RX 46 | # include "SpdifReceive.h" 47 | #endif 48 | 49 | void clockGen (streaming chanend c_spdif_rx, chanend c_adat_rx, out port p, chanend, chanend, chanend); 50 | void mixer(chanend, chanend, chanend); 51 | void dsp(chanend); 52 | void dsp_router(chanend, chanend, chanend, chanend); 53 | 54 | /* Cores */ 55 | #define CORE_USB 0 56 | #define CORE_AUD 1 57 | #define CORE_DSP 2 58 | 59 | /* Core 0 */ 60 | #define PORT_USB_RST XS1_PORT_1M 61 | #define PORT_PLL_CLK XS1_PORT_4E /* Clk Output to PLL */ 62 | 63 | /* Core 1 */ 64 | #define PORT_COD_CLK_BIT XS1_PORT_1I /* Bit clock */ 65 | #define PORT_COD_CLK_LR XS1_PORT_1E /* LR clock */ 66 | #define PORT_I2C_SCL XS1_PORT_1D 67 | #define PORT_I2C_SDA XS1_PORT_1C 68 | 69 | #define PORT_COD_DAC_0 XS1_PORT_1M 70 | #define PORT_COD_DAC_1 XS1_PORT_1F 71 | #define PORT_COD_DAC_2 XS1_PORT_1H 72 | #define PORT_COD_DAC_3 XS1_PORT_1N 73 | 74 | #define PORT_COD_ADC_0 XS1_PORT_1G 75 | #define PORT_COD_ADC_1 XS1_PORT_1A 76 | #define PORT_COD_ADC_2 XS1_PORT_1B 77 | 78 | #define PORT_COD_CLK_MAS XS1_PORT_1L 79 | 80 | on stdcore[CORE_USB] : buffered in port:4 p_spdif_rx = XS1_PORT_1K; /* K: coax, J: optical */ 81 | on stdcore[CORE_USB] : out port p_usb_rst = PORT_USB_RST; 82 | on stdcore[CORE_USB] : in port p_for_mclk_count = XS1_PORT_32A; 83 | on stdcore[CORE_USB] : in port p_mclk_too = XS1_PORT_1L; 84 | on stdcore[CORE_AUD] : out port p_pll_clk = PORT_PLL_CLK; 85 | #ifdef CODEC_SLAVE 86 | on stdcore[CORE_AUD] : buffered out port:32 p_lrclk = PORT_COD_CLK_LR; 87 | on stdcore[CORE_AUD] : buffered out port:32 p_bclk = PORT_COD_CLK_BIT; 88 | #else 89 | on stdcore[CORE_AUD] : in port p_lrclk = PORT_COD_CLK_LR; 90 | on stdcore[CORE_AUD] : in port p_bclk = PORT_COD_CLK_BIT; 91 | #endif 92 | on stdcore[CORE_AUD] : port p_mclk = PORT_COD_CLK_MAS; 93 | on stdcore[CORE_AUD] : out port p_aud_cfg = XS1_PORT_4A; 94 | on stdcore[CORE_AUD] : port p_i2c_scl = PORT_I2C_SCL; // 2-wire configuration interface. 95 | on stdcore[CORE_AUD] : port p_i2c_sda = PORT_I2C_SDA; 96 | on stdcore[CORE_AUD] : buffered out port:32 p_spdif_tx = XS1_PORT_1J; // K: coax, J: optical 97 | on stdcore[CORE_AUD] : out port p_midi_tx = XS1_PORT_1O; 98 | on stdcore[CORE_AUD] : port p_midi_rx = XS1_PORT_1P; 99 | on stdcore[CORE_AUD] : buffered out port:32 p_i2s_dac[I2S_WIRES_DAC] = {PORT_COD_DAC_0, PORT_COD_DAC_1, PORT_COD_DAC_2, PORT_COD_DAC_3}; 100 | on stdcore[CORE_AUD] : buffered in port:32 p_i2s_adc[I2S_WIRES_ADC] = {PORT_COD_ADC_0, PORT_COD_ADC_1, PORT_COD_ADC_2}; 101 | 102 | /* Clock blocks */ 103 | on stdcore[CORE_USB] : clock clk_adat_rx = XS1_CLKBLK_1; 104 | on stdcore[CORE_USB] : clock clk_spi = XS1_CLKBLK_2; 105 | on stdcore[CORE_USB] : clock clk = XS1_CLKBLK_3; /* USB clock */ 106 | on stdcore[CORE_USB] : clock clk_spd_rx = XS1_CLKBLK_4; 107 | on stdcore[CORE_USB] : clock clk_master_too = XS1_CLKBLK_5; /* Master clock on USB core */ 108 | 109 | on stdcore[CORE_AUD] : clock clk_audio_mclk = XS1_CLKBLK_1; /* Master clock */ 110 | on stdcore[CORE_AUD] : clock clk_audio_bclk = XS1_CLKBLK_2; /* Bit clock */ 111 | on stdcore[CORE_AUD] : clock clk_midi = XS1_CLKBLK_3; 112 | on stdcore[CORE_AUD] : clock clk_mst_spd = XS1_CLKBLK_4; 113 | 114 | on stdcore[CORE_AUD] : out port p_led = XS1_PORT_8B; 115 | on stdcore[CORE_AUD] : out port p_gpio = XS1_PORT_4F; 116 | 117 | /* Endpoint type tables for XUD */ 118 | XUD_EpType epTypeTableOut[NUM_EP_OUT] = { XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, 119 | XUD_EPTYPE_ISO}; 120 | 121 | XUD_EpType epTypeTableIn[NUM_EP_IN] = { XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, 122 | XUD_EPTYPE_ISO, 123 | XUD_EPTYPE_ISO, 124 | XUD_EPTYPE_BUL}; 125 | 126 | void InitMixers(chanend c_mix_ctl); 127 | 128 | int main() 129 | { 130 | chan c_sof; 131 | 132 | chan c_xud_out[NUM_EP_OUT]; /* Endpoint channels for XUD */ 133 | chan c_xud_in[NUM_EP_IN]; 134 | 135 | chan c_aud_ctl; 136 | chan c_mix_ctl; 137 | chan c_clk_ctl; 138 | 139 | #ifdef MIXER 140 | chan c_mix_out; 141 | #endif 142 | 143 | chan c_dig_rx; 144 | chan c_del_out; 145 | chan c_dsp_out; 146 | #ifdef DEBUG_LEDS 147 | chan c_led; 148 | #endif 149 | streaming chan c_spdif_rx; 150 | chan c_adat_rx; // CT_END after each sample 151 | chan c_clk_int; 152 | chan c_dsp; 153 | chan c_dsp_ctl; 154 | chan c_peaks; 155 | 156 | par 157 | { 158 | /* Core 0 */ 159 | /* USB Interface */ 160 | on stdcore[0] : 161 | { 162 | #ifdef DEBUG 163 | xscope_register(0); 164 | xscope_config_io(XSCOPE_IO_BASIC); 165 | #endif 166 | puts("Hello, world from mgr!"); 167 | XUD_Manager(c_xud_out, NUM_EP_OUT, c_xud_in, NUM_EP_IN, 168 | c_sof, epTypeTableOut, epTypeTableIn, p_usb_rst, clk, 1, XUD_SPEED_HS, null); 169 | } 170 | 171 | /* Endpoint 0 */ 172 | on stdcore[0] : 173 | { 174 | puts("Hello, world from ep0!"); 175 | InitMixers(c_mix_ctl); 176 | Endpoint0( c_xud_out[0], c_xud_in[0], c_aud_ctl, c_mix_ctl, c_clk_ctl, c_dsp_ctl); 177 | } 178 | 179 | /* Buffer / EP Man */ 180 | on stdcore[0] : 181 | { 182 | set_thread_fast_mode_on(); 183 | configure_clock_src(clk_master_too, p_mclk_too); 184 | set_port_clock(p_for_mclk_count, clk_master_too); 185 | start_clock(clk_master_too); 186 | 187 | puts("Hello, world from buffer!"); 188 | buffer(c_xud_out[1], c_xud_in[2], c_xud_in[1], 189 | c_xud_in[3], 190 | c_sof, c_aud_ctl, 191 | p_for_mclk_count); 192 | } 193 | 194 | on stdcore[0] : 195 | { 196 | unsigned int i; 197 | puts("Hello, world from decouple!"); 198 | decouple(c_mix_out, c_clk_int, c_led); 199 | } 200 | #ifdef SPDIF_RX 201 | on stdcore[0] : 202 | { 203 | puts("Hello, world from SpdifReceive!"); 204 | set_thread_fast_mode_on(); 205 | SpdifReceive(p_spdif_rx, c_spdif_rx, 2, clk_spd_rx); 206 | } 207 | #endif 208 | 209 | #define FULL 0x40000000 210 | #define HALF 0x16a09e66 211 | 212 | #define IDLE_TIME 30 * 600 213 | 214 | on stdcore[1] : 215 | { 216 | unsigned int i; 217 | int active; 218 | int tmr = IDLE_TIME; 219 | puts("Hello, world from LED!"); 220 | while(1) { 221 | active = 1; 222 | i = inuint(c_peaks); 223 | if (i > (FULL>>0)) { 224 | p_led <: 0xff; 225 | } else if (i > (HALF>>0)) { 226 | p_led <: 0x7f; 227 | } else if (i > (FULL>>3)) { 228 | p_led <: 0x3f; 229 | } else if (i > (HALF>>3)) { 230 | p_led <: 0x1f; 231 | } else if (i > (FULL>>6)) { 232 | p_led <: 0x0f; 233 | } else if (i > (HALF>>6)) { 234 | p_led <: 0x07; 235 | } else if (i > (FULL>>9)) { 236 | p_led <: 0x03; 237 | } else if (i > (HALF>>9)) { 238 | p_led <: 0x01; 239 | } else { 240 | active = 0; 241 | } 242 | if (active) { 243 | tmr = 0; 244 | p_gpio <: 0x03; 245 | } else if (tmr < IDLE_TIME) { 246 | p_led <: 0x00; 247 | p_gpio <: 0x03; 248 | tmr++; 249 | } else { 250 | p_led <: 0x18; 251 | p_gpio <: 0x0c; 252 | } 253 | } 254 | } 255 | 256 | /* Core 1 */ 257 | on stdcore[1] : 258 | { 259 | puts("Hello, world from mixer!"); 260 | mixer(c_mix_out, c_dsp_out, c_mix_ctl); 261 | } 262 | 263 | /* Audio I/O (pars additional S/PDIF TX thread) */ 264 | on stdcore[1] : 265 | { 266 | puts("Hello, world from AudioIO!"); 267 | audio(c_del_out, c_dig_rx, null, c_peaks) ; 268 | } 269 | 270 | on stdcore[1] : 271 | { 272 | puts("Hello, world from clockGen!"); 273 | clockGen(c_spdif_rx, c_adat_rx, p_pll_clk, c_dig_rx, c_clk_ctl, c_clk_int); 274 | } 275 | 276 | on stdcore[1] : 277 | { 278 | puts("Hello, world from DSP Router!"); 279 | dsp_router(c_dsp_out, c_del_out, c_dsp, c_dsp_ctl); 280 | } 281 | on stdcore[2] : 282 | { 283 | puts("Hello, world from DSP!"); 284 | dsp(c_dsp); 285 | } 286 | } 287 | 288 | return 0; 289 | } 290 | 291 | -------------------------------------------------------------------------------- /firmware/repeat.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v2beta14 4 | * Build: 828cd13ccba5efa7d63ff5d0c967357ccd0c8ad4 5 | * File: repeat.h 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | #ifndef N 21 | #error "N must be defined before including repeat.h" 22 | #endif 23 | #if N > 256 24 | #error "N cannot be larger than 256" 25 | #endif 26 | #ifndef BODY 27 | #error "BODY must be defined before including repeat.h" 28 | #endif 29 | #if N > 0 30 | BODY(0) 31 | #endif 32 | #if N > 1 33 | BODY(1) 34 | #endif 35 | #if N > 2 36 | BODY(2) 37 | #endif 38 | #if N > 3 39 | BODY(3) 40 | #endif 41 | #if N > 4 42 | BODY(4) 43 | #endif 44 | #if N > 5 45 | BODY(5) 46 | #endif 47 | #if N > 6 48 | BODY(6) 49 | #endif 50 | #if N > 7 51 | BODY(7) 52 | #endif 53 | #if N > 8 54 | BODY(8) 55 | #endif 56 | #if N > 9 57 | BODY(9) 58 | #endif 59 | #if N > 10 60 | BODY(10) 61 | #endif 62 | #if N > 11 63 | BODY(11) 64 | #endif 65 | #if N > 12 66 | BODY(12) 67 | #endif 68 | #if N > 13 69 | BODY(13) 70 | #endif 71 | #if N > 14 72 | BODY(14) 73 | #endif 74 | #if N > 15 75 | BODY(15) 76 | #endif 77 | #if N > 16 78 | BODY(16) 79 | #endif 80 | #if N > 17 81 | BODY(17) 82 | #endif 83 | #if N > 18 84 | BODY(18) 85 | #endif 86 | #if N > 19 87 | BODY(19) 88 | #endif 89 | #if N > 20 90 | BODY(20) 91 | #endif 92 | #if N > 21 93 | BODY(21) 94 | #endif 95 | #if N > 22 96 | BODY(22) 97 | #endif 98 | #if N > 23 99 | BODY(23) 100 | #endif 101 | #if N > 24 102 | BODY(24) 103 | #endif 104 | #if N > 25 105 | BODY(25) 106 | #endif 107 | #if N > 26 108 | BODY(26) 109 | #endif 110 | #if N > 27 111 | BODY(27) 112 | #endif 113 | #if N > 28 114 | BODY(28) 115 | #endif 116 | #if N > 29 117 | BODY(29) 118 | #endif 119 | #if N > 30 120 | BODY(30) 121 | #endif 122 | #if N > 31 123 | BODY(31) 124 | #endif 125 | #if N > 32 126 | BODY(32) 127 | #endif 128 | #if N > 33 129 | BODY(33) 130 | #endif 131 | #if N > 34 132 | BODY(34) 133 | #endif 134 | #if N > 35 135 | BODY(35) 136 | #endif 137 | #if N > 36 138 | BODY(36) 139 | #endif 140 | #if N > 37 141 | BODY(37) 142 | #endif 143 | #if N > 38 144 | BODY(38) 145 | #endif 146 | #if N > 39 147 | BODY(39) 148 | #endif 149 | #if N > 40 150 | BODY(40) 151 | #endif 152 | #if N > 41 153 | BODY(41) 154 | #endif 155 | #if N > 42 156 | BODY(42) 157 | #endif 158 | #if N > 43 159 | BODY(43) 160 | #endif 161 | #if N > 44 162 | BODY(44) 163 | #endif 164 | #if N > 45 165 | BODY(45) 166 | #endif 167 | #if N > 46 168 | BODY(46) 169 | #endif 170 | #if N > 47 171 | BODY(47) 172 | #endif 173 | #if N > 48 174 | BODY(48) 175 | #endif 176 | #if N > 49 177 | BODY(49) 178 | #endif 179 | #if N > 50 180 | BODY(50) 181 | #endif 182 | #if N > 51 183 | BODY(51) 184 | #endif 185 | #if N > 52 186 | BODY(52) 187 | #endif 188 | #if N > 53 189 | BODY(53) 190 | #endif 191 | #if N > 54 192 | BODY(54) 193 | #endif 194 | #if N > 55 195 | BODY(55) 196 | #endif 197 | #if N > 56 198 | BODY(56) 199 | #endif 200 | #if N > 57 201 | BODY(57) 202 | #endif 203 | #if N > 58 204 | BODY(58) 205 | #endif 206 | #if N > 59 207 | BODY(59) 208 | #endif 209 | #if N > 60 210 | BODY(60) 211 | #endif 212 | #if N > 61 213 | BODY(61) 214 | #endif 215 | #if N > 62 216 | BODY(62) 217 | #endif 218 | #if N > 63 219 | BODY(63) 220 | #endif 221 | #if N > 64 222 | BODY(64) 223 | #endif 224 | #if N > 65 225 | BODY(65) 226 | #endif 227 | #if N > 66 228 | BODY(66) 229 | #endif 230 | #if N > 67 231 | BODY(67) 232 | #endif 233 | #if N > 68 234 | BODY(68) 235 | #endif 236 | #if N > 69 237 | BODY(69) 238 | #endif 239 | #if N > 70 240 | BODY(70) 241 | #endif 242 | #if N > 71 243 | BODY(71) 244 | #endif 245 | #if N > 72 246 | BODY(72) 247 | #endif 248 | #if N > 73 249 | BODY(73) 250 | #endif 251 | #if N > 74 252 | BODY(74) 253 | #endif 254 | #if N > 75 255 | BODY(75) 256 | #endif 257 | #if N > 76 258 | BODY(76) 259 | #endif 260 | #if N > 77 261 | BODY(77) 262 | #endif 263 | #if N > 78 264 | BODY(78) 265 | #endif 266 | #if N > 79 267 | BODY(79) 268 | #endif 269 | #if N > 80 270 | BODY(80) 271 | #endif 272 | #if N > 81 273 | BODY(81) 274 | #endif 275 | #if N > 82 276 | BODY(82) 277 | #endif 278 | #if N > 83 279 | BODY(83) 280 | #endif 281 | #if N > 84 282 | BODY(84) 283 | #endif 284 | #if N > 85 285 | BODY(85) 286 | #endif 287 | #if N > 86 288 | BODY(86) 289 | #endif 290 | #if N > 87 291 | BODY(87) 292 | #endif 293 | #if N > 88 294 | BODY(88) 295 | #endif 296 | #if N > 89 297 | BODY(89) 298 | #endif 299 | #if N > 90 300 | BODY(90) 301 | #endif 302 | #if N > 91 303 | BODY(91) 304 | #endif 305 | #if N > 92 306 | BODY(92) 307 | #endif 308 | #if N > 93 309 | BODY(93) 310 | #endif 311 | #if N > 94 312 | BODY(94) 313 | #endif 314 | #if N > 95 315 | BODY(95) 316 | #endif 317 | #if N > 96 318 | BODY(96) 319 | #endif 320 | #if N > 97 321 | BODY(97) 322 | #endif 323 | #if N > 98 324 | BODY(98) 325 | #endif 326 | #if N > 99 327 | BODY(99) 328 | #endif 329 | #if N > 100 330 | BODY(100) 331 | #endif 332 | #if N > 101 333 | BODY(101) 334 | #endif 335 | #if N > 102 336 | BODY(102) 337 | #endif 338 | #if N > 103 339 | BODY(103) 340 | #endif 341 | #if N > 104 342 | BODY(104) 343 | #endif 344 | #if N > 105 345 | BODY(105) 346 | #endif 347 | #if N > 106 348 | BODY(106) 349 | #endif 350 | #if N > 107 351 | BODY(107) 352 | #endif 353 | #if N > 108 354 | BODY(108) 355 | #endif 356 | #if N > 109 357 | BODY(109) 358 | #endif 359 | #if N > 110 360 | BODY(110) 361 | #endif 362 | #if N > 111 363 | BODY(111) 364 | #endif 365 | #if N > 112 366 | BODY(112) 367 | #endif 368 | #if N > 113 369 | BODY(113) 370 | #endif 371 | #if N > 114 372 | BODY(114) 373 | #endif 374 | #if N > 115 375 | BODY(115) 376 | #endif 377 | #if N > 116 378 | BODY(116) 379 | #endif 380 | #if N > 117 381 | BODY(117) 382 | #endif 383 | #if N > 118 384 | BODY(118) 385 | #endif 386 | #if N > 119 387 | BODY(119) 388 | #endif 389 | #if N > 120 390 | BODY(120) 391 | #endif 392 | #if N > 121 393 | BODY(121) 394 | #endif 395 | #if N > 122 396 | BODY(122) 397 | #endif 398 | #if N > 123 399 | BODY(123) 400 | #endif 401 | #if N > 124 402 | BODY(124) 403 | #endif 404 | #if N > 125 405 | BODY(125) 406 | #endif 407 | #if N > 126 408 | BODY(126) 409 | #endif 410 | #if N > 127 411 | BODY(127) 412 | #endif 413 | #if N > 128 414 | BODY(128) 415 | #endif 416 | #if N > 129 417 | BODY(129) 418 | #endif 419 | #if N > 130 420 | BODY(130) 421 | #endif 422 | #if N > 131 423 | BODY(131) 424 | #endif 425 | #if N > 132 426 | BODY(132) 427 | #endif 428 | #if N > 133 429 | BODY(133) 430 | #endif 431 | #if N > 134 432 | BODY(134) 433 | #endif 434 | #if N > 135 435 | BODY(135) 436 | #endif 437 | #if N > 136 438 | BODY(136) 439 | #endif 440 | #if N > 137 441 | BODY(137) 442 | #endif 443 | #if N > 138 444 | BODY(138) 445 | #endif 446 | #if N > 139 447 | BODY(139) 448 | #endif 449 | #if N > 140 450 | BODY(140) 451 | #endif 452 | #if N > 141 453 | BODY(141) 454 | #endif 455 | #if N > 142 456 | BODY(142) 457 | #endif 458 | #if N > 143 459 | BODY(143) 460 | #endif 461 | #if N > 144 462 | BODY(144) 463 | #endif 464 | #if N > 145 465 | BODY(145) 466 | #endif 467 | #if N > 146 468 | BODY(146) 469 | #endif 470 | #if N > 147 471 | BODY(147) 472 | #endif 473 | #if N > 148 474 | BODY(148) 475 | #endif 476 | #if N > 149 477 | BODY(149) 478 | #endif 479 | #if N > 150 480 | BODY(150) 481 | #endif 482 | #if N > 151 483 | BODY(151) 484 | #endif 485 | #if N > 152 486 | BODY(152) 487 | #endif 488 | #if N > 153 489 | BODY(153) 490 | #endif 491 | #if N > 154 492 | BODY(154) 493 | #endif 494 | #if N > 155 495 | BODY(155) 496 | #endif 497 | #if N > 156 498 | BODY(156) 499 | #endif 500 | #if N > 157 501 | BODY(157) 502 | #endif 503 | #if N > 158 504 | BODY(158) 505 | #endif 506 | #if N > 159 507 | BODY(159) 508 | #endif 509 | #if N > 160 510 | BODY(160) 511 | #endif 512 | #if N > 161 513 | BODY(161) 514 | #endif 515 | #if N > 162 516 | BODY(162) 517 | #endif 518 | #if N > 163 519 | BODY(163) 520 | #endif 521 | #if N > 164 522 | BODY(164) 523 | #endif 524 | #if N > 165 525 | BODY(165) 526 | #endif 527 | #if N > 166 528 | BODY(166) 529 | #endif 530 | #if N > 167 531 | BODY(167) 532 | #endif 533 | #if N > 168 534 | BODY(168) 535 | #endif 536 | #if N > 169 537 | BODY(169) 538 | #endif 539 | #if N > 170 540 | BODY(170) 541 | #endif 542 | #if N > 171 543 | BODY(171) 544 | #endif 545 | #if N > 172 546 | BODY(172) 547 | #endif 548 | #if N > 173 549 | BODY(173) 550 | #endif 551 | #if N > 174 552 | BODY(174) 553 | #endif 554 | #if N > 175 555 | BODY(175) 556 | #endif 557 | #if N > 176 558 | BODY(176) 559 | #endif 560 | #if N > 177 561 | BODY(177) 562 | #endif 563 | #if N > 178 564 | BODY(178) 565 | #endif 566 | #if N > 179 567 | BODY(179) 568 | #endif 569 | #if N > 180 570 | BODY(180) 571 | #endif 572 | #if N > 181 573 | BODY(181) 574 | #endif 575 | #if N > 182 576 | BODY(182) 577 | #endif 578 | #if N > 183 579 | BODY(183) 580 | #endif 581 | #if N > 184 582 | BODY(184) 583 | #endif 584 | #if N > 185 585 | BODY(185) 586 | #endif 587 | #if N > 186 588 | BODY(186) 589 | #endif 590 | #if N > 187 591 | BODY(187) 592 | #endif 593 | #if N > 188 594 | BODY(188) 595 | #endif 596 | #if N > 189 597 | BODY(189) 598 | #endif 599 | #if N > 190 600 | BODY(190) 601 | #endif 602 | #if N > 191 603 | BODY(191) 604 | #endif 605 | #if N > 192 606 | BODY(192) 607 | #endif 608 | #if N > 193 609 | BODY(193) 610 | #endif 611 | #if N > 194 612 | BODY(194) 613 | #endif 614 | #if N > 195 615 | BODY(195) 616 | #endif 617 | #if N > 196 618 | BODY(196) 619 | #endif 620 | #if N > 197 621 | BODY(197) 622 | #endif 623 | #if N > 198 624 | BODY(198) 625 | #endif 626 | #if N > 199 627 | BODY(199) 628 | #endif 629 | #if N > 200 630 | BODY(200) 631 | #endif 632 | #if N > 201 633 | BODY(201) 634 | #endif 635 | #if N > 202 636 | BODY(202) 637 | #endif 638 | #if N > 203 639 | BODY(203) 640 | #endif 641 | #if N > 204 642 | BODY(204) 643 | #endif 644 | #if N > 205 645 | BODY(205) 646 | #endif 647 | #if N > 206 648 | BODY(206) 649 | #endif 650 | #if N > 207 651 | BODY(207) 652 | #endif 653 | #if N > 208 654 | BODY(208) 655 | #endif 656 | #if N > 209 657 | BODY(209) 658 | #endif 659 | #if N > 210 660 | BODY(210) 661 | #endif 662 | #if N > 211 663 | BODY(211) 664 | #endif 665 | #if N > 212 666 | BODY(212) 667 | #endif 668 | #if N > 213 669 | BODY(213) 670 | #endif 671 | #if N > 214 672 | BODY(214) 673 | #endif 674 | #if N > 215 675 | BODY(215) 676 | #endif 677 | #if N > 216 678 | BODY(216) 679 | #endif 680 | #if N > 217 681 | BODY(217) 682 | #endif 683 | #if N > 218 684 | BODY(218) 685 | #endif 686 | #if N > 219 687 | BODY(219) 688 | #endif 689 | #if N > 220 690 | BODY(220) 691 | #endif 692 | #if N > 221 693 | BODY(221) 694 | #endif 695 | #if N > 222 696 | BODY(222) 697 | #endif 698 | #if N > 223 699 | BODY(223) 700 | #endif 701 | #if N > 224 702 | BODY(224) 703 | #endif 704 | #if N > 225 705 | BODY(225) 706 | #endif 707 | #if N > 226 708 | BODY(226) 709 | #endif 710 | #if N > 227 711 | BODY(227) 712 | #endif 713 | #if N > 228 714 | BODY(228) 715 | #endif 716 | #if N > 229 717 | BODY(229) 718 | #endif 719 | #if N > 230 720 | BODY(230) 721 | #endif 722 | #if N > 231 723 | BODY(231) 724 | #endif 725 | #if N > 232 726 | BODY(232) 727 | #endif 728 | #if N > 233 729 | BODY(233) 730 | #endif 731 | #if N > 234 732 | BODY(234) 733 | #endif 734 | #if N > 235 735 | BODY(235) 736 | #endif 737 | #if N > 236 738 | BODY(236) 739 | #endif 740 | #if N > 237 741 | BODY(237) 742 | #endif 743 | #if N > 238 744 | BODY(238) 745 | #endif 746 | #if N > 239 747 | BODY(239) 748 | #endif 749 | #if N > 240 750 | BODY(240) 751 | #endif 752 | #if N > 241 753 | BODY(241) 754 | #endif 755 | #if N > 242 756 | BODY(242) 757 | #endif 758 | #if N > 243 759 | BODY(243) 760 | #endif 761 | #if N > 244 762 | BODY(244) 763 | #endif 764 | #if N > 245 765 | BODY(245) 766 | #endif 767 | #if N > 246 768 | BODY(246) 769 | #endif 770 | #if N > 247 771 | BODY(247) 772 | #endif 773 | #if N > 248 774 | BODY(248) 775 | #endif 776 | #if N > 249 777 | BODY(249) 778 | #endif 779 | #if N > 250 780 | BODY(250) 781 | #endif 782 | #if N > 251 783 | BODY(251) 784 | #endif 785 | #if N > 252 786 | BODY(252) 787 | #endif 788 | #if N > 253 789 | BODY(253) 790 | #endif 791 | #if N > 254 792 | BODY(254) 793 | #endif 794 | #if N > 255 795 | BODY(255) 796 | #endif 797 | -------------------------------------------------------------------------------- /firmware/usb_buffer.xc: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_usb_aud_shared 3 | * Version: 2v3 4 | * Build: 1f458299986de727de7ac8f49b72f8d29ea1ffab 5 | * File: usb_buffer.xc 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | //In this file xud.h is not included since we are interpreting the 26 | //assembly functions GetData/SetData as taking xc_ptrs 27 | //#include "xud.h" 28 | 29 | #define XUD_SPEED_HS 2 30 | 31 | #include "usb.h" 32 | #include "devicedefines.h" 33 | #include "xc_ptr.h" 34 | #include "clockcmds.h" 35 | #include "xud.h" 36 | 37 | 38 | //typedef unsigned int XUD_ep; 39 | 40 | //int XUD_GetData_NoReq(chanend c, xc_ptr buffer); 41 | //int XUD_SetData_NoReq(chanend c, xc_ptr buffer, unsigned datalength, unsigned startIndex); 42 | XUD_ep XUD_Init_Ep(chanend c_ep); 43 | 44 | inline void XUD_SetNotReady(XUD_ep e) 45 | { 46 | int chan_array_ptr; 47 | asm ("ldw %0, %1[0]":"=r"(chan_array_ptr):"r"(e)); 48 | asm ("stw %0, %1[0]"::"r"(0),"r"(chan_array_ptr)); 49 | } 50 | 51 | void GetADCCounts(unsigned samFreq, int &min, int &mid, int &max); 52 | #define BUFFER_SIZE_OUT (1028 >> 2) 53 | #define BUFFER_SIZE_IN (1028 >> 2) 54 | 55 | /* Packet buffers for audio data */ 56 | 57 | extern unsigned int g_curSamFreqMultiplier; 58 | 59 | 60 | /* Global var for speed. Related to feedback. Used by input stream to determine IN packet size */ 61 | unsigned g_speed; 62 | unsigned g_freqChange = 0; 63 | 64 | /* Interrupt EP data */ 65 | unsigned char g_intData[8]; 66 | 67 | unsigned char fb_clocks[16]; 68 | 69 | //#define FB_TOLERANCE_TEST 70 | #define FB_TOLERANCE 0x100 71 | 72 | extern unsigned inZeroBuff[]; 73 | extern unsigned g_numUsbChanIn; 74 | /** 75 | * Buffers data from audio endpoints 76 | * @param c_aud_out chanend for audio from xud 77 | * @param c_aud_in chanend for audio to xud 78 | * @param c_aud_fb chanend for feeback to xud 79 | * @return void 80 | */ 81 | void buffer(register chanend c_aud_out, register chanend c_aud_in, chanend c_aud_fb, 82 | chanend c_int, chanend c_sof, 83 | chanend c_aud_ctl, 84 | in port p_off_mclk 85 | ) 86 | { 87 | XUD_ep ep_aud_out = XUD_Init_Ep(c_aud_out); 88 | XUD_ep ep_aud_in = XUD_Init_Ep(c_aud_in); 89 | XUD_ep ep_aud_fb = XUD_Init_Ep(c_aud_fb); 90 | XUD_ep ep_int = XUD_Init_Ep(c_int); 91 | 92 | unsigned datalength; 93 | unsigned tmp; 94 | unsigned sampleFreq = 0; 95 | unsigned lastClock; 96 | 97 | unsigned clocks = 0; 98 | 99 | 100 | unsigned bufferIn = 1; 101 | unsigned remnant = 0, cycles; 102 | unsigned sofCount = 0; 103 | unsigned freqChange = 0; 104 | //unsigned expected = (DEFAULT_FREQ/8000)<<16; 105 | 106 | unsigned expected_fb = 0; 107 | 108 | xc_ptr aud_from_host_buffer = 0; 109 | 110 | 111 | 112 | set_thread_fast_mode_on(); 113 | 114 | asm("stw %0, dp[int_usb_ep]"::"r"(ep_int)); 115 | asm("stw %0, dp[aud_from_host_usb_ep]"::"r"(ep_aud_out)); 116 | asm("stw %0, dp[aud_to_host_usb_ep]"::"r"(ep_aud_in)); 117 | asm("stw %0, dp[buffer_aud_ctl_chan]"::"r"(c_aud_ctl)); 118 | 119 | /* Wait for USB connect then setup our first packet */ 120 | { 121 | int min, mid, max; 122 | int usb_speed = 0; 123 | int frameTime; 124 | 125 | while(usb_speed == 0) 126 | asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :); 127 | 128 | GetADCCounts(DEFAULT_FREQ, min, mid, max); 129 | asm("stw %0, dp[g_speed]"::"r"(mid << 16)); 130 | if (usb_speed == XUD_SPEED_HS) 131 | mid*=NUM_USB_CHAN_IN*4; 132 | else 133 | mid*=NUM_USB_CHAN_IN*3; 134 | asm("stw %0, %1[0]"::"r"(mid),"r"(inZeroBuff)); 135 | 136 | expected_fb = ((DEFAULT_FREQ * 0x2000) / 1000); 137 | 138 | } 139 | 140 | #ifdef OUTPUT 141 | SET_SHARED_GLOBAL(g_aud_from_host_flag, 1); 142 | #endif 143 | 144 | #ifdef INPUT 145 | SET_SHARED_GLOBAL(g_aud_to_host_flag, 1); 146 | #endif 147 | 148 | (fb_clocks, unsigned[])[0] = 0; 149 | 150 | 151 | { 152 | int usb_speed; 153 | int x; 154 | 155 | asm("ldaw %0, dp[fb_clocks]":"=r"(x)); 156 | asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :); 157 | 158 | if (usb_speed == XUD_SPEED_HS) 159 | { 160 | 161 | XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 4); 162 | 163 | } 164 | else 165 | { 166 | 167 | XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 3); 168 | } 169 | } 170 | 171 | while(1) 172 | { 173 | /* Wait for response from XUD and service relevant EP */ 174 | select 175 | { 176 | /* Interrupt EP, send back interrupt data. Note, request made from decouple */ 177 | case inuint_byref(c_int, tmp): 178 | { 179 | int sent_ok = 0; 180 | /* Start XUD_SetData */ 181 | 182 | XUD_SetData_Inline(ep_int, c_int); 183 | 184 | #if 0 185 | while (!sent_ok) 186 | { 187 | outct(c_int, 64); 188 | asm("ldw %0, dp[g_intData]":"=r"(tmp)); 189 | outuint(c_int, tmp); 190 | asm("ldw %0, dp[g_intData+4]":"=r"(tmp)); 191 | outct(c_int, 64); 192 | outuint(c_int, tmp); 193 | sent_ok = inuint(c_int); 194 | /* End XUD_SetData */ 195 | } 196 | #endif 197 | 198 | asm("stw %0, dp[g_intFlag]" :: "r" (0) ); 199 | XUD_SetNotReady(ep_int); 200 | break; 201 | } 202 | 203 | /* Sample Freq our chan count update from ep 0 */ 204 | case inuint_byref(c_aud_ctl, tmp): 205 | { 206 | int min, mid, max; 207 | int usb_speed; 208 | int frameTime; 209 | asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :); 210 | 211 | if(tmp == SET_SAMPLE_FREQ) 212 | { 213 | sampleFreq = inuint(c_aud_ctl); 214 | 215 | /* Tidy up double buffer, note we can do better than this for 44.1 etc but better 216 | * than sending two packets at old speed! */ 217 | if (usb_speed == XUD_SPEED_HS) 218 | frameTime = 8000; 219 | else 220 | frameTime = 1000; 221 | 222 | min = sampleFreq / frameTime; 223 | 224 | max = min + 1; 225 | 226 | mid = min; 227 | 228 | /* Check for INT(SampFreq/8000) == SampFreq/8000 */ 229 | if((sampleFreq % frameTime) == 0) 230 | { 231 | min -= 1; 232 | } 233 | expected_fb = ((sampleFreq * 0x2000) / frameTime); 234 | 235 | asm("stw %0, dp[g_speed]"::"r"(mid << 16)); 236 | 237 | if (usb_speed == XUD_SPEED_HS) 238 | mid *= NUM_USB_CHAN_IN*4; 239 | else 240 | mid *= NUM_USB_CHAN_IN*3; 241 | 242 | asm("stw %0, %1[0]"::"r"(mid),"r"(inZeroBuff)); 243 | 244 | /* Reset FB */ 245 | /* Note, Endpoint 0 will hold off host for a sufficient period to allow out feedback 246 | * to stabilise (i.e. sofCount == 128 to fire) */ 247 | sofCount = 0; 248 | clocks = 0; 249 | remnant = 0; 250 | 251 | /* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this 252 | * thread locked, it must stay responsive to packets/SOFs. So, set a flag and check for 253 | * handshake elsewhere */ 254 | /* Pass on sample freq change to decouple */ 255 | SET_SHARED_GLOBAL(g_freqChange, SET_SAMPLE_FREQ); 256 | SET_SHARED_GLOBAL(g_freqChange_sampFreq, sampleFreq); 257 | SET_SHARED_GLOBAL(g_freqChange_flag, SET_SAMPLE_FREQ); 258 | } 259 | else 260 | { 261 | sampleFreq = inuint(c_aud_ctl); 262 | SET_SHARED_GLOBAL(g_freqChange, tmp); /* Set command */ 263 | SET_SHARED_GLOBAL(g_freqChange_sampFreq, sampleFreq); /* Set flag */ 264 | SET_SHARED_GLOBAL(g_freqChange_flag, tmp); 265 | } 266 | 267 | 268 | 269 | break; 270 | } 271 | 272 | #define MASK_16_13 (7) // Bits that should not be transmitted as part of feedback. 273 | #define MASK_16_10 (127) //(63) /* For Audio 1.0 we use a mask 1 bit longer than expected to avoid Windows LSB isses */ 274 | 275 | case inuint_byref(c_sof, tmp): 276 | 277 | /* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to 278 | * lastClock being incorrect */ 279 | asm("#sof"); 280 | 281 | /* Get MCLK count */ 282 | asm (" getts %0, res[%1]" : "=r" (tmp) : "r" (p_off_mclk)); 283 | 284 | GET_SHARED_GLOBAL(freqChange, g_freqChange); 285 | if(freqChange == SET_SAMPLE_FREQ) 286 | { 287 | /* Keep getting MCLK counts */ 288 | lastClock = tmp; 289 | } 290 | else 291 | { 292 | unsigned mask = MASK_16_13, usb_speed; 293 | 294 | asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :); 295 | 296 | if(usb_speed != XUD_SPEED_HS) 297 | mask = MASK_16_10; 298 | 299 | /* Number of MCLKS this SOF, approx 125 * 24 (3000), sample by sample rate */ 300 | asm("ldw %0, dp[g_curSamFreqMultiplier]":"=r"(cycles)); 301 | cycles = ((int)((short)(tmp - lastClock))) * cycles; 302 | 303 | /* Any odd bits (lower than 16.23) have to be kept seperate */ 304 | remnant += cycles & mask; 305 | 306 | /* Add 16.13 bits into clock count */ 307 | clocks += (cycles & ~mask) + (remnant & ~mask); 308 | 309 | /* and overflow from odd bits. Remove overflow from odd bits. */ 310 | remnant &= mask; 311 | 312 | /* Store MCLK for next time around... */ 313 | lastClock = tmp; 314 | 315 | /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll 316 | * We always could 128 sofs, so 16ms @ HS, 128ms @ FS */ 317 | if(sofCount == 128) 318 | { 319 | sofCount = 0; 320 | #ifdef FB_TOLERANCE_TEST 321 | if (clocks > (expected_fb - FB_TOLERANCE) && 322 | clocks < (expected_fb + FB_TOLERANCE)) 323 | #endif 324 | { 325 | int usb_speed; 326 | asm("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks 327 | //fb_clocks = clocks; 328 | 329 | asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :); 330 | 331 | if (usb_speed == XUD_SPEED_HS) 332 | { 333 | (fb_clocks, unsigned[])[0] = clocks; 334 | } 335 | else 336 | { 337 | (fb_clocks, unsigned[])[0] = clocks>>2; 338 | } 339 | } 340 | #ifdef FB_TOLERANCE_TEST 341 | else { 342 | } 343 | #endif 344 | clocks = 0; 345 | } 346 | 347 | sofCount++; 348 | } 349 | break; 350 | 351 | #ifdef OUTPUT 352 | /* Audio HOST -> DEVICE */ 353 | case inuint_byref(c_aud_out, tmp): 354 | 355 | asm("#h->d aud data"); 356 | GET_SHARED_GLOBAL(aud_from_host_buffer, g_aud_from_host_buffer); 357 | 358 | // XUD_GetData 359 | { 360 | xc_ptr p = aud_from_host_buffer+4; 361 | xc_ptr p0 = p; 362 | int tail; 363 | while (!testct(c_aud_out)) 364 | { 365 | unsigned int datum = inuint(c_aud_out); 366 | write_via_xc_ptr(p, datum); 367 | p += 4; 368 | } 369 | tail = inct(c_aud_out); 370 | datalength = p - p0 - 4; 371 | switch (tail) 372 | { 373 | case 10: 374 | // the tail is 0 which means 375 | datalength -= 2; 376 | break; 377 | default: 378 | // the tail is 2 which means the input was word aligned 379 | break; 380 | } 381 | } 382 | 383 | XUD_SetNotReady(ep_aud_out); 384 | write_via_xc_ptr(aud_from_host_buffer, datalength); 385 | /* Sync with audio thread */ 386 | SET_SHARED_GLOBAL(g_aud_from_host_flag, 1); 387 | 388 | break; 389 | #endif 390 | 391 | #ifdef INPUT 392 | /* DEVICE -> HOST */ 393 | case inuint_byref(c_aud_in, tmp): 394 | { 395 | XUD_SetData_Inline(ep_aud_in, c_aud_in); 396 | 397 | XUD_SetNotReady(ep_aud_in); 398 | 399 | /* Inform stream that buffer sent */ 400 | SET_SHARED_GLOBAL(g_aud_to_host_flag, bufferIn+1); 401 | } 402 | break; 403 | 404 | #endif 405 | 406 | #ifdef OUTPUT 407 | /* Feedback Pipe */ 408 | case inuint_byref(c_aud_fb, tmp): 409 | { 410 | 411 | int usb_speed; 412 | int x; 413 | 414 | asm("#aud fb"); 415 | 416 | XUD_SetData_Inline(ep_aud_fb, c_aud_fb); 417 | 418 | asm("ldaw %0, dp[fb_clocks]":"=r"(x)); 419 | asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :); 420 | 421 | if (usb_speed == XUD_SPEED_HS) 422 | { 423 | XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 4); 424 | } 425 | else 426 | { 427 | XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 3); 428 | } 429 | } 430 | break; 431 | #endif 432 | } 433 | 434 | } 435 | 436 | set_thread_fast_mode_off(); 437 | } 438 | -------------------------------------------------------------------------------- /firmware/XUD_EpFuncs.S: -------------------------------------------------------------------------------- 1 | /** 2 | * Module: module_xud 3 | * Version: 0v60 4 | * Build: 5749c99b7821363ba858462b29442d52f62eafe2 5 | * File: XUD_EpFuncs.S 6 | * 7 | * The copyrights, all other intellectual and industrial 8 | * property rights are retained by XMOS and/or its licensors. 9 | * Terms and conditions covering the use of this code can 10 | * be found in the Xmos End User License Agreement. 11 | * 12 | * Copyright XMOS Ltd 2010 13 | * 14 | * In the case where this code is a modification of existing code 15 | * under a separate license, the separate license terms are shown 16 | * below. The modifications to the code are still covered by the 17 | * copyright notice above. 18 | * 19 | **/ 20 | /** XUD_EpFuncs.S 21 | * @brief Functions for data transfer to/from XUD 22 | * @author Ross Owen, XMOS Limited 23 | * @version 0v9 24 | */ 25 | #include "usb.h" 26 | 27 | #define SR_EEBLE_BIT 0x1 28 | //int XUD_GetSetupData(chanend c, unsigned buffer[]); 29 | // r0 r1 30 | // TODO just use GetData 31 | .globl XUD_GetSetupData 32 | .globl XUD_GetSetupData.nstackwords 33 | .linkset XUD_GetSetupData.nstackwords, 0 34 | .text 35 | 36 | .cc_top XUD_GetSetupData.func, XUD_GetSetupData 37 | XUD_GetSetupData: 38 | ldw r2, r0[0] 39 | ldw r11, r0[1] 40 | stw r11, r2[0] 41 | ldw r0, r0[2] 42 | 43 | XUD_GetSetupData_Retry: 44 | out res[r0], r1 // TODO Should only need CT 45 | 46 | 47 | testct r11, res[r0] // Test whether there is a RESET/SUSPEND exception 48 | bt r11, ResetSuspend 49 | 50 | in r11, res[r0] 51 | SetupDataLoop: 52 | testct r11, res[r0] 53 | bt r11, XUD_GetSetupData_Retry 54 | in r11, res[r0] // r2: 0 55 | stw r11, r1[0] 56 | testct r11, res[r0] 57 | bt r11, XUD_GetSetupData_Retry 58 | in r11, res[r0] // r2: 0 59 | stw r11, r1[1] 60 | inct r11, res[r0] // tail or 9 for crc error 61 | sub r11, r11, 9 62 | bf r11, XUD_GetSetupData_Retry 63 | ldc r11, 0 64 | stw r11, r2[0] // Zero ready entry 65 | ldc r0, 8 66 | 67 | retsp 0 68 | .cc_bottom XUD_GetSetupData.func 69 | 70 | 71 | .globl XUD_GetData_NoReq 72 | .globl XUD_GetData_NoReq.nstackwords 73 | .linkset XUD_GetData_NoReq.nstackwords, 0 74 | 75 | //int XUD_GetData(chanend c, unsigned buffer[]); 76 | // r0 r1 77 | 78 | .globl XUD_GetData 79 | .globl XUD_GetData.nstackwords 80 | .linkset XUD_GetData.nstackwords, 0 81 | .text 82 | 83 | .cc_top XUD_GetData.func, XUD_GetData 84 | XUD_GetData: 85 | ldw r2, r0[0] 86 | ldw r11, r0[1] 87 | stw r11, r2[0] // Mark EP as ready 88 | ldw r0, r0[2] 89 | XUD_GetDataRetry: 90 | out res[r0], r1 // TODO Should only need CT 91 | 92 | testct r11, res[r0] // Test whether there is a RESET/SUSPEND exception 93 | bt r11, ResetSuspend 94 | 95 | in r11, res[r0] // Wait for XUD response 96 | 97 | XUD_GetData_NoReq: // Entry for _NoReq 98 | testct r3, res[r0] // Wait for data (or end) 99 | bt r3, DataEnd 100 | 101 | DataLoop: 102 | in r11, res[r0] // r2: 0 103 | stw r11, r1[r3] 104 | add r3, r3, 1 105 | testct r11, res[r0] 106 | bf r11, DataLoop 107 | 108 | DataEnd: 109 | inct r11, res[r0] // r11 is tail length (bytes + 10) 110 | // or 9 for crc error 111 | sub r11, r11, 10 112 | 113 | CalcdataLength: 114 | shl r3, r3, 2 // Num received words to bytes 115 | add r3, r11, r3 // r11: Total bytes received (Note this includes 2 byte crc) 116 | 117 | add r11, r11, 1 118 | bf r11, XUD_GetDataBadCRC // CRC error, restart 119 | 120 | ldc r11, 0 121 | stw r11, r2[0] // Zero ready entry 122 | 123 | sub r0, r3, 6 // CRC correction and extra increment 124 | 125 | retsp 0 126 | 127 | ResetSuspend: 128 | ldc r11, 0 129 | stw r11, r2[0] // Zero ready entry 130 | 131 | mkmsk r0, 32 132 | Return: 133 | retsp 0 134 | 135 | XUD_GetDataBadCRC: 136 | bu XUD_GetDataRetry 137 | .cc_bottom XUD_GetData.func 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | // Note: Assumes startIndex is word aligned 151 | //int XUD_SetData_indexed(chanend c, unsigned buffer[], unsigned datasize, unsigned startIndex unsigned pid); 152 | // r0 r1 r2 r3 153 | 154 | .globl XUD_SetData_NoReq 155 | .globl XUD_SetData_NoReq.nstackwords 156 | .linkset XUD_SetData_NoReq.nstackwords, 0 157 | 158 | .globl XUD_SetData 159 | .globl XUD_SetData.nstackwords 160 | .linkset XUD_SetData.nstackwords, 7 161 | .text 162 | 163 | .cc_top XUD_SetData.func, XUD_SetData 164 | XUD_SetData: 165 | entsp 7 166 | stw r0, sp[1] // Reg save (for retry) 167 | stw r1, sp[2] 168 | stw r2, sp[3] 169 | stw r3, sp[4] 170 | stw r5, sp[5] 171 | 172 | XUD_SetDataRetry: 173 | stw r4, sp[0] 174 | 175 | ldw r11, sp[8] // Load PID toggle param from stack 176 | bt r11, XUD_SetData_PidReset 177 | 178 | XUD_SetData_PidToggle: 179 | ldw r11, r0[4] // Load EP PID from structure 180 | ldc r4, 0x88 181 | xor r11, r11, r4 182 | stw r11, r0[4] 183 | 184 | XUD_SetData_PidReset: 185 | stw r11, r0[4] // Store back Reset PID 186 | 187 | 188 | XUD_SetData_NoReq: 189 | add r1, r1, r3 // Add start index to buffer address 190 | 191 | CalcTailLength: 192 | shl r3, r2, 5 // Taillength: bytes to bits * 2 193 | zext r3, 7 194 | 195 | SetupLoopTerm: 196 | shr r2, r2, 2 // r2: datalength (bytes) ---> r2: datalength (words) 197 | 198 | AdjustBufferPointer: 199 | shl r5, r2, 2 // Get end off buffer address 200 | add r1, r1, r5 201 | 202 | NegativeIndex: // Produce negtive offset from end of buffer 203 | neg r2, r2 204 | 205 | LoadFirstWord: 206 | ldw r5, r1[r2] // Load first word.. (done to save branching to load) 207 | 208 | ldw r4, r0[2] // Load channel 209 | out res[r4], r11 // Send PID 210 | 211 | ldw r4, r0[0] 212 | ldw r11, r0[1] // Load chan 213 | ldw r0, r0[2] 214 | 215 | outct res[r0], r3 // Out tail length 216 | bf r2, XUD_SetData_ShortPacket 217 | 218 | XUD_SetData_DataRdy: 219 | stw r11, r4[0] // Mark EP as ready to go 220 | 221 | testct r11, res[r0] // Test whether there is a RESET/SUSPEND exception 222 | bt r11, ResetSuspend2 223 | in r11, res[r0] // Wait for response to request to send 224 | 225 | XUD_SetData_OutputLoop_Out: 226 | OutputLoop: 227 | out res[r0], r5 228 | add r2, r2, 1 229 | ldw r5, r1[r2] 230 | bt r2, OutputLoop // NOTE: We have a instruction spare here 231 | 232 | XUD_SetData_OutputLoop_End: 233 | outct res[r0], r3 // Send out tail length, note: safe as only CT 1 and 2 are reserved (END and PAUSE) 234 | 235 | SendTail: 236 | out res[r0], r5 237 | in r1, res[r0] 238 | ldc r0, 0 239 | bf r1, Return2 240 | 241 | ldw r0, sp[1] 242 | ldw r1, sp[2] 243 | ldw r2, sp[3] 244 | ldw r3, sp[4] 245 | ldw r5, sp[5] 246 | 247 | bu XUD_SetDataRetry 248 | 249 | Return2: 250 | ldc r11, 0 251 | stw r11, r4[0] // Zero ready entry 252 | ldw r4, sp[0] 253 | ldw r5, sp[5] 254 | retsp 7 255 | 256 | ResetSuspend2: 257 | 258 | mkmsk r0, 32 259 | bu Return2 260 | 261 | .cc_bottom XUD_SetData.func 262 | 263 | XUD_SetData_ShortPacket: 264 | 265 | stw r11, r4[0] 266 | 267 | testct r11, res[r0] // Test whether there is a RESET/SUSPEND exception 268 | bt r11, ResetSuspend2 269 | in r11, res[r0] // Wait for response to request to send 270 | 271 | //outct res[r0], r3 // Out tail length 272 | 273 | XUD_SetData_OutTail_Short: 274 | outct res[r0], r3 // Send out tail length, note: safe as only CT 1 and 2 are reserved (END and PAUSE) 275 | 276 | out res[r0], r5 277 | in r1, res[r0] 278 | ldc r0, 0 279 | bf r1, Return2 280 | 281 | ldw r0, sp[1] 282 | ldw r1, sp[2] 283 | ldw r2, sp[3] 284 | ldw r3, sp[4] 285 | ldw r5, sp[5] 286 | 287 | bu XUD_SetDataRetry 288 | 289 | 290 | .globl XUD_ResetEndpoint 291 | .globl XUD_ResetEndpoint.nstackwords 292 | .linkset XUD_ResetEndpoint.nstackwords, 1 293 | 294 | .cc_top XUD_ResetEndpoint.func, XUD_ResetEndpoint 295 | XUD_ResetEndpoint: 296 | entsp 1 297 | ldw r0, r0[2] 298 | bf r1, .L0 299 | ldw r1, r1[0] 300 | ldw r1, r1[2] 301 | .L0: 302 | bl XUD_ResetEndpoint0 303 | retsp 1 304 | .cc_bottom XUD_ResetEndpoint.func 305 | 306 | .globl XUD_SetReady.nstackwords 307 | .linkset XUD_SetReady.nstackwords, 0 308 | 309 | .cc_top XUD_SetReady.func, XUD_SetReady 310 | XUD_SetReady: 311 | ldw r0, r0[2] 312 | out res[r0], r1 313 | ldw r11, r0[0] 314 | ldw r2, r0[1] 315 | stw r2, r11[0] 316 | retsp 0 317 | .cc_bottom XUD_SetReady.func 318 | 319 | 320 | .globl XUD_SetStall_Out 321 | .globl XUD_SetStall_Out.nstackwords 322 | .linkset XUD_SetStall_Out.nstackwords, 0 323 | 324 | /* R0: ep number */ 325 | .cc_top XUD_SetStall_Out.func, XUD_SetStall_Out 326 | XUD_SetStall_Out: 327 | ldaw r1, dp[handshakeTable_OUT] 328 | ldc r2, PIDn_STALL 329 | stw r2, r1[r0] 330 | retsp 0 331 | .cc_bottom XUD_SetStall_Out.func 332 | 333 | 334 | .globl XUD_SetStall_In 335 | .globl XUD_SetStall_In.nstackwords 336 | .linkset XUD_SetStall_In.nstackwords, 0 337 | 338 | /* R0: ep number */ 339 | .cc_top XUD_SetStall_In.func, XUD_SetStall_In 340 | XUD_SetStall_In: 341 | ldaw r1, dp[handshakeTable_IN] 342 | ldc r2, PIDn_STALL 343 | stw r2, r1[r0] 344 | retsp 0 345 | .cc_bottom XUD_SetStall_In.func 346 | 347 | .globl XUD_UnStall_Out 348 | .globl XUD_UnStall_Out.nstackwords 349 | .linkset XUD_UnStall_Out.nstackwords, 0 350 | 351 | /* R0: ep number */ 352 | .cc_top XUD_UnStall_Out.func, XUD_UnStall_Out 353 | XUD_UnStall_Out: 354 | ldaw r1, dp[handshakeTable_OUT] 355 | ldc r2, PIDn_NAK 356 | stw r2, r1[r0] 357 | retsp 0 358 | .cc_bottom XUD_UnStall_Out.func 359 | 360 | 361 | .globl XUD_UnStall_In 362 | .globl XUD_UnStall_In.nstackwords 363 | .linkset XUD_UnStall_In.nstackwords, 0 364 | 365 | /* R0: ep number */ 366 | .cc_top XUD_UnStall_In.func, XUD_UnStall_In 367 | XUD_UnStall_In: 368 | ldaw r1, dp[handshakeTable_IN] 369 | ldc r2, PIDn_NAK 370 | stw r2, r1[r0] 371 | retsp 0 372 | .cc_bottom XUD_UnStall_In.func 373 | -------------------------------------------------------------------------------- /firmware/mkdescriptors.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | CS_INTERFACE = 0x24 4 | HEADER = 0x01 5 | INPUT_TERMINAL = 0x02 6 | OUTPUT_TERMINAL = 0x03 7 | MIXER_UNIT = 0x04 8 | SELECTOR_UNIT = 0x05 9 | FEATURE_UNIT = 0x06 10 | EFFECT_UNIT = 0x07 11 | PROCESSING_UNIT = 0x08 12 | EXTENSION_UNIT = 0x09 13 | CLOCK_SOURCE = 0x0a 14 | CLOCK_SELECTOR = 0x0b 15 | CLOCK_MULTIPLIER = 0x0c 16 | SAMPLE_RATE_CONVERTER = 0x0d 17 | 18 | #channels = "FL FR FC LFE BL BR" 19 | channels = "FL FR BL BR FC LFE" 20 | for i,c in enumerate(channels.split()): 21 | globals()["C_%s" % c] = 1 << i 22 | for i,c in enumerate(channels.split()): 23 | globals()["%s" % c] = i + 1 24 | 25 | CHAN_STEREO = (2, C_FL | C_FR) 26 | CHAN_6CH = (6, C_FL | C_FR | C_FC | C_LFE | C_BL | C_BR) 27 | MASTER = 0 28 | 29 | RO = 0x01 30 | RW = 0x03 31 | 32 | USB_STREAMING = 0x0101 33 | LINE_CONNECTOR = 0x0603 34 | SPDIF_INTERFACE = 0x0605 35 | 36 | UP_DOWNMIX_PROCESS = 0x01 37 | 38 | CLOCK_EXTERNAL = 0x00 39 | CLOCK_INT_FIXED = 0x01 40 | 41 | HOME_THEATER = 0x02 42 | 43 | string_offset = 6 44 | strings = [] 45 | audio_descriptors = [] 46 | 47 | def mkstring(s): 48 | if s is None: 49 | return 0 50 | if s in strings: 51 | return strings.index(s) + string_offset 52 | else: 53 | strings.append(s) 54 | return len(strings) - 1 + string_offset 55 | 56 | class Descriptor(object): 57 | def __init__(self, type): 58 | self.type = type 59 | 60 | def build(self, data): 61 | data = struct.pack(" 27 | #include 28 | #include 29 | 30 | #include "xud.h" /* XUD user defines and functions */ 31 | #include "usb.h" /* Defines from USB 2.0 Spec */ 32 | #include "usbaudio20.h" /* Defines from USB Audio 2.0 spec */ 33 | 34 | #include "devicedefines.h" 35 | #include "DescriptorRequests.h" /* This device's descriptors */ 36 | #include "descriptors_2.h" /* Descriptors */ 37 | #include "clockcmds.h" 38 | #include "audiostream.h" 39 | 40 | /* Handles Audio Class requests */ 41 | int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, SetupPacket &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl); 42 | int VendorRequests(XUD_ep ep0_out, XUD_ep ep0_in, SetupPacket &sp, chanend c_dsp_ctl); 43 | 44 | /* Global var for current frequency, set to default freq */ 45 | unsigned int g_curSamFreq = DEFAULT_FREQ; 46 | unsigned int g_curSamFreq48000Family = DEFAULT_FREQ % 48000 == 0; 47 | unsigned int g_curSamFreqMultiplier = DEFAULT_FREQ / 48000; 48 | 49 | int min(int x, int y); 50 | 51 | /* Records alt setting for each interface */ 52 | int interfaceAlt[NUM_INTERFACES] = {0}; 53 | 54 | /* Global current device config var*/ 55 | unsigned g_config = 0; 56 | 57 | /* Global endpoint status arrays */ 58 | unsigned g_epStatusOut[NUM_EP_OUT]; 59 | unsigned g_epStatusIn[NUM_EP_IN]; 60 | 61 | /* Global variable for current USB bus speed (i.e. FS/HS) */ 62 | unsigned g_curUsbSpeed = 0; 63 | 64 | /* Used when setting/clearing EP halt */ 65 | void SetEndpointStatus(unsigned epNum, unsigned status) 66 | { 67 | /* Inspect for IN bit */ 68 | if( epNum & 0x80 ) 69 | { 70 | epNum &= 0x7f; 71 | 72 | /* Range check */ 73 | if(epNum < NUM_EP_IN) 74 | { 75 | g_epStatusIn[ epNum & 0x7F ] = status; 76 | } 77 | } 78 | else 79 | { 80 | if(epNum < NUM_EP_OUT) 81 | { 82 | g_epStatusOut[ epNum ] = status; 83 | } 84 | } 85 | } 86 | 87 | #define STR_USENG 0x0409 88 | 89 | #define DESC_STR_LANGIDS \ 90 | { \ 91 | STR_USENG & 0xff, /* 2 wLangID[0] */ \ 92 | STR_USENG>>8, /* 3 wLangID[0] */ \ 93 | '\0' \ 94 | } 95 | 96 | /* String descriptors */ 97 | static unsigned char strDesc_langIDs[] = DESC_STR_LANGIDS; 98 | 99 | /* Endpoint 0 function. Handles all requests to the device */ 100 | void Endpoint0( chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend c_dsp_ctl) 101 | { 102 | unsigned char buffer[512]; 103 | SetupPacket sp; 104 | XUD_ep ep0_out = XUD_Init_Ep(c_ep0_out); 105 | XUD_ep ep0_in = XUD_Init_Ep(c_ep0_in); 106 | 107 | /* Init endpoint status tables */ 108 | for (int i = 0; i++; i < NUM_EP_OUT) 109 | g_epStatusOut[i] = 0; 110 | 111 | for (int i = 0; i++; i < NUM_EP_IN) 112 | g_epStatusIn[i] = 0; 113 | 114 | /* Copy langIDs string desc into string[0] */ 115 | safememcpy(strDescs_Audio2[0], strDesc_langIDs, sizeof(strDesc_langIDs)); 116 | 117 | while(1) 118 | { 119 | int retVal = 1; 120 | 121 | /* Do standard enumeration requests */ 122 | if(g_curUsbSpeed == XUD_SPEED_HS) 123 | { 124 | 125 | /* Return Audio 2.0 Descriptors */ 126 | cfgDesc_Audio2[1] = CONFIGURATION; 127 | cfgDesc_Null[1] = OTHER_SPEED_CONFIGURATION; 128 | 129 | retVal = DescriptorRequests(ep0_out, ep0_in, 130 | devDesc_Audio2, sizeof(devDesc_Audio2), 131 | cfgDesc_Audio2, sizeof(cfgDesc_Audio2), 132 | devQualDesc_Null, sizeof(devQualDesc_Null), 133 | cfgDesc_Null, sizeof(cfgDesc_Null), 134 | strDescs_Audio2, sp); 135 | } 136 | else 137 | { 138 | /* Return descriptors for full-speed - NULL */ 139 | cfgDesc_Null[1] = CONFIGURATION; 140 | cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION; 141 | 142 | retVal = DescriptorRequests(ep0_out, ep0_in, 143 | devDesc_Null, sizeof(devDesc_Null), 144 | cfgDesc_Null, sizeof(cfgDesc_Null), 145 | devQualDesc_Audio2, sizeof(devQualDesc_Audio2), 146 | cfgDesc_Audio2, sizeof(cfgDesc_Audio2), 147 | strDescs_Audio2, sp); 148 | } 149 | 150 | if (retVal == 1) 151 | { 152 | /* Request not covered by XUD_DoEnumReqs() so decode ourselves */ 153 | /* Inspect Request type and Receipient */ 154 | switch( (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) ) 155 | { 156 | case STANDARD_INTERFACE_REQUEST: 157 | 158 | switch(sp.bRequest) 159 | { 160 | /* Set Interface */ 161 | case SET_INTERFACE: 162 | 163 | 164 | #if defined(OUTPUT) && defined(INPUT) 165 | /* Check for stream start stop on output and input audio interfaces */ 166 | if(sp.wValue && !interfaceAlt[1] && !interfaceAlt[2]) 167 | { 168 | /* If start and input AND output not currently running */ 169 | AudioStreamStart(); 170 | } 171 | else if(((sp.wIndex == 1)&& (!sp.wValue)) && interfaceAlt[1] && (!interfaceAlt[2])) 172 | { 173 | /* if output stop and output running and input not running */ 174 | AudioStreamStop(); 175 | } 176 | else if(((sp.wIndex == 2) && (!sp.wValue)) && interfaceAlt[2] && (!interfaceAlt[1])) 177 | { 178 | /* if input stop and input running and output not running */ 179 | AudioStreamStop(); 180 | } 181 | #elif defined(OUTPUT) || defined(INPUT) 182 | if(sp.wValue && (!interfaceAlt[1])) 183 | { 184 | /* if start and not currently running */ 185 | AudioStreamStart(); 186 | } 187 | else if (!sp.wValue && interfaceAlt[1]) 188 | { 189 | /* if stop and currently running */ 190 | AudioStreamStop(); 191 | } 192 | 193 | #endif 194 | /* Record interface change */ 195 | if( sp.wIndex < NUM_INTERFACES ) 196 | interfaceAlt[sp.wIndex] = sp.wValue; 197 | #if 1 198 | /* Check for audio stream from host start/stop */ 199 | if(sp.wIndex == 2) // Input interface 200 | { 201 | switch(sp.wValue) 202 | { 203 | case 0: 204 | 205 | break; 206 | 207 | case 1: 208 | /* Stream active + 0 chans */ 209 | outuint(c_audioControl, SET_CHAN_COUNT_IN); 210 | outuint(c_audioControl, NUM_USB_CHAN_IN); 211 | 212 | #ifdef ADAT_RX 213 | outuint(c_clk_ctl, SET_SMUX); 214 | outuint(c_clk_ctl, 0); 215 | outct(c_clk_ctl, XS1_CT_END); 216 | #endif 217 | 218 | break; 219 | 220 | #ifdef ADAT_RX 221 | case 2: 222 | 223 | /* Stream active + 8 chans */ 224 | outuint(c_audioControl, SET_CHAN_COUNT_IN); 225 | outuint(c_audioControl, NUM_USB_CHAN_IN-4); 226 | 227 | outuint(c_clk_ctl, SET_SMUX); 228 | outuint(c_clk_ctl, 1); 229 | outct(c_clk_ctl, XS1_CT_END); 230 | break; 231 | 232 | case 3: 233 | outuint(c_audioControl, SET_CHAN_COUNT_IN); 234 | outuint(c_audioControl, NUM_USB_CHAN_IN-6); 235 | 236 | 237 | outuint(c_clk_ctl, SET_SMUX); 238 | outuint(c_clk_ctl, 1); 239 | outct(c_clk_ctl, XS1_CT_END); 240 | /* Stream active + 8 chans */ 241 | //outuint(c_audioControl, 8); 242 | // Handshake 243 | //chkct(c_audioControl, XS1_CT_END); 244 | 245 | break; 246 | 247 | #endif 248 | 249 | } 250 | } 251 | #endif 252 | /* No data stage for this request, just do data stage */ 253 | retVal = XUD_DoSetRequestStatus(ep0_in, 0); 254 | break; 255 | 256 | /* A device must support the GetInterface request if it has alternate setting for that interface */ 257 | case GET_INTERFACE: 258 | 259 | buffer[0] = 0; 260 | 261 | /* Bounds check */ 262 | if( sp.wIndex < NUM_INTERFACES ) 263 | buffer[0] = interfaceAlt[sp.wIndex]; 264 | 265 | retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 1, sp.wLength); 266 | break; 267 | 268 | 269 | default: 270 | printstr("Unknown Standard Interface Request: "); 271 | printhexln(sp.bRequest); 272 | printhexln(sp.bmRequestType.Type); 273 | printhexln(sp.bmRequestType.Recipient); 274 | printhexln(sp.bmRequestType.Recipient | (sp.bmRequestType.Type << 5)); 275 | break; 276 | } 277 | break; 278 | 279 | /* Recipient: Device */ 280 | case STANDARD_DEVICE_REQUEST: 281 | 282 | /* Standard Device requests (8) */ 283 | switch( sp.bRequest ) 284 | { 285 | 286 | /* Set Device Address: This is a unique set request. */ 287 | case SET_ADDRESS: 288 | 289 | /* Status stage: Send a zero length packet */ 290 | retVal = XUD_SetBuffer_ResetPid(ep0_in, buffer, 0, PIDn_DATA1); 291 | 292 | /* TODO We should wait until ACK is received for status stage before changing address */ 293 | //XUD_Sup_Delay(50000); 294 | { 295 | timer t; 296 | unsigned time; 297 | t :> time; 298 | t when timerafter(time+50000) :> void; 299 | } 300 | 301 | /* Set device address in XUD */ 302 | XUD_SetDevAddr(sp.wValue); 303 | 304 | break; 305 | 306 | 307 | /* TODO Check direction */ 308 | /* Standard request: SetConfiguration */ 309 | case SET_CONFIGURATION: 310 | 311 | g_config = sp.wValue; 312 | 313 | /* No data stage for this request, just do status stage */ 314 | retVal = XUD_DoSetRequestStatus(ep0_in, 0); 315 | break; 316 | 317 | case GET_CONFIGURATION: 318 | buffer[0] = g_config; 319 | retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 1, sp.wLength); 320 | break; 321 | 322 | /* Get Status request */ 323 | case GET_STATUS: 324 | 325 | buffer[0] = 0; // bus powered 326 | buffer[1] = 0; // remote wakeup not supported 327 | 328 | retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 2, sp.wLength); 329 | break; 330 | 331 | 332 | default: 333 | XUD_Error("Unknown device request"); 334 | break; 335 | 336 | } 337 | break; 338 | 339 | /* Receipient: Endpoint */ 340 | case STANDARD_ENDPOINT_REQUEST: 341 | 342 | /* Standard endpoint requests */ 343 | switch ( sp.bRequest ) 344 | { 345 | 346 | /* ClearFeature */ 347 | case CLEAR_FEATURE: 348 | 349 | switch ( sp.wValue ) 350 | { 351 | case ENDPOINT_HALT: 352 | 353 | /* Mark the endpoint status */ 354 | 355 | SetEndpointStatus(sp.wIndex, 0); 356 | 357 | /* No data stage for this request, just do status stage */ 358 | retVal = XUD_DoSetRequestStatus(ep0_in, 0); 359 | 360 | break; 361 | 362 | 363 | default: 364 | XUD_Error( "Unknown request in Endpoint ClearFeature" ); 365 | break; 366 | } 367 | break; /* B_REQ_CLRFEAR */ 368 | 369 | /* SetFeature */ 370 | case SET_FEATURE: 371 | 372 | switch( sp.wValue ) 373 | { 374 | case ENDPOINT_HALT: 375 | 376 | /* Check request is in range */ 377 | SetEndpointStatus(sp.wIndex, 1); 378 | 379 | break; 380 | 381 | default: 382 | XUD_Error("Unknown feature in SetFeature Request"); 383 | break; 384 | } 385 | 386 | 387 | retVal = XUD_DoSetRequestStatus(ep0_in, 0); 388 | 389 | break; 390 | 391 | 392 | 393 | /* Endpoint GetStatus Request */ 394 | case GET_STATUS: 395 | 396 | buffer[0] = 0; 397 | buffer[1] = 0; 398 | 399 | if( sp.wIndex & 0x80 ) 400 | { 401 | /* IN Endpoint */ 402 | if((sp.wIndex&0x7f) < NUM_EP_IN) 403 | { 404 | buffer[0] = ( g_epStatusIn[ sp.wIndex & 0x7F ] & 0xff ); 405 | buffer[1] = ( g_epStatusIn[ sp.wIndex & 0x7F ] >> 8 ); 406 | } 407 | } 408 | else 409 | { 410 | /* OUT Endpoint */ 411 | if(sp.wIndex < NUM_EP_OUT) 412 | { 413 | buffer[0] = ( g_epStatusOut[ sp.wIndex ] & 0xff ); 414 | buffer[1] = ( g_epStatusOut[ sp.wIndex ] >> 8 ); 415 | } 416 | } 417 | 418 | retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 2, sp.wLength); 419 | 420 | break; 421 | 422 | default: 423 | //printstrln("Unknown Standard Endpoint Request"); 424 | break; 425 | 426 | } 427 | break; 428 | 429 | case CLASS_INTERFACE_REQUEST: 430 | case CLASS_ENDPOINT_REQUEST: 431 | { 432 | unsigned interfaceNum = sp.wIndex & 0xff; 433 | unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5); 434 | 435 | retVal = AudioClassRequests_2(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl); 436 | 437 | } 438 | break; 439 | 440 | case VENDOR_DEVICE_REQUEST: { 441 | retVal = VendorRequests(ep0_out, ep0_in, sp, c_dsp_ctl); 442 | break; 443 | } 444 | 445 | default: 446 | //printstr("unrecognised request\n"); 447 | //printhexln(sp.bRequest); 448 | //printhexln(sp.bmRequestType.Type); 449 | //printhexln(sp.bmRequestType.Recipient); 450 | //printhexln(sp.bmRequestType.Recipient | (sp.bmRequestType.Type << 5)); 451 | break; 452 | 453 | 454 | } 455 | 456 | } /* if(retVal == 0) */ 457 | 458 | if(retVal == 1) 459 | { 460 | /* Did not handle request - Protocol Stall Secion 8.4.5 of USB 2.0 spec 461 | * Detailed in Section 8.5.3. Protocol stall is unique to control pipes. 462 | Protocol stall differs from functional stall in meaning and duration. 463 | A protocol STALL is returned during the Data or Status stage of a control 464 | transfer, and the STALL condition terminates at the beginning of the 465 | next control transfer (Setup). The remainder of this section refers to 466 | the general case of a functional stall */ 467 | 468 | dprintf("Stall\n"); 469 | XUD_SetStall_Out(0); 470 | XUD_SetStall_In(0); 471 | } 472 | 473 | if (retVal < 0) 474 | { 475 | g_curUsbSpeed = XUD_ResetEndpoint(ep0_in, ep0_out); 476 | 477 | g_config = 0; 478 | } 479 | } 480 | } 481 | --------------------------------------------------------------------------------