diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b0dd1bdc..2496ee28a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -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) diff --git a/lib_xua/api/xua_audiohub.h b/lib_xua/api/xua_audiohub.h index 70b8036ab..73000d518 100644 --- a/lib_xua/api/xua_audiohub.h +++ b/lib_xua/api/xua_audiohub.h @@ -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) @@ -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); diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index cf916105c..9b34e2329 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -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 */ @@ -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. * @@ -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 */ diff --git a/lib_xua/api/xua_pwm_conf_default.h b/lib_xua/api/xua_pwm_conf_default.h new file mode 100644 index 000000000..9af82b933 --- /dev/null +++ b/lib_xua/api/xua_pwm_conf_default.h @@ -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 diff --git a/lib_xua/lib_build_info.cmake b/lib_xua/lib_build_info.cmake index e6e2d35ff..2a01244ca 100644 --- a/lib_xua/lib_build_info.cmake +++ b/lib_xua/lib_build_info.cmake @@ -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)" diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 99fd2c8e0..a2276de39 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -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 @@ -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 { @@ -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; @@ -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; @@ -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]] @@ -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) @@ -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 */ } @@ -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], @@ -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 */ @@ -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 */ @@ -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); @@ -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 @@ -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 */ diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.xc b/lib_xua/src/core/clocking/sw_pll_wrapper.xc index 168ef66e5..c9fa9cedb 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.xc +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.xc @@ -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) { diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index ca5879f79..fa02c43be 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -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" diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 05942ac62..f5fead548 100644 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -13,6 +13,7 @@ #include #include #include +#include #include #ifdef XSCOPE #include @@ -29,6 +30,10 @@ #include "spdif.h" /* From lib_spdif */ #endif +#if (XUA_PWM_CHANNELS > 0) +#include "pwm_thread.h" +#endif + #if (XUA_ADAT_RX_EN) #include "adat_rx.h" #endif @@ -105,6 +110,7 @@ on tile[AUDIO_IO_TILE] : buffered in port:32 p_i2s_adc[I2S_WIRES_ADC] = #define p_i2s_adc null #endif +#if XUA_I2S_EN #if CODEC_MASTER on tile[AUDIO_IO_TILE] : buffered in port:32 p_lrclk = PORT_I2S_LRCLK; @@ -113,6 +119,10 @@ on tile[AUDIO_IO_TILE] : buffered in port:32 p_bclk = PORT_I2S_BCLK; on tile[AUDIO_IO_TILE] : buffered out port:32 p_lrclk = PORT_I2S_LRCLK; on tile[AUDIO_IO_TILE] : buffered out port:32 p_bclk = PORT_I2S_BCLK; #endif +#else +#define p_lrclk null +#define p_bclk null +#endif #if (MCLK_REQUIRED) /* Audio master clock input */ @@ -168,6 +178,10 @@ on tile[MIDI_TILE] : buffered in port:1 p_midi_rx = PORT_MIDI_IN; #endif +#if (XUA_PWM_CHANNELS > 0) +clock clk_pwm_channels = on tile[PWM_CHANNELS_TILE]: CLKBLK_PWM; +#endif + #ifdef MIDI on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; #endif @@ -266,6 +280,9 @@ void usb_audio_io(chanend ?c_aud_in, #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) chanend c_spdif_tx, #endif +#if (XUA_PWM_CHANNELS > 0) + chanend c_pwm_channels, +#endif #if (MIXER) chanend c_mix_ctl, #endif @@ -307,6 +324,10 @@ void usb_audio_io(chanend ?c_aud_in, #endif /* (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) */ +#if (XUA_PWM_CHANNELS > 0) && (PWM_CHANNELS_TILE == AUDIO_IO_TILE) + pwm_init(p_mclk_in); +#endif + #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE == AUDIO_IO_TILE) chan c_spdif_tx; @@ -354,6 +375,9 @@ void usb_audio_io(chanend ?c_aud_in, #endif #if (XUA_NUM_PDM_MICS > 0) , c_pdm_pcm +#endif +#if (XUA_PWM_CHANNELS > 0) + , c_pwm_channels #endif ); } @@ -438,6 +462,10 @@ int main() chan c_spdif_tx; #endif +#if (XUA_PWM_CHANNELS > 0) + chan c_pwm_channels; +#endif + #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) chan c_clk_ctl; chan c_clk_int; @@ -531,6 +559,9 @@ int main() /* Attach mclk count port to mclk clock-block (for feedback) */ //set_port_clock(p_for_mclk_count, clk_audio_mclk); +#if (XUA_PWM_CHANNELS > 0) && (PWM_CHANNELS_TILE != AUDIO_IO_TILE) + pwm_init(p_mclk_in); +#endif #if(SECOND_MCLK_REQUIRED) set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb); set_port_clock(p_for_mclk_count, clk_audio_mclk_usb); @@ -610,6 +641,9 @@ int main() #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) , c_spdif_tx #endif +#if (XUA_PWM_CHANNELS > 0) + , c_pwm_channels +#endif #if (MIXER) , c_mix_ctl #endif @@ -642,7 +676,23 @@ int main() } #endif +#if (XUA_PWM_CHANNELS > 0) + on tile[PWM_CHANNELS_TILE]: + { + thread_speed(); + timer tmr; + int tt; + tmr :> tt; + // Nasty - wait for clock block to be inited + // Ideally, this happens before the PAR. + // But it is inside the IO thread + tmr when timerafter(tt + 1000000) :> void; + pwm_thread(c_pwm_channels); + } +#endif + #ifdef MIDI + /* MIDI core */ on tile[MIDI_TILE]: { diff --git a/lib_xua/src/core/ports/audioports.c b/lib_xua/src/core/ports/audioports.c index 6f018998e..59312708a 100644 --- a/lib_xua/src/core/ports/audioports.c +++ b/lib_xua/src/core/ports/audioports.c @@ -41,8 +41,15 @@ void ConfigAudioPortsWrapper( port p_adc[], int numPortsAdc, #endif - port p_lrclk, - port p_bclk, +#if (I2S_CHANS_DAC != 0) || (I2S_CHANS_ADC != 0) +#if (CODEC_MASTER == 0) + NULLABLE_RESOURCE(out_buffered_port_32_t, p_lrclk), + out_buffered_port_32_t p_bclk, +#else + NULLABLE_RESOURCE(in_buffered_port_32_t, p_lrclk), + in_buffered_port_32_t p_bclk, +#endif +#endif NULLABLE_RESOURCE(in_port_t, p_mclk_in), clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq) { @@ -55,8 +62,11 @@ void ConfigAudioPortsWrapper( p_adc, numPortsAdc, #endif +#if (I2S_CHANS_DAC != 0) || (I2S_CHANS_ADC != 0) p_lrclk, p_bclk, - p_mclk_in, clk_audio_bclk, divide, curSamFreq); +#endif + p_mclk_in, + clk_audio_bclk, divide, curSamFreq); } diff --git a/lib_xua/src/core/ports/audioports.h b/lib_xua/src/core/ports/audioports.h index ed3f019c6..dc0c4f088 100644 --- a/lib_xua/src/core/ports/audioports.h +++ b/lib_xua/src/core/ports/audioports.h @@ -17,16 +17,19 @@ void ConfigAudioPorts( in_buffered_port_32_t p_i2s_adc[], int numAdcPorts, #endif +#if (I2S_CHANS_DAC != 0) || (I2S_CHANS_ADC != 0) #if (CODEC_MASTER == 0) NULLABLE_RESOURCE(out_buffered_port_32_t, p_lrclk), out_buffered_port_32_t p_bclk, #else NULLABLE_RESOURCE(in_port_t, p_lrclk), in_port_t p_bclk, +#endif #endif NULLABLE_RESOURCE(in_port_t, p_mclk_in), clock clk_audio_bclk, unsigned int divide, unsigned int curSamFreq); + void DeConfigAudioPorts( #if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0) out_buffered_port_32_t p_i2s_dac[], @@ -47,7 +50,6 @@ void DeConfigAudioPorts( clock clk_audio_bclk); - void ConfigAudioPortsWrapper( #if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0) out_buffered_port_32_t p_i2s_dac[], @@ -57,12 +59,14 @@ void ConfigAudioPortsWrapper( in_buffered_port_32_t p_i2s_adc[], int numPortsADC, #endif +#if (I2S_CHANS_DAC != 0) || (I2S_CHANS_ADC != 0) #if (CODEC_MASTER == 0) NULLABLE_RESOURCE(out_buffered_port_32_t, p_lrclk), out_buffered_port_32_t p_bclk, #else NULLABLE_RESOURCE(in_buffered_port_32_t, p_lrclk), in_buffered_port_32_t p_bclk, +#endif #endif NULLABLE_RESOURCE(in_port_t, p_mclk_in), clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq); diff --git a/lib_xua/src/core/ports/audioports.xc b/lib_xua/src/core/ports/audioports.xc index c1350b3d1..959879ddf 100644 --- a/lib_xua/src/core/ports/audioports.xc +++ b/lib_xua/src/core/ports/audioports.xc @@ -17,12 +17,14 @@ void ConfigAudioPorts( int numPortsAdc, #endif +#if (I2S_CHANS_DAC != 0) || (I2S_CHANS_ADC != 0) #if (CODEC_MASTER == 0) buffered out port:32 ?p_lrclk, buffered out port:32 p_bclk, #else in port ?p_lrclk, in port p_bclk, +#endif #endif in port ?p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq) diff --git a/lib_xua/src/core/pwm_thread.c b/lib_xua/src/core/pwm_thread.c new file mode 100644 index 000000000..6106fb588 --- /dev/null +++ b/lib_xua/src/core/pwm_thread.c @@ -0,0 +1,52 @@ +// Copyright 2024-2025 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +/** + * @file pwm_thread.c + * @brief Fork the threads to run a PWM engine + * @author Henk Muller, XMOS Semiconductor Ltd + */ +#include "xua_conf_default.h" // Settings +#if (XUA_PWM_CHANNELS > 0) +#include "xua_pwm_conf_default.h" // PWM Settings +#include +#include +#include +#include +#include "software_dac_hp.h" +#include "sigma_delta_modulators.h" +#include "uac_hwresources.h" + +void setup_master_clock(port_t clk_in) __attribute__ ((weak)); +void setup_master_clock(port_t clk_in) { +} + +void pwm_init(port_t clk_in) { + xclock_t clk = CLKBLK_PWM; + setup_master_clock(clk_in); + port_set_invert(clk_in); + clock_enable(clk); + clock_set_source_port(clk, clk_in); +} + +void pwm_thread(chanend_t c_data) +{ + software_dac_hp_t sd; + xclock_t clk = CLKBLK_PWM; + port_t ports[2] = {PORT_PWM_OUT_LEFT, PORT_PWM_OUT_RIGHT}; + port_t clk_out = PORT_PWM_CLK_OUT; + + software_dac_hp_init(&sd, ports, clk, clk_out, 8, + XUA_PWM_SD_COEFFS, + XUA_PWM_SCALE, + XUA_PWM_LIMIT, + XUA_PWM_FLAT_COMP_X2, + XUA_PWM_FLAT_COMP_X3, + XUA_PWM_PWM_COMP_X2, + XUA_PWM_PWM_COMP_X3, + XUA_PWM_NEGATE); + software_dac_hp(&sd, c_data); +} +#endif + + + diff --git a/lib_xua/src/core/pwm_thread.h b/lib_xua/src/core/pwm_thread.h new file mode 100644 index 000000000..037596da3 --- /dev/null +++ b/lib_xua/src/core/pwm_thread.h @@ -0,0 +1,22 @@ +// Copyright 2024-2025 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#ifndef __pwm_thread__h_ +#define __pwm_thread__h_ + +#include "xua_conf_default.h" // Settings + +#if (XUA_PWM_CHANNELS > 0) + #ifdef __XC__ + void pwm_init(in port clk_in); + void pwm_thread(chanend c_data); + #else + #include + void pwm_init(port_t clk_in); + void pwm_thread(chanend_t c_data); + #endif +#endif + +#endif + + + diff --git a/lib_xua/src/core/uac_hwresources.h b/lib_xua/src/core/uac_hwresources.h index 4cd6cdf7d..db6799ba5 100644 --- a/lib_xua/src/core/uac_hwresources.h +++ b/lib_xua/src/core/uac_hwresources.h @@ -11,5 +11,6 @@ #define CLKBLK_FLASHLIB XS1_CLKBLK_3 /* Clock block for use by flash lib */ #define CLKBLK_ADAT_RX XS1_CLKBLK_REF /* Use REF for ADAT_RX on x200/AI series */ #define CLKBLK_I2S_BIT XS1_CLKBLK_3 +#define CLKBLK_PWM XS1_CLKBLK_1 #endif /* _UAC_HWRESOURCES_H_ */