forked from PAWPAW-Mirror/lib_xua
Audiohub now takes some resources as params (prev was global)
This commit is contained in:
@@ -17,12 +17,22 @@
|
|||||||
*
|
*
|
||||||
* \param c_aud Audio sample channel connected to the mixer() thread or the
|
* \param c_aud Audio sample channel connected to the mixer() thread or the
|
||||||
* decouple() thread
|
* 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
|
* \param c_dig channel connected to the clockGen() thread for
|
||||||
* receiving/transmitting samples
|
* receiving/transmitting samples
|
||||||
* \param c_config An optional channel that will be passed on to the
|
|
||||||
* CODEC configuration functions.
|
|
||||||
*/
|
*/
|
||||||
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)
|
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||||
, chanend c_spdif_tx
|
, chanend c_spdif_tx
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,4 +8,10 @@
|
|||||||
|
|
||||||
#include "xua_conf_default.h"
|
#include "xua_conf_default.h"
|
||||||
|
|
||||||
|
#if CODEC_MASTER
|
||||||
|
#define _XUA_CLK_DIR in
|
||||||
|
#else
|
||||||
|
#define _XUA_CLK_DIR out
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ The code is split into several directories.
|
|||||||
- Device Firmware Upgrade code
|
- 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
|
Including in a project
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
All `lib_xua` functions can be accessed via the ``xud.h`` header filer::
|
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.
|
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.
|
||||||
|
|||||||
106
lib_xua/src/core/audiohub/init_ports.h
Normal file
106
lib_xua/src/core/audiohub/init_ports.h
Normal 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
|
||||||
|
|
||||||
@@ -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];
|
extern buffered in port:32 p_i2s_adc[I2S_WIRES_ADC];
|
||||||
#endif
|
#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;
|
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)
|
#if (XUA_SPDIF_TX_EN)
|
||||||
extern buffered out port:32 p_spdif_tx;
|
extern buffered out port:32 p_spdif_tx;
|
||||||
#endif
|
#endif
|
||||||
@@ -99,15 +87,10 @@ extern buffered out port:32 p_spdif_tx;
|
|||||||
extern buffered out port:32 p_adat_tx;
|
extern buffered out port:32 p_adat_tx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern clock clk_audio_mclk;
|
|
||||||
extern clock clk_audio_bclk;
|
|
||||||
|
|
||||||
#if XUA_SPDIF_TX_EN || defined(ADAT_TX)
|
#if XUA_SPDIF_TX_EN || defined(ADAT_TX)
|
||||||
extern clock clk_mst_spd;
|
extern clock clk_mst_spd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//extern void device_reboot(void);
|
|
||||||
|
|
||||||
#define MAX_DIVIDE_48 (MCLK_48/MIN_FREQ_48/64)
|
#define MAX_DIVIDE_48 (MCLK_48/MIN_FREQ_48/64)
|
||||||
#define MAX_DIVIDE_44 (MCLK_44/MIN_FREQ_44/64)
|
#define MAX_DIVIDE_44 (MCLK_44/MIN_FREQ_44/64)
|
||||||
#if (MAX_DIVIDE_44 > MAX_DIVIDE_48)
|
#if (MAX_DIVIDE_44 > MAX_DIVIDE_48)
|
||||||
@@ -116,10 +99,14 @@ extern clock clk_mst_spd;
|
|||||||
#define MAX_DIVIDE (MAX_DIVIDE_48)
|
#define MAX_DIVIDE (MAX_DIVIDE_48)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "init_ports.h"
|
||||||
|
|
||||||
#ifdef ADAT_TX
|
#ifdef ADAT_TX
|
||||||
unsigned adatCounter = 0;
|
unsigned adatCounter = 0;
|
||||||
unsigned adatSamples[8];
|
unsigned adatSamples[8];
|
||||||
|
|
||||||
|
|
||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
static inline void TransferAdatTxSamples(chanend c_adat_out, const unsigned samplesFromHost[], int smux, int handshake)
|
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
|
#ifndef CODEC_MASTER
|
||||||
if(dsdMode == DSD_MODE_OFF)
|
if(dsdMode == DSD_MODE_OFF)
|
||||||
{
|
{
|
||||||
// Set clocks low
|
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||||
|
/* Set clocks low */
|
||||||
p_lrclk <: 0;
|
p_lrclk <: 0;
|
||||||
p_bclk <: 0;
|
p_bclk <: 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -293,9 +282,11 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa
|
|||||||
dsdCount = 0;
|
dsdCount = 0;
|
||||||
dsdMarker = DSD_MARKER_2;
|
dsdMarker = DSD_MARKER_2;
|
||||||
|
|
||||||
|
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||||
// Set clocks low
|
// Set clocks low
|
||||||
p_lrclk <: 0;
|
p_lrclk <: 0;
|
||||||
p_bclk <: 0;
|
p_bclk <: 0;
|
||||||
|
#endif
|
||||||
p_dsd_clk <: 0;
|
p_dsd_clk <: 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -315,8 +306,10 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa
|
|||||||
{
|
{
|
||||||
dsdMode = DSD_MODE_OFF;
|
dsdMode = DSD_MODE_OFF;
|
||||||
// Set clocks low
|
// Set clocks low
|
||||||
|
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||||
p_lrclk <: 0;
|
p_lrclk <: 0;
|
||||||
p_bclk <: 0;
|
p_bclk <: 0;
|
||||||
|
#endif
|
||||||
p_dsd_clk <: 0;
|
p_dsd_clk <: 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -327,104 +320,6 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
#if (NUM_PDM_MICS > 0)
|
||||||
, chanend c_pdm_pcm
|
, chanend c_pdm_pcm
|
||||||
#endif
|
#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 */
|
/* 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;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitPorts_master(divide);
|
InitPorts_master(divide, p_lrclk, p_bclk);
|
||||||
|
|
||||||
/* Main Audio I/O loop */
|
/* Main Audio I/O loop */
|
||||||
while (1)
|
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
|
/* 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) */
|
* after the falling edge on which LRCLK was toggled. (see I2S spec) */
|
||||||
/* Generate clocks LR Clock low - LEFT */
|
/* Generate clocks LR Clock low - LEFT */
|
||||||
|
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||||
#if I2S_MODE_TDM
|
#if I2S_MODE_TDM
|
||||||
p_lrclk <: 0x00000000;
|
p_lrclk <: 0x00000000;
|
||||||
#else
|
#else
|
||||||
p_lrclk <: 0x80000000;
|
p_lrclk <: 0x80000000;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#pragma xta endpoint "i2s_output_l"
|
#pragma xta endpoint "i2s_output_l"
|
||||||
|
|
||||||
@@ -725,6 +623,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||||
#if I2S_MODE_TDM
|
#if I2S_MODE_TDM
|
||||||
if(frameCount == (I2S_CHANS_PER_FRAME-2))
|
if(frameCount == (I2S_CHANS_PER_FRAME-2))
|
||||||
p_lrclk <: 0x80000000;
|
p_lrclk <: 0x80000000;
|
||||||
@@ -732,6 +631,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out
|
|||||||
p_lrclk <: 0x00000000;
|
p_lrclk <: 0x00000000;
|
||||||
#else
|
#else
|
||||||
p_lrclk <: 0x7FFFFFFF;
|
p_lrclk <: 0x7FFFFFFF;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
@@ -821,6 +721,7 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out
|
|||||||
#if (NUM_PDM_MICS > 0)
|
#if (NUM_PDM_MICS > 0)
|
||||||
, chanend c_pdm_pcm
|
, chanend c_pdm_pcm
|
||||||
#endif
|
#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 */
|
/* 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 lrval;
|
||||||
unsigned syncError = 0;
|
unsigned syncError = 0;
|
||||||
|
|
||||||
InitPorts_slave(divide);
|
InitPorts_slave(divide, p_lrclk, p_bclk);
|
||||||
|
|
||||||
while (!syncError)
|
while (!syncError)
|
||||||
{
|
{
|
||||||
@@ -956,8 +857,10 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out
|
|||||||
}
|
}
|
||||||
#endif //(I2S_CHANS_ADC != 0)
|
#endif //(I2S_CHANS_ADC != 0)
|
||||||
|
|
||||||
|
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||||
/* LR Clock sync check */
|
/* LR Clock sync check */
|
||||||
p_lrclk :> lrval;
|
p_lrclk :> lrval;
|
||||||
|
#endif
|
||||||
|
|
||||||
if(I2S_MODE_TDM)
|
if(I2S_MODE_TDM)
|
||||||
{
|
{
|
||||||
@@ -1094,9 +997,10 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out
|
|||||||
}
|
}
|
||||||
#endif //(I2S_CHANS_ADC != 0)
|
#endif //(I2S_CHANS_ADC != 0)
|
||||||
|
|
||||||
|
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||||
/* LR Clock sync check */
|
/* LR Clock sync check */
|
||||||
p_lrclk :> lrval;
|
p_lrclk :> lrval;
|
||||||
|
#endif
|
||||||
if(I2S_MODE_TDM)
|
if(I2S_MODE_TDM)
|
||||||
{
|
{
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
@@ -1179,7 +1083,7 @@ void SpdifTxWrapper(chanend c_spdif_tx)
|
|||||||
|
|
||||||
// TODO could share clock block here..
|
// TODO could share clock block here..
|
||||||
// NOTE, Assuming SPDIF tile == USB tile 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));
|
asm("setclk res[%0], %1"::"r"(clk_mst_spd), "r"(portId));
|
||||||
configure_out_port_no_ready(p_spdif_tx, clk_mst_spd, 0);
|
configure_out_port_no_ready(p_spdif_tx, clk_mst_spd, 0);
|
||||||
set_clock_fall_delay(clk_mst_spd, 7);
|
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);
|
void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd);
|
||||||
#endif
|
#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)
|
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||||
, chanend c_spdif_out
|
, chanend c_spdif_out
|
||||||
#endif
|
#endif
|
||||||
@@ -1457,7 +1364,7 @@ void XUA_AudioHub(chanend ?c_mix_out
|
|||||||
#endif
|
#endif
|
||||||
/* Handshake back */
|
/* Handshake back */
|
||||||
#ifndef NO_USB
|
#ifndef NO_USB
|
||||||
outct(c_mix_out, XS1_CT_END);
|
outct(c_aud, XS1_CT_END);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1505,9 +1412,9 @@ void XUA_AudioHub(chanend ?c_mix_out
|
|||||||
outuint(c_adat_out, adatSmuxMode);
|
outuint(c_adat_out, adatSmuxMode);
|
||||||
#endif
|
#endif
|
||||||
#if CODEC_MASTER
|
#if CODEC_MASTER
|
||||||
command = deliver_slave(c_mix_out
|
command = deliver_slave(c_aud
|
||||||
#else
|
#else
|
||||||
command = deliver_master(c_mix_out
|
command = deliver_master(c_aud
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_SPDIF_TX_EN)
|
#if (XUA_SPDIF_TX_EN)
|
||||||
, c_spdif_out
|
, c_spdif_out
|
||||||
@@ -1525,12 +1432,14 @@ void XUA_AudioHub(chanend ?c_mix_out
|
|||||||
#if (NUM_PDM_MICS > 0)
|
#if (NUM_PDM_MICS > 0)
|
||||||
, c_pdm_in
|
, c_pdm_in
|
||||||
#endif
|
#endif
|
||||||
|
, p_lrclk,
|
||||||
|
p_bclk
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifndef NO_USB
|
#ifndef NO_USB
|
||||||
if(command == SET_SAMPLE_FREQ)
|
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)
|
else if(command == SET_STREAM_FORMAT_OUT)
|
||||||
{
|
{
|
||||||
@@ -1538,17 +1447,17 @@ void XUA_AudioHub(chanend ?c_mix_out
|
|||||||
* DOP = 1
|
* DOP = 1
|
||||||
* Native = 2
|
* Native = 2
|
||||||
*/
|
*/
|
||||||
dsdMode = inuint(c_mix_out);
|
dsdMode = inuint(c_aud);
|
||||||
curSamRes_DAC = inuint(c_mix_out);
|
curSamRes_DAC = inuint(c_aud);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (XUA_DFU_EN == 1)
|
#if (XUA_DFU_EN == 1)
|
||||||
/* Currently no more audio will happen after this point */
|
/* Currently no more audio will happen after this point */
|
||||||
if ((curSamFreq / AUD_TO_USB_RATIO) == AUDIO_STOP_FOR_DFU)
|
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)
|
while (1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ int main(void)
|
|||||||
{
|
{
|
||||||
par
|
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);
|
generator(c_checker, c_out);
|
||||||
checker(c_checker, 0);
|
checker(c_checker, 0);
|
||||||
#ifdef SIMULATION
|
#ifdef SIMULATION
|
||||||
|
|||||||
Reference in New Issue
Block a user