sw_usb_audio: USB Audio reference designs£££doc/rst/sw_usb_audio.html#sw-usb-audio-usb-audio-reference-designs

The XMOS USB Audio solution provides USB Audio Class compliant devices over USB 2.0 (high-speed or full-speed). Based on the XMOS xcore-200 (XS2) and xcore.ai (XS3) architectures, it supports USB Audio Class 2.0 and USB Audio Class 1.0, asynchronous mode (synchronous as an option) and sample rates up to 384kHz.

The complete source code, together with the free XMOS XTC development tools and xcore multi-core micro-controller devices, allow the developer to select the exact mix of interfaces and processing required.

The XMOS USB Audio solution is deployed as a framework (see lib_xua) with reference design applications extending and customising this framework. These reference designs have particular qualified feature sets and an accompanying reference hardware platform.

This software user guide assumes the reader is familiar with the XC language and xcore devices. For more information see XMOS Programming Guide.

The reader should also familiarise themselves with the XMOS USB device library (lib_xud) and the XMOS USB audio library (lib_xua)

Note

The reader should always refer to the supplied CHANGELOG and README files for known issues relating to a specific release

sw_usb_audio: USB Audio reference designs$$$Overview£££doc/rst/overview.html#overview

Functionality

Provides USB interface to audio I/O.

Supported Standards

USB

USB 2.0 (Full-speed and High-speed)

USB Audio Class 1.0

USB Audio Class 2.0

USB Firmware Upgrade (DFU) 1.1

USB MIDI Device Class 1.0

Audio

I²S/TDM

S/PDIF (receive may be limited to 96kHz depending on external hardware)

ADAT

Direct Stream Digital (DSD)

PDM Microphones

MIDI

Supported sample frequencies

16kHz to 384kHz [1]

Supported devices

XMOS Devices

xcore-200 Series

xcore.ai Series

Requirements

Development Tools

XTC Development Tools (see readme for required version)

USB

xcore device with integrated USB phy

Audio

External audio DAC/ADC/CODECs (and required supporting componentry) supporting I²S/TDM

Boot/Storage

Compatible SPI/QSPI Flash device (or xcore device with internal flash)

Licensing

Reference code provided without charge under license from XMOS.

Footnotes

sw_usb_audio: USB Audio reference designs$$$USB Audio hardware platforms£££doc/rst/hw.html#usb-audio-hardware-platforms

This section describes the hardware development platforms supported by the XMOS USB Audio reference design software.

Board

xcore device

Analog channels

Digital Rx/Tx & MIDI

XK_EVK_XU316

xcore.ai

2 in + 2 out

N/A

XK_AUDIO_316_MC_AB

xcore.ai

8 in + 8 out

Supported

XK_AUDIO_216_MC_AB

xcore-200

8 in + 8 out

Supported

Each of the platforms supported has a Board Support Package (BSP), the code for which can be be found in lib_board_support. The code in lib_board_support abstracts away all of the hardware setup including enabling external hardware blocks and DAC and ADC configuration and provides a translation layer from the common API supported by lib_xua for initialising and configuring hardware on a sample rate or stream format change.

Detailed feature sets for the each of the supported boards can be found in the documentation for lib_board_support.

sw_usb_audio: USB Audio reference designs$$$Driver support£££doc/rst/drivers.html#driver-support

The XMOS USB Audio Reference design includes support for USB Audio Class (UAC) versions 1.0 and 2.0. UAC 2.0 includes support for audio over high-speed USB (UAC 1.0 supports full-speed only) and other feature additions.

sw_usb_audio: USB Audio reference designs$$$Driver support$$$OS support for UAC 1.0£££doc/rst/drivers.html#os-support-for-uac-1-0

Support for USB Audio Class 1.0 has been included in macOS and Windows for a number of years. Most Linux distributions also include support.

sw_usb_audio: USB Audio reference designs$$$Driver support$$$OS support for UAC 2.0£££doc/rst/drivers.html#os-support-for-uac-2-0

Support for USB Audio Class 2.0 is only included in more modern versions of macOS and Windows:

  • Since version 10.6.4 macOS natively supports USB Audio Class 2.0

  • Since version 10, release 1809, Windows natively supports USB Audio Class 2.0

sw_usb_audio: USB Audio reference designs$$$Driver support$$$Third party Windows drivers£££doc/rst/drivers.html#third-party-windows-drivers

For some products it may be desirable to use a third-party driver for Windows. A number of reasons exist as to why this may be desirable:

  • In order to support UAC 2.0 on Windows versions earlier than 10

  • The built-in Windows support is typically designed for consumer audio devices, not for professional audio devices

  • The built in drivers support sound APIs such as WASAPI, DirectSound, MME, but not ASIO.

The XMOS USB Audio Reference design is tested against Thesycon USB Audio Driver for Windows. This includes the following feature-set/benefits:

  • Available for Windows 10 and Windows 11 operating systems

  • Designed for professional audio devices and consumer-style devices

  • Supports ASIO for transparent and low-latency audio streaming

  • Supports Windows sound APIs such as WASAPI, DirectSound, MME

  • Supports high-end audio features such as bit-perfect PCM up to 768 kHz sampling rate, native DSD format (through ASIO) up to DSD1024

  • Supports multiple clock sources such as S/PDIF, ADAT or WCLK inputs

  • Supports MIDI 1.0 class, including MIDI port sharing

  • Supports DFU (Device Firmware Upgrade) and comes with a GUI utility for firmware update

  • Provides a private API for driver control and direct device communication (SDK available)

  • Comes with a control panel application for driver status/control

  • Optionally supports virtual channels (channels available at ASIO and Windows APIs but not implemented in the device)

  • Optionally supports mixing and/or signal processing plugin in the kernel-mode driver

  • Fully supports driver signing, branding and customization including driver installer (Customization will be done by Thesycon)

  • Technical support and maintenance provided by Thesycon

  • Custom features available on request

Note

Many of the benefits listed above apply to both UAC1.0 and UAC2.0 and the Thesycon Driver supports both class versions.

sw_usb_audio: USB Audio reference designs$$$Quick start£££doc/rst/quick.html#quick-start

Warning

XMOS development boards are typically supplied with no firmware pre-programmed.

The following steps explain how to programmed the latest firmware on the board and use it. Each step is explained in detail in the following sections.

  1. Download the latest USB Audio 2.0 Device software release from the XMOS website USB & Multichannel Audio page, using the DOWNLOAD SOFTWARE link.

    • Before downloading the software, review the licence and click Accept to initiate the download.

    (Section USB Audio 2.0 reference software.)

  2. If using a Windows host computer, download the USB Audio Class 2.0 Evaluation Driver for Windows.

    (Section USB Audio Class 2.0 evaluation driver for Windows.)

  3. Download and install the the XMOS XTC Tools

    • The minimum required XTC Tools version for compiling USB Audio applications can be found in the README. Make sure to download the correct version of the tools.

    (Section XMOS XTC development tools)

  4. Compile the firmware relavant to the available reference hardware platform .

    (Section: Building the firmware)

  5. Connect the board to the development system using (using the supplied xTAG if required), and program the firmware onto the board.

    (Section Running the firmware)

  6. Connect audio input and output devices, and play audio.

    (Section Playing audio)

sw_usb_audio: USB Audio reference designs$$$Quick start$$$USB Audio 2.0 reference software£££doc/rst/quick.html#usb-audio-2-0-reference-software

The latest USB Audio 2.0 Reference Design software is available free of charge from XMOS.

When downloading the software for the first time, the user needs to register at http://www.xmos.com/.

To download the firmware:

  1. On the XMOS website USB & Multichannel Audio page, follow the DOWNLOAD SOFTWARE link

  2. Review the licence agreement and click Accept.

  3. Download and save the software when prompted.

The software is distributed as a zip archive containing pre-compiled binaries and source code that can be built using the XMOS XTC Tools.

Alternatively, contact a local sales representative for further details:

sw_usb_audio: USB Audio reference designs$$$Quick start$$$USB Audio Class 2.0 evaluation driver for Windows£££doc/rst/quick.html#usb-audio-class-2-0-evaluation-driver-for-windows

Note

Since version 10.6.4, macOS natively supports USB Audio Class 2.0 – no driver install is required.

Note

Since version 10, release 1703, Windows natively supports USB Audio Class 2.0 – no driver install is required.

Earlier Window versions only provides support for USB Audio Class 1.0. To use a USB Audio Class 2.0 device under these Windows versions requires a third party driver.

Developers may also wish to use a third party driver for reasons including:

  • ASIO support

  • Advanced clocking options and controls

  • Improved latency

  • Native DSD (via ASIO)

  • Branding customisation and custom control panels

  • Large channel count devices

  • Etc

XMOS therefore provides a free Windows USB Audio driver for evaluation and prototyping and a path to a more feature-rich multichannel production driver from our partner Thesycon.

The evaluation driver is available from the XMOS website:

Further information about the evaluation and production drivers is available in the USB Audio Class 2.0 Windows Driver Overview document available on the website:

sw_usb_audio: USB Audio reference designs$$$Quick start$$$XMOS XTC development tools£££doc/rst/quick.html#xmos-xtc-development-tools

The XMOS XTC tools provide everything required to develop applications for xcore multicore microcontrollers and can be downloaded, free of charge, from XMOS XTC tools. Installation instructions can be found here. Be sure to pay attention to the section Installation of required third-party tools.

The XMOS XTC tools make it easy to define real-time tasks as a parallel system. They come with standards compliant C and C++ compilers, language libraries, simulator, symbolic debugger, and runtime instrumentation and trace libraries. Multicore support offers features for task based parallelism and communication, accurate timing and I/O, and safe memory management. All components work off the real-time multicore functionality, giving a fully integrated approach.

The XTC tools are required by anyone developing or deploying applications on an xcore processor. The tools include:

  • “Tile-level” toolchain (Compiler, assembler, etc)

  • System libraries

  • “Network-level” tools (Multi-tile mapper etc)

  • XSIM simulator

  • XGDB debugger

  • Deployment tools

The tools as delivered are to be used within a command line environment, though may also be integrated with VS Code graphical code editor.

Warning

USB Audio applications are compiled using the XCommon CMake build system. The minimum XTC tools version that supports XCommon CMake can be found in the README file. Ensure that the firmware is compiled using the correct XTC Tools version.

sw_usb_audio: USB Audio reference designs$$$Quick start$$$Building the firmware£££doc/rst/quick.html#building-the-firmware

Note

For convenience the release zips provided from XMOS contain precompiled binary (xe) files.

From a command prompt with the XMOS tools available, follow these steps:

  1. Unzip the package zip to a known location

  2. From the relevant application directory (e.g. app_usb_aud_xk_audio_316_mc), execute the commands:

    cmake -G "Unix Makefiles" -B build
    xmake -C build
    

The above steps will configure and build all of the available and supported build configurations for the application.

The applications are compiled using XCommon CMake which is a CMake based build system. The primary configuration file for the application is the CMakeLists.txt. It is present in the application directory (e.g. app_usb_aud_xk_audio_316_mc). This file specifies build configs, sources, build options and dependencies.

Note

See Build system for more details.

sw_usb_audio: USB Audio reference designs$$$Quick start$$$Running the firmware£££doc/rst/quick.html#running-the-firmware

Typically during development the developer wishes to program the device’s internal RAM with the application binary directly via JTAG and then execute this application.

To run one of the compiled binaries complete the following steps:

  1. Connect the USB Audio board to the host computer.

  2. Connect the xTAG to the USB Audio board and connect it to the host machine on which the application binary is present via a separate USB cable.

    note, some boards have integrated xTAGs.

  3. Ensure any required external power jacks are connected

Finally, to run the binary on the target, execute a command similar to the following:

xrun path/to/binary.xe

The device should now present itself as a USB Audio Device on the connected host computer. It will continue to operate as a USB Audio Device until the target board is power cycled.

sw_usb_audio: USB Audio reference designs$$$Quick start$$$Writing the application binary to flash£££doc/rst/quick.html#writing-the-application-binary-to-flash

Optionally a binary can be programmed into the boot flash. To do this:

  1. Connect the USB Audio board to the host computer.

  2. Connect the xTAG to the USB Audio board and connect the it to the host machine on which the application binary is present via a separate USB cable

  3. Ensure any required external power jacks are connected

From a command prompt with the XMOS tools available, run the following command:

xflash path/to/binary.xe

Once flashed the target device will reboot and execute the binary. Power cycling the target board will cause the device to reboot the flashed binary.

sw_usb_audio: USB Audio reference designs$$$Quick start$$$Playing audio£££doc/rst/quick.html#playing-audio

  1. Connect the board to any power supply provided (note, some boards will be USB bus powered)

  2. Connect the board to a host with driver support for USB Audio Class using a USB cable

  3. Install the Windows USB Audio 2.0 demonstration driver, if required.

  4. Connect audio input/output devices to the connectors on the board e.g powered speakers

  5. In the audio application, select the XMOS USB Audio device.

  6. Start playing and recording.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide£££doc/rst/programming.html#usb-audio-programming-guide

The following sections provide a guide on how to program the USB Audio applications including information on project structure, build configurations and creating custom USB audio applications.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Project structure£££doc/rst/prog_proj_structure.html#project-structure

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Project structure$$$Build system£££doc/rst/prog_proj_structure.html#build-system

The XMOS USB Audio Reference Design software and associated libraries employ the XCommon CMake build system. The XCommon CMake build system uses CMake to configure and generate the build environment which can then be built using xmake. As part of configuring the build environment, if there are any missing dependencies, XCommon CMake fetches them using git.

Note

All required dependencies are included in the sw_usb_audio zip download.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Project structure$$$Applications and libraries£££doc/rst/prog_proj_structure.html#applications-and-libraries

The sw_usb_audio GIT repository includes multiple application directories. Each application directory contains a CMakeLists.txt file which describes the build configs for that application. The format of the CMakeLists.txt is described here XCommon CMake uses the CMakeLists.txt to generate Makefiles that can be compiled using xmake into executables. Typically, there’s one application directory per hardware platform. Applications and their respective hardware platforms are listed in Table 1.

USB Audio Reference Applications

Application

Hardware platform

app_usb_aud_xk_316_mc

xcore.ai USB Audio 2.0 Multi-channel Audio Board

app_usb_aud_xk_216_mc

xcore-200 USB Audio 2.0 Multi-channel Audio Board

app_usb_aud_xk_evk_xu316

xcore.ai Evaluation Kit

The applications depend on several modules (or libraries), each of which have their own GIT repository. The immediate dependency libraries for the applications are specified by setting the APP_DEPENDENT_MODULES variable in the deps.cmake file. deps.cmake lists the common dependencies for all the applications and is included in each application’s CMakeLists.txt.

The dependency list specified in the deps.cmake can be extended to add new dependencies. Refer to the XCommon CMake Dependency Format documentation for more information about adding dependencies.

A shared file containing common dependencies ensures a consistent set of dependencies between all of the applications.

Each library has a lib_build_info.cmake which lists the library source, compile flags and dependencies. The library dependencies are specified in the LIB_DEPENDENT_MODULES variable in the lib_build_info.cmake. This allows dependency trees and nesting. XCommon CMake builds up a tree which is traversed depth-first, and populates the sandbox, fetching any missing dependencies by cloning them from github.

Most of the core code is contained in the XMOS USB Audio Library (lib_xua). A full list of core dependencies is shown in Table 2.

Core dependencies of USB Audio

Library

Description

lib_xua

Common code for USB audio applications

lib_xud

Low level USB device library

lib_spdif

S/PDIF transmit and receive code

lib_adat

ADAT transmit and receive code

lib_mic_array

PDM microphone interface and decimator

lib_xassert

Lightweight assertions library

Note

Some of these core dependencies will have their own dependencies, for example lib_mic_array depnds on lib_xassert (see above), lib_logging (a lightweight print library) and lib_xcore_math (a DSP library).

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Build configurations£££doc/rst/prog_build_configs.html#build-configurations

Due to the flexibility of the reference design software there are a large number of build options. For example input and output channel counts, Audio Class version, interface types etc. A “build configuration” is a set of build options that combine to produce a binary with a certain feature set.

The build configurations are listed in the application CMakeLists.txt file. The build config names are appended to the APP_COMPILER_FLAGS variable to list the options for the compiler to use when compiling all source files for the given build configuration (APP_COMPILER_FLAGS_<build config>). For example:

set(APP_COMPILER_FLAGS_2AMi10o10xssxxx ${SW_USB_AUDIO_FLAGS}
                                        -DXUA_SPDIF_TX_EN=1
                                        -DXUA_SPDIF_RX_EN=1)

specifies that the compiler flags used when compiling the 2AMi10o10xssxxx build config are everything defined in the SW_USB_AUDIO_FLAGS variable plus two extra compiler options for enabling S/PDIF transmit and receive.

To configure the build configurations, run the cmake command from the application (e.g. app_usb_aud_xk_audio_316_mc) directory:

cmake -G "Unix Makefiles" -B build

This will create a directory called build within the application directory. The output displayed on stdout for the cmake command will contain the list of all the build configurations for that application. For example,

-- Configuring application: app_usb_aud_xk_evk_xu316
-- Found build configs:
-- 1AMi2o2xxxxxx
-- 2AMi2o2xxxxxx

The cmake command generates the Makefile for compiling the different build configurations. The Makefile is created in the build directory.

The next step is to run the xmake command which executes the commands in the Makefile to build the executables corresponding to the build configs. To build all supported configurations for a given application, from the application directory (e.g. app_usb_aud_xk_audio_316_mc), run:

xmake -C build

This will run the xmake command in the build directory. The built executables are stored in the <app name>/bin/<config name> directories. For example, the app_usb_aud_xk_316_mc/bin/2AMi8o8xxxxxx directory contains the app_usb_aud_xk_316_mc_2ASi8o8xxxxxx.xe executable. Note how the name of the executable is set to <app_name>_<config_name>.xe:

<app name>/bin/<config name>/<app_name>_<config_name>.xe

To build a specific build configuration, after running the cmake command, run xmake with the build config specified:

xmake -C build <build config>

For example:

xmake -C build 2AMi10o10xssxxx

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Configuration naming£££doc/rst/prog_build_configs.html#configuration-naming

A naming scheme is employed in each application to link features to a build configuration/binary. Depending on the hardware interfaces available variations of the same basic scheme are used.

Each relevant build option is assigned a position in the configuration name, with a character denoting the options value (normally ‘x’ is used to denote “off” or “disabled”)

Some example build options are listed in Table 3.

Example build options and naming

Build Option Name

Options

Denoted by

Audio Class Version

1 or 2

1 or 2

USB synchronisation type

Asynchronous or Synchronous

A or S

Device I2S role

Master or Slave

M or S

USB IN channels

i<number>

USB OUT channels

i<number>

MIDI

on or off

m or x

S/PDIF Output

on or off

s or x

S/PDIF Input

on or off

s or x

ADAT Input

on or off

a or x

ADAT Output

on or off

a or x

DSD

on or off

d or x

For example, in this scheme, a configuration named 2AMi8o8msxxax would indicate Audio Class 2.0, USB asynchronous mode, xcore is I²S master, 8 USB IN channels, 8 USB OUT channels, MIDI enabled, S/PDIF input enabled, S/PDIF output disabled, ADAT input disabled, ADAT output enabled and DSD disabled.

See comments in the application CMakeLists.txt for details.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Quality & testing£££doc/rst/prog_build_configs.html#quality-testing

It is not practical for all build option permutations to be exhaustively tested. The XMOS USB Audio Reference Design software therefore defines three levels of quality:

  • Fully Tested - the configuration is fully supported. A product based on it can be immediately put into to a production environment with high confidence. Quality assurance (QA) should cover any customised code/functionality.

  • Partially Tested - the configuration is partially tested. A product based on it can be put into a production environment with medium confidence. Some additional QA is recommended.

  • Build Tested - the configuration is guaranteed to build but has not been tested. Full QA is required.

Note

Typically disabling a function should have no effect on QA. For example, disabling S/PDIF on a fully-tested configuration with it enabled should not affect its quality.

XMOS aims to provide fully tested configurations for popular device configurations and common customer requirements and use cases.

Note

It is advised that full QA is applied to any product regardless of the quality level of the configuration it is based on.

Fully tested configurations can be found in the application CMakeLists.txt. Partially and build tested configurations can be found in the configs_partial.cmake and configs_build.cmake files respectively.

Running cmake -G "Unix Makefiles" -B build will only configure the fully tested configurations and following this up with the xmake -C build command will build only these.

To configure and build the partially tested configs in addition to the fully tested ones, run cmake with the PARTIAL_TESTED_CONFIGS variable set to 1:

cmake -G "Unix Makefiles" -B build -DPARTIAL_TESTED_CONFIGS=1

Following this with the xmake -C build command will build both fully and partially tested configs.

Similarly to also build the build tested configs along with the fully tested ones, run cmake with BUILD_TESTED_CONFIGS set to 1, followed by the xmake command:

cmake -G "Unix Makefiles" -B build -DBUILD_TESTED_CONFIGS=1

Note that setting BUILD_TESTED_CONFIGS to 1 internally also set the PARTIAL_TESTED_CONFIGS to 1. So running cmake with BUILD_TESTED_CONFIGS set to 1 will configure the fully tested, partially tested and build-only configs and following this up with an xmake -C build will build all the 3 types of configs.

Note

Pre-release (i.e. alpha, beta or RC) firmware should not be used as basis for a production device and may not be representative of the final release firmware. Additionally, some releases may include features of lesser quality level. For example a beta release may contain a feature still at alpha level quality. See application README for details of any such features.

Note

Due to the similarities between the xcore-200 and xcore.ai series feature sets, it is fully expected that all listed xcore-200 series configurations will operate as expected on the xcore.ai series and vice versa. It is therefore expected that a quality level of a configuration will migrate between XMOS device series.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$A typical USB Audio application£££doc/rst/prog_app_tutorial.html#a-typical-usb-audio-application

This section provides a walk through of a typical USB Audio application. Where specific examples are required, code is used from the application for XK-AUDIO-316-MC (app_usb_aud_xk_316_mc).

Note

The applications in sw_usb_audio use the “Codeless Programming Model” as documented in lib_xua. Briefly, the main() function is used from lib_xua with build-time defines in the application configuring the framework provided by lib_xua. Various functions from lib_xua are then overridden to provide customisation. See lib_xua for full details.

Each application directory contains:

  1. A CMakeLists.txt

  2. A src directory

The src directory is arranged into two directories:

  1. A core directory containing source items that must be made available to the USB Audio framework i.e. lib_xua.

  2. An extensions directory that includes extensions to the framework such as external device configuration etc

The core folder for each application contains:

  1. A .xn file to describe the hardware platform the application will run on

  2. An optional header file to customise the framework provided by lib_xua named xua_conf.h

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$A typical USB Audio application$$$lib_xua configuration£££doc/rst/prog_app_tutorial.html#lib-xua-configuration

The xua_conf.h file contains all the build-time #defines required to tailor the framework provided by lib_xua to the particular application at hand. Typically these override default values in xua_conf_default.h in lib_xua/api.

Firstly in app_usb_aud_xk_316_mc the xua_conf.h file sets defines to determine overall capability. For this application most of the optional interfaces are disabled by default. This is because the applications provide a large number build configurations in the CMakeLists.txt enabling various interfaces. For a product with a fixed specification this almost certainly would not be the case and setting in this file may be the preferred option.

Note that ifndef is used to check that the option is not already defined in the CMakeLists.txt.

/* Enable/Disable MIDI - Default is MIDI off */
#ifndef MIDI
#define MIDI               (0)
#endif

/* Enable/Disable S/PDIF output - Default is S/PDIF off */
#ifndef XUA_SPDIF_TX_EN
#define XUA_SPDIF_TX_EN    (0)
#endif

/* Enable/Disable S/PDIF input - Default is S/PDIF off */
#ifndef XUA_SPDIF_RX_EN
#define XUA_SPDIF_RX_EN    (0)
#endif

/* Enable/Disable ADAT output - Default is ADAT off */
#ifndef XUA_ADAT_TX_EN
#define XUA_ADAT_TX_EN     (0)
#endif

/* Enable/Disable ADAT input - Default is ADAT off */
#ifndef XUA_ADAT_RX_EN
#define XUA_ADAT_RX_EN     (0)
#endif

/* Enable/Disable Mixing core(s) - Default is on */
#ifndef MIXER
#define MIXER              (1)
#endif

/* Set the number of mixes to perform - Default is 0 i.e mixing disabled */
#ifndef MAX_MIX_COUNT
#define MAX_MIX_COUNT      (0)
#endif

/* Audio Class version - Default is 2.0 */
#ifndef AUDIO_CLASS
#define AUDIO_CLASS        (2)
#endif

Next, the file defines properties of the audio channels including counts and arrangements. By default the application provides 8 analogue channels for input and output.

The total number of channels exposed to the USB host (set via NUM_USB_CHAN_OUT and NUM_USB_CHAN_IN) are calculated based on the audio interfaces enabled. Again, this is due to the multiple build configurations in the application CMakeLists.txt and likely to be hard-coded for a product.

/* Number of I2S channels to DACs*/
#ifndef I2S_CHANS_DAC
#define I2S_CHANS_DAC      (8)
#endif

/* Number of I2S channels from ADCs */
#ifndef I2S_CHANS_ADC
#define I2S_CHANS_ADC      (8)
#endif

/* Number of USB streaming channels - by default calculate by counting audio interfaces */
#ifndef NUM_USB_CHAN_IN
#define NUM_USB_CHAN_IN    (I2S_CHANS_ADC + 2*XUA_SPDIF_RX_EN + 8*XUA_ADAT_RX_EN)  /* Device to Host */
#endif

#ifndef NUM_USB_CHAN_OUT
#define NUM_USB_CHAN_OUT   (I2S_CHANS_DAC + 2*XUA_SPDIF_TX_EN + 8*XUA_ADAT_TX_EN)  /* Host to Device */
#endif

/*** Defines relating to channel arrangement/indices ***/

Channel indices/offsets are set based on the audio interfaces enabled. Channels are indexed from 0. Setting SPDIF_TX_INDEX to 0 would cause the S/PDIF channels to duplicate analogue channels 0 and 1. Note, the offset for analogue channels is always 0.

/* Channel index of S/PDIF Tx channels: separate channels after analogue channels (if they fit) */
#ifndef SPDIF_TX_INDEX
    #if (I2S_CHANS_DAC + 2*XUA_SPDIF_TX_EN) <= NUM_USB_CHAN_OUT
        #define SPDIF_TX_INDEX   (I2S_CHANS_DAC)
    #else
        #define SPDIF_TX_INDEX   (0)
    #endif
#endif

/* Channel index of S/PDIF Rx channels: separate channels after analogue channels */
#ifndef SPDIF_RX_INDEX
#define SPDIF_RX_INDEX     (I2S_CHANS_ADC)
#endif

/* Channel index of ADAT Tx channels: separate channels after S/PDIF channels (if they fit) */
#ifndef ADAT_TX_INDEX
    #define ADAT_TX_INDEX    (I2S_CHANS_DAC + 2*XUA_SPDIF_TX_EN)
#endif

/* Channel index of ADAT Rx channels: separate channels after S/PDIF channels */
#ifndef ADAT_RX_INDEX
#define ADAT_RX_INDEX      (I2S_CHANS_ADC + 2*XUA_SPDIF_RX_EN)
#endif

The file then sets some frequency related defines for the audio master clocks and the maximum sample-rate for the device.

/* Master clock defines (in Hz) */
#ifndef MCLK_441
#define MCLK_441           (512*44100)   /* 44.1, 88.2 etc */
#endif

#ifndef MCLK_48
#define MCLK_48            (512*48000)   /* 48, 96 etc */
#endif

/* Minumum sample frequency device runs at */
#ifndef MIN_FREQ
#define MIN_FREQ           (44100)
#endif

/* Maximum sample frequency device runs at */
#ifndef MAX_FREQ
#define MAX_FREQ           (192000)
#endif

Due to the multi-tile nature of the xcore architecture the framework needs to be informed as to which tile various interfaces should be placed on, for example USB, S/PDIF etc.

#define XUD_TILE           (0)
#define PLL_REF_TILE       (0)

#define AUDIO_IO_TILE      (1)
#define MIDI_TILE          (1)

The file also sets some defines for general USB IDs and strings. These are set for the XMOS reference design but vary per manufacturer:

#define VENDOR_ID          (0x20B1) /* XMOS VID */
#ifndef PID_AUDIO_2
#define PID_AUDIO_2        (0x0016)
#endif
#ifndef PID_AUDIO_1
#define PID_AUDIO_1        (0x0017)
#endif

#ifndef DFU_PID
#if (AUDIO_CLASS == 1)
#define DFU_PID             (0xD000 + PID_AUDIO_1)
#else
#define DFU_PID             (0xD000 + PID_AUDIO_2)
#endif
#endif

#define PRODUCT_STR_A2     "XMOS xCORE.ai MC (UAC2.0)"
#define PRODUCT_STR_A1     "XMOS xCORE.ai MC (UAC1.0)"

For a full description of all the defines that can be set in xua_conf.h see Configuration defines.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$A typical USB Audio application$$$User functions£££doc/rst/prog_app_tutorial.html#user-functions

In addition to the xua_conf.h file, the application needs to provide implementations of some overridable user functions in lib_xua to provide custom functionality.

For app_usb_aud_xk_316_mc the implementations can be found in src/extensions/audiohw.xc and src/extensions/audiostream.xc

The two functions it overrides in audiohw.xc are AudioHwInit() and AudioHwConfig(). These are run from lib_xua on startup and sample-rate change respectively. Note, the default implementations in lib_xua are empty. These functions have parameters for sample frequency, sample depth, etc.

In the case of app_usb_aud_xk_316_mc these functions configure the external DACs and ADCs via an I²C bus and configure the xcore secondary PLL to generate the required master clock frequencies.

Due to the complexity of the hardware on the XK-AUDIO-316-MC the source code is not included here.

The application also overrides UserAudioStreamStart() and UserAudioStreamStop(). These are called from lib_xua when the audio stream to the device is started or stopped respectively. The application uses these functions to enable/disable the on board LEDs based on whether an audio stream is active (input or output).

// Copyright 2022-2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <platform.h>

on tile[0]: out port p_leds = XS1_PORT_4F;

void UserAudioStreamStart(void)
{
    /* Turn all LEDs on */
    p_leds <: 0xF;
}

void UserAudioStreamStop(void)
{
    /* Turn all LEDs off */
    p_leds <: 0x0;
}

Note

A media player application may choose to keep an audio stream open and active and simply send zero data when paused.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$A typical USB Audio application$$$The main program£££doc/rst/prog_app_tutorial.html#the-main-program

The main() function is the entry point to an application. In the XMOS USB Audio Reference Design software it is shared by all applications and is therefore part of the framework.

This section is largely informational as most developers should not need to modify the main() function. main() is located in main.xc in lib_xua, this file contains:

  • A declaration of all the ports used in the framework. These clearly vary depending on the hardware platform the application is running on.

  • A main() function which declares some channels and then has a par statement which runs the required cores in parallel.

Full documentation can be found in lib_xua.

The first items in the par include running tasks for the Endpoint 0 implementaton and buffering tasks for audio and endpoint buffering:

            {
                unsigned x;
                thread_speed();

                /* Attach mclk count port to mclk clock-block (for feedback) */
                //set_port_clock(p_for_mclk_count, clk_audio_mclk);
#if(AUDIO_IO_TILE != XUD_TILE)
                set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb);
                set_port_clock(p_for_mclk_count, clk_audio_mclk_usb);
                start_clock(clk_audio_mclk_usb);
#else
                /* Clock port from same clock-block as I2S */
                /* TODO remove asm() */
                asm("ldw %0, dp[clk_audio_mclk]":"=r"(x));
                asm("setclk res[%0], %1"::"r"(p_for_mclk_count), "r"(x));
#endif
                /* Endpoint & audio buffering cores - buffers all EP's other than 0 */
                XUA_Buffer(
#if (NUM_USB_CHAN_OUT > 0)
                           c_xud_out[ENDPOINT_NUMBER_OUT_AUDIO],       /* Audio Out*/
#endif
#if (NUM_USB_CHAN_IN > 0)
                           c_xud_in[ENDPOINT_NUMBER_IN_AUDIO],         /* Audio In */
#endif
#if (NUM_USB_CHAN_OUT > 0) && ((NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP))
                           c_xud_in[ENDPOINT_NUMBER_IN_FEEDBACK],      /* Audio FB */
#endif
#ifdef MIDI
                           c_xud_out[ENDPOINT_NUMBER_OUT_MIDI],        /* MIDI Out */ // 2
                           c_xud_in[ENDPOINT_NUMBER_IN_MIDI],          /* MIDI In */  // 4
                           c_midi,
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
                           /* Audio Interrupt - only used for interrupts on external clock change */
                           c_xud_in[ENDPOINT_NUMBER_IN_INTERRUPT],
                           c_clk_int,
#endif
                           c_sof, c_aud_ctl, p_for_mclk_count
#if (XUA_HID_ENABLED)
                           , c_xud_in[ENDPOINT_NUMBER_IN_HID]
#endif
                           , c_mix_out
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
                           , c_audio_rate_change
    #if (!XUA_USE_SW_PLL)
                           , i_pll_ref
    #else
                           , c_sw_pll
    #endif
#endif
                    );
                //:
            }
#endif

            /* Endpoint 0 Core */
            {
                thread_speed();
                XUA_Endpoint0( c_xud_out[0], c_xud_in[0], c_aud_ctl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_);
            }

It also runs a task for the USB interfacing thread (XUD_Main()):

                XUD_Main(c_xud_out, ENDPOINT_COUNT_OUT, c_xud_in, ENDPOINT_COUNT_IN,

The specification of the channel arrays connecting to this driver are described in the documentation for lib_xud.

The channels connected to XUD_Main() are passed to the XUA_Buffer() function which implements audio buffering and also buffering for other Endpoints.

                XUA_Buffer(
#if (NUM_USB_CHAN_OUT > 0)
                           c_xud_out[ENDPOINT_NUMBER_OUT_AUDIO],       /* Audio Out*/
#endif
#if (NUM_USB_CHAN_IN > 0)
                           c_xud_in[ENDPOINT_NUMBER_IN_AUDIO],         /* Audio In */
#endif
#if (NUM_USB_CHAN_OUT > 0) && ((NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP))
                           c_xud_in[ENDPOINT_NUMBER_IN_FEEDBACK],      /* Audio FB */
#endif
#ifdef MIDI
                           c_xud_out[ENDPOINT_NUMBER_OUT_MIDI],        /* MIDI Out */ // 2
                           c_xud_in[ENDPOINT_NUMBER_IN_MIDI],          /* MIDI In */  // 4
                           c_midi,
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
                           /* Audio Interrupt - only used for interrupts on external clock change */
                           c_xud_in[ENDPOINT_NUMBER_IN_INTERRUPT],
                           c_clk_int,
#endif
                           c_sof, c_aud_ctl, p_for_mclk_count
#if (XUA_HID_ENABLED)
                           , c_xud_in[ENDPOINT_NUMBER_IN_HID]
#endif
                           , c_mix_out
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
                           , c_audio_rate_change
    #if (!XUA_USE_SW_PLL)
                           , i_pll_ref
    #else
                           , c_sw_pll
    #endif
#endif
                    );

A channel connects this buffering task to the audio driver which controls the I²S output. It also forwards and receives audio samples from other interfaces e.g. S/PDIF, ADAT, as required:

            usb_audio_io(
#if (NUM_USB_CHAN_OUT > 0) || (NUM_USB_CHAN_IN > 0)
                /* Connect audio system to XUA_Buffer(); */
                c_mix_out
#else
                /* Connect to XUA_Endpoint0() */
                c_aud_ctl
#endif
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
                , c_spdif_tx
#endif
#if (MIXER)
                , c_mix_ctl
#endif
                , c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
                , dfuInterface
#endif
#if (XUA_NUM_PDM_MICS > 0)
                , c_pdm_pcm
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
                , i_pll_ref
#endif
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
                , c_audio_rate_change
#endif
#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
                , p_for_mclk_count_audio
                , c_sw_pll
#endif
            );
        }

Finally, other tasks are created for various interfaces, for example, if MIDI is enabled a core is required to drive the MIDI input and output.

        on tile[MIDI_TILE]:
        {
            thread_speed();
            usb_midi(p_midi_rx, p_midi_tx, clk_midi, c_midi, 0);
        }

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Adding custom code£££doc/rst/prog_modification.html#adding-custom-code

The flexibility of the XMOS USB Audio Reference Design software is such that the reference applications can be modified to change the feature set or add extra functionality. Any part of the software can be altered since full source code is supplied.

Note

The reference designs have been verified against a variety of host operating systems at different samples rates. Modifications to the code may invalidate the results of this verification and fully retesting the resulting software is strongly recommended.

Note

Developers are encouraged to use a version control system, i.e. GIT, to track changes to the codebase, however, this is beyond the scope of this document.

The general steps to producing a custom codebase are as follows:

  1. Make a copy of the reference application directory (e.g. app_usb_aud_xk_316_mc or app_usb_aud_xk_216_mc) to a separate directory with a different name. Modify the new application to suit the custom requirements. For example:

    • Provide the .xn file for the target hardware platform by setting the APP_HW_TARGET in the application’s CMakeLists.txt.

    • Update xua_conf.h with specific defines for the custom application.

    • Add any other custom code in the files as needed.

    • Update the main.xc to add any custom tasks.

  2. Make a copy of any dependencies that require modification (in most cases, this step is unnecessary). Update the custom application’s CMakeLists.txt to use these new modules.

  3. After making appropriate changes to the code, rebuild and re-flash the device for testing.

Note

Whilst a developer may directly change the code in main.xc to add custom tasks this may not always be desirable. Doing this may make taking updates from XMOS non-trivial (the same can be said for any custom modifications to any core libraries). Since adding tasks is considered reasonably common, customisation defines USER_MAIN_CORES and USER_MAIN_DECLARATIONS are made available.

An example usage is shown in app_usb_aud_xk_316_mc/src/extensions/user_main.h In reality the developer must weigh up the inconvenience of using these defines versus the inconvenience of merging updates from XMOS into a modified codebase.

The following sections show some example changes with a high level overview of how to change the code.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Adding custom code$$$Example: Changing output format£££doc/rst/prog_modification.html#example-changing-output-format

Customising the digital output format may be required, for example, to support a CODEC that expects sample data right-justified with respect to the word clock.

To achieve this, alter the main audio driver loop in xua_audiohub.xc. After making the alteration, re-test the functionality to ensure proper operation.

Hint, a naive approach would simply include right-shifting the audio data by 7 bits before it is output to the port. This would of course lose LSB data depending on the sample-depth.

sw_usb_audio: USB Audio reference designs$$$USB Audio programming guide$$$Adding custom code$$$Example: Adding DSP to the output stream£££doc/rst/prog_modification.html#example-adding-dsp-to-the-output-stream

To add some DSP requires an extra thread of computation. Depending on the xcore device being used, some existing functionality might need to be disabled to free up a thread (e.g. disable S/PDIF). There are many ways that DSP processing can be added, the steps below outline one approach:

  1. Remove some functionality using the defines in Configuration defines to free up a thread as required.

  2. Add another thread to do the DSP. This core will probably have a single XC channel. This channel can be used to send and receive audio samples from the XUA_AudioHub() task. A benefit of modifying samples here is that samples from all inputs are collected into one place at this point. Optionally, a second channel could be used to accept control messages that affect the DSP. This could be from Endpoint 0 or some other task with user input - a thread handling button presses, for example.

  3. Implement the DSP in this thread. This needs to be synchronous (i.e. for every sample received from the XUA_AudioHub(), a sample needs to be output back).

sw_usb_audio: USB Audio reference designs$$$USB Audio applications£££doc/rst/apps.html#usb-audio-applications

The reference applications supplied in sw_usb_audio use the framework provided in lib_xua and provide qualified configurations of the framework which support, and are validated, on an accompanying reference hardware platform.

These reference design applications customise and extend this framework to provide the required functionality. This document will now examine in detail how each of the provided applications customise and extend the framework.

The applications contained in this repo use lib_xua in a “code-less” manner. That is, they use the main() function from lib_xua and customise the code-base as required using build time defines and by providing implementations to the various required functions in order to support their hardware.

Refer to lib_xua <https://www.xmos.com/file/lib_xua>`_ documentation for full details.

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore.ai Multi-Channel Audio Board£££doc/rst/app_316_mc.html#the-xcore-ai-multi-channel-audio-board

An application of the USB audio framework is provided specifically for the XK_AUDIO_316_MC hardware described in USB Audio hardware platforms and is implemented on an xcore.ai series dual tile device. The related code can be found in app_usb_aud_xk_316_mc.

The design supports upto 8 channels of analogue audio input/output at sample-rates up to 192 kHz (assuming the use of I²S). This can be further increased by utilising TDM. It also supports S/PDIF, ADAT and MIDI input and output as well as the mixing functionalty of lib_xua.

The design uses the following tasks:

  • XMOS USB Device Driver (XUD)

  • Endpoint 0

  • Endpoint Buffer

  • Decoupler

  • AudioHub Driver

  • Mixer

  • S/PDIF Transmitter

  • S/PDIF Receiver

  • ADAT Transmitter

  • ADAT Receiver

  • Clockgen

  • MIDI

The software layout of the USB Audio 2.0 Reference Design running on the xcore.ai device is shown in Fig. 1.

Each circle depicts a task running in a single core concurrently with the other tasks. The lines show the communication between each task.

../../_images/xk_316_system.png

xcore.ai multichannel audio system/task diagram

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore.ai Multi-Channel Audio Board$$$Audio hardware£££doc/rst/app_316_mc.html#audio-hardware

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore.ai Multi-Channel Audio Board$$$Audio hardware$$$Clocking and clock selection£££doc/rst/app_316_mc.html#clocking-and-clock-selection

As well as the secondary (application) PLL of the xcore.ai device the board includes two options for master clock generation:

  • A Cirrus Logic CS2100 fractional-N clock multiplier allowing the master clock to be generated from a xcore derived reference clock.

  • A Skyworks Si5351A-B-GT CMOS clock generator.

The master clock source is chosen by driving two control signals as shown below:

Control Signal

Master Clock Source

EXT_PLL_SEL

MCLK_DIR

0

0

Cirrus CS2100

1

0

Skyworks SI5351A-B-GT

X

1

xcore.ai secondary (application) PLL

Each of the sources have potential benefits, some of which are discussed below:

  • The Cirrus CS2100 simplifies generating a master clock locked to an external clock (such as S/PDIF in or word clock in).

    • It multiplies up the PLL_SYNC signal which is generated by the xcore.ai device based on the desired external source (so S/PDIF in frame signal or word clock in).

  • The Si5351A-B-GT offers very low jitter performance at a relatively lower cost than the CS2100. Locking to an external source is more difficult.

  • The xcore.ai secondary PLL is obviously the lowest cost and significantly lowest power solution, however its jitter performance can not match the Si5351A which may be important in demanding applications. Locking to an external clock is possible but involves more complicated firmware and more MIPS.

The master clock source is controlled by a mux which, in turn, is controlled by bit 5 of PORT 8C:

Master Clock Source Selection

Value

Source

0

Master clock is sourced from PhaseLink PLL

1

Master clock is source from Cirrus Clock Multiplier

The clock-select from the phaselink part is controlled via bit 7 of PORT 8C:

Master Clock Frequency Select

Value

Frequency

0

24.576MHz

1

22.579MHz

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore.ai Multi-Channel Audio Board$$$Audio hardware$$$DAC and ADC£££doc/rst/app_316_mc.html#dac-and-adc

The board is equipped with four PCM5122 stereo DACs from Texas instruments and two quad-channel PCM1865 ADCs from Texas Instruments, giving 8 channels of analogue output and 8 channels of analogue input. Configuration of both the DAC and the ADC takes place over I²C.

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore.ai Multi-Channel Audio Board$$$Configuring audio hardware£££doc/rst/app_316_mc.html#configuring-audio-hardware

All of the external audio hardware is configured using lib_board_support.

Note

lib_board_support has the I²C library (lib_i2c) in its dependency list.

The hardware targeted is the XMOS XU316 Multichannel Audio board (XK-AUDIO-316-MC). The lib_board_support functions xk_audio_316_mc_ab_board_setup(), xk_audio_316_mc_ab_i2c_master(), xk_audio_316_mc_ab_AudioHwInit() and xk_audio_316_mc_ab_AudioHwConfig() are called at various points during initialisation and runtime to start the I²C master, initialise and configure the audio hardware.

The audio hardware configuration is set in the config structure of type xk_audio_316_mc_ab_config_t which is passed to the xk_audio_316_mc_ab_board_setup(), xk_audio_316_mc_ab_AudioHwInit() and xk_audio_316_mc_ab_AudioHwConfig() functions.

static xk_audio_316_mc_ab_config_t config =
{
    // clk_mode
    (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
    ? ( XUA_USE_SW_PLL
        ? CLK_PLL : CLK_CS2100 )
    : CLK_FIXED,

    // dac_is_clk_master
    CODEC_MASTER,

    // default_mclk
    (DEFAULT_FREQ % 22050 == 0) ? MCLK_441 : MCLK_48,

    // pll_sync_freq
    PLL_SYNC_FREQ,

    // pcm_format
    XUA_PCM_FORMAT,

    // i2s_n_bits
    XUA_I2S_N_BITS,

    // i2s_chans_per_frame
    I2S_CHANS_PER_FRAME
};

xk_audio_316_mc_ab_board_setup() function is called from the wrapper function board_setup() as part of the application’s initialisation process. It performs the required port operations to enable the audio hardware on the platform.

xk_audio_316_mc_ab_i2c_master() function is called after board_setup() during initialisation and it starts the I²C master task. This is required to allow the audio hardware to be configured over I²C, remotely from the other tile, due to the IO arrangement of the XK-AUDIO-316-MC board.

#define USER_MAIN_CORES on tile[0]: {\
                                        board_setup();\
                                        xk_audio_316_mc_ab_i2c_master(i2c);\

The AudioHwInit() function is implemented to make a call to the lib_board_support function xk_audio_316_mc_ab_AudioHwInit() to power up and initialise the audio hardware ready for a configuration.

The AudioHwConfig() function configures the audio hardware post initialisation. It is typically called each time a sample rate or stream format change occurs. It is implmented to make a call to the lib_board_support function xk_audio_316_mc_ab_AudioHwConfig().

For further details on the hardware platform and the functions available for configuring it refer to lib_board_support documentation.

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore.ai Multi-Channel Audio Board$$$Validated build options£££doc/rst/app_316_mc.html#validated-build-options

The reference design can be built in several ways by changing the build options. These are described in Configuration defines.

The design has only been fully validated against the build options as set in the application as distributed in the CMakeLists.txt. See Build configurations for details and general information on build configuration naming scheme.

These fully validated build configurations are enumerated in the supplied CMakeLists.txt.

The build configuration naming scheme employed in the CMakeLists.txt is shown in Table 6.

Build config naming scheme

Feature

Option 1

Option 2

Audio Class

1

2

USB Sync Mode

async: A

sync: S

I²S Role

slave: S

master: M

Input

enabled: i (channel count)

disabled: x

Output

enabled: i (channel count)

disabled: x

MIDI

enabled: m

disabled: x

S/PDIF input

enabled: s

disabled: x

S/PDIF input

enabled: s

disabled: x

ADAT input

enabled: a

disabled: x

ADAT output

enabled: a

disabled: x

DSD output

enabled: d

disabled: x

e.g. A build configuration named 2AMi10o10xsxxxx would signify: Audio Class 2.0 running in asynchronous mode. The xcore is I²S master. Input and output enabled (10 channels each), no MIDI, S/PDIF input, no S/PDIF output, no ADAT or DSD.

In addition to this some terms may be appended onto a build configuration name to signify additional options. For example, tdm may be appended to the build configuration name to indicate the I²S mode employed.

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore-200 Multi-Channel Audio Board£££doc/rst/app_216_mc.html#the-xcore-200-multi-channel-audio-board

An application of the USB audio framework is provided specifically for the XK_AUDIO_216_MC_AB hardware described in USB Audio hardware platforms and is implemented on an xcore-200 series dual tile device. The related code can be found in app_usb_aud_xk_216_mc.

The design supports upto 8 channels of analogue audio input/output at sample-rates up to 192kHz (assuming the use of I²S). This can be further increased by utilising TDM. It also supports S/PDIF, ADAT and MIDI input and output as well as the mixing functionalty of lib_xua.

The design uses the following tasks:

  • XMOS USB Device Driver (XUD)

  • Endpoint 0

  • Endpoint Buffer

  • Decoupler

  • AudioHub Driver

  • Mixer

  • S/PDIF Transmitter

  • S/PDIF Receiver

  • ADAT Receiver

  • Clockgen

  • MIDI

The software layout of the USB Audio 2.0 Reference Design running on the xcore.ai device is shown in Fig. 2.

Each circle depicts a task running in a single core concurrently with the other tasks. The lines show the communication between each task.

../../_images/threads-l2-crop.png

xcore-200 Multichannel Audio system/task diagram

The app_usb_aud_xk_216_mc application uses the functions provided in lib_board_support for master clock generation and audio hardware configuration. The functions xk_audio_216_mc_ab_AudioHwInit() and xk_audio_216_mc_ab_AudioHwConfig() are called at various points during initialisation and runtime to initialise and configure the audio hardware.

For further details on the hardware platform and the functions available for configuring it refer to lib_board_support documentation.

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore-200 Multi-Channel Audio Board$$$Audio hardware£££doc/rst/app_216_mc.html#audio-hardware

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore-200 Multi-Channel Audio Board$$$Audio hardware$$$Clocking and Clock Selection£££doc/rst/app_216_mc.html#clocking-and-clock-selection

The board includes two options for master clock generation:

  • A single oscillator with a Phaselink PLL to generate fixed 24.576MHz and 22.5792MHz master-clocks.

  • A Cirrus Logic CS2100 clock multiplier allowing the master clock to be generated from a xcore derived reference clock.

The master clock source is controlled by a mux which, in turn, is controlled by bit 5 of PORT 8C:

Master Clock Source Selection

Value

Source

0

Master clock is sourced from PhaseLink PLL

1

Master clock is source from Cirrus Clock Multiplier

The clock-select from the phaselink part is controlled via bit 7 of PORT 8C:

Master Clock Frequency Select

Value

Frequency

0

24.576MHz

1

22.579MHz

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore-200 Multi-Channel Audio Board$$$Audio hardware$$$DAC and ADC£££doc/rst/app_216_mc.html#dac-and-adc

The board is equipped with a single multi-channel audio DAC (Cirrus Logic CS4384) and a single multi-channel ADC (Cirrus Logic CS5368) giving 8 channels of analogue output and 8 channels of analogue input. Configuration of both the DAC and the ADC takes place over I²C.

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore-200 Multi-Channel Audio Board$$$Configuring audio hardware£££doc/rst/app_216_mc.html#configuring-audio-hardware

All of the external audio hardware is configured using lib_board_support.

Note

lib_board_support has the I²C library (lib_i2c) in its dependency list.

The hardware targeted is the XMOS XU216 Multichannel Audio board (XK-AUDIO-216-MC). The functions xk_audio_216_mc_ab_AudioHwInit() and xk_audio_216_mc_ab_AudioHwConfig() are called at various points during initialisation and runtime to initialise and configure the audio hardware.

The audio hardware configuration is set in the config structure of type xk_audio_216_mc_ab_config_t which is passed to the xk_audio_216_mc_ab_AudioHwInit() and xk_audio_216_mc_ab_AudioHwConfig() functions.

static const xk_audio_216_mc_ab_config_t config = {
    // clk_mode
    CLK_MODE,

    // codec_is_clk_master
    CODEC_MASTER,

    // usb_sel
    (USB_SEL_A ? AUD_216_USB_A : AUD_216_USB_B),

    // pcm_format
    XUA_PCM_FORMAT,

    // pll_sync_freq
    PLL_SYNC_FREQ
};

The AudioHwInit() function is implemented to make a call to the lib_board_support function xk_audio_216_mc_ab_AudioHwInit() to power up and initialise the audio hardware ready for a configuration.

The AudioHwConfig() function configures the audio hardware post initialisation. It is called each time a sample rate or stream format change occurs. It is implemented to make a call to the lib_board_support function xk_audio_216_mc_ab_AudioHwConfig().

For further details on the hardware platform and the functions available for configuring it refer to lib_board_support documentation.

sw_usb_audio: USB Audio reference designs$$$USB Audio applications$$$The xcore-200 Multi-Channel Audio Board$$$Validated build options£££doc/rst/app_216_mc.html#validated-build-options

The reference design can be built in several ways by changing the build options. These are described in Configuration defines.

The design has only been fully validated against the build options as set in the application as distributed in the CMakeLists.txt. See Build configurations for details and general information on build configuation naming scheme.

These fully validated build configurations are enumerated in the supplied CMakeLists.txt.

In practise, due to the similarities between the xcore-200 and xcore.ai series feature set, it is fully expected that all listed xcore-200 series configurations will operate as expected on the xcore.ai series and vice versa.

The build configuration naming scheme employed in the CMakeLists.txt is shown in Table 9.

Build config naming scheme

Feature

Option 1

Option 2

Audio Class

1

2

USB Sync Mode

async: A

sync: S

I²S Role

slave: S

master: M

Input

enabled: i (channel count)

disabled: x

Output

enabled: i (channel count)

disabled: x

MIDI

enabled: m

disabled: x

S/PDIF input

enabled: s

disabled: x

S/PDIF input

enabled: s

disabled: x

ADAT input

enabled: a

disabled: x

ADAT output

enabled: a

disabled: x

DSD output

enabled: d

disabled: x

e.g. A build configuration named 2AMi10o10xsxxxx would signify: Audio class 2.0 running in asynchronous mode. The xcore is I²S master. Input and output enabled (10 channels each), no MIDI, S/PDIF input, no S/PDIF output, no ADAT or DSD.

In addition to this some terms may be appended onto a build configuration name to signify additional options. For example, tdm may be appended to the build configuration name to indicate the I²S mode employed.

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference£££doc/rst/api.html#usb-audio-api-reference

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines£££doc/rst/api_xua_conf.html#configuration-defines

An application using the USB audio framework provided by lib_xua needs to be configured via defines. Defaults for these defines are found in lib_xua in xua_conf_default.h.

An application should override these defines in an optional xua_conf.h file or in the CMakeLists.txt for the relevant build configuration.

This section documents commonly used defines, for full listings and documentation see the lib_xua.

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$Code location (tile)£££doc/rst/api_xua_conf.html#code-location-tile

AUDIO_IO_TILE

Location (tile) of audio I/O. Default: 0.

XUD_TILE

Location (tile) of audio I/O. Default: 0.

MIDI_TILE

Location (tile) of MIDI I/O. Default: AUDIO_IO_TILE.

PLL_REF_TILE

Location (tile) of reference signal to CS2100. Default: AUDIO_IO_TILE.

SPDIF_TX_TILE

Location (tile) of SPDIF Tx. Default: AUDIO_IO_TILE.

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$Channel counts£££doc/rst/api_xua_conf.html#channel-counts

NUM_USB_CHAN_OUT

Number of output channels (host to device). Default: NONE (Must be defined by app)

NUM_USB_CHAN_IN

Number of input channels (device to host). Default: NONE (Must be defined by app)

I2S_CHANS_DAC

Number of I2S channesl to DAC/CODEC. Must be a multiple of 2.

Default: NONE (Must be defined by app)

I2S_CHANS_ADC

Number of I2S channels from ADC/CODEC. Must be a multiple of 2.

Default: NONE (Must be defined by app)

DSD_CHANS_DAC

Number of DSD output channels.

Default: 0 (disabled)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$Frequencies and clocks£££doc/rst/api_xua_conf.html#frequencies-and-clocks

MAX_FREQ

Max supported sample frequency for device (Hz).

Default: 192000Hz

MIN_FREQ

Min supported sample frequency for device (Hz).

Default: 44100Hz

MCLK_441

Master clock defines for 44100 rates (in Hz).

Default: NONE (Must be defined by app)

MCLK_48

Master clock defines for 48000 rates (in Hz).

Default: NONE (Must be defined by app)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$Audio Class£££doc/rst/api_xua_conf.html#audio-class

AUDIO_CLASS

USB Audio Class Version.

Default: 2 (Audio Class version 2.0)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$System feature configuration£££doc/rst/api_xua_conf.html#system-feature-configuration

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$System feature configuration$$$MIDI£££doc/rst/api_xua_conf.html#midi
MIDI

Enable MIDI functionality including buffering, descriptors etc. Default: DISABLED.

MIDI_RX_PORT_WIDTH

MIDI Rx port width (1 or 4bit). Default: 1.

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$System feature configuration$$$S/PDIF£££doc/rst/api_xua_conf.html#s-pdif
XUA_SPDIF_TX_EN

Enables SPDIF Tx. Default: 0 (Disabled)

SPDIF_TX_INDEX

Defines which output channels (stereo) should be output on S/PDIF. Note, Output channels indexed from 0.

Default: 0 (i.e. channels 0 & 1)

XUA_SPDIF_RX_EN

Enables SPDIF Rx. Default: 0 (Disabled)

SPDIF_RX_INDEX

S/PDIF Rx first channel index, defines which channels S/PDIF will be input on. Note, indexed from 0.

Default: NONE (Must be defined by app when SPDIF_RX enabled)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$System feature configuration$$$ADAT£££doc/rst/api_xua_conf.html#adat
XUA_ADAT_TX_EN

Enables ADAT Tx. Default: 0 (Disabled)

ADAT_TX_INDEX

Defines which output channels (8) should be output on ADAT. Note, Output channels indexed from 0.

Default: 0 (i.e. channels [0:7])

XUA_ADAT_RX_EN

Enables ADAT Rx. Default: 0 (Disabled)

ADAT_RX_INDEX

ADAT Rx first channel index. defines which channels ADAT will be input on. Note, indexed from 0.

Default: NONE (Must be defined by app when XUA_ADAT_RX_EN is true)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$System feature configuration$$$PDM Microphones£££doc/rst/api_xua_conf.html#pdm-microphones
XUA_NUM_PDM_MICS

Number of PDM microphones in the design.

Default: 0

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$System feature configuration$$$DFU£££doc/rst/api_xua_conf.html#dfu
XUA_DFU_EN

Enable DFU functionality.

Default: 1 (Enabled)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$System feature configuration$$$HID£££doc/rst/api_xua_conf.html#hid
HID_CONTROLS

Enable HID playback controls functionality.

1 for enabled, 0 for disabled.

Default 0 (Disabled)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$System feature configuration$$$CODEC Interface£££doc/rst/api_xua_conf.html#codec-interface
CODEC_MASTER

Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks)

0: XMOS is I2S master. 1: CODEC is I2s master.

Default: 0 (XMOS is master)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$USB device configuration£££doc/rst/api_xua_conf.html#usb-device-configuration

VENDOR_STR

Vendor String used by the device. This is also pre-pended to various strings used by the design.

Default: “XMOS”

VENDOR_ID

USB Vendor ID (or VID) as assigned by the USB-IF.

Default: 0x20B1 (XMOS)

PRODUCT_STR

USB Product String for the device. If defined will be used for both PRODUCT_STR_A2 and PRODUCT_STR_A1.

Default: Undefined

PRODUCT_STR_A2

Product string for Audio Class 2.0 mode.

Default: “XMOS xCORE (UAC2.0)”

PRODUCT_STR_A1

Product string for Audio Class 1.0 mode.

Default: “XMOS xCORE (UAC1.0)”

PID_AUDIO_1

USB Product ID (PID) for Audio Class 1.0 mode. Only required if AUDIO_CLASS == 1 or AUDIO_CLASS_FALLBACK is enabled.

Default: 0x0003

PID_AUDIO_2

USB Product ID (PID) for Audio Class 2.0 mode.

Default: 0x0002

BCD_DEVICE

Device firmware version number in Binary Coded Decimal format: 0xJJMN where JJ: major, M: minor, N: sub-minor version number.

NOTE: User code should not modify this but should modify BCD_DEVICE_J, BCD_DEVICE_M, BCD_DEVICE_N instead

Default: XMOS USB Audio Release version (e.g. 0x0651 for 6.5.1).

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$Volume control£££doc/rst/api_xua_conf.html#volume-control

OUTPUT_VOLUME_CONTROL

Enable/disable output volume control including all processing and descriptor support.

Default: 1 (Enabled)

INPUT_VOLUME_CONTROL

Enable/disable input volume control including all processing and descriptor support.

Default: 1 (Enabled)

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$Mixing parameters£££doc/rst/api_xua_conf.html#mixing-parameters

MIXER

Enable “mixer” core.

Default: 0 (Disabled)

MAX_MIX_COUNT

Number of seperate mixes to perform.

Default: 8 if MIXER enabled, else 0

MIX_INPUTS

Number of channels input into the mixer.

Note, total number of mixer nodes is MIX_INPUTS * MAX_MIX_COUNT

Default: 18

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$Configuration defines$$$Power£££doc/rst/api_xua_conf.html#power

XUA_POWERMODE

Report as self or bus powered device. This affects descriptors and XUD usage and is important for USB compliance.

Default: XUA_POWERMODE_BUS

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$User function definitions£££doc/rst/api_user_functions.html#user-function-definitions

The following functions can be optionally defined by an application to override default (empty) implementations in lib_xua.

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$User function definitions$$$External audio hardware configuration£££doc/rst/api_user_functions.html#external-audio-hardware-configuration

The functions listed below should be implemented to configure external audio hardware.

void AudioHwInit(void)

User audio hardware initialisation code.

This function is called when the device starts up and should contain user code to perform any required audio hardware initialisation

void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)

User audio hardware configuration code.

This function is called when on sample rate change and should contain user code to configure audio hardware (clocking, CODECs etc) for a specific mClk/Sample frequency

Parameters:
  • samFreq – The new sample frequency (in Hz)

  • mClk – The new master clock frequency (in Hz)

  • dsdMode – DSD mode, DSD_MODE_NATIVE, DSD_MODE_DOP or DSD_MODE_OFF

  • sampRes_DAC – Playback sample resolution (in bits)

  • sampRes_ADC – Record sample resolution (in bits)

void AudioHwConfig_Mute(void)

User code mute audio hardware.

This function is called before AudioHwConfig() and should contain user code to mute audio hardware before a sample rate change in order to reduced audible pops/clicks

Note, if using the application PLL of a xcore.ai device this function will be called before the master-clock is changed

void AudioHwConfig_UnMute(void)

User code to un-mute audio hardware.

This function is called after AudioHwConfig() and should contain user code to un-mute audio hardware after a sample rate change

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$User function definitions$$$Audio streaming notification£££doc/rst/api_user_functions.html#audio-streaming-notification

The functions listed below can be useful for mute lines, indication LEDs etc.

void UserAudioStreamStart(void)

User stream start code.

User code to perform any actions required at every stream start - either input or output

void UserAudioStreamStop(void)

User stream stop code.

User code to perform any actions required on every stream stop - either input or output

void UserAudioInputStreamStart(void)

User input stream stop code.

User code to perform any actions required on input stream start i.e. device to host

void UserAudioInputStreamStop(void)

User input stream stop code.

User code to perform any actions required on input stream stop i.e. device to host

void UserAudioOutputStreamStart(void)

User output stream start code.

User code to perform any actions required on output stream start i.e. host to device

void UserAudioOutputStreamStop(void)

User output stream stop code.

User code to perfrom any actions required on output stream stop i.e. host to device

sw_usb_audio: USB Audio reference designs$$$USB Audio API reference$$$User function definitions$$$HID controls£££doc/rst/api_user_functions.html#hid-controls

The following function is called when the device wishes to read physical user input (buttons etc). The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used.

size_t UserHIDGetData(const unsigned id, unsigned char hidData[HID_MAX_DATA_BYTES])

Get the data for the next HID Report.

Parameters:
  • id[in] The HID Report ID (see 5.6, 6.2.2.7, 8.1 and 8.2 of the USB Device Class Definition for HID 1.11) Set to zero if the application provides only one HID Report which does not include a Report ID

  • hidData[out] The HID data If using Report IDs, this function places the Report ID in the first element; otherwise the first element holds the first byte of HID event data.

Return values:

Zero – means no new HID event data has been recorded for the given id

Returns:

The length of the HID Report in the hidData argument

sw_usb_audio: USB Audio reference designs$$$Frequently Asked Questions£££doc/rst/faq.html#frequently-asked-questions

Why does the USBView tool from Microsoft show errors in the devices descriptors?

The USBView tool supports USB Audio Class 1.0 only

How do I set the maximum sample rate of the device?

See MAX_FREQ define in Configuration defines

What is the maximum channel count the device can support?

The maximum channel count of a device is a function of sample-rate and sample-depth. A standard high-speed USB Isochronous endpoint can handle a 1024 byte packet every microframe (125uS).

It follows then that at 192 kHz the device/hosts expects 24 samples per frame (192000/8000). When using Asynchronous mode we must allow for +/- one sample, so 25 samples per microframe in this case.

Assuming 4 byte (32 bit) sample size, the bus expects ((192000/8000)+1) * 4 = 100 bytes per channel per microframe. Dividing the maximum packet size by this value yields the theoretical maximum channel count at the given frequency, that is 1024/100 = 10.24. Clearly this must be rounded down to 10 whole channels.