Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ UNRELEASED
same functionality as `xua_conf_cores.h` i.e. to allow insertion of tasks
into the `main()` function (`xua_conf_cores.h` to be deprecated in a future
release)
* ADDED: Support for lib_sigma_delta to provide high-quality PWM audio
outputs via GPIO pins
ADDED: Support for define `USER_MAIN_TASKS` with the same functionalty
as `USER_MAIN_CORES` i.e. to allow insertion of tasks into the `main()`
function (`USER_MAIN_CORES` to be deprecated in a future release)
Expand Down
6 changes: 5 additions & 1 deletion lib_xua/api/xua_audiohub.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@
void XUA_AudioHub(
NULLABLE_RESOURCE(chanend, c_aud),
NULLABLE_RESOURCE(clock, clk_audio_mclk),
NULLABLE_RESOURCE(clock, clk_audio_bclk), NULLABLE_RESOURCE(in_port_t, p_mclk_in)
NULLABLE_RESOURCE(clock, clk_audio_bclk)
, NULLABLE_RESOURCE(in_port_t, p_mclk_in)
, NULLABLE_RESOURCE(i2s_clk_port_type, p_lrclk)
, NULLABLE_RESOURCE(i2s_clk_port_type, p_bclk)
, NULLABLE_ARRAY_OF_SIZE(out_buffered_port_32_t, p_i2s_dac, I2S_WIRES_DAC)
Expand All @@ -75,6 +76,9 @@ void XUA_AudioHub(
#if (XUA_NUM_PDM_MICS > 0 || defined(__DOXYGEN__))
, chanend c_pdm_in
#endif
#if (XUA_PWM_CHANNELS > 0) || defined(__DOXYGEN__)
, chanend c_pwm_channels
#endif
);

void SpdifTxWrapper(chanend c_spdif_tx);
Expand Down
30 changes: 30 additions & 0 deletions lib_xua/api/xua_conf_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@
#define SPDIF_TX_TILE AUDIO_IO_TILE
#endif

/**
* @brief Location (tile) of SPDIF Tx. Default: XUD_TILE
*/
#ifndef PWM_CHANNELS_TILE
#define PWM_CHANNELS_TILE XUD_TILE
#endif

/**
* @brief Location (tile) of PDM Rx. Default: AUDIO_IO_TILE
*/
Expand Down Expand Up @@ -85,6 +92,27 @@
#define XUA_NUM_PDM_MICS (0)
#endif

/**
* @brief Number of PWM output channels in the design. Must be 2 or 0.
*
* Default: 0
*/
#ifndef XUA_NUM_PWM_CHANNELS
#define XUA_NUM_PWM_CHANNELS (0)
#endif
#if (XUA_NUM_PWM_CHANNELS != 0 && XUA_NUM_PWM_CHANNELS != 2)
#error "Only none or two PWM channels supported at present"
#endif

/**
* @brief Defines which output channels (stereo) should be output on PWM. Note, Output channels indexed from 0.
*
* Default: 0 (i.e. channels 0 & 1)
* */
#ifndef PWM_CHANNELS_INDEX
#define PWM_CHANNELS_INDEX (0)
#endif

/**
* @brief Number of DSD output channels.
*
Expand Down Expand Up @@ -124,6 +152,8 @@
#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME)
#endif

#define XUA_I2S_EN ((I2S_WIRES_ADC) > 0 || (I2S_WIRES_DAC) > 0)

/*
* Defines relating to the interface to external audio hardware i.e. DAC/ADC
*/
Expand Down
42 changes: 42 additions & 0 deletions lib_xua/api/xua_pwm_conf_default.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2025 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _xua_pwm_conf_default_h_
#define _xua_pwm_conf_default_h_

#ifdef __xua_pwm_conf_h_exists__
#include "xua_pwm_conf.h"
#endif

#ifndef XUA_PWM_SD_COEFFS
#define XUA_PWM_SD_COEFFS sd_coeffs_o6_f1_5_n8
#endif

#ifndef XUA_PWM_SCALE
#define XUA_PWM_SCALE 2.8544
#endif

#ifndef XUA_PWM_LIMIT
#define XUA_PWM_LIMIT 2.8684735298
#endif

#ifndef XUA_PWM_FLAT_COMP_X2
#define XUA_PWM_FLAT_COMP_X2 (-1.0/29000)
#endif

#ifndef XUA_PWM_FLAT_COMP_X3
#define XUA_PWM_FLAT_COMP_X3 (1.0/120000)
#endif

#ifndef XUA_PWM_PWM_COMP_X2
#define XUA_PWM_PWM_COMP_X2 (-3.0/190)
#endif

#ifndef XUA_PWM_PWM_COMP_X3
#define XUA_PWM_PWM_COMP_X3 (0.63/80)
#endif

#ifndef XUA_PWM_NEGATE
#define XUA_PWM_NEGATE 1
#endif

#endif
1 change: 1 addition & 0 deletions lib_xua/lib_build_info.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ set(LIB_OPTIONAL_HEADERS xua_conf.h
xua_conf_cores.h
xua_conf_tasks.h
static_hid_report.h
xua_pwm_conf.h
)

set(LIB_DEPENDENT_MODULES "lib_adat(2.0.1)"
Expand Down
53 changes: 42 additions & 11 deletions lib_xua/src/core/audiohub/xua_audiohub.xc
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,12 @@ static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:3
}

#pragma unsafe arrays
unsigned static AudioHub_MainLoop(chanend ?c_aud, chanend ?c_spd_out
unsigned static AudioHub_MainLoop(
chanend ?c_aud,
chanend ?c_spd_out
#if (XUA_PWM_CHANNELS > 0)
, chanend c_pwm_channels
#endif
#if (XUA_ADAT_TX_EN)
, chanend c_adat_out
, unsigned adatSmuxMode
Expand Down Expand Up @@ -409,6 +414,11 @@ unsigned static AudioHub_MainLoop(chanend ?c_aud, chanend ?c_spd_out
outuint(c_dig_rx, 0);
#endif

#if (XUA_PWM_CHANNELS > 0) && (NUM_USB_CHAN_OUT > 0)
outuint(c_pwm_channels, samplesOut[PWM_CHANNELS_INDEX]); /* Forward samples to PWM generator threads */
outuint(c_pwm_channels, samplesOut[PWM_CHANNELS_INDEX + 1]);
#endif

#if (XUA_NUM_PDM_MICS > 0)
if ((AUD_TO_MICS_RATIO - 1) == audioToMicsRatioCounter)
unsafe {
Expand Down Expand Up @@ -603,7 +613,7 @@ void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd);
connect to the codec ports. It is used during DFU reset and during idle non-streaming mode, if enabled.
Note there are two paths through depending on dfuMode.*/
[[combinable]]
static void dummy_deliver(chanend ?c_aud, unsigned sampFreq, unsigned dfuMode, unsigned &command)
static void dummy_deliver(chanend ?c_aud, chanend ?c_pwm, unsigned sampFreq, unsigned dfuMode, unsigned &command)
{
const int wait_ticks = XS1_TIMER_HZ / sampFreq;
timer tmr;
Expand Down Expand Up @@ -642,6 +652,14 @@ static void dummy_deliver(chanend ?c_aud, unsigned sampFreq, unsigned dfuMode, u
/* Process the command in the callee */
return;
}

#if XUA_PWM_CHANNELS > 0
#pragma loop unroll
for(int i = 0; i < XUA_PWM_CHANNELS; i++)
{
outuint(c_pwm, 0);
}
#endif
}
/* Wait one sample period */
tmr when timerafter(tmr_trigger) :> void;
Expand All @@ -657,7 +675,6 @@ static void dummy_deliver(chanend ?c_aud, unsigned sampFreq, unsigned dfuMode, u
}
}


#if XUA_DFU_EN
/* External DFU handler task */
[[distributable]]
Expand All @@ -667,7 +684,7 @@ void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd);
/* Helper function to see if a request for entry to DFU has been issued via a sample rate change.
If so, enter DFU. Note this code will never return. The device will
need to be reset which is part of the DFU sequence */
void check_and_enter_dfu(unsigned curSamFreq, chanend c_aud, server interface i_dfu ?dfuInterface)
void check_and_enter_dfu(unsigned curSamFreq, chanend c_aud, chanend ?c_pwm, server interface i_dfu ?dfuInterface)
{
/* Currently no more audio will happen after this point */
if ((curSamFreq / AUD_TO_USB_RATIO) == AUDIO_STOP_FOR_DFU)
Expand All @@ -691,7 +708,7 @@ void check_and_enter_dfu(unsigned curSamFreq, chanend c_aud, server interface i_
DFUHandler(dfuInterface, null);
#endif
/* This never exits because we set DFU mode*/
dummy_deliver(c_aud, 48000, 1, command);
dummy_deliver(c_aud, c_pwm, 48000, 1, command);
}
/* Note, we shouldn't reach here. Audio, once stopped for DFU, cannot be resumed */
}
Expand All @@ -700,8 +717,12 @@ void check_and_enter_dfu(unsigned curSamFreq, chanend c_aud, server interface i_
#endif /* XUA_DFU_EN */


void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
in port ?p_mclk_in,
#if(XUA_PWM_CHANNELS == 0)
#define c_pwm_channels null
#endif

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,
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
Expand All @@ -721,6 +742,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
#if (XUA_NUM_PDM_MICS > 0)
, chanend c_pdm_in
#endif
#if (XUA_PWM_CHANNELS > 0) || defined(__DOXYGEN__)
, chanend c_pwm_channels
#endif
)
{
/* This is a bit annoying but we have a mixture of nullable interfaces and variadic function signatures based on defines */
Expand Down Expand Up @@ -766,10 +790,10 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
firstRun = 0;
}
/* Now run dummy loop with no IO. This is sufficient to poll for commands from decouple */
dummy_deliver(c_aud, 1000, 0, command); /* Run loop at 1kHz for min power and exit if command */
dummy_deliver(c_aud, c_pwm_channels, 1000, 0, command); /* Run loop at 1kHz for min power and exit if command */
receive_command(command, c_aud, curSamFreq, dsdMode, curSamRes_DAC, audioActive);
#if (XUA_DFU_EN == 1)
check_and_enter_dfu(curSamFreq, c_aud, dfuInterface);
check_and_enter_dfu(curSamFreq, c_aud, c_pwm_channels, dfuInterface);
#endif /* (XUA_DFU_EN == 1) */
} /* audioActive == 0 */

Expand Down Expand Up @@ -979,6 +1003,11 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
}
#endif
{
#if (XUA_PWM_CHANNELS > 0)
/* Communicate master clock and sample freq to PWM thread */
outct(c_pwm_channels, XS1_CT_END);
outuint(c_pwm_channels, curSamFreq);
#endif
#if (XUA_SPDIF_TX_EN)
/* Communicate master clock and sample freq to S/PDIF thread */
outct(c_spdif_out, XS1_CT_END);
Expand All @@ -1005,6 +1034,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
#else
, null
#endif
#if (XUA_PWM_CHANNELS > 0)
, c_pwm_channels
#endif
#if (XUA_ADAT_TX_EN)
, c_adat_out
, adatSmuxMode
Expand All @@ -1022,8 +1054,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
/* Now perform any additional inputs and update state accordingly */
receive_command(command, c_aud, curSamFreq, dsdMode, curSamRes_DAC, audioActive);
#if (XUA_DFU_EN == 1)
check_and_enter_dfu(curSamFreq, c_aud, dfuInterface);

check_and_enter_dfu(curSamFreq, c_aud, c_pwm_channels, dfuInterface);
#endif /* (XUA_DFU_EN == 1) */
#endif /* XUA_USB_EN */

Expand Down
2 changes: 1 addition & 1 deletion lib_xua/src/core/clocking/sw_pll_wrapper.xc
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void sw_pll_task(chanend c_sw_pll){
the first control value has been received. This avoids issues with
channel lockup if two tasks (eg. init and SDM) try to write at the same time. */

unsigned command = inuint(c_sw_pll);
inuint(c_sw_pll);
inct(c_sw_pll);
while(1)
{
Expand Down
1 change: 1 addition & 0 deletions lib_xua/src/core/endpoint0/xua_ep0_descriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "descriptor_defs.h"
#include "usbaudio20.h" /* Defines from the USB Audio 2.0 Specifications */
#include "usbaudiocommon.h"
#include "packet_sizes.h"
#include "xud_device.h"
#include "xua_hid_descriptor.h"
#include "xua_ep0_midi_descriptors.h"
Expand Down
Loading