- Improved audio performance in synchronous mode when using the App PLL

- Software PLL code now uses a core rather than running entirely in XUA_Buffer_EP()
This commit is contained in:
Ross Owen
2023-08-01 15:56:00 +01:00
parent 77fad35497
commit a7943a8859
7 changed files with 313 additions and 129 deletions

View File

@@ -12,6 +12,8 @@
#include "dfu_interface.h"
#endif
#include "xua_clocking.h"
/** The audio driver thread.
*
* This function drives I2S ports and handles samples to/from other digital
@@ -34,6 +36,8 @@
*
* \param p_i2s_adc Nullable array of ports for I2S data input lines
*
* \param i_SoftPll Interface to software PLL task
*
* \param c_spdif_tx Channel connected to S/PDIF transmiter core from lib_spdif
*
* \param c_dig Channel connected to the clockGen() thread for
@@ -47,6 +51,9 @@ void XUA_AudioHub(chanend ?c_aud,
buffered _XUA_CLK_DIR port:32 ?p_bclk,
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, client interface SoftPll_if i_SoftPll
#endif
#if (XUA_SPDIF_TX_EN) || defined(__DOXYGEN__)
, chanend c_spdif_tx
#endif

View File

@@ -26,6 +26,7 @@
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
* \param c_aud Channel connected to XUA_AudioHub() core
* \param i_pll_ref Interface to task that toggles reference pin to CS2100
* \param c_swpll_update Channel connected to software PLL task. Expects master clock counts based on USB frames.
*/
void XUA_Buffer(
chanend c_aud_out,
@@ -51,8 +52,13 @@ void XUA_Buffer(
, chanend c_hid
#endif
, chanend c_aud
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL) || defined(__DOXYGEN__)
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
#if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, client interface pll_ref_if i_pll_ref
#endif
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, chanend c_swpll_update
#endif
#endif
);
@@ -81,10 +87,16 @@ void XUA_Buffer_Ep(chanend c_aud_out,
#ifdef CHAN_BUFF_CTRL
, chanend c_buff_ctrl
#endif
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL) || defined(__DOXYGEN__)
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
#if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, client interface pll_ref_if i_pll_ref
#endif
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, chanend c_swpll_update
#endif
#endif
);
);
/** Manage the data transfer between the USB audio buffer and the
* Audio I/O driver.

View File

@@ -31,18 +31,35 @@ void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_sync);
void clockGen(streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interface pll_ref_if i_pll_ref, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int);
#if (XUA_USE_APP_PLL)
struct PllSettings
struct SoftPllState
{
// Count we expect on MCLK port timer at SW PLL check point.
// Note, we expect wrapping so this is essentiually a modulus
unsigned adder;
unsigned fracIdx;
int firstUpdate;
unsigned expectedClkMod;
unsigned initialSetting;
unsigned setting;
unsigned firstUpdate;
unsigned ds_in;
int ds_fb;
int ds_x1;
int ds_x2;
};
void AppPllEnable(tileref tile, int mclkFreq_hz);
void AppPllGetSettings(int clkFreq_hz, struct PllSettings &pllSettings);
void AppPllUpdate(tileref tile, unsigned short mclk_pt, struct PllSettings &pllSettings);
void AppPllGetSettings(int clkFreq_hz, struct SoftPllState &pllState);
void AppPllUpdate(tileref tile, unsigned short mclk_pt, struct SoftPllState &pllState);
interface SoftPll_if
{
void init(int mclk_hz);
};
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
[[distributable]]
#endif
void XUA_SoftPll(tileref tile, server interface SoftPll_if i_softPll, chanend c_update);
#endif
#endif

View File

@@ -636,6 +636,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
buffered _XUA_CLK_DIR port:32 ?p_bclk,
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]
#if (XUA_USE_APP_PLL)
, client interface SoftPll_if i_softPll
#endif
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
, chanend c_spdif_out
#endif
@@ -663,6 +666,12 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
unsigned divide;
unsigned firstRun = 1;
#if (XUA_USE_APP_PLL)
/* Use xCORE.ai Secondary PLL to generate master clock
* This could be "fixed" for async mode or adjusted if in sync mode */
i_softPll.init(DEFAULT_MCLK);
#endif
/* Clock master clock-block from master-clock port */
/* Note, marked unsafe since other cores may be using this mclk port */
configure_clock_src(clk_audio_mclk, p_mclk_in);
@@ -688,11 +697,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
#endif
#endif
#if (XUA_USE_APP_PLL)
/* Use xCORE.ai Secondary PLL to generate master clock
* This could be "fixed" for async mode or adjusted if in sync mode */
AppPllEnable(tile[AUDIO_IO_TILE], DEFAULT_MCLK);
#endif
/* Perform required CODEC/ADC/DAC initialisation */
AudioHwInit();
@@ -810,7 +815,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
AudioHwConfig_Mute();
#if (XUA_USE_APP_PLL)
AppPllEnable(tile[AUDIO_IO_TILE], mClk);
i_softPll.init(mClk);
#endif
/* User code should configure audio harware for SampleFreq/MClk etc */

View File

@@ -10,6 +10,9 @@
#include "xud.h"
#include "testct_byref.h"
on tile[0] : out port p_test = XS1_PORT_1A;
int tog = 0;
#if XUA_HID_ENABLED
#include "xua_hid_report.h"
#include "user_hid.h"
@@ -104,8 +107,12 @@ void XUA_Buffer(
, chanend c_hid
#endif
, chanend c_aud
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL)
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
#if(XUA_USE_APP_PLL)
, chanend c_swpll_update
#else
, client interface pll_ref_if i_pll_ref
#endif
#endif
)
{
@@ -140,8 +147,12 @@ void XUA_Buffer(
#ifdef CHAN_BUFF_CTRL
, c_buff_ctrl
#endif
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL)
, i_pll_ref
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
#if(XUA_USE_APP_PLL)
, c_swpll_update
#else
, i_pll_ref
#endif
#endif
);
@@ -190,8 +201,12 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#ifdef CHAN_BUFF_CTRL
, chanend c_buff_ctrl
#endif
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL)
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
#if (XUA_USE_APP_PLL)
, chanend c_swpll_update
#else
, client interface pll_ref_if i_pll_ref
#endif
#endif
)
{
@@ -295,7 +310,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
unsigned iap_ea_native_interface_alt_setting = 0;
unsigned iap_ea_native_control_to_send = 0;
unsigned iap_ea_native_incoming = 0;
#endif
#endif
@@ -359,10 +373,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#define LOCAL_CLOCK_MARGIN (1000)
#endif
#if (XUA_USE_APP_PLL)
struct PllSettings pllSettings;
AppPllGetSettings(DEFAULT_MCLK, pllSettings);
#else
#if (!XUA_USE_APP_PLL)
timer t_sofCheck;
unsigned timeLastEdge;
unsigned timeNextEdge;
@@ -458,10 +469,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
{
masterClockFreq = MCLK_441;
}
#if (XUA_USE_APP_PLL && (XUA_SYNCMODE == XUA_SYNCMODE_SYNC))
AppPllGetSettings(masterClockFreq, pllSettings);
#endif
}
#endif
/* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this
@@ -515,7 +522,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
}
#endif
/* Pass on sample freq change to decouple() via global flag (saves a chanend) */
/* Note: freqChange flags now used to communicate other commands also */
/* Note: freqChange_flag now used to communicate other commands also */
SET_SHARED_GLOBAL0(g_freqChange, cmd); /* Set command */
SET_SHARED_GLOBAL(g_freqChange_flag, cmd); /* Set Flag */
}
@@ -567,9 +574,10 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
pllUpdate = 0;
unsigned short mclk_pt;
asm volatile("getts %0, res[%1]" : "=r" (mclk_pt) : "r" (p_off_mclk));
// TODO on a change of SR we don't want to run this before audiohub has set the PLL to the new freq
AppPllUpdate(tile[XUD_TILE], mclk_pt, pllSettings);
outuint(c_swpll_update, mclk_pt);
outct(c_swpll_update, XS1_CT_END);
p_test <: tog;
tog = !tog;
}
#endif

View File

@@ -19,19 +19,35 @@
* App PLL settings used for syncing to external clocks
*/
#include "fractions_80_top.h"
// Found solution: IN 24.000MHz, OUT 24.575758MHz, VCO 3244.00MHz, RD 3, FD 405.500 (m = 1, n = 2), OD 3, FOD 11, ERR -9.864ppm
#define APP_PLL_CTL_SYNC_24M (0x09019402)
#define APP_PLL_DIV_SYNC_24M (0x8000000A)
#define APP_PLL_FRAC_SYNC_24M (0x80000001)
// This can do +350ppm.
//Found solution: IN 24.000MHz, OUT 22.579211MHz, VCO 3070.77MHz, RD 2, FD 255.898 (m = 79, n = 88), OD 2, FOD 17, ERR 0.497ppm
#define APP_PLL_CTL_SYNC_22M (0x0880FE01)
#define APP_PLL_DIV_SYNC_22M (0x80000010)
#define APP_PLL_F_INDEX_SYNC_22M (193)
// Fout = (Fin/3)*divider/(2*2*3*11) = (fin/396) * divider = (24/396) * divider. = 2/33 * divider.
// Total freq tune range = ((406/405) - 1) * 1000000 ppm = 2469ppm.
// Step size: 2469/2^20 ~= 2.4ppb.
// Setting of 0 (0x000000) => Divide of 405. Output freq = (2/33) * 405 = 24.545MHz. This is -1244ppm from ideal 24.576MHz.
// Setting of 1 (0xFFFFFF) => Divide of 406. Output freq = (2/33) * 406 = 24.606MHz. This is +1223ppm from ideal 24.576MHz.
//This can do +256ppm.
//Found solution: IN 24.000MHz, OUT 24.576007MHz, VCO 3538.95MHz, RD 2, FD 294.912 (m = 83, n = 91), OD 3, FOD 12, ERR 0.298ppm
#define APP_PLL_CTL_SYNC_24M (0x09012501)
#define APP_PLL_DIV_SYNC_24M (0x8000000B)
#define APP_PLL_F_INDEX_SYNC_24M (220)
// To achieve frequency f, Fraction Setting = ((33/2)*f) - 405
// So to achieve 24.576MHz, Fraction Setting = (16.5*24.576) - 405 = 0.504
// Numerical input = round((Fraction setting * 2^20) = 0.504 * 1048576 = 528482 = 0x81062.
// Found solution: IN 24.000MHz, OUT 22.579365MHz, VCO 3251.43MHz, RD 3, FD 406.429 (m = 3, n = 7), OD 6, FOD 6, ERR 7.311ppm
#define APP_PLL_CTL_SYNC_22M (0x0A819502)
#define APP_PLL_DIV_SYNC_22M (0x80000005)
#define APP_PLL_FRAC_SYNC_22M (0x80000206)
// Fout = (Fin/3)*divider/(2*2*3*11) = (fin/396) * divider = (24/396) * divider. = 2/33 * divider.
// Total freq tune range = ((406/405) - 1) * 1000000 ppm = 2469ppm.
// Step size: 2469/2^20 ~= 2.4ppb.
// Setting of 0 (0x000000) => Divide of 405. Output freq = (2/33) * 405 = 24.545MHz. This is -1244ppm from ideal 24.576MHz.
// Setting of 1 (0xFFFFFF) => Divide of 406. Output freq = (2/33) * 406 = 24.606MHz. This is +1223ppm from ideal 24.576MHz.
// To achieve frequency f, Fraction Setting = ((33/2)*f) - 405
// So to achieve 24.576MHz, Fraction Setting = (16.5*24.576) - 405 = 0.504
// Numerical input = round((Fraction setting * 2^20) = 0.504 * 1048576 = 528482 = 0x81062.
/*
* App PLL settings used for low jitter fixed local clocks
@@ -99,30 +115,7 @@ static void set_app_pll_init(tileref tile, int app_pll_ctrl)
delay_microseconds(500);
}
void AppPllGetSettings(int clkFreq_hz, struct PllSettings &pllSettings)
{
pllSettings.firstUpdate = 1;
switch(clkFreq_hz)
{
case 44100 * 512:
pllSettings.fracIdx = APP_PLL_F_INDEX_SYNC_22M;
pllSettings.adder = 29184;
break;
case 48000 * 512:
pllSettings.fracIdx = APP_PLL_F_INDEX_SYNC_24M;
pllSettings.adder = 49152;
break;
default:
assert(0);
break;
}
}
//unsigned sw_pll_adder;
//unsigned app_pll_frac_i;
void AppPllEnable(tileref tile, int clkFreq_hz)
{
@@ -136,17 +129,13 @@ void AppPllEnable(tileref tile, int clkFreq_hz)
case 44100 * 512:
app_pll_ctrl = APP_PLL_CTL_SYNC_22M;
app_pll_div = APP_PLL_DIV_SYNC_22M;
//app_pll_frac_i = APP_PLL_F_INDEX_SYNC_22M;
app_pll_frac = frac_values_80[APP_PLL_F_INDEX_SYNC_22M];
//sw_pll_adder = 29184; // Count we expect on MCLK port timer at SW PLL check point. Note, we expect wrapping so this is essentiually a modulus
app_pll_frac = APP_PLL_FRAC_SYNC_22M;
break;
case 48000 * 512:
app_pll_ctrl = APP_PLL_CTL_SYNC_24M;
app_pll_div = APP_PLL_DIV_SYNC_24M;
//app_pll_frac_i = APP_PLL_F_INDEX_SYNC_24M;
app_pll_frac = frac_values_80[APP_PLL_F_INDEX_SYNC_24M];
//sw_pll_adder = 49152;
app_pll_frac = APP_PLL_FRAC_SYNC_24M;
break;
default:
@@ -203,85 +192,208 @@ void AppPllEnable(tileref tile, int clkFreq_hz)
// Initialise the AppPLL and get it running.
set_app_pll_init(tile, app_pll_ctrl);
// Write the fractional-n register
// Set the top bit to enable the frac-n block.
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, (0x80000000 | app_pll_frac));
// Write the fractional-n register, note, the top bit is set to enable the frac-n block.
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, app_pll_frac);
// And then write the clock divider register to enable the output
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, app_pll_div);
// Wait for PLL output frequency to stabilise due to fractional divider enable
delay_microseconds(100);
// Write the clock divider register to enable the output
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, app_pll_div);
}
void AppPllUpdate(tileref tile, unsigned short mclk_pt, struct PllSettings &pllSettings)
void SoftPllInit(int clkFreq_hz, struct SoftPllState &pllState)
{
static int mclk_pt_last;
static int oldsetting = 0;
static int cum_error = 0;
unsigned sw_pll_adder = pllSettings.adder;
unsigned app_pll_frac_i = pllSettings.fracIdx;
const int Kp = 0;
const int Ki = 1;
int error, error_p, error_i;
unsigned short expected_pt;
if(pllSettings.firstUpdate)
switch(clkFreq_hz)
{
mclk_pt_last = mclk_pt; // load last mclk measurement with sensible data
pllSettings.firstUpdate = 0;
case 44100 * 512:
pllState.expectedClkMod = 29184;
pllState.initialSetting = 0x6CF42;
break;
case 48000 * 512:
pllState.expectedClkMod = 49152;
pllState.initialSetting = 0x81062;
break;
default:
assert(0);
break;
}
pllState.firstUpdate = 1;
pllState.ds_in = pllState.initialSetting;
pllState.ds_fb = 0;
pllState.ds_x1 = 0;
pllState.ds_x2 = 0;
}
int SoftPllUpdate(tileref tile, unsigned short mclk_pt, unsigned short mclk_pt_last, struct SoftPllState &pllState)
{
static int int_error = 0;
unsigned expectedClksMod = pllState.expectedClkMod;
unsigned initialSetting = pllState.initialSetting;
// TODO These values need revisiting
const int Kp = 0;
const int Ki = 32;
int newsetting;
int abs_error, error_p, error_i;
unsigned short expectedPt;
int set = -1;
int diff;
// expectedClkMod is the value of the port counter that we expect given the desired MCLK in the 10ms time period we are running at.
expectedPt = mclk_pt_last + expectedClksMod;
// Handle wrapping
if (porttimeafter(mclk_pt, expectedPt))
{
diff = -(short)(expectedPt - mclk_pt);
}
else
{
int diff;
diff = (short)(mclk_pt - expectedPt);
}
// sw_pll_adder is the value of the port counter that we expect given the desired MCLK in the 10ms time period we are running at.
expected_pt = mclk_pt_last + sw_pll_adder;
// TODO Add a bounds checker on diff to make sure it's roughly where we expect.
// If it isn't we should ignore it as it's either a glitch or from clock start/stop.
// Handle wrapping
if (porttimeafter(mclk_pt, expected_pt))
// Absolute error for last measurement cycle. If diff is positive, port timer was beyond where it should have been, so MCLK was too fast. So this needs to describe a negative error.
abs_error = -diff;
int_error = int_error + abs_error; // Integral error.
error_p = (Kp * abs_error);
error_i = (Ki * int_error);
newsetting = (error_p + error_i);
// Only output new frequency tune value if different to the previous setting
if (newsetting != pllState.setting)
{
set = (initialSetting + newsetting); // init_set is the value to feed into the NCO to give the "expected" frequency (24.576 or 22.5792). Not required but will make lock faster.
if (set < 0)
set = 0;
else if (set > 0xFFFFF)
set = 0xFFFFF;
}
pllState.setting = newsetting;
// Return the setting to the NCO thread. -1 means no update
return set;
}
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
[[distributable]]
#endif
void XUA_SoftPll(tileref tile, server interface SoftPll_if i_softPll, chanend c_update)
{
unsigned ds_out;
timer tmr;
int time;
unsigned mclk_pt;
unsigned short mclk_pt_last;
struct SoftPllState pllState;
int running = 0;
int firstUpdate = 1;
tmr :> time;
while(1)
{
select
{
diff = -(short)(expected_pt - mclk_pt);
/* Interface used for basic frequency setting such that it can be distributed
* when the update code is not required */
case i_softPll.init(int mclk_hz):
AppPllEnable(tile, mclk_hz);
SoftPllInit(mclk_hz, pllState);
running = 1;
firstUpdate = 1;
break;
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
}
}
}
#else
/* Channel used for update such that other side is not blocked */
/* TODO add CT handshake before opening route */
case inuint_byref(c_update, mclk_pt):
inct(c_update);
if(firstUpdate)
{
firstUpdate = 0;
}
else
{
int setting = SoftPllUpdate(tile, (unsigned short) mclk_pt, mclk_pt_last, pllState);
if(setting != -1)
{
pllState.ds_in = setting;
pllState.ds_in = pllState.ds_in & 0x000FFFFF; // Ensure input is limited to 20 bits
}
}
mclk_pt_last = (unsigned short) mclk_pt;
break;
default :
break;
}
// Second order, Single bit delta sigma - mod2
pllState.ds_x1 += pllState.ds_in - pllState.ds_fb;
pllState.ds_x2 += pllState.ds_x1 - pllState.ds_fb;
if (pllState.ds_x2 < 0)
{
ds_out = 0;
pllState.ds_fb = 0;
}
else
{
diff = (short)(mclk_pt - expected_pt);
ds_out = 1;
pllState.ds_fb = 1048575; //pow(2, 20)
}
// TODO Add a bounds checker on diff to make sure it's roughly where we expect.
// If it isn't we should ignore it as it's either a glitch or from clock start/stop.
// Now write the register.
// We need to write the register at a specific period at a fast rate.
// This period needs to be (div ref clk period (ns) * how many times we repeat same value)
// In this case, div ref clk = 24/3 = 8MHz. So div ref clk period = 125ns.
// So minimum period we could use is 125ns.
// We use sw ref clk to time the register write. This uses 10ns clock ticks.
// So this period should be a multiple of 10ns too.
// So shortest period to meet these requirements is 250ns. This is still very fast though.
// 1000ns is a great choice if we can.
// 1500ns is a better choice.
// 2250ns is the next choice.
// The slower we write, our jitter goes up significantly.
// Measuring rms jitter 100Hz-40kHz and TIE (TIE across 80ms of clock output).
// 750ns - jitter = 51ps, tie = +-1.5ns.
// 1500ns - jitter = 110ps, tie = +-2.5ns.
// 2250ns - jitter = 162ps, tie = +-3.2ns. // Note to be measured for single bit DS.
error = diff; // Absolute error for last measurement cycle.
cum_error = cum_error + error; // Integral error.
time += 150; // We write reg every 1500ns.
tmr when timerafter(time) :> void;
error_p = (Kp * error);
error_i = (Ki * cum_error);
int newsetting = (error_p + error_i);
// Only write new PLL settings if they're different to the old settings
if (newsetting != oldsetting)
// ds_out = 1 => fraction of 1/1 = N+1. ds_out = 0 => fraction of 0/1 = N.
if(running)
{
int frac_index = (app_pll_frac_i - newsetting) >> 2; // Tmp shift down to stop freq moving around much
if (frac_index < 0)
{
frac_index = 0;
}
else if (frac_index > 326)
{
frac_index = 326;
}
// Write the register. Because we are timing the reg writes accurately we do not need to use reg write with ack.
// This saves a lot of time. Additionally, apparently we can shorten the time for this reg write by only setting up
// the channel once and just doing a few instructions to do the write each time.
// We can hard code this in assembler.
write_node_config_reg_no_ack(tile, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, (0x80000000 | frac_values_80[frac_index]));
write_node_config_reg_no_ack(tile, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, (ds_out << 31));
}
oldsetting = newsetting;
mclk_pt_last = mclk_pt;
}
}
#endif
#endif

View File

@@ -314,6 +314,9 @@ void usb_audio_io(chanend ?c_aud_in,
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
, client interface pll_ref_if i_pll_ref
#endif
#if (XUA_USE_APP_PLL)
, client interface SoftPll_if i_softPll
#endif
)
{
#if (MIXER)
@@ -364,6 +367,9 @@ void usb_audio_io(chanend ?c_aud_in,
#define AUDIO_CHANNEL c_aud_in
#endif
XUA_AudioHub(AUDIO_CHANNEL, clk_audio_mclk, clk_audio_bclk, p_mclk_in, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc
#if (XUA_USE_APP_PLL)
, i_softPll
#endif
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
, c_spdif_tx
#endif
@@ -470,6 +476,11 @@ int main()
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
interface pll_ref_if i_pll_ref;
#endif
#if (XUA_USE_APP_PLL)
interface SoftPll_if i_softPll;
chan c_swpll_update;
#endif
chan c_sof;
chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */
chan c_xud_in[ENDPOINT_COUNT_IN];
@@ -522,6 +533,10 @@ int main()
c_sof, epTypeTableOut, epTypeTableIn, usbSpeed, xudPwrCfg);
}
#if (XUA_USE_APP_PLL)
//XUA_SoftPll(tile[0], i_softPll, c_swpll_update);
#endif
/* Core USB audio task, buffering, USB etc */
{
unsigned x;
@@ -563,8 +578,12 @@ int main()
, c_xud_in[ENDPOINT_NUMBER_IN_HID]
#endif
, c_mix_out
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL))
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
#if (!XUA_USE_APP_PLL)
, i_pll_ref
#else
, c_swpll_update
#endif
#endif
);
//:
@@ -579,6 +598,7 @@ int main()
#endif /* XUA_USB_EN */
}
on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update);
on tile[AUDIO_IO_TILE]:
{
/* Audio I/O task, includes mixing etc */
@@ -601,6 +621,9 @@ int main()
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
, i_pll_ref
#endif
#if (XUA_USE_APP_PLL)
, i_softPll
#endif
);
}