Compare commits
94 Commits
develop
...
v4.0.0/max
| Author | SHA1 | Date | |
|---|---|---|---|
| f9c393b5f0 | |||
|
|
4589319151 | ||
|
|
e789da24d3 | ||
|
|
7ffeaf3dde | ||
|
|
9ba6425d83 | ||
|
|
8f63590956 | ||
|
|
6235c168a1 | ||
|
|
f3a0dbc79f | ||
|
|
68a1a793cc | ||
|
|
0fc8aec495 | ||
|
|
4e893d4565 | ||
|
|
c11e62e27f | ||
|
|
57d5ea7613 | ||
|
|
03a646f95d | ||
|
|
05c8c44619 | ||
|
|
0d913cdce3 | ||
|
|
165417962f | ||
|
|
cffb7a272d | ||
|
|
41566b3970 | ||
|
|
7847a5ee42 | ||
|
|
8ec5f8c7fc | ||
|
|
4d3fe82113 | ||
|
|
5980d0edea | ||
|
|
e72a386fa2 | ||
|
|
0d1f81276d | ||
|
|
7febbfdcd0 | ||
|
|
44049ecfca | ||
|
|
d49c6b4656 | ||
|
|
3be17bf8cc | ||
|
|
e8317eae36 | ||
|
|
5669a5b021 | ||
|
|
fc708fe4e9 | ||
|
|
f32955a419 | ||
|
|
a9ed38252c | ||
|
|
27a7d185d1 | ||
|
|
7126b91848 | ||
|
|
cb84d69231 | ||
|
|
8b58fe5aaa | ||
|
|
fe6afc93de | ||
|
|
eb4b19ce16 | ||
|
|
3d9d174dcc | ||
|
|
f0709d35fc | ||
|
|
4edf86b3a6 | ||
|
|
de0279d769 | ||
|
|
a12111ba55 | ||
|
|
1b6a785b03 | ||
|
|
2d1585b8b1 | ||
|
|
eb6ed9f56e | ||
|
|
af9a6b18b2 | ||
|
|
ca16467158 | ||
|
|
aac2b4b7fb | ||
|
|
c0a844c303 | ||
|
|
103aa8840b | ||
|
|
a4e6fd0194 | ||
|
|
57debd0558 | ||
|
|
de6210d1dd | ||
|
|
ce987622d9 | ||
|
|
e04ecf5fc9 | ||
|
|
d81b510102 | ||
|
|
8ef63fcdf5 | ||
|
|
529aea28dc | ||
|
|
edbadca0cd | ||
|
|
13d9229f52 | ||
|
|
a0610fc1e0 | ||
|
|
334f36e5e1 | ||
|
|
c412c81fe3 | ||
|
|
9abfa167ca | ||
|
|
c6a970d7c0 | ||
|
|
3291a05493 | ||
|
|
91d23fb1d6 | ||
|
|
2fcc9ca2ac | ||
|
|
6d8d66f823 | ||
|
|
23f1a8d48e | ||
|
|
e6899afbb9 | ||
|
|
87a105d8f6 | ||
|
|
3003ce7241 | ||
|
|
ccaaf40ab3 | ||
|
|
dc81964f22 | ||
|
|
a3419fdba7 | ||
|
|
4962cebc9c | ||
|
|
56d728f349 | ||
|
|
7f8f07b4b6 | ||
|
|
8e161707a5 | ||
|
|
b242c54574 | ||
|
|
702e8d14b9 | ||
|
|
ace59f63a4 | ||
|
|
780a407519 | ||
|
|
61f17f3fe9 | ||
|
|
d644775e4c | ||
|
|
2133598347 | ||
|
|
7b843b1d56 | ||
|
|
f035e1dc13 | ||
|
|
c5496ea994 | ||
|
|
b0db22a50b |
@@ -1,16 +1,43 @@
|
||||
lib_xua Change Log
|
||||
==================
|
||||
|
||||
HEAD
|
||||
----
|
||||
UNRELEASED
|
||||
----------
|
||||
|
||||
* FIXED: Device fails to enumerate when ADAT and S/PDIF transmit are enabled
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* ADDED: Support for XCommon CMake build system
|
||||
* RESOLVED: Output volume control not enabled by default when MIXER disabled
|
||||
* RESOLVED: Full 32bit result of volume processing not calculated when required
|
||||
* RESOLVED: Input stream sending an erroneous zero-length packet when exiting underflow state
|
||||
* RESOLVED Build failures when XUA_USB_EN = 0
|
||||
* RESOLVED: Clock configuration issues when ADAT and S/PDIF receive are enabled (#352)
|
||||
* FIXED: Output volume control not enabled by default when MIXER disabled
|
||||
* FIXED: Full 32bit result of volume processing not calculated when
|
||||
required
|
||||
* FIXED: Input stream sending an erroneous zero-length packet when exiting
|
||||
underflow state
|
||||
* FIXED Build failures when XUA_USB_EN = 0
|
||||
* FIXED: Clock configuration issues when ADAT and S/PDIF receive are
|
||||
enabled (#352)
|
||||
* FIXED: Repeated old S/PDIF and ADAT samples when entering underflow
|
||||
state
|
||||
* 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 and synchronous USB audio by default
|
||||
* CHANGED: Windows host mixer control application now requires driver GUID
|
||||
option
|
||||
|
||||
* Changes to dependencies:
|
||||
|
||||
- lib_dsp: 6.2.1 -> 6.3.0
|
||||
|
||||
- lib_mic_array: 4.5.0 -> 4.6.0
|
||||
|
||||
- lib_spdif: 5.0.1 -> 6.1.0
|
||||
|
||||
- lib_sw_pll: Added dependency 2.1.0
|
||||
|
||||
- lib_xud: 2.2.3 -> 2.3.1
|
||||
|
||||
3.5.1
|
||||
-----
|
||||
|
||||
3
Jenkinsfile
vendored
3
Jenkinsfile
vendored
@@ -49,7 +49,8 @@ pipeline {
|
||||
withVenv {
|
||||
runWaf('.', "configure clean build --target=xcore200")
|
||||
viewEnv() {
|
||||
runPython("TARGET=XCORE200 pytest -s")
|
||||
runPython("TARGET=XCORE200 pytest -s --junitxml=pytest_unity.xml")
|
||||
junit "pytest_unity.xml"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
lib_xua
|
||||
#######
|
||||
|
||||
:Version: 3.5.1
|
||||
:Version: 4.0.0
|
||||
:Vendor: XMOS
|
||||
|
||||
|
||||
:Scope: General Use
|
||||
|
||||
Summary
|
||||
@@ -83,14 +82,15 @@ The following application notes use this library:
|
||||
Required Software (dependencies)
|
||||
================================
|
||||
|
||||
* lib_adat (www.github.com/xmos/lib_adat)
|
||||
* lib_locks (www.github.com/xmos/lib_locks)
|
||||
* lib_logging (www.github.com/xmos/lib_logging)
|
||||
* lib_mic_array (www.github.com/xmos/lib_mic_array)
|
||||
* lib_xassert (www.github.com/xmos/lib_xassert)
|
||||
* lib_dsp (www.github.com/xmos/lib_dsp)
|
||||
* lib_spdif (www.github.com/xmos/lib_spdif)
|
||||
* lib_sw_pll (www.github.com/xmos/lib_sw_pll)
|
||||
* lib_xud (www.github.com/xmos/lib_xud)
|
||||
* lib_adat (www.github.com/xmos/lib_adat)
|
||||
|
||||
Documentation
|
||||
=============
|
||||
@@ -101,4 +101,3 @@ Support
|
||||
=======
|
||||
|
||||
This package is supported by XMOS Ltd. Issues can be raised against the software at: http://www.xmos.com/support
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <xs1.h>
|
||||
#include <platform.h>
|
||||
#include "xua.h"
|
||||
#include "../../shared/apppll.h"
|
||||
extern "C"{
|
||||
#include "sw_pll.h"
|
||||
}
|
||||
|
||||
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
||||
|
||||
@@ -38,19 +40,26 @@ void AudioHwInit()
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
||||
AppPllEnable_SampleRate(DEFAULT_FREQ);
|
||||
if(DEFAULT_FREQ % 22050 == 0)
|
||||
{
|
||||
sw_pll_fixed_clock(MCLK_441);
|
||||
}
|
||||
else
|
||||
{
|
||||
sw_pll_fixed_clock(MCLK_48);
|
||||
}
|
||||
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
|
||||
* It holds DAC in reset until it gets clocks anyway.
|
||||
* Note, this example doesn't use the ADC's
|
||||
* Note, this example doesn't use the ADCs
|
||||
*/
|
||||
}
|
||||
|
||||
/* Configures the external audio hardware for the required sample frequency */
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
{
|
||||
AppPllEnable_SampleRate(samFreq);
|
||||
sw_pll_fixed_clock(mClk);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <xs1.h>
|
||||
#include <platform.h>
|
||||
#include "xua.h"
|
||||
#include "../../shared/apppll.h"
|
||||
#include "xassert.h"
|
||||
extern "C"{
|
||||
#include "sw_pll.h"
|
||||
}
|
||||
|
||||
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
||||
|
||||
@@ -38,19 +41,26 @@ void AudioHwInit()
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
||||
AppPllEnable_SampleRate(DEFAULT_FREQ);
|
||||
if(DEFAULT_FREQ % 22050 == 0)
|
||||
{
|
||||
sw_pll_fixed_clock(MCLK_441);
|
||||
}
|
||||
else
|
||||
{
|
||||
sw_pll_fixed_clock(MCLK_48);
|
||||
}
|
||||
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
|
||||
* It holds DAC in reset until it gets clocks anyway.
|
||||
* Note, this example doesn't use the ADC's
|
||||
* Note, this example doesn't use the ADCs
|
||||
*/
|
||||
}
|
||||
|
||||
/* Configures the external audio hardware for the required sample frequency */
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
{
|
||||
AppPllEnable_SampleRate(samFreq);
|
||||
sw_pll_fixed_clock(mClk);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
// Copyright 2022 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <stdint.h>
|
||||
#include "xassert.h"
|
||||
|
||||
// App PLL setup
|
||||
#define APP_PLL_CTL_BYPASS (0) // 0 = no bypass, 1 = bypass.
|
||||
#define APP_PLL_CTL_INPUT_SEL (0) // 0 = XTAL, 1 = sysPLL
|
||||
#define APP_PLL_CTL_ENABLE (1) // 0 = disabled, 1 = enabled.
|
||||
|
||||
// 24MHz in, 24.576MHz out, integer mode
|
||||
// Found exact solution: IN 24000000.0, OUT 24576000.0, VCO 2457600000.0, RD 5, FD 512, OD 10, FOD 10
|
||||
#define APP_PLL_CTL_OD_48 (4) // Output divider = (OD+1)
|
||||
#define APP_PLL_CTL_F_48 (511) // FB divider = (F+1)/2
|
||||
#define APP_PLL_CTL_R_48 (4) // Ref divider = (R+1)
|
||||
|
||||
#define APP_PLL_CTL_48 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
|
||||
(APP_PLL_CTL_OD_48 << 23) | (APP_PLL_CTL_F_48 << 8) | APP_PLL_CTL_R_48)
|
||||
|
||||
// Fractional divide is M/N
|
||||
#define APP_PLL_FRAC_EN_48 (0) // 0 = disabled
|
||||
#define APP_PLL_FRAC_NPLUS1_CYCLES_48 (0) // M value is this reg value + 1.
|
||||
#define APP_PLL_FRAC_TOTAL_CYCLES_48 (0) // N value is this reg value + 1.
|
||||
#define APP_PLL_FRAC_48 ((APP_PLL_FRAC_EN_48 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_48 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_48)
|
||||
|
||||
// 24MHz in, 22.5792MHz out (44.1kHz * 512), frac mode
|
||||
// Found exact solution: IN 24000000.0, OUT 22579200.0, VCO 2257920000.0, RD 5, FD 470.400 (m = 2, n = 5), OD 5, FOD 10
|
||||
#define APP_PLL_CTL_OD_441 (4) // Output divider = (OD+1)
|
||||
#define APP_PLL_CTL_F_441 (469) // FB divider = (F+1)/2
|
||||
#define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
|
||||
|
||||
#define APP_PLL_CTL_441 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
|
||||
(APP_PLL_CTL_OD_441 << 23) | (APP_PLL_CTL_F_441 << 8) | APP_PLL_CTL_R_441)
|
||||
|
||||
#define APP_PLL_FRAC_EN_44 (1) // 1 = enabled
|
||||
#define APP_PLL_FRAC_NPLUS1_CYCLES_44 (1) // M value is this reg value + 1.
|
||||
#define APP_PLL_FRAC_TOTAL_CYCLES_44 (4) // N value is this reg value + 1.define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
|
||||
#define APP_PLL_FRAC_44 ((APP_PLL_FRAC_EN_44 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_44 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_44)
|
||||
|
||||
#define APP_PLL_DIV_INPUT_SEL (1) // 0 = sysPLL, 1 = app_PLL
|
||||
#define APP_PLL_DIV_DISABLE (0) // 1 = disabled (pin connected to X1D11), 0 = enabled divider output to pin.
|
||||
#define APP_PLL_DIV_VALUE (4) // Divide by N+1 - remember there's a /2 also afterwards for 50/50 duty cycle.
|
||||
#define APP_PLL_DIV ((APP_PLL_DIV_INPUT_SEL << 31) | (APP_PLL_DIV_DISABLE << 16) | APP_PLL_DIV_VALUE)
|
||||
|
||||
/* TODO support more than two freqs..*/
|
||||
void AppPllEnable(int32_t clkFreq_hz)
|
||||
{
|
||||
switch(clkFreq_hz)
|
||||
{
|
||||
case 44100*512:
|
||||
|
||||
// Disable the PLL
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
|
||||
// Enable the PLL to invoke a reset on the appPLL.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
||||
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
||||
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
||||
|
||||
// Set the fractional divider if used
|
||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_44);
|
||||
|
||||
break;
|
||||
|
||||
case 48000*512:
|
||||
|
||||
// Disable the PLL
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
|
||||
// Enable the PLL to invoke a reset on the appPLL.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
||||
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
||||
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
||||
|
||||
// Set the fractional divider if used
|
||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_48);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for PLL output frequency to stabilise due to fractional divider enable
|
||||
delay_microseconds(100);
|
||||
|
||||
// Turn on the clock output
|
||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, APP_PLL_DIV);
|
||||
}
|
||||
|
||||
void AppPllEnable_SampleRate(int32_t sampleRate_hz)
|
||||
{
|
||||
assert(sampleRate_hz >= 22050);
|
||||
|
||||
if(sampleRate_hz % 22050 == 0)
|
||||
{
|
||||
AppPllEnable(44100*512);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppPllEnable(48000*512);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// Copyright 2022-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -14,10 +14,20 @@
|
||||
// TODO
|
||||
// res, min, max
|
||||
|
||||
#ifdef _WIN32
|
||||
int mixer_init(TCHAR guid[GUID_STR_LEN])
|
||||
#else
|
||||
int mixer_init(void)
|
||||
#endif
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int ret = usb_mixer_connect(guid);
|
||||
#else
|
||||
int ret = usb_mixer_connect();
|
||||
#endif
|
||||
|
||||
/* Open the connection to the USB mixer */
|
||||
if (usb_mixer_connect() == USB_MIXER_FAILURE)
|
||||
if (ret == USB_MIXER_FAILURE)
|
||||
{
|
||||
return USB_MIXER_FAILURE;
|
||||
}
|
||||
@@ -381,8 +391,15 @@ void print_levels(const char* levelTitle, unsigned char* levels, int levelBytes)
|
||||
|
||||
|
||||
void mixer_display_usage(void) {
|
||||
fprintf(stderr, "Usage :\n");
|
||||
fprintf(stderr,
|
||||
fprintf(stderr, "Usage: xmos_mixer "
|
||||
#ifdef _WIN32
|
||||
"-g<GUID> "
|
||||
#endif
|
||||
"<options>\n");
|
||||
fprintf(stderr,
|
||||
#ifdef _WIN32
|
||||
" -g<GUID> Driver GUID string, eg. -g{E5A2658B-817D-4A02-A1DE-B628A93DDF5D}\n"
|
||||
#endif
|
||||
" --display-info\n"
|
||||
" --display-mixer-nodes mixer_id\n"
|
||||
" --display-min mixer_id\n"
|
||||
@@ -421,97 +438,124 @@ int main (int argc, char **argv) {
|
||||
unsigned int mixer_index = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
int min_argc;
|
||||
// arg_idx is the position in the arguments to start parsing to skip the "-g" GUID option on Windows
|
||||
int arg_idx;
|
||||
#ifdef _WIN32
|
||||
// Driver GUID string is required on Windows
|
||||
min_argc = 3;
|
||||
arg_idx = 2;
|
||||
#else
|
||||
min_argc = 2;
|
||||
arg_idx = 1;
|
||||
#endif
|
||||
|
||||
|
||||
if (argc < 2) {
|
||||
if (argc < min_argc) {
|
||||
fprintf(stderr, "ERROR :: No options passed to mixer application\n");
|
||||
mixer_display_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
TCHAR driver_guid[GUID_STR_LEN];
|
||||
|
||||
if (strncmp(argv[1], "-g", 2) == 0) {
|
||||
swprintf(driver_guid, GUID_STR_LEN, L"%hs", argv[1]+2);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: First option must be driver GUID\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strcmp(argv[1], "--help") == 0) {
|
||||
mixer_display_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mixer_init() != USB_MIXER_SUCCESS) {
|
||||
#ifdef _WIN32
|
||||
int ret = mixer_init(driver_guid);
|
||||
#else
|
||||
int ret = mixer_init();
|
||||
#endif
|
||||
|
||||
if (ret != USB_MIXER_SUCCESS) {
|
||||
fprintf(stderr, "ERROR :: Cannot connect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--display-info") == 0)
|
||||
if (strcmp(argv[arg_idx], "--display-info") == 0)
|
||||
{
|
||||
mixer_display_info();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-mixer-nodes") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--display-mixer-nodes") == 0)
|
||||
{
|
||||
if (argv[2])
|
||||
if (argv[arg_idx+1])
|
||||
{
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_index = atoi(argv[arg_idx+1]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||
} else if (strcmp(argv[1], "--display-mixer-nodes") == 0) {
|
||||
} else if (strcmp(argv[arg_idx], "--display-mixer-nodes") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_index = atoi(argv[arg_idx+1]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||
} else if (strcmp(argv[1], "--display-min") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else if (strcmp(argv[arg_idx], "--display-min") == 0) {
|
||||
if (argv[arg_idx+1]) {
|
||||
mixer_index = atoi(argv[arg_idx+1]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MIN);
|
||||
} else if (strcmp(argv[1], "--display-max") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else if (strcmp(argv[arg_idx], "--display-max") == 0) {
|
||||
if (argv[arg_idx+1]) {
|
||||
mixer_index = atoi(argv[arg_idx+1]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MAX);
|
||||
} else if (strcmp(argv[1], "--display-res") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else if (strcmp(argv[arg_idx], "--display-res") == 0) {
|
||||
if (argv[arg_idx+1]) {
|
||||
mixer_index = atoi(argv[arg_idx+1]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_RES);
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-value") == 0) {
|
||||
else if (strcmp(argv[arg_idx], "--set-value") == 0) {
|
||||
unsigned int mixer_unit = 0;
|
||||
double value = 0;
|
||||
if (argc < 5) {
|
||||
if (argc - arg_idx < 4) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_unit = atoi(argv[3]);
|
||||
if (strcmp(argv[4],"-inf")==0)
|
||||
mixer_index = atoi(argv[arg_idx+1]);
|
||||
mixer_unit = atoi(argv[arg_idx+2]);
|
||||
if (strcmp(argv[arg_idx+3],"-inf")==0)
|
||||
value = -128;
|
||||
else
|
||||
value = atof(argv[4]);
|
||||
value = atof(argv[arg_idx+3]);
|
||||
|
||||
usb_mixer_set_value(mixer_index, mixer_unit, value);
|
||||
} else if (strcmp(argv[1], "--get-value") == 0) {
|
||||
} else if (strcmp(argv[arg_idx], "--get-value") == 0) {
|
||||
unsigned int mixer_unit = 0;
|
||||
double result = 0;
|
||||
if (argc < 4) {
|
||||
if (argc - arg_idx < 3) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_unit = atoi(argv[3]);
|
||||
mixer_index = atoi(argv[arg_idx+1]);
|
||||
mixer_unit = atoi(argv[arg_idx+2]);
|
||||
|
||||
result = usb_mixer_get_value(mixer_index, mixer_unit);
|
||||
if (result <= -127.996)
|
||||
@@ -519,99 +563,99 @@ int main (int argc, char **argv) {
|
||||
else
|
||||
printf("%g\n",result);
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-current-mixer-sources") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--display-current-mixer-sources") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
if(argc - arg_idx < 2)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
display_mixer_sources(atoi(argv[2]));
|
||||
display_mixer_sources(atoi(argv[arg_idx+1]));
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-available-mixer-sources") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--display-available-mixer-sources") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
if(argc - arg_idx < 2)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
display_available_mixer_sources(atoi(argv[2]));
|
||||
display_available_mixer_sources(atoi(argv[arg_idx+1]));
|
||||
}
|
||||
else if(strcmp(argv[1], "--set-mixer-source") == 0)
|
||||
else if(strcmp(argv[arg_idx], "--set-mixer-source") == 0)
|
||||
{
|
||||
if(argc < 5)
|
||||
if(argc - arg_idx < 4)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
set_mixer_source(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
|
||||
set_mixer_source(atoi(argv[arg_idx+1]), atoi(argv[arg_idx+2]), atoi(argv[arg_idx+3]));
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-aud-channel-map") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--display-aud-channel-map") == 0)
|
||||
{
|
||||
/* Display the channel mapping to the devices audio outputs */
|
||||
display_aud_channel_map();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-aud-channel-map-sources") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--display-aud-channel-map-sources") == 0)
|
||||
{
|
||||
display_aud_channel_map_sources();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-daw-channel-map") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--display-daw-channel-map") == 0)
|
||||
{
|
||||
/* Display the channel mapping to the devices DAW output to host */
|
||||
display_daw_channel_map();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-daw-channel-map-sources") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--display-daw-channel-map-sources") == 0)
|
||||
{
|
||||
display_daw_channel_map_sources();
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-aud-channel-map") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--set-aud-channel-map") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned int src = 0;
|
||||
if (argc != 4)
|
||||
if (argc - arg_idx != 3)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
dst = atoi(argv[2]);
|
||||
src = atoi(argv[3]);
|
||||
dst = atoi(argv[arg_idx+1]);
|
||||
src = atoi(argv[arg_idx+2]);
|
||||
|
||||
usb_set_aud_channel_map(dst, src);
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-daw-channel-map") == 0)
|
||||
else if (strcmp(argv[arg_idx], "--set-daw-channel-map") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned int src = 0;
|
||||
if (argc != 4)
|
||||
if (argc - arg_idx != 3)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
dst = atoi(argv[2]);
|
||||
src = atoi(argv[3]);
|
||||
dst = atoi(argv[arg_idx+1]);
|
||||
src = atoi(argv[arg_idx+2]);
|
||||
|
||||
usb_set_usb_channel_map(dst, src);
|
||||
}
|
||||
else if(strcmp(argv[1], "--get-mixer-levels-input") == 0 ||
|
||||
strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
||||
else if(strcmp(argv[arg_idx], "--get-mixer-levels-input") == 0 ||
|
||||
strcmp(argv[arg_idx],"--get-mixer-levels-output") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned char levels[64];
|
||||
int datalength = 0;
|
||||
int offset = 0;
|
||||
|
||||
if (argc < 3) {
|
||||
if (argc - arg_idx < 2) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
||||
if(strcmp(argv[arg_idx],"--get-mixer-levels-output") == 0)
|
||||
offset = 1;
|
||||
|
||||
for(int i = 0; i < 64; i++)
|
||||
levels[i] = 0;
|
||||
|
||||
dst = atoi(argv[2]);
|
||||
dst = atoi(argv[arg_idx+1]);
|
||||
|
||||
/* Mem request to mixer with offset of 0 gives input levels */
|
||||
datalength = usb_mixer_mem_get(dst, offset, levels);
|
||||
@@ -628,7 +672,7 @@ int main (int argc, char **argv) {
|
||||
print_levels("Mixer Input", levels, datalength);
|
||||
|
||||
}
|
||||
else if(strcmp(argv[1], "--vendor-audio-request-get") == 0)
|
||||
else if(strcmp(argv[arg_idx], "--vendor-audio-request-get") == 0)
|
||||
{
|
||||
unsigned int bRequest = 0;
|
||||
unsigned int cs = 0;
|
||||
@@ -637,7 +681,7 @@ int main (int argc, char **argv) {
|
||||
int datalength = 0;
|
||||
unsigned char data[64];
|
||||
|
||||
if(argc < 6)
|
||||
if(argc - arg_idx < 5)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
@@ -646,10 +690,10 @@ int main (int argc, char **argv) {
|
||||
for(int i = 0; i < 64; i++)
|
||||
data[i] = 0;
|
||||
|
||||
bRequest = atoi(argv[2]);
|
||||
cs = atoi(argv[3]);
|
||||
cn = atoi(argv[4]);
|
||||
unitId = atoi(argv[5]);
|
||||
bRequest = atoi(argv[arg_idx+1]);
|
||||
cs = atoi(argv[arg_idx+2]);
|
||||
cn = atoi(argv[arg_idx+3]);
|
||||
unitId = atoi(argv[arg_idx+4]);
|
||||
|
||||
/* Do request */
|
||||
datalength = usb_audio_request_get(bRequest, cs, cn, unitId, data);
|
||||
@@ -666,7 +710,7 @@ int main (int argc, char **argv) {
|
||||
printf("0x%02x\n" ,data[i]);
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1], "--vendor-audio-request-set") == 0)
|
||||
else if(strcmp(argv[arg_idx], "--vendor-audio-request-set") == 0)
|
||||
{
|
||||
|
||||
unsigned int bRequest = 0;
|
||||
@@ -680,23 +724,23 @@ int main (int argc, char **argv) {
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
if(argc < 7)
|
||||
if(argc - arg_idx < 6)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed - no data passed\n");
|
||||
return -1;
|
||||
}
|
||||
bRequest = atoi(argv[2]);
|
||||
cs = atoi(argv[3]);
|
||||
cn = atoi(argv[4]);
|
||||
unitId = atoi(argv[5]);
|
||||
bRequest = atoi(argv[arg_idx+1]);
|
||||
cs = atoi(argv[arg_idx+2]);
|
||||
cn = atoi(argv[arg_idx+3]);
|
||||
unitId = atoi(argv[arg_idx+4]);
|
||||
|
||||
/* Get data */
|
||||
for(int i=0; i < argc-6; i++)
|
||||
for(int i=0; i < argc-arg_idx-5; i++)
|
||||
{
|
||||
data[i] = atoi(argv[i+6]);
|
||||
data[i] = atoi(argv[i+arg_idx+5]);
|
||||
}
|
||||
|
||||
result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-6);
|
||||
result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-arg_idx-5);
|
||||
|
||||
if(result < 0)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// Copyright 2022-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -800,14 +800,18 @@ static int find_xmos_device(unsigned int id)
|
||||
|
||||
// End of libusb interface functions
|
||||
|
||||
int usb_mixer_connect()
|
||||
#ifdef _WIN32
|
||||
int usb_mixer_connect(TCHAR guid[GUID_STR_LEN])
|
||||
#else
|
||||
int usb_mixer_connect()
|
||||
#endif
|
||||
{
|
||||
// Allocate internal storage
|
||||
usb_mixers = (usb_mixer_handle *)malloc(sizeof(usb_mixer_handle));
|
||||
memset(usb_mixers, 0, sizeof(usb_mixer_handle));
|
||||
|
||||
#if defined(_WIN32)
|
||||
gDrvApi.LoadByGUID(_T("{E5A2658B-817D-4A02-A1DE-B628A93DDF5D}"));
|
||||
gDrvApi.LoadByGUID(guid);
|
||||
TUsbAudioStatus st = gDrvApi.TUSBAUDIO_EnumerateDevices();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// Copyright 2022-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define USB_MIXER_SUCCESS 0
|
||||
@@ -22,7 +22,14 @@ enum usb_chan_type {
|
||||
#define RANGE (2)
|
||||
#define MEM (3)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <tchar.h>
|
||||
// GUID strings are 36 characters, plus a pair of braces and NUL-termination
|
||||
#define GUID_STR_LEN (36+2+1)
|
||||
int usb_mixer_connect(TCHAR guid[GUID_STR_LEN]);
|
||||
#else
|
||||
int usb_mixer_connect();
|
||||
#endif
|
||||
int usb_mixer_disconnect();
|
||||
|
||||
/* MIXER UNIT(s) INTERFACE */
|
||||
|
||||
9
lib_xua/README.md
Normal file
9
lib_xua/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# lib_xua
|
||||
|
||||
- 版本:3.5.1
|
||||
- 私有版本维护:Vergil Wong
|
||||
|
||||
## 主要改动
|
||||
|
||||
- 添加了`I2S_TDM_LRCLK_EDGES`,以适配AK4438VN的TDM时序,参考[修改时序以配置TDM](https://docs.pawpaw.cn/docs/applications/USB-Audio-Interface/Advanced-Guide/app-note/dac-timing-config/)
|
||||
- 添加了`AUDIO_UNSAFE_RESRC`,以将`unsafe`资源的赋值,合并到Audio线程中,以避免编译器检查(额外占用核心)
|
||||
@@ -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.
|
||||
#ifndef _XUA_AUDIOHUB_H_
|
||||
#define _XUA_AUDIOHUB_H_
|
||||
@@ -12,32 +12,42 @@
|
||||
#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
|
||||
* 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 c_spdif_tx Channel connected to S/PDIF transmiter core from lib_spdif
|
||||
* \param i_SoftPll Interface to software PLL task
|
||||
*
|
||||
* \param c_dig Channel connected to the clockGen() thread for
|
||||
* receiving/transmitting samples
|
||||
* \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_audio_rate_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,
|
||||
@@ -53,10 +63,13 @@ void XUA_AudioHub(chanend ?c_aud,
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__))
|
||||
, chanend c_dig
|
||||
#endif
|
||||
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__))
|
||||
, 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
|
||||
#endif
|
||||
#if (XUA_NUM_PDM_MICS > 0)
|
||||
#if (XUA_NUM_PDM_MICS > 0 || defined(__DOXYGEN__))
|
||||
, chanend c_pdm_in
|
||||
#endif
|
||||
);
|
||||
@@ -76,8 +89,29 @@ void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode,
|
||||
|
||||
#endif // __XC__
|
||||
|
||||
void UserBufferManagementInit();
|
||||
|
||||
/**
|
||||
* @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_
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -13,19 +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_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,
|
||||
@@ -38,7 +40,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 +53,14 @@ 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__)
|
||||
, chanend c_audio_rate_change
|
||||
#if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#if (XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||
, chanend c_swpll_update
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
|
||||
@@ -66,7 +74,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 +89,17 @@ 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__)
|
||||
, chanend c_audio_rate_change
|
||||
#if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#if (XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||
, chanend c_swpll_update
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
/** Manage the data transfer between the USB audio buffer and the
|
||||
* Audio I/O driver.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// 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 _CLOCKING_H_
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <xs1.h>
|
||||
|
||||
#include "sw_pll_wrapper.h"
|
||||
|
||||
interface pll_ref_if
|
||||
{
|
||||
void toggle();
|
||||
@@ -18,15 +20,31 @@ 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_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
|
||||
*
|
||||
*/
|
||||
void clockGen(streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interface pll_ref_if i_pll_ref, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int);
|
||||
void clockGen( streaming chanend ?c_spdif_rx,
|
||||
chanend ?c_adat_rx,
|
||||
client interface pll_ref_if i_pll_ref,
|
||||
chanend c_audio,
|
||||
chanend c_clk_ctl,
|
||||
chanend c_clk_int,
|
||||
chanend c_audio_rate_change
|
||||
#if XUA_USE_SW_PLL
|
||||
, port p_for_mclk_count_aud
|
||||
, chanend c_sw_pll
|
||||
#endif
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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,29 @@
|
||||
#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 and recovering master-clocks.
|
||||
* Only available on xcore.ai devices.
|
||||
*
|
||||
* Default: Enabled (for xcore.ai devices)
|
||||
*/
|
||||
#ifndef XUA_USE_SW_PLL
|
||||
#if defined(__XS3A__)
|
||||
#define XUA_USE_SW_PLL (1)
|
||||
#else
|
||||
#define XUA_USE_SW_PLL (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default device sample frequency. A safe default should be used.
|
||||
*
|
||||
@@ -249,10 +287,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 +314,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 +331,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 +348,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 +372,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 +400,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 +409,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 +425,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 +494,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 +507,7 @@
|
||||
* Default 0 (Disabled)
|
||||
*/
|
||||
#ifndef HID_CONTROLS
|
||||
#define HID_CONTROLS (0)
|
||||
#define HID_CONTROLS (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -488,12 +523,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 +540,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 +549,7 @@
|
||||
* Default: ""
|
||||
*/
|
||||
#ifndef SERIAL_STR
|
||||
#define SERIAL_STR ""
|
||||
#define SERIAL_STR ""
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -535,7 +558,7 @@
|
||||
* Default: "XMOS"
|
||||
*/
|
||||
#ifndef VENDOR_STR
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_STR "XMOS"
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -544,7 +567,7 @@
|
||||
* Default: 0x20B1 (XMOS)
|
||||
*/
|
||||
#ifndef VENDOR_ID
|
||||
#define VENDOR_ID (0x20B1)
|
||||
#define VENDOR_ID (0x20B1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -586,7 +609,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 +619,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 +1044,7 @@
|
||||
* Default: 1 (Enabled)
|
||||
*/
|
||||
#ifndef OUTPUT_VOLUME_CONTROL
|
||||
#define OUTPUT_VOLUME_CONTROL (1)
|
||||
#define OUTPUT_VOLUME_CONTROL (1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -1030,7 +1053,7 @@
|
||||
* Default: 1 (Enabled)
|
||||
*/
|
||||
#ifndef INPUT_VOLUME_CONTROL
|
||||
#define INPUT_VOLUME_CONTROL (1)
|
||||
#define INPUT_VOLUME_CONTROL (1)
|
||||
#endif
|
||||
|
||||
/* Power */
|
||||
@@ -1072,7 +1095,7 @@
|
||||
* Default: 0 (Disabled)
|
||||
*/
|
||||
#ifndef MIXER
|
||||
#define MIXER (0)
|
||||
#define MIXER (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -1082,11 +1105,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 +1121,7 @@
|
||||
* Default: 18
|
||||
*/
|
||||
#ifndef MIX_INPUTS
|
||||
#define MIX_INPUTS (18)
|
||||
#define MIX_INPUTS (18)
|
||||
#endif
|
||||
|
||||
/* Volume processing defines */
|
||||
@@ -1110,7 +1133,7 @@
|
||||
* Default: 0x8100 (-127db)
|
||||
*/
|
||||
#ifndef MIN_VOLUME
|
||||
#define MIN_VOLUME (0x8100)
|
||||
#define MIN_VOLUME (0x8100)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1120,7 +1143,7 @@
|
||||
* Default: 0x0000 (0db)
|
||||
*/
|
||||
#ifndef MAX_VOLUME
|
||||
#define MAX_VOLUME (0x0000)
|
||||
#define MAX_VOLUME (0x0000)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -1129,7 +1152,7 @@
|
||||
* Default: 0x100 (1db)
|
||||
*/
|
||||
#ifndef VOLUME_RES
|
||||
#define VOLUME_RES (0x100)
|
||||
#define VOLUME_RES (0x100)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -1139,7 +1162,7 @@
|
||||
* Default: 0x8100 (-127db)
|
||||
*/
|
||||
#ifndef MIN_MIXER_VOLUME
|
||||
#define MIN_MIXER_VOLUME (0x8100)
|
||||
#define MIN_MIXER_VOLUME (0x8100)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -1148,7 +1171,7 @@
|
||||
* Default: 0x0000 (0db)
|
||||
*/
|
||||
#ifndef MAX_MIXER_VOLUME
|
||||
#define MAX_MIXER_VOLUME (0x0000)
|
||||
#define MAX_MIXER_VOLUME (0x0000)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -1157,36 +1180,36 @@
|
||||
* 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)
|
||||
#define OUT_VOLUME_IN_MIXER (1)
|
||||
#else
|
||||
#define OUT_VOLUME_IN_MIXER (0)
|
||||
#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 */
|
||||
#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 */
|
||||
#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 +1217,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 +1299,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)
|
||||
|
||||
@@ -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:: XUA_USE_SW_PLL
|
||||
|
||||
Audio Class
|
||||
-----------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -54,7 +54,9 @@ In addition :ref:`usb_audio_optional_components` shows optional components that
|
||||
* - Clockgen
|
||||
- Drives an external frequency generator (PLL) and manages
|
||||
changes between internal clocks and external clocks arising
|
||||
from digital input.
|
||||
from digital input. On xcore.ai Clockgen may also work in
|
||||
conjunction with lib_sw_pll to produce a local clock from
|
||||
the XCORE which is locked to the incoming digital stream.
|
||||
* - MIDI
|
||||
- Outputs and inputs MIDI over a serial UART interface.
|
||||
|
||||
|
||||
@@ -29,10 +29,11 @@ The S/PDIF receiver should be called on the appropriate tile::
|
||||
With the steps above an S/PDIF stream can be captured by the xCORE. To be functionally useful the audio
|
||||
master clock must be able to synchronise to this external digital stream. Additionally, the host can be
|
||||
notified regarding changes in the validity of this stream, it's frequency etc. To synchronise to external
|
||||
streams the codebase assumes the use of an external Cirrus Logic CS2100 device.
|
||||
streams the codebase assumes the use of an external Cirrus Logic CS2100 device or lib_sw_pll on xcore.ai designs.
|
||||
|
||||
The ``ClockGen()`` task from ``lib_xua`` provides the reference signal to the CS2100 device and also handles
|
||||
recording of clock validity etc. See :ref:`usb_audio_sec_clock_recovery` for full details regarding ``ClockGen()``.
|
||||
The ``ClockGen()`` task from ``lib_xua`` provides the reference signal to the CS2100 device or timing information
|
||||
to lib_sw_pll and also handles recording of clock validity etc.
|
||||
See :ref:`usb_audio_sec_clock_recovery` for full details regarding ``ClockGen()``.
|
||||
|
||||
It also provides a small FIFO for S/PDIF samples before they are forwarded to the ``AudioHub`` core.
|
||||
As such it requires to be inserted in the communication path between the S/PDIF receiver and the
|
||||
|
||||
@@ -52,11 +52,11 @@ Three methods of generating an audio master clock are provided on the board:
|
||||
|
||||
* A Skyworks Si5351B PLL device. The Si5351 is an I2C configurable clock generator that is ideally suited for replacing crystals, crystal oscillators, VCXOs, phase-locked loops (PLLs), and fanout buffers.
|
||||
|
||||
* xCORE.ai devices are equipped with a secondary (or 'application') PLL which can be used to generate audio clocks
|
||||
* xCORE.ai devices are equipped with a secondary (or 'application') PLL which can be used to generate fixed audio clocks or recover external clocks using lib_sw_pll.
|
||||
|
||||
Selection between these methods is done via writing to bits 6 and 7 of PORT 8D on tile[0].
|
||||
|
||||
Either the locally generated clock (from the PL611) or the recovered low jitter clock (from the CS2100) may be selected to clock the audio stages; the xCORE-200, the ADC/DAC and Digital output stages. Selection is controlled via an additional I/O, bit 5 of PORT 8C, see :ref:`hw_316_ctrlport`.
|
||||
Either the locally generated clock (from the PL611) or the recovered low jitter clock (from the CS2100) may be selected to clock the audio stages; the xcore.ai, the ADC/DAC and Digital output stages. Selection is controlled via an additional I/O, bit 5 of PORT 8C, see :ref:`hw_316_ctrlport`.
|
||||
|
||||
.. _hw_316_ctrlport:
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ This must be a 1-bit port, for example::
|
||||
|
||||
<Port Location="XS1_PORT_1A" Name="PORT_SPDIF_IN"/>
|
||||
|
||||
When S/PDIF receive is enabled the codebase expects to drive a synchronisation signal to an external
|
||||
Cirrus Logic CS2100 device for master-clock generation.
|
||||
When S/PDIF receive is enabled the codebase expects to either drive a synchronisation signal to an external
|
||||
Cirrus Logic CS2100 device or use lib_swp_pll (xcore.ai only) for master-clock generation.
|
||||
|
||||
The programmer should ensure the define in :ref:`opt_spdif_rx_ref_defines` is set appropriately.
|
||||
|
||||
|
||||
@@ -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::
|
||||
|
||||
<Port Location="XS1_PORT_1A" Name="PORT_PLL_REF"/>
|
||||
|
||||
@@ -15,32 +15,35 @@ the xCORE.
|
||||
|
||||
Using an external PLL/Clock Multiplier allows an Asynchronous mode design to lock to an external
|
||||
clock source from a digital stream (e.g. S/PDIF or ADAT input). The codebase supports the Cirrus
|
||||
Logic CS2100 device for this purpose. Other devices may be supported via code modification.
|
||||
Logic CS2100 device or use of lib_sw_pll (xcore.ai only) for this purpose. Other devices may be
|
||||
supported via code modification.
|
||||
|
||||
.. note::
|
||||
|
||||
It is expected that in a future release the secondary PLL in xCORE.ai devices, coupled with
|
||||
associated software changes, will be capable of replacing the CS2100 part for most designs.
|
||||
The Clock Recovery core (Clock Gen) is responsible for either generating the reference frequency
|
||||
to the CS2100 device or driving lib_sw_pll from time measurements based on the local master clock
|
||||
and the time of received samples. Clock Gen (via CS2100 or lib_sw_pll) generates the master clock
|
||||
used over the whole design. This core also serves as a smaller buffer between ADAT and S/PDIF
|
||||
receiving cores and the Audio Hub core.
|
||||
|
||||
The Clock Recovery core (Clock Gen) is responsible for generating the reference frequency
|
||||
to the CS2100 device. This, in turn, generates the master clock used over the whole design.
|
||||
This core also serves as a smaller buffer between ADAT and S/PDIF receiving cores and the Audio Hub
|
||||
core.
|
||||
When using lib_sw_pll (xcore.ai only) an further core is instantiated which performs the sigma-delta
|
||||
modulation of the xCORE PLL to ensure the lowest jitter over the audio band. See lib_sw_pll
|
||||
documentation for further details.
|
||||
|
||||
When running in *Internal Clock* mode this core simply generates this clock using a local
|
||||
timer, based on the XMOS reference clock.
|
||||
|
||||
When running in an external clock mode (i.e. S/PDIF Clock" or "ADAT Clock" mode) samples are
|
||||
received from the S/PDIF and/or ADAT receive core. The external frequency is calculated through
|
||||
counting samples in a given period. The reference clock to the CS2100 is then generated based on
|
||||
the reception of these samples.
|
||||
received from the S/PDIF and/or ADAT receive core. The external frequency is calculated through
|
||||
counting samples in a given period. Either the reference clock to the CS2100 is then generated based on
|
||||
the reception of these samples or the timing information is provided to lib_sw_pll to generate
|
||||
the phase-locked clock on-chip (xcore.ai only).
|
||||
|
||||
If an external stream becomes invalid, the *Internal Clock* timer event will fire to ensure that
|
||||
valid master clock generation continues regardless of cable unplugs etc. Efforts are made to
|
||||
ensure the transition between these clocks are relatively seamless. Additionally efforts are also
|
||||
made to try and keep the jitter on the reference clock as low as possibly, regardless of activity
|
||||
made to try and keep the jitter on the reference clock as low as possible, regardless of activity
|
||||
level of the Clock Gen core. The is achieved though the use of port times to schedule pin toggling
|
||||
rather than directly outputting to the port.
|
||||
rather than directly outputting to the port in the case of using the CS2100. For lib_sw_pll cases the
|
||||
last setting is kept for the sigma-delta modulator ensuring clock continuity.
|
||||
|
||||
The Clock Gen core gets clock selection Get/Set commands from Endpoint 0 via the ``c_clk_ctl``
|
||||
channel. This core also records the validity of external clocks, which is also queried
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
|
||||
xmosdfu: xmosdfu.cpp
|
||||
mkdir -p bin
|
||||
g++ -D_GNU_SOURCE -Wall -g -o bin/xmosdfu -Ilibusb/Rasp -lusb-1.0 -x c xmosdfu.cpp -std=c99
|
||||
g++ -D_GNU_SOURCE -Wall -g -o bin/xmosdfu -Ilibusb/Rasp -x c xmosdfu.cpp -std=c99 -lusb-1.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
set(LIB_NAME lib_xua)
|
||||
set(LIB_VERSION 3.5.1)
|
||||
set(LIB_VERSION 4.0.0)
|
||||
set(LIB_INCLUDES api
|
||||
src/core
|
||||
src/core/audiohub
|
||||
@@ -14,18 +14,20 @@ 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
|
||||
src/midi)
|
||||
set(LIB_OPTIONAL_HEADERS xua_conf.h static_hid_report.h)
|
||||
set(LIB_DEPENDENT_MODULES "lib_locks"
|
||||
"lib_logging"
|
||||
"lib_mic_array(feature/xcommon_cmake)"
|
||||
"lib_spdif"
|
||||
"lib_xassert"
|
||||
"lib_xud"
|
||||
"lib_adat")
|
||||
set(LIB_DEPENDENT_MODULES "lib_adat(1.1.0)"
|
||||
"lib_locks(2.2.0)"
|
||||
"lib_logging(3.2.0)"
|
||||
"lib_mic_array(4.6.0)"
|
||||
"lib_spdif(6.1.0)"
|
||||
"lib_sw_pll(2.1.0)"
|
||||
"lib_xassert(4.2.0)"
|
||||
"lib_xud(2.3.1)")
|
||||
|
||||
set(LIB_COMPILER_FLAGS -O3 -DREF_CLK_FREQ=100 -fasm-linenum -fcomment-asm)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION = 3.5.1
|
||||
VERSION = 4.0.0
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
@@ -8,13 +8,14 @@ else
|
||||
DEBUG_FLAGS = -DXASSERT_ENABLE_ASSERTIONS=0 -DXASSERT_ENABLE_DEBUG=0 -DXASSERT_ENABLE_LINE_NUMBERS=0
|
||||
endif
|
||||
|
||||
DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
||||
lib_logging(>=3.1.1) \
|
||||
lib_mic_array(>=4.5.0) \
|
||||
lib_spdif(>=5.0.0) \
|
||||
lib_xassert(>=4.1.0) \
|
||||
lib_xud(>=2.2.3) \
|
||||
lib_adat(>=1.0.0)
|
||||
DEPENDENT_MODULES = lib_adat(>=1.1.0) \
|
||||
lib_locks(>=2.2.0) \
|
||||
lib_logging(>=3.2.0) \
|
||||
lib_mic_array(>=4.6.0) \
|
||||
lib_spdif(>=6.1.0) \
|
||||
lib_sw_pll(>=2.1.0) \
|
||||
lib_xassert(>=4.2.0) \
|
||||
lib_xud(>=2.3.1)
|
||||
|
||||
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
|
||||
-O3 \
|
||||
@@ -53,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 \
|
||||
@@ -69,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 \
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
// Copyright 2018-2022 XMOS LIMITED.
|
||||
// Copyright 2018-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
unsigned adatCounter = 0;
|
||||
unsigned adatSamples[8];
|
||||
|
||||
#pragma unsafe arrays
|
||||
static inline void TransferAdatTxSamples(chanend c_adat_out, const unsigned samplesFromHost[], int smux, int handshake)
|
||||
{
|
||||
|
||||
/* Do some re-arranging for SMUX.. */
|
||||
unsafe
|
||||
{
|
||||
@@ -29,7 +27,6 @@ static inline void TransferAdatTxSamples(chanend c_adat_out, const unsigned samp
|
||||
|
||||
if(adatCounter == smux)
|
||||
{
|
||||
|
||||
#ifdef ADAT_TX_USE_SHARED_BUFF
|
||||
unsafe
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
/**
|
||||
* @file 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)
|
||||
@@ -241,12 +242,12 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
}
|
||||
#endif // ((DEBUG_MIC_ARRAY == 1) && (XUA_NUM_PDM_MICS > 0))
|
||||
|
||||
UserBufferManagementInit();
|
||||
UserBufferManagementInit(curSamFreq);
|
||||
|
||||
unsigned command = DoSampleTransfer(c_out, readBuffNo, underflowWord);
|
||||
|
||||
// Reinitialise user state before entering the main loop
|
||||
UserBufferManagementInit();
|
||||
UserBufferManagementInit(curSamFreq);
|
||||
|
||||
#if (XUA_ADAT_TX_EN)
|
||||
unsafe{
|
||||
@@ -641,6 +642,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
#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_audio_rate_change
|
||||
#endif
|
||||
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
|
||||
, server interface i_dfu ?dfuInterface
|
||||
#endif
|
||||
@@ -666,7 +670,6 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
/* Note, marked unsafe since other cores may be using this mclk port */
|
||||
configure_clock_src(clk_audio_mclk, p_mclk_in);
|
||||
|
||||
start_clock(clk_audio_mclk);
|
||||
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
/* Make sure the DSD ports are on and buffered - just in case they are not shared with I2S */
|
||||
@@ -678,15 +681,12 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
#endif
|
||||
|
||||
#if (XUA_ADAT_TX_EN)
|
||||
/* Share SPDIF clk blk */
|
||||
configure_clock_src(clk_mst_spd, p_mclk_in);
|
||||
configure_out_port_no_ready(p_adat_tx, clk_mst_spd, 0);
|
||||
set_clock_fall_delay(clk_mst_spd, 7);
|
||||
#if (XUA_SPDIF_TX_EN == 0)
|
||||
start_clock(clk_mst_spd);
|
||||
#endif
|
||||
configure_out_port_no_ready(p_adat_tx, clk_audio_mclk, 0);
|
||||
set_clock_fall_delay(clk_audio_mclk, 7);
|
||||
#endif
|
||||
|
||||
start_clock(clk_audio_mclk);
|
||||
|
||||
/* Perform required CODEC/ADC/DAC initialisation */
|
||||
AudioHwInit();
|
||||
|
||||
@@ -799,7 +799,23 @@ 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();
|
||||
|
||||
/* User code should configure audio harware for SampleFreq/MClk etc */
|
||||
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_audio_rate_change <: mClk;
|
||||
c_audio_rate_change <: curFreq;
|
||||
|
||||
/* Wait for ACK back from clockgen or ep_buffer to signal clocks all good */
|
||||
c_audio_rate_change :> int _;
|
||||
#endif
|
||||
|
||||
/* User should unmute audio hardware */
|
||||
AudioHwConfig_UnMute();
|
||||
}
|
||||
|
||||
if(!firstRun)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2016-2021 XMOS LIMITED.
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include "xccompat.h"
|
||||
#include "xua_audiohub.h"
|
||||
|
||||
/* Default implementation for UserBufferManagementInit() */
|
||||
void __attribute__ ((weak)) UserBufferManagementInit()
|
||||
void __attribute__ ((weak)) UserBufferManagementInit(unsigned sampFreq)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -105,7 +105,12 @@ void XUA_Buffer(
|
||||
#endif
|
||||
, chanend c_aud
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
, chanend c_audio_rate_change
|
||||
#if(XUA_USE_SW_PLL)
|
||||
, chanend c_sw_pll
|
||||
#else
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@@ -141,7 +146,12 @@ void XUA_Buffer(
|
||||
, c_buff_ctrl
|
||||
#endif
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
, i_pll_ref
|
||||
, c_audio_rate_change
|
||||
#if(XUA_USE_SW_PLL)
|
||||
, c_sw_pll
|
||||
#else
|
||||
, i_pll_ref
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
|
||||
@@ -190,8 +200,13 @@ 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)
|
||||
, chanend c_audio_rate_change
|
||||
#if (XUA_USE_SW_PLL)
|
||||
, chanend c_sw_pll
|
||||
#else
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@@ -247,7 +262,7 @@ 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;
|
||||
|
||||
unsigned mod_from_last_time = 0;
|
||||
#ifdef FB_TOLERANCE_TEST
|
||||
@@ -294,7 +309,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,6 +371,24 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
#ifndef LOCAL_CLOCK_MARGIN
|
||||
#define LOCAL_CLOCK_MARGIN (1000)
|
||||
#endif
|
||||
|
||||
#if (XUA_USE_SW_PLL)
|
||||
/* Setup the phase frequency detector */
|
||||
const unsigned controller_rate_hz = 100;
|
||||
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,
|
||||
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);
|
||||
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;
|
||||
unsigned timeLastEdge;
|
||||
unsigned timeNextEdge;
|
||||
@@ -365,6 +397,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
i_pll_ref.toggle();
|
||||
#endif
|
||||
|
||||
#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) */
|
||||
|
||||
while(1)
|
||||
{
|
||||
XUD_Result_t result;
|
||||
@@ -427,7 +461,7 @@ 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;
|
||||
clocks = 0;
|
||||
clockcounter = 0;
|
||||
mod_from_last_time = 0;
|
||||
@@ -450,7 +484,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
masterClockFreq = MCLK_441;
|
||||
}
|
||||
}
|
||||
#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 */
|
||||
@@ -502,13 +536,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_SW_PLL)
|
||||
case t_sofCheck when timerafter(timeNextEdge) :> void:
|
||||
i_pll_ref.toggle();
|
||||
timeLastEdge = timeNextEdge;
|
||||
@@ -523,28 +557,61 @@ 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);
|
||||
static int sofCount = 0;
|
||||
#if (XUA_USE_SW_PLL)
|
||||
/* 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) */
|
||||
|
||||
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++;
|
||||
if (sofCount == sofFreqDivider)
|
||||
{
|
||||
#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));
|
||||
|
||||
uint8_t first_loop = 0;
|
||||
unsafe{
|
||||
sw_pll_calc_error_from_port_timers(&sw_pll_pfd, &first_loop, mclk_pt, 0);
|
||||
}
|
||||
|
||||
int error = 0;
|
||||
if(!first_loop)
|
||||
{
|
||||
error = sw_pll_pfd.mclk_diff;
|
||||
}
|
||||
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);
|
||||
|
||||
#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;
|
||||
sofCount = 0;
|
||||
timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
#endif /* (XUA_USE_SW_PLL) */
|
||||
sofCount = 0;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
||||
/* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to
|
||||
@@ -646,7 +713,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.
|
||||
@@ -691,7 +757,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);
|
||||
@@ -897,8 +962,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 +976,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)
|
||||
{
|
||||
@@ -963,6 +1028,33 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
break;
|
||||
#endif /* ifdef MIDI */
|
||||
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
case c_audio_rate_change :> u_tmp:
|
||||
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)
|
||||
sw_pll_pfd_init(&sw_pll_pfd,
|
||||
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
|
||||
c_audio_rate_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):
|
||||
inct(c_sw_pll);
|
||||
c_audio_rate_change <: 0; /* ACK back to audio to release */
|
||||
|
||||
break;
|
||||
#endif /* (XUA_USE_SW_PLL) */
|
||||
#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) */
|
||||
|
||||
#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):
|
||||
|
||||
@@ -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 <xs1.h>
|
||||
#include <assert.h>
|
||||
@@ -25,11 +25,11 @@ unsigned g_digData[10];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int receivedSamples;
|
||||
int samples;
|
||||
int savedSamples;
|
||||
int lastDiff;
|
||||
unsigned identicaldiffs;
|
||||
int receivedSamples; /* Uses by clockgen to count number of dig rx samples to ascertain clock specs */
|
||||
int samples; /* Raw sample count - rolling int and never reset */
|
||||
int savedSamples; /* Used by validSamples() to store state of last raw sample count */
|
||||
int lastDiff; /* Used by validSamples() to store state of last sample count diff */
|
||||
unsigned identicaldiffs; /* Used by validSamples() to store state of number of identical diffs */
|
||||
int samplesPerTick;
|
||||
} Counter;
|
||||
|
||||
@@ -38,6 +38,7 @@ static int clockValid[NUM_CLOCKS]; /* Store current val
|
||||
static int clockInt[NUM_CLOCKS]; /* Interupt flag for clocks */
|
||||
static int clockId[NUM_CLOCKS];
|
||||
|
||||
|
||||
[[distributable]]
|
||||
void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_pll_ref)
|
||||
{
|
||||
@@ -87,27 +88,10 @@ static int abs(int x)
|
||||
return x;
|
||||
}
|
||||
|
||||
static int channelContainsControlToken(chanend x)
|
||||
{
|
||||
unsigned char tmpc;
|
||||
|
||||
select
|
||||
{
|
||||
case inct_byref(x, tmpc):
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void outInterrupt(chanend c_interruptControl, int value)
|
||||
{
|
||||
/* Non-blocking check for control token */
|
||||
//if (channelContainsControlToken(c_interruptControl))
|
||||
{
|
||||
outuint(c_interruptControl, value);
|
||||
outct(c_interruptControl, XS1_CT_END);
|
||||
}
|
||||
outuint(c_interruptControl, value);
|
||||
outct(c_interruptControl, XS1_CT_END);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -206,7 +190,7 @@ static inline int validSamples(Counter &counter, int clockIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else /* No valid frequency found - reset state */
|
||||
{
|
||||
counter.identicaldiffs = 0;
|
||||
counter.lastDiff = diff;
|
||||
@@ -215,6 +199,13 @@ static inline int validSamples(Counter &counter, int clockIndex)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if XUA_USE_SW_PLL
|
||||
unsafe
|
||||
{
|
||||
unsigned * unsafe selected_mclk_rate_ptr = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
void VendorLedRefresh(unsigned levelData[]);
|
||||
unsigned g_inputLevelData[NUM_USB_CHAN_IN];
|
||||
@@ -225,14 +216,25 @@ extern int samples_to_host_inputs_buff[NUM_USB_CHAN_IN];
|
||||
int VendorAudCoreReqs(unsigned cmd, chanend c);
|
||||
|
||||
#pragma unsafe arrays
|
||||
void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interface pll_ref_if i_pll_ref, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
|
||||
void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
chanend ?c_adat_rx,
|
||||
client interface pll_ref_if i_pll_ref,
|
||||
chanend c_dig_rx,
|
||||
chanend c_clk_ctl,
|
||||
chanend c_clk_int,
|
||||
chanend c_audio_rate_change
|
||||
#if XUA_USE_SW_PLL
|
||||
, port p_for_mclk_count_aud
|
||||
, chanend c_sw_pll
|
||||
#endif
|
||||
)
|
||||
{
|
||||
timer t_local;
|
||||
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
|
||||
unsigned clkMode = CLOCK_INTERNAL; /* Current clocking mode in operation */
|
||||
unsigned tmp;
|
||||
|
||||
/* start in no-SMUX (8-channel) mode */
|
||||
/* Start in no-SMUX (8-channel) mode */
|
||||
int smux = 0;
|
||||
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
@@ -242,6 +244,16 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
timer t_external;
|
||||
unsigned selected_mclk_rate = MCLK_48; // Assume 24.576MHz initial clock
|
||||
unsigned selected_sample_rate = 0;
|
||||
#if XUA_USE_SW_PLL
|
||||
|
||||
unsigned mclks_per_sample = 0;
|
||||
unsigned short mclk_time_stamp = 0;
|
||||
|
||||
/* Get MCLK count */
|
||||
asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
@@ -281,21 +293,21 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
}
|
||||
|
||||
/* Init clock unit state */
|
||||
clockFreq[CLOCK_INTERNAL] = 0;
|
||||
clockId[CLOCK_INTERNAL] = ID_CLKSRC_INT;
|
||||
clockValid[CLOCK_INTERNAL] = 0;
|
||||
clockInt[CLOCK_INTERNAL] = 0;
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
clockFreq[CLOCK_SPDIF_INDEX] = 0;
|
||||
clockValid[CLOCK_SPDIF_INDEX] = 0;
|
||||
clockInt[CLOCK_SPDIF_INDEX] = 0;
|
||||
clockId[CLOCK_SPDIF_INDEX] = ID_CLKSRC_SPDIF;
|
||||
clockFreq[CLOCK_SPDIF] = 0;
|
||||
clockValid[CLOCK_SPDIF] = 0;
|
||||
clockInt[CLOCK_SPDIF] = 0;
|
||||
clockId[CLOCK_SPDIF] = ID_CLKSRC_SPDIF;
|
||||
#endif
|
||||
clockFreq[CLOCK_INTERNAL_INDEX] = 0;
|
||||
clockId[CLOCK_INTERNAL_INDEX] = ID_CLKSRC_INT;
|
||||
clockValid[CLOCK_INTERNAL_INDEX] = 0;
|
||||
clockInt[CLOCK_INTERNAL_INDEX] = 0;
|
||||
#if (XUA_ADAT_RX_EN)
|
||||
clockFreq[CLOCK_ADAT_INDEX] = 0;
|
||||
clockInt[CLOCK_ADAT_INDEX] = 0;
|
||||
clockValid[CLOCK_ADAT_INDEX] = 0;
|
||||
clockId[CLOCK_ADAT_INDEX] = ID_CLKSRC_ADAT;
|
||||
clockFreq[CLOCK_ADAT] = 0;
|
||||
clockInt[CLOCK_ADAT] = 0;
|
||||
clockValid[CLOCK_ADAT] = 0;
|
||||
clockId[CLOCK_ADAT] = ID_CLKSRC_ADAT;
|
||||
#endif
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
spdifCounters.receivedSamples = 0;
|
||||
@@ -333,6 +345,12 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
/* Initial ref clock output and get timestamp */
|
||||
i_pll_ref.init();
|
||||
|
||||
#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 */
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
{
|
||||
select
|
||||
@@ -389,13 +407,9 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
|
||||
case SET_SEL:
|
||||
/* Update clock mode */
|
||||
tmp = inuint(c_clk_ctl);
|
||||
clkMode = inuint(c_clk_ctl);
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
|
||||
if(tmp!=0)
|
||||
{
|
||||
clkMode = tmp;
|
||||
}
|
||||
#ifdef CLOCK_VALIDITY_CALL
|
||||
switch(clkMode)
|
||||
{
|
||||
@@ -404,12 +418,12 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
break;
|
||||
#if (XUA_ADAT_RX_EN)
|
||||
case CLOCK_ADAT:
|
||||
VendorClockValidity(clockValid[CLOCK_ADAT_INDEX]);
|
||||
VendorClockValidity(clockValid[CLOCK_ADAT]);
|
||||
break;
|
||||
#endif
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
case CLOCK_SPDIF:
|
||||
VendorClockValidity(clockValid[CLOCK_SPDIF_INDEX]);
|
||||
VendorClockValidity(clockValid[CLOCK_SPDIF]);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
@@ -454,9 +468,12 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
/* Generate local clock from timer */
|
||||
case t_local when timerafter(timeNextEdge) :> void:
|
||||
|
||||
#if XUA_USE_SW_PLL
|
||||
/* Do nothing - hold the most recent sw_pll setting */
|
||||
#else
|
||||
/* Setup next local clock edge */
|
||||
i_pll_ref.toggle_timed(0);
|
||||
|
||||
#endif
|
||||
/* Record time of edge */
|
||||
timeLastEdge = timeNextEdge;
|
||||
|
||||
@@ -483,32 +500,63 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
case t_external when timerafter(timeNextClockDetection) :> void:
|
||||
|
||||
timeNextClockDetection += (LOCAL_CLOCK_INCREMENT);
|
||||
{
|
||||
int valid;
|
||||
timeNextClockDetection += (LOCAL_CLOCK_INCREMENT);
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
tmp = spdifCounters.samplesPerTick;
|
||||
|
||||
/* Returns 1 if valid clock found */
|
||||
tmp = validSamples(spdifCounters, CLOCK_SPDIF_INDEX);
|
||||
setClockValidity(c_clk_int, CLOCK_SPDIF_INDEX, tmp, 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)
|
||||
tmp = validSamples(adatCounters, CLOCK_ADAT_INDEX);
|
||||
setClockValidity(c_clk_int, CLOCK_ADAT_INDEX, tmp, clkMode);
|
||||
/* Returns 1 if valid clock found */
|
||||
valid = validSamples(adatCounters, CLOCK_ADAT);
|
||||
setClockValidity(c_clk_int, CLOCK_ADAT, valid, clkMode);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
|
||||
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)
|
||||
{
|
||||
c_audio_rate_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_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);
|
||||
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_audio_rate_change <: 0;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
/* Receive sample from S/PDIF RX thread (streaming chan) */
|
||||
case c_spdif_rx :> spdifRxData:
|
||||
|
||||
#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
|
||||
t_local :> spdifRxTime;
|
||||
|
||||
/* Check parity and ignore if bad */
|
||||
@@ -530,7 +578,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
case SPDIF_FRAME_Y:
|
||||
|
||||
/* Only store sample if not in overflow and stream is reasonably valid */
|
||||
if(!spdifOverflow && clockValid[CLOCK_SPDIF_INDEX])
|
||||
if(!spdifOverflow && clockValid[CLOCK_SPDIF])
|
||||
{
|
||||
/* Store left and right sample pair to buffer */
|
||||
spdifSamples[spdifWr] = spdifLeft;
|
||||
@@ -562,7 +610,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
|
||||
spdifCounters.samples += 1;
|
||||
|
||||
if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF_INDEX])
|
||||
if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF])
|
||||
{
|
||||
spdifCounters.receivedSamples+=1;
|
||||
|
||||
@@ -578,9 +626,16 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
/* Setup for next edge */
|
||||
timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
|
||||
#if XUA_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;
|
||||
}
|
||||
@@ -591,7 +646,11 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
#if (XUA_ADAT_RX_EN)
|
||||
/* receive sample from ADAT rx thread (streaming channel with CT_END) */
|
||||
case inuint_byref(c_adat_rx, tmp):
|
||||
|
||||
#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
|
||||
t_local :> adatReceivedTime;
|
||||
|
||||
/* Sync is: 1 | (user_byte << 4) */
|
||||
@@ -611,7 +670,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
if (adatChannel == 8)
|
||||
{
|
||||
/* only store left samples if not in overflow and stream is reasonably valid */
|
||||
if (!adatOverflow && clockValid[CLOCK_ADAT_INDEX])
|
||||
if (!adatOverflow && clockValid[CLOCK_ADAT])
|
||||
{
|
||||
/* Unpick the SMUX.. */
|
||||
if(smux == 2)
|
||||
@@ -668,7 +727,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
{
|
||||
adatCounters.samples += 1;
|
||||
|
||||
if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT_INDEX])
|
||||
if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT])
|
||||
{
|
||||
adatCounters.receivedSamples += 1;
|
||||
|
||||
@@ -684,8 +743,16 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
/* Setup for next edge */
|
||||
timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
|
||||
#if XUA_USE_SW_PLL
|
||||
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);
|
||||
#endif
|
||||
|
||||
/* Reset counters */
|
||||
adatCounters.receivedSamples = 0;
|
||||
@@ -724,7 +791,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
spdifSamps -= 2;
|
||||
|
||||
/* spdifSamps could go to -1 */
|
||||
if(spdifSamps < 0)
|
||||
if(spdifSamps <= 0)
|
||||
{
|
||||
/* We're out of S/PDIF samples, mark underflow condition */
|
||||
spdifUnderflow = 1;
|
||||
@@ -738,7 +805,6 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
spdifOverflow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if (XUA_ADAT_RX_EN)
|
||||
if (adatUnderflow)
|
||||
@@ -806,7 +872,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
}
|
||||
|
||||
/* adatSamps could go to -1 */
|
||||
if (adatSamps < 0)
|
||||
if (adatSamps <= 0)
|
||||
{
|
||||
/* we're out of ADAT samples, mark underflow condition */
|
||||
adatUnderflow = 1;
|
||||
@@ -823,7 +889,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
outuint(c_dig_rx, 1);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* select */
|
||||
} /* while(1) */
|
||||
} /* clkgen task scope */
|
||||
|
||||
|
||||
57
lib_xua/src/core/clocking/sw_pll_wrapper.h
Normal file
57
lib_xua/src/core/clocking/sw_pll_wrapper.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#ifndef _SW_PLL_WRAPPPER_H_
|
||||
#define _SW_PLL_WRAPPPER_H_
|
||||
|
||||
#include "xua.h"
|
||||
|
||||
#if XUA_USE_SW_PLL
|
||||
extern "C"
|
||||
{
|
||||
#include "sw_pll.h"
|
||||
}
|
||||
|
||||
/* Special control value to disable SDM. Outside of normal range which is less than 16b.*/
|
||||
#define DISABLE_SDM 0x10000000
|
||||
|
||||
|
||||
/** 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_sw_pll Channel connected to the clocking thread to pass raw error terms.
|
||||
*/
|
||||
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_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_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_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_sw_pll,
|
||||
int receivedSamples,
|
||||
int &reset_sw_pll_pfd);
|
||||
|
||||
/** Initilaises the software PLL both hardware and state. Sets the mclk frequency to a nominal point.
|
||||
*
|
||||
* \param sw_pll Reference to a software pll state struct to be initialised.
|
||||
* \param mClk The current nominal mClk frequency.
|
||||
*
|
||||
* 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 /* XUA_USE_SW_PLL */
|
||||
#endif /* _SW_PLL_WRAPPPER_H_ */
|
||||
202
lib_xua/src/core/clocking/sw_pll_wrapper.xc
Normal file
202
lib_xua/src/core/clocking/sw_pll_wrapper.xc
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright 2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <xs1.h>
|
||||
#include <assert.h>
|
||||
#include <print.h>
|
||||
|
||||
#include "sw_pll_wrapper.h"
|
||||
#include "xua.h"
|
||||
|
||||
#if XUA_USE_SW_PLL
|
||||
|
||||
|
||||
{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
|
||||
F: 134
|
||||
R: 0
|
||||
f: 8
|
||||
p: 18
|
||||
OD: 5
|
||||
ACD: 5
|
||||
*/
|
||||
|
||||
#define APP_PLL_CTL_REG_22 0x0A808600
|
||||
#define APP_PLL_DIV_REG_22 0x80000005
|
||||
#define APP_PLL_FRAC_REG_22 0x80000812
|
||||
#define SW_PLL_SDM_CTRL_MID_22 498283
|
||||
#define SW_PLL_SDM_RATE_22 1000000
|
||||
|
||||
/* Autogenerated SDM App PLL setup by dco_model.py using 24.576_1M profile */
|
||||
/* Input freq: 24000000
|
||||
F: 146
|
||||
R: 0
|
||||
f: 4
|
||||
p: 10
|
||||
OD: 5
|
||||
ACD: 5
|
||||
*/
|
||||
|
||||
#define APP_PLL_CTL_REG_24 0x0A809200
|
||||
#define APP_PLL_DIV_REG_24 0x80000005
|
||||
#define APP_PLL_FRAC_REG_24 0x8000040A
|
||||
#define SW_PLL_SDM_CTRL_MID_24 478151
|
||||
#define SW_PLL_SDM_RATE_24 1000000
|
||||
|
||||
|
||||
const uint32_t app_pll_ctl_reg[2] = {APP_PLL_CTL_REG_22, APP_PLL_CTL_REG_24};
|
||||
const uint32_t app_pll_div_reg[2] = {APP_PLL_DIV_REG_22, APP_PLL_DIV_REG_24};
|
||||
const uint32_t app_pll_frac_reg[2] = {APP_PLL_FRAC_REG_22, APP_PLL_FRAC_REG_24};
|
||||
const uint32_t sw_pll_sdm_ctrl_mid[2] = {SW_PLL_SDM_CTRL_MID_22, SW_PLL_SDM_CTRL_MID_24};
|
||||
const uint32_t sw_pll_sdm_rate[2] = {SW_PLL_SDM_RATE_22, SW_PLL_SDM_RATE_24};
|
||||
|
||||
const int clkIndex = mClk == MCLK_48 ? 1 : 0;
|
||||
|
||||
sw_pll_sdm_init(&sw_pll,
|
||||
SW_PLL_15Q16(0.0),
|
||||
SW_PLL_15Q16(32.0),
|
||||
SW_PLL_15Q16(0.25),
|
||||
0, /* LOOP COUNT Don't care for this API */
|
||||
0, /* PLL_RATIO Don't care for this API */
|
||||
0, /* No jitter compensation needed */
|
||||
app_pll_ctl_reg[clkIndex],
|
||||
app_pll_div_reg[clkIndex],
|
||||
app_pll_frac_reg[clkIndex],
|
||||
sw_pll_sdm_ctrl_mid[clkIndex],
|
||||
3000 /* PPM_RANGE (FOR PFD) Don't care for this API*/ );
|
||||
|
||||
/* Reset SDM too */
|
||||
sw_pll_init_sigma_delta(&sw_pll.sdm_state);
|
||||
|
||||
return {XS1_TIMER_HZ / sw_pll_sdm_rate[clkIndex], sw_pll_sdm_ctrl_mid[clkIndex]};
|
||||
}
|
||||
|
||||
void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp,
|
||||
unsigned mclks_per_sample,
|
||||
chanend c_sw_pll,
|
||||
int receivedSamples,
|
||||
int &reset_sw_pll_pfd)
|
||||
{
|
||||
const unsigned control_loop_rate_divider = 6; /* 300Hz * 2 edges / 6 -> 100Hz loop rate */
|
||||
static unsigned control_loop_counter = 0;
|
||||
static unsigned total_received_samples = 0;
|
||||
|
||||
/* Keep a store of the last mclk time stamp so we can work out the increment */
|
||||
static unsigned short last_mclk_time_stamp = 0;
|
||||
|
||||
control_loop_counter++;
|
||||
|
||||
total_received_samples += receivedSamples;
|
||||
|
||||
if(control_loop_counter == control_loop_rate_divider)
|
||||
{
|
||||
/* Calculate what the zero-error mclk count increment should be for this many samples */
|
||||
const unsigned expected_mclk_inc = mclks_per_sample * total_received_samples / 2; /* divide by 2 because this fn is called per edge */
|
||||
|
||||
/* Calculate actualy time-stamped mclk count increment is */
|
||||
const unsigned short actual_mclk_inc = mclk_time_stamp - last_mclk_time_stamp;
|
||||
|
||||
/* The difference is the raw error in terms of mclk counts */
|
||||
short f_error = (int)actual_mclk_inc - (int)expected_mclk_inc;
|
||||
if(reset_sw_pll_pfd)
|
||||
{
|
||||
f_error = 0; /* Skip first measurement as it will likely be very out */
|
||||
reset_sw_pll_pfd = 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
total_received_samples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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_sw_pll);
|
||||
inct(c_sw_pll);
|
||||
|
||||
int f_error = 0;
|
||||
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} = init_sw_pll(sw_pll, selected_mclk_rate);
|
||||
|
||||
tileref_t this_tile = get_local_tile_id();
|
||||
|
||||
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 */
|
||||
outct(c_sw_pll, XS1_CT_END);
|
||||
|
||||
unsigned rx_word = 0;
|
||||
while(running)
|
||||
{
|
||||
/* Poll for new SDM control value */
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_sw_pll, rx_word):
|
||||
inct(c_sw_pll);
|
||||
if(rx_word == DISABLE_SDM)
|
||||
{
|
||||
f_error = 0;
|
||||
running = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
} /* while running */
|
||||
} /* while(1) */
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
@@ -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.
|
||||
/**
|
||||
* @file xua_ep0_descriptors.h
|
||||
@@ -772,6 +772,11 @@ typedef struct
|
||||
unsigned char configDesc_DFU[DFU_LENGTH];
|
||||
#endif
|
||||
|
||||
#ifdef USB_CONTROL_DESCS
|
||||
/* Inferface descriptor for control */
|
||||
unsigned char itfDesc_control[9];
|
||||
#endif
|
||||
|
||||
#ifdef IAP
|
||||
USB_Descriptor_Interface_t iAP_Interface;
|
||||
USB_Descriptor_Endpoint_t iAP_Out_Endpoint;
|
||||
@@ -2104,6 +2109,21 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
#endif
|
||||
#endif /* (XUA_DFU_EN == 1) */
|
||||
|
||||
#ifdef USB_CONTROL_DESCS
|
||||
{
|
||||
/* Control interface descriptor */
|
||||
0x09, /* 0 bLength : Size of this descriptor, in bytes. (field size 1 bytes) */
|
||||
0x04, /* 1 bDescriptorType : INTERFACE descriptor. (field size 1 bytes) */
|
||||
(INTERFACE_NUMBER_MISC_CONTROL), /* 2 bInterfaceNumber */
|
||||
0x00, /* 3 bAlternateSetting : Index of this setting. (field size 1 bytes) */
|
||||
0x00, /* 4 bNumEndpoints : 0 endpoints. (field size 1 bytes) */
|
||||
USB_CLASS_VENDOR_SPECIFIC, /* 5 bInterfaceClass : Vendor specific. (field size 1 bytes) */
|
||||
0xFF, /* 6 bInterfaceSubclass : (field size 1 bytes) */
|
||||
0xFF, /* 7 bInterfaceProtocol : Unused. (field size 1 bytes) */
|
||||
offsetof(StringDescTable_t, ctrlStr)/sizeof(char *), /* 8 iInterface */
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef IAP
|
||||
/* Interface descriptor */
|
||||
.iAP_Interface =
|
||||
|
||||
@@ -456,34 +456,35 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
(buffer, unsigned char[])[0] = 1;
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
||||
break;
|
||||
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
case ID_CLKSRC_SPDIF:
|
||||
|
||||
/* Interogate clockgen thread for validity */
|
||||
if (!isnull(c_clk_ctl))
|
||||
{
|
||||
outuint(c_clk_ctl, GET_VALID);
|
||||
outuint(c_clk_ctl, CLOCK_SPDIF_INDEX);
|
||||
outuint(c_clk_ctl, CLOCK_SPDIF);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
(buffer, unsigned char[])[0] = inuint(c_clk_ctl);
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#endif
|
||||
#if (XUA_ADAT_RX_EN)
|
||||
case ID_CLKSRC_ADAT:
|
||||
|
||||
if (!isnull(c_clk_ctl))
|
||||
{
|
||||
outuint(c_clk_ctl, GET_VALID);
|
||||
outuint(c_clk_ctl, CLOCK_ADAT_INDEX);
|
||||
outuint(c_clk_ctl, CLOCK_ADAT);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
(buffer, unsigned char[])[0] = inuint(c_clk_ctl);
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
//Unknown Unit ID in Clock Valid Control Request
|
||||
@@ -513,19 +514,23 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Check for correct datalength for clock sel */
|
||||
if(datalength == 1)
|
||||
{
|
||||
if (!isnull(c_clk_ctl))
|
||||
{
|
||||
outuint(c_clk_ctl, SET_SEL);
|
||||
outuint(c_clk_ctl, (buffer, unsigned char[])[0]);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
}
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
int clockIndex = (int) (buffer, unsigned char[])[0];
|
||||
clockIndex -= 1; /* Index to/from host is 1-based */
|
||||
|
||||
if((clockIndex >= 0) && (clockIndex < CLOCK_COUNT))
|
||||
{
|
||||
if(!isnull(c_clk_ctl))
|
||||
{
|
||||
outuint(c_clk_ctl, SET_SEL);
|
||||
outuint(c_clk_ctl, clockIndex);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
}
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -533,13 +538,15 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
(buffer, unsigned char[])[0] = 1;
|
||||
if (!isnull(c_clk_ctl))
|
||||
{
|
||||
int clockIndex;
|
||||
outuint(c_clk_ctl, GET_SEL);
|
||||
outct(c_clk_ctl, XS1_CT_END);
|
||||
(buffer, unsigned char[])[0] = inuint(c_clk_ctl);
|
||||
clockIndex = inuint(c_clk_ctl);
|
||||
clockIndex += 1; /* Index to/from host is 1-based */
|
||||
(buffer, unsigned char[])[0] = (unsigned char) clockIndex;
|
||||
chkct(c_clk_ctl, XS1_CT_END);
|
||||
}
|
||||
return XUD_DoGetRequest( ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength );
|
||||
|
||||
return XUD_DoGetRequest( ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -916,17 +923,20 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
{
|
||||
storeFreq((buffer, unsigned char[]), i, currentFreq44);
|
||||
num_freqs++;
|
||||
currentFreq44*=2;
|
||||
}
|
||||
|
||||
if((currentFreq48 <= maxFreq))
|
||||
currentFreq44*=2;
|
||||
|
||||
if((currentFreq48 <= maxFreq) && (currentFreq48 >= MIN_FREQ))
|
||||
{
|
||||
/* Note i passed byref here */
|
||||
storeFreq((buffer, unsigned char[]), i, currentFreq48);
|
||||
num_freqs++;
|
||||
currentFreq48*=2;
|
||||
}
|
||||
else
|
||||
|
||||
currentFreq48*=2;
|
||||
|
||||
if((currentFreq48 > MAX_FREQ) && (currentFreq44 > MAX_FREQ))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2012-2023 XMOS LIMITED.
|
||||
// Copyright 2012-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include "xua.h" /* Device specific defines */
|
||||
@@ -144,6 +144,11 @@ on tile[XUD_TILE] : in port p_spdif_rx = PORT_SPDIF_IN;
|
||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) || (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
/* Reference to external clock multiplier */
|
||||
on tile[PLL_REF_TILE] : out port p_pll_ref = PORT_PLL_REF;
|
||||
#ifdef __XS3A__
|
||||
on tile[AUDIO_IO_TILE] : port p_for_mclk_count_audio = PORT_MCLK_COUNT_2;
|
||||
#else /* __XS3A__ */
|
||||
#define p_for_mclk_count_audio null
|
||||
#endif /* __XS3A__ */
|
||||
#endif
|
||||
|
||||
#ifdef MIDI
|
||||
@@ -310,6 +315,13 @@ 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_audio_rate_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
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if (MIXER)
|
||||
@@ -318,9 +330,14 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
chan c_dig_rx;
|
||||
#else
|
||||
#define c_dig_rx null
|
||||
#endif
|
||||
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));
|
||||
#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)
|
||||
/* Configure clocks ports - sharing mclk port with I2S */
|
||||
@@ -366,6 +383,9 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
#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_audio_rate_change
|
||||
#endif
|
||||
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
|
||||
, dfuInterface
|
||||
#endif
|
||||
@@ -385,12 +405,22 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
* However, due to the use of an interface the pll reference signal port can be on another tile
|
||||
*/
|
||||
thread_speed();
|
||||
clockGen(c_spdif_rx, c_adat_rx, i_pll_ref, c_dig_rx, c_clk_ctl, c_clk_int);
|
||||
clockGen( c_spdif_rx,
|
||||
c_adat_rx,
|
||||
i_pll_ref,
|
||||
c_dig_rx,
|
||||
c_clk_ctl,
|
||||
c_clk_int,
|
||||
c_audio_rate_change
|
||||
#if XUA_USE_SW_PLL
|
||||
, p_for_mclk_count_aud
|
||||
, c_sw_pll
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
//:
|
||||
}
|
||||
} // par
|
||||
}
|
||||
|
||||
#ifndef USER_MAIN_DECLARATIONS
|
||||
@@ -437,7 +467,7 @@ int main()
|
||||
#define c_adat_rx null
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
chan c_spdif_tx;
|
||||
#endif
|
||||
|
||||
@@ -463,9 +493,16 @@ 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_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) && XUA_USE_SW_PLL)
|
||||
chan c_sw_pll;
|
||||
#endif
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
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 */
|
||||
chan c_xud_in[ENDPOINT_COUNT_IN];
|
||||
@@ -487,7 +524,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_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]:
|
||||
@@ -558,7 +595,12 @@ int main()
|
||||
#endif
|
||||
, c_mix_out
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
, c_audio_rate_change
|
||||
#if (!XUA_USE_SW_PLL)
|
||||
, i_pll_ref
|
||||
#else
|
||||
, c_sw_pll
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
//:
|
||||
@@ -573,8 +615,16 @@ int main()
|
||||
#endif /* XUA_USB_EN */
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
on tile[AUDIO_IO_TILE]:
|
||||
{
|
||||
#ifndef AUDIO_UNSAFE_RESRC
|
||||
#define AUDIO_UNSAFE_RESRC
|
||||
#endif
|
||||
AUDIO_UNSAFE_RESRC
|
||||
/* Audio I/O task, includes mixing etc */
|
||||
usb_audio_io(c_mix_out
|
||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
@@ -588,13 +638,16 @@ 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)
|
||||
, i_pll_ref
|
||||
#endif
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
, c_audio_rate_change
|
||||
#endif
|
||||
#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
|
||||
, p_for_mclk_count_audio
|
||||
, c_sw_pll
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,9 @@ void ConfigAudioPorts(
|
||||
if(!isnull(p_lrclk))
|
||||
{
|
||||
/* Clock LR clock from bit clock-block */
|
||||
#if((XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)&&(I2S_TDM_LRCLK_EDGES==0))
|
||||
set_port_inv(p_lrclk);//反向lrclk的输出
|
||||
#endif
|
||||
configure_out_port_no_ready(p_lrclk, clk_audio_bclk, 0);
|
||||
}
|
||||
|
||||
|
||||
29
lib_xua/src/core/user/audiohw/audiohw.c
Normal file
29
lib_xua/src/core/user/audiohw/audiohw.c
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
54
lib_xua/src/core/user/audiohw/audiohw.h
Normal file
54
lib_xua/src/core/user/audiohw/audiohw.h
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 <stddef.h>
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -10,20 +10,19 @@
|
||||
#define SET_SEL 1 /* Set value of clock selector */
|
||||
#define GET_FREQ 2 /* Get current freq */
|
||||
#define GET_VALID 3 /* Get current validity */
|
||||
#define SET_SMUX 7 /* Set SMUX mode (ADAT) */
|
||||
|
||||
#define CLOCK_INTERNAL 1
|
||||
#define CLOCK_SPDIF 2
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
#define CLOCK_ADAT 3
|
||||
#else
|
||||
#define CLOCK_ADAT 2
|
||||
enum
|
||||
{
|
||||
CLOCK_INTERNAL = 0,
|
||||
#if XUA_SPDIF_RX_EN
|
||||
CLOCK_SPDIF,
|
||||
#endif
|
||||
|
||||
#define CLOCK_INTERNAL_INDEX (CLOCK_INTERNAL - 1)
|
||||
#define CLOCK_ADAT_INDEX (CLOCK_ADAT - 1)
|
||||
#define CLOCK_SPDIF_INDEX (CLOCK_SPDIF - 1)
|
||||
|
||||
#define SET_SMUX 7
|
||||
#if XUA_ADAT_RX_EN
|
||||
CLOCK_ADAT,
|
||||
#endif
|
||||
CLOCK_COUNT
|
||||
};
|
||||
|
||||
/* c_audioControl */
|
||||
#define SET_SAMPLE_FREQ 4
|
||||
|
||||
@@ -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_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_SW_PLL=0 \
|
||||
$(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
@@ -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
|
||||
@@ -173,6 +173,7 @@ int main()
|
||||
chan c_in[EP_COUNT_IN];
|
||||
chan c_sof;
|
||||
chan c_aud_ctl;
|
||||
chan c_audio_rate_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_audio_rate_change, i_pll_ref
|
||||
);
|
||||
}
|
||||
|
||||
@@ -193,4 +194,6 @@ int main()
|
||||
|
||||
checker();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user