This commit is contained in:
Steven Dan
2025-12-11 09:43:42 +08:00
commit d8b2974133
1822 changed files with 280037 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
# The TARGET variable determines what target system the application is
# compiled for. It either refers to an XN file in the source directories
# or a valid argument for the --target option when compiling.
TARGET = xk-audio-316-mc.xn
# The APP_NAME variable determines the name of the final .xe file. It should
# not include the .xe postfix. If left blank the name will default to
# the project name
APP_NAME = app_spdif_loopback
# The flags passed to xcc when building the application
# You can also set the following to override flags for a particular language:
#
# XCC_XC_FLAGS, XCC_C_FLAGS, XCC_ASM_FLAGS, XCC_CPP_FLAGS
#
# If the variable XCC_MAP_FLAGS is set it overrides the flags passed to
# xcc for the final link (mapping) stage.
XCC_FLAGS = -O3 -g
# The USED_MODULES variable lists other module used by the application.
USED_MODULES = lib_spdif lib_xassert
#=============================================================================
# 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

View File

@@ -0,0 +1,2 @@
<xSCOPEconfig ioMode="basic" enabled="true">
</xSCOPEconfig>

View File

@@ -0,0 +1,334 @@
// Copyright 2014-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include <platform.h>
#include <stdint.h>
#include <stddef.h>
#include <spdif.h>
#include <stdio.h>
#include <print.h>
// Change these defines to control optical/coax and set the sample frequency.
#ifndef OPTICAL
#define OPTICAL (0)
#endif
#define SAMPLE_FREQUENCY_HZ (192000)
#if(OPTICAL)
on tile[0]: in port p_spdif_rx = XS1_PORT_1O; // Optical rx
on tile[1]: out buffered port:32 p_spdif_tx = XS1_PORT_1G; // Optical tx
#else
on tile[0]: in port p_spdif_rx = XS1_PORT_1N; // Coaxial rx
on tile[1]: out buffered port:32 p_spdif_tx = XS1_PORT_1A; // Coaxial tx
#endif
on tile[0]: out port p_ctrl = XS1_PORT_8D;
on tile[0]: clock clk_spdif_rx = XS1_CLKBLK_1;
on tile[1]: in port p_mclk_in = XS1_PORT_1D;
on tile[1]: clock clk_spdif_tx = XS1_CLKBLK_1;
#define MCLK_FREQUENCY_48 (24576000)
#define MCLK_FREQUENCY_441 (22579200)
// Found solution: IN 24.000MHz, OUT 24.576000MHz, VCO 2457.60MHz, RD 1, FD 102.400 (m = 2, n = 5), OD 5, FOD 5, ERR 0.0ppm
#define APP_PLL_CTL_24M (0x0A006500)
#define APP_PLL_DIV_24M (0x80000004)
#define APP_PLL_FRAC_24M (0x80000104)
// Found solution: IN 24.000MHz, OUT 22.579186MHz, VCO 3522.35MHz, RD 1, FD 146.765 (m = 13, n = 17), OD 3, FOD 13, ERR -0.641ppm
#define APP_PLL_CTL_22M (0x09009100)
#define APP_PLL_DIV_22M (0x8000000C)
#define APP_PLL_FRAC_22M (0x80000C10)
// One cycle of full scale 24 bit sine wave in 96 samples.
// This will produce 500Hz signal at Fs = 48kHz, 1kHz at 96kHz and 2kHz at 192kHz.
const int32_t sine_table1[96] =
{
0x000000,0x085F21,0x10B515,0x18F8B8,0x2120FB,0x2924ED,0x30FBC5,0x389CEA,
0x3FFFFF,0x471CEC,0x4DEBE4,0x546571,0x5A8279,0x603C49,0x658C99,0x6A6D98,
0x6ED9EB,0x72CCB9,0x7641AE,0x793501,0x7BA374,0x7D8A5E,0x7EE7A9,0x7FB9D6,
0x7FFFFF,0x7FB9D6,0x7EE7A9,0x7D8A5E,0x7BA374,0x793501,0x7641AE,0x72CCB9,
0x6ED9EB,0x6A6D98,0x658C99,0x603C49,0x5A8279,0x546571,0x4DEBE4,0x471CEC,
0x3FFFFF,0x389CEA,0x30FBC5,0x2924ED,0x2120FB,0x18F8B8,0x10B515,0x085F21,
0x000000,0xF7A0DF,0xEF4AEB,0xE70748,0xDEDF05,0xD6DB13,0xCF043B,0xC76316,
0xC00001,0xB8E314,0xB2141C,0xAB9A8F,0xA57D87,0x9FC3B7,0x9A7367,0x959268,
0x912615,0x8D3347,0x89BE52,0x86CAFF,0x845C8C,0x8275A2,0x811857,0x80462A,
0x800001,0x80462A,0x811857,0x8275A2,0x845C8C,0x86CAFF,0x89BE52,0x8D3347,
0x912615,0x959268,0x9A7367,0x9FC3B7,0xA57D87,0xAB9A8F,0xB2141C,0xB8E314,
0xC00001,0xC76316,0xCF043B,0xD6DB13,0xDEDF05,0xE70748,0xEF4AEB,0xF7A0DF
};
// Two cycles of full scale 24 bit sine wave in 96 samples.
// This will produce 1kHz signal at Fs = 48kHz, 2kHz at 96kHz and 4kHz at 192kHz.
const int32_t sine_table2[96] =
{
0x000000,0x10B515,0x2120FB,0x30FBC5,0x3FFFFF,0x4DEBE4,0x5A8279,0x658C99,
0x6ED9EB,0x7641AE,0x7BA374,0x7EE7A9,0x7FFFFF,0x7EE7A9,0x7BA374,0x7641AE,
0x6ED9EB,0x658C99,0x5A8279,0x4DEBE4,0x3FFFFF,0x30FBC5,0x2120FB,0x10B515,
0x000000,0xEF4AEB,0xDEDF05,0xCF043B,0xC00001,0xB2141C,0xA57D87,0x9A7367,
0x912615,0x89BE52,0x845C8C,0x811857,0x800001,0x811857,0x845C8C,0x89BE52,
0x912615,0x9A7367,0xA57D87,0xB2141C,0xC00001,0xCF043B,0xDEDF05,0xEF4AEB,
0x000000,0x10B515,0x2120FB,0x30FBC5,0x3FFFFF,0x4DEBE4,0x5A8279,0x658C99,
0x6ED9EB,0x7641AE,0x7BA374,0x7EE7A9,0x7FFFFF,0x7EE7A9,0x7BA374,0x7641AE,
0x6ED9EB,0x658C99,0x5A8279,0x4DEBE4,0x3FFFFF,0x30FBC5,0x2120FB,0x10B515,
0x000000,0xEF4AEB,0xDEDF05,0xCF043B,0xC00001,0xB2141C,0xA57D87,0x9A7367,
0x912615,0x89BE52,0x845C8C,0x811857,0x800001,0x811857,0x845C8C,0x89BE52,
0x912615,0x9A7367,0xA57D87,0xB2141C,0xC00001,0xCF043B,0xDEDF05,0xEF4AEB
};
void generate_samples(chanend c, chanend c_sync)
{
int mclk;
int exit = 0;
if ((SAMPLE_FREQUENCY_HZ % 44100) == 0)
{
mclk = MCLK_FREQUENCY_441;
}
else
{
mclk = MCLK_FREQUENCY_48;
}
printf("Generating S/PDIF samples at %dHz\n", SAMPLE_FREQUENCY_HZ);
spdif_tx_reconfigure_sample_rate(c,SAMPLE_FREQUENCY_HZ, mclk);
while(!exit)
{
for(int i = 0; i < (sizeof(sine_table1)/sizeof(sine_table1[0])); i++)
{
// Generate a sine wave
int sample_l = sine_table1[i] << 8;
int sample_r = sine_table2[i] << 8; // Twice the frequency on right channel.
spdif_tx_output(c, sample_l, sample_r);
}
/* Check for exit */
select
{
case c_sync :> int tmp:
exit = 1;
break;
default:
break;
}
}
}
// Set secondary (App) PLL control register
void set_app_pll_init (tileref tile, int app_pll_ctl)
{
// Disable the PLL
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (app_pll_ctl & 0xF7FFFFFF));
// Enable the PLL to invoke a reset on the appPLL.
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctl);
// 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, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctl);
// 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, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (app_pll_ctl & 0xF7FFFFFF));
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctl);
// Wait for PLL to lock.
delay_microseconds(500);
}
void app_pll_setup(void)
{
if ((SAMPLE_FREQUENCY_HZ % 44100) == 0)
{
set_app_pll_init(tile[0], APP_PLL_CTL_22M);
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_22M);
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, APP_PLL_DIV_22M);
}
else
{
set_app_pll_init(tile[0], APP_PLL_CTL_24M);
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_24M);
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, APP_PLL_DIV_24M);
}
delay_milliseconds(10);
}
#pragma unsafe arrays
void handle_samples(streaming chanend c, chanend c_sync)
{
unsigned tmp;
unsigned outwords[20000] = {0};
// Check for a stream of alternating preambles before trying decode.
int alt_pre_count = 0;
while(alt_pre_count < 128)
{
c :> tmp;
if ((tmp & SPDIF_RX_PREAMBLE_MASK) == SPDIF_FRAME_X) // X
{
c :> tmp;
if ((tmp & SPDIF_RX_PREAMBLE_MASK) == SPDIF_FRAME_Y) // Y
alt_pre_count++;
else
alt_pre_count = 0;
}
else
{
alt_pre_count = 0;
}
}
// Collecting samples
for(int i = 0; i<20000;i++)
{
c :> tmp;
outwords[i] = tmp;
}
#define CHAN_STAT_44100 (0x00000000)
#define CHAN_STAT_48000 (0x02000000)
#define CHAN_STAT_88200 (0x08000000)
#define CHAN_STAT_96000 (0x0A000000)
#define CHAN_STAT_176400 (0x0C000000)
#define CHAN_STAT_192000 (0x0E000000)
// Known channel status block data. Needs sample rate bits OR'ing in.
unsigned cs_block_l[6] = {0x00107A04, 0x0000000B, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
unsigned cs_block_r[6] = {0x00207A04, 0x0000000B, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
// Or in the sampling frequency bits into the channel status block.
switch(SAMPLE_FREQUENCY_HZ)
{
//case 32000:
case 44100: cs_block_l[0] |= CHAN_STAT_44100; cs_block_r[0] |= CHAN_STAT_44100; break;
case 48000: cs_block_l[0] |= CHAN_STAT_48000; cs_block_r[0] |= CHAN_STAT_48000; break;
case 88200: cs_block_l[0] |= CHAN_STAT_88200; cs_block_r[0] |= CHAN_STAT_88200; break;
case 96000: cs_block_l[0] |= CHAN_STAT_96000; cs_block_r[0] |= CHAN_STAT_96000; break;
case 176400: cs_block_l[0] |= CHAN_STAT_176400; cs_block_r[0] |= CHAN_STAT_176400; break;
case 192000: cs_block_l[0] |= CHAN_STAT_192000; cs_block_r[0] |= CHAN_STAT_192000; break;
default: cs_block_l[0] |= CHAN_STAT_44100; cs_block_r[0] |= CHAN_STAT_44100; break;
}
// Manually parse the output words to look for errors etc.
// Based on known TX samples.
unsigned errors = 0;
unsigned ok = 0;
unsigned block_count = 0;
unsigned block_size_errors = 0;
int i_last =0;
for(int i=0; i<20000; i++)
{
unsigned pre = outwords[i] & SPDIF_RX_PREAMBLE_MASK;
if (pre == SPDIF_FRAME_Z) // Z preamble
{
if (i+384 >= 20000)
break;
if (block_count > 0)
{
if ((i-i_last) != 384)
{
printf("Error - Block not 384 samples in length\n");
block_size_errors++;
}
}
block_count++;
i_last = i;
unsigned expected = 0;
unsigned rx_word;
unsigned expected_cs_bit;
unsigned expected_parity_bit;
for(int j=0; j<384;j++)
{
rx_word = outwords[i+j];
unsigned index = j/2;
if (j%2 == 0) // Even
{
if (j == 0)
expected = (sine_table1[index % 96] << 4) | SPDIF_FRAME_Z;
else
expected = (sine_table1[index % 96] << 4) | SPDIF_FRAME_X;
expected_cs_bit = (cs_block_l[index/32] & (0x1 << (index%32))) >> (index%32);
}
else // Odd
{
expected = (sine_table2[index % 96] << 4) | SPDIF_FRAME_Y;
expected_cs_bit = (cs_block_r[index/32] & (0x1 << (index%32))) >> (index%32);
}
expected |= expected_cs_bit << 30;
expected_parity_bit = spdif_rx_check_parity(expected); // Parity is over all bits excluding preamble.
expected |= expected_parity_bit << 31;
// Note in tx stream, Validity and User bits both 0.
unsigned checkword = rx_word & (0xFFFFFFF0 | SPDIF_RX_PREAMBLE_MASK);
if (checkword != expected)
{
errors++;
//printf("Error checkword 0x%08X, expected 0x%08X, i %d, j %d\n", checkword, expected, i, j);
}
else
{
ok++;
//printf("OK checkword 0x%08X, expected 0x%08X, i %d, j %d\n", checkword, expected, i, j);
}
}
}
}
printf("Checked %d channel status blocks of samples. Expected number of samples = %d.\n", block_count, (block_count*384));
printf("Error count %d, block size errors %d, ok samples count %d\n", errors, block_size_errors, ok);
/* Inform generate task that this task has finished */
c_sync <: (int) 1;
}
void board_setup(void)
{
set_port_drive_high(p_ctrl);
// Drive control port to turn on 3V3.
// Bits set to low will be high-z, pulled down.
p_ctrl <: 0xA0;
// Wait for power supplies to be up and stable.
delay_milliseconds(10);
}
int main(void)
{
chan c_spdif_tx;
streaming chan c_spdif_rx;
chan c_sync;
par
{
on tile[0]:
{
board_setup();
app_pll_setup();
spdif_rx(c_spdif_rx, p_spdif_rx, clk_spdif_rx, SAMPLE_FREQUENCY_HZ);
}
on tile[0]:
{
handle_samples(c_spdif_rx, c_sync);
spdif_rx_shutdown(c_spdif_rx);
}
on tile[1]:
{
spdif_tx_port_config(p_spdif_tx, clk_spdif_tx, p_mclk_in, 0);
start_clock(clk_spdif_tx);
spdif_tx(p_spdif_tx, c_spdif_tx);
}
on tile[1]:
{
generate_samples(c_spdif_tx, c_sync);
spdif_tx_shutdown(c_spdif_tx);
}
}
return 0;
}

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_1L" Name="PORT_I2C_SCL"/>
<Port Location="XS1_PORT_1M" Name="PORT_I2C_SDA"/>
<!-- 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_1G" Name="PORT_ADAT_OUT"/> <!-- A: Coax G: Optical -->
<Port Location="XS1_PORT_1A" Name="PORT_SPDIF_OUT"/> <!-- A: Coax G: 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

@@ -0,0 +1,33 @@
# The TARGET variable determines what target system the application is
# compiled for. It either refers to an XN file in the source directories
# or a valid argument for the --target option when compiling.
TARGET = xk-audio-316-mc.xn
# The APP_NAME variable determines the name of the final .xe file. It should
# not include the .xe postfix. If left blank the name will default to
# the project name
APP_NAME = app_example_rx
# The flags passed to xcc when building the application
# You can also set the following to override flags for a particular language:
#
# XCC_XC_FLAGS, XCC_C_FLAGS, XCC_ASM_FLAGS, XCC_CPP_FLAGS
#
# If the variable XCC_MAP_FLAGS is set it overrides the flags passed to
# xcc for the final link (mapping) stage.
XCC_FLAGS = -O2 -g -DDEBUG_PRINT_ENABLE=1
# The USED_MODULES variable lists other module used by the application.
USED_MODULES = lib_spdif lib_logging
#=============================================================================
# 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

View File

@@ -0,0 +1,2 @@
<xSCOPEconfig ioMode="basic" enabled="true">
</xSCOPEconfig>

View File

@@ -0,0 +1,76 @@
// Copyright 2014-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include <platform.h>
#include <stdint.h>
#include <stddef.h>
#include <spdif.h>
#include <debug_print.h>
on tile[0]: out port p_ctrl = XS1_PORT_8D;
on tile[0]: in port p_i2c_sda = XS1_PORT_1M;
on tile[0]: in port p_coax_rx = XS1_PORT_1N;
on tile[0]: in port p_opt_rx = XS1_PORT_1O;
on tile[0]: in port p_word_clk = XS1_PORT_1P;
on tile[0]: clock audio_clk = XS1_CLKBLK_1;
void handle_samples(streaming chanend c)
{
int32_t sample;
size_t index;
int32_t left_count = 0;
int32_t right_count = 0;
while(1)
{
select
{
case spdif_rx_sample(c, sample, index):
// sample contains the 24bit data
// You can process the audio data here
if (index == 0)
left_count++;
else
right_count++;
break;
}
int32_t total = left_count + right_count;
if (total % 10000 == 0)
{
debug_printf("Received %u left samples and %u right samples\n",
left_count,
right_count);
}
}
}
void board_setup(void)
{
// Define other tile 0 ports as inputs to avoid driving them when writing to 8 bit port.
p_i2c_sda :> void;
p_coax_rx :> void;
p_opt_rx :> void;
p_word_clk :> void;
// Drive control port to turn on 3V3 and set MCLK_DIR/EXT_PLL_SEL to select App PLL.
p_ctrl <: 0xA0;
// Wait for power supplies to be up and stable.
delay_milliseconds(10);
}
int main(void)
{
streaming chan c;
par {
on tile[0]: {
board_setup();
spdif_rx(c, p_coax_rx, audio_clk, 96000);
}
on tile[0]: handle_samples(c);
}
return 0;
}

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_1L" Name="PORT_I2C_SCL"/>
<Port Location="XS1_PORT_1M" Name="PORT_I2C_SDA"/>
<!-- 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_1G" Name="PORT_ADAT_OUT"/> <!-- A: Coax G: Optical -->
<Port Location="XS1_PORT_1A" Name="PORT_SPDIF_OUT"/> <!-- A: Coax G: 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

@@ -0,0 +1,33 @@
# The TARGET variable determines what target system the application is
# compiled for. It either refers to an XN file in the source directories
# or a valid argument for the --target option when compiling.
TARGET = xk-audio-316-mc.xn
# The APP_NAME variable determines the name of the final .xe file. It should
# not include the .xe postfix. If left blank the name will default to
# the project name
APP_NAME =
# The flags passed to xcc when building the application
# You can also set the following to override flags for a particular language:
#
# XCC_XC_FLAGS, XCC_C_FLAGS, XCC_ASM_FLAGS, XCC_CPP_FLAGS
#
# If the variable XCC_MAP_FLAGS is set it overrides the flags passed to
# xcc for the final link (mapping) stage.
XCC_FLAGS = -O2 -g
# The USED_MODULES variable lists other module used by the application.
USED_MODULES = lib_spdif lib_xassert
#=============================================================================
# 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

View File

@@ -0,0 +1,6 @@
app_example_tx
==============
:scope: General Use
:description: app_example_tx

View File

@@ -0,0 +1,129 @@
// Copyright 2014-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include <platform.h>
#include <spdif.h>
#include <xassert.h>
on tile[0]: out port p_ctrl = XS1_PORT_8D;
on tile[0]: in port p_i2c_sda = XS1_PORT_1M;
on tile[0]: in port p_coax_rx = XS1_PORT_1N;
on tile[0]: in port p_opt_rx = XS1_PORT_1O;
on tile[0]: in port p_word_clk = XS1_PORT_1P;
on tile[1]: out buffered port:32 p_spdif_tx = XS1_PORT_1A;
on tile[1]: in port p_mclk_in = XS1_PORT_1D;
on tile[1]: clock clk_audio = XS1_CLKBLK_1;
// Found solution: IN 24.000MHz, OUT 24.576000MHz, VCO 2457.60MHz, RD 1, FD 102.400 (m = 2, n = 5), OD 5, FOD 5, ERR 0.0ppm
// Measure: 100Hz-40kHz: ~8ps
// 100Hz-1MHz: 63ps.
// 100Hz high pass: 127ps.
#define APP_PLL_CTL_24M 0x0A006500
#define APP_PLL_DIV_24M 0x80000004
#define APP_PLL_FRAC_24M 0x80000104
#define SAMPLE_FREQUENCY_HZ 96000
#define MCLK_FREQUENCY_48 24576000
#define SINE_TABLE_SIZE 100
const int32_t sine_table[SINE_TABLE_SIZE] =
{
0x0100da00,0x0200b000,0x02fe8100,0x03f94b00,0x04f01100,
0x05e1da00,0x06cdb200,0x07b2aa00,0x088fdb00,0x09646600,
0x0a2f7400,0x0af03700,0x0ba5ed00,0x0c4fde00,0x0ced5f00,
0x0d7dd100,0x0e00a100,0x0e754b00,0x0edb5a00,0x0f326700,
0x0f7a1800,0x0fb22700,0x0fda5b00,0x0ff28a00,0x0ffa9c00,
0x0ff28a00,0x0fda5b00,0x0fb22700,0x0f7a1800,0x0f326700,
0x0edb5a00,0x0e754b00,0x0e00a100,0x0d7dd100,0x0ced5f00,
0x0c4fde00,0x0ba5ed00,0x0af03700,0x0a2f7400,0x09646600,
0x088fdb00,0x07b2aa00,0x06cdb200,0x05e1da00,0x04f01100,
0x03f94b00,0x02fe8100,0x0200b000,0x0100da00,0x00000000,
0xfeff2600,0xfdff5000,0xfd017f00,0xfc06b500,0xfb0fef00,
0xfa1e2600,0xf9324e00,0xf84d5600,0xf7702500,0xf69b9a00,
0xf5d08c00,0xf50fc900,0xf45a1300,0xf3b02200,0xf312a100,
0xf2822f00,0xf1ff5f00,0xf18ab500,0xf124a600,0xf0cd9900,
0xf085e800,0xf04dd900,0xf025a500,0xf00d7600,0xf0056400,
0xf00d7600,0xf025a500,0xf04dd900,0xf085e800,0xf0cd9900,
0xf124a600,0xf18ab500,0xf1ff5f00,0xf2822f00,0xf312a100,
0xf3b02200,0xf45a1300,0xf50fc900,0xf5d08c00,0xf69b9a00,
0xf7702500,0xf84d5600,0xf9324e00,0xfa1e2600,0xfb0fef00,
0xfc06b500,0xfd017f00,0xfdff5000,0xfeff2600,0x00000000,
};
void generate_samples(chanend c) {
int i = 0;
spdif_tx_reconfigure_sample_rate(c,
SAMPLE_FREQUENCY_HZ,
MCLK_FREQUENCY_48);
while(1) {
// Generate a sine wave
int sample = sine_table[i];
i = (i + 1) % SINE_TABLE_SIZE;
spdif_tx_output(c, sample, sample);
}
}
// Set secondary (App) PLL control register
void set_app_pll_init (tileref tile, int app_pll_ctl)
{
// delay_microseconds(500);
// Disable the PLL
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (app_pll_ctl & 0xF7FFFFFF));
// Enable the PLL to invoke a reset on the appPLL.
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctl);
// 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, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctl);
// 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, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (app_pll_ctl & 0xF7FFFFFF));
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctl);
// Wait for PLL to lock.
delay_microseconds(500);
}
void app_pll_setup(void)
{
set_app_pll_init(tile[0], APP_PLL_CTL_24M);
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_24M);
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, APP_PLL_DIV_24M);
}
void board_setup(void)
{
//////// BOARD SETUP ////////
// Define other tile 0 ports as inputs to avoid driving them when writing to 8 bit port.
p_i2c_sda :> void;
p_coax_rx :> void;
p_opt_rx :> void;
p_word_clk :> void;
// Drive control port to turn on 3V3 and set MCLK_DIR/EXT_PLL_SEL to select App PLL.
p_ctrl <: 0xA0;
// Wait for power supplies to be up and stable.
delay_milliseconds(10);
/////////////////////////////
}
int main(void) {
chan c_spdif;
par
{
on tile[0]: {
board_setup();
app_pll_setup();
while(1) {};
}
on tile[1]: {
spdif_tx_port_config(p_spdif_tx, clk_audio, p_mclk_in, 7);
start_clock(clk_audio);
spdif_tx(p_spdif_tx, c_spdif);
}
on tile[1]: generate_samples(c_spdif);
}
return 0;
}

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_1L" Name="PORT_I2C_SCL"/>
<Port Location="XS1_PORT_1M" Name="PORT_I2C_SDA"/>
<!-- 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_1G" Name="PORT_ADAT_OUT"/> <!-- A: Coax G: Optical -->
<Port Location="XS1_PORT_1A" Name="PORT_SPDIF_OUT"/> <!-- A: Coax G: 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>