From c0a844c3034692af7d04bbc6ce61b9c0eef48fb5 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Jan 2024 14:08:22 +0000 Subject: [PATCH 01/30] Manual merge from experimental/sync_app_pll (not working yet) --- lib_xua/api/xua_audiohub.h | 7 + lib_xua/api/xua_buffer.h | 28 +- lib_xua/api/xua_clocking.h | 13 + lib_xua/api/xua_conf_default.h | 448 +++++++++--------- lib_xua/doc/rst/api_defines.rst | 15 +- lib_xua/doc/rst/api_user_functions.rst | 81 ++-- lib_xua/doc/rst/xdoc.conf | 2 +- lib_xua/src/core/audiohub/xua_audiohub.xc | 22 + lib_xua/src/core/buffer/ep/ep_buffer.xc | 56 ++- lib_xua/src/core/main.xc | 33 +- lib_xua/src/core/user/audiohw/audiohw.c | 29 ++ lib_xua/src/core/user/audiohw/audiohw.h | 54 +++ .../src/core/user/audiostream/audiostream.h | 45 +- lib_xua/src/core/user/hid/user_hid.h | 25 +- lib_xua/src/core/user/hostactive/hostactive.h | 10 +- tests/test_sync_clk_basic/Makefile | 2 + 16 files changed, 546 insertions(+), 324 deletions(-) create mode 100644 lib_xua/src/core/user/audiohw/audiohw.c create mode 100644 lib_xua/src/core/user/audiohw/audiohw.h diff --git a/lib_xua/api/xua_audiohub.h b/lib_xua/api/xua_audiohub.h index 8fa29eef..12c44379 100644 --- a/lib_xua/api/xua_audiohub.h +++ b/lib_xua/api/xua_audiohub.h @@ -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 @@ -49,6 +53,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 diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index d7d182d7..a1299079 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -1,7 +1,7 @@ -// Copyright 2011-2022 XMOS LIMITED. +// Copyright 2011-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. -#ifndef __XUA_BUFFER_H__ -#define __XUA_BUFFER_H__ +#ifndef _XUA_BUFFER_H_ +#define _XUA_BUFFER_H_ #if __XC__ @@ -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, @@ -38,7 +39,7 @@ void XUA_Buffer( #if defined(MIDI) || defined(__DOXYGEN__) chanend c_midi_from_host, chanend c_midi_to_host, - chanend c_midi, + chanend c_midi, #endif #if XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__) chanend ?c_int, @@ -51,8 +52,13 @@ void XUA_Buffer( , chanend c_hid #endif , chanend c_aud -#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || 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 ); @@ -66,7 +72,7 @@ void XUA_Buffer_Ep(chanend c_aud_out, #ifdef MIDI chanend c_midi_from_host, chanend c_midi_to_host, - chanend c_midi, + chanend c_midi, #endif #if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) chanend ?c_int, @@ -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) || 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. diff --git a/lib_xua/api/xua_clocking.h b/lib_xua/api/xua_clocking.h index 8a9f8b83..f24ab1b5 100644 --- a/lib_xua/api/xua_clocking.h +++ b/lib_xua/api/xua_clocking.h @@ -38,5 +38,18 @@ void clockGen( streaming chanend ?c_spdif_rx, chanend c_clk_int, port ?p_for_mclk_count_aud, chanend c_mclk_change); + + +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 diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 685f5672..0fbb1046 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -11,56 +11,55 @@ #include "xua_conf.h" #endif -/* Default tile arrangement */ +/* + * Tile arrangement defines + */ /** * @brief Location (tile) of audio I/O. Default: 0 */ #ifndef AUDIO_IO_TILE -#define AUDIO_IO_TILE (0) +#define AUDIO_IO_TILE (0) #endif /** * @brief Location (tile) of audio I/O. Default: 0 */ #ifndef XUD_TILE -#define XUD_TILE (0) +#define XUD_TILE (0) #endif /** * @brief Location (tile) of MIDI I/O. Default: AUDIO_IO_TILE */ #ifndef MIDI_TILE -#define MIDI_TILE AUDIO_IO_TILE +#define MIDI_TILE AUDIO_IO_TILE #endif /** * @brief Location (tile) of SPDIF Tx. Default: AUDIO_IO_TILE */ #ifndef SPDIF_TX_TILE -#define SPDIF_TX_TILE AUDIO_IO_TILE +#define SPDIF_TX_TILE AUDIO_IO_TILE #endif /** * @brief Location (tile) of PDM Rx. Default: AUDIO_IO_TILE */ #ifndef PDM_TILE -#define PDM_TILE AUDIO_IO_TILE +#define PDM_TILE AUDIO_IO_TILE #endif /** * @brief Location (tile) of reference signal to CS2100. Default: AUDIO_IO_TILE */ #ifndef PLL_REF_TILE -#define PLL_REF_TILE AUDIO_IO_TILE +#define PLL_REF_TILE AUDIO_IO_TILE #endif -/** - * @brief Disable USB functionalty just leaving AudioHub +/* + * Channel based defines */ -#ifndef XUA_USB_EN -#define XUA_USB_EN (1) -#endif /** * @brief Number of input channels (device to host). Default: NONE (Must be defined by app) @@ -79,18 +78,57 @@ #endif /** - * @brief Number of DSD output channels. Default: 0 (disabled) + * @brief Number of PDM microphones in the design. + * + * Default: 0 + */ +#ifndef XUA_NUM_PDM_MICS +#define XUA_NUM_PDM_MICS (0) +#endif + +/** + * @brief Number of DSD output channels. + * + * Default: 0 (disabled) */ #if defined(DSD_CHANS_DAC) && (DSD_CHANS_DAC != 0) #if defined(NATIVE_DSD) && (NATIVE_DSD == 0) #undef NATIVE_DSD #else - #define NATIVE_DSD (1) /* Always enable Native DSD when DSD mode is enabled */ + #define NATIVE_DSD 1 /* Always enable Native DSD when DSD mode is enabled */ #endif #else - #define DSD_CHANS_DAC (0) + #define DSD_CHANS_DAC 0 #endif +/** + * @brief Number of I2S channesl to DAC/CODEC. Must be a multiple of 2. + * + * Default: NONE (Must be defined by app) + */ +#ifndef I2S_CHANS_DAC + #error I2S_CHANS_DAC not defined + #define I2S_CHANS_DAC 2 /* Define anyway for doxygen */ +#else +#define I2S_WIRES_DAC (I2S_CHANS_DAC / I2S_CHANS_PER_FRAME) +#endif + +/** + * @brief Number of I2S channels from ADC/CODEC. Must be a multiple of 2. + * + * Default: NONE (Must be defined by app) + */ +#ifndef I2S_CHANS_ADC + #error I2S_CHANS_ADC not defined + #define I2S_CHANS_ADC 2 /* Define anyway for doxygen */ +#else +#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME) +#endif + +/* + * Defines relating to the interface to external audio hardware i.e. DAC/ADC + */ + #define XUA_PCM_FORMAT_I2S (0) #define XUA_PCM_FORMAT_TDM (1) /** @@ -103,7 +141,7 @@ #error Bad value for XUA_PCM_FORMAT #endif #else - #define XUA_PCM_FORMAT XUA_PCM_FORMAT_I2S + #define XUA_PCM_FORMAT XUA_PCM_FORMAT_I2S #endif /** @@ -114,89 +152,12 @@ **/ #ifndef I2S_CHANS_PER_FRAME #if (XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM) - #define I2S_CHANS_PER_FRAME (8) + #define I2S_CHANS_PER_FRAME 8 #else - #define I2S_CHANS_PER_FRAME (2) + #define I2S_CHANS_PER_FRAME 2 #endif #endif - -/** - * @brief Number of IS2 channesl to DAC/CODEC. Must be a multiple of 2. - * - * Default: NONE (Must be defined by app) - */ -#ifndef I2S_CHANS_DAC - #error I2S_CHANS_DAC not defined - #define I2S_CHANS_DAC 2 /* Define anyway for doxygen */ -#else -#define I2S_WIRES_DAC (I2S_CHANS_DAC / I2S_CHANS_PER_FRAME) -#endif - - -/** - * @brief Number of I2S channels from ADC/CODEC. Must be a multiple of 2. - * - * Default: NONE (Must be defined by app) - */ -#ifndef I2S_CHANS_ADC - #error I2S_CHANS_ADC not defined - #define I2S_CHANS_ADC 2 /* Define anyway for doxygen */ -#else -#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME) -#endif - -/** - * @brief Ratio of the I2S sample rate to the USB Audio sample rate. Up and - * down-sampling will be enabled as necessary when the rates differ. - * - * Default: 1 i.e. I2S and USB Audio are running at the same sample rate. - */ -#ifndef AUD_TO_USB_RATIO -#define AUD_TO_USB_RATIO (1) -#else - #if (AUD_TO_USB_RATIO != 3) && (AUD_TO_USB_RATIO != 1) - #error Unsupported I2S to USB Audio sample rate ratio - #endif -#endif - -/** - * @brief Ratio of the I2S sample rate to the PDM microphone decimator sample - * rate. - * - * Default: 1 i.e. I2S and PDM microphone decimators are running at the same sample rate. - */ -#ifndef AUD_TO_MICS_RATIO -#define AUD_TO_MICS_RATIO (1) -#else - #if (AUD_TO_MICS_RATIO != 3) && (AUD_TO_MICS_RATIO != 1) - #error Unsupported I2S to PDM microphone decimator sample rate ratio - #endif -#endif - -/** - * @brief Only downsample one channel per input I2S frame. - * - * Default: 0 i.e. mono mode is disabled, all input channels will be downsampled. - */ -#ifndef I2S_DOWNSAMPLE_MONO_IN -#define I2S_DOWNSAMPLE_MONO_IN (0) -#endif - -/** - * @brief Number of incoming (device to host) I2S channels to downsample. - * - * Default: The number of I2S incoming channels, or half this if mono downsampling is enabled. - */ -#if (I2S_DOWNSAMPLE_MONO_IN == 1) - #define I2S_DOWNSAMPLE_CHANS_IN (I2S_CHANS_ADC / 2) - #if ((I2S_DOWNSAMPLE_FACTOR_IN > 1) && (XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)) - #error Mono I2S input downsampling is not avaliable in TDM mode - #endif -#else - #define I2S_DOWNSAMPLE_CHANS_IN I2S_CHANS_ADC -#endif - /** * @brief Number of bits per channel for I2S/TDM. Supported values: 16/32-bit. * @@ -211,21 +172,82 @@ #endif /** - * @brief Max supported sample frequency for device (Hz). Default: 192000 + * @brief Ratio of the I2S sample rate to the USB Audio sample rate. Up and + * down-sampling will be enabled as necessary when the rates differ. + * + * Default: 1 i.e. I2S and USB Audio are running at the same sample rate. + */ +#ifndef AUD_TO_USB_RATIO +#define AUD_TO_USB_RATIO (1) +#else + #if (AUD_TO_USB_RATIO != 3) && (AUD_TO_USB_RATIO != 1) + #error Unsupported I2S to USB Audio sample rate ratio + #endif +#endif + +/** + * @brief Ratio of the I2S sample rate to the PDM microphone decimator sample + * rate. + * + * Default: 1 i.e. I2S and PDM microphone decimators are running at the same sample rate. + */ +#ifndef AUD_TO_MICS_RATIO +#define AUD_TO_MICS_RATIO (1) +#else + #if (AUD_TO_MICS_RATIO != 3) && (AUD_TO_MICS_RATIO != 1) + #error Unsupported I2S to PDM microphone decimator sample rate ratio + #endif +#endif + +/** + * @brief Only downsample one channel per input I2S frame. + * + * Default: 0 i.e. mono mode is disabled, all input channels will be downsampled. + */ +#ifndef I2S_DOWNSAMPLE_MONO_IN +#define I2S_DOWNSAMPLE_MONO_IN (0) +#endif + +/** + * @brief Number of incoming (device to host) I2S channels to downsample. + * + * Default: The number of I2S incoming channels, or half this if mono downsampling is enabled. + */ +#if (I2S_DOWNSAMPLE_MONO_IN == 1) + #define I2S_DOWNSAMPLE_CHANS_IN (I2S_CHANS_ADC / 2) + #if ((I2S_DOWNSAMPLE_FACTOR_IN > 1) && (XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)) + #error Mono I2S input downsampling is not avaliable in TDM mode + #endif +#else + #define I2S_DOWNSAMPLE_CHANS_IN I2S_CHANS_ADC +#endif + +/* + * Clocking related defines + */ + +/** + * @brief Max supported sample frequency for device (Hz). + * + * Default: 192000Hz */ #ifndef MAX_FREQ #define MAX_FREQ (192000) #endif /** - * @brief Min supported sample frequency for device (Hz). Default 44100 + * @brief Min supported sample frequency for device (Hz). + * + * Default: 44100Hz */ #ifndef MIN_FREQ #define MIN_FREQ (44100) #endif /** - * @brief Master clock defines for 44100 rates (in Hz). Default: NONE (Must be defined by app) + * @brief Master clock defines for 44100 rates (in Hz). + * + * Default: NONE (Must be defined by app) */ #ifndef MCLK_441 #error MCLK_441 not defined @@ -233,13 +255,34 @@ #endif /** - * @brief Master clock defines for 48000 rates (in Hz). Default: NONE (Must be defined by app) + * @brief Master clock defines for 48000 rates (in Hz). + * + * Default: NONE (Must be defined by app) */ #ifndef MCLK_48 #error MCLK_48 not defined #define MCLK_48 (256 * 48000) /* Define anyway for doygen */ #endif +/** + * @brief Enable/disable the use of the secondary/application PLL for generating master-clocks. + * Only available on xcore.ai devices. + * + * Default: Enabled (for xcore.ai devices) + */ +#ifndef XUA_USE_APP_PLL + #if defined(__XS3A__) + #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) + /* Currently must use an external CS2100 device for syncing to external digital streams */ + #define XUA_USE_APP_PLL (0) + #else + #define XUA_USE_APP_PLL (1) + #endif + #else + #define XUA_USE_APP_PLL (0) + #endif +#endif + /** * @brief Default device sample frequency. A safe default should be used. * @@ -249,10 +292,25 @@ #define DEFAULT_FREQ (MIN_FREQ) #endif -/* Audio Class Defines */ +#define DEFAULT_MCLK (((DEFAULT_FREQ % 7350) == 0) ? MCLK_441 : MCLK_48) /** - * @brief USB Audio Class Version. + * @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks) + * + * 0: XMOS is I2S master. 1: CODEC is I2s master. + * + * Default: 0 (XMOS is master) + */ +#ifndef CODEC_MASTER +#define CODEC_MASTER (0) +#endif + +/* + * Audio Class defines + */ + +/** + * @brief USB Audio Class Version * * Default: 2 (Audio Class version 2.0) */ @@ -261,9 +319,9 @@ #endif /** - * @brief Whether or not to fall back to Audio Class 1.0 in USB Full-speed. + * @brief Enable/disable fall back to Audio Class 1.0 in USB Full-speed. * - * Default: 0 (Disabled i.e. do not fall back to UAC 1.0 + * Default: Disabled */ #ifndef AUDIO_CLASS_FALLBACK #define AUDIO_CLASS_FALLBACK (0) @@ -278,7 +336,7 @@ #if (AUDIO_CLASS == 2) /* Whether to run in Audio Class 2.0 mode in USB Full-speed */ #if !defined(FULL_SPEED_AUDIO_2) && (AUDIO_CLASS_FALLBACK == 0) - #define FULL_SPEED_AUDIO_2 (1) /* Default to falling back to UAC2 */ + #define FULL_SPEED_AUDIO_2 1 /* Default to falling back to UAC2 */ #endif #endif @@ -295,16 +353,17 @@ #error AUDIO_CLASS set to 1 and FULL_SPEED_AUDIO_2 enabled! #endif - -/* Feature defines */ +/* + * Feature defines + */ /** - * @brief Number of PDM microphones in the design. + * @brief Disable USB functionalty just leaving AudioHub * - * Default: None + * Default: Enabled */ -#ifndef XUA_NUM_PDM_MICS -#define XUA_NUM_PDM_MICS (0) +#ifndef XUA_USB_EN +#define XUA_USB_EN (1) #endif /** @@ -318,18 +377,14 @@ #endif /** - * @brief Size of a frame of microphone data samples. - * - * Default: 1 + * @brief Size of a frame of microphone data samples. Default: 1 */ #ifndef XUA_MIC_FRAME_SIZE #define XUA_MIC_FRAME_SIZE (1) #endif /** - * @brief Enable MIDI functionality including buffering, descriptors etc. - * - * Default: 0 (Disabled) + * @brief Enable MIDI functionality including buffering, descriptors etc. Default: DISABLED */ #ifndef MIDI #define MIDI (0) @@ -350,7 +405,7 @@ * @brief Enables SPDIF Tx. Default: 0 (Disabled) */ #ifndef XUA_SPDIF_TX_EN -#define XUA_SPDIF_TX_EN (0) +#define XUA_SPDIF_TX_EN (0) #endif /** @@ -359,16 +414,14 @@ * Default: 0 (i.e. channels 0 & 1) * */ #ifndef SPDIF_TX_INDEX -#define SPDIF_TX_INDEX (0) +#define SPDIF_TX_INDEX (0) #endif /** - * @brief Enables ADAT Tx. - * - * Default: 0 (Disabled) + * @brief Enables ADAT Tx. Default: 0 (Disabled) */ #ifndef XUA_ADAT_TX_EN -#define XUA_ADAT_TX_EN (0) +#define XUA_ADAT_TX_EN (0) #endif /** @@ -377,25 +430,21 @@ * Default: 0 (i.e. channels [0:7]) * */ #ifndef ADAT_TX_INDEX -#define ADAT_TX_INDEX (0) +#define ADAT_TX_INDEX (0) #endif /** - * @brief Enables SPDIF Rx. - * - * Default: 0 (Disabled) + * @brief Enables SPDIF Rx. Default: 0 (Disabled) */ #ifndef XUA_SPDIF_RX_EN -#define XUA_SPDIF_RX_EN (0) +#define XUA_SPDIF_RX_EN (0) #endif /** - * @brief Enables ADAT Rx. - * - * Default: 0 (Disabled) + * @brief Enables ADAT Rx. Default: 0 (Disabled) */ #ifndef XUA_ADAT_RX_EN -#define XUA_ADAT_RX_EN (0) +#define XUA_ADAT_RX_EN (0) #endif /** @@ -450,20 +499,11 @@ * Default: 1 (Enabled) */ #if !defined(XUA_DFU_EN) -#define XUA_DFU_EN (1) +#define XUA_DFU_EN (1) #elif defined(XUA_DFU_EN) && (XUA_DFU_EN == 0) #undef XUA_DFU_EN #endif -/** - * @brief Use a QSPI (rather than SPI) flash for DFU (and boot) - * - * Default: 1 (True i.e use QSPI flash) -*/ -#if !defined(XUA_QUAD_SPI_FLASH) -#define XUA_QUAD_SPI_FLASH (1) -#endif - /** * @brief Enable HID playback controls functionality. * @@ -472,7 +512,7 @@ * Default 0 (Disabled) */ #ifndef HID_CONTROLS -#define HID_CONTROLS (0) +#define HID_CONTROLS (0) #endif /** @@ -488,12 +528,11 @@ * You must also supply your own function to deal with the HID endpoint(s) * in this case. */ -#if( 0 < HID_CONTROLS ) +#if (HID_CONTROLS) || defined (__DOXYGEN__) #define XUA_HID_ENABLED (1) #define XUA_OR_STATIC_HID_ENABLED (1) #endif - #if defined(__static_hid_report_h_exists__) #define XUA_OR_STATIC_HID_ENABLED (1) #endif @@ -506,18 +545,7 @@ * Default 0 (Disabled) */ #ifndef HID_OUT_REQUIRED -#define HID_OUT_REQUIRED (0) -#endif - -/** - * @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks) - * - * 0: XMOS is I2S master. 1: CODEC is I2s master. - * - * Default: 0 (XMOS is master) - */ -#ifndef CODEC_MASTER -#define CODEC_MASTER (0) +#define HID_OUT_REQUIRED (0) #endif /** @@ -526,7 +554,7 @@ * Default: "" */ #ifndef SERIAL_STR -#define SERIAL_STR "" +#define SERIAL_STR "" #endif /** @@ -535,7 +563,7 @@ * Default: "XMOS" */ #ifndef VENDOR_STR -#define VENDOR_STR "XMOS" +#define VENDOR_STR "XMOS" #endif /** @@ -544,7 +572,7 @@ * Default: 0x20B1 (XMOS) */ #ifndef VENDOR_ID -#define VENDOR_ID (0x20B1) +#define VENDOR_ID (0x20B1) #endif /** @@ -586,7 +614,7 @@ */ #if (AUDIO_CLASS == 1) || (AUDIO_CLASS_FALLBACK) || defined(__DOXYGEN__) #ifndef PID_AUDIO_1 -#define PID_AUDIO_1 (0x0003) +#define PID_AUDIO_1 (0x0003) #endif #endif @@ -596,28 +624,28 @@ * Default: 0x0002 */ #ifndef PID_AUDIO_2 -#define PID_AUDIO_2 (0x0002) +#define PID_AUDIO_2 (0x0002) #endif /** * @brief Device firmware version number in Binary Coded Decimal format: 0xJJMN where JJ: major, M: minor, N: sub-minor version number. */ #ifndef BCD_DEVICE_J -#define BCD_DEVICE_J (1) +#define BCD_DEVICE_J (1) #endif /** * @brief Device firmware version number in Binary Coded Decimal format: 0xJJMN where JJ: major, M: minor, N: sub-minor version number. */ #ifndef BCD_DEVICE_M -#define BCD_DEVICE_M (2) +#define BCD_DEVICE_M (2) #endif /** * @brief Device firmware version number in Binary Coded Decimal format: 0xJJMN where JJ: major, M: minor, N: sub-minor version number. */ #ifndef BCD_DEVICE_N -#define BCD_DEVICE_N (0) +#define BCD_DEVICE_N (0) #endif /** @@ -1021,7 +1049,7 @@ * Default: 1 (Enabled) */ #ifndef OUTPUT_VOLUME_CONTROL -#define OUTPUT_VOLUME_CONTROL (1) +#define OUTPUT_VOLUME_CONTROL (1) #endif /** @@ -1030,7 +1058,7 @@ * Default: 1 (Enabled) */ #ifndef INPUT_VOLUME_CONTROL -#define INPUT_VOLUME_CONTROL (1) +#define INPUT_VOLUME_CONTROL (1) #endif /* Power */ @@ -1072,7 +1100,7 @@ * Default: 0 (Disabled) */ #ifndef MIXER -#define MIXER (0) +#define MIXER (0) #endif /** @@ -1082,11 +1110,11 @@ */ #if (MIXER) #ifndef MAX_MIX_COUNT - #define MAX_MIX_COUNT (8) + #define MAX_MIX_COUNT (8) #endif #else #ifndef MAX_MIX_COUNT - #define MAX_MIX_COUNT (0) + #define MAX_MIX_COUNT (0) #endif #endif @@ -1098,7 +1126,7 @@ * Default: 18 */ #ifndef MIX_INPUTS - #define MIX_INPUTS (18) + #define MIX_INPUTS (18) #endif /* Volume processing defines */ @@ -1110,7 +1138,7 @@ * Default: 0x8100 (-127db) */ #ifndef MIN_VOLUME -#define MIN_VOLUME (0x8100) +#define MIN_VOLUME (0x8100) #endif @@ -1120,7 +1148,7 @@ * Default: 0x0000 (0db) */ #ifndef MAX_VOLUME -#define MAX_VOLUME (0x0000) +#define MAX_VOLUME (0x0000) #endif /** @@ -1129,7 +1157,7 @@ * Default: 0x100 (1db) */ #ifndef VOLUME_RES -#define VOLUME_RES (0x100) +#define VOLUME_RES (0x100) #endif /** @@ -1139,7 +1167,7 @@ * Default: 0x8100 (-127db) */ #ifndef MIN_MIXER_VOLUME -#define MIN_MIXER_VOLUME (0x8100) +#define MIN_MIXER_VOLUME (0x8100) #endif /** @@ -1148,7 +1176,7 @@ * Default: 0x0000 (0db) */ #ifndef MAX_MIXER_VOLUME -#define MAX_MIXER_VOLUME (0x0000) +#define MAX_MIXER_VOLUME (0x0000) #endif /** @@ -1157,36 +1185,32 @@ * Default: 0x100 (1db) */ #ifndef VOLUME_RES_MIXER -#define VOLUME_RES_MIXER (0x100) +#define VOLUME_RES_MIXER (0x100) #endif -/* Handle out volume control in the mixer - enabled by default if mixer enabled */ +/* Handle out volume control in the mixer - enabled by default */ #ifndef OUT_VOLUME_IN_MIXER -#if MIXER - #define OUT_VOLUME_IN_MIXER (1) -#else - #define OUT_VOLUME_IN_MIXER (0) -#endif +#define OUT_VOLUME_IN_MIXER (1) #endif /* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */ #ifndef OUT_VOLUME_AFTER_MIX -#define OUT_VOLUME_AFTER_MIX (1) +#define OUT_VOLUME_AFTER_MIX (1) #endif /* Handle in volume control in the mixer - disabled by default */ #ifndef IN_VOLUME_IN_MIXER -#define IN_VOLUME_IN_MIXER (0) +#define IN_VOLUME_IN_MIXER (0) #endif -/* Apply in volume controls after the mix. Only relevant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */ +/* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */ #ifndef IN_VOLUME_AFTER_MIX -#define IN_VOLUME_AFTER_MIX (1) +#define IN_VOLUME_AFTER_MIX (1) #endif /* Always enable explicit feedback EP, even when input stream is present */ #ifndef UAC_FORCE_FEEDBACK_EP -#define UAC_FORCE_FEEDBACK_EP (1) +#define UAC_FORCE_FEEDBACK_EP (1) #endif #if (defined(UAC_FORCE_FEEDBACK_EP) && UAC_FORCE_FEEDBACK_EP == 0) @@ -1194,9 +1218,9 @@ #endif /* Synchronisation defines */ -#define XUA_SYNCMODE_ASYNC (1) // USB_ENDPOINT_SYNCTYPE_ASYNC -#define XUA_SYNCMODE_ADAPT (2) // USB_ENDPOINT_SYNCTYPE_ADAPT -#define XUA_SYNCMODE_SYNC (3) // USB_ENDPOINT_SYNCTYPE_SYNC +#define XUA_SYNCMODE_ASYNC (1) // USB_ENDPOINT_SYNCTYPE_ASYNC +#define XUA_SYNCMODE_ADAPT (2) // USB_ENDPOINT_SYNCTYPE_ADAPT +#define XUA_SYNCMODE_SYNC (3) // USB_ENDPOINT_SYNCTYPE_SYNC #ifndef XUA_SYNCMODE #define XUA_SYNCMODE XUA_SYNCMODE_ASYNC @@ -1276,6 +1300,8 @@ enum USBEndpointNumber_Out #endif /* __ASSEMBLER__ */ #define AUDIO_STOP_FOR_DFU (0x12345678) +#define AUDIO_START_FROM_DFU (0x87654321) +#define AUDIO_REBOOT_FROM_DFU (0xa5a5a5a5) /* Result of db_to_mult(MAX_VOLUME, 8, 29) */ #define MAX_VOLUME_MULT (0x20000000) @@ -1378,7 +1404,7 @@ enum USBEndpointNumber_Out /* Some defines that allow us to remove unused code */ /* Useful for dropping lower part of macs in volume processing... */ -#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || \ +#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \ (((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \ (((FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 2)) #define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1 @@ -1412,29 +1438,29 @@ enum USBEndpointNumber_Out #endif /* Useful for dropping lower part of macs in volume processing... */ -#if (FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) - #define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 1 -#else - #define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 0 -#endif + #if (FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) || (FS_STREAM_FORMAT_INPUT_2_RESOLUTION_BITS > 24) + #define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 1 + #else + #define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 0 + #endif -#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4)) - #define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 1 -#else - #define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 0 -#endif + #if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4)) + #define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 1 + #else + #define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 0 + #endif -#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3)) - #define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 1 -#else - #define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 0 -#endif + #if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3)) + #define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 1 + #else + #define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 0 + #endif -#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2)) - #define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 1 -#else - #define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 0 -#endif + #if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2)) + #define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 1 + #else + #define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 0 + #endif #if MAX_FREQ < MIN_FREQ #error MAX_FREQ should be >= MIN_FREQ!! diff --git a/lib_xua/doc/rst/api_defines.rst b/lib_xua/doc/rst/api_defines.rst index a67b08fd..a9a395a0 100644 --- a/lib_xua/doc/rst/api_defines.rst +++ b/lib_xua/doc/rst/api_defines.rst @@ -8,9 +8,9 @@ An application using the USB audio framework needs to have defines set for confi Defaults for these defines are found in ``xua_conf_default.h``. These defines should be over-ridden in an optional header file ``xua_conf.h`` file or in the ``Makefile`` -for a relevant build configuration. +for a relevant build configuration. -This section fully documents all of the settable defines and their default values (where appropriate). +This section fully documents all of the settable defines and their default values (where appropriate). Code Location (tile) -------------------- @@ -25,12 +25,12 @@ Code Location (tile) Channel Counts -------------- -.. doxygendefine:: NUM_USB_CHAN_OUT -.. doxygendefine:: NUM_USB_CHAN_IN -.. doxygendefine:: I2S_CHANS_DAC -.. doxygendefine:: I2S_CHANS_ADC +.. doxygendefine:: NUM_USB_CHAN_OUT +.. doxygendefine:: NUM_USB_CHAN_IN +.. doxygendefine:: I2S_CHANS_DAC +.. doxygendefine:: I2S_CHANS_ADC -Frequencies and Clocks +Frequencies and Clocks ---------------------- .. doxygendefine:: MAX_FREQ @@ -38,6 +38,7 @@ Frequencies and Clocks .. doxygendefine:: DEFAULT_FREQ .. doxygendefine:: MCLK_441 .. doxygendefine:: MCLK_48 +.. doxygendefine:: USE_SW_PLL Audio Class ----------- diff --git a/lib_xua/doc/rst/api_user_functions.rst b/lib_xua/doc/rst/api_user_functions.rst index e0728647..e9c1ed61 100644 --- a/lib_xua/doc/rst/api_user_functions.rst +++ b/lib_xua/doc/rst/api_user_functions.rst @@ -1,74 +1,49 @@ -Required User Function Definitions -================================== +|newpage| -The following functions need to be defined by an application using the XMOS USB Audio framework. +User Function Definitions +========================= + +The following functions can be defined by an application using `lib_xua`. + +.. note:: Default, empty, implementations of these functions are provided in `lib_xua`. These are marked + as weak symbols so the application can simply define its own version of them. External Audio Hardware Configuration Functions ----------------------------------------------- -.. c:function:: void AudioHwInit(chanend ?c_codec) +The following functions can be optionally used by the design to configure external audio hardware. +As a minimum, in most applications, it is expected that a implementation of `AudioHwConfig()` will need +to be provided. - This function is called when the audio core starts after the - device boots up and should initialize the external audio harware e.g. clocking, DAC, ADC etc +.. doxygenfunction:: AudioHwInit +.. doxygenfunction:: AudioHwConfig +.. doxygenfunction:: AudioHwConfig_Mute +.. doxygenfunction:: AudioHwConfig_UnMute - :param c_codec: An optional chanend that was original passed into - :c:func:`audio` that can be used to communicate - with other cores. - -.. c:function:: void AudioHwConfig(unsigned samFreq, unsigned mclk, chanend ?c_codec, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) - - This function is called when the audio core starts or changes - sample rate. It should configure the extenal audio hardware to run at the specified - sample rate given the supplied master clock frequency. - - :param samFreq: The sample frequency in Hz that the hardware should be configured to (in Hz). - - :param mclk: The master clock frequency that is required in Hz. - - :param c_codec: An optional chanend that was original passed into - :c:func:`audio` that can be used to communicate - with other cores. - - :param dsdMode: Signifies if the audio hardware should be configured for DSD operation - - :param sampRes_DAC: The sample resolution of the DAC stream - - :param sampRes_ADC: The sample resolution of the ADC stream - - -Audio Streaming Functions -------------------------- +Audio Stream Start/Stop Functions +--------------------------------- The following functions can be optionally used by the design. They can be useful for mute lines etc. -.. c:function:: void AudioStreamStart(void) +.. doxygenfunction:: UserAudioStreamStart +.. doxygenfunction:: UserAudioStreamStop +.. doxygenfunction:: UserAudioInputStreamStart +.. doxygenfunction:: UserAudioInputStreamStop +.. doxygenfunction:: UserAudioOutputStreamStart +.. doxygenfunction:: UserAudioOutputStreamStop - This function is called when the audio stream from device to host - starts. - -.. c:function:: void AudioStreamStop(void) - - This function is called when the audio stream from device to host stops. - -Host Active ------------ +Host Active Functions +--------------------- The following function can be used to signal that the device is connected to a valid host. -This is called on a change in state. - -.. c:function:: void AudioStreamStart(int active) - - :param active: Indicates if the host is active or not. 1 for active else 0. - +.. doxygenfunction:: UserHostActive HID Controls ------------ The following function is called when the device wishes to read physical user input (buttons etc). +The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used. -.. c:function:: void UserReadHIDButtons(unsigned char hidData[]) - - :param hidData: The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used. - +.. doxygenfunction:: UserHIDGetData diff --git a/lib_xua/doc/rst/xdoc.conf b/lib_xua/doc/rst/xdoc.conf index 4d522c83..ae22d5a0 100644 --- a/lib_xua/doc/rst/xdoc.conf +++ b/lib_xua/doc/rst/xdoc.conf @@ -1,5 +1,5 @@ XMOSNEWSTYLE = 2 -DOXYGEN_DIRS=../../api +DOXYGEN_DIRS=../../api ../../src/core/user/audiostream ../../src/core/user/hostactive ../../src/core/user/hid ../../src/core/user/audiohw SOURCE_INCLUDE_DIRS=../../../lib_xua SPHINX_MASTER_DOC=lib_xua diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 3089523a..3c6ce660 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -20,6 +20,7 @@ #include "xua.h" +#include "audiohw.h" #include "audioports.h" #include "mic_array_conf.h" #if (XUA_SPDIF_TX_EN) @@ -635,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 +667,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); @@ -800,6 +810,15 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, } #endif /* Configure Clocking/CODEC/DAC/ADC for SampleFreq/MClk */ + + /* User should mute audio hardware */ + AudioHwConfig_Mute(); + + #if (XUA_USE_APP_PLL) + i_softPll.init(mClk); + #endif + + /* User code should configure audio harware for SampleFreq/MClk etc */ AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC); #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) /* Notify clockgen of new mCLk */ @@ -809,6 +828,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, /* Wait for ACK back from clockgen to signal clocks all good */ c_mclk_change :> int _; #endif + + /* User should unmute audio hardware */ + AudioHwConfig_UnMute(); } if(!firstRun) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index a2e42199..2a7ee928 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -105,7 +105,11 @@ void XUA_Buffer( #endif , chanend c_aud #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 ) { @@ -141,7 +145,11 @@ void XUA_Buffer( , c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - , i_pll_ref + #if(XUA_USE_APP_PLL) + , c_swpll_update + #else + , i_pll_ref + #endif #endif ); @@ -190,8 +198,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 +#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 ) { @@ -247,7 +259,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #if (NUM_USB_CHAN_IN > 0) unsigned bufferIn = 1; #endif - unsigned sofCount = 0; + int sofCount = 0; + int pllUpdate = 0; unsigned mod_from_last_time = 0; #ifdef FB_TOLERANCE_TEST @@ -294,7 +307,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 @@ -357,12 +369,16 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #ifndef LOCAL_CLOCK_MARGIN #define LOCAL_CLOCK_MARGIN (1000) #endif + +#if (!XUA_USE_APP_PLL) timer t_sofCheck; unsigned timeLastEdge; unsigned timeNextEdge; t_sofCheck :> timeLastEdge; timeNextEdge + LOCAL_CLOCK_INCREMENT; i_pll_ref.toggle(); +#endif + #endif while(1) @@ -427,7 +443,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out, /* Reset FB */ /* Note, Endpoint 0 will hold off host for a sufficient period to allow our feedback * to stabilise (i.e. sofCount == 128 to fire) */ - sofCount = 1; + sofCount = 0; + pllUpdate = 0; clocks = 0; clockcounter = 0; mod_from_last_time = 0; @@ -502,13 +519,13 @@ 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 */ } break; } -#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL) case t_sofCheck when timerafter(timeNextEdge) :> void: i_pll_ref.toggle(); timeLastEdge = timeNextEdge; @@ -528,7 +545,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, unsigned usbSpeed; int framesPerSec; GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed); - static int sofCount = 0; framesPerSec = (usbSpeed == XUD_SPEED_HS) ? 8000 : 1000; @@ -539,12 +555,27 @@ void XUA_Buffer_Ep(register chanend c_aud_out, sofCount += 1000; if (sofCount == framesPerSec) { + sofCount = 0; + pllUpdate++; +#if (!XUA_USE_APP_PLL) /* Port is accessed via interface to allow flexibilty with location */ i_pll_ref.toggle(); t_sofCheck :> timeLastEdge; - sofCount = 0; timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; +#endif } +#if (XUA_USE_APP_PLL) + // Update PLL @ 100Hz + if(pllUpdate == 10) + { + pllUpdate = 0; + unsigned short mclk_pt; + asm volatile("getts %0, res[%1]" : "=r" (mclk_pt) : "r" (p_off_mclk)); + outuint(c_swpll_update, mclk_pt); + outct(c_swpll_update, XS1_CT_END); + } +#endif + #elif (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC) /* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to @@ -646,7 +677,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, clockcounter = 0; } #else - /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. @@ -897,8 +927,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #endif -#if XUA_HID_ENABLED - /* HID Report Data */ +#if (XUA_HID_ENABLED) + /* HID Report Data */ case XUD_SetData_Select(c_hid, ep_hid, result): hid_ready_flag = 0U; unsigned reportTime; @@ -911,7 +941,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #ifdef MIDI - /* Received word from MIDI thread - Check for ACK or Data */ + /* Received word from MIDI thread - Check for ACK or Data */ case midi_get_ack_or_data(c_midi, is_ack, datum): if (is_ack) { diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index c4403acb..6bfb1b30 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -316,6 +316,9 @@ void usb_audio_io(chanend ?c_aud_in, , client interface pll_ref_if i_pll_ref , port ?p_for_mclk_count_aud #endif + #if (XUA_USE_APP_PLL) + , client interface SoftPll_if i_softPll + #endif ) { #if (MIXER) @@ -373,6 +376,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 @@ -483,9 +489,14 @@ int main() #endif #endif -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#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]; @@ -507,7 +518,7 @@ int main() { USER_MAIN_CORES -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XUA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref); #endif on tile[XUD_TILE]: @@ -520,6 +531,10 @@ int main() DFUHandler(dfuInterface, null); #endif +#if (XUA_USE_APP_PLL) + //XUA_SoftPll(tile[0], i_softPll, c_swpll_update); +#endif + /* Core USB task, buffering, USB etc */ { #ifdef XUD_PRIORITY_HIGH @@ -578,7 +593,13 @@ int main() #endif , c_mix_out #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) + #if (!XUA_USE_APP_PLL) + , i_pll_ref + #else + , c_swpll_update + #endif +#endif #endif ); //: @@ -593,6 +614,10 @@ int main() #endif /* XUA_USB_EN */ } +#if(XUA_USE_APP_PLL) + on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update); +#endif + on tile[AUDIO_IO_TILE]: { @@ -616,6 +641,10 @@ int main() #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , i_pll_ref +#endif +if (XUA_USE_APP_PLL) + , i_softPll +#endif , p_for_mclk_count_audio #endif ); diff --git a/lib_xua/src/core/user/audiohw/audiohw.c b/lib_xua/src/core/user/audiohw/audiohw.c new file mode 100644 index 00000000..a7713c2c --- /dev/null +++ b/lib_xua/src/core/user/audiohw/audiohw.c @@ -0,0 +1,29 @@ +// Copyright 2023-2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* Default implementations of AudioHwInit(), AudioHwConfig(), AudioHwConfig_Mute() and AudioHwConfig_UnMute() */ + +void AudioHwInit() __attribute__ ((weak)); +void AudioHwInit() +{ + return; +} + +void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) __attribute__ ((weak)); +void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) +{ + return; +} + +void AudioHwConfig_Mute() __attribute__ ((weak)); +void AudioHwConfig_Mute() +{ + return; +} + +void AudioHwConfig_UnMute() __attribute__ ((weak)); +void AudioHwConfig_UnMute() +{ + return; +} + diff --git a/lib_xua/src/core/user/audiohw/audiohw.h b/lib_xua/src/core/user/audiohw/audiohw.h new file mode 100644 index 00000000..aa839991 --- /dev/null +++ b/lib_xua/src/core/user/audiohw/audiohw.h @@ -0,0 +1,54 @@ +// Copyright 2023-2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#ifndef _AUDIO_HW_H_ +#define _AUDIO_HW_H_ + +/* The functions below should be implemented for the external audio hardware arrangement of a specific design. + * Note, default (empty) implementations of these are provided in audiohub_user.c + */ + +/** + * @brief User audio hardware initialisation code + * + * This function is called when the device starts up and should contain user code to perform any required audio hardware initialisation + */ +void AudioHwInit(void); + +/** + * @brief User audio hardware configuration code + * + * This function is called when on sample rate change and should contain user code to configure audio hardware + * (clocking, CODECs etc) for a specific mClk/Sample frequency + * + * \param samFreq The new sample frequency (in Hz) + * + * \param mClk The new master clock frequency (in Hz) + * + * \param dsdMode DSD mode, DSD_MODE_NATIVE, DSD_MODE_DOP or DSD_MODE_OFF + * + * \param sampRes_DAC Playback sample resolution (in bits) + * + * \param sampRes_ADC Record sample resolution (in bits) + */ +void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC); + +/** + * @brief User code mute audio hardware + * + * This function is called before AudioHwConfig() and should contain user code to mute audio hardware before a + * sample rate change in order to reduced audible pops/clicks + * + * Note, if using the application PLL of a xcore.ai device this function will be called before the master-clock is + * changed + */ +void AudioHwConfig_Mute(void); + +/** + * @brief User code to un-mute audio hardware + * + * This function is called after AudioHwConfig() and should contain user code to un-mute audio hardware after a + * sample rate change + */ +void AudioHwConfig_UnMute(void); + +#endif diff --git a/lib_xua/src/core/user/audiostream/audiostream.h b/lib_xua/src/core/user/audiostream/audiostream.h index 1f27774e..4e1ce5e2 100644 --- a/lib_xua/src/core/user/audiostream/audiostream.h +++ b/lib_xua/src/core/user/audiostream/audiostream.h @@ -1,30 +1,51 @@ -// Copyright 2011-2021 XMOS LIMITED. +// Copyright 2011-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef _AUDIOSTREAM_H_ #define _AUDIOSTREAM_H_ -/* Functions that handle functions that must occur on stream start/stop e.g. DAC mute/un-mute - * - * THESE NEED IMPLEMENTING FOR A SPECIFIC DESIGN - * - * */ +/* Functions that handle functionality that occur on stream start/stop e.g. DAC mute/un-mute. + * They should be implemented for the external audio hardware arrangement of a specific design. + */ -/* Any actions required for stream start e.g. DAC un-mute - run every stream start */ +/** + * @brief User stream start code + * + * User code to perform any actions required at every stream start - either input or output + */ void UserAudioStreamStart(void); -/* Any actions required on stream stop e.g. DAC mute - run every steam stop */ +/** + * @brief User stream stop code + * + * User code to perform any actions required on every stream stop - either input or output*/ void UserAudioStreamStop(void); -/* Any actions required on input stream start */ +/** + * @brief User input stream stop code + * + * User code to perform any actions required on input stream start i.e. device to host + */ void UserAudioInputStreamStart(void); -/* Any actions required on input stream stop */ +/** + * @brief User input stream stop code + * + * User code to perform any actions required on input stream stop i.e. device to host + */ void UserAudioInputStreamStop(void); -/* Any actions required on output stream start */ +/** + * @brief User output stream start code + * + * User code to perform any actions required on output stream start i.e. host to device + */ void UserAudioOutputStreamStart(void); -/* Any actions required on output stream stop */ +/** + * @brief User output stream stop code + * + * User code to perfrom any actions required on output stream stop i.e. host to device + */ void UserAudioOutputStreamStop(void); #endif diff --git a/lib_xua/src/core/user/hid/user_hid.h b/lib_xua/src/core/user/hid/user_hid.h index d5b2b425..419682f2 100644 --- a/lib_xua/src/core/user/hid/user_hid.h +++ b/lib_xua/src/core/user/hid/user_hid.h @@ -1,17 +1,17 @@ -// Copyright 2013-2023 XMOS LIMITED. +// Copyright 2013-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /** * @brief Human Interface Device (HID) API * * This file defines the Application Programming Interface (API) used to record HID - * events and retrieve a HID Report for sending to a host. + * events and retrieve a HID Report for sending to a host. * The using application has the responsibility to fulfill this API. * Document section numbers refer to the HID Device Class Definition, version 1.11. */ -#ifndef __USER_HID_H__ -#define __USER_HID_H__ +#ifndef _USER_HID_H_ +#define _USER_HID_H_ #include @@ -34,22 +34,16 @@ typedef struct hidEvent_t { #define HID_MAX_DATA_BYTES ( 4 ) #define HID_EVENT_INVALID_ID ( 0x100 ) -#if XUA_HID_ENABLED - /** * \brief Get the data for the next HID Report * - * \note This function returns the HID data as a list of unsigned char because the - * \c XUD_SetReady_In() accepts data for transmission to the USB Host using - * this type. - * * \param[in] id The HID Report ID (see 5.6, 6.2.2.7, 8.1 and 8.2) * Set to zero if the application provides only one HID Report - * which does not include a Report ID + * which does not include a Report ID * \param[out] hidData The HID data * If using Report IDs, this function places the Report ID in - * the first element; otherwise the first element holds the - * first byte of HID event data. + * the first element; otherwise the first element holds the + * first byte of HID event data. * * \returns The length of the HID Report in the \a hidData argument * \retval Zero means no new HID event data has been recorded for the given \a id @@ -57,9 +51,8 @@ typedef struct hidEvent_t { size_t UserHIDGetData( const unsigned id, unsigned char hidData[ HID_MAX_DATA_BYTES ]); /** - * \brief Initialize HID processing + * \brief Initialize HID processing */ void UserHIDInit( void ); -#endif /* ( 0 < HID_CONTROLS ) */ -#endif /* __USER_HID_H__ */ +#endif /* _USER_HID_H_ */ diff --git a/lib_xua/src/core/user/hostactive/hostactive.h b/lib_xua/src/core/user/hostactive/hostactive.h index fa100d10..c4c2d302 100644 --- a/lib_xua/src/core/user/hostactive/hostactive.h +++ b/lib_xua/src/core/user/hostactive/hostactive.h @@ -1,4 +1,12 @@ -// Copyright 2013-2021 XMOS LIMITED. +// Copyright 2013-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. +/** + * @brief User host active code + * + * This function can be used to perform user defined actions based on host present/not-present events. + * This function is called on a change in state. + * + * \param active Indicates if the host is active or not. 1 for active, else 0 + */ void UserHostActive(int active); diff --git a/tests/test_sync_clk_basic/Makefile b/tests/test_sync_clk_basic/Makefile index 513f2614..86e4e277 100644 --- a/tests/test_sync_clk_basic/Makefile +++ b/tests/test_sync_clk_basic/Makefile @@ -3,10 +3,12 @@ TEST_FLAGS ?= XCC_FLAGS_HS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \ -DBUS_SPEED=2 \ + -DXUA_USE_APP_PLL=0 \ $(TEST_FLAGS) XCC_FLAGS_FS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \ -DBUS_SPEED=1 \ + -DXUA_USE_APP_PLL=0 \ $(TEST_FLAGS) TARGET = test_xs3_600.xn From aac2b4b7fbec07acf02b53a74d4fdc361040029a Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Jan 2024 15:20:37 +0000 Subject: [PATCH 02/30] Initial conflict resolve following merge --- lib_xua/api/xua_audiohub.h | 25 ++++++++++++++-- lib_xua/api/xua_buffer.h | 8 +++--- lib_xua/api/xua_clocking.h | 1 + lib_xua/api/xua_conf_default.h | 13 +++------ lib_xua/module_build_info | 2 ++ lib_xua/src/core/audiohub/xua_audiohub.xc | 7 +++-- lib_xua/src/core/buffer/ep/ep_buffer.xc | 16 +++++------ lib_xua/src/core/main.xc | 35 ++++++++--------------- 8 files changed, 58 insertions(+), 49 deletions(-) diff --git a/lib_xua/api/xua_audiohub.h b/lib_xua/api/xua_audiohub.h index 12c44379..ed9da2aa 100644 --- a/lib_xua/api/xua_audiohub.h +++ b/lib_xua/api/xua_audiohub.h @@ -86,8 +86,29 @@ void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, #endif // __XC__ -void UserBufferManagementInit(unsigned samFreq); - +/** + * @brief User buffer management code + * + * This function is called at the sample rate of the USB Audio stack (e.g,. 48 kHz) and between the two parameter arrays + * contain a full multi-channel audio-frame. The first array carries all the data that has been received from the USB host + * and is to be presented to the audio interfaces. The second array carries all the data received from the interfaces and + * is to be presented to the USB host. The user can chose to intercept and overwrite the samples stored in these arrays. + * + * \param sampsFromUsbToAudio Samples received from USB host and to be presented to audio interfaces + * + * \param sampsFromAudioToUsb Samples received from the audio interfaces and to be presented to the USB host +*/ void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]); +/** + * @brief User buffer managment init code + * + * This function is called once, before the first call to UserBufferManagement(), and can be used to initialise any + * related user state + * + * \param sampFreq The initial sample frequency + * + */ +void UserBufferManagementInit(unsigned sampFreq); + #endif // _XUA_AUDIOHUB_H_ diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index a1299079..7e07a113 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -53,10 +53,10 @@ void XUA_Buffer( #endif , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__) - #if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__) + #if (!USE_SW_PLL) || defined(__DOXYGEN__) , client interface pll_ref_if i_pll_ref #endif - #if (XUA_USE_APP_PLL) || defined(__DOXYGEN__) + #if (USE_SW_PLL) || defined(__DOXYGEN__) , chanend c_swpll_update #endif #endif @@ -88,10 +88,10 @@ void XUA_Buffer_Ep(chanend c_aud_out, , chanend c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__) - #if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__) + #if (!USE_SW_PLL) || defined(__DOXYGEN__) , client interface pll_ref_if i_pll_ref #endif - #if (XUA_USE_APP_PLL) || defined(__DOXYGEN__) + #if (USE_SW_PLL) || defined(__DOXYGEN__) , chanend c_swpll_update #endif #endif diff --git a/lib_xua/api/xua_clocking.h b/lib_xua/api/xua_clocking.h index f24ab1b5..f2a80c1c 100644 --- a/lib_xua/api/xua_clocking.h +++ b/lib_xua/api/xua_clocking.h @@ -39,6 +39,7 @@ void clockGen( streaming chanend ?c_spdif_rx, port ?p_for_mclk_count_aud, chanend c_mclk_change); +#if (XUA_USE_APP_PLL) interface SoftPll_if { diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 0fbb1046..5937fe07 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -265,21 +265,16 @@ #endif /** - * @brief Enable/disable the use of the secondary/application PLL for generating master-clocks. + * @brief Enable/disable the use of the secondary/application PLL for generating and recovering master-clocks. * Only available on xcore.ai devices. * * Default: Enabled (for xcore.ai devices) */ -#ifndef XUA_USE_APP_PLL +#ifndef USE_SW_PLL #if defined(__XS3A__) - #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - /* Currently must use an external CS2100 device for syncing to external digital streams */ - #define XUA_USE_APP_PLL (0) - #else - #define XUA_USE_APP_PLL (1) - #endif + #define USE_SW_PLL (1) #else - #define XUA_USE_APP_PLL (0) + #define USE_SW_PLL (0) #endif #endif diff --git a/lib_xua/module_build_info b/lib_xua/module_build_info index 444c67ce..d11e0585 100644 --- a/lib_xua/module_build_info +++ b/lib_xua/module_build_info @@ -54,6 +54,7 @@ INCLUDE_DIRS = $(EXPORT_INCLUDE_DIRS) \ src/core/support \ src/core/user \ src/core/user/audiostream \ + src/core/user/audiohw \ src/core/user/hid \ src/core/user/hostactive \ src/hid \ @@ -70,6 +71,7 @@ SOURCE_DIRS = src/core \ src/core/ports \ src/core/support \ src/core/user/audiostream \ + src/core/user/audiohw \ src/core/user/hostactive \ src/core/xuduser \ src/dfu \ diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 3c6ce660..279ef608 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -814,9 +814,10 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, /* User should mute audio hardware */ AudioHwConfig_Mute(); - #if (XUA_USE_APP_PLL) - i_softPll.init(mClk); - #endif +#if (USE_SW_PLL) + // i_softPll.init(mClk); + #warning SORT THIS +#endif /* User code should configure audio harware for SampleFreq/MClk etc */ AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC); diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 2a7ee928..0544b960 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -105,7 +105,7 @@ void XUA_Buffer( #endif , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - #if(XUA_USE_APP_PLL) + #if(USE_SW_PLL) , chanend c_swpll_update #else , client interface pll_ref_if i_pll_ref @@ -145,7 +145,7 @@ void XUA_Buffer( , c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - #if(XUA_USE_APP_PLL) + #if(USE_SW_PLL) , c_swpll_update #else , i_pll_ref @@ -199,7 +199,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, , chanend c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - #if (XUA_USE_APP_PLL) + #if (USE_SW_PLL) , chanend c_swpll_update #else , client interface pll_ref_if i_pll_ref @@ -370,7 +370,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #define LOCAL_CLOCK_MARGIN (1000) #endif -#if (!XUA_USE_APP_PLL) +#if (!USE_SW_PLL) timer t_sofCheck; unsigned timeLastEdge; unsigned timeNextEdge; @@ -379,7 +379,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, i_pll_ref.toggle(); #endif -#endif +#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) */ while(1) { @@ -525,7 +525,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, } break; } -#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL) +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!USE_SW_PLL) case t_sofCheck when timerafter(timeNextEdge) :> void: i_pll_ref.toggle(); timeLastEdge = timeNextEdge; @@ -557,14 +557,14 @@ void XUA_Buffer_Ep(register chanend c_aud_out, { sofCount = 0; pllUpdate++; -#if (!XUA_USE_APP_PLL) +#if (!USE_SW_PLL) /* Port is accessed via interface to allow flexibilty with location */ i_pll_ref.toggle(); t_sofCheck :> timeLastEdge; timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; #endif } -#if (XUA_USE_APP_PLL) +#if (USE_SW_PLL) // Update PLL @ 100Hz if(pllUpdate == 10) { diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 6bfb1b30..053dd63b 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -316,9 +316,6 @@ void usb_audio_io(chanend ?c_aud_in, , client interface pll_ref_if i_pll_ref , port ?p_for_mclk_count_aud #endif - #if (XUA_USE_APP_PLL) - , client interface SoftPll_if i_softPll - #endif ) { #if (MIXER) @@ -376,9 +373,6 @@ 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 @@ -489,13 +483,12 @@ int main() #endif #endif -#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && !USE_SW_PLL) interface pll_ref_if i_pll_ref; #endif -#if (XUA_USE_APP_PLL) - interface SoftPll_if i_softPll; - chan c_swpll_update; +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) + chan c_sw_pll; #endif chan c_sof; chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */ @@ -518,7 +511,7 @@ int main() { USER_MAIN_CORES -#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XUA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && !USE_SW_PLL) on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref); #endif on tile[XUD_TILE]: @@ -531,7 +524,7 @@ int main() DFUHandler(dfuInterface, null); #endif -#if (XUA_USE_APP_PLL) +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) //XUA_SoftPll(tile[0], i_softPll, c_swpll_update); #endif @@ -593,13 +586,11 @@ int main() #endif , c_mix_out #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - #if (!XUA_USE_APP_PLL) - + #if (!USE_SW_PLL) , i_pll_ref #else - , c_swpll_update + , c_sw_pll #endif -#endif #endif ); //: @@ -614,8 +605,8 @@ int main() #endif /* XUA_USB_EN */ } -#if(XUA_USE_APP_PLL) - on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update); +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) + // on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update); #endif on tile[AUDIO_IO_TILE]: @@ -634,17 +625,15 @@ int main() , dfuInterface #endif #if (XUA_NUM_PDM_MICS > 0) -#if (PDM_TILE == AUDIO_IO_TILE) + #if (PDM_TILE == AUDIO_IO_TILE) , c_ds_output -#endif + #endif , c_pdm_pcm #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , i_pll_ref #endif -if (XUA_USE_APP_PLL) - , i_softPll -#endif +#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , p_for_mclk_count_audio #endif ); From ca16467158a4ce71118213f7a1f48001b3f29508 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Jan 2024 17:00:54 +0000 Subject: [PATCH 03/30] Building but not tested merge --- lib_xua/api/xua_clocking.h | 10 +- lib_xua/src/core/audiohub/xua_audiohub.xc | 11 +- lib_xua/src/core/clocking/clockgen.xc | 887 ++++++++++---------- lib_xua/src/core/clocking/sw_pll_wrapper.h | 14 +- lib_xua/src/core/clocking/sw_pll_wrapper.xc | 107 +-- lib_xua/src/core/main.xc | 33 +- 6 files changed, 521 insertions(+), 541 deletions(-) diff --git a/lib_xua/api/xua_clocking.h b/lib_xua/api/xua_clocking.h index f2a80c1c..c0240035 100644 --- a/lib_xua/api/xua_clocking.h +++ b/lib_xua/api/xua_clocking.h @@ -6,6 +6,8 @@ #include +#include "sw_pll_wrapper.h" + interface pll_ref_if { void toggle(); @@ -26,9 +28,10 @@ void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_sync); * clock * \param c_clk_int channel connected to the decouple() thread for clock * interrupts - * \param p_for_mclk_count_aud port used for counting mclk and providing a timestamp - * * \param c_mclk_change channel to notify of master clock change + * \param p_for_mclk_count_aud port used for counting mclk and providing a timestamp + * \param c_sw_pll channel used to communicate with software PLL task + * */ void clockGen( streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, @@ -36,8 +39,9 @@ void clockGen( streaming chanend ?c_spdif_rx, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int, + chanend c_mclk_change, port ?p_for_mclk_count_aud, - chanend c_mclk_change); + chanend ?c_sw_pll); #if (XUA_USE_APP_PLL) diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 279ef608..35751848 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -636,9 +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_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 @@ -814,11 +814,6 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, /* User should mute audio hardware */ AudioHwConfig_Mute(); -#if (USE_SW_PLL) - // i_softPll.init(mClk); - #warning SORT THIS -#endif - /* User code should configure audio harware for SampleFreq/MClk etc */ AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC); #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) diff --git a/lib_xua/src/core/clocking/clockgen.xc b/lib_xua/src/core/clocking/clockgen.xc index 08040504..479b56d7 100644 --- a/lib_xua/src/core/clocking/clockgen.xc +++ b/lib_xua/src/core/clocking/clockgen.xc @@ -7,7 +7,6 @@ #include "xua.h" #include "xua_commands.h" #include "xua_clocking.h" -#include "sw_pll_wrapper.h" #if (XUA_SPDIF_RX_EN) #include "spdif.h" @@ -201,8 +200,6 @@ static inline int validSamples(Counter &counter, int clockIndex) #endif #if USE_SW_PLL -/* Pointer to sw_pll struct to allow it to be used in separate SDM thread */ -extern sw_pll_state_t * unsafe sw_pll_ptr; unsafe { unsigned * unsafe selected_mclk_rate_ptr = NULL; @@ -225,8 +222,9 @@ void clockGen ( streaming chanend ?c_spdif_rx, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int, + chanend c_mclk_change, port ?p_for_mclk_count_aud, - chanend c_mclk_change) + chanend ?c_sw_pll) { timer t_local; unsigned timeNextEdge, timeLastEdge, timeNextClockDetection; @@ -343,568 +341,551 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Initial ref clock output and get timestamp */ i_pll_ref.init(); -#if (USE_SW_PLL && (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) - chan c_sigma_delta; +#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) int reset_sw_pll_pfd = 1; int require_ack_to_audio = 0; - - /* Set selected_mclk_rate_ptr to point at local var selected_mclk_rate */ - unsafe { - selected_mclk_rate_ptr = &selected_mclk_rate; - } - - par - { - while(1) - { - unsafe - { - SigmaDeltaTask(c_sigma_delta, selected_mclk_rate_ptr); - } - } -#else - { + restart_sigma_delta(c_sw_pll, MCLK_48); /* default to 48kHz - this will be reset shortly when host selects rate */ #endif - while(1) + + while(1) + { + select { - select - { #ifdef LEVEL_METER_LEDS #warning Level metering enabled - case t_level when timerafter(levelTime) :> void: + case t_level when timerafter(levelTime) :> void: - levelTime += LEVEL_UPDATE_RATE; + levelTime += LEVEL_UPDATE_RATE; - /* Copy over level data and reset */ - for(int i = 0; i< NUM_USB_CHAN_IN; i++) + /* Copy over level data and reset */ + for(int i = 0; i< NUM_USB_CHAN_IN; i++) + { + int tmp; + + /* Read level data */ + //g_inputLevelData[i] = samples_to_host_inputs[i]; + asm volatile("ldw %0, %1[%2]":"=r"(tmp):"r"((const int *)samples_to_host_inputs),"r"(i)); + g_inputLevelData[i] = tmp; + + /* Reset level data */ + //samples_to_host_inputs[i] = 0; + asm volatile("stw %0, %1[%2]"::"r"(0),"r"((const int *)samples_to_host_inputs),"r"(i)); + + /* Guard against host polling slower than timer and missing peaks */ + asm volatile("ldw %0, %1[%2]":"=r"(tmp):"r"((const int *)samples_to_host_inputs_buff),"r"(i)); + + if (g_inputLevelData[i] > tmp) + //if(g_inputLevelData[i] > samples_to_host_inputs_buff[i]) { - int tmp; - - /* Read level data */ - //g_inputLevelData[i] = samples_to_host_inputs[i]; - asm volatile("ldw %0, %1[%2]":"=r"(tmp):"r"((const int *)samples_to_host_inputs),"r"(i)); - g_inputLevelData[i] = tmp; - - /* Reset level data */ - //samples_to_host_inputs[i] = 0; - asm volatile("stw %0, %1[%2]"::"r"(0),"r"((const int *)samples_to_host_inputs),"r"(i)); - - /* Guard against host polling slower than timer and missing peaks */ - asm volatile("ldw %0, %1[%2]":"=r"(tmp):"r"((const int *)samples_to_host_inputs_buff),"r"(i)); - - if (g_inputLevelData[i] > tmp) - //if(g_inputLevelData[i] > samples_to_host_inputs_buff[i]) - { - //samples_to_host_inputs_buff[i] = g_inputLevelData[i]; - asm volatile("stw %0, %1[%2]"::"r"(tmp),"r"((const int *)samples_to_host_inputs),"r"(i)); - } + //samples_to_host_inputs_buff[i] = g_inputLevelData[i]; + asm volatile("stw %0, %1[%2]"::"r"(tmp),"r"((const int *)samples_to_host_inputs),"r"(i)); } + } - /* Call user LED refresh */ - VendorLedRefresh(g_inputLevelData); + /* Call user LED refresh */ + VendorLedRefresh(g_inputLevelData); - break; + break; #endif - /* Updates to clock settings from endpoint 0 */ - case inuint_byref(c_clk_ctl, tmp): - switch(tmp) - { - case GET_SEL: - chkct(c_clk_ctl, XS1_CT_END); + /* Updates to clock settings from endpoint 0 */ + case inuint_byref(c_clk_ctl, tmp): + switch(tmp) + { + case GET_SEL: + chkct(c_clk_ctl, XS1_CT_END); - /* Send back current clock mode */ - outuint(c_clk_ctl, clkMode); - outct(c_clk_ctl, XS1_CT_END); + /* Send back current clock mode */ + outuint(c_clk_ctl, clkMode); + outct(c_clk_ctl, XS1_CT_END); - break; + break; - case SET_SEL: - /* Update clock mode */ - clkMode = inuint(c_clk_ctl); - chkct(c_clk_ctl, XS1_CT_END); + case SET_SEL: + /* Update clock mode */ + clkMode = inuint(c_clk_ctl); + chkct(c_clk_ctl, XS1_CT_END); #ifdef CLOCK_VALIDITY_CALL - switch(clkMode) - { - case CLOCK_INTERNAL: - VendorClockValidity(1); - break; + switch(clkMode) + { + case CLOCK_INTERNAL: + VendorClockValidity(1); + break; #if (XUA_ADAT_RX_EN) - case CLOCK_ADAT: - VendorClockValidity(clockValid[CLOCK_ADAT]); - break; + case CLOCK_ADAT: + VendorClockValidity(clockValid[CLOCK_ADAT]); + break; #endif #if (XUA_SPDIF_RX_EN) - case CLOCK_SPDIF: - VendorClockValidity(clockValid[CLOCK_SPDIF]); - break; + case CLOCK_SPDIF: + VendorClockValidity(clockValid[CLOCK_SPDIF]); + break; #endif - } + } #endif - break; + break; - case GET_VALID: - /* Clock Unit Index */ - tmp = inuint(c_clk_ctl); - chkct(c_clk_ctl, XS1_CT_END); - outuint(c_clk_ctl, clockValid[tmp]); - outct(c_clk_ctl, XS1_CT_END); - break; + case GET_VALID: + /* Clock Unit Index */ + tmp = inuint(c_clk_ctl); + chkct(c_clk_ctl, XS1_CT_END); + outuint(c_clk_ctl, clockValid[tmp]); + outct(c_clk_ctl, XS1_CT_END); + break; - case GET_FREQ: - tmp = inuint(c_clk_ctl); - chkct(c_clk_ctl, XS1_CT_END); - outuint(c_clk_ctl, clockFreq[tmp]); - outct(c_clk_ctl, XS1_CT_END); - break; + case GET_FREQ: + tmp = inuint(c_clk_ctl); + chkct(c_clk_ctl, XS1_CT_END); + outuint(c_clk_ctl, clockFreq[tmp]); + outct(c_clk_ctl, XS1_CT_END); + break; - case SET_SMUX: - smux = inuint(c_clk_ctl); + case SET_SMUX: + smux = inuint(c_clk_ctl); #if (XUA_ADAT_RX_EN) - adatRd = 0; /* Reset adat FIFO */ - adatWr = 0; - adatSamps = 0; + adatRd = 0; /* Reset adat FIFO */ + adatWr = 0; + adatSamps = 0; #endif - chkct(c_clk_ctl, XS1_CT_END); - break; + chkct(c_clk_ctl, XS1_CT_END); + break; - default: + default: #ifdef VENDOR_AUDCORE_REQS - if(VendorAudCoreReqs(tmp, c_clk_ctl)) + if(VendorAudCoreReqs(tmp, c_clk_ctl)) #endif - printstrln("ERR: Bad req in clockgen\n"); - break; - } + printstrln("ERR: Bad req in clockgen\n"); + break; + } - break; + break; - /* Generate local clock from timer */ - case t_local when timerafter(timeNextEdge) :> void: + /* Generate local clock from timer */ + case t_local when timerafter(timeNextEdge) :> void: #if USE_SW_PLL - /* Do nothing - hold the most recent sw_pll setting */ + /* Do nothing - hold the most recent sw_pll setting */ #else - /* Setup next local clock edge */ - i_pll_ref.toggle_timed(0); + /* Setup next local clock edge */ + i_pll_ref.toggle_timed(0); #endif - /* Record time of edge */ - timeLastEdge = timeNextEdge; + /* Record time of edge */ + timeLastEdge = timeNextEdge; - /* Setup for next edge */ - timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT/2); - timeNextEdge += LOCAL_CLOCK_INCREMENT; + /* Setup for next edge */ + timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT/2); + timeNextEdge += LOCAL_CLOCK_INCREMENT; - /* If we are in an external clock mode and this fire, then clock invalid - * reset counters in case we are moved to digital clock - we want a well timed - * first edge */ + /* If we are in an external clock mode and this fire, then clock invalid + * reset counters in case we are moved to digital clock - we want a well timed + * first edge */ #if (XUA_SPDIF_RX_EN) - spdifCounters.receivedSamples = 0; + spdifCounters.receivedSamples = 0; #endif #if (XUA_ADAT_RX_EN) - adatCounters.receivedSamples = 0; + adatCounters.receivedSamples = 0; #endif #ifdef CLOCK_VALIDITY_CALL - if(clkMode == CLOCK_INTERNAL) - { - /* Internal clock always valid */ - VendorClockValidity(1); - } + if(clkMode == CLOCK_INTERNAL) + { + /* Internal clock always valid */ + VendorClockValidity(1); + } #endif - break; + break; #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - case t_external when timerafter(timeNextClockDetection) :> void: - { - int valid; - timeNextClockDetection += (LOCAL_CLOCK_INCREMENT); + case t_external when timerafter(timeNextClockDetection) :> void: + { + int valid; + timeNextClockDetection += (LOCAL_CLOCK_INCREMENT); #if (XUA_SPDIF_RX_EN) - /* Returns 1 if valid clock found */ - valid = validSamples(spdifCounters, CLOCK_SPDIF); - setClockValidity(c_clk_int, CLOCK_SPDIF, valid, clkMode); + /* Returns 1 if valid clock found */ + valid = validSamples(spdifCounters, CLOCK_SPDIF); + setClockValidity(c_clk_int, CLOCK_SPDIF, valid, clkMode); #endif #if (XUA_ADAT_RX_EN) - /* Returns 1 if valid clock found */ - valid = validSamples(adatCounters, CLOCK_ADAT); - setClockValidity(c_clk_int, CLOCK_ADAT, valid, clkMode); + /* Returns 1 if valid clock found */ + valid = validSamples(adatCounters, CLOCK_ADAT); + setClockValidity(c_clk_int, CLOCK_ADAT, valid, clkMode); #endif - } - break; + } + break; #endif #if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) - case inuint_byref(c_sigma_delta, tmp): - /* Send ACK back to audiohub to allow I2S to start - This happens only on SDM restart and only once */ - if(require_ack_to_audio) - { - c_mclk_change <: tmp; - require_ack_to_audio = 0; - } - break; + case inuint_byref(c_sw_pll, tmp): + /* Send ACK back to audiohub to allow I2S to start + This happens only on SDM restart and only once */ + if(require_ack_to_audio) + { + c_mclk_change <: tmp; + require_ack_to_audio = 0; + } + break; #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - /* Receive notification of audio streaming settings change and store */ - case c_mclk_change :> selected_mclk_rate: - c_mclk_change :> selected_sample_rate; + /* Receive notification of audio streaming settings change and store */ + case c_mclk_change :> selected_mclk_rate: + c_mclk_change :> selected_sample_rate; #if USE_SW_PLL - mclks_per_sample = selected_mclk_rate / selected_sample_rate; - restart_sigma_delta(c_sigma_delta); - reset_sw_pll_pfd = 1; - /* We will shedule an ACK when sigma delta is up and running */ - require_ack_to_audio = 1; + mclks_per_sample = selected_mclk_rate / selected_sample_rate; + restart_sigma_delta(c_sw_pll, selected_mclk_rate); + reset_sw_pll_pfd = 1; + /* We will shedule an ACK when sigma delta is up and running */ + require_ack_to_audio = 1; #else - /* Send ACK immediately as we are good to go if not using SW_PLL */ - c_mclk_change <: 0; + /* Send ACK immediately as we are good to go if not using SW_PLL */ + c_mclk_change <: 0; #endif - break; + break; #endif #if (XUA_SPDIF_RX_EN) - /* Receive sample from S/PDIF RX thread (streaming chan) */ - case c_spdif_rx :> spdifRxData: + /* Receive sample from S/PDIF RX thread (streaming chan) */ + case c_spdif_rx :> spdifRxData: - /* Record time of sample */ + /* Record time of sample */ + if(!isnull(p_for_mclk_count_aud)) + { + asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); + } + t_local :> spdifRxTime; + + /* Check parity and ignore if bad */ + if(spdif_rx_check_parity(spdifRxData)) + continue; + + /* Get preamble */ + unsigned preamble = spdifRxData & SPDIF_RX_PREAMBLE_MASK; + + switch(preamble) + { + /* LEFT */ + case SPDIF_FRAME_X: + case SPDIF_FRAME_Z: + spdifLeft = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData); + break; + + /* RIGHT */ + case SPDIF_FRAME_Y: + + /* Only store sample if not in overflow and stream is reasonably valid */ + if(!spdifOverflow && clockValid[CLOCK_SPDIF]) + { + /* Store left and right sample pair to buffer */ + spdifSamples[spdifWr] = spdifLeft; + spdifSamples[spdifWr+1] = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData); + + spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1); + + spdifSamps += 2; + + /* Check for over flow */ + if(spdifSamps > MAX_SPDIF_SAMPLES-1) + { + spdifOverflow = 1; + } + + /* Check for coming out of under flow */ + if(spdifUnderflow && (spdifSamps >= (MAX_SPDIF_SAMPLES >> 1))) + { + spdifUnderflow = 0; + } + } + break; + + default: + /* Bad sample, skip */ + continue; + break; + } + + spdifCounters.samples += 1; + + if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF]) + { + spdifCounters.receivedSamples+=1; + + /* Inspect for if we need to produce an edge */ + if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick)) + { + /* Check edge is about right... S/PDIF may have changed freq... */ + if(timeafter(spdifRxTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN))) + { + /* Record edge time */ + timeLastEdge = spdifRxTime; + + /* Setup for next edge */ + timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; + +#if USE_SW_PLL + do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, + mclks_per_sample, + c_sw_pll, + spdifCounters.receivedSamples, + reset_sw_pll_pfd); +#else + /* Toggle edge */ + i_pll_ref.toggle_timed(1); +#endif + /* Reset counters */ + spdifCounters.receivedSamples = 0; + } + } + } + break; +#endif +#if (XUA_ADAT_RX_EN) + /* receive sample from ADAT rx thread (streaming channel with CT_END) */ + case inuint_byref(c_adat_rx, tmp): + /* record time of sample */ if(!isnull(p_for_mclk_count_aud)) { asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); } - t_local :> spdifRxTime; + t_local :> adatReceivedTime; - /* Check parity and ignore if bad */ - if(spdif_rx_check_parity(spdifRxData)) + /* Sync is: 1 | (user_byte << 4) */ + if(tmp&1) + { + /* user bits - start of frame */ + adatChannel = 0; continue; - - /* Get preamble */ - unsigned preamble = spdifRxData & SPDIF_RX_PREAMBLE_MASK; - - switch(preamble) - { - /* LEFT */ - case SPDIF_FRAME_X: - case SPDIF_FRAME_Z: - spdifLeft = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData); - break; - - /* RIGHT */ - case SPDIF_FRAME_Y: - - /* Only store sample if not in overflow and stream is reasonably valid */ - if(!spdifOverflow && clockValid[CLOCK_SPDIF]) - { - /* Store left and right sample pair to buffer */ - spdifSamples[spdifWr] = spdifLeft; - spdifSamples[spdifWr+1] = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData); - - spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1); - - spdifSamps += 2; - - /* Check for over flow */ - if(spdifSamps > MAX_SPDIF_SAMPLES-1) - { - spdifOverflow = 1; - } - - /* Check for coming out of under flow */ - if(spdifUnderflow && (spdifSamps >= (MAX_SPDIF_SAMPLES >> 1))) - { - spdifUnderflow = 0; - } - } - break; - - default: - /* Bad sample, skip */ - continue; - break; - } - - spdifCounters.samples += 1; - - if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF]) - { - spdifCounters.receivedSamples+=1; - - /* Inspect for if we need to produce an edge */ - if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick)) - { - /* Check edge is about right... S/PDIF may have changed freq... */ - if(timeafter(spdifRxTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN))) - { - /* Record edge time */ - timeLastEdge = spdifRxTime; - - /* Setup for next edge */ - timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; - -#if USE_SW_PLL - do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, - mclks_per_sample, - c_sigma_delta, - spdifCounters.receivedSamples, - reset_sw_pll_pfd); -#else - /* Toggle edge */ - i_pll_ref.toggle_timed(1); -#endif - /* Reset counters */ - spdifCounters.receivedSamples = 0; - } - } } - break; -#endif -#if (XUA_ADAT_RX_EN) - /* receive sample from ADAT rx thread (streaming channel with CT_END) */ - case inuint_byref(c_adat_rx, tmp): - /* record time of sample */ - if(!isnull(p_for_mclk_count_aud)) - { - asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); - } - t_local :> adatReceivedTime; + else + { + /* audio sample */ + adatSamplesEver++; + adatFrame[adatChannel] = tmp; - /* Sync is: 1 | (user_byte << 4) */ - if(tmp&1) + adatChannel++; + if (adatChannel == 8) { - /* user bits - start of frame */ - adatChannel = 0; - continue; - } - else - { - /* audio sample */ - adatSamplesEver++; - adatFrame[adatChannel] = tmp; - - adatChannel++; - if (adatChannel == 8) + /* only store left samples if not in overflow and stream is reasonably valid */ + if (!adatOverflow && clockValid[CLOCK_ADAT]) { - /* only store left samples if not in overflow and stream is reasonably valid */ - if (!adatOverflow && clockValid[CLOCK_ADAT]) + /* Unpick the SMUX.. */ + if(smux == 2) { - /* Unpick the SMUX.. */ - if(smux == 2) + adatSamples[adatWr + 0] = adatFrame[0]; + adatSamples[adatWr + 1] = adatFrame[4]; + adatSamples[adatWr + 2] = adatFrame[1]; + adatSamples[adatWr + 3] = adatFrame[5]; + adatSamples[adatWr + 4] = adatFrame[2]; + adatSamples[adatWr + 5] = adatFrame[6]; + adatSamples[adatWr + 6] = adatFrame[3]; + adatSamples[adatWr + 7] = adatFrame[7]; + } + else if(smux) + { + + adatSamples[adatWr + 0] = adatFrame[0]; + adatSamples[adatWr + 1] = adatFrame[2]; + adatSamples[adatWr + 2] = adatFrame[4]; + adatSamples[adatWr + 3] = adatFrame[6]; + adatSamples[adatWr + 4] = adatFrame[1]; + adatSamples[adatWr + 5] = adatFrame[3]; + adatSamples[adatWr + 6] = adatFrame[5]; + adatSamples[adatWr + 7] = adatFrame[7]; + } + else + { + adatSamples[adatWr + 0] = adatFrame[0]; + adatSamples[adatWr + 1] = adatFrame[1]; + adatSamples[adatWr + 2] = adatFrame[2]; + adatSamples[adatWr + 3] = adatFrame[3]; + adatSamples[adatWr + 4] = adatFrame[4]; + adatSamples[adatWr + 5] = adatFrame[5]; + adatSamples[adatWr + 6] = adatFrame[6]; + adatSamples[adatWr + 7] = adatFrame[7]; + } + adatWr = (adatWr + 8) & (MAX_ADAT_SAMPLES - 1); + adatSamps += 8; + + /* check for overflow */ + if (adatSamps > MAX_ADAT_SAMPLES - 1) { - adatSamples[adatWr + 0] = adatFrame[0]; - adatSamples[adatWr + 1] = adatFrame[4]; - adatSamples[adatWr + 2] = adatFrame[1]; - adatSamples[adatWr + 3] = adatFrame[5]; - adatSamples[adatWr + 4] = adatFrame[2]; - adatSamples[adatWr + 5] = adatFrame[6]; - adatSamples[adatWr + 6] = adatFrame[3]; - adatSamples[adatWr + 7] = adatFrame[7]; + adatOverflow = 1; } - else if(smux) - { - adatSamples[adatWr + 0] = adatFrame[0]; - adatSamples[adatWr + 1] = adatFrame[2]; - adatSamples[adatWr + 2] = adatFrame[4]; - adatSamples[adatWr + 3] = adatFrame[6]; - adatSamples[adatWr + 4] = adatFrame[1]; - adatSamples[adatWr + 5] = adatFrame[3]; - adatSamples[adatWr + 6] = adatFrame[5]; - adatSamples[adatWr + 7] = adatFrame[7]; + /* check for coming out of underflow */ + if (adatUnderflow && (adatSamps >= (MAX_ADAT_SAMPLES >> 1))) + { + adatUnderflow = 0; } - else + } + } + if(adatChannel == 4 || adatChannel == 8) + { + adatCounters.samples += 1; + + if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT]) + { + adatCounters.receivedSamples += 1; + + /* Inspect for if we need to produce an edge */ + if ((adatCounters.receivedSamples >= adatCounters.samplesPerTick)) { - adatSamples[adatWr + 0] = adatFrame[0]; - adatSamples[adatWr + 1] = adatFrame[1]; - adatSamples[adatWr + 2] = adatFrame[2]; - adatSamples[adatWr + 3] = adatFrame[3]; - adatSamples[adatWr + 4] = adatFrame[4]; - adatSamples[adatWr + 5] = adatFrame[5]; - adatSamples[adatWr + 6] = adatFrame[6]; - adatSamples[adatWr + 7] = adatFrame[7]; - } - adatWr = (adatWr + 8) & (MAX_ADAT_SAMPLES - 1); - adatSamps += 8; - - /* check for overflow */ - if (adatSamps > MAX_ADAT_SAMPLES - 1) + /* Check edge is about right... ADAT may have changed freq... */ + if (timeafter(adatReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN))) { - adatOverflow = 1; - } + /* Record edge time */ + timeLastEdge = adatReceivedTime; - /* check for coming out of underflow */ - if (adatUnderflow && (adatSamps >= (MAX_ADAT_SAMPLES >> 1))) - { - adatUnderflow = 0; - } - } - } - if(adatChannel == 4 || adatChannel == 8) - { - adatCounters.samples += 1; - - if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT]) - { - adatCounters.receivedSamples += 1; - - /* Inspect for if we need to produce an edge */ - if ((adatCounters.receivedSamples >= adatCounters.samplesPerTick)) - { - /* Check edge is about right... ADAT may have changed freq... */ - if (timeafter(adatReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN))) - { - /* Record edge time */ - timeLastEdge = adatReceivedTime; - - /* Setup for next edge */ - timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; + /* Setup for next edge */ + timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; #if USE_SW_PLL - do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, - mclks_per_sample, - c_sigma_delta, - adatCounters.receivedSamples, - reset_sw_pll_pfd); + do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, + mclks_per_sample, + c_sw_pll, + adatCounters.receivedSamples, + reset_sw_pll_pfd); #else - /* Toggle edge */ - i_pll_ref.toggle_timed(1); + /* Toggle edge */ + i_pll_ref.toggle_timed(1); #endif - - /* Reset counters */ - adatCounters.receivedSamples = 0; - } + + /* Reset counters */ + adatCounters.receivedSamples = 0; } } } - if (adatChannel == 8) - adatChannel = 0; } - break; + if (adatChannel == 8) + adatChannel = 0; + } + break; #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - /* AudioHub requests data */ - case inuint_byref(c_dig_rx, tmp): + /* AudioHub requests data */ + case inuint_byref(c_dig_rx, tmp): #if (XUA_SPDIF_RX_EN) - if(spdifUnderflow) + if(spdifUnderflow) + { + /* S/PDIF underflowing, send out zero samples */ + g_digData[0] = 0; + g_digData[1] = 0; + } + else + { + /* Read out samples from S/PDIF buffer and send... */ + tmp = spdifSamples[spdifRd]; + tmp2 = spdifSamples[spdifRd + 1]; + + spdifRd += 2; + spdifRd &= (MAX_SPDIF_SAMPLES - 1); + + g_digData[0] = tmp; + g_digData[1] = tmp2; + + spdifSamps -= 2; + + /* spdifSamps could go to -1 */ + if(spdifSamps <= 0) { - /* S/PDIF underflowing, send out zero samples */ - g_digData[0] = 0; - g_digData[1] = 0; + /* We're out of S/PDIF samples, mark underflow condition */ + spdifUnderflow = 1; + spdifLeft = 0; } - else + + /* If we are in over flow condition and we have a sensible number of samples + * come out of overflow condition */ + if(spdifOverflow && (spdifSamps < (MAX_SPDIF_SAMPLES>>1))) { - /* Read out samples from S/PDIF buffer and send... */ - tmp = spdifSamples[spdifRd]; - tmp2 = spdifSamples[spdifRd + 1]; - - spdifRd += 2; - spdifRd &= (MAX_SPDIF_SAMPLES - 1); - - g_digData[0] = tmp; - g_digData[1] = tmp2; - - spdifSamps -= 2; - - /* spdifSamps could go to -1 */ - if(spdifSamps <= 0) - { - /* We're out of S/PDIF samples, mark underflow condition */ - spdifUnderflow = 1; - spdifLeft = 0; - } - - /* If we are in over flow condition and we have a sensible number of samples - * come out of overflow condition */ - if(spdifOverflow && (spdifSamps < (MAX_SPDIF_SAMPLES>>1))) - { - spdifOverflow = 0; - } + spdifOverflow = 0; } + } #endif #if (XUA_ADAT_RX_EN) - if (adatUnderflow) + if (adatUnderflow) + { + /* ADAT underflowing, send out zero samples */ + g_digData[2] = 0; + g_digData[3] = 0; + g_digData[4] = 0; + g_digData[5] = 0; + g_digData[6] = 0; + g_digData[7] = 0; + g_digData[8] = 0; + g_digData[9] = 0; + } + else + { + /* read out samples from the ADAT buffer and send */ + /* always return 8 samples */ + /* SMUX II mode */ + if (smux == 2) { - /* ADAT underflowing, send out zero samples */ - g_digData[2] = 0; - g_digData[3] = 0; + /* SMUX2 mode - 2 samples from fifo and 4 zero samples */ + g_digData[2] = adatSamples[adatRd + 0]; + g_digData[3] = adatSamples[adatRd + 1]; + g_digData[4] = 0; g_digData[5] = 0; g_digData[6] = 0; g_digData[7] = 0; g_digData[8] = 0; g_digData[9] = 0; + adatRd = (adatRd + 2) & (MAX_ADAT_SAMPLES - 1); + adatSamps -= 2; + } + else if(smux) + { + /* SMUX mode - 4 samples from fifo and 4 zero samples */ + g_digData[2] = adatSamples[adatRd + 0]; + g_digData[3] = adatSamples[adatRd + 1]; + g_digData[4] = adatSamples[adatRd + 2]; + g_digData[5] = adatSamples[adatRd + 3]; + + g_digData[6] = 0; + g_digData[7] = 0; + g_digData[8] = 0; + g_digData[9] = 0; + adatRd = (adatRd + 4) & (MAX_ADAT_SAMPLES - 1); + adatSamps -= 4; } else { - /* read out samples from the ADAT buffer and send */ - /* always return 8 samples */ - /* SMUX II mode */ - if (smux == 2) - { - /* SMUX2 mode - 2 samples from fifo and 4 zero samples */ - g_digData[2] = adatSamples[adatRd + 0]; - g_digData[3] = adatSamples[adatRd + 1]; + /* no SMUX mode - 8 samples from fifo */ + g_digData[2] = adatSamples[adatRd + 0]; + g_digData[3] = adatSamples[adatRd + 1]; + g_digData[4] = adatSamples[adatRd + 2]; + g_digData[5] = adatSamples[adatRd + 3]; - g_digData[4] = 0; - g_digData[5] = 0; - g_digData[6] = 0; - g_digData[7] = 0; - g_digData[8] = 0; - g_digData[9] = 0; - adatRd = (adatRd + 2) & (MAX_ADAT_SAMPLES - 1); - adatSamps -= 2; - } - else if(smux) - { - /* SMUX mode - 4 samples from fifo and 4 zero samples */ - g_digData[2] = adatSamples[adatRd + 0]; - g_digData[3] = adatSamples[adatRd + 1]; - g_digData[4] = adatSamples[adatRd + 2]; - g_digData[5] = adatSamples[adatRd + 3]; + g_digData[6] = adatSamples[adatRd + 4]; + g_digData[7] = adatSamples[adatRd + 5]; + g_digData[8] = adatSamples[adatRd + 6]; + g_digData[9] = adatSamples[adatRd + 7]; - g_digData[6] = 0; - g_digData[7] = 0; - g_digData[8] = 0; - g_digData[9] = 0; - adatRd = (adatRd + 4) & (MAX_ADAT_SAMPLES - 1); - adatSamps -= 4; - } - else - { - /* no SMUX mode - 8 samples from fifo */ - g_digData[2] = adatSamples[adatRd + 0]; - g_digData[3] = adatSamples[adatRd + 1]; - g_digData[4] = adatSamples[adatRd + 2]; - g_digData[5] = adatSamples[adatRd + 3]; - - g_digData[6] = adatSamples[adatRd + 4]; - g_digData[7] = adatSamples[adatRd + 5]; - g_digData[8] = adatSamples[adatRd + 6]; - g_digData[9] = adatSamples[adatRd + 7]; - - adatRd = (adatRd + 8) & (MAX_ADAT_SAMPLES - 1); - adatSamps -= 8; - } - - /* adatSamps could go to -1 */ - if (adatSamps <= 0) - { - /* we're out of ADAT samples, mark underflow condition */ - adatUnderflow = 1; - } - - /* if we are in overflow condition and have a sensible number of samples - come out of overflow condition */ - if (adatOverflow && adatSamps < (MAX_ADAT_SAMPLES >> 1)) - { - adatOverflow = 0; - } + adatRd = (adatRd + 8) & (MAX_ADAT_SAMPLES - 1); + adatSamps -= 8; } -#endif - outuint(c_dig_rx, 1); - break; -#endif - } /* select */ - } /* while(1) */ - } /* clkgen task scope */ -} + + /* adatSamps could go to -1 */ + if (adatSamps <= 0) + { + /* we're out of ADAT samples, mark underflow condition */ + adatUnderflow = 1; + } + + /* if we are in overflow condition and have a sensible number of samples + come out of overflow condition */ + if (adatOverflow && adatSamps < (MAX_ADAT_SAMPLES >> 1)) + { + adatOverflow = 0; + } + } +#endif + outuint(c_dig_rx, 1); + break; +#endif + } /* select */ + } /* while(1) */ +} /* clkgen task scope */ diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.h b/lib_xua/src/core/clocking/sw_pll_wrapper.h index be808696..315824e6 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.h +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.h @@ -27,29 +27,29 @@ extern "C" /** Task that receives an error term, passes it through a PI controller and periodically * calclulates a sigma delta output value and sends it to the PLL fractional register. * - * \param c_sigma_delta Channel connected to the clocking thread to pass raw error terms. - * \param selected_mclk_rate_ptr Pointer to the mclk rate variable declared in clockgen. + * \param c_sw_pll Channel connected to the clocking thread to pass raw error terms. */ -void SigmaDeltaTask(chanend c_sigma_delta, unsigned * unsafe selected_mclk_rate_ptr); +void sw_pll_task(chanend c_sw_pll); /** Helper function that sends a special restart command. It causes the SDM task * to quit and restart using the new mclk. * - * \param c_sigma_delta Channel connected to the clocking thread to pass raw error terms. + * \param c_sw_pll Channel connected to the clocking thread to pass raw error terms. + * \param mclk_Rate The mclk frequency in Hz. */ -void restart_sigma_delta(chanend c_sigma_delta); +void restart_sigma_delta(chanend c_sw_pll, unsigned mclk_rate); /** Performs a frequency comparsion between the incoming digital Rx stream and the local mclk. * * \param mclk_time_stamp The captured mclk count (using port timer) at the time of sample Rx. * \param mclks_per_sample The nominal number of mclks per audio sample. - * \param c_sigma_delta Channel connected to the sigma delta and controller thread. + * \param c_sw_pll Channel connected to the sigma delta and controller thread. * \param receivedSamples The number of received samples since tha last call to this function. * \param reset_sw_pll_pfd Reference to a flag which will be used to signal reset of this function's state. */ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, unsigned mclks_per_sample, - chanend c_sigma_delta, + chanend c_sw_pll, int receivedSamples, int &reset_sw_pll_pfd); diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.xc b/lib_xua/src/core/clocking/sw_pll_wrapper.xc index 7cb3163d..0513e261 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.xc +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.xc @@ -114,79 +114,82 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, } } -void SigmaDeltaTask(chanend c_sigma_delta, unsigned * unsafe selected_mclk_rate_ptr){ +void sw_pll_task(chanend c_sigma_delta){ /* Zero is an invalid number and the SDM will not write the frac reg until 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. */ - int f_error = 0; - int dco_setting = 0; /* gets set at InitSWPLL */ - unsigned sdm_interval = 0; /* gets set at InitSWPLL */ - sw_pll_state_t sw_pll; - - unsafe + while(1) { + unsigned selected_mclk_rate = inuint(c_sigma_delta); + + int f_error = 0; + int dco_setting = 0; /* gets set at InitSWPLL */ + unsigned sdm_interval = 0; /* gets set at InitSWPLL */ + sw_pll_state_t sw_pll; + /* initialse the SDM and gather SDM initial settings */ - {sdm_interval, dco_setting} = InitSWPLL(sw_pll, (unsigned)*selected_mclk_rate_ptr); - } + {sdm_interval, dco_setting} = InitSWPLL(sw_pll, selected_mclk_rate); - tileref_t this_tile = get_local_tile_id(); + tileref_t this_tile = get_local_tile_id(); - timer tmr; - int32_t time_trigger; - tmr :> time_trigger; - int running = 1; + timer tmr; + int32_t time_trigger; + tmr :> time_trigger; + int running = 1; - outuint(c_sigma_delta, 0); /* Signal back via clockgen to audio to start I2S */ + outuint(c_sigma_delta, 0); /* Signal back via clockgen to audio to start I2S */ - unsigned rx_word = 0; - while(running) - { - /* Poll for new SDM control value */ - select + unsigned rx_word = 0; + while(running) { - case inuint_byref(c_sigma_delta, rx_word): - if(rx_word == DISABLE_SDM) - { - f_error = 0; - running = 0; - } - else - { - f_error = (int32_t)rx_word; - unsafe + /* Poll for new SDM control value */ + select + { + case inuint_byref(c_sigma_delta, rx_word): + if(rx_word == DISABLE_SDM) { - sw_pll_sdm_do_control_from_error(&sw_pll, -f_error); - dco_setting = sw_pll.sdm_state.current_ctrl_val; + f_error = 0; + running = 0; } - } - break; + else + { + f_error = (int32_t)rx_word; + unsafe + { + sw_pll_sdm_do_control_from_error(&sw_pll, -f_error); + dco_setting = sw_pll.sdm_state.current_ctrl_val; + } + } + break; - /* Do nothing & fall-through. Above case polls only once per loop */ - default: - break; - } + /* Do nothing & fall-through. Above case polls only once per loop */ + default: + break; + } - /* Wait until the timer value has been reached - This implements a timing barrier and keeps - the loop rate constant. */ - select - { - case tmr when timerafter(time_trigger) :> int _: - time_trigger += sdm_interval; - break; - } + /* Wait until the timer value has been reached + This implements a timing barrier and keeps + the loop rate constant. */ + select + { + case tmr when timerafter(time_trigger) :> int _: + time_trigger += sdm_interval; + break; + } - unsafe { - sw_pll_do_sigma_delta(&sw_pll.sdm_state, this_tile, dco_setting); - } - } /* if running */ + unsafe { + sw_pll_do_sigma_delta(&sw_pll.sdm_state, this_tile, dco_setting); + } + } /* if running */ + } /* while(1) */ } -void restart_sigma_delta(chanend c_sigma_delta) +void restart_sigma_delta(chanend c_sigma_delta, unsigned selected_mclk_rate) { outuint(c_sigma_delta, DISABLE_SDM); /* Resets SDM */ + outuint(c_sigma_delta, selected_mclk_rate); } #endif /* USE_SW_PLL */ diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 053dd63b..7e1f9303 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -314,8 +314,11 @@ void usb_audio_io(chanend ?c_aud_in, #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , client interface pll_ref_if i_pll_ref - , port ?p_for_mclk_count_aud -#endif +#if USE_SW_PLL + , port p_for_mclk_count_aud + , chanend c_sw_pll +#endif /* USE_SW_PLL */ +#endif /* (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) */ ) { #if (MIXER) @@ -405,8 +408,9 @@ void usb_audio_io(chanend ?c_aud_in, c_dig_rx, c_clk_ctl, c_clk_int, + c_mclk_change, p_for_mclk_count_aud, - c_mclk_change); + c_sw_pll); } #endif @@ -483,7 +487,7 @@ int main() #endif #endif -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && !USE_SW_PLL) +#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) ) interface pll_ref_if i_pll_ref; #endif @@ -511,7 +515,7 @@ int main() { USER_MAIN_CORES -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && !USE_SW_PLL) +#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref); #endif on tile[XUD_TILE]: @@ -524,10 +528,6 @@ int main() DFUHandler(dfuInterface, null); #endif -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) - //XUA_SoftPll(tile[0], i_softPll, c_swpll_update); -#endif - /* Core USB task, buffering, USB etc */ { #ifdef XUD_PRIORITY_HIGH @@ -589,7 +589,7 @@ int main() #if (!USE_SW_PLL) , i_pll_ref #else - , c_sw_pll + , c_sw_pll #endif #endif ); @@ -605,8 +605,8 @@ int main() #endif /* XUA_USB_EN */ } -#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) - // on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update); +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) + on tile[AUDIO_IO_TILE]: sw_pll_task(c_sw_pll); #endif on tile[AUDIO_IO_TILE]: @@ -625,16 +625,13 @@ int main() , dfuInterface #endif #if (XUA_NUM_PDM_MICS > 0) - #if (PDM_TILE == AUDIO_IO_TILE) - , c_ds_output - #endif - , c_pdm_pcm #endif -#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , i_pll_ref #endif -#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if (USE_SW_PLL && (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) , p_for_mclk_count_audio + , c_sw_pll #endif ); } From af9a6b18b2d3cb3baee2fb8b4bde3654c73e85e8 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Jan 2024 17:28:38 +0000 Subject: [PATCH 04/30] make use of # guards and nullable consistent --- lib_xua/api/xua_clocking.h | 20 ++++--------- lib_xua/src/core/clocking/clockgen.xc | 33 +++++++++++---------- lib_xua/src/core/clocking/sw_pll_wrapper.xc | 26 ++++++++-------- lib_xua/src/core/main.xc | 21 +++++++------ 4 files changed, 48 insertions(+), 52 deletions(-) diff --git a/lib_xua/api/xua_clocking.h b/lib_xua/api/xua_clocking.h index c0240035..e6bdd713 100644 --- a/lib_xua/api/xua_clocking.h +++ b/lib_xua/api/xua_clocking.h @@ -39,22 +39,12 @@ void clockGen( streaming chanend ?c_spdif_rx, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int, - chanend c_mclk_change, - port ?p_for_mclk_count_aud, - chanend ?c_sw_pll); - -#if (XUA_USE_APP_PLL) - -interface SoftPll_if -{ - void init(int mclk_hz); -}; - -#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC) -[[distributable]] + chanend c_mclk_change +#if USE_SW_PLL + , port p_for_mclk_count_aud + , chanend c_sw_pll #endif -void XUA_SoftPll(tileref tile, server interface SoftPll_if i_softPll, chanend c_update); + ); #endif -#endif diff --git a/lib_xua/src/core/clocking/clockgen.xc b/lib_xua/src/core/clocking/clockgen.xc index 479b56d7..46383913 100644 --- a/lib_xua/src/core/clocking/clockgen.xc +++ b/lib_xua/src/core/clocking/clockgen.xc @@ -222,9 +222,12 @@ void clockGen ( streaming chanend ?c_spdif_rx, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int, - chanend c_mclk_change, - port ?p_for_mclk_count_aud, - chanend ?c_sw_pll) + chanend c_mclk_change +#if USE_SW_PLL + , port p_for_mclk_count_aud + , chanend c_sw_pll +#endif +) { timer t_local; unsigned timeNextEdge, timeLastEdge, timeNextClockDetection; @@ -243,13 +246,14 @@ void clockGen ( streaming chanend ?c_spdif_rx, timer t_external; unsigned selected_mclk_rate = MCLK_48; // Assume 24.576MHz initial clock unsigned selected_sample_rate = 0; +#if USE_SW_PLL + unsigned mclks_per_sample = 0; unsigned short mclk_time_stamp = 0; + /* Get MCLK count */ - if(!isnull(p_for_mclk_count_aud)) - { - asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); - } + asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); +#endif #endif #if (XUA_SPDIF_RX_EN) @@ -548,11 +552,10 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Receive sample from S/PDIF RX thread (streaming chan) */ case c_spdif_rx :> spdifRxData: +#if USE_SW_PLL /* Record time of sample */ - if(!isnull(p_for_mclk_count_aud)) - { - asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); - } + asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); +#endif t_local :> spdifRxTime; /* Check parity and ignore if bad */ @@ -642,11 +645,11 @@ void clockGen ( streaming chanend ?c_spdif_rx, #if (XUA_ADAT_RX_EN) /* receive sample from ADAT rx thread (streaming channel with CT_END) */ case inuint_byref(c_adat_rx, tmp): + +#if USE_SW_PLL /* record time of sample */ - if(!isnull(p_for_mclk_count_aud)) - { - asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); - } + asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); +#endif t_local :> adatReceivedTime; /* Sync is: 1 | (user_byte << 4) */ diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.xc b/lib_xua/src/core/clocking/sw_pll_wrapper.xc index 0513e261..76f34b2a 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.xc +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.xc @@ -10,7 +10,7 @@ #if USE_SW_PLL -{unsigned, unsigned} InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk) +{unsigned, unsigned} init_sw_pll(sw_pll_state_t &sw_pll, unsigned mClk) { /* Autogenerated SDM App PLL setup by dco_model.py using 22.5792_1M profile */ /* Input freq: 24000000 @@ -74,7 +74,7 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, unsigned mclks_per_sample, - chanend c_sigma_delta, + chanend c_sw_pll, int receivedSamples, int &reset_sw_pll_pfd) { @@ -106,7 +106,7 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, } /* send PFD output to the sigma delta thread */ - outuint(c_sigma_delta, (int) f_error); + outuint(c_sw_pll, (int) f_error); last_mclk_time_stamp = mclk_time_stamp; control_loop_counter = 0; @@ -114,22 +114,22 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, } } -void sw_pll_task(chanend c_sigma_delta){ +void sw_pll_task(chanend c_sw_pll){ /* Zero is an invalid number and the SDM will not write the frac reg until 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. */ while(1) { - unsigned selected_mclk_rate = inuint(c_sigma_delta); + unsigned selected_mclk_rate = inuint(c_sw_pll); int f_error = 0; - int dco_setting = 0; /* gets set at InitSWPLL */ - unsigned sdm_interval = 0; /* gets set at InitSWPLL */ + int dco_setting = 0; /* gets set at init_sw_pll */ + unsigned sdm_interval = 0; /* gets set at init_sw_pll */ sw_pll_state_t sw_pll; /* initialse the SDM and gather SDM initial settings */ - {sdm_interval, dco_setting} = InitSWPLL(sw_pll, selected_mclk_rate); + {sdm_interval, dco_setting} = init_sw_pll(sw_pll, selected_mclk_rate); tileref_t this_tile = get_local_tile_id(); @@ -138,7 +138,7 @@ void sw_pll_task(chanend c_sigma_delta){ tmr :> time_trigger; int running = 1; - outuint(c_sigma_delta, 0); /* Signal back via clockgen to audio to start I2S */ + outuint(c_sw_pll, 0); /* Signal back via clockgen to audio to start I2S */ unsigned rx_word = 0; while(running) @@ -146,7 +146,7 @@ void sw_pll_task(chanend c_sigma_delta){ /* Poll for new SDM control value */ select { - case inuint_byref(c_sigma_delta, rx_word): + case inuint_byref(c_sw_pll, rx_word): if(rx_word == DISABLE_SDM) { f_error = 0; @@ -186,10 +186,10 @@ void sw_pll_task(chanend c_sigma_delta){ } -void restart_sigma_delta(chanend c_sigma_delta, unsigned selected_mclk_rate) +void restart_sigma_delta(chanend c_sw_pll, unsigned selected_mclk_rate) { - outuint(c_sigma_delta, DISABLE_SDM); /* Resets SDM */ - outuint(c_sigma_delta, selected_mclk_rate); + outuint(c_sw_pll, DISABLE_SDM); /* Resets SDM */ + outuint(c_sw_pll, selected_mclk_rate); } #endif /* USE_SW_PLL */ diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 7e1f9303..c675e95a 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -329,13 +329,13 @@ void usb_audio_io(chanend ?c_aud_in, chan c_dig_rx; chan c_mclk_change; /* Notification of new mclk freq to clockgen */ +#if USE_SW_PLL /* Connect p_for_mclk_count_aud to clk_audio_mclk so we can count mclks/timestamp in digital rx*/ - if(!isnull(p_for_mclk_count_aud)) - { - unsigned x = 0; - asm("ldw %0, dp[clk_audio_mclk]":"=r"(x)); - asm("setclk res[%0], %1"::"r"(p_for_mclk_count_aud), "r"(x)); - } + + unsigned x = 0; + asm("ldw %0, dp[clk_audio_mclk]":"=r"(x)); + asm("setclk res[%0], %1"::"r"(p_for_mclk_count_aud), "r"(x)); +#endif /* USE_SW_PLL */ #endif /* (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) */ #if (XUA_NUM_PDM_MICS > 0) && (PDM_TILE == AUDIO_IO_TILE) @@ -408,9 +408,12 @@ void usb_audio_io(chanend ?c_aud_in, c_dig_rx, c_clk_ctl, c_clk_int, - c_mclk_change, - p_for_mclk_count_aud, - c_sw_pll); + c_mclk_change +#if USE_SW_PLL + , p_for_mclk_count_aud + , c_sw_pll +#endif + ); } #endif From eb6ed9f56edb856d2ea3ee4ece7ffe619795a0a7 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Jan 2024 17:43:51 +0000 Subject: [PATCH 05/30] Fix guarding on i_pll for sync --- lib_xua/src/core/main.xc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index c675e95a..bd5f576d 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -314,11 +314,11 @@ void usb_audio_io(chanend ?c_aud_in, #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , client interface pll_ref_if i_pll_ref -#if USE_SW_PLL +#endif +#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) , port p_for_mclk_count_aud , chanend c_sw_pll -#endif /* USE_SW_PLL */ -#endif /* (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) */ +#endif ) { #if (MIXER) @@ -629,10 +629,10 @@ int main() #endif #if (XUA_NUM_PDM_MICS > 0) #endif -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , i_pll_ref #endif -#if (USE_SW_PLL && (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) +#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) , p_for_mclk_count_audio , c_sw_pll #endif From 2d1585b8b1960f00f1ac95f2e53f01963b69d8ee Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 16 Jan 2024 09:58:44 +0000 Subject: [PATCH 06/30] Copyright --- lib_xua/api/xua_conf_default.h | 2 +- lib_xua/src/core/buffer/ep/ep_buffer.xc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 5937fe07..66e732b0 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -1,4 +1,4 @@ -// Copyright 2011-2023 XMOS LIMITED. +// Copyright 2011-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* * @brief Defines relating to device configuration and customisation of lib_xua diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 0544b960..79fd6c2a 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -1,4 +1,4 @@ -// Copyright 2011-2023 XMOS LIMITED. +// Copyright 2011-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include "xua.h" #if XUA_USB_EN @@ -466,6 +466,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, { masterClockFreq = MCLK_441; } + // TODO add signalling to sw_pll here } #endif /* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this From f0709d35fcba7948f44ec45063688bfe9ad893d8 Mon Sep 17 00:00:00 2001 From: Ed Date: Thu, 18 Jan 2024 14:39:27 +0000 Subject: [PATCH 07/30] WIP sync mode --- lib_xua/src/core/audiohub/xua_audiohub.xc | 9 ----- lib_xua/src/core/buffer/ep/ep_buffer.xc | 44 +++++++++++++++++++---- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 35751848..ca499f28 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -636,9 +636,6 @@ 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 @@ -667,12 +664,6 @@ 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); diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 79fd6c2a..0ae0bc43 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -106,7 +106,7 @@ void XUA_Buffer( , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) #if(USE_SW_PLL) - , chanend c_swpll_update + , chanend c_sw_pll #else , client interface pll_ref_if i_pll_ref #endif @@ -146,7 +146,7 @@ void XUA_Buffer( #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) #if(USE_SW_PLL) - , c_swpll_update + , c_sw_pll #else , i_pll_ref #endif @@ -200,7 +200,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) #if (USE_SW_PLL) - , chanend c_swpll_update + , chanend c_sw_pll #else , client interface pll_ref_if i_pll_ref #endif @@ -370,7 +370,21 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #define LOCAL_CLOCK_MARGIN (1000) #endif -#if (!USE_SW_PLL) +#if (USE_SW_PLL) + /* Setup the phase frequency detector */ + const unsigned controller_rate_hz = 100; + const unsigned sof_rate_hz = (AUDIO_CLASS == 1 ? 1000 : 8000); + + sw_pll_pfd_state_t sw_pll_pfd; + sw_pll_pfd_init(&sw_pll_pfd, + sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ + masterClockFreq / sof_rate_hz, /* pll ratio integer */ + 0, /* Assume precise timing of sampling */ + 2000); /* PPM range before we assume unlocked */ + outuint(c_sw_pll, masterClockFreq); + inuint(c_sw_pll); /* receive ACK */ + +#else /* USE_SW_PLL */ timer t_sofCheck; unsigned timeLastEdge; unsigned timeNextEdge; @@ -466,7 +480,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, { masterClockFreq = MCLK_441; } - // TODO add signalling to sw_pll here + restart_sigma_delta(c_sw_pll, masterClockFreq); } #endif /* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this @@ -572,8 +586,15 @@ 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)); - outuint(c_swpll_update, mclk_pt); - outct(c_swpll_update, XS1_CT_END); + + uint8_t first_loop = 0; + unsafe{ + sw_pll_calc_error_from_port_timers(&sw_pll_pfd, &first_loop, mclk_pt, 0); + } + int error = sw_pll_pfd.mclk_diff; + + outuint(c_sw_pll, error); + // outct(c_sw_pll, XS1_CT_END); } #endif @@ -994,6 +1015,15 @@ void XUA_Buffer_Ep(register chanend c_aud_out, break; #endif /* ifdef MIDI */ +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && USE_SW_PLL) + /* This is fired when sw_pll has completed initialising a new mclk_rate */ + case inuint_byref(c_sw_pll, u_tmp): + printstrln("SWPLL synch\n"); + + //TODO - hold off audio until we get this ACK + break; +#endif /* ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && USE_SW_PLL) */ + #ifdef IAP /* Received word from iap thread - Check for ACK or Data */ case iap_get_ack_or_reset_or_data(c_iap, is_ack_iap, is_reset, datum_iap): From eb4b19ce165bfc4bca94f3acc5e9815a5675aeff Mon Sep 17 00:00:00 2001 From: Ed Date: Thu, 18 Jan 2024 16:22:43 +0000 Subject: [PATCH 08/30] Initial loop closed --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 0ae0bc43..d45e4f70 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -591,7 +591,18 @@ void XUA_Buffer_Ep(register chanend c_aud_out, unsafe{ sw_pll_calc_error_from_port_timers(&sw_pll_pfd, &first_loop, mclk_pt, 0); } - int error = sw_pll_pfd.mclk_diff; + + int error = 0; + if(first_loop) + { + printstr("fl\n"); + } + else + { + error = sw_pll_pfd.mclk_diff; + printintln(error); + } + sw_pll_pfd.mclk_pt_last = mclk_pt; outuint(c_sw_pll, error); // outct(c_sw_pll, XS1_CT_END); @@ -1018,7 +1029,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && USE_SW_PLL) /* This is fired when sw_pll has completed initialising a new mclk_rate */ case inuint_byref(c_sw_pll, u_tmp): - printstrln("SWPLL synch\n"); + printstr("SWPLL synch\n"); //TODO - hold off audio until we get this ACK break; From fe6afc93de33c6aaf3e0558a6409cbdbb42dd8f1 Mon Sep 17 00:00:00 2001 From: Ed Date: Thu, 18 Jan 2024 17:02:35 +0000 Subject: [PATCH 09/30] Add reconfig of pfd on SR change --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index d45e4f70..0acac22a 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -480,7 +480,15 @@ void XUA_Buffer_Ep(register chanend c_aud_out, { masterClockFreq = MCLK_441; } +#if USE_SW_PLL + sw_pll_pfd_init(&sw_pll_pfd, + sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ + masterClockFreq / sof_rate_hz, /* pll ratio integer */ + 0, /* Assume precise timing of sampling */ + 2000); restart_sigma_delta(c_sw_pll, masterClockFreq); + +#endif } #endif /* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this @@ -593,17 +601,13 @@ void XUA_Buffer_Ep(register chanend c_aud_out, } int error = 0; - if(first_loop) - { - printstr("fl\n"); - } - else + if(!first_loop) { error = sw_pll_pfd.mclk_diff; - printintln(error); } sw_pll_pfd.mclk_pt_last = mclk_pt; + outuint(c_sw_pll, error); // outct(c_sw_pll, XS1_CT_END); } From 8b58fe5aaafe44a602dd038801dee25d5faad6f5 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Jan 2024 09:17:29 +0000 Subject: [PATCH 10/30] sw_pll sync fs change support --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 0acac22a..79bf1f83 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -480,7 +480,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, { masterClockFreq = MCLK_441; } -#if USE_SW_PLL +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && USE_SW_PLL) sw_pll_pfd_init(&sw_pll_pfd, sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ masterClockFreq / sof_rate_hz, /* pll ratio integer */ @@ -488,9 +488,9 @@ void XUA_Buffer_Ep(register chanend c_aud_out, 2000); restart_sigma_delta(c_sw_pll, masterClockFreq); -#endif +#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && USE_SW_PLL) */ } -#endif +#endif /* (MAX_FREQ != MIN_FREQ) */ /* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this * core locked, it must stay responsive to packets (MIDI etc) and SOFs. So, set a flag and check for * handshake elsewhere */ From cb84d69231a38ab2cffcb117a4eae8ba9c9e8b3d Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Jan 2024 09:24:02 +0000 Subject: [PATCH 11/30] Remove unneeded define --- lib_xua/src/core/clocking/sw_pll_wrapper.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.h b/lib_xua/src/core/clocking/sw_pll_wrapper.h index 315824e6..d050f562 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.h +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.h @@ -4,15 +4,7 @@ #ifndef _SW_PLL_WRAPPPER_H_ #define _SW_PLL_WRAPPPER_H_ -/* By default we use SW_PLL for Digital Rx configs running on xcore.ai */ -/* Note: Not yet implemented for Synchronous mode */ -#ifdef __XS3A__ -#ifndef USE_SW_PLL -#define USE_SW_PLL 1 -#endif /* USE_SW_PLL */ -#else -#define USE_SW_PLL 0 -#endif /* __XS3A__ */ +#include "xua.h" #if USE_SW_PLL extern "C" From 7126b918486181f022c1c926599cdabf9f3eeea9 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Jan 2024 09:25:37 +0000 Subject: [PATCH 12/30] USE_SW_PLL -> XUA_USE_SW_PLL --- lib_xua/api/xua_buffer.h | 8 +++---- lib_xua/api/xua_clocking.h | 2 +- lib_xua/api/xua_conf_default.h | 6 +++--- lib_xua/doc/rst/api_defines.rst | 2 +- lib_xua/src/core/buffer/ep/ep_buffer.xc | 24 ++++++++++----------- lib_xua/src/core/clocking/clockgen.xc | 22 +++++++++---------- lib_xua/src/core/clocking/sw_pll_wrapper.h | 4 ++-- lib_xua/src/core/clocking/sw_pll_wrapper.xc | 4 ++-- lib_xua/src/core/main.xc | 20 ++++++++--------- 9 files changed, 46 insertions(+), 46 deletions(-) diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index 7e07a113..0e2dd3ee 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -53,10 +53,10 @@ void XUA_Buffer( #endif , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__) - #if (!USE_SW_PLL) || defined(__DOXYGEN__) + #if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__) , client interface pll_ref_if i_pll_ref #endif - #if (USE_SW_PLL) || defined(__DOXYGEN__) + #if (XUA_USE_SW_PLL) || defined(__DOXYGEN__) , chanend c_swpll_update #endif #endif @@ -88,10 +88,10 @@ void XUA_Buffer_Ep(chanend c_aud_out, , chanend c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__) - #if (!USE_SW_PLL) || defined(__DOXYGEN__) + #if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__) , client interface pll_ref_if i_pll_ref #endif - #if (USE_SW_PLL) || defined(__DOXYGEN__) + #if (XUA_USE_SW_PLL) || defined(__DOXYGEN__) , chanend c_swpll_update #endif #endif diff --git a/lib_xua/api/xua_clocking.h b/lib_xua/api/xua_clocking.h index e6bdd713..2b64e7bf 100644 --- a/lib_xua/api/xua_clocking.h +++ b/lib_xua/api/xua_clocking.h @@ -40,7 +40,7 @@ void clockGen( streaming chanend ?c_spdif_rx, chanend c_clk_ctl, chanend c_clk_int, chanend c_mclk_change -#if USE_SW_PLL +#if XUA_USE_SW_PLL , port p_for_mclk_count_aud , chanend c_sw_pll #endif diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 66e732b0..872064c2 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -270,11 +270,11 @@ * * Default: Enabled (for xcore.ai devices) */ -#ifndef USE_SW_PLL +#ifndef XUA_USE_SW_PLL #if defined(__XS3A__) - #define USE_SW_PLL (1) + #define XUA_USE_SW_PLL (1) #else - #define USE_SW_PLL (0) + #define XUA_USE_SW_PLL (0) #endif #endif diff --git a/lib_xua/doc/rst/api_defines.rst b/lib_xua/doc/rst/api_defines.rst index a9a395a0..8cf2ca5e 100644 --- a/lib_xua/doc/rst/api_defines.rst +++ b/lib_xua/doc/rst/api_defines.rst @@ -38,7 +38,7 @@ Frequencies and Clocks .. doxygendefine:: DEFAULT_FREQ .. doxygendefine:: MCLK_441 .. doxygendefine:: MCLK_48 -.. doxygendefine:: USE_SW_PLL +.. doxygendefine:: XUA_USE_SW_PLL Audio Class ----------- diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 79bf1f83..608f301b 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -105,7 +105,7 @@ void XUA_Buffer( #endif , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - #if(USE_SW_PLL) + #if(XUA_USE_SW_PLL) , chanend c_sw_pll #else , client interface pll_ref_if i_pll_ref @@ -145,7 +145,7 @@ void XUA_Buffer( , c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - #if(USE_SW_PLL) + #if(XUA_USE_SW_PLL) , c_sw_pll #else , i_pll_ref @@ -199,7 +199,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, , chanend c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - #if (USE_SW_PLL) + #if (XUA_USE_SW_PLL) , chanend c_sw_pll #else , client interface pll_ref_if i_pll_ref @@ -370,7 +370,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #define LOCAL_CLOCK_MARGIN (1000) #endif -#if (USE_SW_PLL) +#if (XUA_USE_SW_PLL) /* Setup the phase frequency detector */ const unsigned controller_rate_hz = 100; const unsigned sof_rate_hz = (AUDIO_CLASS == 1 ? 1000 : 8000); @@ -384,7 +384,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, outuint(c_sw_pll, masterClockFreq); inuint(c_sw_pll); /* receive ACK */ -#else /* USE_SW_PLL */ +#else /* XUA_USE_SW_PLL */ timer t_sofCheck; unsigned timeLastEdge; unsigned timeNextEdge; @@ -480,7 +480,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, { masterClockFreq = MCLK_441; } -#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && USE_SW_PLL) +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && XUA_USE_SW_PLL) sw_pll_pfd_init(&sw_pll_pfd, sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ masterClockFreq / sof_rate_hz, /* pll ratio integer */ @@ -488,7 +488,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, 2000); restart_sigma_delta(c_sw_pll, masterClockFreq); -#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && USE_SW_PLL) */ +#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && XUA_USE_SW_PLL) */ } #endif /* (MAX_FREQ != MIN_FREQ) */ /* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this @@ -548,7 +548,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, } break; } -#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!USE_SW_PLL) +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_SW_PLL) case t_sofCheck when timerafter(timeNextEdge) :> void: i_pll_ref.toggle(); timeLastEdge = timeNextEdge; @@ -580,14 +580,14 @@ void XUA_Buffer_Ep(register chanend c_aud_out, { sofCount = 0; pllUpdate++; -#if (!USE_SW_PLL) +#if (!XUA_USE_SW_PLL) /* Port is accessed via interface to allow flexibilty with location */ i_pll_ref.toggle(); t_sofCheck :> timeLastEdge; timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; #endif } -#if (USE_SW_PLL) +#if (XUA_USE_SW_PLL) // Update PLL @ 100Hz if(pllUpdate == 10) { @@ -1030,14 +1030,14 @@ void XUA_Buffer_Ep(register chanend c_aud_out, break; #endif /* ifdef MIDI */ -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && USE_SW_PLL) +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XUA_USE_SW_PLL) /* This is fired when sw_pll has completed initialising a new mclk_rate */ case inuint_byref(c_sw_pll, u_tmp): printstr("SWPLL synch\n"); //TODO - hold off audio until we get this ACK break; -#endif /* ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && USE_SW_PLL) */ +#endif /* ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XUA_USE_SW_PLL) */ #ifdef IAP /* Received word from iap thread - Check for ACK or Data */ diff --git a/lib_xua/src/core/clocking/clockgen.xc b/lib_xua/src/core/clocking/clockgen.xc index 46383913..7673b298 100644 --- a/lib_xua/src/core/clocking/clockgen.xc +++ b/lib_xua/src/core/clocking/clockgen.xc @@ -199,7 +199,7 @@ static inline int validSamples(Counter &counter, int clockIndex) } #endif -#if USE_SW_PLL +#if XUA_USE_SW_PLL unsafe { unsigned * unsafe selected_mclk_rate_ptr = NULL; @@ -223,7 +223,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, chanend c_clk_ctl, chanend c_clk_int, chanend c_mclk_change -#if USE_SW_PLL +#if XUA_USE_SW_PLL , port p_for_mclk_count_aud , chanend c_sw_pll #endif @@ -246,7 +246,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, timer t_external; unsigned selected_mclk_rate = MCLK_48; // Assume 24.576MHz initial clock unsigned selected_sample_rate = 0; -#if USE_SW_PLL +#if XUA_USE_SW_PLL unsigned mclks_per_sample = 0; unsigned short mclk_time_stamp = 0; @@ -345,7 +345,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Initial ref clock output and get timestamp */ i_pll_ref.init(); -#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) +#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) int reset_sw_pll_pfd = 1; int require_ack_to_audio = 0; restart_sigma_delta(c_sw_pll, MCLK_48); /* default to 48kHz - this will be reset shortly when host selects rate */ @@ -468,7 +468,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Generate local clock from timer */ case t_local when timerafter(timeNextEdge) :> void: -#if USE_SW_PLL +#if XUA_USE_SW_PLL /* Do nothing - hold the most recent sw_pll setting */ #else /* Setup next local clock edge */ @@ -519,7 +519,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, break; #endif -#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) +#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) case inuint_byref(c_sw_pll, tmp): /* Send ACK back to audiohub to allow I2S to start This happens only on SDM restart and only once */ @@ -535,7 +535,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Receive notification of audio streaming settings change and store */ case c_mclk_change :> selected_mclk_rate: c_mclk_change :> selected_sample_rate; -#if USE_SW_PLL +#if XUA_USE_SW_PLL mclks_per_sample = selected_mclk_rate / selected_sample_rate; restart_sigma_delta(c_sw_pll, selected_mclk_rate); reset_sw_pll_pfd = 1; @@ -552,7 +552,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Receive sample from S/PDIF RX thread (streaming chan) */ case c_spdif_rx :> spdifRxData: -#if USE_SW_PLL +#if XUA_USE_SW_PLL /* Record time of sample */ asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); #endif @@ -625,7 +625,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Setup for next edge */ timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; -#if USE_SW_PLL +#if XUA_USE_SW_PLL do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, mclks_per_sample, c_sw_pll, @@ -646,7 +646,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* receive sample from ADAT rx thread (streaming channel with CT_END) */ case inuint_byref(c_adat_rx, tmp): -#if USE_SW_PLL +#if XUA_USE_SW_PLL /* record time of sample */ asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); #endif @@ -742,7 +742,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Setup for next edge */ timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; -#if USE_SW_PLL +#if XUA_USE_SW_PLL do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, mclks_per_sample, c_sw_pll, diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.h b/lib_xua/src/core/clocking/sw_pll_wrapper.h index d050f562..fbbb98ad 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.h +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.h @@ -6,7 +6,7 @@ #include "xua.h" -#if USE_SW_PLL +#if XUA_USE_SW_PLL extern "C" { #include "sw_pll.h" @@ -53,5 +53,5 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, * returns The SDM update interval in ticks and the initial DCO setting for nominal frequency */ {unsigned, unsigned} InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk); -#endif /* USE_SW_PLL */ +#endif /* XUA_USE_SW_PLL */ #endif /* _SW_PLL_WRAPPPER_H_ */ \ No newline at end of file diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.xc b/lib_xua/src/core/clocking/sw_pll_wrapper.xc index 76f34b2a..bc9a7d9d 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.xc +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.xc @@ -7,7 +7,7 @@ #include "sw_pll_wrapper.h" #include "xua.h" -#if USE_SW_PLL +#if XUA_USE_SW_PLL {unsigned, unsigned} init_sw_pll(sw_pll_state_t &sw_pll, unsigned mClk) @@ -192,4 +192,4 @@ void restart_sigma_delta(chanend c_sw_pll, unsigned selected_mclk_rate) outuint(c_sw_pll, selected_mclk_rate); } -#endif /* USE_SW_PLL */ +#endif /* XUA_USE_SW_PLL */ diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index bd5f576d..901e59bc 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -315,7 +315,7 @@ 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_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) +#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) , port p_for_mclk_count_aud , chanend c_sw_pll #endif @@ -329,13 +329,13 @@ void usb_audio_io(chanend ?c_aud_in, chan c_dig_rx; chan c_mclk_change; /* Notification of new mclk freq to clockgen */ -#if USE_SW_PLL +#if XUA_USE_SW_PLL /* Connect p_for_mclk_count_aud to clk_audio_mclk so we can count mclks/timestamp in digital rx*/ unsigned x = 0; asm("ldw %0, dp[clk_audio_mclk]":"=r"(x)); asm("setclk res[%0], %1"::"r"(p_for_mclk_count_aud), "r"(x)); -#endif /* USE_SW_PLL */ +#endif /* XUA_USE_SW_PLL */ #endif /* (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) */ #if (XUA_NUM_PDM_MICS > 0) && (PDM_TILE == AUDIO_IO_TILE) @@ -409,7 +409,7 @@ void usb_audio_io(chanend ?c_aud_in, c_clk_ctl, c_clk_int, c_mclk_change -#if USE_SW_PLL +#if XUA_USE_SW_PLL , p_for_mclk_count_aud , c_sw_pll #endif @@ -490,11 +490,11 @@ int main() #endif #endif -#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) ) +#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !XUA_USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) ) interface pll_ref_if i_pll_ref; #endif -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) chan c_sw_pll; #endif chan c_sof; @@ -518,7 +518,7 @@ int main() { USER_MAIN_CORES -#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) +#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !XUA_USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref); #endif on tile[XUD_TILE]: @@ -589,7 +589,7 @@ int main() #endif , c_mix_out #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - #if (!USE_SW_PLL) + #if (!XUA_USE_SW_PLL) , i_pll_ref #else , c_sw_pll @@ -608,7 +608,7 @@ int main() #endif /* XUA_USB_EN */ } -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) on tile[AUDIO_IO_TILE]: sw_pll_task(c_sw_pll); #endif @@ -632,7 +632,7 @@ int main() #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , i_pll_ref #endif -#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) +#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) , p_for_mclk_count_audio , c_sw_pll #endif From 27a7d185d154a62da478860841303703ab1a0b82 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Jan 2024 11:06:13 +0000 Subject: [PATCH 13/30] Add in plumbing between ep_buffer and audio for PLL stability synch --- lib_xua/api/xua_audiohub.h | 14 ++++++++++---- lib_xua/api/xua_buffer.h | 2 ++ lib_xua/src/core/audiohub/xua_audiohub.xc | 6 ++++-- lib_xua/src/core/buffer/ep/ep_buffer.xc | 15 +++++++++++++-- lib_xua/src/core/main.xc | 13 ++++++++++++- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lib_xua/api/xua_audiohub.h b/lib_xua/api/xua_audiohub.h index ed9da2aa..c056d591 100644 --- a/lib_xua/api/xua_audiohub.h +++ b/lib_xua/api/xua_audiohub.h @@ -38,12 +38,16 @@ * * \param i_SoftPll Interface to software PLL task * - * \param c_spdif_tx Channel connected to S/PDIF transmiter core from lib_spdif + * \param c_spdif_tx Channel connected to S/PDIF transmitter core from lib_spdif * * \param c_dig Channel connected to the clockGen() thread for * receiving/transmitting samples * - * \param c_mclk_change Channel notifying clockgen of an mclk frequency change + * \param c_mclk_change Channel notifying ep_buffer of an mclk frequency change and sync for stable clock + * + * \param dfuInterface Interface supporting DFU methods + * + * \param c_pdm_in Channel for receiving decimated PDM samples */ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, @@ -61,12 +65,14 @@ void XUA_AudioHub(chanend ?c_aud, #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__)) , chanend c_dig +#endif +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__)) , chanend c_mclk_change #endif -#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1) +#if (((XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)) || defined(__DOXYGEN__)) , server interface i_dfu ?dfuInterface #endif -#if (XUA_NUM_PDM_MICS > 0) +#if (XUA_NUM_PDM_MICS > 0 || defined(__DOXYGEN__)) , chanend c_pdm_in #endif ); diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index 0e2dd3ee..10539bfa 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -53,6 +53,7 @@ void XUA_Buffer( #endif , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__) + , chanend c_mclk_change #if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__) , client interface pll_ref_if i_pll_ref #endif @@ -88,6 +89,7 @@ void XUA_Buffer_Ep(chanend c_aud_out, , chanend c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__) + , chanend c_mclk_change #if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__) , client interface pll_ref_if i_pll_ref #endif diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index ca499f28..b4a62e9e 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -641,6 +641,8 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, #endif #if (XUA_ADAT_RX_EN || XUA_SPDIF_RX_EN) , chanend c_dig_rx +#endif +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , chanend c_mclk_change #endif #if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1) @@ -807,12 +809,12 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, /* User code should configure audio harware for SampleFreq/MClk etc */ AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC); -#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) /* Notify clockgen of new mCLk */ c_mclk_change <: mClk; c_mclk_change <: curFreq; - /* Wait for ACK back from clockgen to signal clocks all good */ + /* Wait for ACK back from clockgen or ep_buffer to signal clocks all good */ c_mclk_change :> int _; #endif diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 608f301b..c5261512 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -105,6 +105,7 @@ void XUA_Buffer( #endif , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) + , chanend c_mclk_change #if(XUA_USE_SW_PLL) , chanend c_sw_pll #else @@ -145,6 +146,7 @@ void XUA_Buffer( , c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) + , c_mclk_change #if(XUA_USE_SW_PLL) , c_sw_pll #else @@ -199,6 +201,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, , chanend c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) + , chanend c_mclk_change #if (XUA_USE_SW_PLL) , chanend c_sw_pll #else @@ -1030,14 +1033,22 @@ void XUA_Buffer_Ep(register chanend c_aud_out, break; #endif /* ifdef MIDI */ -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XUA_USE_SW_PLL) +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) + case c_mclk_change :> u_tmp: + unsigned selected_mclk_rate = u_tmp; + c_mclk_change :> u_tmp; /* Sample rate we discard */ + c_mclk_change <: 0; /* ACK back to audio to release */ + break; + +#if (XUA_USE_SW_PLL) /* This is fired when sw_pll has completed initialising a new mclk_rate */ case inuint_byref(c_sw_pll, u_tmp): printstr("SWPLL synch\n"); //TODO - hold off audio until we get this ACK break; -#endif /* ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XUA_USE_SW_PLL) */ +#endif /* (XUA_USE_SW_PLL) */ +#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) */ #ifdef IAP /* Received word from iap thread - Check for ACK or Data */ diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 901e59bc..85cd0f29 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -315,6 +315,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_SYNCMODE == XUA_SYNCMODE_SYNC) + , chanend c_mclk_change +#endif #if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) , port p_for_mclk_count_aud , chanend c_sw_pll @@ -328,7 +331,6 @@ void usb_audio_io(chanend ?c_aud_in, #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) chan c_dig_rx; chan c_mclk_change; /* Notification of new mclk freq to clockgen */ - #if XUA_USE_SW_PLL /* Connect p_for_mclk_count_aud to clk_audio_mclk so we can count mclks/timestamp in digital rx*/ @@ -381,6 +383,8 @@ void usb_audio_io(chanend ?c_aud_in, #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , c_dig_rx +#endif +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , c_mclk_change #endif #if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1) @@ -496,6 +500,9 @@ int main() #if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) chan c_sw_pll; +#endif +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) + chan c_mclk_change; /* Notification of new mclk freq to ep_buffer */ #endif chan c_sof; chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */ @@ -589,6 +596,7 @@ int main() #endif , c_mix_out #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) + , c_mclk_change #if (!XUA_USE_SW_PLL) , i_pll_ref #else @@ -632,6 +640,9 @@ int main() #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , i_pll_ref #endif +#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) + , c_mclk_change +#endif #if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) , p_for_mclk_count_audio , c_sw_pll From a9ed38252ceb92a0dc4d7ed3ecd006eb637370c3 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Jan 2024 16:14:50 +0000 Subject: [PATCH 14/30] Put PFD reset in c_mclk_change case --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 28 +++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index c5261512..a2697df2 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -483,15 +483,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, { masterClockFreq = MCLK_441; } -#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && XUA_USE_SW_PLL) - sw_pll_pfd_init(&sw_pll_pfd, - sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ - masterClockFreq / sof_rate_hz, /* pll ratio integer */ - 0, /* Assume precise timing of sampling */ - 2000); - restart_sigma_delta(c_sw_pll, masterClockFreq); - -#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && XUA_USE_SW_PLL) */ } #endif /* (MAX_FREQ != MIN_FREQ) */ /* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this @@ -1035,17 +1026,28 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) case c_mclk_change :> u_tmp: + printstr("c_mclk_change\n"); unsigned selected_mclk_rate = u_tmp; - c_mclk_change :> u_tmp; /* Sample rate we discard */ - c_mclk_change <: 0; /* ACK back to audio to release */ + c_mclk_change :> u_tmp; /* Sample rate is discarded as only care about mclk */ +#if (XUA_USE_SW_PLL) + sw_pll_pfd_init(&sw_pll_pfd, + sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ + selected_mclk_rate / sof_rate_hz, /* pll muliplication ratio integer */ + 0, /* Assume precise timing of sampling */ + 2000); + restart_sigma_delta(c_sw_pll, selected_mclk_rate); + /* Delay ACK until sw_pll says it is ready */ +#else + c_mclk_change <: 0; /* ACK back to audio to release I2S immediately */ +#endif /* XUA_USE_SW_PLL */ break; #if (XUA_USE_SW_PLL) /* This is fired when sw_pll has completed initialising a new mclk_rate */ case inuint_byref(c_sw_pll, u_tmp): printstr("SWPLL synch\n"); - - //TODO - hold off audio until we get this ACK + c_mclk_change <: 0; /* ACK back to audio to release */ + break; #endif /* (XUA_USE_SW_PLL) */ #endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) */ From f32955a419781e6bf1c556bbad1b469b56d0d2d1 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Jan 2024 17:13:01 +0000 Subject: [PATCH 15/30] Add missing include in cmake --- lib_xua/lib_build_info.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/lib_xua/lib_build_info.cmake b/lib_xua/lib_build_info.cmake index fe37f3b3..36d83e71 100644 --- a/lib_xua/lib_build_info.cmake +++ b/lib_xua/lib_build_info.cmake @@ -14,6 +14,7 @@ set(LIB_INCLUDES api src/core/support src/core/user src/core/user/audiostream + src/core/user/audiohw src/core/user/hid src/core/user/hostactive src/hid From fc708fe4e9181e41705176a003550cb7d8a15e45 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Jan 2024 17:13:19 +0000 Subject: [PATCH 16/30] Update changelog for sync / sw_pll --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dc98f70c..7892a1e7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,7 +14,7 @@ HEAD * CHANGED: QUAD_SPI_FLASH replaced by XUA_QUAD_SPI_FLASH (default: 1) * CHANGED: UserBufferManagementInit() now takes a sample rate parameter * CHANGED: xcore.ai targets use sigma-delta software PLL for clock recovery of - digital Rx streams by default. + digital Rx streams and synch USB audio by default. * Changes to dependencies: From 5669a5b02161784d584a918b8d030f85261a4300 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 22 Jan 2024 09:27:18 +0000 Subject: [PATCH 17/30] Fix synch test --- tests/test_sync_clk_basic/Makefile | 4 ++-- tests/test_sync_clk_basic/src/main.xc | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/test_sync_clk_basic/Makefile b/tests/test_sync_clk_basic/Makefile index 86e4e277..8b1468ac 100644 --- a/tests/test_sync_clk_basic/Makefile +++ b/tests/test_sync_clk_basic/Makefile @@ -3,12 +3,12 @@ TEST_FLAGS ?= XCC_FLAGS_HS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \ -DBUS_SPEED=2 \ - -DXUA_USE_APP_PLL=0 \ + -DXUA_USE_SW_PLL=0 \ $(TEST_FLAGS) XCC_FLAGS_FS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \ -DBUS_SPEED=1 \ - -DXUA_USE_APP_PLL=0 \ + -DXUA_USE_SW_PLL=0 \ $(TEST_FLAGS) TARGET = test_xs3_600.xn diff --git a/tests/test_sync_clk_basic/src/main.xc b/tests/test_sync_clk_basic/src/main.xc index d6c5b519..ad397226 100644 --- a/tests/test_sync_clk_basic/src/main.xc +++ b/tests/test_sync_clk_basic/src/main.xc @@ -173,6 +173,7 @@ int main() chan c_in[EP_COUNT_IN]; chan c_sof; chan c_aud_ctl; + chan c_mclk_change; interface pll_ref_if i_pll_ref; @@ -185,7 +186,7 @@ int main() XUA_Buffer_Ep(c_out[1], /* USB Audio Out*/ c_in[1], /* USB Audio In */ - c_sof, c_aud_ctl, p_off_mclk, i_pll_ref + c_sof, c_aud_ctl, p_off_mclk, c_mclk_change, i_pll_ref ); } @@ -193,4 +194,6 @@ int main() checker(); } + + return 0; } From e8317eae3632332742722045a6d5bf40e890988a Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 22 Jan 2024 09:57:40 +0000 Subject: [PATCH 18/30] Minor fixes --- lib_xua/lib_build_info.cmake | 2 +- tests/test_sync_clk_basic/src/main.xc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib_xua/lib_build_info.cmake b/lib_xua/lib_build_info.cmake index 36d83e71..14435992 100644 --- a/lib_xua/lib_build_info.cmake +++ b/lib_xua/lib_build_info.cmake @@ -27,7 +27,7 @@ set(LIB_DEPENDENT_MODULES "lib_locks" "lib_xassert" "lib_xud" "lib_adat" - "lib_sw_pll(develop)") + "lib_sw_pll") set(LIB_COMPILER_FLAGS -O3 -DREF_CLK_FREQ=100 -fasm-linenum -fcomment-asm) diff --git a/tests/test_sync_clk_basic/src/main.xc b/tests/test_sync_clk_basic/src/main.xc index ad397226..49d216cf 100644 --- a/tests/test_sync_clk_basic/src/main.xc +++ b/tests/test_sync_clk_basic/src/main.xc @@ -1,4 +1,4 @@ -// Copyright 2022 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* Simple test to ensure reference clock to CS2100 device continues when SOF clock not available From 3be17bf8cc0647b0d6dc3cb79882d5580bab0a38 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 22 Jan 2024 14:32:03 +0000 Subject: [PATCH 19/30] c_mclk_change -> c_audio_rate_change --- lib_xua/api/xua_audiohub.h | 34 +++++++++++------------ lib_xua/api/xua_buffer.h | 4 +-- lib_xua/api/xua_clocking.h | 22 +++++++-------- lib_xua/src/core/audiohub/xua_audiohub.xc | 8 +++--- lib_xua/src/core/buffer/ep/ep_buffer.xc | 16 +++++------ lib_xua/src/core/clocking/clockgen.xc | 10 +++---- lib_xua/src/core/main.xc | 15 +++++----- tests/test_sync_clk_basic/src/main.xc | 4 +-- 8 files changed, 56 insertions(+), 57 deletions(-) diff --git a/lib_xua/api/xua_audiohub.h b/lib_xua/api/xua_audiohub.h index c056d591..2f18960f 100644 --- a/lib_xua/api/xua_audiohub.h +++ b/lib_xua/api/xua_audiohub.h @@ -19,35 +19,35 @@ * 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_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 master clock * - * \param clk_audio_bclk Nullable clockblock to be clocked from i2s bit clock + * \param clk_audio_bclk Nullable clockblock to be clocked from i2s bit clock * - * \param p_mclk_in Master clock inport port (must be 1-bit) + * \param p_mclk_in Master clock inport port (must be 1-bit) * - * \param p_lrclk Nullable port for I2S sample clock + * \param p_lrclk Nullable port for I2S sample clock * - * \param p_bclk Nullable port for I2S bit + * \param p_bclk Nullable port for I2S bit clock * - * \param p_i2s_dac Nullable array of ports for I2S data output lines + * \param p_i2s_dac Nullable array of ports for I2S data output lines * - * \param p_i2s_adc Nullable array of ports for I2S data input lines + * \param p_i2s_adc Nullable array of ports for I2S data input lines * - * \param i_SoftPll Interface to software PLL task + * \param i_SoftPll Interface to software PLL task * - * \param c_spdif_tx Channel connected to S/PDIF transmitter core from lib_spdif + * \param c_spdif_tx Channel connected to S/PDIF transmitter core from lib_spdif * - * \param c_dig Channel connected to the clockGen() thread for - * receiving/transmitting samples + * \param c_dig Channel connected to the clockGen() thread for + * receiving/transmitting samples * - * \param c_mclk_change Channel notifying ep_buffer of an mclk frequency change and sync for stable clock + * \param c_audio_rate_change Channel notifying ep_buffer of an mclk frequency change and sync for stable clock * - * \param dfuInterface Interface supporting DFU methods + * \param dfuInterface Interface supporting DFU methods * - * \param c_pdm_in Channel for receiving decimated PDM samples + * \param c_pdm_in Channel for receiving decimated PDM samples */ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, @@ -67,7 +67,7 @@ void XUA_AudioHub(chanend ?c_aud, , chanend c_dig #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__)) - , chanend c_mclk_change + , chanend c_audio_rate_change #endif #if (((XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)) || defined(__DOXYGEN__)) , server interface i_dfu ?dfuInterface diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index 10539bfa..5f853133 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -53,7 +53,7 @@ void XUA_Buffer( #endif , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__) - , chanend c_mclk_change + , chanend c_audio_rate_change #if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__) , client interface pll_ref_if i_pll_ref #endif @@ -89,7 +89,7 @@ void XUA_Buffer_Ep(chanend c_aud_out, , chanend c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__) - , chanend c_mclk_change + , chanend c_audio_rate_change #if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__) , client interface pll_ref_if i_pll_ref #endif diff --git a/lib_xua/api/xua_clocking.h b/lib_xua/api/xua_clocking.h index 2b64e7bf..4709bdad 100644 --- a/lib_xua/api/xua_clocking.h +++ b/lib_xua/api/xua_clocking.h @@ -20,17 +20,17 @@ void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_sync); /** Clock generation and digital audio I/O handling. * - * \param c_spdif_rx channel connected to S/PDIF receive thread - * \param c_adat_rx channel connect to ADAT receive thread - * \param i_pll_ref interface to taslk that outputs clock signal to drive external frequency synthesizer - * \param c_audio channel connected to the audio() thread - * \param c_clk_ctl channel connected to Endpoint0() for configuration of the - * clock - * \param c_clk_int channel connected to the decouple() thread for clock - * interrupts - * \param c_mclk_change channel to notify of master clock change + * \param c_spdif_rx channel connected to S/PDIF receive thread + * \param c_adat_rx channel connect to ADAT receive thread + * \param i_pll_ref interface to taslk that outputs clock signal to drive external frequency synthesizer + * \param c_audio channel connected to the audio() thread + * \param c_clk_ctl channel connected to Endpoint0() for configuration of the + * clock + * \param c_clk_int channel connected to the decouple() thread for clock + * interrupts + * \param c_audio_rate_change channel to notify of master clock change * \param p_for_mclk_count_aud port used for counting mclk and providing a timestamp - * \param c_sw_pll channel used to communicate with software PLL task + * \param c_sw_pll channel used to communicate with software PLL task * */ void clockGen( streaming chanend ?c_spdif_rx, @@ -39,7 +39,7 @@ void clockGen( streaming chanend ?c_spdif_rx, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int, - chanend c_mclk_change + chanend c_audio_rate_change #if XUA_USE_SW_PLL , port p_for_mclk_count_aud , chanend c_sw_pll diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index b4a62e9e..ddc3e857 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -643,7 +643,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, , chanend c_dig_rx #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - , chanend c_mclk_change + , chanend c_audio_rate_change #endif #if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1) , server interface i_dfu ?dfuInterface @@ -811,11 +811,11 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC); #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) /* Notify clockgen of new mCLk */ - c_mclk_change <: mClk; - c_mclk_change <: curFreq; + c_audio_rate_change <: mClk; + c_audio_rate_change <: curFreq; /* Wait for ACK back from clockgen or ep_buffer to signal clocks all good */ - c_mclk_change :> int _; + c_audio_rate_change :> int _; #endif /* User should unmute audio hardware */ diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index a2697df2..504d9e2d 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -105,7 +105,7 @@ void XUA_Buffer( #endif , chanend c_aud #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - , chanend c_mclk_change + , chanend c_audio_rate_change #if(XUA_USE_SW_PLL) , chanend c_sw_pll #else @@ -146,7 +146,7 @@ void XUA_Buffer( , c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - , c_mclk_change + , c_audio_rate_change #if(XUA_USE_SW_PLL) , c_sw_pll #else @@ -201,7 +201,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, , chanend c_buff_ctrl #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - , chanend c_mclk_change + , chanend c_audio_rate_change #if (XUA_USE_SW_PLL) , chanend c_sw_pll #else @@ -1025,10 +1025,10 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif /* ifdef MIDI */ #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - case c_mclk_change :> u_tmp: - printstr("c_mclk_change\n"); + case c_audio_rate_change :> u_tmp: + printstr("c_audio_rate_change\n"); unsigned selected_mclk_rate = u_tmp; - c_mclk_change :> u_tmp; /* Sample rate is discarded as only care about mclk */ + c_audio_rate_change :> u_tmp; /* Sample rate is discarded as only care about mclk */ #if (XUA_USE_SW_PLL) sw_pll_pfd_init(&sw_pll_pfd, sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ @@ -1038,7 +1038,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, restart_sigma_delta(c_sw_pll, selected_mclk_rate); /* Delay ACK until sw_pll says it is ready */ #else - c_mclk_change <: 0; /* ACK back to audio to release I2S immediately */ + c_audio_rate_change <: 0; /* ACK back to audio to release I2S immediately */ #endif /* XUA_USE_SW_PLL */ break; @@ -1046,7 +1046,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, /* This is fired when sw_pll has completed initialising a new mclk_rate */ case inuint_byref(c_sw_pll, u_tmp): printstr("SWPLL synch\n"); - c_mclk_change <: 0; /* ACK back to audio to release */ + c_audio_rate_change <: 0; /* ACK back to audio to release */ break; #endif /* (XUA_USE_SW_PLL) */ diff --git a/lib_xua/src/core/clocking/clockgen.xc b/lib_xua/src/core/clocking/clockgen.xc index 7673b298..88166a85 100644 --- a/lib_xua/src/core/clocking/clockgen.xc +++ b/lib_xua/src/core/clocking/clockgen.xc @@ -222,7 +222,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int, - chanend c_mclk_change + chanend c_audio_rate_change #if XUA_USE_SW_PLL , port p_for_mclk_count_aud , chanend c_sw_pll @@ -525,7 +525,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, This happens only on SDM restart and only once */ if(require_ack_to_audio) { - c_mclk_change <: tmp; + c_audio_rate_change <: tmp; require_ack_to_audio = 0; } break; @@ -533,8 +533,8 @@ void clockGen ( streaming chanend ?c_spdif_rx, #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) /* Receive notification of audio streaming settings change and store */ - case c_mclk_change :> selected_mclk_rate: - c_mclk_change :> selected_sample_rate; + case c_audio_rate_change :> selected_mclk_rate: + c_audio_rate_change :> selected_sample_rate; #if XUA_USE_SW_PLL mclks_per_sample = selected_mclk_rate / selected_sample_rate; restart_sigma_delta(c_sw_pll, selected_mclk_rate); @@ -543,7 +543,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, require_ack_to_audio = 1; #else /* Send ACK immediately as we are good to go if not using SW_PLL */ - c_mclk_change <: 0; + c_audio_rate_change <: 0; #endif break; #endif diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 85cd0f29..2b5efdeb 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -316,7 +316,7 @@ void usb_audio_io(chanend ?c_aud_in, , client interface pll_ref_if i_pll_ref #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - , chanend c_mclk_change + , chanend c_audio_rate_change #endif #if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) , port p_for_mclk_count_aud @@ -330,10 +330,9 @@ void usb_audio_io(chanend ?c_aud_in, #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) chan c_dig_rx; - chan c_mclk_change; /* Notification of new mclk freq to clockgen */ + chan c_audio_rate_change; /* Notification of new mclk freq to clockgen and synch */ #if XUA_USE_SW_PLL /* Connect p_for_mclk_count_aud to clk_audio_mclk so we can count mclks/timestamp in digital rx*/ - unsigned x = 0; asm("ldw %0, dp[clk_audio_mclk]":"=r"(x)); asm("setclk res[%0], %1"::"r"(p_for_mclk_count_aud), "r"(x)); @@ -385,7 +384,7 @@ void usb_audio_io(chanend ?c_aud_in, , c_dig_rx #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - , c_mclk_change + , c_audio_rate_change #endif #if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1) , dfuInterface @@ -412,7 +411,7 @@ void usb_audio_io(chanend ?c_aud_in, c_dig_rx, c_clk_ctl, c_clk_int, - c_mclk_change + c_audio_rate_change #if XUA_USE_SW_PLL , p_for_mclk_count_aud , c_sw_pll @@ -502,7 +501,7 @@ int main() chan c_sw_pll; #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - chan c_mclk_change; /* Notification of new mclk freq to ep_buffer */ + chan c_audio_rate_change; /* Notification of new mclk freq to ep_buffer */ #endif chan c_sof; chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */ @@ -596,7 +595,7 @@ int main() #endif , c_mix_out #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - , c_mclk_change + , c_audio_rate_change #if (!XUA_USE_SW_PLL) , i_pll_ref #else @@ -641,7 +640,7 @@ int main() , i_pll_ref #endif #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - , c_mclk_change + , c_audio_rate_change #endif #if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) , p_for_mclk_count_audio diff --git a/tests/test_sync_clk_basic/src/main.xc b/tests/test_sync_clk_basic/src/main.xc index 49d216cf..79c5e1e7 100644 --- a/tests/test_sync_clk_basic/src/main.xc +++ b/tests/test_sync_clk_basic/src/main.xc @@ -173,7 +173,7 @@ int main() chan c_in[EP_COUNT_IN]; chan c_sof; chan c_aud_ctl; - chan c_mclk_change; + chan c_audio_rate_change; interface pll_ref_if i_pll_ref; @@ -186,7 +186,7 @@ int main() XUA_Buffer_Ep(c_out[1], /* USB Audio Out*/ c_in[1], /* USB Audio In */ - c_sof, c_aud_ctl, p_off_mclk, c_mclk_change, i_pll_ref + c_sof, c_aud_ctl, p_off_mclk, c_audio_rate_change, i_pll_ref ); } From d49c6b4656c75998fd453b3ef9b41e98bcd58fc4 Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 23 Jan 2024 10:45:27 +0000 Subject: [PATCH 20/30] Fix non-integer divide result issue --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 21 ++++++++++----------- lib_xua/src/core/clocking/sw_pll_wrapper.xc | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 504d9e2d..6e5ba75c 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -376,14 +376,14 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #if (XUA_USE_SW_PLL) /* Setup the phase frequency detector */ const unsigned controller_rate_hz = 100; - const unsigned sof_rate_hz = (AUDIO_CLASS == 1 ? 1000 : 8000); + const unsigned pfd_ppm_max = 2000; /* PPM range before we assume unlocked */ sw_pll_pfd_state_t sw_pll_pfd; sw_pll_pfd_init(&sw_pll_pfd, - sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ - masterClockFreq / sof_rate_hz, /* pll ratio integer */ - 0, /* Assume precise timing of sampling */ - 2000); /* PPM range before we assume unlocked */ + 1, /* How often the PFD is invoked per call */ + masterClockFreq / controller_rate_hz, /* pll ratio integer */ + 0, /* Assume precise timing of sampling */ + pfd_ppm_max); outuint(c_sw_pll, masterClockFreq); inuint(c_sw_pll); /* receive ACK */ @@ -601,8 +601,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out, } sw_pll_pfd.mclk_pt_last = mclk_pt; - outuint(c_sw_pll, error); + printintln(error); // outct(c_sw_pll, XS1_CT_END); } #endif @@ -752,7 +752,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, clocks < (expected_fb + FB_TOLERANCE)) #endif { - int usb_speed; asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed); @@ -1031,10 +1030,10 @@ void XUA_Buffer_Ep(register chanend c_aud_out, c_audio_rate_change :> u_tmp; /* Sample rate is discarded as only care about mclk */ #if (XUA_USE_SW_PLL) sw_pll_pfd_init(&sw_pll_pfd, - sof_rate_hz / controller_rate_hz, /* How often the PFD is invoked */ - selected_mclk_rate / sof_rate_hz, /* pll muliplication ratio integer */ - 0, /* Assume precise timing of sampling */ - 2000); + 1, /* How often the PFD is invoked per call */ + selected_mclk_rate / controller_rate_hz, /* pll muliplication ratio integer */ + 0, /* Assume precise timing of sampling */ + pfd_ppm_max); restart_sigma_delta(c_sw_pll, selected_mclk_rate); /* Delay ACK until sw_pll says it is ready */ #else diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.xc b/lib_xua/src/core/clocking/sw_pll_wrapper.xc index bc9a7d9d..c83b9a6c 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.xc +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.xc @@ -181,7 +181,7 @@ void sw_pll_task(chanend c_sw_pll){ unsafe { sw_pll_do_sigma_delta(&sw_pll.sdm_state, this_tile, dco_setting); } - } /* if running */ + } /* while running */ } /* while(1) */ } From 44049ecfca7799d2cde6b4c814cea0c378a91ae4 Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 23 Jan 2024 11:43:36 +0000 Subject: [PATCH 21/30] Use CT_END in sw_pll comms to clear switch path --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 6 +++++- lib_xua/src/core/clocking/clockgen.xc | 3 ++- lib_xua/src/core/clocking/sw_pll_wrapper.xc | 6 ++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 6e5ba75c..171fa7cf 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -385,7 +385,9 @@ void XUA_Buffer_Ep(register chanend c_aud_out, 0, /* Assume precise timing of sampling */ pfd_ppm_max); outuint(c_sw_pll, masterClockFreq); + outct(c_sw_pll, XS1_CT_END); inuint(c_sw_pll); /* receive ACK */ + inct(c_sw_pll); #else /* XUA_USE_SW_PLL */ timer t_sofCheck; @@ -602,8 +604,9 @@ void XUA_Buffer_Ep(register chanend c_aud_out, sw_pll_pfd.mclk_pt_last = mclk_pt; outuint(c_sw_pll, error); + outct(c_sw_pll, XS1_CT_END); + printintln(error); - // outct(c_sw_pll, XS1_CT_END); } #endif @@ -1044,6 +1047,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #if (XUA_USE_SW_PLL) /* This is fired when sw_pll has completed initialising a new mclk_rate */ case inuint_byref(c_sw_pll, u_tmp): + inct(c_sw_pll); printstr("SWPLL synch\n"); c_audio_rate_change <: 0; /* ACK back to audio to release */ diff --git a/lib_xua/src/core/clocking/clockgen.xc b/lib_xua/src/core/clocking/clockgen.xc index 88166a85..f44c7f37 100644 --- a/lib_xua/src/core/clocking/clockgen.xc +++ b/lib_xua/src/core/clocking/clockgen.xc @@ -520,7 +520,8 @@ void clockGen ( streaming chanend ?c_spdif_rx, #endif #if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) - case inuint_byref(c_sw_pll, tmp): + case inuint_byref(c_sw_pll, tmp): + inct(c_sw_pll); /* Send ACK back to audiohub to allow I2S to start This happens only on SDM restart and only once */ if(require_ack_to_audio) diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.xc b/lib_xua/src/core/clocking/sw_pll_wrapper.xc index c83b9a6c..04397396 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.xc +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.xc @@ -107,6 +107,7 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, /* send PFD output to the sigma delta thread */ outuint(c_sw_pll, (int) f_error); + outct(c_sw_pll, XS1_CT_END); last_mclk_time_stamp = mclk_time_stamp; control_loop_counter = 0; @@ -122,6 +123,7 @@ void sw_pll_task(chanend c_sw_pll){ while(1) { unsigned selected_mclk_rate = inuint(c_sw_pll); + inct(c_sw_pll); int f_error = 0; int dco_setting = 0; /* gets set at init_sw_pll */ @@ -139,6 +141,7 @@ void sw_pll_task(chanend c_sw_pll){ int running = 1; outuint(c_sw_pll, 0); /* Signal back via clockgen to audio to start I2S */ + outct(c_sw_pll, XS1_CT_END); unsigned rx_word = 0; while(running) @@ -147,6 +150,7 @@ void sw_pll_task(chanend c_sw_pll){ select { case inuint_byref(c_sw_pll, rx_word): + inct(c_sw_pll); if(rx_word == DISABLE_SDM) { f_error = 0; @@ -189,7 +193,9 @@ void sw_pll_task(chanend c_sw_pll){ void restart_sigma_delta(chanend c_sw_pll, unsigned selected_mclk_rate) { outuint(c_sw_pll, DISABLE_SDM); /* Resets SDM */ + outct(c_sw_pll, XS1_CT_END); outuint(c_sw_pll, selected_mclk_rate); + outct(c_sw_pll, XS1_CT_END); } #endif /* XUA_USE_SW_PLL */ From 7febbfdcd08ab6292dd20291d9d705821e69c313 Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 23 Jan 2024 12:40:15 +0000 Subject: [PATCH 22/30] Refactor sync mode c_sof code --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 59 +++++++++++++------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 171fa7cf..e8de973a 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -263,7 +263,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, unsigned bufferIn = 1; #endif int sofCount = 0; - int pllUpdate = 0; unsigned mod_from_last_time = 0; #ifdef FB_TOLERANCE_TEST @@ -463,7 +462,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, /* Note, Endpoint 0 will hold off host for a sufficient period to allow our feedback * to stabilise (i.e. sofCount == 128 to fire) */ sofCount = 0; - pllUpdate = 0; clocks = 0; clockcounter = 0; mod_from_last_time = 0; @@ -559,35 +557,23 @@ void XUA_Buffer_Ep(register chanend c_aud_out, /* SOF notification from XUD_Manager() */ case inuint_byref(c_sof, u_tmp): #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) - /* This really could (should) be done in decouple. However, for a quick demo this is okay - * Decouple expects a 16:16 number in fixed point stored in the global g_speed */ unsigned usbSpeed; - int framesPerSec; GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed); - - framesPerSec = (usbSpeed == XUD_SPEED_HS) ? 8000 : 1000; - - clocks = ((int64_t) sampleFreq << 16) / framesPerSec; - - asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); - - sofCount += 1000; - if (sofCount == framesPerSec) - { - sofCount = 0; - pllUpdate++; -#if (!XUA_USE_SW_PLL) - /* Port is accessed via interface to allow flexibilty with location */ - i_pll_ref.toggle(); - t_sofCheck :> timeLastEdge; - timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; -#endif - } + static int sofCount = 0; #if (XUA_USE_SW_PLL) - // Update PLL @ 100Hz - if(pllUpdate == 10) + /* Run PFD and sw_pll controller at 100Hz */ + const int sofFreqDivider = (usbSpeed == XUD_SPEED_HS) ? (8000 / controller_rate_hz) : (1000 / controller_rate_hz); +#else /* (XUA_USE_SW_PLL) */ + /* 1000 toggles per second for CS2100 reference -> 500 Hz */ + const int toggleRateHz = 1000; + const int sofFreqDivider = (usbSpeed == XUD_SPEED_HS) ? (8000 / toggleRateHz) : (1000 / toggleRateHz); +#endif /* (XUA_USE_SW_PLL) */ + + sofCount++; + if (sofCount == sofFreqDivider) { - pllUpdate = 0; +#if (XUA_USE_SW_PLL) + /* Grab port timer count, run through PFD and send to sw_pll */ unsigned short mclk_pt; asm volatile("getts %0, res[%1]" : "=r" (mclk_pt) : "r" (p_off_mclk)); @@ -603,12 +589,29 @@ void XUA_Buffer_Ep(register chanend c_aud_out, } sw_pll_pfd.mclk_pt_last = mclk_pt; + /* Send error to sw_pll */ outuint(c_sw_pll, error); outct(c_sw_pll, XS1_CT_END); printintln(error); +#else /* (XUA_USE_SW_PLL) */ + /* Do toggle for CS2100 reference clock */ + /* Port is accessed via interface to allow flexibilty with location */ + i_pll_ref.toggle(); + t_sofCheck :> timeLastEdge; + timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; +#endif /* (XUA_USE_SW_PLL) */ + sofCount = 0; } -#endif + + /* This really could (should) be done in decouple. However, for a quick demo this is okay + * Decouple expects a 16:16 number in fixed point stored in the global g_speed */ + + const int framesPerSec = (usbSpeed == XUD_SPEED_HS) ? 8000 : 1000; + + clocks = ((int64_t) sampleFreq << 16) / framesPerSec; + asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); + #elif (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC) From 0d1f81276dcf7ef3ac1c5c3bd86c60cb7a5da467 Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 23 Jan 2024 17:06:27 +0000 Subject: [PATCH 23/30] Make SDM loop startup safer --- lib_xua/src/core/buffer/ep/ep_buffer.xc | 4 ++-- lib_xua/src/core/clocking/sw_pll_wrapper.xc | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index e8de973a..d0fb1adf 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -1031,7 +1031,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) case c_audio_rate_change :> u_tmp: - printstr("c_audio_rate_change\n"); + printstr("rc\n"); unsigned selected_mclk_rate = u_tmp; c_audio_rate_change :> u_tmp; /* Sample rate is discarded as only care about mclk */ #if (XUA_USE_SW_PLL) @@ -1051,7 +1051,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, /* This is fired when sw_pll has completed initialising a new mclk_rate */ case inuint_byref(c_sw_pll, u_tmp): inct(c_sw_pll); - printstr("SWPLL synch\n"); + printstr("sy\n"); c_audio_rate_change <: 0; /* ACK back to audio to release */ break; diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.xc b/lib_xua/src/core/clocking/sw_pll_wrapper.xc index 04397396..beb69ee8 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.xc +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.xc @@ -138,6 +138,7 @@ void sw_pll_task(chanend c_sw_pll){ timer tmr; int32_t time_trigger; tmr :> time_trigger; + time_trigger += sdm_interval; /* ensure first loop has correct delay */ int running = 1; outuint(c_sw_pll, 0); /* Signal back via clockgen to audio to start I2S */ From e72a386fa20bf49594441c09b26288eaab0369d2 Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 23 Jan 2024 17:06:41 +0000 Subject: [PATCH 24/30] Use branch of sw_pll for now --- lib_xua/lib_build_info.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/lib_build_info.cmake b/lib_xua/lib_build_info.cmake index 14435992..782ae6cd 100644 --- a/lib_xua/lib_build_info.cmake +++ b/lib_xua/lib_build_info.cmake @@ -27,7 +27,7 @@ set(LIB_DEPENDENT_MODULES "lib_locks" "lib_xassert" "lib_xud" "lib_adat" - "lib_sw_pll") + "lib_sw_pll(feature/non_ack_reg_Write)") set(LIB_COMPILER_FLAGS -O3 -DREF_CLK_FREQ=100 -fasm-linenum -fcomment-asm) From 5980d0edeacd4114eda72fc3b5779a3d2a9280f7 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 26 Jan 2024 09:22:15 +0000 Subject: [PATCH 25/30] sw_pll to develop --- lib_xua/lib_build_info.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/lib_build_info.cmake b/lib_xua/lib_build_info.cmake index 782ae6cd..14435992 100644 --- a/lib_xua/lib_build_info.cmake +++ b/lib_xua/lib_build_info.cmake @@ -27,7 +27,7 @@ set(LIB_DEPENDENT_MODULES "lib_locks" "lib_xassert" "lib_xud" "lib_adat" - "lib_sw_pll(feature/non_ack_reg_Write)") + "lib_sw_pll") set(LIB_COMPILER_FLAGS -O3 -DREF_CLK_FREQ=100 -fasm-linenum -fcomment-asm) From 4d3fe821134a6728acdf057b734f2b1d19c76270 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 26 Jan 2024 11:05:31 +0000 Subject: [PATCH 26/30] Update docs for sync mode with sw_pll --- lib_xua/doc/rst/opt_sync.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib_xua/doc/rst/opt_sync.rst b/lib_xua/doc/rst/opt_sync.rst index dce27bab..a6b3b607 100644 --- a/lib_xua/doc/rst/opt_sync.rst +++ b/lib_xua/doc/rst/opt_sync.rst @@ -39,8 +39,11 @@ Setting the synchronisation mode of the device is done using the define in :ref: - USB synchronisation mode - ``XUA_SYNCMODE_ASYNC`` -When operating in synchronous mode an external Cirrus Logic CS2100 device is required for master clock -generation. The codebase expects to drive a synchronisation signal to this external device +When operating in synchronous mode a local master clock must be generated that is synchronised to the incoming +SoF rate from USB. Either an external Cirrus Logic CS2100 device is required for this purpose +or, on xcore.ai devices, the on-chip application PLL may be used via lib_sw_pll. +In the case of using the CS2100, the codebase expects to drive a synchronisation signal to this external device +as a reference. The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set appropriately. @@ -56,8 +59,11 @@ The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set ap * - ``PLL_REF_TILE`` - Tile location of reference to CS2100 device - ``AUDIO_IO_TILE`` + * - ``XUA_USE_SW_PLL`` + - Whether or not to use sw_pll to recover the clock (xcore.ai only) + - 1 for xcore.ai targets. May be overridden to 0 in ``xua_conf.h`` -The codebase expects this reference signal port to be defined in the application XN file as ``PORT_PLL_REF``. +The codebase expects the CS2100 reference signal port to be defined in the application XN file as ``PORT_PLL_REF``. This may be a port of any bit-width, however, connection to bit[0] is assumed:: From 8ec5f8c7fccd50e7fabee390a41b00171cf2d0ed Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 26 Jan 2024 11:48:38 +0000 Subject: [PATCH 27/30] Review cleanup --- lib_xua/api/xua_audiohub.h | 3 --- lib_xua/api/xua_buffer.h | 29 +++++++++++----------- lib_xua/src/core/buffer/ep/ep_buffer.xc | 3 --- lib_xua/src/core/clocking/sw_pll_wrapper.h | 2 +- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/lib_xua/api/xua_audiohub.h b/lib_xua/api/xua_audiohub.h index 2f18960f..01383277 100644 --- a/lib_xua/api/xua_audiohub.h +++ b/lib_xua/api/xua_audiohub.h @@ -57,9 +57,6 @@ 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 diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index 5f853133..e8ebdbc7 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -13,20 +13,21 @@ * Most of the chanend parameters to the function should be connected to * XUD_Manager(). The uses two cores. * - * \param c_aud_out Audio OUT endpoint channel connected to the XUD - * \param c_aud_in Audio IN endpoint channel connected to the XUD - * \param c_aud_fb Audio feedback endpoint channel connected to the XUD - * \param c_midi_from_host MIDI OUT endpoint channel connected to the XUD - * \param c_midi_to_host MIDI IN endpoint channel connected to the XUD - * \param c_midi Channel connected to MIDI core - * \param c_int Audio clocking interrupt endpoint channel connected to the XUD - * \param c_clk_int Optional chanend connected to the clockGen() thread if present - * \param c_sof Start of frame channel connected to the XUD - * \param c_aud_ctl Audio control channel connected to Endpoint0() - * \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. + * \param c_aud_out Audio OUT endpoint channel connected to the XUD + * \param c_aud_in Audio IN endpoint channel connected to the XUD + * \param c_aud_fb Audio feedback endpoint channel connected to the XUD + * \param c_midi_from_host MIDI OUT endpoint channel connected to the XUD + * \param c_midi_to_host MIDI IN endpoint channel connected to the XUD + * \param c_midi Channel connected to MIDI core + * \param c_int Audio clocking interrupt endpoint channel connected to the XUD + * \param c_clk_int Optional chanend connected to the clockGen() thread if present + * \param c_sof Start of frame channel connected to the XUD + * \param c_aud_ctl Audio control channel connected to Endpoint0() + * \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 c_audio_rate_change Channel to notify and synchronise on audio rate change + * \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, diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index d0fb1adf..050ce5b5 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -593,7 +593,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, outuint(c_sw_pll, error); outct(c_sw_pll, XS1_CT_END); - printintln(error); #else /* (XUA_USE_SW_PLL) */ /* Do toggle for CS2100 reference clock */ /* Port is accessed via interface to allow flexibilty with location */ @@ -1031,7 +1030,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) case c_audio_rate_change :> u_tmp: - printstr("rc\n"); unsigned selected_mclk_rate = u_tmp; c_audio_rate_change :> u_tmp; /* Sample rate is discarded as only care about mclk */ #if (XUA_USE_SW_PLL) @@ -1051,7 +1049,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out, /* This is fired when sw_pll has completed initialising a new mclk_rate */ case inuint_byref(c_sw_pll, u_tmp): inct(c_sw_pll); - printstr("sy\n"); c_audio_rate_change <: 0; /* ACK back to audio to release */ break; diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.h b/lib_xua/src/core/clocking/sw_pll_wrapper.h index fbbb98ad..edc86096 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.h +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.h @@ -54,4 +54,4 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, {unsigned, unsigned} InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk); #endif /* XUA_USE_SW_PLL */ -#endif /* _SW_PLL_WRAPPPER_H_ */ \ No newline at end of file +#endif /* _SW_PLL_WRAPPPER_H_ */ From 7847a5ee42f2d398509e97ab7c56154b745a0bf4 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 26 Jan 2024 14:56:53 +0000 Subject: [PATCH 28/30] Reapply volume control fix from 341 --- lib_xua/api/xua_conf_default.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 872064c2..4fb5c2a3 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -1185,7 +1185,11 @@ /* Handle out volume control in the mixer - enabled by default */ #ifndef OUT_VOLUME_IN_MIXER -#define OUT_VOLUME_IN_MIXER (1) +#if MIXER + #define OUT_VOLUME_IN_MIXER (1) +#else + #define OUT_VOLUME_IN_MIXER (0) +#endif #endif /* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */ From 41566b397006eb33968a82b28beac9b0dafbb246 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 26 Jan 2024 15:02:28 +0000 Subject: [PATCH 29/30] Further re-apply #341 --- lib_xua/api/xua_conf_default.h | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 4fb5c2a3..e4884fa4 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -1403,7 +1403,7 @@ enum USBEndpointNumber_Out /* Some defines that allow us to remove unused code */ /* Useful for dropping lower part of macs in volume processing... */ -#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \ +#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || \ (((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \ (((FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 2)) #define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1 @@ -1437,29 +1437,29 @@ enum USBEndpointNumber_Out #endif /* Useful for dropping lower part of macs in volume processing... */ - #if (FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) || (FS_STREAM_FORMAT_INPUT_2_RESOLUTION_BITS > 24) - #define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 1 - #else - #define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 0 - #endif +#if (FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) + #define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 1 +#else + #define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 0 +#endif - #if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4)) - #define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 1 - #else - #define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 0 - #endif +#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4)) + #define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 1 +#else + #define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 0 +#endif - #if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3)) - #define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 1 - #else - #define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 0 - #endif +#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3)) + #define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 1 +#else + #define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 0 +#endif - #if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2)) - #define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 1 - #else - #define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 0 - #endif +#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2)) + #define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 1 +#else + #define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 0 +#endif #if MAX_FREQ < MIN_FREQ #error MAX_FREQ should be >= MIN_FREQ!! From cffb7a272da9e69a189a101ba83957ddaa2dbc45 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 26 Jan 2024 15:04:52 +0000 Subject: [PATCH 30/30] Re-apply typo fix --- lib_xua/api/xua_conf_default.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index e4884fa4..c7a9ef44 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -1202,7 +1202,7 @@ #define IN_VOLUME_IN_MIXER (0) #endif -/* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */ +/* Apply in volume controls after the mix. Only relevant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */ #ifndef IN_VOLUME_AFTER_MIX #define IN_VOLUME_AFTER_MIX (1) #endif