Very early cut of xua_lite app. Builds (4 threads + I2C) but not functional
This commit is contained in:
22
examples/xua_lite_example/Makefile
Normal file
22
examples/xua_lite_example/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
APP_NAME =
|
||||
|
||||
TARGET = RPI_HAT_60QFN.xn
|
||||
|
||||
# The flags passed to xcc when building the application
|
||||
XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report \
|
||||
-g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[0]
|
||||
|
||||
#-DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope
|
||||
|
||||
# The USED_MODULES variable lists other module used by the application. These
|
||||
# modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables.
|
||||
# Modules are expected to be in the directory above the BASE_DIR directory.
|
||||
USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_gpio
|
||||
|
||||
#=============================================================================
|
||||
# The following part of the Makefile includes the common build infrastructure
|
||||
# for compiling XMOS applications. You should not need to edit below here.
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
15
examples/xua_lite_example/src/AudioConfig.h
Executable file
15
examples/xua_lite_example/src/AudioConfig.h
Executable file
@@ -0,0 +1,15 @@
|
||||
#ifndef _AUDIO_CONFIG_
|
||||
#define _AUDIO_CONFIG_
|
||||
|
||||
void ConfigAudioPorts(unsigned divide);
|
||||
|
||||
void AudioHwInit();
|
||||
|
||||
void PLL_Init(void);
|
||||
|
||||
/* Configures master clock and codc for passed sample freq */
|
||||
void AudioHwConfig(unsigned samFreq);
|
||||
|
||||
void ConfigCodec24576(unsigned samFeq);
|
||||
|
||||
#endif
|
||||
220
examples/xua_lite_example/src/AudioConfig.xc
Executable file
220
examples/xua_lite_example/src/AudioConfig.xc
Executable file
@@ -0,0 +1,220 @@
|
||||
#include <xs1.h>
|
||||
#include <assert.h>
|
||||
#include <platform.h>
|
||||
#include <print.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
// TLV320DAC3101 Device I2C Address
|
||||
#define DAC3101_I2C_DEVICE_ADDR 0x18
|
||||
|
||||
// TLV320DAC3101 Register Addresses
|
||||
// Page 0
|
||||
#define DAC3101_PAGE_CTRL 0x00 // Register 0 - Page Control
|
||||
#define DAC3101_SW_RST 0x01 // Register 1 - Software Reset
|
||||
#define DAC3101_CLK_GEN_MUX 0x04 // Register 4 - Clock-Gen Muxing
|
||||
#define DAC3101_PLL_P_R 0x05 // Register 5 - PLL P and R Values
|
||||
#define DAC3101_PLL_J 0x06 // Register 6 - PLL J Value
|
||||
#define DAC3101_PLL_D_MSB 0x07 // Register 7 - PLL D Value (MSB)
|
||||
#define DAC3101_PLL_D_LSB 0x08 // Register 8 - PLL D Value (LSB)
|
||||
#define DAC3101_NDAC_VAL 0x0B // Register 11 - NDAC Divider Value
|
||||
#define DAC3101_MDAC_VAL 0x0C // Register 12 - MDAC Divider Value
|
||||
#define DAC3101_DOSR_VAL_LSB 0x0E // Register 14 - DOSR Divider Value (LS Byte)
|
||||
#define DAC3101_CLKOUT_MUX 0x19 // Register 25 - CLKOUT MUX
|
||||
#define DAC3101_CLKOUT_M_VAL 0x1A // Register 26 - CLKOUT M_VAL
|
||||
#define DAC3101_CODEC_IF 0x1B // Register 27 - CODEC Interface Control
|
||||
#define DAC3101_DAC_DAT_PATH 0x3F // Register 63 - DAC Data Path Setup
|
||||
#define DAC3101_DAC_VOL 0x40 // Register 64 - DAC Vol Control
|
||||
#define DAC3101_DACL_VOL_D 0x41 // Register 65 - DAC Left Digital Vol Control
|
||||
#define DAC3101_DACR_VOL_D 0x42 // Register 66 - DAC Right Digital Vol Control
|
||||
#define DAC3101_GPIO1_IO 0x33 // Register 51 - GPIO1 In/Out Pin Control
|
||||
// Page 1
|
||||
#define DAC3101_HP_DRVR 0x1F // Register 31 - Headphone Drivers
|
||||
#define DAC3101_SPK_AMP 0x20 // Register 32 - Class-D Speaker Amp
|
||||
#define DAC3101_HP_DEPOP 0x21 // Register 33 - Headphone Driver De-pop
|
||||
#define DAC3101_DAC_OP_MIX 0x23 // Register 35 - DAC_L and DAC_R Output Mixer Routing
|
||||
#define DAC3101_HPL_VOL_A 0x24 // Register 36 - Analog Volume to HPL
|
||||
#define DAC3101_HPR_VOL_A 0x25 // Register 37 - Analog Volume to HPR
|
||||
#define DAC3101_SPKL_VOL_A 0x26 // Register 38 - Analog Volume to Left Speaker
|
||||
#define DAC3101_SPKR_VOL_A 0x27 // Register 39 - Analog Volume to Right Speaker
|
||||
#define DAC3101_HPL_DRVR 0x28 // Register 40 - Headphone Left Driver
|
||||
#define DAC3101_HPR_DRVR 0x29 // Register 41 - Headphone Right Driver
|
||||
#define DAC3101_SPKL_DRVR 0x2A // Register 42 - Left Class-D Speaker Driver
|
||||
#define DAC3101_SPKR_DRVR 0x2B // Register 43 - Right Class-D Speaker Driver
|
||||
|
||||
// TLV320DAC3101 easy register access defines
|
||||
//#define DAC3101_REGREAD(reg, data) {data[0] = 0xAA; i2c_master_read_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);}
|
||||
//#define DAC3101_REGWRITE(reg, val) {data[0] = val; i2c_master_write_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);}
|
||||
|
||||
//#define DAC3101_REGWRITE(reg, val) {i_i2c[0].write_reg(DAC3101_I2C_DEVICE_ADDR, reg, val);}
|
||||
|
||||
// TLV320DAC3101 easy register access defines
|
||||
//#define DAC3101_REGWRITE(reg, val) {data[0] = val; i2c_master_write_reg(DAC3101_I2C_DEVICE_ADDR, reg, data, 1, i2c);}
|
||||
#define DAC3101_REGWRITE(reg, val)
|
||||
|
||||
|
||||
void AudioHwConfigure(unsigned samFreq)
|
||||
{
|
||||
|
||||
// Take DAC out of reset.
|
||||
//p_gpio <: 1;
|
||||
|
||||
par
|
||||
{
|
||||
{
|
||||
unsigned char data[1] = {0};
|
||||
|
||||
// Wait for 1ms
|
||||
delay_milliseconds(1);
|
||||
|
||||
// Set register page to 0
|
||||
DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00);
|
||||
// Initiate SW reset (PLL is powered off as part of reset)
|
||||
DAC3101_REGWRITE(DAC3101_SW_RST, 0x01);
|
||||
|
||||
// so I've got 24MHz in to PLL, I want 24.576MHz or 22.5792MHz out.
|
||||
|
||||
// I will always be using fractional-N (D != 0) so we must set R = 1
|
||||
// PLL_CLKIN/P must be between 10 and 20MHz so we must set P = 2
|
||||
|
||||
// PLL_CLK = CLKIN * ((RxJ.D)/P)
|
||||
// We know R = 1, P = 2.
|
||||
// PLL_CLK = CLKIN * (J.D / 2)
|
||||
|
||||
// For 24.576MHz:
|
||||
// J = 8
|
||||
// D = 1920
|
||||
// So PLL_CLK = 24 * (8.192/2) = 24 x 4.096 = 98.304MHz
|
||||
// Then:
|
||||
// NDAC = 4
|
||||
// MDAC = 4
|
||||
// DOSR = 128
|
||||
// So:
|
||||
// DAC_CLK = PLL_CLK / 4 = 24.576MHz.
|
||||
// DAC_MOD_CLK = DAC_CLK / 4 = 6.144MHz.
|
||||
// DAC_FS = DAC_MOD_CLK / 128 = 48kHz.
|
||||
|
||||
// For 22.5792MHz:
|
||||
// J = 7
|
||||
// D = 5264
|
||||
// So PLL_CLK = 24 * (7.5264/2) = 24 x 3.7632 = 90.3168MHz
|
||||
// Then:
|
||||
// NDAC = 4
|
||||
// MDAC = 4
|
||||
// DOSR = 128
|
||||
// So:
|
||||
// DAC_CLK = PLL_CLK / 4 = 22.5792MHz.
|
||||
// DAC_MOD_CLK = DAC_CLK / 4 = 5.6448MHz.
|
||||
// DAC_FS = DAC_MOD_CLK / 128 = 44.1kHz.
|
||||
|
||||
/* Sample frequency dependent register settings */
|
||||
if ((samFreq % 11025) == 0)
|
||||
{
|
||||
// MCLK = 22.5792MHz (44.1,88.2,176.4kHz)
|
||||
// Set PLL J Value to 7
|
||||
DAC3101_REGWRITE(DAC3101_PLL_J, 0x07);
|
||||
// Set PLL D to 5264 ... (0x1490)
|
||||
// Set PLL D MSB Value to 0x14
|
||||
DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x14);
|
||||
// Set PLL D LSB Value to 0x90
|
||||
DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x90);
|
||||
|
||||
}
|
||||
else if ((samFreq % 8000) == 0)
|
||||
{
|
||||
// MCLK = 24.576MHz (48,96,192kHz)
|
||||
// Set PLL J Value to 8
|
||||
DAC3101_REGWRITE(DAC3101_PLL_J, 0x08);
|
||||
// Set PLL D to 1920 ... (0x780)
|
||||
// Set PLL D MSB Value to 0x07
|
||||
DAC3101_REGWRITE(DAC3101_PLL_D_MSB, 0x07);
|
||||
// Set PLL D LSB Value to 0x80
|
||||
DAC3101_REGWRITE(DAC3101_PLL_D_LSB, 0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
//debug_printf("Unrecognised sample freq of %d in ConfigCodec\n", samFreq);
|
||||
}
|
||||
|
||||
delay_milliseconds(1);
|
||||
|
||||
// Set PLL_CLKIN = MCLK (device pin), CODEC_CLKIN = PLL_CLK (generated on-chip)
|
||||
DAC3101_REGWRITE(DAC3101_CLK_GEN_MUX, 0x03);
|
||||
|
||||
// Set PLL P and R values and power up.
|
||||
DAC3101_REGWRITE(DAC3101_PLL_P_R, 0xA1);
|
||||
// Set NDAC clock divider to 4 and power up.
|
||||
DAC3101_REGWRITE(DAC3101_NDAC_VAL, 0x84);
|
||||
// Set MDAC clock divider to 4 and power up.
|
||||
DAC3101_REGWRITE(DAC3101_MDAC_VAL, 0x84);
|
||||
// Set OSR clock divider to 128.
|
||||
DAC3101_REGWRITE(DAC3101_DOSR_VAL_LSB, 0x80);
|
||||
|
||||
// Set CLKOUT Mux to DAC_CLK
|
||||
DAC3101_REGWRITE(DAC3101_CLKOUT_MUX, 0x04);
|
||||
// Set CLKOUT M divider to 1 and power up.
|
||||
DAC3101_REGWRITE(DAC3101_CLKOUT_M_VAL, 0x81);
|
||||
// Set GPIO1 output to come from CLKOUT output.
|
||||
DAC3101_REGWRITE(DAC3101_GPIO1_IO, 0x10);
|
||||
|
||||
// Set CODEC interface mode: I2S, 24 bit, slave mode (BCLK, WCLK both inputs).
|
||||
DAC3101_REGWRITE(DAC3101_CODEC_IF, 0x20);
|
||||
// Set register page to 1
|
||||
DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x01);
|
||||
// Program common-mode voltage to mid scale 1.65V.
|
||||
DAC3101_REGWRITE(DAC3101_HP_DRVR, 0x14);
|
||||
// Program headphone-specific depop settings.
|
||||
// De-pop, Power on = 800 ms, Step time = 4 ms
|
||||
DAC3101_REGWRITE(DAC3101_HP_DEPOP, 0x4E);
|
||||
// Program routing of DAC output to the output amplifier (headphone/lineout or speaker)
|
||||
// LDAC routed to left channel mixer amp, RDAC routed to right channel mixer amp
|
||||
DAC3101_REGWRITE(DAC3101_DAC_OP_MIX, 0x44);
|
||||
// Unmute and set gain of output driver
|
||||
// Unmute HPL, set gain = 0 db
|
||||
DAC3101_REGWRITE(DAC3101_HPL_DRVR, 0x06);
|
||||
// Unmute HPR, set gain = 0 dB
|
||||
DAC3101_REGWRITE(DAC3101_HPR_DRVR, 0x06);
|
||||
// Unmute Left Class-D, set gain = 12 dB
|
||||
DAC3101_REGWRITE(DAC3101_SPKL_DRVR, 0x0C);
|
||||
// Unmute Right Class-D, set gain = 12 dB
|
||||
DAC3101_REGWRITE(DAC3101_SPKR_DRVR, 0x0C);
|
||||
// Power up output drivers
|
||||
// HPL and HPR powered up
|
||||
DAC3101_REGWRITE(DAC3101_HP_DRVR, 0xD4);
|
||||
// Power-up L and R Class-D drivers
|
||||
DAC3101_REGWRITE(DAC3101_SPK_AMP, 0xC6);
|
||||
// Enable HPL output analog volume, set = -9 dB
|
||||
DAC3101_REGWRITE(DAC3101_HPL_VOL_A, 0x92);
|
||||
// Enable HPR output analog volume, set = -9 dB
|
||||
DAC3101_REGWRITE(DAC3101_HPR_VOL_A, 0x92);
|
||||
// Enable Left Class-D output analog volume, set = -9 dB
|
||||
DAC3101_REGWRITE(DAC3101_SPKL_VOL_A, 0x92);
|
||||
// Enable Right Class-D output analog volume, set = -9 dB
|
||||
DAC3101_REGWRITE(DAC3101_SPKR_VOL_A, 0x92);
|
||||
|
||||
delay_milliseconds(100);
|
||||
|
||||
// Power up DAC
|
||||
// Set register page to 0
|
||||
DAC3101_REGWRITE(DAC3101_PAGE_CTRL, 0x00);
|
||||
// Power up DAC channels and set digital gain
|
||||
// Powerup DAC left and right channels (soft step enabled)
|
||||
DAC3101_REGWRITE(DAC3101_DAC_DAT_PATH, 0xD4);
|
||||
// DAC Left gain = 0dB
|
||||
DAC3101_REGWRITE(DAC3101_DACL_VOL_D, 0x00);
|
||||
// DAC Right gain = 0dB
|
||||
DAC3101_REGWRITE(DAC3101_DACR_VOL_D, 0x00);
|
||||
// Unmute digital volume control
|
||||
// Unmute DAC left and right channels
|
||||
DAC3101_REGWRITE(DAC3101_DAC_VOL, 0x00);
|
||||
|
||||
// Shutdown
|
||||
//i_i2c[0].shutdown();
|
||||
}
|
||||
} /* par */
|
||||
}
|
||||
|
||||
//These are here just to silence compiler warnings
|
||||
void AudioHwInit(){}
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC){}
|
||||
66
examples/xua_lite_example/src/RPI_HAT_60QFN.xn
Normal file
66
examples/xua_lite_example/src/RPI_HAT_60QFN.xn
Normal file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Type>Device</Type>
|
||||
<Name>XVF3510 Device</Name>
|
||||
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
<Declaration>tileref usb_tile</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS2-UFnA-512-TQ128">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS2-L16A-512" SystemFrequency="500MHz" OscillatorSrc="1">
|
||||
<Boot>
|
||||
<Source Location="bootFlash0"/>
|
||||
</Boot>
|
||||
<Tile Number="0" Reference="tile[0]">
|
||||
<Port Location="XS1_PORT_1B" Name="PORT_SQI_CS_0"/>
|
||||
<Port Location="XS1_PORT_1C" Name="PORT_SQI_SCLK_0"/>
|
||||
<Port Location="XS1_PORT_4B" Name="PORT_SQI_SIO_0"/>
|
||||
</Tile>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
<Node Id="1" InPackageId="1" Type="periph:XS1-SU" Reference="usb_tile" Oscillator="24MHz">
|
||||
</Node>
|
||||
</Nodes>
|
||||
<Links>
|
||||
<Link Encoding="5wire">
|
||||
<LinkEndpoint NodeId="0" Link="8" Delays="52clk,52clk"/>
|
||||
<LinkEndpoint NodeId="1" Link="XL0" Delays="1clk,1clk"/>
|
||||
</Link>
|
||||
</Links>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<Nodes>
|
||||
<Node Id="3" Type="device:" RoutingId="0x8000">
|
||||
<Service Id="0" Proto="xscope_host_data(chanend c);">
|
||||
<Chanend Identifier="c" end="3"/>
|
||||
</Service>
|
||||
</Node>
|
||||
</Nodes>
|
||||
|
||||
<Links>
|
||||
<Link Encoding="2wire" Delays="4,4" Flags="XSCOPE">
|
||||
<LinkEndpoint NodeId="0" Link="XL0"/>
|
||||
<LinkEndpoint NodeId="3" Chanend="1"/>
|
||||
</Link>
|
||||
</Links>
|
||||
|
||||
<ExternalDevices>
|
||||
<Device NodeId="0" Tile="0" Class="SQIFlash" Name="bootFlash0">
|
||||
<Attribute Name="PORT_SQI_CS" Value="PORT_SQI_CS_0"/>
|
||||
<Attribute Name="PORT_SQI_SCLK" Value="PORT_SQI_SCLK_0"/>
|
||||
<Attribute Name="PORT_SQI_SIO" Value="PORT_SQI_SIO_0"/>
|
||||
</Device>
|
||||
</ExternalDevices>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
106
examples/xua_lite_example/src/app_xua_lite.xc
Normal file
106
examples/xua_lite_example/src/app_xua_lite.xc
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved
|
||||
|
||||
// A very simple *example* of a USB audio application (and as such is un-verified for production)
|
||||
|
||||
#include <xs1.h>
|
||||
#include <platform.h>
|
||||
|
||||
#include "xua.h"
|
||||
#include "i2s.h"
|
||||
#include "i2c.h"
|
||||
#include "gpio.h"
|
||||
|
||||
// Port declarations. Note, the defines come from the xn file
|
||||
on tile[0]: buffered out port:32 p_i2s_dac[] = {XS1_PORT_1M}; //DAC
|
||||
on tile[0]: buffered in port:32 p_i2s_adc[] = {XS1_PORT_1N}; //Unused currently
|
||||
on tile[0]: buffered out port:32 p_lrclk = XS1_PORT_1O; //I2S Bit-clock
|
||||
on tile[0]: out port p_bclk = XS1_PORT_1P; //I2S L/R-clock
|
||||
|
||||
// Master clock for the audio IO tile
|
||||
on tile[0]: in port p_mclk_in = XS1_PORT_1A;
|
||||
|
||||
// Resources for USB feedback
|
||||
on tile[0]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks
|
||||
|
||||
// [0] : DAC_RESET_N
|
||||
// [1] : I2C_INTERRUPT_N
|
||||
// [2] : MUTE_EN
|
||||
// [3] : LED
|
||||
on tile[0]: out port p_gpio = XS1_PORT_4D;
|
||||
|
||||
on tile[1]: port p_scl = XS1_PORT_1C;
|
||||
on tile[1]: port p_sda = XS1_PORT_1D;
|
||||
|
||||
|
||||
// Clock-block declarations
|
||||
clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_2; // Bit clock
|
||||
clock clk_audio_mclk = on tile[0]: XS1_CLKBLK_3; // Master clock
|
||||
|
||||
// Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also
|
||||
// if the endpoint wishes to be informed of USB bus resets
|
||||
|
||||
XUD_EpType epTypeTableOut[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO};
|
||||
XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_ISO, XUD_EPTYPE_ISO};
|
||||
|
||||
void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_aud_host);
|
||||
[[distributable]]
|
||||
void AudioHub(server i2s_frame_callback_if i2s, chanend c_aud, client i2c_master_if i2c, client output_gpio_if dac_reset);
|
||||
|
||||
int main()
|
||||
{
|
||||
// Channels for lib_xud
|
||||
chan c_ep_out[2];
|
||||
chan c_ep_in[3];
|
||||
|
||||
// Channel for communicating SOF notifications from XUD to the Buffering cores
|
||||
chan c_sof;
|
||||
|
||||
interface i2s_frame_callback_if i_i2s;
|
||||
interface i2c_master_if i_i2c[1];
|
||||
interface output_gpio_if i_gpio[1];
|
||||
|
||||
chan c_audio;
|
||||
|
||||
|
||||
// Channel for communicating control messages from EP0 to the rest of the device (via the buffering cores)
|
||||
chan c_aud_ctl;
|
||||
|
||||
par
|
||||
{
|
||||
on tile[0]: {
|
||||
// Connect master-clock clock-block to clock-block pin
|
||||
set_clock_src(clk_audio_mclk, p_mclk_in); // Clock clock-block from mclk pin
|
||||
set_port_clock(p_for_mclk_count, clk_audio_mclk); // Clock the "count" port from the clock block
|
||||
start_clock(clk_audio_mclk); // Set the clock off running
|
||||
|
||||
|
||||
par {
|
||||
// Low level USB device layer core
|
||||
XUD_Main(c_ep_out, 2, c_ep_in, 3,
|
||||
c_sof, epTypeTableOut, epTypeTableIn,
|
||||
null, null, -1 ,
|
||||
XUD_SPEED_FS, XUD_PWR_BUS);
|
||||
|
||||
// Endpoint 0 core from lib_xua
|
||||
// Note, since we are not using many features we pass in null for quite a few params..
|
||||
XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null);
|
||||
|
||||
// Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core
|
||||
XUA_Buffer_lite(c_ep_out[1], c_ep_in[2], c_ep_in[1], c_sof, c_aud_ctl, p_for_mclk_count, c_audio);
|
||||
|
||||
i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk);
|
||||
[[distribute]]AudioHub(i_i2s, c_audio, i_i2c[0], i_gpio[0]);
|
||||
[[distribute]]output_gpio(i_gpio, 1, p_gpio, null);
|
||||
}
|
||||
}
|
||||
on tile[1]:{
|
||||
par{
|
||||
i2c_master(i_i2c, 1, p_scl, p_sda, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
44
examples/xua_lite_example/src/audio_hub.xc
Normal file
44
examples/xua_lite_example/src/audio_hub.xc
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "i2s.h"
|
||||
#include "i2c.h"
|
||||
#include "gpio.h"
|
||||
#include "xua.h"
|
||||
|
||||
[[distributable]]
|
||||
void AudioHub(server i2s_frame_callback_if i2s,
|
||||
chanend c_aud,
|
||||
client i2c_master_if i2c,
|
||||
client output_gpio_if dac_reset)
|
||||
{
|
||||
int32_t samples[8] = {0}; // Array used for looping back samples
|
||||
while (1) {
|
||||
select {
|
||||
case i2s.init(i2s_config_t &?i2s_config, tdm_config_t &?tdm_config):
|
||||
i2s_config.mode = I2S_MODE_I2S;
|
||||
i2s_config.mclk_bclk_ratio = (MCLK_48/DEFAULT_FREQ)/64;
|
||||
|
||||
// Set CODECs in reset
|
||||
dac_reset.output(0);
|
||||
|
||||
// Allow reset to assert
|
||||
delay_milliseconds(1);
|
||||
|
||||
// Take CODECs out of reset
|
||||
dac_reset.output(1);
|
||||
|
||||
//reset_codecs(i2c);
|
||||
break;
|
||||
|
||||
case i2s.receive(size_t n_chans, int32_t in_samps[n_chans]):
|
||||
for (int i = 0; i < n_chans; i++) samples[i] = in_samps[i]; // copy samples
|
||||
break;
|
||||
|
||||
case i2s.send(size_t n_chans, int32_t out_samps[n_chans]):
|
||||
for (int i = 0; i < n_chans; i++) out_samps[i] = samples[i]; // copy samples
|
||||
break;
|
||||
|
||||
case i2s.restart_check() -> i2s_restart_t restart:
|
||||
restart = I2S_NO_RESTART; // Keep on looping
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
274
examples/xua_lite_example/src/xua_buffer.xc
Normal file
274
examples/xua_lite_example/src/xua_buffer.xc
Normal file
@@ -0,0 +1,274 @@
|
||||
#include <xs1.h>
|
||||
#include "xua_commands.h"
|
||||
#include "xud.h"
|
||||
#include "testct_byref.h"
|
||||
#include "debug_print.h"
|
||||
#include "xua_conf.h"
|
||||
//#include "fifo_impl.h" //xua_conf.h must be included before hand so that we have FIFO sizes
|
||||
|
||||
//Currently only single frequency supported
|
||||
#define NOMINAL_SR_DEVICE DEFAULT_FREQ
|
||||
#define NOMINAL_SR_HOST DEFAULT_FREQ
|
||||
|
||||
#define DIV_ROUND_UP(n, d) (n / d + 1) //Always rounds up to the next integer. Needed for 48001Hz case etc.
|
||||
#define BIGGEST(a, b) (a > b ? a : b)
|
||||
|
||||
#define SOF_FREQ_HZ (8000 - ((2 - AUDIO_CLASS) * 7000) )
|
||||
|
||||
//Defines for endpoint buffer sizes. Samples is total number of samples across all channels
|
||||
#define MAX_OUT_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_OUT)
|
||||
#define MAX_IN_SAMPLES_PER_SOF_PERIOD (DIV_ROUND_UP(MAX_FREQ, SOF_FREQ_HZ) * NUM_USB_CHAN_IN)
|
||||
#define MAX_OUTPUT_SLOT_SIZE 4
|
||||
#define MAX_INPUT_SLOT_SIZE 4
|
||||
|
||||
#define OUT_AUDIO_BUFFER_SIZE_BYTES (MAX_OUT_SAMPLES_PER_SOF_PERIOD * MAX_OUTPUT_SLOT_SIZE)
|
||||
#define IN_AUDIO_BUFFER_SIZE_BYTES (MAX_IN_SAMPLES_PER_SOF_PERIOD * MAX_INPUT_SLOT_SIZE)
|
||||
|
||||
//Helper to disassemble USB packets into 32b left aligned audio samples
|
||||
static inline void unpack_buff_to_samples(unsigned char input[], const unsigned n_samples, const unsigned slot_size, int output[]){
|
||||
switch(slot_size){
|
||||
case 4:
|
||||
for (int i = 0; i < n_samples; i++){
|
||||
unsigned base = i * 4;
|
||||
output[i] = (input[base + 3] << 24) | (input[base + 2] << 16) | (input[base + 1] << 8) | input[base + 0];
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < n_samples; i++){
|
||||
unsigned base = i * 3;
|
||||
output[i] = (input[base + 2] << 24) | (input[base + 1] << 16) | (input[base + 0] << 8);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < n_samples; i++){
|
||||
unsigned base = i * 2;
|
||||
output[i] = (input[base + 1] << 24) | (input[base + 0] << 16);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug_printf("Invalid slot_size\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Helper to assemble USB packets from 32b left aligned audio samples
|
||||
static inline void pack_samples_to_buff(int input[], const unsigned n_samples, const unsigned slot_size, unsigned char output[]){
|
||||
switch(slot_size){
|
||||
case 4:
|
||||
for (int i = 0; i < n_samples; i++){
|
||||
unsigned base = i * 4;
|
||||
unsigned in_word = (unsigned)input[i];
|
||||
output[base + 0] = in_word & 0xff;
|
||||
output[base + 1] = (in_word & 0xff00) >> 8;
|
||||
output[base + 2] = (in_word & 0xff0000) >> 16;
|
||||
output[base + 3] = (in_word) >> 24;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < n_samples; i++){
|
||||
unsigned base = i * 3;
|
||||
unsigned in_word = (unsigned)input[i];
|
||||
output[base + 0] = (in_word & 0xff00) >> 8;
|
||||
output[base + 1] = (in_word & 0xff0000) >> 16;
|
||||
output[base + 2] = (in_word) >> 24;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < n_samples; i++){
|
||||
unsigned base = i * 2;
|
||||
unsigned in_word = (unsigned)input[i];
|
||||
output[base + 0] = (in_word & 0xff0000) >> 16;
|
||||
output[base + 1] = (in_word) >> 24;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug_printf("Invalid slot_size\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Shared memory buffers between buffer task and audio side
|
||||
int asrc_to_host_sample_buffer[MAX_IN_SAMPLES_PER_SOF_PERIOD] = {0};
|
||||
|
||||
void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_aud_host){
|
||||
|
||||
debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD);
|
||||
|
||||
unsigned sampleFreq = DEFAULT_FREQ;
|
||||
|
||||
unsigned char buffer_aud_out[OUT_AUDIO_BUFFER_SIZE_BYTES];
|
||||
unsigned char buffer_aud_in[IN_AUDIO_BUFFER_SIZE_BYTES];
|
||||
|
||||
unsigned in_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES;
|
||||
unsigned out_subslot_size = (AUDIO_CLASS == 1) ? FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES : HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES;
|
||||
|
||||
unsigned in_num_chan = NUM_USB_CHAN_IN;
|
||||
unsigned out_num_chan = NUM_USB_CHAN_OUT;
|
||||
|
||||
unsigned tmp;
|
||||
|
||||
XUD_ep ep_aud_out = XUD_InitEp(c_aud_out);
|
||||
XUD_ep ep_aud_in = XUD_InitEp(c_aud_in);
|
||||
|
||||
unsigned num_samples_received_from_host = 0;
|
||||
unsigned outstanding_samples_to_host = 0;
|
||||
unsigned num_samples_to_send_to_host = 0;
|
||||
|
||||
XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out);
|
||||
XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host);
|
||||
|
||||
// printintln(OUT_AUDIO_BUFFER_SIZE_BYTES);
|
||||
// printintln(MAX_OUT_SAMPLES_PER_SOF_PERIOD);
|
||||
|
||||
while(1){
|
||||
XUD_Result_t result;
|
||||
unsigned length = 0;
|
||||
|
||||
|
||||
select{
|
||||
//Handle control path from EP0
|
||||
case testct_byref(c_aud_ctl, tmp):
|
||||
//ignore tmp as is used for reboot signalling only
|
||||
unsigned cmd = inuint(c_aud_ctl);
|
||||
|
||||
debug_printf("c_aud_ctl cmd: %d\n", cmd);
|
||||
if(cmd == SET_SAMPLE_FREQ){
|
||||
unsigned receivedSampleFreq = inuint(c_aud_ctl);
|
||||
debug_printf("SET_SAMPLE_FREQ: %d\n", receivedSampleFreq);
|
||||
sampleFreq = receivedSampleFreq;
|
||||
}
|
||||
|
||||
else if(cmd == SET_STREAM_FORMAT_IN){
|
||||
unsigned formatChange_DataFormat = inuint(c_aud_ctl);
|
||||
unsigned formatChange_NumChans = inuint(c_aud_ctl);
|
||||
unsigned formatChange_SubSlot = inuint(c_aud_ctl);
|
||||
unsigned formatChange_SampRes = inuint(c_aud_ctl);
|
||||
debug_printf("SET_STREAM_FORMAT_IN: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes);
|
||||
in_subslot_size = formatChange_SubSlot;
|
||||
in_num_chan = formatChange_NumChans;
|
||||
}
|
||||
|
||||
else if (cmd == SET_STREAM_FORMAT_OUT)
|
||||
{
|
||||
XUD_BusSpeed_t busSpeed;
|
||||
unsigned formatChange_DataFormat = inuint(c_aud_ctl);
|
||||
unsigned formatChange_NumChans = inuint(c_aud_ctl);
|
||||
unsigned formatChange_SubSlot = inuint(c_aud_ctl);
|
||||
unsigned formatChange_SampRes = inuint(c_aud_ctl);
|
||||
debug_printf("SET_STREAM_FORMAT_OUT: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes);
|
||||
out_subslot_size = formatChange_SubSlot;
|
||||
out_num_chan = formatChange_NumChans;
|
||||
}
|
||||
|
||||
else{
|
||||
debug_printf("Unhandled command\n");
|
||||
}
|
||||
outct(c_aud_ctl, XS1_CT_END);
|
||||
break;
|
||||
|
||||
//SOF
|
||||
case inuint_byref(c_sof, tmp):
|
||||
unsigned mclk_port_count = 0;
|
||||
asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_count) : "r" (p_for_mclk_count));
|
||||
|
||||
static unsigned sof_count=0;
|
||||
sof_count++;
|
||||
if (sof_count > SOF_FREQ_HZ * 10){
|
||||
debug_printf("SOF\n");
|
||||
sof_count = 0;
|
||||
}
|
||||
|
||||
/* Assuming 48kHz from a 24.576 master clock (0.0407uS period)
|
||||
* MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF.
|
||||
* expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format.
|
||||
* Average over 128 SOFs - 128 x 3072 = 0x60000.
|
||||
*/
|
||||
#if 0
|
||||
unsigned long long feedbackMul = 64ULL;
|
||||
if(usb_speed != XUD_SPEED_HS)
|
||||
feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */
|
||||
|
||||
/* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */
|
||||
int count = (int) ((short)(u_tmp - lastClock));
|
||||
|
||||
unsigned long long full_result = count * feedbackMul * sampleFreq;
|
||||
|
||||
clockcounter += full_result;
|
||||
|
||||
/* Store MCLK for next time around... */
|
||||
lastClock = u_tmp;
|
||||
|
||||
/* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll
|
||||
* We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */
|
||||
if(sofCount == 128)
|
||||
{
|
||||
sofCount = 0;
|
||||
|
||||
clockcounter += mod_from_last_time;
|
||||
clocks = clockcounter / masterClockFreq;
|
||||
mod_from_last_time = clockcounter % masterClockFreq;
|
||||
|
||||
if(usb_speed == XUD_SPEED_HS)
|
||||
{
|
||||
clocks <<= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
clocks <<= 6;
|
||||
}
|
||||
|
||||
{
|
||||
int usb_speed;
|
||||
asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks
|
||||
|
||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||
|
||||
if (usb_speed == XUD_SPEED_HS)
|
||||
{
|
||||
fb_clocks[0] = clocks;
|
||||
}
|
||||
else
|
||||
{
|
||||
fb_clocks[0] = clocks >> 2;
|
||||
}
|
||||
}
|
||||
clockcounter = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
//Receive samples from host
|
||||
case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result):
|
||||
num_samples_received_from_host = length / out_subslot_size;
|
||||
//debug_printf("out samps: %d\n", num_samples_received_from_host);
|
||||
outstanding_samples_to_host += num_samples_received_from_host;
|
||||
int samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD];
|
||||
unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, samples);
|
||||
|
||||
//Push into fifo for ASRC
|
||||
|
||||
//else debug_printf("Push\n");
|
||||
|
||||
//Tell ASRC manager what we have just sent
|
||||
outuint(c_aud_host, num_samples_received_from_host); //We assume this will not block and other side always consumes
|
||||
num_samples_to_send_to_host = inuint(c_aud_host); //get number of return samples for sending back to host
|
||||
|
||||
//Mark EP as ready for next frame from host
|
||||
XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out);
|
||||
break;
|
||||
|
||||
//Send samples to host
|
||||
case XUD_SetData_Select(c_aud_in, ep_aud_in, result):
|
||||
//debug_printf("sent data\n");
|
||||
|
||||
//Populate the input buffer ready for the next read
|
||||
pack_samples_to_buff(asrc_to_host_sample_buffer, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in);
|
||||
//Use the number of samples we received last time so we are always balanced (assumes same in/out count)
|
||||
unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size;
|
||||
XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback
|
||||
num_samples_to_send_to_host = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
examples/xua_lite_example/src/xua_conf.h
Normal file
25
examples/xua_lite_example/src/xua_conf.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved
|
||||
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT 2 /* Number of channels from host to device */
|
||||
#define NUM_USB_CHAN_IN 2 /* Number of channels from device to host */
|
||||
#define I2S_CHANS_DAC 2 /* Number of I2S channels out of xCORE */
|
||||
#define I2S_CHANS_ADC 2 /* Number of I2S channels in to xCORE */
|
||||
#define MCLK_441 (512 * 44100) /* 44.1kHz family master clock frequency */
|
||||
#define MCLK_48 (512 * 48000) /* 48kHz family master clock frequency */
|
||||
#define MIN_FREQ 48000 /* Minimum sample rate */
|
||||
#define MAX_FREQ 48000 /* Maximum sample rate */
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "XUA Example"
|
||||
#define PRODUCT_STR_A1 "XUA Example"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example */
|
||||
|
||||
#endif
|
||||
7
examples/xua_lite_example/src/xud_conf.h
Normal file
7
examples/xua_lite_example/src/xud_conf.h
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) 2017-2018, XMOS Ltd, All rights reserved
|
||||
|
||||
#include "xua_conf.h"
|
||||
|
||||
/* TODO */
|
||||
#define XUD_UAC_NUM_USB_CHAN_OUT NUM_USB_CHAN_OUT
|
||||
#define XUD_UAC_NUM_USB_CHAN_IN NUM_USB_CHAN_IN
|
||||
Reference in New Issue
Block a user