forked from PAWPAW-Mirror/lib_xua
Compare commits
130 Commits
experiment
...
v4.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
1f74f8c601 | ||
|
|
9f8a4e737f | ||
|
|
c57079cd4a | ||
|
|
5a78b5079f | ||
|
|
5b5ee132e0 | ||
|
|
15c3007d1c | ||
|
|
ab7a94a821 | ||
|
|
29156d5b19 | ||
|
|
5e5b2b7bd5 | ||
|
|
eebbb88fee | ||
|
|
db63b93ac1 | ||
|
|
32c783795b | ||
|
|
5b37c4d224 | ||
|
|
8fbe410e0e | ||
|
|
52b72285e0 | ||
|
|
2cfaff9221 | ||
|
|
0f4cb1ccb5 | ||
|
|
bd702db2c6 | ||
|
|
764fe0bfe9 | ||
|
|
f1d902306f | ||
|
|
74894341d1 | ||
|
|
a89df80da8 | ||
|
|
07ffd9221a | ||
|
|
7bbaff49af | ||
|
|
f970623edf | ||
|
|
b4c1587478 | ||
|
|
be682f2b72 | ||
|
|
86f531b6ea | ||
|
|
66e6894f95 | ||
|
|
a8a0feaf52 | ||
|
|
fc3e3636ec | ||
|
|
a796e1ee36 | ||
|
|
b49bd69abe | ||
|
|
ae550d5fc9 | ||
|
|
a485ffe41a | ||
|
|
f25a9eeade | ||
|
|
f7331a1ed3 | ||
|
|
15036f2bcc | ||
|
|
fa5723947f |
@@ -1,6 +1,39 @@
|
||||
lib_xua Change Log
|
||||
==================
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* ADDED: Support for XCommon CMake build system
|
||||
* 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,8 +1,9 @@
|
||||
lib_xua
|
||||
#######
|
||||
|
||||
:Version: 3.5.0
|
||||
:Version: 4.0.0
|
||||
:Vendor: XMOS
|
||||
|
||||
:Scope: General Use
|
||||
|
||||
Summary
|
||||
@@ -81,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
|
||||
=============
|
||||
@@ -99,4 +101,3 @@ Support
|
||||
=======
|
||||
|
||||
This package is supported by XMOS Ltd. Issues can be raised against the software at: http://www.xmos.com/support
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Required hardware
|
||||
.................
|
||||
|
||||
The example code provided with the application has been implemented
|
||||
and tested on the xCORE-200 Multi-channel Audio Board
|
||||
and tested on the xCORE.ai Multi-channel Audio Board
|
||||
|
||||
Prerequisites
|
||||
.............
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright 2017-2023 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"
|
||||
extern "C"{
|
||||
#include "sw_pll.h"
|
||||
}
|
||||
|
||||
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
||||
|
||||
@@ -34,20 +37,29 @@ void ctrlPort()
|
||||
void AudioHwInit()
|
||||
{
|
||||
/* Wait for power supply to come up */
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
||||
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
|
||||
* Note, the application PLL in xcore.ai will be configured to the correct master clock frequency
|
||||
* by lib_xua
|
||||
*/
|
||||
/* Configures the external audio hardware for the required sample frequency */
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
{
|
||||
/* Nothing required since the DAC's will auto detect the sample rate from the clocks */
|
||||
sw_pll_fixed_clock(mClk);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
// Copyright 2017-2023 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 "xassert.h"
|
||||
extern "C"{
|
||||
#include "sw_pll.h"
|
||||
}
|
||||
|
||||
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
||||
|
||||
@@ -34,20 +38,29 @@ void ctrlPort()
|
||||
void AudioHwInit()
|
||||
{
|
||||
/* Wait for power supply to come up */
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
||||
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
|
||||
* Note, the application PLL in xcore.ai will be configured to the correct master clock frequency
|
||||
* by lib_xua
|
||||
*/
|
||||
/* Configures the external audio hardware for the required sample frequency */
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
{
|
||||
/* Nothing required since the DAC's will auto detect the sample rate from the clocks */
|
||||
sw_pll_fixed_clock(mClk);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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_
|
||||
@@ -19,29 +19,35 @@
|
||||
* This function drives I2S ports and handles samples to/from other digital
|
||||
* I/O threads.
|
||||
*
|
||||
* \param c_aud Audio sample channel connected to the mixer() thread or the
|
||||
* decouple() thread
|
||||
* \param c_aud Audio sample channel connected to the mixer() thread or the
|
||||
* decouple() thread
|
||||
*
|
||||
* \param clk_audio_mclk Nullable clockblock to be clocked from master clock
|
||||
* \param clk_audio_mclk Nullable clockblock to be clocked from master clock
|
||||
*
|
||||
* \param clk_audio_bclk Nullable clockblock to be clocked from i2s bit clock
|
||||
* \param clk_audio_bclk Nullable clockblock to be clocked from i2s bit clock
|
||||
*
|
||||
* \param p_mclk_in Master clock inport port (must be 1-bit)
|
||||
* \param p_mclk_in Master clock inport port (must be 1-bit)
|
||||
*
|
||||
* \param p_lrclk Nullable port for I2S sample clock
|
||||
* \param p_lrclk Nullable port for I2S sample clock
|
||||
*
|
||||
* \param p_bclk Nullable port for I2S bit
|
||||
* \param p_bclk Nullable port for I2S bit clock
|
||||
*
|
||||
* \param p_i2s_dac Nullable array of ports for I2S data output lines
|
||||
* \param p_i2s_dac Nullable array of ports for I2S data output lines
|
||||
*
|
||||
* \param p_i2s_adc Nullable array of ports for I2S data input lines
|
||||
* \param p_i2s_adc Nullable array of ports for I2S data input lines
|
||||
*
|
||||
* \param i_SoftPll Interface to software PLL task
|
||||
* \param i_SoftPll Interface to software PLL task
|
||||
*
|
||||
* \param c_spdif_tx Channel connected to S/PDIF transmiter core from lib_spdif
|
||||
* \param c_spdif_tx Channel connected to S/PDIF transmitter core from lib_spdif
|
||||
*
|
||||
* \param c_dig Channel connected to the clockGen() thread for
|
||||
* receiving/transmitting samples
|
||||
* \param c_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,
|
||||
@@ -51,25 +57,36 @@ void XUA_AudioHub(chanend ?c_aud,
|
||||
buffered _XUA_CLK_DIR port:32 ?p_bclk,
|
||||
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
|
||||
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]
|
||||
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
, client interface SoftPll_if i_SoftPll
|
||||
#endif
|
||||
#if (XUA_SPDIF_TX_EN) || defined(__DOXYGEN__)
|
||||
, chanend c_spdif_tx
|
||||
#endif
|
||||
#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
|
||||
);
|
||||
|
||||
void SpdifTxWrapper(chanend c_spdif_tx);
|
||||
|
||||
/* These functions must be implemented for the CODEC/ADC/DAC arrangement of a specific design */
|
||||
|
||||
/* Any required clocking and CODEC initialisation - run once at start up */
|
||||
/* TODO Provide default implementation of this */
|
||||
void AudioHwInit();
|
||||
|
||||
/* Configure audio hardware (clocking, CODECs etc) for a specific mClk/Sample frquency - run on every sample frequency change */
|
||||
/* TODO Provide default implementation of this */
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode,
|
||||
unsigned sampRes_DAC, unsigned sampRes_ADC);
|
||||
|
||||
#endif // __XC__
|
||||
|
||||
/**
|
||||
@@ -91,7 +108,10 @@ void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudi
|
||||
*
|
||||
* 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();
|
||||
void UserBufferManagementInit(unsigned sampFreq);
|
||||
|
||||
#endif // _XUA_AUDIOHUB_H_
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// Copyright 2011-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_BUFFER_H_
|
||||
#define _XUA_BUFFER_H_
|
||||
@@ -13,20 +13,21 @@
|
||||
* Most of the chanend parameters to the function should be connected to
|
||||
* XUD_Manager(). The uses two cores.
|
||||
*
|
||||
* \param c_aud_out Audio OUT endpoint channel connected to the XUD
|
||||
* \param c_aud_in Audio IN endpoint channel connected to the XUD
|
||||
* \param c_aud_fb Audio feedback endpoint channel connected to the XUD
|
||||
* \param c_midi_from_host MIDI OUT endpoint channel connected to the XUD
|
||||
* \param c_midi_to_host MIDI IN endpoint channel connected to the XUD
|
||||
* \param c_midi Channel connected to MIDI core
|
||||
* \param c_int Audio clocking interrupt endpoint channel connected to the XUD
|
||||
* \param c_clk_int Optional chanend connected to the clockGen() thread if present
|
||||
* \param c_sof Start of frame channel connected to the XUD
|
||||
* \param c_aud_ctl Audio control channel connected to Endpoint0()
|
||||
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
|
||||
* \param c_aud Channel connected to XUA_AudioHub() core
|
||||
* \param i_pll_ref Interface to task that toggles reference pin to CS2100
|
||||
* \param c_swpll_update Channel connected to software PLL task. Expects master clock counts based on USB frames.
|
||||
* \param c_aud_out Audio OUT endpoint channel connected to the XUD
|
||||
* \param c_aud_in Audio IN endpoint channel connected to the XUD
|
||||
* \param c_aud_fb Audio feedback endpoint channel connected to the XUD
|
||||
* \param c_midi_from_host MIDI OUT endpoint channel connected to the XUD
|
||||
* \param c_midi_to_host MIDI IN endpoint channel connected to the XUD
|
||||
* \param c_midi Channel connected to MIDI core
|
||||
* \param c_int Audio clocking interrupt endpoint channel connected to the XUD
|
||||
* \param c_clk_int Optional chanend connected to the clockGen() thread if present
|
||||
* \param c_sof Start of frame channel connected to the XUD
|
||||
* \param c_aud_ctl Audio control channel connected to Endpoint0()
|
||||
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
|
||||
* \param c_aud Channel connected to XUA_AudioHub() core
|
||||
* \param c_audio_rate_change Channel to notify and synchronise on audio rate change
|
||||
* \param i_pll_ref Interface to task that toggles reference pin to CS2100
|
||||
* \param c_swpll_update Channel connected to software PLL task. Expects master clock counts based on USB frames.
|
||||
*/
|
||||
void XUA_Buffer(
|
||||
chanend c_aud_out,
|
||||
@@ -39,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,
|
||||
@@ -53,10 +54,11 @@ void XUA_Buffer(
|
||||
#endif
|
||||
, chanend c_aud
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
|
||||
#if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
, chanend c_audio_rate_change
|
||||
#if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
#if (XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||
, chanend c_swpll_update
|
||||
#endif
|
||||
#endif
|
||||
@@ -72,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,
|
||||
@@ -88,10 +90,11 @@ void XUA_Buffer_Ep(chanend c_aud_out,
|
||||
, chanend c_buff_ctrl
|
||||
#endif
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
|
||||
#if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
, chanend c_audio_rate_change
|
||||
#if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
#if (XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||
, chanend c_swpll_update
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// 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 _CLOCKING_H_
|
||||
#define _CLOCKING_H_
|
||||
|
||||
#include <xs1.h>
|
||||
#include "xua.h"
|
||||
|
||||
#include "sw_pll_wrapper.h"
|
||||
|
||||
interface pll_ref_if
|
||||
{
|
||||
@@ -19,56 +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);
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
struct SoftPllState
|
||||
{
|
||||
// Count we expect on MCLK port timer at SW PLL check point.
|
||||
// Note, we expect wrapping so this is essentiually a modulus
|
||||
unsigned expectedClkMod;
|
||||
unsigned initialSetting;
|
||||
unsigned initialErrorMult;
|
||||
unsigned setting;
|
||||
|
||||
int phaseError;
|
||||
|
||||
/* Integrated phase error */
|
||||
int phaseErrorInt;
|
||||
|
||||
/* IIR filter */
|
||||
int iir_y;
|
||||
|
||||
/* Delta sigma modulator */
|
||||
unsigned ds_in;
|
||||
int ds_x1;
|
||||
int ds_x2;
|
||||
int ds_x3;
|
||||
};
|
||||
|
||||
void AppPllEnable(tileref tile, int mclkFreq_hz);
|
||||
void AppPllGetSettings(int clkFreq_hz, struct SoftPllState &pllState);
|
||||
void AppPllUpdate(tileref tile, unsigned short mclk_pt, struct SoftPllState &pllState);
|
||||
|
||||
interface SoftPll_if
|
||||
{
|
||||
void init(int mclk_hz);
|
||||
};
|
||||
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
||||
[[distributable]]
|
||||
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
|
||||
void XUA_SoftPll(tileref tile, server interface SoftPll_if i_softPll, chanend c_update);
|
||||
);
|
||||
|
||||
#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
|
||||
@@ -265,21 +265,16 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable/disable the use of the secondary/application PLL for generating master-clocks.
|
||||
* @brief Enable/disable the use of the secondary/application PLL for generating and recovering master-clocks.
|
||||
* Only available on xcore.ai devices.
|
||||
*
|
||||
* Default: Enabled (for xcore.ai devices)
|
||||
*/
|
||||
#ifndef XUA_USE_APP_PLL
|
||||
#ifndef XUA_USE_SW_PLL
|
||||
#if defined(__XS3A__)
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
/* Currently must use an external CS2100 device for syncing to external digital streams */
|
||||
#define XUA_USE_APP_PLL (0)
|
||||
#else
|
||||
#define XUA_USE_APP_PLL (1)
|
||||
#endif
|
||||
#define XUA_USE_SW_PLL (1)
|
||||
#else
|
||||
#define XUA_USE_APP_PLL (0)
|
||||
#define XUA_USE_SW_PLL (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1049,7 +1044,7 @@
|
||||
* Default: 1 (Enabled)
|
||||
*/
|
||||
#ifndef OUTPUT_VOLUME_CONTROL
|
||||
#define OUTPUT_VOLUME_CONTROL (1)
|
||||
#define OUTPUT_VOLUME_CONTROL (1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -1058,7 +1053,7 @@
|
||||
* Default: 1 (Enabled)
|
||||
*/
|
||||
#ifndef INPUT_VOLUME_CONTROL
|
||||
#define INPUT_VOLUME_CONTROL (1)
|
||||
#define INPUT_VOLUME_CONTROL (1)
|
||||
#endif
|
||||
|
||||
/* Power */
|
||||
@@ -1110,7 +1105,7 @@
|
||||
*/
|
||||
#if (MIXER)
|
||||
#ifndef MAX_MIX_COUNT
|
||||
#define MAX_MIX_COUNT (8)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
#endif
|
||||
#else
|
||||
#ifndef MAX_MIX_COUNT
|
||||
@@ -1190,7 +1185,11 @@
|
||||
|
||||
/* Handle out volume control in the mixer - enabled by default */
|
||||
#ifndef OUT_VOLUME_IN_MIXER
|
||||
#define OUT_VOLUME_IN_MIXER (1)
|
||||
#if MIXER
|
||||
#define OUT_VOLUME_IN_MIXER (1)
|
||||
#else
|
||||
#define OUT_VOLUME_IN_MIXER (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */
|
||||
@@ -1203,7 +1202,7 @@
|
||||
#define IN_VOLUME_IN_MIXER (0)
|
||||
#endif
|
||||
|
||||
/* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
|
||||
/* Apply in volume controls after the mix. Only relevant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
|
||||
#ifndef IN_VOLUME_AFTER_MIX
|
||||
#define IN_VOLUME_AFTER_MIX (1)
|
||||
#endif
|
||||
@@ -1404,7 +1403,7 @@ enum USBEndpointNumber_Out
|
||||
/* Some defines that allow us to remove unused code */
|
||||
|
||||
/* Useful for dropping lower part of macs in volume processing... */
|
||||
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
|
||||
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || \
|
||||
(((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \
|
||||
(((FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 2))
|
||||
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1
|
||||
@@ -1438,29 +1437,29 @@ enum USBEndpointNumber_Out
|
||||
#endif
|
||||
|
||||
/* Useful for dropping lower part of macs in volume processing... */
|
||||
#if (FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) || (FS_STREAM_FORMAT_INPUT_2_RESOLUTION_BITS > 24)
|
||||
#define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 0
|
||||
#endif
|
||||
#if (FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24)
|
||||
#define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 0
|
||||
#endif
|
||||
|
||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4))
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 0
|
||||
#endif
|
||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4))
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 0
|
||||
#endif
|
||||
|
||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3))
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 0
|
||||
#endif
|
||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3))
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 0
|
||||
#endif
|
||||
|
||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2))
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 0
|
||||
#endif
|
||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2))
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 0
|
||||
#endif
|
||||
|
||||
#if MAX_FREQ < MIN_FREQ
|
||||
#error MAX_FREQ should be >= MIN_FREQ!!
|
||||
|
||||
@@ -38,7 +38,7 @@ Frequencies and Clocks
|
||||
.. doxygendefine:: DEFAULT_FREQ
|
||||
.. doxygendefine:: MCLK_441
|
||||
.. doxygendefine:: MCLK_48
|
||||
.. doxygendefine:: XUA_USE_APP_PLL
|
||||
.. doxygendefine:: XUA_USE_SW_PLL
|
||||
|
||||
Audio Class
|
||||
-----------
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
|
||||
|newpage|
|
||||
|
||||
Synchronisation & Clocking
|
||||
==========================
|
||||
Synchronisation
|
||||
===============
|
||||
|
||||
The codebase supports "Synchronous" and "Asynchronous" modes for USB transfer as defined by the
|
||||
The codebase supports "Synchronous" and "Asynchronous" modes for USB transfer as defined by the
|
||||
USB specification(s).
|
||||
|
||||
Asynchronous mode (``XUA_SYNCMODE_ASYNC``) has the advantage that the device is clock-master. This means that
|
||||
a high-quality local master-clock source can be utilised. It also has the benefit that the device may
|
||||
synchronise it's master clock to an external digital input stream e.g. S/PDIF thus avoiding sample-rate
|
||||
Asynchronous mode (``XUA_SYNCMODE_ASYNC``) has the advantage that the device is clock-master. This means that
|
||||
a high-quality local master-clock source can be utilised. It also has the benefit that the device may
|
||||
synchronise it's master clock to an external digital input stream e.g. S/PDIF and thus avoiding sample-rate
|
||||
conversion.
|
||||
|
||||
The drawback of this mode is that it burdens the host with syncing to the device which some hosts
|
||||
The drawback of this mode is that it burdens the host with syncing to the device which some hosts
|
||||
may not support. This is especially pertinent to embedded hosts, however, most PC's and mobile devices
|
||||
will indeed support this mode.
|
||||
|
||||
Synchronous mode (``XUA_SYNCMODE_SYNC``) is an option if the target host does not support asynchronous mode
|
||||
or if it is desirable to synchronise many devices to a single host. It should be noted, however, that input
|
||||
or if it is desirable to synchronise many devices to a single host. It should be noted, however, that input
|
||||
from digital streams, such as S/PDIF, are not currently supported in this mode.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
The selection of synchronisation mode is done at build time and cannot be changed dynamically.
|
||||
|
||||
Setting the synchronisation mode of the device is done using the define in :ref:`opt_sync_defines`
|
||||
@@ -39,17 +39,13 @@ Setting the synchronisation mode of the device is done using the define in :ref:
|
||||
- USB synchronisation mode
|
||||
- ``XUA_SYNCMODE_ASYNC``
|
||||
|
||||
When operating in asynchronous mode xcore.ai based devices will be configured, by default, to use their internal
|
||||
"Applications" PLL to generated an appropriate master-clock signal. To disable this ``XUA_USE_APP_PLL`` should be
|
||||
set to ``0``. For all other devices the developer is expected to supply external master-clock generation circuitry.
|
||||
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.
|
||||
|
||||
When operating in synchronous mode an xcore.ai based device, by default, will be configured to used it's internal
|
||||
"application" PLL to generate a master-clock synchronised to the USB host.
|
||||
|
||||
xcore-200 based devices do not have this application PLL and so an external Cirrus Logic CS2100 device is required
|
||||
for master clock generation. The codebase expects to drive a synchronisation signal to this external device.
|
||||
|
||||
In this case the developer should ensure the define in :ref:`opt_sync_ref_defines` is set appropriately.
|
||||
The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set appropriately.
|
||||
|
||||
.. _opt_sync_ref_defines:
|
||||
|
||||
@@ -63,34 +59,14 @@ In this case the developer should ensure the define in :ref:`opt_sync_ref_define
|
||||
* - ``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"/>
|
||||
|
||||
Configuration of the external CS2100 device (typically via I2C) is beyond the scope of this document.
|
||||
|
||||
Note, in all cases the master-clocks are generated (when using the xcore.ai Application PLL) or should be generated
|
||||
(if using external circuitry) to match the defines in :ref:`opt_sync_mclk_defines`.
|
||||
|
||||
.. _opt_sync_mclk_defines:
|
||||
|
||||
.. list-table:: Master clock frequencies
|
||||
:header-rows: 1
|
||||
:widths: 20 80 20
|
||||
|
||||
* - Define
|
||||
- Description
|
||||
- Default
|
||||
* - ``MCLK_48``
|
||||
- Master clock frequency (in Hz)used for sample-rates related to 48KHz
|
||||
- NOTE
|
||||
* - ``MCLK_441``
|
||||
- Master clock frequency (in Hz) used for sample-rates related to 44.1KHz
|
||||
- NONE
|
||||
|
||||
.. note::
|
||||
|
||||
The master clock defines above are critical for proper operation and default values are not provided.
|
||||
If they are not defined by the devloper a build error will be emmited.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
53
lib_xua/lib_build_info.cmake
Normal file
53
lib_xua/lib_build_info.cmake
Normal file
@@ -0,0 +1,53 @@
|
||||
set(LIB_NAME lib_xua)
|
||||
set(LIB_VERSION 4.0.0)
|
||||
set(LIB_INCLUDES api
|
||||
src/core
|
||||
src/core/audiohub
|
||||
src/core/buffer/ep
|
||||
src/core/endpoint0
|
||||
src/dfu
|
||||
src/core/buffer/decouple
|
||||
src/core/clocking
|
||||
src/core/mixer
|
||||
src/core/pdm_mics
|
||||
src/core/ports
|
||||
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_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)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
list(APPEND LIB_COMPILER_FLAGS -DXASSERT_ENABLE_ASSERTIONS=1
|
||||
-DXASSERT_ENABLE_DEBUG=1
|
||||
-DXASSERT_ENBALE_LINE_NUMBERS=1)
|
||||
else()
|
||||
list(APPEND LIB_COMPILER_FLAGS -DXASSERT_ENABLE_ASSERTIONS=0
|
||||
-DXASSERT_ENABLE_DEBUG=0
|
||||
-DXASSERT_ENABLE_LINE_NUMBERS=0)
|
||||
endif()
|
||||
|
||||
set(LIB_COMPILER_FLAGS_xua_endpoint0.c ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||
set(LIB_COMPILER_FLAGS_xua_ep0_uacreqs.xc ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||
set(LIB_COMPILER_FLAGS_dbcalc.xc ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||
set(LIB_COMPILER_FLAGS_audioports.c ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||
set(LIB_COMPILER_FLAGS_audioports.xc ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||
set(LIB_COMPILER_FLAGS_dfu.xc ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||
set(LIB_COMPILER_FLAGS_flash_interface.c ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||
set(LIB_COMPILER_FLAGS_flashlib_user.c ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||
|
||||
XMOS_REGISTER_MODULE()
|
||||
@@ -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,9 +54,9 @@ 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/core/user/audiohw \
|
||||
src/hid \
|
||||
src/midi
|
||||
|
||||
@@ -70,8 +71,8 @@ SOURCE_DIRS = src/core \
|
||||
src/core/ports \
|
||||
src/core/support \
|
||||
src/core/user/audiostream \
|
||||
src/core/user/hostactive \
|
||||
src/core/user/audiohw \
|
||||
src/core/user/hostactive \
|
||||
src/core/xuduser \
|
||||
src/dfu \
|
||||
src/hid \
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -38,12 +38,12 @@ void InitPorts_master(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_D
|
||||
#endif
|
||||
|
||||
unsigned tmp;
|
||||
|
||||
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_lrclk <: 0 @ tmp;
|
||||
else
|
||||
tmp = partout_timestamped(p_lrclk, XUA_I2S_N_BITS, 0);
|
||||
|
||||
|
||||
tmp += 100;
|
||||
|
||||
/* Since BCLK is free-running, setup outputs/inputs at a known point in the future */
|
||||
@@ -72,7 +72,7 @@ void InitPorts_master(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_D
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
|
||||
|
||||
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_i2s_adc[i], XUA_I2S_N_BITS);
|
||||
}
|
||||
@@ -127,13 +127,13 @@ void InitPorts_slave(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DI
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_i2s_adc[i], XUA_I2S_N_BITS);
|
||||
}
|
||||
#endif
|
||||
|
||||
asm("setpt res[%0], %1"::"r"(p_lrclk),"r"(tmp-1));
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_lrclk, XUA_I2S_N_BITS);
|
||||
#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -17,10 +17,10 @@
|
||||
#include <string.h>
|
||||
#include <xassert.h>
|
||||
|
||||
|
||||
#include "xua.h"
|
||||
|
||||
#include "audiohw.h"
|
||||
|
||||
#include "audioports.h"
|
||||
#include "mic_array_conf.h"
|
||||
#if (XUA_SPDIF_TX_EN)
|
||||
@@ -242,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{
|
||||
@@ -636,15 +636,15 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
buffered _XUA_CLK_DIR port:32 ?p_bclk,
|
||||
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
|
||||
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]
|
||||
#if (XUA_USE_APP_PLL)
|
||||
, client interface SoftPll_if i_softPll
|
||||
#endif
|
||||
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
, chanend c_spdif_out
|
||||
#endif
|
||||
#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,12 +666,6 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
unsigned divide;
|
||||
unsigned firstRun = 1;
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
/* Use xCORE.ai Secondary PLL to generate master clock
|
||||
* This could be "fixed" for async mode or adjusted if in sync mode */
|
||||
i_softPll.init(DEFAULT_MCLK);
|
||||
#endif
|
||||
|
||||
/* Clock master clock-block from master-clock port */
|
||||
/* Note, marked unsafe since other cores may be using this mclk port */
|
||||
configure_clock_src(clk_audio_mclk, p_mclk_in);
|
||||
@@ -697,8 +691,6 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Perform required CODEC/ADC/DAC initialisation */
|
||||
AudioHwInit();
|
||||
|
||||
@@ -810,16 +802,21 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
curFreq *= 16;
|
||||
}
|
||||
#endif
|
||||
/* Configure Clocking/CODEC/DAC/ADC for SampleFreq/MClk */
|
||||
|
||||
/* User should mute audio hardware */
|
||||
AudioHwConfig_Mute();
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
i_softPll.init(mClk);
|
||||
#endif
|
||||
|
||||
/* User code should configure audio harware for SampleFreq/MClk etc */
|
||||
AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC);
|
||||
#if (XUA_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();
|
||||
@@ -829,7 +826,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
{
|
||||
/* TODO wait for good mclk instead of delay */
|
||||
/* No delay for DFU modes */
|
||||
if (((curSamFreq / AUD_TO_USB_RATIO) != AUDIO_REBOOT_FROM_DFU) && ((curSamFreq / AUD_TO_USB_RATIO) != AUDIO_STOP_FOR_DFU) && command)
|
||||
if (((curSamFreq / AUD_TO_USB_RATIO) != AUDIO_STOP_FOR_DFU) && command)
|
||||
{
|
||||
#if 0
|
||||
/* User should ensure MCLK is stable in AudioHwConfig */
|
||||
@@ -939,13 +936,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
#else
|
||||
dummy_deliver(c_aud, command);
|
||||
#endif
|
||||
/* Note, we do not expect to reach here */
|
||||
curSamFreq = inuint(c_aud);
|
||||
|
||||
if (curSamFreq == AUDIO_START_FROM_DFU)
|
||||
{
|
||||
outct(c_aud, XS1_CT_END);
|
||||
break;
|
||||
}
|
||||
outct(c_aud, XS1_CT_END);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -514,7 +514,7 @@ __builtin_unreachable();
|
||||
{
|
||||
/* Finished creating packet - commit it to the FIFO */
|
||||
/* Total samps to write could start at 0 (i.e. no MCLK) so need to check for < 0) */
|
||||
if (sampsToWrite <= 0)
|
||||
if(sampsToWrite <= 0)
|
||||
{
|
||||
int speed, wrPtr;
|
||||
packState = 0;
|
||||
@@ -651,6 +651,7 @@ __builtin_unreachable();
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
|
||||
/* TODO We should properly size zeros packet rather than using "mid" */
|
||||
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
|
||||
xc_ptr aud_to_host_zeros)
|
||||
{
|
||||
@@ -659,8 +660,8 @@ static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned samp
|
||||
|
||||
/* Set IN stream packet size to something sensible. We expect the buffer to
|
||||
* over flow and this to be reset */
|
||||
SET_SHARED_GLOBAL(sampsToWrite, 0);
|
||||
SET_SHARED_GLOBAL(totalSampsToWrite, 0);
|
||||
SET_SHARED_GLOBAL(sampsToWrite, mid);
|
||||
SET_SHARED_GLOBAL(totalSampsToWrite, mid);
|
||||
|
||||
mid *= g_numUsbChan_In * slotSize;
|
||||
|
||||
@@ -821,6 +822,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||
#endif
|
||||
|
||||
#if (NUM_USB_CHAN_OUT > 0)
|
||||
/* Reset OUT buffer state */
|
||||
outUnderflow = 1;
|
||||
SET_SHARED_GLOBAL(g_aud_from_host_rdptr, aud_from_host_fifo_start);
|
||||
@@ -830,9 +832,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
if(outOverflow)
|
||||
{
|
||||
/* If we were previously in overflow we wont have marked as ready */
|
||||
XUD_SetReady_OutPtr(aud_from_host_usb_ep, aud_from_host_fifo_start+4);
|
||||
XUD_SetReady_OutPtr(aud_from_host_usb_ep, aud_from_host_fifo_start + 4);
|
||||
outOverflow = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Wait for handshake back and pass back up */
|
||||
@@ -906,6 +909,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
GET_SHARED_GLOBAL(dataFormat, g_formatChange_DataFormat);
|
||||
GET_SHARED_GLOBAL(sampRes, g_formatChange_SampRes);
|
||||
|
||||
#if (NUM_USB_CHAN_OUT > 0)
|
||||
/* Reset OUT buffer state */
|
||||
SET_SHARED_GLOBAL(g_aud_from_host_rdptr, aud_from_host_fifo_start);
|
||||
SET_SHARED_GLOBAL(g_aud_from_host_wrptr, aud_from_host_fifo_start);
|
||||
@@ -921,6 +925,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
XUD_SetReady_OutPtr(aud_from_host_usb_ep, aud_from_host_fifo_start+4);
|
||||
outOverflow = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NATIVE_DSD
|
||||
if(dataFormat == UAC_FORMAT_TYPEI_RAW_DATA)
|
||||
@@ -1041,7 +1046,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
|
||||
DISABLE_INTERRUPTS();
|
||||
|
||||
if (inUnderflow)
|
||||
if(inUnderflow)
|
||||
{
|
||||
int fillLevel;
|
||||
GET_SHARED_GLOBAL(fillLevel, g_aud_to_host_fill_level);
|
||||
|
||||
@@ -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,8 +105,9 @@ void XUA_Buffer(
|
||||
#endif
|
||||
, chanend c_aud
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if(XUA_USE_APP_PLL)
|
||||
, chanend c_swpll_update
|
||||
, chanend c_audio_rate_change
|
||||
#if(XUA_USE_SW_PLL)
|
||||
, chanend c_sw_pll
|
||||
#else
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
@@ -145,8 +146,9 @@ void XUA_Buffer(
|
||||
, c_buff_ctrl
|
||||
#endif
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if(XUA_USE_APP_PLL)
|
||||
, c_swpll_update
|
||||
, c_audio_rate_change
|
||||
#if(XUA_USE_SW_PLL)
|
||||
, c_sw_pll
|
||||
#else
|
||||
, i_pll_ref
|
||||
#endif
|
||||
@@ -199,8 +201,9 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
, chanend c_buff_ctrl
|
||||
#endif
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if (XUA_USE_APP_PLL)
|
||||
, chanend c_swpll_update
|
||||
, chanend c_audio_rate_change
|
||||
#if (XUA_USE_SW_PLL)
|
||||
, chanend c_sw_pll
|
||||
#else
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
@@ -260,7 +263,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
unsigned bufferIn = 1;
|
||||
#endif
|
||||
int sofCount = 0;
|
||||
int pllUpdate = 0;
|
||||
|
||||
unsigned mod_from_last_time = 0;
|
||||
#ifdef FB_TOLERANCE_TEST
|
||||
@@ -370,7 +372,23 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
#define LOCAL_CLOCK_MARGIN (1000)
|
||||
#endif
|
||||
|
||||
#if (!XUA_USE_APP_PLL)
|
||||
#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;
|
||||
@@ -379,7 +397,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
i_pll_ref.toggle();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) */
|
||||
|
||||
while(1)
|
||||
{
|
||||
@@ -444,7 +462,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
/* Note, Endpoint 0 will hold off host for a sufficient period to allow our feedback
|
||||
* to stabilise (i.e. sofCount == 128 to fire) */
|
||||
sofCount = 0;
|
||||
pllUpdate = 0;
|
||||
clocks = 0;
|
||||
clockcounter = 0;
|
||||
mod_from_last_time = 0;
|
||||
@@ -467,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 */
|
||||
@@ -525,7 +542,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL)
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_SW_PLL)
|
||||
case t_sofCheck when timerafter(timeNextEdge) :> void:
|
||||
i_pll_ref.toggle();
|
||||
timeLastEdge = timeNextEdge;
|
||||
@@ -540,41 +557,60 @@ 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)
|
||||
{
|
||||
sofCount = 0;
|
||||
pllUpdate++;
|
||||
#if (!XUA_USE_APP_PLL)
|
||||
#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;
|
||||
timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
#endif
|
||||
#endif /* (XUA_USE_SW_PLL) */
|
||||
sofCount = 0;
|
||||
}
|
||||
#if (XUA_USE_APP_PLL)
|
||||
// Update PLL @ 100Hz
|
||||
if(pllUpdate == 10)
|
||||
{
|
||||
pllUpdate = 0;
|
||||
unsigned short mclk_pt;
|
||||
asm volatile("getts %0, res[%1]" : "=r" (mclk_pt) : "r" (p_off_mclk));
|
||||
outuint(c_swpll_update, mclk_pt);
|
||||
outct(c_swpll_update, XS1_CT_END);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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)
|
||||
|
||||
@@ -721,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);
|
||||
@@ -993,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,457 +0,0 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <print.h>
|
||||
#include <platform.h>
|
||||
#include "xua.h"
|
||||
#include "xassert.h"
|
||||
#include <stdio.h>
|
||||
#if (XUA_USE_APP_PLL)
|
||||
|
||||
/*
|
||||
* Functions for interacting with the secondary/application PLL
|
||||
*/
|
||||
|
||||
#ifndef __XS3A__
|
||||
#error App PLL not included in device
|
||||
#endif
|
||||
|
||||
/*
|
||||
* App PLL settings used for syncing to external clocks
|
||||
*/
|
||||
|
||||
// Define the PLL settings to generate the required frequencies.
|
||||
// All settings allow greater than +-1000ppm lock range.
|
||||
// Comment out the following line for 2us update.
|
||||
|
||||
//#define FAST_FRAC_REG_WRITE
|
||||
|
||||
// OPTION 1 - 1us register update rate - Lowest jitter
|
||||
// 10ps jitter 100Hz-40kHz. Low freq noise floor -100dBc
|
||||
|
||||
#ifdef FAST_FRAC_REG_WRITE
|
||||
|
||||
#define FRAC_REG_WRITE_DLY (100)
|
||||
|
||||
// Found solution: IN 24.000MHz, OUT 22.578947MHz, VCO 3251.37MHz, RD 1, FD 135.474 (m = 9, n = 19), OD 6, FOD 6, ERR -11.189ppm
|
||||
#define APP_PLL_CTL_SYNC_22M (0x0A808600)
|
||||
#define APP_PLL_DIV_SYNC_22M (0x80000005)
|
||||
#define APP_PLL_FRAC_SYNC_22M (0x80000812)
|
||||
#define APP_PLL_ERR_MULT_22M (627) // round(135(divider)*100Hz*1048576/22579200)
|
||||
#define APP_PLL_MOD_INIT_22M (498283)
|
||||
|
||||
// Fout = Fin*divider/(2*2*6*6) = (fin/144) * divider = (24/144) * divider. = 1/6 * divider.
|
||||
// To achieve frequency f, Fraction Setting = (6*f) - 135
|
||||
// So to achieve 22.5792MHz, Fraction Setting = (6*22.5792) - 135 = 0.4752
|
||||
// Numerical input = round((Fraction setting * 2^20) = 0.4752 * 1048576 = 498283
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 24.575758MHz, VCO 3538.91MHz, RD 1, FD 147.455 (m = 5, n = 11), OD 6, FOD 6, ERR -9.864ppm
|
||||
#define APP_PLL_CTL_SYNC_24M (0x0A809200)
|
||||
#define APP_PLL_DIV_SYNC_24M (0x80000005)
|
||||
#define APP_PLL_FRAC_SYNC_24M (0x8000040A)
|
||||
#define APP_PLL_ERR_MULT_24M (627) // round(147(divider)*100Hz*1048576/24576000)
|
||||
#define APP_PLL_MOD_INIT_24M (478151)
|
||||
|
||||
// Fout = Fin*divider/(2*2*6*6) = (fin/144) * divider = (24/144) * divider. = 1/6 * divider.
|
||||
// To achieve frequency f, Fraction Setting = (6*f) - 147
|
||||
// So to achieve 24.576MHz, Fraction Setting = (6*24.576) - 147 = 0.456
|
||||
// Numerical input = round((Fraction setting * 2^20) = 0.456 * 1048576 = 478151
|
||||
|
||||
#else
|
||||
|
||||
// OPTION 2 - 2us register update rate - Higher jitter
|
||||
// 50ps jitter 100Hz-40kHz. Low freq noise floor -93dBc
|
||||
|
||||
#define FRAC_REG_WRITE_DLY (200)
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 22.579186MHz, VCO 3522.35MHz, RD 2, FD 293.529 (m = 9, n = 17), OD 3, FOD 13, ERR -0.641ppm
|
||||
#define APP_PLL_CTL_SYNC_22M (0x09012401)
|
||||
#define APP_PLL_DIV_SYNC_22M (0x8000000C)
|
||||
#define APP_PLL_FRAC_SYNC_22M (0x80000810)
|
||||
#define APP_PLL_ERR_MULT_22M (1361) // round(293(divider)*100Hz*1048576/22579200)
|
||||
#define APP_PLL_MOD_INIT_22M (555326)
|
||||
|
||||
// Fout = (Fin/2)*divider/(2*2*3*13) = (fin/312) * divider = (24/312) * divider. = 1/13 * divider.
|
||||
// To achieve frequency f, Fraction Setting = (13*f) - 293
|
||||
// So to achieve 22.5792MHz, Fraction Setting = (13*22.5792) - 293 = 0.5296
|
||||
// Numerical input = round((Fraction setting * 2^20) = 0.5296 * 1048576 = 555326
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 24.576125MHz, VCO 3342.35MHz, RD 2, FD 278.529 (m = 9, n = 17), OD 2, FOD 17, ERR 5.069ppm - Runs VCO out fractionally out of spec at 835MHz
|
||||
#define APP_PLL_CTL_SYNC_24M (0x08811501)
|
||||
#define APP_PLL_DIV_SYNC_24M (0x80000010)
|
||||
#define APP_PLL_FRAC_SYNC_24M (0x80000810)
|
||||
#define APP_PLL_ERR_MULT_24M (1186) // round(278(divider)*100Hz*1048576/24576000)
|
||||
#define APP_PLL_MOD_INIT_24M (553648)
|
||||
|
||||
// Fout = (Fin/2)*divider/(2*2*2*17) = (fin/272) * divider = (24/272) * divider. = 3/34 * divider.
|
||||
// To achieve frequency f, Fraction Setting = ((34/3)*f) - 278
|
||||
// So to achieve 24.576MHz, Fraction Setting = ((34/3)*24.576) - 278 = 0.528
|
||||
// Numerical input = round((Fraction setting * 2^20) = 0.528 * 1048576 = 553648
|
||||
#endif
|
||||
|
||||
/*
|
||||
* App PLL settings used for low jitter fixed local clocks
|
||||
*/
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 49.151786MHz, VCO 3145.71MHz, RD 1, FD 131.071 (m = 1, n = 14), OD 8, FOD 2, ERR -4.36ppm
|
||||
// Measure: 100Hz-40kHz: ~7ps
|
||||
// 100Hz-1MHz: 70ps.
|
||||
// 100Hz high pass: 118ps.
|
||||
#define APP_PLL_CTL_FIXED_49M (0x0B808200)
|
||||
#define APP_PLL_DIV_FIXED_49M (0x80000001)
|
||||
#define APP_PLL_FRAC_FIXED_49M (0x8000000D)
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 45.157895MHz, VCO 2709.47MHz, RD 1, FD 112.895 (m = 17, n = 19), OD 5, FOD 3, ERR -11.19ppm
|
||||
// Measure: 100Hz-40kHz: 6.5ps
|
||||
// 100Hz-1MHz: 67ps.
|
||||
// 100Hz high pass: 215ps.
|
||||
#define APP_PLL_CTL_FIXED_45M (0x0A006F00)
|
||||
#define APP_PLL_DIV_FIXED_45M (0x80000002)
|
||||
#define APP_PLL_FRAC_FIXED_45M (0x80001012)
|
||||
|
||||
// Found solution: IN 24.000MHz, OUT 24.576000MHz, VCO 2457.60MHz, RD 1, FD 102.400 (m = 2, n = 5), OD 5, FOD 5, ERR 0.0ppm
|
||||
// Measure: 100Hz-40kHz: ~8ps
|
||||
// 100Hz-1MHz: 63ps.
|
||||
// 100Hz high pass: 127ps.
|
||||
#define APP_PLL_CTL_FIXED_24M (0x0A006500)
|
||||
#define APP_PLL_DIV_FIXED_24M (0x80000004)
|
||||
#define APP_PLL_FRAC_FIXED_24M (0x80000104)
|
||||
|
||||
// Found solution: IN 24.000MHz, OUT 22.579186MHz, VCO 3522.35MHz, RD 1, FD 146.765 (m = 13, n = 17), OD 3, FOD 13, ERR -0.641ppm
|
||||
// Measure: 100Hz-40kHz: 7ps
|
||||
// 100Hz-1MHz: 67ps.
|
||||
// 100Hz high pass: 260ps.
|
||||
#define APP_PLL_CTL_FIXED_22M (0x09009100)
|
||||
#define APP_PLL_DIV_FIXED_22M (0x8000000C)
|
||||
#define APP_PLL_FRAC_FIXED_22M (0x80000C10)
|
||||
|
||||
#define APP_PLL_CTL_FIXED_12M (0x0A006500)
|
||||
#define APP_PLL_DIV_FIXED_12M (0x80000009)
|
||||
#define APP_PLL_FRAC_FIXED_12M (0x80000104)
|
||||
|
||||
#define APP_PLL_CTL_FIXED_11M (0x09009100)
|
||||
#define APP_PLL_DIV_FIXED_11M (0x80000009)
|
||||
#define APP_PLL_FRAC_FIXED_11M (0x80000C10)
|
||||
|
||||
#define APP_PLL_CTL_ENABLE (1 << 27)
|
||||
#define APP_PLL_CLK_OUTPUT_ENABLE (1 << 16)
|
||||
|
||||
static void set_app_pll_init(tileref tile, int app_pll_ctrl)
|
||||
{
|
||||
// Disable the PLL
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (app_pll_ctrl & ~APP_PLL_CTL_ENABLE));
|
||||
|
||||
// Enable the PLL to invoke a reset on the appPLL.
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctrl);
|
||||
|
||||
// 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, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctrl);
|
||||
|
||||
// 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, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (app_pll_ctrl & 0xF7FFFFFF));
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctrl);
|
||||
|
||||
// Wait for PLL to lock.
|
||||
delay_microseconds(500);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AppPllEnable(tileref tile, int clkFreq_hz)
|
||||
{
|
||||
unsigned app_pll_ctrl, app_pll_div, app_pll_frac;
|
||||
|
||||
/* Decide on App PLL settings */
|
||||
if(XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
{
|
||||
switch(clkFreq_hz)
|
||||
{
|
||||
case 44100 * 512:
|
||||
app_pll_ctrl = APP_PLL_CTL_SYNC_22M;
|
||||
app_pll_div = APP_PLL_DIV_SYNC_22M;
|
||||
app_pll_frac = APP_PLL_FRAC_SYNC_22M;
|
||||
break;
|
||||
|
||||
case 48000 * 512:
|
||||
app_pll_ctrl = APP_PLL_CTL_SYNC_24M;
|
||||
app_pll_div = APP_PLL_DIV_SYNC_24M;
|
||||
app_pll_frac = APP_PLL_FRAC_SYNC_24M;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(clkFreq_hz)
|
||||
{
|
||||
case 44100 * 256:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_11M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_11M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_11M;
|
||||
break;
|
||||
|
||||
case 48000 * 256:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_12M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_12M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_12M;
|
||||
break;
|
||||
|
||||
case 44100 * 512:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_22M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_22M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_22M;
|
||||
break;
|
||||
|
||||
case 48000 * 512:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_24M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_24M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_24M;
|
||||
break;
|
||||
|
||||
case 44100 * 1024:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_45M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_45M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_45M;
|
||||
break;
|
||||
|
||||
case 48000 * 1024:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_49M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_49M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_49M;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the AppPLL and get it running.
|
||||
set_app_pll_init(tile, app_pll_ctrl);
|
||||
|
||||
// Write the fractional-n register, note, the top bit is set to enable the frac-n block.
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, app_pll_frac);
|
||||
|
||||
// And then write the clock divider register to enable the output
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, app_pll_div);
|
||||
|
||||
// Wait for PLL output frequency to stabilise due to fractional divider enable
|
||||
delay_microseconds(100);
|
||||
}
|
||||
|
||||
void SoftPllInit(int clkFreq_hz, struct SoftPllState &pllState)
|
||||
{
|
||||
switch(clkFreq_hz)
|
||||
{
|
||||
case 44100 * 512:
|
||||
pllState.expectedClkMod = 29184; // Count we expect on MCLK port timer at SW PLL check point. For 100Hz, 10ms.
|
||||
pllState.initialSetting = APP_PLL_MOD_INIT_22M;
|
||||
pllState.initialErrorMult = APP_PLL_ERR_MULT_22M;
|
||||
break;
|
||||
|
||||
case 48000 * 512:
|
||||
pllState.expectedClkMod = 49152;
|
||||
pllState.initialSetting = APP_PLL_MOD_INIT_24M;
|
||||
pllState.initialErrorMult = APP_PLL_ERR_MULT_24M;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
pllState.ds_in = pllState.initialSetting;
|
||||
pllState.ds_x1 = 0;
|
||||
pllState.ds_x2 = 0;
|
||||
pllState.ds_x3 = 0;
|
||||
pllState.iir_y = 0;
|
||||
pllState.phaseError = 0;
|
||||
pllState.phaseErrorInt = 0;
|
||||
}
|
||||
|
||||
int SoftPllUpdate(tileref tile, unsigned short mclk_pt, unsigned short mclk_pt_last, struct SoftPllState &pllState, int fastLock)
|
||||
{
|
||||
int freq_error, error_p, error_i;
|
||||
|
||||
unsigned expectedClksMod = pllState.expectedClkMod;
|
||||
unsigned initialSetting = pllState.initialSetting;
|
||||
unsigned init_err_mult = pllState.initialErrorMult;
|
||||
|
||||
int newSetting;
|
||||
unsigned short expectedPt;
|
||||
|
||||
int set = -1;
|
||||
int diff;
|
||||
|
||||
// expectedClkMod is the value of the port counter that we expect given the desired MCLK in the 10ms time period we are running at.
|
||||
expectedPt = mclk_pt_last + expectedClksMod;
|
||||
|
||||
// Handle wrapping
|
||||
if (porttimeafter(mclk_pt, expectedPt))
|
||||
{
|
||||
diff = -(short)(expectedPt - mclk_pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = (short)(mclk_pt - expectedPt);
|
||||
}
|
||||
|
||||
// TODO Add a bounds checker on diff to make sure it's roughly where we expect.
|
||||
// If it isn't we should ignore it as it's either a glitch or from clock start/stop.
|
||||
|
||||
if(fastLock) // Fast lock - set DCO based on measured frequency error in first cycle
|
||||
{
|
||||
initialSetting = initialSetting - (diff * init_err_mult); // init_err_mult is the dco input change to cause an output frequency offset equating to a measured input freq error of 1.
|
||||
diff = 0; // reset diff to zero so following code does not see any error in this cycle.
|
||||
}
|
||||
|
||||
// Absolute frequency error for last measurement cycle. If diff is positive, port timer was beyond where it should have been, so MCLK was too fast. So this needs to describe a negative error.
|
||||
freq_error = -diff;
|
||||
|
||||
// Phase error is the integral of frequency error.
|
||||
pllState.phaseError += freq_error;
|
||||
|
||||
// Integral of phase error for use in PI loop below.
|
||||
pllState.phaseErrorInt += pllState.phaseError;
|
||||
|
||||
error_p = (pllState.phaseError << 5); // << 5 => Kp = 32
|
||||
error_i = (pllState.phaseErrorInt >> 2); // >> 2 => Ki = 0.25
|
||||
|
||||
// input to filter (x) is output of PI controller
|
||||
int x = (error_p + error_i);
|
||||
|
||||
// Filter some noise into DCO to reduce jitter
|
||||
// First order IIR, make A=0.125
|
||||
// y = y + A(x-y)
|
||||
pllState.iir_y += ((x-pllState.iir_y)>>3);
|
||||
|
||||
newSetting = pllState.iir_y;
|
||||
|
||||
// Only output new frequency tune value if different to the previous setting
|
||||
if (newSetting != pllState.setting)
|
||||
{
|
||||
set = (initialSetting + newSetting); // init_set is our calculation of the setting required after measuring one cycle, should be accurate to +- 1MCLK.
|
||||
|
||||
if (set < 0)
|
||||
set = 0;
|
||||
else if (set > 0xFFFFF)
|
||||
set = 0xFFFFF;
|
||||
}
|
||||
|
||||
pllState.setting = newSetting;
|
||||
|
||||
// Return the setting to the NCO thread. -1 means no update
|
||||
return set;
|
||||
}
|
||||
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
||||
[[distributable]]
|
||||
#endif
|
||||
void XUA_SoftPll(tileref tile, server interface SoftPll_if i_softPll, chanend c_update)
|
||||
{
|
||||
#if (XUA_SYNCMODE != XUA_SYNCMODE_ASYNC)
|
||||
unsigned frac_val;
|
||||
int ds_out;
|
||||
timer tmr;
|
||||
int time;
|
||||
unsigned mclk_pt;
|
||||
unsigned short mclk_pt_last;
|
||||
tmr :> time;
|
||||
#endif
|
||||
struct SoftPllState pllState;
|
||||
int running = 0;
|
||||
int firstUpdate = 1;
|
||||
int fastLock = 1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
select
|
||||
{
|
||||
/* Interface used for basic frequency setting such that it can be distributed
|
||||
* when the update code is not required */
|
||||
case i_softPll.init(int mclk_hz):
|
||||
AppPllEnable(tile, mclk_hz);
|
||||
SoftPllInit(mclk_hz, pllState);
|
||||
running = 1;
|
||||
firstUpdate = 1;
|
||||
fastLock = 1;
|
||||
break;
|
||||
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Channel used for update such that other side is not blocked */
|
||||
/* TODO add CT handshake before opening route */
|
||||
case inuint_byref(c_update, mclk_pt):
|
||||
inct(c_update);
|
||||
|
||||
if(firstUpdate)
|
||||
{
|
||||
firstUpdate = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int setting = SoftPllUpdate(tile, (unsigned short) mclk_pt, mclk_pt_last, pllState, fastLock);
|
||||
|
||||
fastLock = 0;
|
||||
|
||||
if(setting != -1)
|
||||
{
|
||||
pllState.ds_in = setting;
|
||||
// Limit input range for modulator stability.
|
||||
if(pllState.ds_in > 980000)
|
||||
pllState.ds_in = 980000;
|
||||
if(pllState.ds_in < 60000)
|
||||
pllState.ds_in = 60000;
|
||||
}
|
||||
}
|
||||
|
||||
mclk_pt_last = (unsigned short) mclk_pt;
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Third order, 9 level output delta sigma. 20 bit unsigned input.
|
||||
ds_out = ((pllState.ds_x3<<4) + (pllState.ds_x3<<1)) >> 13;
|
||||
if (ds_out > 8)
|
||||
ds_out = 8;
|
||||
if (ds_out < 0)
|
||||
ds_out = 0;
|
||||
pllState.ds_x3 += (pllState.ds_x2>>5) - (ds_out<<9) - (ds_out<<8);
|
||||
pllState.ds_x2 += (pllState.ds_x1>>5) - (ds_out<<14);
|
||||
pllState.ds_x1 += pllState.ds_in - (ds_out<<17);
|
||||
|
||||
if (ds_out == 0)
|
||||
frac_val = 0x00000007; // 0/8
|
||||
else
|
||||
frac_val = ((ds_out - 1) << 8) | 0x80000007; // 1/8 to 8/8
|
||||
|
||||
// Now write the register.
|
||||
// We need to write the register at a specific period at a fast rate.
|
||||
// This period needs to be (div ref clk period (ns) * how many times we repeat same value)
|
||||
// In this case, div ref clk = 24/3 = 8MHz. So div ref clk period = 125ns.
|
||||
// We're using fraction denominators of 8, so these repeat every 8*125ns = 1us.
|
||||
// So minimum period we could use is 1us and multiples thereof.
|
||||
// The slower we write, the higher our jitter will be.
|
||||
|
||||
time += FRAC_REG_WRITE_DLY; // Time the reg write.
|
||||
tmr when timerafter(time) :> void;
|
||||
|
||||
// Write the register. Because we are timing the reg writes accurately we do not need to use reg write with ack.
|
||||
// This saves a lot of time. Additionally, apparently we can shorten the time for this reg write by only setting up the channel once and just doing a few instructions to do the write each time.
|
||||
// We can hard code this in assembler.
|
||||
if(running)
|
||||
{
|
||||
write_node_config_reg_no_ack(tile, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, frac_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,6 +1,5 @@
|
||||
// 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>
|
||||
#include <print.h>
|
||||
@@ -26,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;
|
||||
|
||||
@@ -39,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)
|
||||
{
|
||||
@@ -88,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
|
||||
|
||||
@@ -141,9 +124,6 @@ static inline void setClockValidity(chanend c_interruptControl, int clkIndex, in
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Returns 1 for valid clock found else 0 */
|
||||
static inline int validSamples(Counter &counter, int clockIndex)
|
||||
{
|
||||
@@ -210,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;
|
||||
@@ -219,16 +199,11 @@ static inline int validSamples(Counter &counter, int clockIndex)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
//:badParity
|
||||
/* Returns 1 for bad parity, else 0 */
|
||||
static inline int badParity(unsigned x)
|
||||
#if XUA_USE_SW_PLL
|
||||
unsafe
|
||||
{
|
||||
unsigned X = (x>>4);
|
||||
crc32(X, 0, 1);
|
||||
return X & 1;
|
||||
unsigned * unsafe selected_mclk_rate_ptr = NULL;
|
||||
}
|
||||
//:
|
||||
#endif
|
||||
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
@@ -241,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
|
||||
@@ -258,20 +244,31 @@ 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)
|
||||
/* S/PDIF buffer state */
|
||||
int spdifSamples[MAX_SPDIF_SAMPLES]; /* S/PDIF sample buffer */
|
||||
int spdifWr = 0; /* Write index */
|
||||
int spdifRd = 0; /* Read index */ //(spdifWriteIndex ^ (MAX_SPDIF_SAMPLES >> 1)) & ~1; // Start in middle
|
||||
int spdifOverflow = 0; /* Overflow/undeflow flags */
|
||||
int spdifSamples[MAX_SPDIF_SAMPLES]; /* S/PDIF sample buffer */
|
||||
int spdifWr = 0; /* Write index */
|
||||
int spdifRd = 0; /* Read index */ //(spdifWriteIndex ^ (MAX_SPDIF_SAMPLES >> 1)) & ~1; // Start in middle
|
||||
int spdifOverflow = 0; /* Overflow/undeflow flags */
|
||||
int spdifUnderflow = 1;
|
||||
int spdifSamps = 0; /* Number of samples in buffer */
|
||||
Counter spdifCounters;
|
||||
int spdifReceivedTime;
|
||||
int spdifRxTime;
|
||||
unsigned tmp2;
|
||||
unsigned spdifLeft = 0;
|
||||
unsigned spdifRxData;
|
||||
#endif
|
||||
|
||||
#if (XUA_ADAT_RX_EN)
|
||||
@@ -296,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;
|
||||
@@ -330,7 +327,6 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
adatCounters.samplesPerTick = 0;
|
||||
#endif
|
||||
|
||||
|
||||
t_local :> timeNextEdge;
|
||||
timeLastEdge = timeNextEdge;
|
||||
timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT / 2);
|
||||
@@ -349,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
|
||||
@@ -390,8 +392,8 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Updates to clock settings from endpoint 0 */
|
||||
case inuint_byref(c_clk_ctl, tmp):
|
||||
/* Updates to clock settings from endpoint 0 */
|
||||
case inuint_byref(c_clk_ctl, tmp):
|
||||
switch(tmp)
|
||||
{
|
||||
case GET_SEL:
|
||||
@@ -405,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)
|
||||
{
|
||||
@@ -420,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
|
||||
}
|
||||
@@ -465,14 +463,17 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
/* 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;
|
||||
|
||||
@@ -499,58 +500,89 @@ 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 (steaming chan) */
|
||||
case c_spdif_rx :> tmp:
|
||||
/* Receive sample from S/PDIF RX thread (streaming chan) */
|
||||
case c_spdif_rx :> spdifRxData:
|
||||
|
||||
#if XUA_USE_SW_PLL
|
||||
/* Record time of sample */
|
||||
t_local :> spdifReceivedTime;
|
||||
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 */
|
||||
if(badParity(tmp))
|
||||
if(spdif_rx_check_parity(spdifRxData))
|
||||
continue;
|
||||
|
||||
/* Get pre-amble */
|
||||
tmp2 = tmp & 0xF;
|
||||
switch(tmp2)
|
||||
/* Get preamble */
|
||||
unsigned preamble = spdifRxData & SPDIF_RX_PREAMBLE_MASK;
|
||||
|
||||
switch(preamble)
|
||||
{
|
||||
/* LEFT */
|
||||
case SPDIF_FRAME_X:
|
||||
case SPDIF_FRAME_Z:
|
||||
|
||||
spdifLeft = tmp << 4;
|
||||
spdifLeft = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData);
|
||||
break;
|
||||
|
||||
/* RIGHT */
|
||||
case SPDIF_FRAME_Y:
|
||||
|
||||
/* Only store sample if not in overflow and stream is reasonably valid */
|
||||
if(!spdifOverflow && clockValid[CLOCK_SPDIF_INDEX])
|
||||
if(!spdifOverflow && clockValid[CLOCK_SPDIF])
|
||||
{
|
||||
/* Store left and right sample pair to buffer */
|
||||
spdifSamples[spdifWr] = spdifLeft;
|
||||
spdifSamples[spdifWr+1] = tmp << 4;
|
||||
spdifSamples[spdifWr+1] = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData);
|
||||
|
||||
spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1);
|
||||
|
||||
@@ -578,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;
|
||||
|
||||
@@ -586,17 +618,24 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick))
|
||||
{
|
||||
/* Check edge is about right... S/PDIF may have changed freq... */
|
||||
if(timeafter(spdifReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN)))
|
||||
if(timeafter(spdifRxTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN)))
|
||||
{
|
||||
/* Record edge time */
|
||||
timeLastEdge = spdifReceivedTime;
|
||||
timeLastEdge = spdifRxTime;
|
||||
|
||||
/* Setup for next edge */
|
||||
timeNextEdge = spdifReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
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;
|
||||
}
|
||||
@@ -607,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) */
|
||||
@@ -627,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)
|
||||
@@ -684,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;
|
||||
|
||||
@@ -700,12 +743,19 @@ 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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -716,10 +766,9 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
/* AudioHub requests data */
|
||||
case inuint_byref(c_dig_rx, tmp):
|
||||
/* AudioHub requests data */
|
||||
case inuint_byref(c_dig_rx, tmp):
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
if(spdifUnderflow)
|
||||
{
|
||||
@@ -734,7 +783,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
tmp2 = spdifSamples[spdifRd + 1];
|
||||
|
||||
spdifRd += 2;
|
||||
spdifRd &= (MAX_SPDIF_SAMPLES - 1);
|
||||
spdifRd &= (MAX_SPDIF_SAMPLES - 1);
|
||||
|
||||
g_digData[0] = tmp;
|
||||
g_digData[1] = tmp2;
|
||||
@@ -742,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;
|
||||
@@ -756,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)
|
||||
@@ -824,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;
|
||||
@@ -839,11 +887,9 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
}
|
||||
#endif
|
||||
outuint(c_dig_rx, 1);
|
||||
break;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} /* select */
|
||||
} /* while(1) */
|
||||
} /* clkgen task scope */
|
||||
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
// Header file listing fraction options searched
|
||||
// These values to go in the bottom 16 bits of the secondary PLL fractional-n divider register.
|
||||
short frac_values_80[391] = {
|
||||
0x3C4B, // Index: 0 Fraction: 61/76 = 0.8026
|
||||
0x3846, // Index: 1 Fraction: 57/71 = 0.8028
|
||||
0x3441, // Index: 2 Fraction: 53/66 = 0.8030
|
||||
0x303C, // Index: 3 Fraction: 49/61 = 0.8033
|
||||
0x2C37, // Index: 4 Fraction: 45/56 = 0.8036
|
||||
0x2832, // Index: 5 Fraction: 41/51 = 0.8039
|
||||
0x242D, // Index: 6 Fraction: 37/46 = 0.8043
|
||||
0x2028, // Index: 7 Fraction: 33/41 = 0.8049
|
||||
0x3D4C, // Index: 8 Fraction: 62/77 = 0.8052
|
||||
0x1C23, // Index: 9 Fraction: 29/36 = 0.8056
|
||||
0x3542, // Index: 10 Fraction: 54/67 = 0.8060
|
||||
0x181E, // Index: 11 Fraction: 25/31 = 0.8065
|
||||
0x2D38, // Index: 12 Fraction: 46/57 = 0.8070
|
||||
0x1419, // Index: 13 Fraction: 21/26 = 0.8077
|
||||
0x3A48, // Index: 14 Fraction: 59/73 = 0.8082
|
||||
0x252E, // Index: 15 Fraction: 38/47 = 0.8085
|
||||
0x3643, // Index: 16 Fraction: 55/68 = 0.8088
|
||||
0x1014, // Index: 17 Fraction: 17/21 = 0.8095
|
||||
0x3F4E, // Index: 18 Fraction: 64/79 = 0.8101
|
||||
0x2E39, // Index: 19 Fraction: 47/58 = 0.8103
|
||||
0x1D24, // Index: 20 Fraction: 30/37 = 0.8108
|
||||
0x2A34, // Index: 21 Fraction: 43/53 = 0.8113
|
||||
0x3744, // Index: 22 Fraction: 56/69 = 0.8116
|
||||
0x0C0F, // Index: 23 Fraction: 13/16 = 0.8125
|
||||
0x3C4A, // Index: 24 Fraction: 61/75 = 0.8133
|
||||
0x2F3A, // Index: 25 Fraction: 48/59 = 0.8136
|
||||
0x222A, // Index: 26 Fraction: 35/43 = 0.8140
|
||||
0x3845, // Index: 27 Fraction: 57/70 = 0.8143
|
||||
0x151A, // Index: 28 Fraction: 22/27 = 0.8148
|
||||
0x3440, // Index: 29 Fraction: 53/65 = 0.8154
|
||||
0x1E25, // Index: 30 Fraction: 31/38 = 0.8158
|
||||
0x2730, // Index: 31 Fraction: 40/49 = 0.8163
|
||||
0x303B, // Index: 32 Fraction: 49/60 = 0.8167
|
||||
0x3946, // Index: 33 Fraction: 58/71 = 0.8169
|
||||
0x080A, // Index: 34 Fraction: 9/11 = 0.8182
|
||||
0x3A47, // Index: 35 Fraction: 59/72 = 0.8194
|
||||
0x313C, // Index: 36 Fraction: 50/61 = 0.8197
|
||||
0x2831, // Index: 37 Fraction: 41/50 = 0.8200
|
||||
0x1F26, // Index: 38 Fraction: 32/39 = 0.8205
|
||||
0x3642, // Index: 39 Fraction: 55/67 = 0.8209
|
||||
0x161B, // Index: 40 Fraction: 23/28 = 0.8214
|
||||
0x3B48, // Index: 41 Fraction: 60/73 = 0.8219
|
||||
0x242C, // Index: 42 Fraction: 37/45 = 0.8222
|
||||
0x323D, // Index: 43 Fraction: 51/62 = 0.8226
|
||||
0x404E, // Index: 44 Fraction: 65/79 = 0.8228
|
||||
0x0D10, // Index: 45 Fraction: 14/17 = 0.8235
|
||||
0x3C49, // Index: 46 Fraction: 61/74 = 0.8243
|
||||
0x2E38, // Index: 47 Fraction: 47/57 = 0.8246
|
||||
0x2027, // Index: 48 Fraction: 33/40 = 0.8250
|
||||
0x333E, // Index: 49 Fraction: 52/63 = 0.8254
|
||||
0x1216, // Index: 50 Fraction: 19/23 = 0.8261
|
||||
0x3D4A, // Index: 51 Fraction: 62/75 = 0.8267
|
||||
0x2A33, // Index: 52 Fraction: 43/52 = 0.8269
|
||||
0x171C, // Index: 53 Fraction: 24/29 = 0.8276
|
||||
0x343F, // Index: 54 Fraction: 53/64 = 0.8281
|
||||
0x1C22, // Index: 55 Fraction: 29/35 = 0.8286
|
||||
0x3E4B, // Index: 56 Fraction: 63/76 = 0.8289
|
||||
0x2128, // Index: 57 Fraction: 34/41 = 0.8293
|
||||
0x262E, // Index: 58 Fraction: 39/47 = 0.8298
|
||||
0x2B34, // Index: 59 Fraction: 44/53 = 0.8302
|
||||
0x303A, // Index: 60 Fraction: 49/59 = 0.8305
|
||||
0x3540, // Index: 61 Fraction: 54/65 = 0.8308
|
||||
0x3A46, // Index: 62 Fraction: 59/71 = 0.8310
|
||||
0x3F4C, // Index: 63 Fraction: 64/77 = 0.8312
|
||||
0x0405, // Index: 64 Fraction: 5/6 = 0.8333
|
||||
0x414E, // Index: 65 Fraction: 66/79 = 0.8354
|
||||
0x3C48, // Index: 66 Fraction: 61/73 = 0.8356
|
||||
0x3742, // Index: 67 Fraction: 56/67 = 0.8358
|
||||
0x323C, // Index: 68 Fraction: 51/61 = 0.8361
|
||||
0x2D36, // Index: 69 Fraction: 46/55 = 0.8364
|
||||
0x2830, // Index: 70 Fraction: 41/49 = 0.8367
|
||||
0x232A, // Index: 71 Fraction: 36/43 = 0.8372
|
||||
0x424F, // Index: 72 Fraction: 67/80 = 0.8375
|
||||
0x1E24, // Index: 73 Fraction: 31/37 = 0.8378
|
||||
0x3843, // Index: 74 Fraction: 57/68 = 0.8382
|
||||
0x191E, // Index: 75 Fraction: 26/31 = 0.8387
|
||||
0x2E37, // Index: 76 Fraction: 47/56 = 0.8393
|
||||
0x1418, // Index: 77 Fraction: 21/25 = 0.8400
|
||||
0x3944, // Index: 78 Fraction: 58/69 = 0.8406
|
||||
0x242B, // Index: 79 Fraction: 37/44 = 0.8409
|
||||
0x343E, // Index: 80 Fraction: 53/63 = 0.8413
|
||||
0x0F12, // Index: 81 Fraction: 16/19 = 0.8421
|
||||
0x3A45, // Index: 82 Fraction: 59/70 = 0.8429
|
||||
0x2A32, // Index: 83 Fraction: 43/51 = 0.8431
|
||||
0x1A1F, // Index: 84 Fraction: 27/32 = 0.8438
|
||||
0x404C, // Index: 85 Fraction: 65/77 = 0.8442
|
||||
0x252C, // Index: 86 Fraction: 38/45 = 0.8444
|
||||
0x3039, // Index: 87 Fraction: 49/58 = 0.8448
|
||||
0x3B46, // Index: 88 Fraction: 60/71 = 0.8451
|
||||
0x0A0C, // Index: 89 Fraction: 11/13 = 0.8462
|
||||
0x3C47, // Index: 90 Fraction: 61/72 = 0.8472
|
||||
0x313A, // Index: 91 Fraction: 50/59 = 0.8475
|
||||
0x262D, // Index: 92 Fraction: 39/46 = 0.8478
|
||||
0x424E, // Index: 93 Fraction: 67/79 = 0.8481
|
||||
0x1B20, // Index: 94 Fraction: 28/33 = 0.8485
|
||||
0x2C34, // Index: 95 Fraction: 45/53 = 0.8491
|
||||
0x3D48, // Index: 96 Fraction: 62/73 = 0.8493
|
||||
0x1013, // Index: 97 Fraction: 17/20 = 0.8500
|
||||
0x3842, // Index: 98 Fraction: 57/67 = 0.8507
|
||||
0x272E, // Index: 99 Fraction: 40/47 = 0.8511
|
||||
0x3E49, // Index: 100 Fraction: 63/74 = 0.8514
|
||||
0x161A, // Index: 101 Fraction: 23/27 = 0.8519
|
||||
0x333C, // Index: 102 Fraction: 52/61 = 0.8525
|
||||
0x1C21, // Index: 103 Fraction: 29/34 = 0.8529
|
||||
0x3F4A, // Index: 104 Fraction: 64/75 = 0.8533
|
||||
0x2228, // Index: 105 Fraction: 35/41 = 0.8537
|
||||
0x282F, // Index: 106 Fraction: 41/48 = 0.8542
|
||||
0x2E36, // Index: 107 Fraction: 47/55 = 0.8545
|
||||
0x343D, // Index: 108 Fraction: 53/62 = 0.8548
|
||||
0x3A44, // Index: 109 Fraction: 59/69 = 0.8551
|
||||
0x404B, // Index: 110 Fraction: 65/76 = 0.8553
|
||||
0x0506, // Index: 111 Fraction: 6/7 = 0.8571
|
||||
0x424D, // Index: 112 Fraction: 67/78 = 0.8590
|
||||
0x3C46, // Index: 113 Fraction: 61/71 = 0.8592
|
||||
0x363F, // Index: 114 Fraction: 55/64 = 0.8594
|
||||
0x3038, // Index: 115 Fraction: 49/57 = 0.8596
|
||||
0x2A31, // Index: 116 Fraction: 43/50 = 0.8600
|
||||
0x242A, // Index: 117 Fraction: 37/43 = 0.8605
|
||||
0x434E, // Index: 118 Fraction: 68/79 = 0.8608
|
||||
0x1E23, // Index: 119 Fraction: 31/36 = 0.8611
|
||||
0x3740, // Index: 120 Fraction: 56/65 = 0.8615
|
||||
0x181C, // Index: 121 Fraction: 25/29 = 0.8621
|
||||
0x444F, // Index: 122 Fraction: 69/80 = 0.8625
|
||||
0x2B32, // Index: 123 Fraction: 44/51 = 0.8627
|
||||
0x3E48, // Index: 124 Fraction: 63/73 = 0.8630
|
||||
0x1215, // Index: 125 Fraction: 19/22 = 0.8636
|
||||
0x323A, // Index: 126 Fraction: 51/59 = 0.8644
|
||||
0x1F24, // Index: 127 Fraction: 32/37 = 0.8649
|
||||
0x2C33, // Index: 128 Fraction: 45/52 = 0.8654
|
||||
0x3942, // Index: 129 Fraction: 58/67 = 0.8657
|
||||
0x0C0E, // Index: 130 Fraction: 13/15 = 0.8667
|
||||
0x3A43, // Index: 131 Fraction: 59/68 = 0.8676
|
||||
0x2D34, // Index: 132 Fraction: 46/53 = 0.8679
|
||||
0x2025, // Index: 133 Fraction: 33/38 = 0.8684
|
||||
0x343C, // Index: 134 Fraction: 53/61 = 0.8689
|
||||
0x1316, // Index: 135 Fraction: 20/23 = 0.8696
|
||||
0x424C, // Index: 136 Fraction: 67/77 = 0.8701
|
||||
0x2E35, // Index: 137 Fraction: 47/54 = 0.8704
|
||||
0x1A1E, // Index: 138 Fraction: 27/31 = 0.8710
|
||||
0x3C45, // Index: 139 Fraction: 61/70 = 0.8714
|
||||
0x2126, // Index: 140 Fraction: 34/39 = 0.8718
|
||||
0x282E, // Index: 141 Fraction: 41/47 = 0.8723
|
||||
0x2F36, // Index: 142 Fraction: 48/55 = 0.8727
|
||||
0x363E, // Index: 143 Fraction: 55/63 = 0.8730
|
||||
0x3D46, // Index: 144 Fraction: 62/71 = 0.8732
|
||||
0x444E, // Index: 145 Fraction: 69/79 = 0.8734
|
||||
0x0607, // Index: 146 Fraction: 7/8 = 0.8750
|
||||
0x3F48, // Index: 147 Fraction: 64/73 = 0.8767
|
||||
0x3840, // Index: 148 Fraction: 57/65 = 0.8769
|
||||
0x3138, // Index: 149 Fraction: 50/57 = 0.8772
|
||||
0x2A30, // Index: 150 Fraction: 43/49 = 0.8776
|
||||
0x2328, // Index: 151 Fraction: 36/41 = 0.8780
|
||||
0x4049, // Index: 152 Fraction: 65/74 = 0.8784
|
||||
0x1C20, // Index: 153 Fraction: 29/33 = 0.8788
|
||||
0x3239, // Index: 154 Fraction: 51/58 = 0.8793
|
||||
0x1518, // Index: 155 Fraction: 22/25 = 0.8800
|
||||
0x3A42, // Index: 156 Fraction: 59/67 = 0.8806
|
||||
0x2429, // Index: 157 Fraction: 37/42 = 0.8810
|
||||
0x333A, // Index: 158 Fraction: 52/59 = 0.8814
|
||||
0x424B, // Index: 159 Fraction: 67/76 = 0.8816
|
||||
0x0E10, // Index: 160 Fraction: 15/17 = 0.8824
|
||||
0x434C, // Index: 161 Fraction: 68/77 = 0.8831
|
||||
0x343B, // Index: 162 Fraction: 53/60 = 0.8833
|
||||
0x252A, // Index: 163 Fraction: 38/43 = 0.8837
|
||||
0x3C44, // Index: 164 Fraction: 61/69 = 0.8841
|
||||
0x1619, // Index: 165 Fraction: 23/26 = 0.8846
|
||||
0x353C, // Index: 166 Fraction: 54/61 = 0.8852
|
||||
0x1E22, // Index: 167 Fraction: 31/35 = 0.8857
|
||||
0x454E, // Index: 168 Fraction: 70/79 = 0.8861
|
||||
0x262B, // Index: 169 Fraction: 39/44 = 0.8864
|
||||
0x2E34, // Index: 170 Fraction: 47/53 = 0.8868
|
||||
0x363D, // Index: 171 Fraction: 55/62 = 0.8871
|
||||
0x3E46, // Index: 172 Fraction: 63/71 = 0.8873
|
||||
0x464F, // Index: 173 Fraction: 71/80 = 0.8875
|
||||
0x0708, // Index: 174 Fraction: 8/9 = 0.8889
|
||||
0x4048, // Index: 175 Fraction: 65/73 = 0.8904
|
||||
0x383F, // Index: 176 Fraction: 57/64 = 0.8906
|
||||
0x3036, // Index: 177 Fraction: 49/55 = 0.8909
|
||||
0x282D, // Index: 178 Fraction: 41/46 = 0.8913
|
||||
0x2024, // Index: 179 Fraction: 33/37 = 0.8919
|
||||
0x3940, // Index: 180 Fraction: 58/65 = 0.8923
|
||||
0x181B, // Index: 181 Fraction: 25/28 = 0.8929
|
||||
0x424A, // Index: 182 Fraction: 67/75 = 0.8933
|
||||
0x292E, // Index: 183 Fraction: 42/47 = 0.8936
|
||||
0x3A41, // Index: 184 Fraction: 59/66 = 0.8939
|
||||
0x1012, // Index: 185 Fraction: 17/19 = 0.8947
|
||||
0x3B42, // Index: 186 Fraction: 60/67 = 0.8955
|
||||
0x2A2F, // Index: 187 Fraction: 43/48 = 0.8958
|
||||
0x444C, // Index: 188 Fraction: 69/77 = 0.8961
|
||||
0x191C, // Index: 189 Fraction: 26/29 = 0.8966
|
||||
0x3C43, // Index: 190 Fraction: 61/68 = 0.8971
|
||||
0x2226, // Index: 191 Fraction: 35/39 = 0.8974
|
||||
0x2B30, // Index: 192 Fraction: 44/49 = 0.8980
|
||||
0x343A, // Index: 193 Fraction: 53/59 = 0.8983
|
||||
0x3D44, // Index: 194 Fraction: 62/69 = 0.8986
|
||||
0x464E, // Index: 195 Fraction: 71/79 = 0.8987
|
||||
0x0809, // Index: 196 Fraction: 9/10 = 0.9000
|
||||
0x3F46, // Index: 197 Fraction: 64/71 = 0.9014
|
||||
0x363C, // Index: 198 Fraction: 55/61 = 0.9016
|
||||
0x2D32, // Index: 199 Fraction: 46/51 = 0.9020
|
||||
0x2428, // Index: 200 Fraction: 37/41 = 0.9024
|
||||
0x4047, // Index: 201 Fraction: 65/72 = 0.9028
|
||||
0x1B1E, // Index: 202 Fraction: 28/31 = 0.9032
|
||||
0x2E33, // Index: 203 Fraction: 47/52 = 0.9038
|
||||
0x4148, // Index: 204 Fraction: 66/73 = 0.9041
|
||||
0x1214, // Index: 205 Fraction: 19/21 = 0.9048
|
||||
0x4249, // Index: 206 Fraction: 67/74 = 0.9054
|
||||
0x2F34, // Index: 207 Fraction: 48/53 = 0.9057
|
||||
0x1C1F, // Index: 208 Fraction: 29/32 = 0.9062
|
||||
0x434A, // Index: 209 Fraction: 68/75 = 0.9067
|
||||
0x262A, // Index: 210 Fraction: 39/43 = 0.9070
|
||||
0x3035, // Index: 211 Fraction: 49/54 = 0.9074
|
||||
0x3A40, // Index: 212 Fraction: 59/65 = 0.9077
|
||||
0x444B, // Index: 213 Fraction: 69/76 = 0.9079
|
||||
0x090A, // Index: 214 Fraction: 10/11 = 0.9091
|
||||
0x464D, // Index: 215 Fraction: 71/78 = 0.9103
|
||||
0x3C42, // Index: 216 Fraction: 61/67 = 0.9104
|
||||
0x3237, // Index: 217 Fraction: 51/56 = 0.9107
|
||||
0x282C, // Index: 218 Fraction: 41/45 = 0.9111
|
||||
0x474E, // Index: 219 Fraction: 72/79 = 0.9114
|
||||
0x1E21, // Index: 220 Fraction: 31/34 = 0.9118
|
||||
0x3338, // Index: 221 Fraction: 52/57 = 0.9123
|
||||
0x484F, // Index: 222 Fraction: 73/80 = 0.9125
|
||||
0x1416, // Index: 223 Fraction: 21/23 = 0.9130
|
||||
0x3439, // Index: 224 Fraction: 53/58 = 0.9138
|
||||
0x1F22, // Index: 225 Fraction: 32/35 = 0.9143
|
||||
0x2A2E, // Index: 226 Fraction: 43/47 = 0.9149
|
||||
0x353A, // Index: 227 Fraction: 54/59 = 0.9153
|
||||
0x4046, // Index: 228 Fraction: 65/71 = 0.9155
|
||||
0x0A0B, // Index: 229 Fraction: 11/12 = 0.9167
|
||||
0x4248, // Index: 230 Fraction: 67/73 = 0.9178
|
||||
0x373C, // Index: 231 Fraction: 56/61 = 0.9180
|
||||
0x2C30, // Index: 232 Fraction: 45/49 = 0.9184
|
||||
0x2124, // Index: 233 Fraction: 34/37 = 0.9189
|
||||
0x383D, // Index: 234 Fraction: 57/62 = 0.9194
|
||||
0x1618, // Index: 235 Fraction: 23/25 = 0.9200
|
||||
0x393E, // Index: 236 Fraction: 58/63 = 0.9206
|
||||
0x2225, // Index: 237 Fraction: 35/38 = 0.9211
|
||||
0x2E32, // Index: 238 Fraction: 47/51 = 0.9216
|
||||
0x3A3F, // Index: 239 Fraction: 59/64 = 0.9219
|
||||
0x464C, // Index: 240 Fraction: 71/77 = 0.9221
|
||||
0x0B0C, // Index: 241 Fraction: 12/13 = 0.9231
|
||||
0x484E, // Index: 242 Fraction: 73/79 = 0.9241
|
||||
0x3C41, // Index: 243 Fraction: 61/66 = 0.9242
|
||||
0x3034, // Index: 244 Fraction: 49/53 = 0.9245
|
||||
0x2427, // Index: 245 Fraction: 37/40 = 0.9250
|
||||
0x3D42, // Index: 246 Fraction: 62/67 = 0.9254
|
||||
0x181A, // Index: 247 Fraction: 25/27 = 0.9259
|
||||
0x3E43, // Index: 248 Fraction: 63/68 = 0.9265
|
||||
0x2528, // Index: 249 Fraction: 38/41 = 0.9268
|
||||
0x3236, // Index: 250 Fraction: 51/55 = 0.9273
|
||||
0x3F44, // Index: 251 Fraction: 64/69 = 0.9275
|
||||
0x0C0D, // Index: 252 Fraction: 13/14 = 0.9286
|
||||
0x4146, // Index: 253 Fraction: 66/71 = 0.9296
|
||||
0x3438, // Index: 254 Fraction: 53/57 = 0.9298
|
||||
0x272A, // Index: 255 Fraction: 40/43 = 0.9302
|
||||
0x4247, // Index: 256 Fraction: 67/72 = 0.9306
|
||||
0x1A1C, // Index: 257 Fraction: 27/29 = 0.9310
|
||||
0x4348, // Index: 258 Fraction: 68/73 = 0.9315
|
||||
0x282B, // Index: 259 Fraction: 41/44 = 0.9318
|
||||
0x363A, // Index: 260 Fraction: 55/59 = 0.9322
|
||||
0x4449, // Index: 261 Fraction: 69/74 = 0.9324
|
||||
0x0D0E, // Index: 262 Fraction: 14/15 = 0.9333
|
||||
0x464B, // Index: 263 Fraction: 71/76 = 0.9342
|
||||
0x383C, // Index: 264 Fraction: 57/61 = 0.9344
|
||||
0x2A2D, // Index: 265 Fraction: 43/46 = 0.9348
|
||||
0x474C, // Index: 266 Fraction: 72/77 = 0.9351
|
||||
0x1C1E, // Index: 267 Fraction: 29/31 = 0.9355
|
||||
0x484D, // Index: 268 Fraction: 73/78 = 0.9359
|
||||
0x2B2E, // Index: 269 Fraction: 44/47 = 0.9362
|
||||
0x3A3E, // Index: 270 Fraction: 59/63 = 0.9365
|
||||
0x494E, // Index: 271 Fraction: 74/79 = 0.9367
|
||||
0x0E0F, // Index: 272 Fraction: 15/16 = 0.9375
|
||||
0x3C40, // Index: 273 Fraction: 61/65 = 0.9385
|
||||
0x2D30, // Index: 274 Fraction: 46/49 = 0.9388
|
||||
0x1E20, // Index: 275 Fraction: 31/33 = 0.9394
|
||||
0x2E31, // Index: 276 Fraction: 47/50 = 0.9400
|
||||
0x3E42, // Index: 277 Fraction: 63/67 = 0.9403
|
||||
0x0F10, // Index: 278 Fraction: 16/17 = 0.9412
|
||||
0x4044, // Index: 279 Fraction: 65/69 = 0.9420
|
||||
0x3033, // Index: 280 Fraction: 49/52 = 0.9423
|
||||
0x2022, // Index: 281 Fraction: 33/35 = 0.9429
|
||||
0x3134, // Index: 282 Fraction: 50/53 = 0.9434
|
||||
0x4246, // Index: 283 Fraction: 67/71 = 0.9437
|
||||
0x1011, // Index: 284 Fraction: 17/18 = 0.9444
|
||||
0x4448, // Index: 285 Fraction: 69/73 = 0.9452
|
||||
0x3336, // Index: 286 Fraction: 52/55 = 0.9455
|
||||
0x2224, // Index: 287 Fraction: 35/37 = 0.9459
|
||||
0x3437, // Index: 288 Fraction: 53/56 = 0.9464
|
||||
0x464A, // Index: 289 Fraction: 71/75 = 0.9467
|
||||
0x1112, // Index: 290 Fraction: 18/19 = 0.9474
|
||||
0x484C, // Index: 291 Fraction: 73/77 = 0.9481
|
||||
0x3639, // Index: 292 Fraction: 55/58 = 0.9483
|
||||
0x2426, // Index: 293 Fraction: 37/39 = 0.9487
|
||||
0x373A, // Index: 294 Fraction: 56/59 = 0.9492
|
||||
0x4A4E, // Index: 295 Fraction: 75/79 = 0.9494
|
||||
0x1213, // Index: 296 Fraction: 19/20 = 0.9500
|
||||
0x393C, // Index: 297 Fraction: 58/61 = 0.9508
|
||||
0x2628, // Index: 298 Fraction: 39/41 = 0.9512
|
||||
0x3A3D, // Index: 299 Fraction: 59/62 = 0.9516
|
||||
0x1314, // Index: 300 Fraction: 20/21 = 0.9524
|
||||
0x3C3F, // Index: 301 Fraction: 61/64 = 0.9531
|
||||
0x282A, // Index: 302 Fraction: 41/43 = 0.9535
|
||||
0x3D40, // Index: 303 Fraction: 62/65 = 0.9538
|
||||
0x1415, // Index: 304 Fraction: 21/22 = 0.9545
|
||||
0x3F42, // Index: 305 Fraction: 64/67 = 0.9552
|
||||
0x2A2C, // Index: 306 Fraction: 43/45 = 0.9556
|
||||
0x4043, // Index: 307 Fraction: 65/68 = 0.9559
|
||||
0x1516, // Index: 308 Fraction: 22/23 = 0.9565
|
||||
0x4245, // Index: 309 Fraction: 67/70 = 0.9571
|
||||
0x2C2E, // Index: 310 Fraction: 45/47 = 0.9574
|
||||
0x4346, // Index: 311 Fraction: 68/71 = 0.9577
|
||||
0x1617, // Index: 312 Fraction: 23/24 = 0.9583
|
||||
0x4548, // Index: 313 Fraction: 70/73 = 0.9589
|
||||
0x2E30, // Index: 314 Fraction: 47/49 = 0.9592
|
||||
0x4649, // Index: 315 Fraction: 71/74 = 0.9595
|
||||
0x1718, // Index: 316 Fraction: 24/25 = 0.9600
|
||||
0x484B, // Index: 317 Fraction: 73/76 = 0.9605
|
||||
0x3032, // Index: 318 Fraction: 49/51 = 0.9608
|
||||
0x494C, // Index: 319 Fraction: 74/77 = 0.9610
|
||||
0x1819, // Index: 320 Fraction: 25/26 = 0.9615
|
||||
0x4B4E, // Index: 321 Fraction: 76/79 = 0.9620
|
||||
0x3234, // Index: 322 Fraction: 51/53 = 0.9623
|
||||
0x4C4F, // Index: 323 Fraction: 77/80 = 0.9625
|
||||
0x191A, // Index: 324 Fraction: 26/27 = 0.9630
|
||||
0x3436, // Index: 325 Fraction: 53/55 = 0.9636
|
||||
0x1A1B, // Index: 326 Fraction: 27/28 = 0.9643
|
||||
0x3638, // Index: 327 Fraction: 55/57 = 0.9649
|
||||
0x1B1C, // Index: 328 Fraction: 28/29 = 0.9655
|
||||
0x383A, // Index: 329 Fraction: 57/59 = 0.9661
|
||||
0x1C1D, // Index: 330 Fraction: 29/30 = 0.9667
|
||||
0x3A3C, // Index: 331 Fraction: 59/61 = 0.9672
|
||||
0x1D1E, // Index: 332 Fraction: 30/31 = 0.9677
|
||||
0x3C3E, // Index: 333 Fraction: 61/63 = 0.9683
|
||||
0x1E1F, // Index: 334 Fraction: 31/32 = 0.9688
|
||||
0x3E40, // Index: 335 Fraction: 63/65 = 0.9692
|
||||
0x1F20, // Index: 336 Fraction: 32/33 = 0.9697
|
||||
0x4042, // Index: 337 Fraction: 65/67 = 0.9701
|
||||
0x2021, // Index: 338 Fraction: 33/34 = 0.9706
|
||||
0x4244, // Index: 339 Fraction: 67/69 = 0.9710
|
||||
0x2122, // Index: 340 Fraction: 34/35 = 0.9714
|
||||
0x4446, // Index: 341 Fraction: 69/71 = 0.9718
|
||||
0x2223, // Index: 342 Fraction: 35/36 = 0.9722
|
||||
0x4648, // Index: 343 Fraction: 71/73 = 0.9726
|
||||
0x2324, // Index: 344 Fraction: 36/37 = 0.9730
|
||||
0x484A, // Index: 345 Fraction: 73/75 = 0.9733
|
||||
0x2425, // Index: 346 Fraction: 37/38 = 0.9737
|
||||
0x4A4C, // Index: 347 Fraction: 75/77 = 0.9740
|
||||
0x2526, // Index: 348 Fraction: 38/39 = 0.9744
|
||||
0x4C4E, // Index: 349 Fraction: 77/79 = 0.9747
|
||||
0x2627, // Index: 350 Fraction: 39/40 = 0.9750
|
||||
0x2728, // Index: 351 Fraction: 40/41 = 0.9756
|
||||
0x2829, // Index: 352 Fraction: 41/42 = 0.9762
|
||||
0x292A, // Index: 353 Fraction: 42/43 = 0.9767
|
||||
0x2A2B, // Index: 354 Fraction: 43/44 = 0.9773
|
||||
0x2B2C, // Index: 355 Fraction: 44/45 = 0.9778
|
||||
0x2C2D, // Index: 356 Fraction: 45/46 = 0.9783
|
||||
0x2D2E, // Index: 357 Fraction: 46/47 = 0.9787
|
||||
0x2E2F, // Index: 358 Fraction: 47/48 = 0.9792
|
||||
0x2F30, // Index: 359 Fraction: 48/49 = 0.9796
|
||||
0x3031, // Index: 360 Fraction: 49/50 = 0.9800
|
||||
0x3132, // Index: 361 Fraction: 50/51 = 0.9804
|
||||
0x3233, // Index: 362 Fraction: 51/52 = 0.9808
|
||||
0x3334, // Index: 363 Fraction: 52/53 = 0.9811
|
||||
0x3435, // Index: 364 Fraction: 53/54 = 0.9815
|
||||
0x3536, // Index: 365 Fraction: 54/55 = 0.9818
|
||||
0x3637, // Index: 366 Fraction: 55/56 = 0.9821
|
||||
0x3738, // Index: 367 Fraction: 56/57 = 0.9825
|
||||
0x3839, // Index: 368 Fraction: 57/58 = 0.9828
|
||||
0x393A, // Index: 369 Fraction: 58/59 = 0.9831
|
||||
0x3A3B, // Index: 370 Fraction: 59/60 = 0.9833
|
||||
0x3B3C, // Index: 371 Fraction: 60/61 = 0.9836
|
||||
0x3C3D, // Index: 372 Fraction: 61/62 = 0.9839
|
||||
0x3D3E, // Index: 373 Fraction: 62/63 = 0.9841
|
||||
0x3E3F, // Index: 374 Fraction: 63/64 = 0.9844
|
||||
0x3F40, // Index: 375 Fraction: 64/65 = 0.9846
|
||||
0x4041, // Index: 376 Fraction: 65/66 = 0.9848
|
||||
0x4142, // Index: 377 Fraction: 66/67 = 0.9851
|
||||
0x4243, // Index: 378 Fraction: 67/68 = 0.9853
|
||||
0x4344, // Index: 379 Fraction: 68/69 = 0.9855
|
||||
0x4445, // Index: 380 Fraction: 69/70 = 0.9857
|
||||
0x4546, // Index: 381 Fraction: 70/71 = 0.9859
|
||||
0x4647, // Index: 382 Fraction: 71/72 = 0.9861
|
||||
0x4748, // Index: 383 Fraction: 72/73 = 0.9863
|
||||
0x4849, // Index: 384 Fraction: 73/74 = 0.9865
|
||||
0x494A, // Index: 385 Fraction: 74/75 = 0.9867
|
||||
0x4A4B, // Index: 386 Fraction: 75/76 = 0.9868
|
||||
0x4B4C, // Index: 387 Fraction: 76/77 = 0.9870
|
||||
0x4C4D, // Index: 388 Fraction: 77/78 = 0.9872
|
||||
0x4D4E, // Index: 389 Fraction: 78/79 = 0.9873
|
||||
0x4E4F, // Index: 390 Fraction: 79/80 = 0.9875
|
||||
};
|
||||
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 =
|
||||
|
||||
@@ -145,7 +145,7 @@ static void updateMasterVol(int unitID, chanend ?c_mix_ctl)
|
||||
outuint(c_mix_ctl, x);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
#else
|
||||
#else
|
||||
unsafe
|
||||
{
|
||||
unsigned int * unsafe multOutPtr = multOut;
|
||||
@@ -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 */
|
||||
@@ -30,8 +30,8 @@
|
||||
#include "iap.h"
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
#include "spdif.h"
|
||||
#if (XUA_SPDIF_RX_EN || XUA_SPDIF_TX_EN)
|
||||
#include "spdif.h" /* From lib_spdif */
|
||||
#endif
|
||||
|
||||
#if (XUA_ADAT_RX_EN)
|
||||
@@ -42,10 +42,6 @@
|
||||
#include "xua_pdm_mic.h"
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_TX_EN)
|
||||
#include "spdif.h" /* From lib_spdif */
|
||||
#endif
|
||||
|
||||
#if (XUA_DFU_EN == 1)
|
||||
[[distributable]]
|
||||
void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd);
|
||||
@@ -145,9 +141,14 @@ on stdcore[XUD_TILE] : buffered in port:32 p_adat_rx = PORT_ADAT_IN;
|
||||
on tile[XUD_TILE] : in port p_spdif_rx = PORT_SPDIF_IN;
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) || ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL))
|
||||
#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
|
||||
@@ -314,8 +315,12 @@ 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_USE_APP_PLL)
|
||||
, client interface SoftPll_if i_softPll
|
||||
#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
|
||||
)
|
||||
{
|
||||
@@ -325,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 */
|
||||
@@ -343,7 +353,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
|
||||
par
|
||||
{
|
||||
#if (MIXER)
|
||||
#if (MIXER && XUA_USB_EN)
|
||||
/* Mixer cores(s) */
|
||||
{
|
||||
thread_speed();
|
||||
@@ -367,15 +377,15 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
#define AUDIO_CHANNEL c_aud_in
|
||||
#endif
|
||||
XUA_AudioHub(AUDIO_CHANNEL, clk_audio_mclk, clk_audio_bclk, p_mclk_in, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc
|
||||
#if (XUA_USE_APP_PLL)
|
||||
, i_softPll
|
||||
#endif
|
||||
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
, c_spdif_tx
|
||||
#endif
|
||||
#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
|
||||
@@ -395,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
|
||||
@@ -447,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
|
||||
|
||||
@@ -473,13 +493,15 @@ int main()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !XUA_USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) )
|
||||
interface pll_ref_if i_pll_ref;
|
||||
#endif
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
interface SoftPll_if i_softPll;
|
||||
chan c_swpll_update;
|
||||
#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 */
|
||||
@@ -502,20 +524,18 @@ int main()
|
||||
{
|
||||
USER_MAIN_CORES
|
||||
|
||||
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XYA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !XUA_USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN))
|
||||
on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref);
|
||||
#endif
|
||||
on tile[XUD_TILE]:
|
||||
par
|
||||
{
|
||||
#if (XUD_TILE == 0)
|
||||
#if XUA_USB_EN
|
||||
#if ((XUD_TILE == 0) && (XUA_DFU_EN == 1))
|
||||
/* Check if USB is on the flash tile (tile 0) */
|
||||
#if (XUA_DFU_EN == 1)
|
||||
[[distribute]]
|
||||
DFUHandler(dfuInterface, null);
|
||||
#endif
|
||||
#endif
|
||||
#if XUA_USB_EN
|
||||
|
||||
/* Core USB task, buffering, USB etc */
|
||||
{
|
||||
@@ -533,10 +553,6 @@ int main()
|
||||
c_sof, epTypeTableOut, epTypeTableIn, usbSpeed, xudPwrCfg);
|
||||
}
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
//XUA_SoftPll(tile[0], i_softPll, c_swpll_update);
|
||||
#endif
|
||||
|
||||
/* Core USB audio task, buffering, USB etc */
|
||||
{
|
||||
unsigned x;
|
||||
@@ -579,10 +595,11 @@ int main()
|
||||
#endif
|
||||
, c_mix_out
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if (!XUA_USE_APP_PLL)
|
||||
, c_audio_rate_change
|
||||
#if (!XUA_USE_SW_PLL)
|
||||
, i_pll_ref
|
||||
#else
|
||||
, c_swpll_update
|
||||
, c_sw_pll
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
@@ -598,11 +615,13 @@ int main()
|
||||
#endif /* XUA_USB_EN */
|
||||
}
|
||||
|
||||
#if(XUA_USE_APP_PLL)
|
||||
on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update);
|
||||
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || 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]:
|
||||
{
|
||||
|
||||
/* Audio I/O task, includes mixing etc */
|
||||
usb_audio_io(c_mix_out
|
||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
@@ -616,16 +635,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_USE_APP_PLL)
|
||||
, i_softPll
|
||||
#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
|
||||
);
|
||||
}
|
||||
@@ -668,7 +687,7 @@ int main()
|
||||
on tile[XUD_TILE]:
|
||||
{
|
||||
thread_speed();
|
||||
spdif_rx(c_spdif_rx,p_spdif_rx,clk_spd_rx,192000);
|
||||
spdif_rx(c_spdif_rx, p_spdif_rx, clk_spd_rx, 192000);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// 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() */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// 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_
|
||||
|
||||
@@ -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 _AUDIOSTREAM_H_
|
||||
#define _AUDIOSTREAM_H_
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// Copyright 2013-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/**
|
||||
@@ -51,7 +51,7 @@ 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 );
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// Copyright 2013-2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright 2011-2021 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#ifndef __XUA_INTERNAL_CMDS_H__
|
||||
#define __XUA_INTERNAL_CMDS_H__
|
||||
#ifndef _XUA_COMMANDS_H_
|
||||
#define _XUA_COMMANDS_H_
|
||||
|
||||
#include "xua.h"
|
||||
|
||||
@@ -11,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 SPDIF_RX
|
||||
#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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2021 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <xs1.h>
|
||||
#include <flash.h>
|
||||
@@ -72,7 +72,7 @@ int flash_cmd_init(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef QUAD_SPI_FLASH
|
||||
#if (!XUA_QUAD_SPI_FLASH)
|
||||
// Disable flash protection
|
||||
fl_setProtection(0);
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2012-2021 XMOS LIMITED.
|
||||
// Copyright 2012-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua.h"
|
||||
#if (XUA_DFU_EN == 1)
|
||||
#include "uac_hwresources.h"
|
||||
#include <xs1.h>
|
||||
#include <xclib.h>
|
||||
#ifdef QUAD_SPI_FLASH
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
#include <quadflashlib.h>
|
||||
#else
|
||||
#include <flashlib.h>
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#ifdef DFU_FLASH_DEVICE
|
||||
|
||||
#ifdef QUAD_SPI_FLASH
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
/* Using specified flash device rather than all supported in tools */
|
||||
fl_QuadDeviceSpec flash_devices[] = {DFU_FLASH_DEVICE};
|
||||
#else
|
||||
@@ -29,7 +29,7 @@ fl_DeviceSpec flash_devices[] = {DFU_FLASH_DEVICE};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef QUAD_SPI_FLASH
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
/*
|
||||
typedef struct {
|
||||
out port qspiCS;
|
||||
@@ -60,7 +60,7 @@ fl_PortHolderStruct p_flash =
|
||||
int flash_cmd_enable_ports()
|
||||
{
|
||||
int result = 0;
|
||||
#ifdef QUAD_SPI_FLASH
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
/* Ports not shared */
|
||||
#else
|
||||
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
|
||||
@@ -89,14 +89,14 @@ int flash_cmd_enable_ports()
|
||||
#endif
|
||||
|
||||
#ifdef DFU_FLASH_DEVICE
|
||||
#ifdef QUAD_SPI_FLASH
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
result = fl_connectToDevice(&p_qflash, flash_devices, sizeof(flash_devices) / sizeof(fl_QuadDeviceSpec));
|
||||
#else
|
||||
result = fl_connectToDevice(&p_flash, flash_devices, sizeof(flash_devices) / sizeof(fl_DeviceSpec));
|
||||
#endif
|
||||
#else
|
||||
/* Use default flash list */
|
||||
#ifdef QUAD_SPI_FLASH
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
result = fl_connect(&p_qflash);
|
||||
#else
|
||||
result = fl_connect(&p_flash);
|
||||
@@ -117,7 +117,7 @@ int flash_cmd_disable_ports()
|
||||
{
|
||||
fl_disconnect();
|
||||
|
||||
#ifndef QUAD_SPI_FLASH
|
||||
#if (!XUA_QUAD_SPI_FLASH)
|
||||
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
|
||||
|
||||
@@ -3,12 +3,12 @@ TEST_FLAGS ?=
|
||||
|
||||
XCC_FLAGS_HS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \
|
||||
-DBUS_SPEED=2 \
|
||||
-DXUA_USE_APP_PLL=0 \
|
||||
-DXUA_USE_SW_PLL=0 \
|
||||
$(TEST_FLAGS)
|
||||
|
||||
XCC_FLAGS_FS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \
|
||||
-DBUS_SPEED=1 \
|
||||
-DXUA_USE_APP_PLL=0 \
|
||||
-DXUA_USE_SW_PLL=0 \
|
||||
$(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
@@ -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