Audiohub now takes some resources as params (prev was global)

This commit is contained in:
xross
2018-03-08 17:40:56 +00:00
parent a33950f675
commit a7645a9b0f
6 changed files with 268 additions and 140 deletions

View File

@@ -15,14 +15,24 @@
* This function drives I2S ports and handles samples to/from other digital
* I/O threads.
*
* \param c_aud Audio sample channel connected to the mixer() thread or the
* decouple() thread
* \param c_dig channel connected to the clockGen() thread for
* receiving/transmitting samples
* \param c_config An optional channel that will be passed on to the
* CODEC configuration functions.
* \param c_aud Audio sample channel connected to the mixer() thread or the
* decouple() thread
*
* \param clk_audio_mclk Nullable clockblock to be clocked from master clock
*
* \param clk_audio_mclk Nullable clockblock to be clocked from i2s clock
*
* \param p_mclk_in Master clock inport port (must be 1-bit)
*
* \param c_dig channel connected to the clockGen() thread for
* receiving/transmitting samples
*/
void XUA_AudioHub(chanend ?c_aud
void XUA_AudioHub(chanend ?c_aud,
clock ?clk_audio_mclk,
clock ?clk_audio_bclk,
in port p_mclk_in,
buffered _XUA_CLK_DIR port:32 ?p_lrclk,
buffered _XUA_CLK_DIR port:32 ?p_bclk
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
, chanend c_spdif_tx
#endif

View File

@@ -8,4 +8,10 @@
#include "xua_conf_default.h"
#if CODEC_MASTER
#define _XUA_CLK_DIR in
#else
#define _XUA_CLK_DIR out
#endif
#endif

View File

@@ -21,11 +21,11 @@ The code is split into several directories.
- Device Firmware Upgrade code
Note, the midi and dfu directories are potential canditates for separate libs in their own right.
Note, the midi and dfu directories are potential candidates for separate libs in their own right.
Including in a project
~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~
All `lib_xua` functions can be accessed via the ``xud.h`` header filer::
@@ -34,4 +34,101 @@ All `lib_xua` functions can be accessed via the ``xud.h`` header filer::
It is also requited to to add ``lib_xua`` to the ``USED_MODULES`` field of your application Makefile.
Core hardware resources
~~~~~~~~~~~~~~~~~~~~~~~
Currently all hardware resources used by `lib_xua` are simply declared globally.
As an absolute minimum the following resources are required
- A 1-bit port for audio master clock input
- A n-bit port for internal feedback calculation (typically a free, unused port is used e.g. `16B`)
- A clock-block, which will be clocked from the master clock input port
.. note::
Since these resources are accessed globally naming is of importance
Example declaration of these resources might look as follows::
in port p_mclk_in = PORT_MCLK_IN;
in port p_for_mclk_count = PORT_MCLK_COUNT; /* Extra port for counting master clock ticks */
clock clk_audio_mclk = on tile[0]: XS1_CLKBLK_5; /* Master clock */
If the ``XUD_AudioHub()`` and ``XUD_Buffer()`` cores reside on separate tiles a separate master clock input port must be provided to each, for example::
/* Master clock for the audio IO tile */
in port p_mclk_in = PORT_MCLK_IN;
/* Resources for USB feedback */
in port p_mclk_in_usb = PORT_MCLK_IN_USB; /* Extra master clock input for the USB tile */
Whilst this satisfies the basic requirements for the operation of `lib_xua` projects typically also needs some additional audio I/O, I2S or SPDIF for example.
These should be passed into the various cores as required (see API section)
Running the core components
~~~~~~~~~~~~~~~~~~~~~~~~~~~
In their most basic form the core components can be run as follows::
par
{
/* Endpoint 0 core from lib_xua */
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 */
XUA_Buffer(c_ep_out[1], c_ep_in[1], c_sof, c_aud_ctl, p_for_mclk_count, c_aud);
/* AudioHub/IO core does most of the audio IO i.e. I2S (also serves as a hub for all audio) */
XUA_AudioHub(c_aud);
}
``XUA_Buffer()`` expects its ``p_for_mclk_count`` argument to be clocked from the audio master clock
The following code satisfies this requirement::
{
/* 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 */
set_port_clock(p_for_mclk_count, clk_audio_mclk_usb); /* Clock the "count" port from the clock block */
start_clock(clk_audio_mclk_usb); /* Set the clock off running */
XUA_Buffer(c_ep_out[1], c_ep_in[1], c_sof, c_aud_ctl, p_for_mclk_count, c_aud);
}
.. note:: By keeping this configuraiton outside of the ``XUA_Buffer()`` function allow the possiblity to share the ``p_mclk_in_usb`` port with additional components
To produce a fully operating device a call to ``XUD_Main()`` (from ``lib_xud``) must also be made for USB connectivity::
/* Low level USB device layer core */
on tile[1]: XUD_Main(c_ep_out, 2, c_ep_in, 2, c_sof, epTypeTableOut, epTypeTableIn, null, null, -1, XUD_SPEED_HS, XUD_PWR_SELF);
Additionally the required communication channels must also be declared::
/* Channel arrays for lib_xud */
chan c_ep_out[2];
chan c_ep_in[2];
/* Channel for communicating SOF notifications from XUD to the Buffering cores */
chan c_sof;
/* Channel for audio data between buffering cores and AudioHub/IO core */
chan c_aud;
/* Channel for communicating control messages from EP0 to the rest of the device (via the buffering cores) */
chan c_aud_ctl;
Configuring XUA
~~~~~~~~~~~~~~~
Built in main()
~~~~~~~~~~~~~~~
Enabling Additional Features
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This sections describes only the basic feature set of ``lib_xua`` details on enabling additional features e.g. S/PDIF can be found later in this document.

View File

@@ -0,0 +1,106 @@
#if !CODEC_MASTER
static inline void InitPorts_master(unsigned divide, buffered out port:32 p_lrclk, buffered out port:32 p_bclk)
{
#if (DSD_CHANS_DAC > 0)
if(dsdMode == DSD_MODE_OFF)
{
#endif
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
/* Clear I2S port buffers */
clearbuf(p_lrclk);
#if (I2S_CHANS_DAC != 0)
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
clearbuf(p_i2s_dac[i]);
}
#endif
#if (I2S_CHANS_ADC != 0)
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
clearbuf(p_i2s_adc[i]);
}
#endif
#pragma xta endpoint "divide_1"
unsigned tmp;
p_lrclk <: 0 @ tmp;
tmp += 100;
/* Since BCLK is free-running, setup outputs/inputs at a known point in the future */
#if (I2S_CHANS_DAC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] @ tmp <: 0;
}
#endif
p_lrclk @ tmp <: 0x7FFFFFFF;
#if (I2S_CHANS_ADC != 0)
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
}
#endif
#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */
#if (DSD_CHANS_DAC > 0)
} /* if (!dsdMode) */
else
{
/* p_dsd_clk must start high */
p_dsd_clk <: 0x80000000;
}
#endif
}
#endif
#if CODEC_MASTER
static inline void InitPorts_slave(unsigned divide, buffered in port:32 p_lrclk, buffered in port:32 p_bclk)
{
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
unsigned tmp;
/* Wait for LRCLK edge (in I2S LRCLK = 0 is left, TDM rising edge is start of frame) */
p_lrclk when pinseq(0) :> void;
p_lrclk when pinseq(1) :> void;
p_lrclk when pinseq(0) :> void;
p_lrclk when pinseq(1) :> void;
#if I2S_MODE_TDM
p_lrclk when pinseq(0) :> void;
p_lrclk when pinseq(1) :> void @ tmp;
#else
p_lrclk when pinseq(0) :> void @ tmp;
#endif
tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ;
/* E.g. 2 * 32 - 32 + 1 = 33 for stereo */
/* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */
#if (I2S_CHANS_DAC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] @ tmp <: 0;
}
#endif
#if (I2S_CHANS_ADC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
}
#endif
asm("setpt res[%0], %1"::"r"(p_lrclk),"r"(tmp-1));
#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */
}
#endif

View File

@@ -76,21 +76,9 @@ extern buffered out port:32 p_i2s_dac[I2S_WIRES_DAC];
extern buffered in port:32 p_i2s_adc[I2S_WIRES_ADC];
#endif
/* I2S LR/Bit clock I/O */
#if CODEC_MASTER
extern buffered in port:32 p_lrclk;
extern buffered in port:32 p_bclk;
#else
extern buffered out port:32 p_lrclk;
extern buffered out port:32 p_bclk;
#endif
unsigned dsdMode = DSD_MODE_OFF;
/* Master clock input */
extern in port p_mclk_in;
extern in port p_mclk_in2;
#if (XUA_SPDIF_TX_EN)
extern buffered out port:32 p_spdif_tx;
#endif
@@ -99,15 +87,10 @@ extern buffered out port:32 p_spdif_tx;
extern buffered out port:32 p_adat_tx;
#endif
extern clock clk_audio_mclk;
extern clock clk_audio_bclk;
#if XUA_SPDIF_TX_EN || defined(ADAT_TX)
extern clock clk_mst_spd;
#endif
//extern void device_reboot(void);
#define MAX_DIVIDE_48 (MCLK_48/MIN_FREQ_48/64)
#define MAX_DIVIDE_44 (MCLK_44/MIN_FREQ_44/64)
#if (MAX_DIVIDE_44 > MAX_DIVIDE_48)
@@ -116,10 +99,14 @@ extern clock clk_mst_spd;
#define MAX_DIVIDE (MAX_DIVIDE_48)
#endif
#include "init_ports.h"
#ifdef ADAT_TX
unsigned adatCounter = 0;
unsigned adatSamples[8];
#pragma unsafe arrays
static inline void TransferAdatTxSamples(chanend c_adat_out, const unsigned samplesFromHost[], int smux, int handshake)
{
@@ -182,9 +169,11 @@ static inline unsigned DoSampleTransfer(chanend c_out, const int readBuffNo, con
#ifndef CODEC_MASTER
if(dsdMode == DSD_MODE_OFF)
{
// Set clocks low
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
/* Set clocks low */
p_lrclk <: 0;
p_bclk <: 0;
#endif
}
else
{
@@ -293,9 +282,11 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa
dsdCount = 0;
dsdMarker = DSD_MARKER_2;
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
// Set clocks low
p_lrclk <: 0;
p_bclk <: 0;
#endif
p_dsd_clk <: 0;
return 0;
}
@@ -315,8 +306,10 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa
{
dsdMode = DSD_MODE_OFF;
// Set clocks low
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
p_lrclk <: 0;
p_bclk <: 0;
#endif
p_dsd_clk <: 0;
return 0;
}
@@ -327,104 +320,6 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa
}
#endif
#if !CODEC_MASTER
static inline void InitPorts_master(unsigned divide)
{
unsigned tmp;
#if (DSD_CHANS_DAC > 0)
if(dsdMode == DSD_MODE_OFF)
{
#endif
/* Clear I2S port buffers */
clearbuf(p_lrclk);
#if (I2S_CHANS_DAC != 0)
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
clearbuf(p_i2s_dac[i]);
}
#endif
#if (I2S_CHANS_ADC != 0)
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
clearbuf(p_i2s_adc[i]);
}
#endif
#pragma xta endpoint "divide_1"
p_lrclk <: 0 @ tmp;
tmp += 100;
/* Since BCLK is free-running, setup outputs/inputs at a known point in the future */
#if (I2S_CHANS_DAC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] @ tmp <: 0;
}
#endif
p_lrclk @ tmp <: 0x7FFFFFFF;
#if (I2S_CHANS_ADC != 0)
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
}
#endif
#if (DSD_CHANS_DAC > 0)
} /* if (!dsdMode) */
else
{
/* p_dsd_clk must start high */
p_dsd_clk <: 0x80000000;
}
#endif
}
#endif
#if CODEC_MASTER
static inline void InitPorts_slave(unsigned divide)
{
unsigned tmp;
/* Wait for LRCLK edge (in I2S LRCLK = 0 is left, TDM rising edge is start of frame) */
p_lrclk when pinseq(0) :> void;
p_lrclk when pinseq(1) :> void;
p_lrclk when pinseq(0) :> void;
p_lrclk when pinseq(1) :> void;
#if I2S_MODE_TDM
p_lrclk when pinseq(0) :> void;
p_lrclk when pinseq(1) :> void @ tmp;
#else
p_lrclk when pinseq(0) :> void @ tmp;
#endif
tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ;
/* E.g. 2 * 32 - 32 + 1 = 33 for stereo */
/* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */
#if (I2S_CHANS_DAC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] @ tmp <: 0;
}
#endif
#if (I2S_CHANS_ADC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
}
#endif
asm("setpt res[%0], %1"::"r"(p_lrclk),"r"(tmp-1));
}
#endif
@@ -442,6 +337,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out
#if (NUM_PDM_MICS > 0)
, chanend c_pdm_pcm
#endif
, buffered out port:32 p_lrclk, buffered out port:32 p_bclk
)
{
/* Since DAC and ADC buffered ports off by one sample we buffer previous ADC frame */
@@ -533,7 +429,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out
return command;
}
InitPorts_master(divide);
InitPorts_master(divide, p_lrclk, p_bclk);
/* Main Audio I/O loop */
while (1)
@@ -598,11 +494,13 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out
/* LR clock delayed by one clock, This is so MSB is output on the falling edge of BCLK
* after the falling edge on which LRCLK was toggled. (see I2S spec) */
/* Generate clocks LR Clock low - LEFT */
#if I2S_MODE_TDM
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
#if I2S_MODE_TDM
p_lrclk <: 0x00000000;
#else
p_lrclk <: 0x80000000;
#endif
#endif
#pragma xta endpoint "i2s_output_l"
@@ -725,6 +623,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out
}
#endif
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
#if I2S_MODE_TDM
if(frameCount == (I2S_CHANS_PER_FRAME-2))
p_lrclk <: 0x80000000;
@@ -732,6 +631,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out
p_lrclk <: 0x00000000;
#else
p_lrclk <: 0x7FFFFFFF;
#endif
#endif
index = 0;
@@ -821,6 +721,7 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out
#if (NUM_PDM_MICS > 0)
, chanend c_pdm_pcm
#endif
, buffered in port:32 p_lrclk, buffered in port:32 p_bclk
)
{
/* Since DAC and ADC buffered ports off by one sample we buffer previous ADC frame */
@@ -903,7 +804,7 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out
unsigned lrval;
unsigned syncError = 0;
InitPorts_slave(divide);
InitPorts_slave(divide, p_lrclk, p_bclk);
while (!syncError)
{
@@ -956,8 +857,10 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out
}
#endif //(I2S_CHANS_ADC != 0)
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
/* LR Clock sync check */
p_lrclk :> lrval;
#endif
if(I2S_MODE_TDM)
{
@@ -1094,9 +997,10 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out
}
#endif //(I2S_CHANS_ADC != 0)
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
/* LR Clock sync check */
p_lrclk :> lrval;
#endif
if(I2S_MODE_TDM)
{
/* Do nothing */
@@ -1179,7 +1083,7 @@ void SpdifTxWrapper(chanend c_spdif_tx)
// TODO could share clock block here..
// NOTE, Assuming SPDIF tile == USB tile here..
asm("ldw %0, dp[p_mclk_in2]":"=r"(portId));
asm("ldw %0, dp[p_mclk_in_usb]":"=r"(portId));
asm("setclk res[%0], %1"::"r"(clk_mst_spd), "r"(portId));
configure_out_port_no_ready(p_spdif_tx, clk_mst_spd, 0);
set_clock_fall_delay(clk_mst_spd, 7);
@@ -1261,7 +1165,10 @@ static void dummy_deliver(chanend ?c_out, unsigned &command)
void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd);
#endif
void XUA_AudioHub(chanend ?c_mix_out
void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
in port p_mclk_in,
buffered _XUA_CLK_DIR port:32 ?p_lrclk,
buffered _XUA_CLK_DIR port:32 ?p_bclk
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
, chanend c_spdif_out
#endif
@@ -1457,7 +1364,7 @@ void XUA_AudioHub(chanend ?c_mix_out
#endif
/* Handshake back */
#ifndef NO_USB
outct(c_mix_out, XS1_CT_END);
outct(c_aud, XS1_CT_END);
#endif
}
}
@@ -1505,9 +1412,9 @@ void XUA_AudioHub(chanend ?c_mix_out
outuint(c_adat_out, adatSmuxMode);
#endif
#if CODEC_MASTER
command = deliver_slave(c_mix_out
command = deliver_slave(c_aud
#else
command = deliver_master(c_mix_out
command = deliver_master(c_aud
#endif
#if (XUA_SPDIF_TX_EN)
, c_spdif_out
@@ -1525,12 +1432,14 @@ void XUA_AudioHub(chanend ?c_mix_out
#if (NUM_PDM_MICS > 0)
, c_pdm_in
#endif
, p_lrclk,
p_bclk
);
#ifndef NO_USB
if(command == SET_SAMPLE_FREQ)
{
curSamFreq = inuint(c_mix_out) * AUD_TO_USB_RATIO;
curSamFreq = inuint(c_aud) * AUD_TO_USB_RATIO;
}
else if(command == SET_STREAM_FORMAT_OUT)
{
@@ -1538,17 +1447,17 @@ void XUA_AudioHub(chanend ?c_mix_out
* DOP = 1
* Native = 2
*/
dsdMode = inuint(c_mix_out);
curSamRes_DAC = inuint(c_mix_out);
dsdMode = inuint(c_aud);
curSamRes_DAC = inuint(c_aud);
}
#if (XUA_DFU_EN == 1)
/* Currently no more audio will happen after this point */
if ((curSamFreq / AUD_TO_USB_RATIO) == AUDIO_STOP_FOR_DFU)
{
outct(c_mix_out, XS1_CT_END);
outct(c_aud, XS1_CT_END);
outuint(c_mix_out, 0);
outuint(c_aud, 0);
while (1)
{

View File

@@ -219,7 +219,7 @@ int main(void)
{
par
{
XUA_AudioHub(c_out);
XUA_AudioHub(c_out, clk_audio_mclk, clk_audio_bclk, p_mclk_in, p_lrclk, p_bclk);
generator(c_checker, c_out);
checker(c_checker, 0);
#ifdef SIMULATION