Moved AN00246 from xCORE-200 to xCORE.ai MC Audio Board

This commit is contained in:
xross
2022-08-08 14:50:31 +01:00
parent 8157a76667
commit f363475529
12 changed files with 272 additions and 469 deletions

View File

@@ -1,11 +1,14 @@
APP_NAME = app_xua_simple
TARGET = xk-audio-216-mc.xn
TARGET = xk-audio-316-mc.xn
# The flags passed to xcc when building the application
XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report -save-temps \
-g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES \
-DXUD_CORE_CLOCK=600 -DUSB_TILE=tile[1] -fxscope -DUAC_FORCE_FEEDBACK_EP=0
XCC_FLAGS = -O3 -report \
-g -Wno-unused-function \
-DXUD_CORE_CLOCK=600 \
-DUSB_TILE=tile[0] \
-fxscope \
-DUAC_FORCE_FEEDBACK_EP=0
# The USED_MODULES variable lists other module used by the application. These
# modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables.

View File

@@ -11,7 +11,7 @@ Introduction
The XMOS USB Audio (XUA) library provides an implemention of USB Audio Class versions 1.0 and 2.0.
This application note demonstrates the implementation of a basic USB Audio Device on
the xCORE-200 MC Audio board.
the xCORE.ai Multichannel (MC) Audio board (XK-AUDIO-316-MC).
The Makefile
@@ -26,14 +26,10 @@ The Makefile also includes::
USED_MODULES = .. lib_xud ..
``lib_xud`` library requires some flags for correct operation. Firstly the
``lib_xud`` library requires some flags for correct operation. Namely the
tile on which ``lib_xud`` will be execute, for example::
XCC_FLAGS = .. -DUSB_TILE=tile[1] ..
Secondly, the architecture of the target device, for example::
XCC_FLAGS = .. -DXUD_SERIES_SUPPORT=XUD_X200_SERIES ..
XCC_FLAGS = .. -DUSB_TILE=tile[0] ..
Includes
........
@@ -55,13 +51,12 @@ be included in your code to use the library.
Allocating hardware resources
.............................
A basic implementation of a USB Audio device (i.e. simple stereo input and output via I2S)
A basic implementation of a USB Audio device (i.e. simple stereo output via I2S)
using ``lib_xua`` requires the follow pins:
- I2S Bit Clock (from xCORE to DAC)
- I2S L/R clock (from xCORE to DAC)
- I2S Data line (from xCORE to DAC)
- I2S Data line (from ADC to xCORE)
- Audio Master clock (from clock source to xCORE)
.. note::
@@ -99,7 +94,7 @@ Other declarations
..................
``lib_xua`` currently requires the manual declaration of tables for the endpoint types for
``lib_xud`` and the calling the main XUD funtion in a par (``XUD_Main()``).
``lib_xud`` and the calling the main XUD function in a par (``XUD_Main()``).
For a simple application the following endpoints are required:
@@ -162,7 +157,7 @@ implentation e.g. master clock frequencies and must be defined. Please see the
Demo Hardware Setup
-------------------
To run the demo, connect a USB cable to power the xCORE-200 MC Audio board
To run the demo, connect a USB cable to power the xCORE.ai Multichannel Audio board
and plug the xTAG to the board and connect the xTAG USB cable to your
development machine.
@@ -177,7 +172,7 @@ Launching the demo application
------------------------------
Once the demo example has been built either from the command line using xmake or
via the build mechanism of xTIMEcomposer studio it can be executed on the xCORE-200
via the build mechanism of xTIMEcomposer studio it can be executed on the xCORE.ai
MC Audio board.
Once built there will be a ``bin/`` directory within the project which contains
@@ -192,7 +187,7 @@ on the xCORE device::
xrun --xscope bin/app_xua_simple.xe
Once this command has executed the application will be running on the
xCORE-200 MC Audio Board
xCORE.ai MC Audio Board
Launching from xTIMEcomposer Studio
...................................
@@ -204,7 +199,7 @@ enable the xSCOPE I/O mode in the dialog box and then
select Run.
Once this command has executed the application will be running on the
xCORE-200 MC Audio board.
xCORE.ai MC Audio board.
Running the application
.......................

View File

@@ -19,7 +19,6 @@
/* Port declarations. Note, the defines come from the xn file */
buffered out port:32 p_i2s_dac[] = {PORT_I2S_DAC0}; /* I2S Data-line(s) */
buffered in port:32 p_i2s_adc[] = {PORT_I2S_ADC0}; /* I2S Data-line(s) */
buffered out port:32 p_lrclk = PORT_I2S_LRCLK; /* I2S Bit-clock */
buffered out port:32 p_bclk = PORT_I2S_BCLK; /* I2S L/R-clock */
@@ -31,15 +30,22 @@ in port p_for_mclk_count = PORT_MCLK_COUNT; /* Extra port for count
in port p_mclk_in_usb = PORT_MCLK_IN_USB; /* Extra master clock input for the USB tile */
/* Clock-block declarations */
clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_4; /* Bit clock */
clock clk_audio_mclk = on tile[0]: XS1_CLKBLK_5; /* Master clock */
clock clk_audio_mclk_usb = on tile[1]: XS1_CLKBLK_1; /* Master clock for USB tile */
clock clk_audio_bclk = on tile[1]: XS1_CLKBLK_4; /* Bit clock */
clock clk_audio_mclk = on tile[1]: XS1_CLKBLK_5; /* Master clock */
clock clk_audio_mclk_usb = on tile[0]: XS1_CLKBLK_1; /* Master clock for USB tile */
/* 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};
/* Port declarations for I2C to config ADC's */
on tile[0]: port p_scl = XS1_PORT_1L;
on tile[0]: port p_sda = XS1_PORT_1M;
/* See hwsupport.xc */
void ctrlPort();
int main()
{
/* Channels for lib_xud */
@@ -58,17 +64,17 @@ int main()
par
{
/* Low level USB device layer core */
on tile[1]: XUD_Main(c_ep_out, 2, c_ep_in, 2,
on tile[0]: XUD_Main(c_ep_out, 2, c_ep_in, 2,
c_sof, epTypeTableOut, epTypeTableIn,
XUD_SPEED_HS, XUD_PWR_SELF);
/* Endpoint 0 core from lib_xua */
/* Note, since we are not using many features we pass in null for quite a few params.. */
on tile[1]: XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null);
on tile[0]: 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 */
/* Note, this spawns two cores */
on tile[1]: {
on tile[0]: {
/* Connect master-clock clock-block to clock-block pin */
set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb); /* Clock clock-block from mclk pin */
@@ -80,7 +86,9 @@ int main()
}
/* AudioHub/IO core does most of the audio IO i.e. I2S (also serves as a hub for all audio) */
on tile[0]: XUA_AudioHub(c_aud, clk_audio_mclk, clk_audio_bclk, p_mclk_in, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
on tile[1]: XUA_AudioHub(c_aud, clk_audio_mclk, clk_audio_bclk, p_mclk_in, p_lrclk, p_bclk, p_i2s_dac, null);
on tile[0]: ctrlPort();
}
return 0;

View File

@@ -1,33 +0,0 @@
// Copyright 2017-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef CS4384_H_
#define CS4384_H_
//Address on I2C bus
#define CS4384_I2C_ADDR (0x18)
//Register Addresess
#define CS4384_CHIP_REV 0x01
#define CS4384_MODE_CTRL 0x02
#define CS4384_PCM_CTRL 0x03
#define CS4384_DSD_CTRL 0x04
#define CS4384_FLT_CTRL 0x05
#define CS4384_INV_CTRL 0x06
#define CS4384_GRP_CTRL 0x07
#define CS4384_RMP_MUTE 0x08
#define CS4384_MUTE_CTRL 0x09
#define CS4384_MIX_PR1 0x0a
#define CS4384_VOL_A1 0x0b
#define CS4384_VOL_B1 0x0c
#define CS4384_MIX_PR2 0x0d
#define CS4384_VOL_A2 0x0e
#define CS4384_VOL_B2 0x0f
#define CS4384_MIX_PR3 0x10
#define CS4384_VOL_A3 0x11
#define CS4384_VOL_B3 0x12
#define CS4384_MIX_PR4 0x13
#define CS4384_VOL_A4 0x14
#define CS4384_VOL_B4 0x15
#define CS4384_CM_MODE 0x16
#endif /* CS4384_H_ */

View File

@@ -1,19 +0,0 @@
// Copyright 2017-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _CS5368_H_
#define _CS5368_H_
//Address on I2C bus
#define CS5368_I2C_ADDR (0x4C)
//Register Addresess
#define CS5368_CHIP_REV 0x00
#define CS5368_GCTL_MDE 0x01
#define CS5368_OVFL_ST 0x02
#define CS5368_OVFL_MSK 0x03
#define CS5368_HPF_CTRL 0x04
#define CS5368_PWR_DN 0x06
#define CS5368_MUTE_CTRL 0x08
#define CS5368_SDO_EN 0x0a
#endif /* _CS5368_H_ */

View File

@@ -1,168 +0,0 @@
// Copyright 2021-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __hid_report_descriptor_h__
#define __hid_report_descriptor_h__
#include "xua_hid_report.h"
#if 0
/* Existing static report descriptor kept for reference */
unsigned char hidReportDescriptor[] =
{
0x05, 0x0c, /* Usage Page (Consumer Device) */
0x09, 0x01, /* Usage (Consumer Control) */
0xa1, 0x01, /* Collection (Application) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x09, 0xb0, /* Usage (Play) */
0x09, 0xb5, /* Usage (Scan Next Track) */
0x09, 0xb6, /* Usage (Scan Previous Track) */
0x09, 0xe9, /* Usage (Volume Up) */
0x09, 0xea, /* Usage (Volume Down) */
0x09, 0xe2, /* Usage (Mute) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x06, /* Report Count (6) */
0x81, 0x02, /* Input (Data, Var, Abs) */
0x95, 0x02, /* Report Count (2) */
0x81, 0x01, /* Input (Cnst, Ary, Abs) */
0xc0 /* End collection */
};
#endif
/*
* Define non-configurable items in the HID Report descriptor.
*/
static const USB_HID_Short_Item_t hidCollectionApplication = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidCollectionEnd = {
.header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION),
.data = { 0x00, 0x00 } };
static const USB_HID_Short_Item_t hidInputConstArray = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidInputDataVar = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT),
.data = { 0x02, 0x00 } };
static const USB_HID_Short_Item_t hidLogicalMaximum0 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM),
.data = { 0x00, 0x00 } };
static const USB_HID_Short_Item_t hidLogicalMaximum1 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidLogicalMinimum0 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM),
.data = { 0x00, 0x00 } };
static const USB_HID_Short_Item_t hidReportCount2 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT),
.data = { 0x02, 0x00 } };
static const USB_HID_Short_Item_t hidReportCount6 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT),
.data = { 0x06, 0x00 } };
static const USB_HID_Short_Item_t hidReportSize1 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidUsageConsumerControl = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.data = { 0x01, 0x00 } };
/*
* Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report
* For internal purposes, a report element with ID of 0 must be included if report IDs are not being used.
*/
static const USB_HID_Report_Element_t hidReportPageConsumer = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE),
.item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 },
.location = HID_REPORT_SET_LOC( 0, 2, 0, 0 )
};
/*
* Define configurable items in the HID Report descriptor.
*/
static USB_HID_Report_Element_t hidUsageByte0Bit5 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xE2, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 5)
}; // Mute
static USB_HID_Report_Element_t hidUsageByte0Bit4 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xEA, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 4)
}; // Vol-
static USB_HID_Report_Element_t hidUsageByte0Bit3 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xE9, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 3)
}; // Vol+
static USB_HID_Report_Element_t hidUsageByte0Bit2 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xB6, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 2)
}; // Scan Prev
static USB_HID_Report_Element_t hidUsageByte0Bit1 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xB5, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 1)
}; // Scan Next
static USB_HID_Report_Element_t hidUsageByte0Bit0 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xB0, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 0)
}; // Play
/*
* List the configurable elements in the HID Report descriptor.
*/
static USB_HID_Report_Element_t* const hidConfigurableElements[] = {
&hidUsageByte0Bit0,
&hidUsageByte0Bit1,
&hidUsageByte0Bit2,
&hidUsageByte0Bit3,
&hidUsageByte0Bit4,
&hidUsageByte0Bit5
};
/*
* List HID Reports, one per Report ID. This should be a usage page item with the relevant
* If not using report IDs - still have one with report ID 0
*/
static const USB_HID_Report_Element_t* const hidReports[] = {
&hidReportPageConsumer
};
/*
* List all items in the HID Report descriptor.
*/
static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = {
&(hidReportPageConsumer.item),
&hidUsageConsumerControl,
&hidCollectionApplication,
&hidLogicalMinimum0,
&hidLogicalMaximum1,
&(hidUsageByte0Bit0.item),
&(hidUsageByte0Bit1.item),
&(hidUsageByte0Bit2.item),
&(hidUsageByte0Bit3.item),
&(hidUsageByte0Bit4.item),
&(hidUsageByte0Bit5.item),
&hidReportSize1,
&hidReportCount6,
&hidInputDataVar,
&hidLogicalMaximum0,
&hidReportCount2,
&hidInputConstArray,
&hidCollectionEnd
};
/*
* Define the number of HID Reports
* Due to XC not supporting designated initializers, this constant has a hard-coded value.
* It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* ))
*/
#define HID_REPORT_COUNT ( 1 )
#endif // __hid_report_descriptor_h__

View File

@@ -1,146 +1,56 @@
// Copyright 2016-2022 XMOS LIMITED.
// Copyright 2017-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include <platform.h>
#include <timer.h>
#include <stdint.h>
#include "xua.h"
#include "i2c.h" /* From lib_i2c */
#include "../../shared/apppll.h"
#include "cs5368.h"
#include "cs4384.h"
on tile[0]: out port p_ctrl = XS1_PORT_8D;
port p_i2c = on tile[0]:XS1_PORT_4A;
/* p_ctrl:
* [0:3] - Unused
* [4] - EN_3v3_N
* [5] - EN_3v3A
* [6] - EXT_PLL_SEL (CS2100:0, SI: 1)
* [7] - MCLK_DIR (Out:0, In: 1)
*/
#define EXT_PLL_SEL__MCLK_DIR (0x80)
/* General output port bit definitions */
#define P_GPIO_DSD_MODE (1 << 0) /* DSD mode select 0 = 8i/8o I2S, 1 = 8o DSD*/
#define P_GPIO_DAC_RST_N (1 << 1)
#define P_GPIO_USB_SEL0 (1 << 2)
#define P_GPIO_USB_SEL1 (1 << 3)
#define P_GPIO_VBUS_EN (1 << 4)
#define P_GPIO_PLL_SEL (1 << 5) /* 1 = CS2100, 0 = Phaselink clock source */
#define P_GPIO_ADC_RST_N (1 << 6)
#define P_GPIO_MCLK_FSEL (1 << 7) /* Select frequency on Phaselink clock. 0 = 24.576MHz for 48k, 1 = 22.5792MHz for 44.1k.*/
#define DAC_REGWRITE(reg, val) result = i2c.write_reg(CS4384_I2C_ADDR, reg, val);
#define DAC_REGREAD(reg) data = i2c.read_reg(CS4384_I2C_ADDR, reg, result);
#define ADC_REGWRITE(reg, val) result = i2c.write_reg(CS5368_I2C_ADDR, reg, val);
out port p_gpio = on tile[0]:XS1_PORT_8C;
void AudioHwConfig2(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC, client interface i2c_master_if i2c)
/* Note, this runs on Tile[0] */
void ctrlPort()
{
unsigned char gpioVal = 0;
i2c_regop_res_t result;
/* Set master clock select appropriately and put ADC and DAC into reset */
if (mClk == MCLK_441)
// Drive control port to turn on 3V3 and set MCLK_DIR
// Note, "soft-start" to reduce current spike
// Note, 3v3_EN is inverted
for (int i = 0; i < 30; i++)
{
gpioVal = P_GPIO_USB_SEL0 | P_GPIO_USB_SEL1;
p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x30; /* 3v3: off, 3v3A: on */
delay_microseconds(5);
p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x20; /* 3v3: on, 3v3A: on */
delay_microseconds(5);
}
else
{
gpioVal = P_GPIO_USB_SEL0 | P_GPIO_USB_SEL1 | P_GPIO_MCLK_FSEL;
}
p_gpio <: gpioVal;
/* Allow MCLK to settle */
delay_microseconds(20000);
/* Take ADC out of reset */
gpioVal |= P_GPIO_ADC_RST_N;
p_gpio <: gpioVal;
/* Configure ADC for I2S slave mode via I2C */
unsigned dif = 0, mode = 0;
dif = 0x01; /* I2S */
mode = 0x03; /* Slave mode all speeds */
/* Reg 0x01: (GCTL) Global Mode Control Register
* Bit[7]: CP-EN: Manages control-port mode
* Bit[6]: CLKMODE: Setting puts part in 384x mode
* Bit[5:4]: MDIV[1:0]: Set to 01 for /2
* Bit[3:2]: DIF[1:0]: Data Format: 0x01 for I2S, 0x02 for TDM
* Bit[1:0]: MODE[1:0]: Mode: 0x11 for slave mode
*/
ADC_REGWRITE(CS5368_GCTL_MDE, 0b10010000 | (dif << 2) | mode);
/* Reg 0x06: (PDN) Power Down Register */
/* Bit[7:6]: Reserved
* Bit[5]: PDN-BG: When set, this bit powers-own the bandgap reference
* Bit[4]: PDM-OSC: Controls power to internal oscillator core
* Bit[3:0]: PDN: When any bit is set all clocks going to that channel pair are turned off
*/
ADC_REGWRITE(CS5368_PWR_DN, 0b00000000);
/* Configure DAC with PCM values. Note 2 writes to mode control to enable/disable freeze/power down */
/* Take DAC out of reset */
gpioVal |= P_GPIO_DAC_RST_N;
p_gpio <: gpioVal;
delay_microseconds(500);
/* Mode Control 1 (Address: 0x02) */
/* bit[7] : Control Port Enable (CPEN) : Set to 1 for enable
* bit[6] : Freeze controls (FREEZE) : Set to 1 for freeze
* bit[5] : PCM/DSD Selection (DSD/PCM) : Set to 0 for PCM
* bit[4:1] : DAC Pair Disable (DACx_DIS) : All Dac Pairs enabled
* bit[0] : Power Down (PDN) : Powered down
*/
DAC_REGWRITE(CS4384_MODE_CTRL, 0b11000001);
/* PCM Control (Address: 0x03) */
/* bit[7:4] : Digital Interface Format (DIF) : 0b0001 for I2S up to 24bit
* bit[3:2] : Reserved
* bit[1:0] : Functional Mode (FM) : 0x00 - single-speed mode (4-50kHz)
* : 0x01 - double-speed mode (50-100kHz)
* : 0x10 - quad-speed mode (100-200kHz)
* : 0x11 - auto-speed detect (32 to 200kHz)
* (note, some Mclk/SR ratios not supported in auto)
*
*/
unsigned char regVal = 0;
if(samFreq < 50000)
regVal = 0b00010100;
else if(samFreq < 100000)
regVal = 0b00010101;
else //if(samFreq < 200000)
regVal = 0b00010110;
DAC_REGWRITE(CS4384_PCM_CTRL, regVal);
/* Mode Control 1 (Address: 0x02) */
/* bit[7] : Control Port Enable (CPEN) : Set to 1 for enable
* bit[6] : Freeze controls (FREEZE) : Set to 0 for freeze
* bit[5] : PCM/DSD Selection (DSD/PCM) : Set to 0 for PCM
* bit[4:1] : DAC Pair Disable (DACx_DIS) : All Dac Pairs enabled
* bit[0] : Power Down (PDN) : Not powered down
*/
DAC_REGWRITE(CS4384_MODE_CTRL, 0b10000000);
/* Kill the i2c task */
i2c.shutdown();
return;
}
/* Configures the external audio hardware at startup. Note this runs on Tile[1] */
void AudioHwInit()
{
/* Set USB Mux to micro-b */
/* ADC and DAC in reset */
p_gpio <: P_GPIO_USB_SEL0 | P_GPIO_USB_SEL1;
/* Wait for power supply to come up */
delay_milliseconds(100);
/* Use xCORE Secondary PLL to generate *fixed* master clock */
AppPllEnable_SampleRate(DEFAULT_FREQ);
delay_milliseconds(100);
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
* It holds DAC in reset until it gets clocks anyway.
* Note, this example doesn't use the ADC's
*/
}
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode,
unsigned sampRes_DAC, unsigned sampRes_ADC)
/* Configures the external audio hardware for the required sample frequency */
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
{
i2c_master_if i2c[1];
par
{
i2c_master_single_port(i2c, 1, p_i2c, 10, 0, 1, 0);
AudioHwConfig2(samFreq, mClk, dsdMode, sampRes_DAC, sampRes_ADC, i2c[0]);
}
AppPllEnable_SampleRate(samFreq);
}

View File

@@ -1,88 +0,0 @@
<?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" ManuallySpecifiedRouting="true">
<Type>Board</Type>
<Name>XS2 MC Audio</Name>
<Declarations>
<Declaration>tileref tile[2]</Declaration>
<Declaration>tileref usb_tile</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS2-UnA-512-FB236">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS2-L16A-512" Oscillator="24MHz" SystemFrequency="500MHz" referencefrequency="100MHz">
<Boot>
<Source Location="SPI:bootFlash"/>
</Boot>
<Tile Number="0" Reference="tile[0]">
<Port Location="XS1_PORT_1B" Name="PORT_SQI_CS"/>
<Port Location="XS1_PORT_1C" Name="PORT_SQI_SCLK"/>
<Port Location="XS1_PORT_4B" Name="PORT_SQI_SIO"/>
<!-- Audio Ports -->
<Port Location="XS1_PORT_1A" Name="PORT_PLL_REF"/>
<Port Location="XS1_PORT_1F" Name="PORT_MCLK_IN"/>
<Port Location="XS1_PORT_1G" Name="PORT_I2S_LRCLK"/>
<Port Location="XS1_PORT_1H" Name="PORT_I2S_BCLK"/>
<Port Location="XS1_PORT_1M" Name="PORT_I2S_DAC0"/>
<port Location="XS1_PORT_1N" Name="PORT_I2S_DAC1"/>
<port Location="XS1_PORT_1O" Name="PORT_I2S_DAC2"/>
<port Location="XS1_PORT_1P" Name="PORT_I2S_DAC3"/>
<Port Location="XS1_PORT_1I" Name="PORT_I2S_ADC0"/>
<Port Location="XS1_PORT_1J" Name="PORT_I2S_ADC1"/>
<Port Location="XS1_PORT_1K" Name="PORT_I2S_ADC2"/>
<Port Location="XS1_PORT_1L" Name="PORT_I2S_ADC3"/>
<Port Location="XS1_PORT_4A" Name="PORT_I2C"/>
<Port Location="XS1_PORT_1M" Name="PORT_DSD_DAC0"/>
<port Location="XS1_PORT_1N" Name="PORT_DSD_DAC1"/>
<Port Location="XS1_PORT_1G" Name="PORT_DSD_CLK"/>
<Port Location="XS1_PORT_1E" Name="PORT_ADAT_OUT"/>--> <!-- D: COAX E: OPT -->
<Port Location="XS1_PORT_1D" Name="PORT_SPDIF_OUT"/>--> <!-- D: COAX E: OPT -->
</Tile>
<Tile Number="1" Reference="tile[1]">
<!-- USB intended to run on this tile -->
<!-- Ports for USB feedback calculation -->
<Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT"/>
<Port Location="XS1_PORT_1L" Name="PORT_MCLK_IN_USB"/>
<!-- Audio Ports -->
<Port Location="XS1_PORT_1M" Name="PORT_MIDI_IN"/>
<Port Location="XS1_PORT_1N" Name="PORT_MIDI_OUT"/>
<Port Location="XS1_PORT_1O" Name="PORT_ADAT_IN"/>--> <!-- P: COAX O: OPT -->
<Port Location="XS1_PORT_1P" Name="PORT_SPDIF_IN"/>--> <!-- P: COAX O: OPT -->
</Tile>
</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="2" 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="2" Chanend="1"/>
</Link>
</Links>
<ExternalDevices>
<Device NodeId="0" Tile="0" Class="SQIFlash" Name="bootFlash" Type="S25FL116K" PageSize="256" SectorSize="4096" NumPages="8192">
<Attribute Name="PORT_SQI_CS" Value="PORT_SQI_CS"/>
<Attribute Name="PORT_SQI_SCLK" Value="PORT_SQI_SCLK"/>
<Attribute Name="PORT_SQI_SIO" Value="PORT_SQI_SIO"/>
</Device>
</ExternalDevices>
<JTAGChain>
<JTAGDevice NodeId="0"/>
<JTAGDevice NodeId="1"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,92 @@
<?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>Board</Type>
<Name>xcore.ai MC Audio Board</Name>
<Declarations>
<Declaration>tileref tile[2]</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-FB265">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
<Boot>
<Source Location="bootFlash"/>
</Boot>
<Tile Number="0" Reference="tile[0]">
<Port Location="XS1_PORT_1B" Name="PORT_SQI_CS"/>
<Port Location="XS1_PORT_1C" Name="PORT_SQI_SCLK"/>
<Port Location="XS1_PORT_4B" Name="PORT_SQI_SIO"/>
<!-- Various ctrl signals -->
<Port Location="XS1_PORT_8D" Name="PORT_CTRL"/>
<!-- I2C -->
<Port Location="XS1_PORT_8D" Name="PORT_CTRL"/>
<Port Location="XS1_PORT_8D" Name="PORT_CTRL"/>
<!-- Clocking -->
<Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT"/>
<Port Location="XS1_PORT_1D" Name="PORT_MCLK_IN_USB"/>
<Port Location="XS1_PORT_1A" Name="PORT_PLL_REF"/>
<!-- Audio Ports: Digital -->
<Port Location="XS1_PORT_1O" Name="PORT_ADAT_IN"/> <!-- N: Coax O: Optical -->
<Port Location="XS1_PORT_1N" Name="PORT_SPDIF_IN"/> <!-- N: Coax O: Optical -->
</Tile>
<Tile Number="1" Reference="tile[1]">
<!-- Audio Ports: I2S -->
<Port Location="XS1_PORT_1D" Name="PORT_MCLK_IN"/>
<Port Location="XS1_PORT_1B" Name="PORT_I2S_LRCLK"/>
<Port Location="XS1_PORT_1C" Name="PORT_I2S_BCLK"/>
<Port Location="XS1_PORT_1P" Name="PORT_I2S_DAC0"/>
<port Location="XS1_PORT_1O" Name="PORT_I2S_DAC1"/>
<port Location="XS1_PORT_1N" Name="PORT_I2S_DAC2"/>
<port Location="XS1_PORT_1M" Name="PORT_I2S_DAC3"/>
<Port Location="XS1_PORT_1I" Name="PORT_I2S_ADC0"/>
<Port Location="XS1_PORT_1J" Name="PORT_I2S_ADC1"/>
<Port Location="XS1_PORT_1K" Name="PORT_I2S_ADC2"/>
<Port Location="XS1_PORT_1L" Name="PORT_I2S_ADC3"/>
<!-- Audio Ports: Digital -->
<Port Location="XS1_PORT_1E" Name="PORT_ADAT_OUT"/> <!-- A: Coax E: Optical -->
<Port Location="XS1_PORT_1A" Name="PORT_SPDIF_OUT"/> <!-- A: Coax E: Optical -->
<!-- MIDI -->
<Port Location="XS1_PORT_1F" Name="PORT_MIDI_IN"/>
<Port Location="XS1_PORT_4C" Name="PORT_MIDI_OUT"/> <!-- bit[0] -->
</Tile>
</Node>
</Nodes>
</Package>
</Packages>
<Nodes>
<Node Id="2" 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="5clk" Flags="XSCOPE">
<LinkEndpoint NodeId="0" Link="XL0"/>
<LinkEndpoint NodeId="2" Chanend="1"/>
</Link>
</Links>
<ExternalDevices>
<Device NodeId="0" Tile="0" Class="SQIFlash" Name="bootFlash" PageSize="256" SectorSize="4096" NumPages="8192">
<Attribute Name="PORT_SQI_CS" Value="PORT_SQI_CS"/>
<Attribute Name="PORT_SQI_SCLK" Value="PORT_SQI_SCLK"/>
<Attribute Name="PORT_SQI_SIO" Value="PORT_SQI_SIO"/>
</Device>
</ExternalDevices>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -5,9 +5,9 @@
#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 NUM_USB_CHAN_IN 0 /* 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 I2S_CHANS_ADC 0 /* 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 */

108
examples/shared/apppll.h Normal file
View File

@@ -0,0 +1,108 @@
#include <stdint.h>
#include "xassert.h"
// App PLL setup
#define APP_PLL_CTL_BYPASS (0) // 0 = no bypass, 1 = bypass.
#define APP_PLL_CTL_INPUT_SEL (0) // 0 = XTAL, 1 = sysPLL
#define APP_PLL_CTL_ENABLE (1) // 0 = disabled, 1 = enabled.
// 24MHz in, 24.576MHz out, integer mode
// Found exact solution: IN 24000000.0, OUT 24576000.0, VCO 2457600000.0, RD 5, FD 512, OD 10, FOD 10
#define APP_PLL_CTL_OD_48 (4) // Output divider = (OD+1)
#define APP_PLL_CTL_F_48 (511) // FB divider = (F+1)/2
#define APP_PLL_CTL_R_48 (4) // Ref divider = (R+1)
#define APP_PLL_CTL_48 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
(APP_PLL_CTL_OD_48 << 23) | (APP_PLL_CTL_F_48 << 8) | APP_PLL_CTL_R_48)
// Fractional divide is M/N
#define APP_PLL_FRAC_EN_48 (0) // 0 = disabled
#define APP_PLL_FRAC_NPLUS1_CYCLES_48 (0) // M value is this reg value + 1.
#define APP_PLL_FRAC_TOTAL_CYCLES_48 (0) // N value is this reg value + 1.
#define APP_PLL_FRAC_48 ((APP_PLL_FRAC_EN_48 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_48 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_48)
// 24MHz in, 22.5792MHz out (44.1kHz * 512), frac mode
// Found exact solution: IN 24000000.0, OUT 22579200.0, VCO 2257920000.0, RD 5, FD 470.400 (m = 2, n = 5), OD 5, FOD 10
#define APP_PLL_CTL_OD_441 (4) // Output divider = (OD+1)
#define APP_PLL_CTL_F_441 (469) // FB divider = (F+1)/2
#define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
#define APP_PLL_CTL_441 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
(APP_PLL_CTL_OD_441 << 23) | (APP_PLL_CTL_F_441 << 8) | APP_PLL_CTL_R_441)
#define APP_PLL_FRAC_EN_44 (1) // 1 = enabled
#define APP_PLL_FRAC_NPLUS1_CYCLES_44 (1) // M value is this reg value + 1.
#define APP_PLL_FRAC_TOTAL_CYCLES_44 (4) // N value is this reg value + 1.define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
#define APP_PLL_FRAC_44 ((APP_PLL_FRAC_EN_44 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_44 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_44)
#define APP_PLL_DIV_INPUT_SEL (1) // 0 = sysPLL, 1 = app_PLL
#define APP_PLL_DIV_DISABLE (0) // 1 = disabled (pin connected to X1D11), 0 = enabled divider output to pin.
#define APP_PLL_DIV_VALUE (4) // Divide by N+1 - remember there's a /2 also afterwards for 50/50 duty cycle.
#define APP_PLL_DIV ((APP_PLL_DIV_INPUT_SEL << 31) | (APP_PLL_DIV_DISABLE << 16) | APP_PLL_DIV_VALUE)
/* TODO support more than two freqs..*/
void AppPllEnable(int32_t clkFreq_hz)
{
switch(clkFreq_hz)
{
case 44100*512:
// Disable the PLL
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
// Enable the PLL to invoke a reset on the appPLL.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
// Set the fractional divider if used
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_44);
break;
case 48000*512:
// Disable the PLL
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
// Enable the PLL to invoke a reset on the appPLL.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
// Set the fractional divider if used
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_48);
break;
default:
assert(0);
break;
}
// Wait for PLL output frequency to stabilise due to fractional divider enable
delay_microseconds(100);
// Turn on the clock output
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, APP_PLL_DIV);
}
void AppPllEnable_SampleRate(int32_t sampleRate_hz)
{
assert(sampleRate_hz >= 22050);
if(sampleRate_hz % 22050 == 0)
{
AppPllEnable(44100*512);
}
else
{
AppPllEnable(48000*512);
}
}