157 Commits

Author SHA1 Message Date
Ross Owen
dd8d2675d3 App PLL sync mode improvements:
- Added IIR to reduce jitter into DCO
- Added PID for tracking external clock
- Added basic “fast lock” based on an initial estimate
2023-08-15 11:58:32 +01:00
Ross Owen
7930a5d59c Sync mode 2nd order delta sigma replaced with third order, level output. 2023-08-08 18:19:04 +01:00
Ross Owen
158d79335c Sync mode related build fix 2023-08-02 12:43:04 +01:00
Ross Owen
ebc09e1c4f Fixes for sync mode related build warnings/errors 2023-08-02 12:14:21 +01:00
Ross Owen
a7943a8859 - Improved audio performance in synchronous mode when using the App PLL
- Software PLL code now uses a core rather than running entirely in XUA_Buffer_EP()
2023-08-01 15:56:00 +01:00
Ross Owen
77fad35497 Documentation updates 2023-07-17 14:23:09 +01:00
Ross Owen
50966dda90 Build fixes related to the use of i_pll_ref 2023-07-14 16:07:38 +01:00
Ross Owen
e7b5faed66 Documentation updates and fixes 2023-07-14 15:58:54 +01:00
Ross Owen
7f72c4b842 - Moved audiohw functions from xua_audiohub into user folder in line with other user functions 2023-07-14 15:58:03 +01:00
Ross Owen
d119755313 Do not use sync out pin when using app PLL for sync mode 2023-07-14 11:59:15 +01:00
Ross Owen
2228575e09 Documentation updates 2023-07-14 11:59:15 +01:00
Ross Owen
b6972295e9 Merge pull request #339 from xross/experimetal/sync_app_pll
Experimental synchronous mode using xs3 app pll
2023-07-13 16:15:26 +01:00
Ross Owen
39802f3620 Example app note code now use app pll code from lib_xua 2023-07-13 15:09:29 +01:00
Ross Owen
5bf53fa453 Fix to test_sync_clk_basic 2023-07-13 14:12:52 +01:00
Ross Owen
2f11eda7d8 - Added AudioHwConfig_Mute() and AudioHwConfig_UnMute()
- Added default (empty) implementations of AudioHW.. functions
2023-07-13 14:12:41 +01:00
Ross Owen
1574137dda - Update sofCount type
- Fix sync clock tests
2023-07-13 13:01:25 +01:00
Ross Owen
c7e782179c Added copyright/licence comments 2023-07-12 15:36:00 +01:00
Ross Owen
badcb71c80 - Added app PLL config functions - previously were in sw_usb_audio
- Use app PLL for sync mode
- Use app PLL on xcore.ai devices by default (unless ADAT or SPDIF receive enabled) 
- Added XUA_USE_APP_PLL (which is default 1)
- Some tidy of xua_conf_default.h
- Added DEFAULT_MCLK define
2023-07-11 13:57:14 +01:00
Ross Owen
dff72573f8 Scripted changelog update 2023-06-21 12:14:34 +01:00
Ross Owen
aaaf1e9652 Version bump 3.5.0 -> 3.5.1 2023-06-21 12:11:56 +01:00
Ross Owen
d6b23cf960 Merge pull request #337 from xross/develop
Respect I2S_CHANS_PER_FRAME when calculating bit-clock rates
2023-06-21 10:06:57 +01:00
Ross Owen
fa8329edaa Changelog update 2023-06-20 20:04:17 +01:00
Ross Owen
83d86e885f Respect I2S_CHANS_PER_FRAME when calculating bit-clock rates 2023-06-20 19:36:26 +01:00
Ross Owen
b1b28f1005 Merge pull request #335 from xross/fix/258
bNumConfigurations changes from 2 to 1
2023-06-14 19:09:28 +01:00
Ross Owen
6d41cfcbea Merge pull request #336 from xross/fix/155
Removed application space HID related function prototype
2023-06-14 16:06:58 +01:00
Ross Owen
5404127dbf Removed application space HID related function prototype 2023-06-14 15:30:37 +01:00
Ross Owen
e5a270347a bNumConfigurations changes from 2 to 1 2023-06-14 14:36:39 +01:00
Ross Owen
f509a12e7d Merge pull request #334 from xross/release_prep
Release prep
2023-06-14 14:23:39 +01:00
Ross Owen
4528bed740 Readme, changelog and version update 2023-06-14 12:58:51 +01:00
Ross Owen
e812ca3e8b Merge remote-tracking branch 'upstream/develop' into release_prep 2023-06-14 12:39:17 +01:00
Ross Owen
2accc0429f Merge pull request #333 from danielpieczko/develop
Update copyright years
2023-06-14 10:30:29 +01:00
Daniel Pieczko
36d5201365 Update copyright years 2023-06-14 08:09:33 +01:00
Ross Owen
cea580ba48 Merge pull request #332 from henkmuller/feature/static-hid-descriptor
Enabling a static HID report descriptor
2023-06-13 16:46:14 +01:00
Ross Owen
6815f12a90 Update copyright comment 2023-06-12 17:16:56 +01:00
Ross Owen
799ad7ba86 Update copyright comment 2023-06-12 17:16:43 +01:00
Ross Owen
3d7e66bdc0 Update copyright comment 2023-06-12 17:16:26 +01:00
Ross Owen
a6387d5fef Update copyright comment 2023-06-12 17:16:11 +01:00
Ross Owen
5ca0738b02 Update copyright comment 2023-06-12 17:15:42 +01:00
Ross Owen
b0e732110d Update copyright comment 2023-06-12 17:15:21 +01:00
Ross Owen
1702078e7c Update copyright comment 2023-06-12 17:14:42 +01:00
Henk Muller
136ec2506c One of the intermediate XUA_HID_REQUIRED slipped through the refactoring 2023-06-12 09:20:43 +01:00
Henk Muller
45e5ef7702 Enabling a static HID report descriptor in addition to the built-in dynamically created one. This is required for AudioWeaver. This also enables the option of an OUT HID endpoint 2023-06-10 18:07:25 +01:00
Ross Owen
1ef5129fde Variable i2s bit width (#331)
- Add support for variable width I2S (via XUA_I2S_N_BITS)
- Add support for variable width TDM (again via XUD_I2S_N_BITS when XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM)
- Includes support for xcore as I2S/TDM master and slave
- Add testing of the the above to test_i2s_loopback
- Rationalised test config building in test_i2s_loopback
- Documentation updated
2023-06-08 15:31:12 +01:00
Ross Owen
b1fe49aff3 Conflicted merge 2023-06-02 14:06:13 +01:00
Brennan Magee
d3ad29e8a6 Merge pull request #330 from BrennanGit/fix/jenkins_windows_bat_sh
Use bat not sh for windows builds on Jenkins
2023-05-31 09:38:31 +01:00
Brennan Magee
17944ad908 Use bat not sh for windows builds on Jenkins
This was causing an issue where the windows workspaces could not be cleared.
2023-05-30 17:08:32 +01:00
danielpieczko
131dd252c0 Merge pull request #329 from danielpieczko/jenkins_windows_build_fix
Use withVS instead of runVS to use the latest Jenkins Windows agents
2023-05-19 09:20:11 +01:00
Daniel Pieczko
23d043630f Use withVS instead of runVS to use the latest Jenkins Windows agents 2023-05-19 09:03:33 +01:00
Ross Owen
761a33f5e4 Update CHANGELOG.rst 2023-05-18 10:07:25 +01:00
Ross Owen
12ec1d7536 module_build_info: lib_xud 2.2.2 -> 2.2.3 2023-05-18 10:05:30 +01:00
Ross Owen
2dba6dce36 Update CHANGELOG.rst 2023-05-18 10:04:36 +01:00
Ross Owen
9cf931898e Move check for XUA_USB_EN after include of xua.h (#325) 2023-05-17 14:55:37 +01:00
Ross Owen
9b104af8cf Merge branch 'develop' into develop 2023-05-17 14:00:38 +01:00
Ross Owen
c469dd6cde Changelog update 2023-05-17 13:58:56 +01:00
Ross Owen
b238196f74 Copyright comment only 2023-05-17 13:55:41 +01:00
Ross Owen
e9586b59d3 Move check for XUA_USB_EN after include of xua.h 2023-05-17 13:48:36 +01:00
Ross Owen
6d168b3209 Merge pull request #321 from TDW89/fix/SPDIF-api
SPDIF api fix
2023-05-17 11:05:57 +01:00
Ross Owen
d301fef6d7 Merge pull request #324 from xross/fix/sw_usb_audio_156
Fix for exception when entering DSD mode (also some tidies)
2023-05-15 10:24:47 +01:00
Ross Owen
1f4e9a99b8 Changelog update 2023-05-12 17:36:04 +01:00
Ross Owen
981ea78be7 Fix for exception when entering DSD mode (also some tidies) 2023-05-12 17:22:47 +01:00
Ross Owen
6cee90d876 Fix audio interrupt endpoint type
Note, this has no functional change
2023-04-17 12:23:27 +01:00
Tom Williams
79d14f8b59 changed to use spdif_rx from SpdifReceive 2023-04-05 17:34:33 +01:00
danielpieczko
05dcb8f3ab Merge pull request #323 from danielpieczko/fix/mixer_init
Fix memory corruption during initialisation of mixer weights
2023-04-04 14:54:57 +01:00
Daniel Pieczko
4e7ddb4036 Fix memory corruption during initialisation of mixer weights 2023-04-04 14:31:35 +01:00
Ross Owen
e8fcc80415 Merge pull request #322 from xross/fix/sw_usb_audio_152
Tidy up of volume control. Removal of xc_ptr.h in favour of built in xc pointers
2023-04-04 14:15:07 +01:00
Ross Owen
71a657dc9a Tidy up of volume control. Removal of xc_ptr.h in favour of built in xc pointers. 2023-04-04 12:37:59 +01:00
Tom Williams
ccfca90451 removed referance to outdated header file, changed for the api file 2023-03-22 15:56:28 +00:00
Ross Owen
cb379f5bfb 'Release: 3.4.0' 2023-03-15 13:02:04 +00:00
Ross Owen
e2c36a9a95 xpd: Cleaned up whitespace 2023-03-15 13:00:39 +00:00
Ross Owen
7e3ae59acc Changelog update and version bump 3.3.1 -> 3.4.0 2023-03-15 12:28:39 +00:00
Ross Owen
f1f453921b Merge pull request #320 from xross/fix/mixer_lock
Improve mixer control protocol to avoid deadlock
2023-03-14 12:52:44 +00:00
Ross Owen
7703fc1a7d Fixed build warning when mixer not enabled 2023-03-14 11:49:08 +00:00
Ross Owen
53a65344fc Improve mixer control protocol to avoid deadlock 2023-03-14 11:48:54 +00:00
Ross Owen
3b2814f8cb Merge pull request #319 from xross/fix/spdif_output_opts 2023-03-13 16:50:40 +00:00
Ross Owen
55a62cf589 - Fixed build issue with !FAST_MIXER
- Fixed issue with !OUT_VOLUME_AFTER_MIX not being respected
2023-03-13 15:50:45 +00:00
Ross Owen
4a84c3e1ec OUT_VOLUME_IN_MIXER enabled by default 2023-03-13 15:49:54 +00:00
Ross Owen
b17f585004 Decouple optimisation for when output slot size = 4 (note, trades off code size) 2023-03-13 14:33:22 +00:00
Ross Owen
57593bfea3 Fixed issue with STREAM_FORMAT_OUTPUT_RESOLUTION_32_BIT_USED be set incorrectly 2023-03-13 14:31:53 +00:00
Ross Owen
8dc77090bf Merge pull request #318 from xross/develop
Reinstate check for current samplerate before changing
2023-03-09 16:42:26 +00:00
Ross Owen
9c20fab216 Updated copyright comment 2023-03-09 15:32:15 +00:00
Ross Owen
cf1940245f Return value of XUD_DoSetRequestStatus in Samp freq change 2023-03-09 15:24:21 +00:00
Ross Owen
837b648bbc Reinstate check for current samplerate before changing 2023-03-09 15:22:58 +00:00
Ross Owen
c1159143ea Fastmix.S now uses defines from xua.h 2023-03-09 14:56:54 +00:00
Ross Owen
2964861b70 Fixed xua.h including in asm files 2023-03-09 14:51:32 +00:00
Ross Owen
208491fe51 Added mixer control unit tests (#316)
* Added test_mixer_routing_output_ctrl
* Added test_mixer_routing_input_ctrl 
* Some minor mixer test and code improvements
* Update lib_xud dep version requirement
2023-03-08 10:53:33 +00:00
TDW89
3fe4593b52 Mixer Host App: Multi device error handeling & device ID agnostic (#315)
Removed device product ID requirement from macOS and added error messages when multiple devices are connected
2023-03-02 16:01:17 +00:00
TDW89
49a116c705 Minor updates (#314)
* SDK location can now set in makefile
* Mixer requirements added to readme
* Uncommented previously broken mixer example from docs as this functionality is now working
* Fixed windows build & runtime info in README
2023-03-01 10:59:00 +00:00
Ross Owen
eee5b474a0 Merge pull request #312 from TDW89/unify_win_osx_code
Unify win osx code
2023-02-20 11:56:04 +00:00
Ross Owen
4655a07542 Merge pull request #313 from xross/develop 2023-02-17 14:04:14 +00:00
Ross Owen
c578bb92d5 Fix build issue with volume processing in mixer (missing xc_ptr func) 2023-02-17 12:10:51 +00:00
Tom Williams
d5a614df55 removed old usb_mixer files 2023-02-15 14:28:27 +00:00
Tom Williams
495140ab8d adding OSX\usb_mixer.cpp changes from mixer tests branch to the combined usb_mixer.cpp file 2023-02-15 13:12:28 +00:00
Tom Williams
f53c1bab09 fixed merge conflict in OSX makefile 2023-02-15 11:47:28 +00:00
Ross Owen
0c6d947e67 Merge pull request #307 from xross/feature/mixer_tests
Feature/mixer tests
2023-02-09 10:51:08 +00:00
Tom Williams
ee271e3769 fixed typos and build issues 2023-02-08 17:49:58 +00:00
Ross Owen
950beb55cb - Fixed ifndef check
- Fixed mix map update
2023-02-08 17:06:08 +00:00
Tom Williams
ca3276792a initial unified version of usb_mixer.cpp 2023-02-08 16:58:18 +00:00
Ross Owen
e26b934233 Conflicted merge from upstream/develop 2023-02-08 13:58:25 +00:00
Ross Owen
51629dba24 Merge pull request #310 from TDW89/host_usb_win
Host usb win pull_v2
2023-02-08 13:56:46 +00:00
Ross Owen
c5e944d73d Use of storeShort function in mixer weight read and comment updates 2023-02-08 13:18:28 +00:00
Ross Owen
22a3d5e043 Added array to size to extern to fix sizeof usage error 2023-02-08 12:20:42 +00:00
Ross Owen
58f691078d Added range checking when getting/setting mixer weights 2023-02-08 12:04:38 +00:00
Ross Owen
f80d7647e0 - Make usage (of lack of) of CS when setting/getting mixer weights more clear in the implementation
- Fix typo in IN_VOLUME_IN_MIXER define
2023-02-08 11:59:13 +00:00
Tom Williams
fe697929bc merge testing branch and osx updates into branch 2023-02-08 11:59:07 +00:00
Tom Williams
b265ccd8bf Merge remote-tracking branch 'xmos/develop' into develop
bringing personal fork up to date
2023-02-08 10:39:25 +00:00
Ross Owen
6c2e7e3042 Fixed issue setting mix maps (#308) 2023-02-08 10:02:32 +00:00
Ross Owen
15ca5ec281 Fixed unused var warning 2023-02-07 16:35:38 +00:00
Ross Owen
71aa64425d Added missing bounds checking when setting host and device maps in the mixer 2023-02-07 12:14:19 +00:00
Ross Owen
9080990234 Fixed typo in define check 2023-02-06 23:44:20 +00:00
Ross Owen
6d8cf9913f Increase timeout cycles for test_mixer_routing_output 2023-02-06 23:42:33 +00:00
Ross Owen
60040de58f Further build issue fixes and copyright comments 2023-02-06 21:08:47 +00:00
Ross Owen
27a59ab3bc - Fixed MIXER define usage in main
- Fixed unsafe pointer usage when MAX_MIX_COUNT=0
- Fixed syntax error building mixer when no features enabled relating to empty switch statement
2023-02-06 21:05:48 +00:00
Ross Owen
317e27e421 - Rationalised MIXER defines and usage
- Further removal of xc_ptr type usage in mixer in favour of native xc pointers
2023-02-06 20:28:29 +00:00
Ross Owen
035c20e01c Fixed build issue in mixer when FAST_MIXER not used 2023-02-06 18:14:48 +00:00
Ross Owen
ef97d667de Further moving of mixer from xc_ptr type to XC pointers 2023-02-06 18:09:33 +00:00
Ross Owen
0e07dc29bc Fix issue in mixer host app when retrieving mixer input strings. Also firmed up some usage error checking. 2023-02-03 11:09:43 +00:00
Ross Owen
43f77c177d Small updates to mixer control README 2023-02-03 11:08:23 +00:00
Ross Owen
6754f812c9 Fixed issues with setting mix map in mixer host app 2023-02-03 11:08:06 +00:00
Ross Owen
fc732b8512 Updated changelog 2023-02-03 11:06:40 +00:00
Ross Owen
39ed235476 Removed old module_description file 2023-02-03 11:06:23 +00:00
Ross Owen
0d7224bd6d Added -arch for to mixer host app makefile 2023-02-03 11:06:13 +00:00
Ross Owen
fd4dfd40a9 Tidy .gitignore 2023-02-03 11:05:21 +00:00
Ross Owen
3d50c96595 - Removed dead XTA pragmas and code from mixer
- Added some more asserts to mixer
2023-02-03 10:59:20 +00:00
Tom Williams
379e8eb54c changed jenkins file to use sh rather than runVS 2023-02-01 16:29:05 +00:00
Tom Williams
63763cf4f5 fixed progect file & typo in jenkinsfile 2023-02-01 15:50:42 +00:00
Tom Williams
b18c34fb0f OSX makefile changed to work on M1, VS project file changed to 2019 (toolset 142) and Jenkins file now builds and archives the binaries 2023-02-01 14:11:47 +00:00
Tom Williams
64d65afeaf project file fixes 2023-02-01 13:43:53 +00:00
Tom Williams
7a47d70229 Revert "added path variable to link project to sdk"
This reverts commit cffd35d146.
2023-02-01 13:40:54 +00:00
Ross Owen
ce8e5a6dbb Merge branch 'develop' into feature/mixer_tests 2023-02-01 12:01:47 +00:00
Ross Owen
bbed806aab Merge remote-tracking branch 'upstream' into develop 2023-02-01 12:01:21 +00:00
Ross Owen
9af31b8c70 Merge pull request #305 from TDW89/host_usb_mixer_control
host_usb_mixer_control_OSX_support
2023-02-01 12:00:45 +00:00
Ross Owen
73955c1a4c - Added mixer related defines to reduce use of magic numbers
- Increases debug output when DEBUG flag set
- Removed some dead code
- Increased alignment of asm mixer functions
- Removed some usages of “xc_ptr” type in favour of native pointers in XC
- Added some asserts to mixer
- Added test_mixer_routing_input
- Moved test_mixer_routing_output to use shared code
2023-02-01 11:54:48 +00:00
Tom Williams
cffd35d146 added path variable to link project to sdk 2023-01-25 16:31:05 +00:00
Tom Williams
ab535e0fb3 removed temporary debug code 2023-01-25 11:07:49 +00:00
Tom Williams
17b039dce8 licence updates 2023-01-25 10:48:44 +00:00
Tom Williams
7a0d0e1f97 Initial windows commit 2023-01-25 10:23:57 +00:00
Tom Williams
2f31260612 updated copyright headers 2023-01-18 16:51:47 +00:00
Tom Williams
9922190450 removed versioning and license files as they are now part of the top level. added the help option to the readme 2023-01-18 16:01:08 +00:00
Ross Owen
0ce91bec90 Copyright comment 2023-01-17 12:12:46 +00:00
Ross Owen
2404eaf35f Remove extern, mark static inline 2023-01-17 11:53:44 +00:00
Ross Owen
8966ad1bb9 Add external linkage to inline DoSampleTransfer 2023-01-17 11:39:22 +00:00
Ross Owen
513761ef5b Moved DoSampleTransfer to a header file so it can still be inlined (but also used in unit tests). Resolves fails in test_i2s_loopback 2023-01-17 11:33:52 +00:00
Ross Owen
da7c45500d - Added test_mixer_routing_output
- Various buffers no longer marked static to allow for easier unit testing 
- Added some comments and removed some dead code from the implementation
- Moved mixer control comms to functions for unit test convenience
2023-01-16 17:28:04 +00:00
Ross Owen
395c88cb22 - Removed unused mixer variable.
- Use of mixer defines rather than fixed values
2023-01-10 11:27:37 +00:00
Tom Williams
94e58edfaf documentation clarifications and some spelling / grammer fixes 2022-12-21 17:22:39 +00:00
Tom Williams
9f00f9159a improvements to documentation 2022-12-21 15:07:14 +00:00
Tom Williams
785a857ca8 moved mixer control to correct path 2022-12-01 09:37:20 +00:00
Tom Williams
3130088c91 Initial commit for host_usb_mixer_control 2022-11-23 17:53:47 +00:00
Ross Owen
c51ee0c460 Removed extra whitespace from example makefiles 2022-11-21 20:05:49 +00:00
danielpieczko
17ed636a74 Merge pull request #303 from danielpieczko/no_usb_chans_in
Avoid calling SetupZerosSendBuffer when there are no IN eps
2022-11-16 10:06:03 +00:00
Daniel Pieczko
0db1b08948 Add changelog entry 2022-11-11 08:56:20 +00:00
Daniel Pieczko
9c460f753f Avoid calling SetupZerosSendBuffer when there are no IN eps 2022-11-10 16:44:34 +00:00
danielpieczko
6a9537fb69 Merge pull request #302 from danielpieczko/develop
Revert TDM ADC clocking change from commit a1946f3
2022-11-07 14:29:16 +00:00
Daniel Pieczko
abfa3a2011 Revert TDM ADC clocking change from commit a1946f3 2022-11-07 08:59:56 +00:00
xross
a1946f340a Remove TDM ADC clocking on neg edge 2022-11-01 19:24:25 +00:00
xross
28be17282f 'Release: 3.3.1' 2022-10-26 18:33:46 +01:00
Ross Owen
a1082b1dfd Documentation
Documentation updates and version bump
2022-10-26 17:48:51 +01:00
136 changed files with 8380 additions and 1704 deletions

56
.gitignore vendored
View File

@@ -1,29 +1,25 @@
*.log
*.dSYM
*/.build_*/*
*/bin/*
*.o
# XMOS bin files
*.xe
*.vcd
*.swo
*.bin
*/bin/*
# XMOS temp files
.build*
*.a
_build*
*.i
*.s
*.xi
*.i
*.bin
*~
*.a
*.swp
*.*~
*.pyc
.build*
*.o
*/.build_*/*
# Temp files
.DS_Store
test_results.csv
_build*
**/.venv/**
**/.vscode/**
**.egg-info
*.pdf
*tests/logs/*
*.*~
*.swp
*.swn
*~
*.swo
# waf build files
.lock-waf_*
@@ -36,3 +32,19 @@ xscope.xmt
# Traces
*.gtkw
*.vcd
# Host binaries
host_usb_mixer_control/xmos_mixer
# Documentation build
*.pdf
# Misc
*.log
*.dSYM
*.vcd
*.pyc
**/.venv/**
**/.vscode/**
**.egg-info
*tests/logs/*

View File

@@ -1,6 +1,63 @@
lib_xua Change Log
==================
3.5.1
-----
* FIXED: Respect I2S_CHANS_PER_FRAME when calculating bit-clock rates
* Changes to dependencies:
- lib_spdif: 5.0.0 -> 5.0.1
3.5.0
-----
* ADDED: Configurable word-length for I2S/TDM via XUA_I2S_N_BITS
* ADDED: Support for statically defined custom HID descriptor
* CHANGED: Rearranged main() such that adding custom code that uses lib_xud
is possible
* CHANGED: bNumConfigurations changed from 2 to 1, removing a work-around to
stop old Windows versions loading the composite driver
* FIXED: Memory corruption due to erroneous initialisation of mixer
weights when not in use (#152)
* FIXED: UserHostActive() not being called as expected (#326)
* FIXED: Exception when entering DSD mode (#327)
* Changes to dependencies:
- lib_spdif: 4.2.1 -> 5.0.0
- lib_xud: 2.2.2 -> 2.2.3
3.4.0
-----
* ADDED: Unit tests for mixer functionality
* ADDED: Host mixer control applications (for Win/macOS)
* CHANGED: Small tidies to mixer implementation
* CHANGED: Improved mixer control channel communication protocol to avoid
deadlock situations
* CHANGED: By default, output volume processing occurs in mixer task, if
present. Previously occurred in decouple task
* CHANGED: Some optimisations in sample transfer from decouple task
* FIXED: Exception on startup when USB input disabled
* FIXED: Full 32bit volume processing only applied when required
* FIXED: Setting OUT_VOLUME_AFTER_MIX to zero now has the expected effect
* Changes to dependencies:
- lib_xud: 2.2.1 -> 2.2.2
3.3.1
-----
* CHANGED: Documentation updates
* Changes to dependencies:
- lib_spdif: 4.1.0 -> 4.2.1
3.3.0
-----

22
Jenkinsfile vendored
View File

@@ -1,4 +1,4 @@
@Library('xmos_jenkins_shared_library@v0.18.0') _
@Library('xmos_jenkins_shared_library@v0.24.0') _
getApproval()
@@ -24,7 +24,7 @@ pipeline {
}
stage('Library checks') {
steps {
xcoreLibraryChecks("${REPO}")
xcoreLibraryChecks("${REPO}", false)
}
}
stage('Testing') {
@@ -106,6 +106,12 @@ pipeline {
dir("${REPO}/${REPO}/host/xmosdfu") {
sh 'make -f Makefile.OSX64'
}
dir("${REPO}/host_usb_mixer_control") {
sh 'make -f Makefile.OSX'
sh 'mkdir OSX/x86'
sh 'mv xmos_mixer OSX/x86/xmos_mixer'
archiveArtifacts artifacts: "OSX/x86/xmos_mixer", fingerprint: true
}
}
post {
cleanup {
@@ -139,7 +145,17 @@ pipeline {
dir("${REPO}") {
checkout scm
dir("${REPO}/host/xmosdfu") {
runVS('nmake /f Makefile.Win32')
withVS("vcvars32.bat") {
bat "nmake /f Makefile.Win32"
}
}
dir("host_usb_mixer_control") {
withVS() {
bat 'msbuild host_usb_mixer_control.vcxproj /property:Configuration=Release /property:Platform=x64'
}
bat 'mkdir Win\\x64'
bat 'mv bin/Release/x64/host_usb_mixer_control.exe Win/x64/xmos_mixer.exe'
archiveArtifacts artifacts: "Win/x64/xmos_mixer.exe", fingerprint: true
}
}
}

View File

@@ -1,20 +1,19 @@
lib_xua
=======
:Latest release: 3.3.0
#######
:Version: 3.5.0
:Vendor: XMOS
:Scope: General Use
Summary
-------
*******
lib_xua contains shared components for use in the XMOS USB Audio (XUA) Reference Designs.
These components enable the development of USB Audio devices on the XMOS xCORE architecture.
Features
~~~~~~~~
========
Key features of the various components in this repository are as follows
@@ -40,9 +39,9 @@ Key features of the various components in this repository are as follows
- Synchronisation to external digital streams i.e. S/PDIF or ADAT (when in asynchronous mode)
- I2S slave & master modes
- I2S (slave/master modes with configurable word-length)
- TDM slave & master modes
- TDM (slave/master modes with configurable word-length)
- MIDI input/output (Compliant to USB Class Specification for MIDI devices)
@@ -52,11 +51,13 @@ Key features of the various components in this repository are as follows
- Simple playback controls via USB Human Interface Device (HID) Class
- Support for adding custom HID interfaces
Note, not all features may be supported at all sample frequencies, simultaneously or on all devices.
Some features may also require specific host driver support.
Host System Requirements
~~~~~~~~~~~~~~~~~~~~~~~~
========================
USB Audio devices built using `lib_xua` have the following host system requirements.
@@ -69,27 +70,33 @@ USB Audio devices built using `lib_xua` have the following host system requireme
Older versions of Windows are not guaranteed to operate as expected. Devices are also expected to operate with various Linux distributions including mobile variants.
Related Application Notes
~~~~~~~~~~~~~~~~~~~~~~~~~
=========================
The following application notes use this library:
* AN000246 - Simple USB Audio Device using lib_xua
* AN000247 - Using lib_xua with lib_spdif (transmit)
* AN000248 - Using lib_xua with lib_mic_array
* AN000246 - Simple USB Audio Device using lib_xua
* AN000247 - Using lib_xua with lib_spdif (transmit)
* AN000248 - Using lib_xua with lib_mic_array
Required software (dependencies)
Required Software (dependencies)
================================
* lib_locks (git@github.com:xmos/lib_locks.git)
* lib_logging (git@github.com:xmos/lib_logging.git)
* lib_mic_array (git@github.com:xmos/lib_mic_array.git)
* lib_xassert (git@github.com:xmos/lib_xassert.git)
* lib_dsp (git@github.com:xmos/lib_dsp)
* lib_i2c (git@github.com:xmos/lib_i2c.git)
* lib_i2s (git@github.com:xmos/lib_i2s.git)
* lib_gpio (git@github.com:xmos/lib_gpio.git)
* lib_mic_array_board_support (git@github.com:xmos/lib_mic_array_board_support.git)
* lib_spdif (git@github.com:xmos/lib_spdif.git)
* lib_xud (git@github.com:xmos/lib_xud.git)
* lib_adat (git@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_xud (www.github.com/xmos/lib_xud)
* lib_adat (www.github.com/xmos/lib_adat)
Documentation
=============
You can find the documentation for this software in the /doc directory of the package.
Support
=======
This package is supported by XMOS Ltd. Issues can be raised against the software at: http://www.xmos.com/support

View File

@@ -21,4 +21,3 @@ USED_MODULES = lib_xua lib_xud lib_i2c
XMOS_MAKE_PATH ?= ../..
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -1,9 +1,8 @@
// Copyright 2017-2022 XMOS LIMITED.
// Copyright 2017-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include <platform.h>
#include "xua.h"
#include "../../shared/apppll.h"
on tile[0]: out port p_ctrl = XS1_PORT_8D;
@@ -35,11 +34,6 @@ void ctrlPort()
void AudioHwInit()
{
/* Wait for power supply to come up */
delay_milliseconds(100);
/* Use xCORE Secondary PLL to generate *fixed* master clock */
AppPllEnable_SampleRate(DEFAULT_FREQ);
delay_milliseconds(100);
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
@@ -48,9 +42,12 @@ void AudioHwInit()
*/
}
/* Configures the external audio hardware for the required sample frequency */
/* 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
*/
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
{
AppPllEnable_SampleRate(samFreq);
/* Nothing required since the DAC's will auto detect the sample rate from the clocks */
}

View File

@@ -20,4 +20,3 @@ USED_MODULES = lib_xua lib_xud lib_spdif
XMOS_MAKE_PATH ?= ../..
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -1,9 +1,8 @@
// Copyright 2017-2022 XMOS LIMITED.
// Copyright 2017-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include <platform.h>
#include "xua.h"
#include "../../shared/apppll.h"
on tile[0]: out port p_ctrl = XS1_PORT_8D;
@@ -35,11 +34,6 @@ void ctrlPort()
void AudioHwInit()
{
/* Wait for power supply to come up */
delay_milliseconds(100);
/* Use xCORE Secondary PLL to generate *fixed* master clock */
AppPllEnable_SampleRate(DEFAULT_FREQ);
delay_milliseconds(100);
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
@@ -48,9 +42,12 @@ void AudioHwInit()
*/
}
/* Configures the external audio hardware for the required sample frequency */
/* 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
*/
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
{
AppPllEnable_SampleRate(samFreq);
/* Nothing required since the DAC's will auto detect the sample rate from the clocks */
}

View File

@@ -19,4 +19,3 @@ USED_MODULES = lib_xua lib_xud lib_mic_array
XMOS_MAKE_PATH ?= ../..
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -1,109 +0,0 @@
// Copyright 2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <stdint.h>
#include "xassert.h"
// App PLL setup
#define APP_PLL_CTL_BYPASS (0) // 0 = no bypass, 1 = bypass.
#define APP_PLL_CTL_INPUT_SEL (0) // 0 = XTAL, 1 = sysPLL
#define APP_PLL_CTL_ENABLE (1) // 0 = disabled, 1 = enabled.
// 24MHz in, 24.576MHz out, integer mode
// Found exact solution: IN 24000000.0, OUT 24576000.0, VCO 2457600000.0, RD 5, FD 512, OD 10, FOD 10
#define APP_PLL_CTL_OD_48 (4) // Output divider = (OD+1)
#define APP_PLL_CTL_F_48 (511) // FB divider = (F+1)/2
#define APP_PLL_CTL_R_48 (4) // Ref divider = (R+1)
#define APP_PLL_CTL_48 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
(APP_PLL_CTL_OD_48 << 23) | (APP_PLL_CTL_F_48 << 8) | APP_PLL_CTL_R_48)
// Fractional divide is M/N
#define APP_PLL_FRAC_EN_48 (0) // 0 = disabled
#define APP_PLL_FRAC_NPLUS1_CYCLES_48 (0) // M value is this reg value + 1.
#define APP_PLL_FRAC_TOTAL_CYCLES_48 (0) // N value is this reg value + 1.
#define APP_PLL_FRAC_48 ((APP_PLL_FRAC_EN_48 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_48 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_48)
// 24MHz in, 22.5792MHz out (44.1kHz * 512), frac mode
// Found exact solution: IN 24000000.0, OUT 22579200.0, VCO 2257920000.0, RD 5, FD 470.400 (m = 2, n = 5), OD 5, FOD 10
#define APP_PLL_CTL_OD_441 (4) // Output divider = (OD+1)
#define APP_PLL_CTL_F_441 (469) // FB divider = (F+1)/2
#define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
#define APP_PLL_CTL_441 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
(APP_PLL_CTL_OD_441 << 23) | (APP_PLL_CTL_F_441 << 8) | APP_PLL_CTL_R_441)
#define APP_PLL_FRAC_EN_44 (1) // 1 = enabled
#define APP_PLL_FRAC_NPLUS1_CYCLES_44 (1) // M value is this reg value + 1.
#define APP_PLL_FRAC_TOTAL_CYCLES_44 (4) // N value is this reg value + 1.define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
#define APP_PLL_FRAC_44 ((APP_PLL_FRAC_EN_44 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_44 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_44)
#define APP_PLL_DIV_INPUT_SEL (1) // 0 = sysPLL, 1 = app_PLL
#define APP_PLL_DIV_DISABLE (0) // 1 = disabled (pin connected to X1D11), 0 = enabled divider output to pin.
#define APP_PLL_DIV_VALUE (4) // Divide by N+1 - remember there's a /2 also afterwards for 50/50 duty cycle.
#define APP_PLL_DIV ((APP_PLL_DIV_INPUT_SEL << 31) | (APP_PLL_DIV_DISABLE << 16) | APP_PLL_DIV_VALUE)
/* TODO support more than two freqs..*/
void AppPllEnable(int32_t clkFreq_hz)
{
switch(clkFreq_hz)
{
case 44100*512:
// Disable the PLL
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
// Enable the PLL to invoke a reset on the appPLL.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
// Set the fractional divider if used
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_44);
break;
case 48000*512:
// Disable the PLL
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
// Enable the PLL to invoke a reset on the appPLL.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
// Set the fractional divider if used
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_48);
break;
default:
assert(0);
break;
}
// Wait for PLL output frequency to stabilise due to fractional divider enable
delay_microseconds(100);
// Turn on the clock output
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, APP_PLL_DIV);
}
void AppPllEnable_SampleRate(int32_t sampleRate_hz)
{
assert(sampleRate_hz >= 22050);
if(sampleRate_hz % 22050 == 0)
{
AppPllEnable(44100*512);
}
else
{
AppPllEnable(48000*512);
}
}

View File

@@ -0,0 +1,10 @@
all:
@echo =======================================================
@echo Build complete [module only - cannot be run on its own]
@echo =======================================================
clean:
@echo =======================================================
@echo Build clean [module only - cannot be run on its own]
@echo =======================================================

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>host_usb_mixer_control</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
<dictionary>
<key>?name?</key>
<value></value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.append_environment</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
<value>all</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildArguments</key>
<value></value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildCommand</key>
<value>xmake</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
<value>clean</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.contents</key>
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
<value>false</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
<value>all</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.stopOnError</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
<value>true</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.core.cnature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,2 @@
all:
g++ -g -o xmos_mixer usb_mixer.cpp mixer_app.cpp -I. -IOSX OSX/libusb-1.0.0.dylib -arch x86_64

View File

@@ -0,0 +1,5 @@
!if [set SDKPath=C:\Program^ Files\XMOS\tusbaudiosdk]
!endif
all:
msbuild host_usb_mixer_control.vcxproj /property:Configuration=Release /property:Platform=x64

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,117 @@
The XMOS USB Audio Reference Design, by default, contains an 18x8 mixer unit
(note that at sample rates above 96Khz only the first two outputs are
enabled).
----WINDOWS REQUIREMENTS----
Building the mixer on Windows requires the tusbaudio SDK from Thesycon. The
default location for the SDK is C:\Program Files\XMOS\tusbaudiosdk\
If it can be found on a different path then this can be changed in
Makefile.Win.
The mixer app on windows makes use of a USB dynamic library, also from Thesycon.
If required please contact thesycon.de for support.
----------------------------
This unit takes input takes 18 inputs: USB OUT channels 1..10 and
DEVICE IN channels 1..6,9..10 and produces 8 outputs: Mixer Output
1..8
Before the mixer there is an unit that allows the selection of the 18 mixer inputs
from all the possible device inputs (DAW and physical audio). This is
an extension unit with id 50 in the descriptors
After the mixer unit there is are channel map units for each output terminal:
Each of these outputs can select a source from one of 28 channels sources: USB OUT
channels 1..10, DEVICE IN channels 1..10 and Mixer Output 1..8
The channel map units are extension unit with init ids 51 and 52. This unit
lets you implement arbitrary routings including loopbacks.
The mixer is controlled on macOS via the command line utility
xmos_mixer. Running this application requires having the
libusb-1.0.0.dylib in the dynamic library load path. Sourcing the
setup.sh script will do this. Source code for the application is
provided as a guide on how to communicate with the device.
Here are the commands for the mixer application (note that the USB
audio reference design has only one unit so the mixer_id argument
should always be 0):
--help
--display-info
Show information about the device.
--display-mixer-nodes mixer_id
Display all the weights of all the mixer nodes (and their id) of a particular mixer.
--display-min mixer_id
Display the minimum allowable weights of a particular mixer.
--display-max mixer_id
Display the maximum allowable weights of a particular mixer.
--display-res mixer_id
Display the resolution of a particular mixer.
--set-value mixer_id mixer_unit value
Set the weight value in the mixer. The second argument should
correspond to the values shown by the --display-unit command. Values
can range from -127db to +128db with the special value -inf for mute.
--get-value mixer_id mixer_unit
Get the weight value in the mixer. The second argument should
correspond to the values shown by the --display-unit command. Values
can range from -127db to +128db with the special value -inf for mute.
--set-mixer-source mixer_id, dst_channel_id, src_channel_id
Allows the selection of the mixer inputs. Sets mixer input (dst) to src
--display-current-mixer-sources mixer_id
Displays the current inputs to a particular mixer
--display-available-mixer-sources mixer_id
Displays all the input channels available that can be fed into the inputs of a particular mixer
--set-aud-channel-map dst src
Sets a channel map value for the device audio output
--display-aud-channel-map
Show audio output channel map i.e. for each audio output of the device what the source is.
--display-aud-channel-map-sources
Show the available audio output channel map sources.
--set-daw-channel-map dst src
Sets a channel map value for the DAW output to the host
--display-daw-channel-map
Show audio output channel map i.e. for each DAW output to host, what the source is.
--display-daw-channel-map-sources
Show the DAW output channel map sources.
--get-mixer-levels-input
--get-mixer-levels-output
--vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId
--vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...

View File

@@ -0,0 +1,48 @@
// Copyright 2022-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/************************************************************************
*
* Module: global.h
* Description:
* APP global includes, constants, declarations, etc.
*
* Author(s):
* Udo Eberhardt
*
* Companies:
* Thesycon GmbH, Germany http://www.thesycon.de
*
************************************************************************/
#ifndef __global_h__
#define __global_h__
// define the Windows versions supported by the application
#define _WIN32_WINNT 0x0500 //Windows 2000 or later
//#define _WIN32_WINNT 0x0501 //Windows XP or later
//#define _WIN32_WINNT 0x0600 //Windows Vista or later
//#define _WIN32_WINNT 0x0A00 //Windows 10 or later
// exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
// version defs
//#include "version.h"
// libwn.h pulls in windows.h
#include "libwn.h"
// TUSBAUDIO driver API
#include "tusbaudioapi.h"
#include "TUsbAudioApiDll.h"
#endif // __global_h__
/*************************** EOF **************************************/

View File

@@ -0,0 +1,177 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{84eacf4f-e405-4909-b440-a04a84a3f8c8}</ProjectGuid>
<RootNamespace>
</RootNamespace>
<SDKPath Condition="'$(SDKPath)' == ''">C:\Program Files\XMOS\tusbaudiosdk</SDKPath>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
<Import Project="$(SDKPath)\source\tusbaudioapi_inc\tusbaudioapi_inc_vs2019.vcxitems" Label="Shared" />
<Import Project="$(SDKPath)\source\libwn_min\_libwn_min_vs2019.vcxitems" Label="Shared" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>.\bin\$(Configuration)\$(PlatformName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformName)_$(PlatformToolset)</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>.\bin\$(Configuration)\$(PlatformName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformName)_$(PlatformToolset)</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>
</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_AMD64;_CONSOLE;_UNICODE;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>.;.\Win;$(SDKPath)\source\shared;$(SDKPath)\source\inc;$(SDKPath)\source\libwn_min;$(SDKPath)\source\libwtl;$(SDKPath)\source\tusbaudioapi_inc</AdditionalIncludeDirectories>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ExceptionHandling>Async</ExceptionHandling>
<PrecompiledHeaderFile />
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<EnableUAC>false</EnableUAC>
<UACExecutionLevel />
<UACUIAccess />
<GenerateMapFile>true</GenerateMapFile>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>
</SDLCheck>
<PreprocessorDefinitions>_AMD64;_CONSOLE;_UNICODE;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>.;.\Win;$(SDKPath)\source\shared;$(SDKPath)\source\inc;$(SDKPath)\source\libwn_min;$(SDKPath)\source\libwtl;$(SDKPath)\source\tusbaudioapi_inc</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ExceptionHandling>Async</ExceptionHandling>
<PrecompiledHeaderFile />
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<EnableUAC>false</EnableUAC>
<UACExecutionLevel />
<UACUIAccess />
<GenerateMapFile>true</GenerateMapFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="usb_mixer.h" />
<ClInclude Include="Win\global.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="mixer_app.cpp" />
<ClCompile Include="usb_mixer.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="usb_mixer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Win\global.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="mixer_app.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Win\usb_mixer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@@ -0,0 +1,718 @@
// Copyright 2022-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "usb_mixer.h"
#define MIXER_UNIT_DISPLAY_VALUE 2
#define MIXER_UNIT_DISPLAY_MIN 3
#define MIXER_UNIT_DISPLAY_MAX 4
#define MIXER_UNIT_DISPLAY_RES 5
// TODO
// res, min, max
int mixer_init(void)
{
/* Open the connection to the USB mixer */
if (usb_mixer_connect() == USB_MIXER_FAILURE)
{
return USB_MIXER_FAILURE;
}
return USB_MIXER_SUCCESS;
}
int mixer_deinit(void) {
// Close the connection to the USB mixer
if (usb_mixer_disconnect() == USB_MIXER_FAILURE) {
return USB_MIXER_FAILURE;
}
return USB_MIXER_SUCCESS;
}
int mixer_display(unsigned int mixer_index, unsigned int type) {
int i = 0;
int j = 0;
int num_inputs = usb_mixer_get_num_inputs(mixer_index);
int num_outputs = usb_mixer_get_num_outputs(mixer_index);
printf("\n");
switch (type) {
case MIXER_UNIT_DISPLAY_VALUE:
//mixer_update_all_values(mixer_index);
printf(" Mixer Values (%d)\n", mixer_index);
printf(" ----------------\n\n");
break;
case MIXER_UNIT_DISPLAY_MIN:
printf(" Mixer Ranges Min (%d)\n", mixer_index);
printf(" --------------------\n\n");
break;
case MIXER_UNIT_DISPLAY_MAX:
printf(" Mixer Ranges Max (%d)\n", mixer_index);
printf(" --------------------\n\n");
break;
case MIXER_UNIT_DISPLAY_RES:
printf(" Mixer Ranges Res (%d)\n", mixer_index);
printf(" --------------------\n\n");
break;
default:
return USB_MIXER_FAILURE;
break;
}
printf(" \t\t\t");
printf("Mixer Outputs\n");
printf("\t\t ");
for (i = 0; i < num_outputs; i++) {
printf(" %d", i+1);
}
printf("\n");
for (i = 0; i < num_inputs; i++) {
printf(" %-20s", usb_mixer_get_input_name(mixer_index,i));
for (j = 0; j < num_outputs; j++) {
switch (type) {
case MIXER_UNIT_DISPLAY_VALUE:
{
double mixNodeVal = usb_mixer_get_value(mixer_index, (i*num_outputs)+j);
int nodeid = (i*num_outputs)+j;
if (mixNodeVal <= -127.996)// todo shoud be < min
{
printf("\t%3d:[ %s ]", nodeid,"-inf");
}
else
{
printf("\t%3d:[%08.03f]", nodeid, mixNodeVal);
}
}
break;
case MIXER_UNIT_DISPLAY_MIN:
{
int nodeid = (i*num_outputs)+j;
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_min(mixer_index, (i*num_outputs)+j)) ;
}
break;
case MIXER_UNIT_DISPLAY_MAX:
{
int nodeid = (i*num_outputs)+j;
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_max(mixer_index, (i*num_outputs)+j)) ;
}
break;
case MIXER_UNIT_DISPLAY_RES:
{
int nodeid = (i*num_outputs)+j;
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_res(mixer_index, (i*num_outputs)+j)) ;
}
break;
default:
return USB_MIXER_FAILURE;
break;
}
}
printf("\n");
}
printf("\n");
return USB_MIXER_SUCCESS;
}
/* Displays basic mixer information */
int mixer_display_info(void)
{
unsigned int i = 0;
int num_mixers = usb_mixer_get_num_mixers();
printf("\n");
printf(" Mixer Info\n");
printf(" ----------\n\n");
printf(" Mixers : %d\n\n", num_mixers);
for (i = 0; i < num_mixers; i++)
{
int num_inputs = usb_mixer_get_num_inputs(i);
int num_outputs = usb_mixer_get_num_outputs(i);
printf(" Mixer %d\n", i);
printf(" -------\n");
printf(" Inputs : %d\n"
" Outputs : %d\n\n", num_inputs, num_outputs);
printf(" Mixer Output Labels:\n");
for(int j = 0; j < num_outputs; j++)
{
printf(" %d: %s\n", j,usb_mixer_get_output_name(i,j));
}
//printf("\n Selectable Inputs (%d): \n", usb_mixsel_get_input_count(i));
//for(int j = 0; j < usb_mixsel_get_input_count(i); j++)
//{
// printf(" %d: %s\n", j, usb_mixsel_get_input_string(i,j));
//}
}
printf("\n");
return USB_MIXER_SUCCESS;
}
void display_available_mixer_sources(int mixIndex)
{
printf("\n");
printf(" Available Mixer Sources (%d)\n", mixIndex);
printf(" -------------------------\n\n");
for(int j = 0; j < usb_mixsel_get_input_count(mixIndex); j++)
{
printf(" %d: %s\n", j, usb_mixsel_get_input_string(mixIndex,j));
}
}
/* Gets the current mixer inputs from the device an displays them */
void display_mixer_sources(int mixerIndex)
{
printf("\n");
printf(" Current Mixer Sources (%d)\n", mixerIndex);
printf(" -------------------------\n\n");
/* Note, mixSel output cound and mixer input chan count should be the same! */
printf(" Number of mixer sources: %d\n", usb_mixsel_get_output_count(mixerIndex));
/* Get the current channel number for every mixer input */
for(int i = 0; i < usb_mixsel_get_output_count(mixerIndex); i++)
{
int inputChan = (int)usb_mixsel_get_state(mixerIndex, i);
char *str = usb_mixer_get_input_name(mixerIndex,inputChan);
printf(" Mixer input %d: Source chan id: %d (%s)\n", i, inputChan, str);
}
}
/* set mixer source */
void set_mixer_source(unsigned mixerIndex, unsigned dst, unsigned src)
{
usb_mixsel_set_state(mixerIndex, dst, src);
/* String lookup */
char *str = usb_mixer_get_input_name(mixerIndex, dst);
int state = usb_mixsel_get_state(mixerIndex, dst);
printf("\n Set mixer(%d) input %d to device input %d (%s)\n", mixerIndex, dst, state, str);
}
void display_aud_channel_map()
{
printf("\n");
printf(" Audio Output Channel Map\n");
printf(" ------------------------\n\n");
for (int i=0;i<usb_get_aud_channel_map_num_outputs();i++)
{
int x = usb_get_aud_channel_map(i);
printf("%d (DEVICE OUT - %s) source is ",i, usb_get_aud_channel_map_name(i));
switch (usb_get_aud_channel_map_type(x))
{
case USB_CHAN_OUT:
printf(" %d (DAW OUT - %s)\n",x,usb_get_aud_channel_map_name(x));
break;
case USB_CHAN_IN:
printf("%d (DEVICE IN - %s)\n",x,usb_get_aud_channel_map_name(x));
break;
case USB_CHAN_MIXER:
printf("%d (%s)\n",x,usb_get_aud_channel_map_name(x));
break;
}
}
}
void display_daw_channel_map()
{
printf("\n");
printf(" DAW Output To Host Channel Map\n");
printf(" ------------------------\n\n");
for (int i=0;i<usb_get_usb_channel_map_num_outputs();i++)
{
int x = usb_get_usb_channel_map(i);
printf("%d (DAW IN - %s) source is ",i, usb_get_usb_channel_map_name(i + usb_get_aud_channel_map_num_outputs()));
switch (usb_get_usb_channel_map_type(x))
{
case USB_CHAN_OUT:
printf(" %d (DAW OUT - %s)\n",x,usb_get_usb_channel_map_name(x));
break;
case USB_CHAN_IN:
printf("%d (DEVICE IN - %s)\n",x,usb_get_usb_channel_map_name(x));
break;
case USB_CHAN_MIXER:
printf("%d (%s)\n",x,usb_get_usb_channel_map_name(x));
break;
}
}
}
void display_aud_channel_map_sources(void)
{
printf("\n");
printf(" Audio Output Channel Map Source List\n");
printf(" ------------------------------------\n\n");
for (int i=0;i<usb_get_aud_channel_map_num_inputs();i++) {
switch (usb_get_aud_channel_map_type(i))
{
case USB_CHAN_OUT:
printf("%d (DAW OUT - %s)\n",i,usb_get_aud_channel_map_name(i));
break;
case USB_CHAN_IN:
printf("%d (DEVICE IN - %s)\n",i,usb_get_aud_channel_map_name(i));
break;
case USB_CHAN_MIXER:
printf("%d (%s)\n",i,usb_get_aud_channel_map_name(i));
break;
}
}
}
void display_daw_channel_map_sources(void)
{
printf("\n");
printf(" DAW Output to Host Channel Map Source List\n");
printf(" ------------------------------------------\n\n");
for (int i=0;i<usb_get_usb_channel_map_num_inputs();i++) {
switch (usb_get_usb_channel_map_type(i))
{
case USB_CHAN_OUT:
printf("%d (DAW OUT - %s)\n",i,usb_get_usb_channel_map_name(i));
break;
case USB_CHAN_IN:
printf("%d (DEVICE IN - %s)\n",i,usb_get_usb_channel_map_name(i));
break;
case USB_CHAN_MIXER:
printf("%d (%s)\n",i,usb_get_usb_channel_map_name(i));
break;
}
}
}
int usb_audio_request_get(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId, unsigned char *data)
{
char reqStr[] = "Custom";
if(bRequest == CUR)
{
strcpy(reqStr, "CUR");
}
else if(bRequest == RANGE)
{
strcpy(reqStr, "RANGE");
}
else if(bRequest == MEM)
{
strcpy(reqStr, "MEM");
}
printf("Performing class GET request to Audio Interface:\n\
bRequest: 0x%02x (%s)\n\
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
return usb_audio_class_get(bRequest, cs, cn, unitId, 64, data);
}
int usb_audio_request_set(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId,
unsigned char *data, int datalength)
{
char reqStr[] = "Custom";
if(bRequest == CUR)
{
strcpy(reqStr, "CUR");
}
else if(bRequest == RANGE)
{
strcpy(reqStr, "RANGE");
}
{
strcpy(reqStr, "MEM");
}
printf("Performing class SET request to Audio Interface:\n\
bRequest: 0x%02x (%s)\n\
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
return usb_audio_class_set(bRequest, cs, cn, unitId, datalength, data);
}
int usb_audio_memreq_get(unsigned unitId, unsigned offset, unsigned char *data)
{
/* Mem requests dont have CS/CN, just an offset.. */
return usb_audio_request_get(MEM, (offset>>8), offset&0xff, unitId, data);
}
void print_levels(const char* levelTitle, unsigned char* levels, int levelBytes)
{
unsigned levelCount = levelBytes/2;
unsigned short* levelData = (unsigned short*) levels;
printf("\n %s Level Data\n"
" ----------------------\n\n"
"%d bytes (%d channels) returned:\n"
, levelTitle, levelBytes, levelCount);
for(int i = 0; i<levelCount; i++)
{
printf("%s %d: 0x%04x\n", levelTitle, i,levelData[i]);
}
}
void mixer_display_usage(void) {
fprintf(stderr, "Usage :\n");
fprintf(stderr,
" --display-info\n"
" --display-mixer-nodes mixer_id\n"
" --display-min mixer_id\n"
" --display-max mixer_id\n"
" --display-res mixer_id\n"
" --set-value mixer_id, mixer_node, value\n"
" --get-value mixer_id, mixer_node\n"
"\n"
" --set-mixer-source mixer_id dst channel_id, src_channel_id\n"
" --display-current-mixer-sources mixer_id\n"
" --display-available-mixer-sources mixer_id\n"
"\n"
" --set-aud-channel-map dst_channel_id, src_channel_id\n"
" --display-aud-channel-map \n"
" --display-aud-channel-map-sources\n"
" --set-daw-channel-map dst_channel_id, src_channel_id\n"
" --display-daw-channel-map \n"
" --display-daw-channel-map-sources\n"
"\n"
" --get-mixer-levels-input mixer_id\n"
" --get-mixer-levels-output mixer_id\n"
" --vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId\n"
" --vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...\n"
);
}
void usage_error()
{
fprintf(stderr, "ERROR :: incorrect number of arguments passed. See --help\n");
}
int main (int argc, char **argv) {
unsigned int mixer_index = 0;
unsigned int result = 0;
if (argc < 2) {
fprintf(stderr, "ERROR :: No options passed to mixer application\n");
mixer_display_usage();
return -1;
}
if (strcmp(argv[1], "--help") == 0) {
mixer_display_usage();
return 0;
}
if (mixer_init() != USB_MIXER_SUCCESS) {
fprintf(stderr, "ERROR :: Cannot connect\n");
return -1;
}
if (strcmp(argv[1], "--display-info") == 0)
{
mixer_display_info();
}
else if (strcmp(argv[1], "--display-mixer-nodes") == 0)
{
if (argv[2])
{
mixer_index = atoi(argv[2]);
} 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) {
if (argv[2]) {
mixer_index = atoi(argv[2]);
} 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 {
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 {
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 {
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) {
unsigned int mixer_unit = 0;
double value = 0;
if (argc < 5) {
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)
value = -128;
else
value = atof(argv[4]);
usb_mixer_set_value(mixer_index, mixer_unit, value);
} else if (strcmp(argv[1], "--get-value") == 0) {
unsigned int mixer_unit = 0;
double result = 0;
if (argc < 4) {
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
return -1;
}
mixer_index = atoi(argv[2]);
mixer_unit = atoi(argv[3]);
result = usb_mixer_get_value(mixer_index, mixer_unit);
if (result <= -127.996)
printf("%s\n", "-inf");
else
printf("%g\n",result);
}
else if (strcmp(argv[1], "--display-current-mixer-sources") == 0)
{
if(argc < 3)
{
usage_error();
return -1;
}
display_mixer_sources(atoi(argv[2]));
}
else if (strcmp(argv[1], "--display-available-mixer-sources") == 0)
{
if(argc < 3)
{
usage_error();
return -1;
}
display_available_mixer_sources(atoi(argv[2]));
}
else if(strcmp(argv[1], "--set-mixer-source") == 0)
{
if(argc < 5)
{
usage_error();
return -1;
}
set_mixer_source(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
}
else if (strcmp(argv[1], "--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)
{
display_aud_channel_map_sources();
}
else if (strcmp(argv[1], "--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)
{
display_daw_channel_map_sources();
}
else if (strcmp(argv[1], "--set-aud-channel-map") == 0)
{
unsigned int dst = 0;
unsigned int src = 0;
if (argc != 4)
{
usage_error();
return -1;
}
dst = atoi(argv[2]);
src = atoi(argv[3]);
usb_set_aud_channel_map(dst, src);
}
else if (strcmp(argv[1], "--set-daw-channel-map") == 0)
{
unsigned int dst = 0;
unsigned int src = 0;
if (argc != 4)
{
usage_error();
return -1;
}
dst = atoi(argv[2]);
src = atoi(argv[3]);
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)
{
unsigned int dst = 0;
unsigned char levels[64];
int datalength = 0;
int offset = 0;
if (argc < 3) {
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
return -1;
}
if(strcmp(argv[1],"--get-mixer-levels-output") == 0)
offset = 1;
for(int i = 0; i < 64; i++)
levels[i] = 0;
dst = atoi(argv[2]);
/* Mem request to mixer with offset of 0 gives input levels */
datalength = usb_mixer_mem_get(dst, offset, levels);
if(datalength < 0)
{
fprintf(stderr, "ERROR in control request: %d\n", datalength);
return -1;
}
if(offset)
print_levels("Mixer Output", levels, datalength);
else
print_levels("Mixer Input", levels, datalength);
}
else if(strcmp(argv[1], "--vendor-audio-request-get") == 0)
{
unsigned int bRequest = 0;
unsigned int cs = 0;
unsigned int cn = 0;
unsigned int unitId = 0;
int datalength = 0;
unsigned char data[64];
if(argc < 6)
{
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
return -1;
}
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]);
/* Do request */
datalength = usb_audio_request_get(bRequest, cs, cn, unitId, data);
/* Print result */
if(datalength < 0)
{
fprintf(stderr, "ERROR in control request: %d\n", datalength);
}
else
{
printf("Response (%d bytes):\n", datalength);
for(int i = 0; i < datalength; i++)
printf("0x%02x\n" ,data[i]);
}
}
else if(strcmp(argv[1], "--vendor-audio-request-set") == 0)
{
unsigned int bRequest = 0;
unsigned int cs = 0;
unsigned int cn = 0;
unsigned int unitId = 0;
unsigned char data[64];
for(int i=0; i<64; i++)
{
data[i] = 0;
}
if(argc < 7)
{
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]);
/* Get data */
for(int i=0; i < argc-6; i++)
{
data[i] = atoi(argv[i+6]);
}
result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-6);
if(result < 0)
{
fprintf(stderr, "ERROR :: Error detected in Set request: %d\n", result);
return -1;
}
}
else
{
fprintf(stderr, "ERROR :: Invalid option passed to mixer application\n");
return -1;
}
mixer_deinit();
return result;
}

View File

@@ -0,0 +1 @@
export DYLD_LIBRARY_PATH=$PWD/OSX:$DYLD_LIBRARY_PATH

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
// Copyright 2022-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#define USB_MIXER_SUCCESS 0
#define USB_MIXER_FAILURE -1
#define USB_MIXERS 1
#define USB_MIXER_INPUTS 18
#define USB_MIXER_OUTPUTS 8
#define USB_MAX_CHANNEL_MAP_SIZE 40
#define USB_MIXER_MAX_NAME_LEN 64
enum usb_chan_type {
USB_CHAN_OUT=0,
USB_CHAN_IN=1,
USB_CHAN_MIXER=2
};
/* A.14 Audio Class-Specific Request Codes */
#define REQUEST_CODE_UNDEFINED 0x00
#define CUR (1)
#define RANGE (2)
#define MEM (3)
int usb_mixer_connect();
int usb_mixer_disconnect();
/* MIXER UNIT(s) INTERFACE */
/* Returns total number of mixers in device */
int usb_mixer_get_num_mixers();
/* Returns number of inputs and outputs for a selected mixer */
int usb_mixer_get_layout(unsigned int mixer, unsigned int *inputs, unsigned int *outputs);
/* Returns the name for a selected mixer input */
char *usb_mixer_get_input_name(unsigned int mixer, unsigned int input);
/* Returns the name for a selected mixer output */
char *usb_mixer_get_output_name(unsigned int mixer, unsigned int output);
/* Returns the current value of a selected mixer unit */
double usb_mixer_get_value(unsigned int mixer, unsigned int mixer_unit);
/* Sets the current value for a selected mixer unit */
int usb_mixer_set_value(unsigned int mixer, unsigned int mixer_unit, double val);
/* Returns the range values for a selected mixer unit */
int usb_mixer_get_range(unsigned int mixer, unsigned int mixer_unit, double *min, double *max, double *res);
/* Returns the number of bytes read from a mem request, data is stored in data */
int usb_mixer_mem_get(unsigned int mixer, unsigned offset, unsigned char *data);
/* INPUT / OUTPUT / MIXER MAPPING UNIT INTERFACE */
/* Get the number of selectable inputs */
int usb_mixsel_get_input_count(unsigned int mixer);
/* Get the string of a input */
char *usb_mixsel_get_input_string(unsigned int mixer, unsigned int channel);
int usb_mixsel_get_output_count(unsigned int mixer);
int usb_mixer_get_num_outputs(unsigned int mixer);
int usb_mixer_get_num_inputs(unsigned int mixer);
unsigned char usb_mixsel_get_state(unsigned int mixer, unsigned int channel);
void usb_mixsel_set_state(unsigned int mixer, unsigned int dst, unsigned int src);
int usb_set_usb_channel_map(int channel, int val);
/* Get the current map for a specified input / output / mixer channel */
int usb_get_usb_channel_map(int channel);
int usb_get_aud_channel_map(int channel);
/* Maps an input / output / mixer channel to another input / output / mixer channel */
int usb_set_aud_channel_map(int channel, int val);
int usb_set_usb_channel_map(int channel, int val);
/* Gets the name of a specified channel */
char *usb_get_aud_channel_map_name(int channel);
char *usb_get_usb_channel_map_name(int channel);
/* Get the type of a channel map */
enum usb_chan_type usb_get_aud_channel_map_type(int channel);
enum usb_chan_type usb_get_usb_channel_map_type(int channel);
int usb_get_aud_channel_map_num_outputs();
int usb_get_usb_channel_map_num_outputs();
int usb_get_aud_channel_map_num_inputs();
int usb_get_usb_channel_map_num_inputs();
/* CUSTOM/GENERIC AUDIO CLASS REQUESTS */
int usb_audio_class_get(unsigned char bRequest, unsigned char cs, unsigned char cn, unsigned short unitID, unsigned short wLength, unsigned char *data);
int usb_audio_class_set(unsigned char bRequest, unsigned char cs, unsigned char cn, unsigned short unitID, unsigned short wLength, unsigned char *data);
double usb_mixer_get_res(unsigned int mixer, unsigned int nodeId);
double usb_mixer_get_min(unsigned int mixer, unsigned int nodeId) ;
double usb_mixer_get_max(unsigned int mixer, unsigned int nodeId) ;

View File

@@ -1,4 +1,4 @@
// Copyright 2017-2022 XMOS LIMITED.
// Copyright 2017-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUA_H_
#define _XUA_H_
@@ -7,14 +7,14 @@
#include "xua_conf_full.h"
#if __XC__ || __STDC__
#ifndef __ASSEMBLER__
#include "xua_audiohub.h"
#include "xua_endpoint0.h"
#include "xua_buffer.h"
#include "xua_mixer.h"
#endif
#if __XC__
#ifdef __XC__
#include "xua_clocking.h"
#include "xua_midi.h"
#if XUA_NUM_PDM_MICS > 0

View File

@@ -1,9 +1,9 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __XUA_AUDIOHUB_H__
#define __XUA_AUDIOHUB_H__
#ifndef _XUA_AUDIOHUB_H_
#define _XUA_AUDIOHUB_H_
#if __XC__
#ifdef __XC__
#include "xccompat.h"
#include "xs1.h"
@@ -12,6 +12,8 @@
#include "dfu_interface.h"
#endif
#include "xua_clocking.h"
/** The audio driver thread.
*
* This function drives I2S ports and handles samples to/from other digital
@@ -34,6 +36,8 @@
*
* \param p_i2s_adc Nullable array of ports for I2S data input lines
*
* \param i_SoftPll Interface to software PLL task
*
* \param c_spdif_tx Channel connected to S/PDIF transmiter core from lib_spdif
*
* \param c_dig Channel connected to the clockGen() thread for
@@ -47,6 +51,9 @@ void XUA_AudioHub(chanend ?c_aud,
buffered _XUA_CLK_DIR port:32 ?p_bclk,
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, client interface SoftPll_if i_SoftPll
#endif
#if (XUA_SPDIF_TX_EN) || defined(__DOXYGEN__)
, chanend c_spdif_tx
#endif
@@ -63,21 +70,28 @@ void XUA_AudioHub(chanend ?c_aud,
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__
void UserBufferManagementInit();
/**
* @brief User buffer management code
*
* This function is called at the sample rate of the USB Audio stack (e.g,. 48 kHz) and between the two parameter arrays
* contain a full multi-channel audio-frame. The first array carries all the data that has been received from the USB host
* and is to be presented to the audio interfaces. The second array carries all the data received from the interfaces and
* is to be presented to the USB host. The user can chose to intercept and overwrite the samples stored in these arrays.
*
* \param sampsFromUsbToAudio Samples received from USB host and to be presented to audio interfaces
*
* \param sampsFromAudioToUsb Samples received from the audio interfaces and to be presented to the USB host
*/
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
#endif // __XUA_AUDIOHUB_H__
/**
* @brief User buffer managment init code
*
* This function is called once, before the first call to UserBufferManagement(), and can be used to initialise any
* related user state
*/
void UserBufferManagementInit();
#endif // _XUA_AUDIOHUB_H_

View File

@@ -1,7 +1,7 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __XUA_BUFFER_H__
#define __XUA_BUFFER_H__
#ifndef _XUA_BUFFER_H_
#define _XUA_BUFFER_H_
#if __XC__
@@ -26,6 +26,7 @@
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
* \param c_aud Channel connected to XUA_AudioHub() core
* \param i_pll_ref Interface to task that toggles reference pin to CS2100
* \param c_swpll_update Channel connected to software PLL task. Expects master clock counts based on USB frames.
*/
void XUA_Buffer(
chanend c_aud_out,
@@ -51,8 +52,13 @@ void XUA_Buffer(
, chanend c_hid
#endif
, chanend c_aud
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOXYGEN__)
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
#if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, client interface pll_ref_if i_pll_ref
#endif
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, chanend c_swpll_update
#endif
#endif
);
@@ -81,10 +87,16 @@ void XUA_Buffer_Ep(chanend c_aud_out,
#ifdef CHAN_BUFF_CTRL
, chanend c_buff_ctrl
#endif
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOXYGEN__)
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
#if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, client interface pll_ref_if i_pll_ref
#endif
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
, chanend c_swpll_update
#endif
#endif
);
);
/** Manage the data transfer between the USB audio buffer and the
* Audio I/O driver.

View File

@@ -1,10 +1,11 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 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"
interface pll_ref_if
{
@@ -28,5 +29,46 @@ void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_sync);
interrupts
*/
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]]
#endif
void XUA_SoftPll(tileref tile, server interface SoftPll_if i_softPll, chanend c_update);
#endif
#endif

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/*
* @brief Defines relating to device configuration and customisation of lib_xua
@@ -11,7 +11,9 @@
#include "xua_conf.h"
#endif
/* Default tile arrangement */
/*
* Tile arrangement defines
*/
/**
* @brief Location (tile) of audio I/O. Default: 0
@@ -55,12 +57,9 @@
#define PLL_REF_TILE AUDIO_IO_TILE
#endif
/**
* @brief Disable USB functionalty just leaving AudioHub
/*
* Channel based defines
*/
#ifndef XUA_USB_EN
#define XUA_USB_EN (1)
#endif
/**
* @brief Number of input channels (device to host). Default: NONE (Must be defined by app)
@@ -79,7 +78,18 @@
#endif
/**
* @brief Number of DSD output channels. Default: 0 (disabled)
* @brief Number of PDM microphones in the design.
*
* Default: 0
*/
#ifndef XUA_NUM_PDM_MICS
#define XUA_NUM_PDM_MICS (0)
#endif
/**
* @brief Number of DSD output channels.
*
* Default: 0 (disabled)
*/
#if defined(DSD_CHANS_DAC) && (DSD_CHANS_DAC != 0)
#if defined(NATIVE_DSD) && (NATIVE_DSD == 0)
@@ -91,9 +101,41 @@
#define DSD_CHANS_DAC 0
#endif
/**
* @brief Number of I2S channesl to DAC/CODEC. Must be a multiple of 2.
*
* Default: NONE (Must be defined by app)
*/
#ifndef I2S_CHANS_DAC
#error I2S_CHANS_DAC not defined
#define I2S_CHANS_DAC 2 /* Define anyway for doxygen */
#else
#define I2S_WIRES_DAC (I2S_CHANS_DAC / I2S_CHANS_PER_FRAME)
#endif
/**
* @brief Number of I2S channels from ADC/CODEC. Must be a multiple of 2.
*
* Default: NONE (Must be defined by app)
*/
#ifndef I2S_CHANS_ADC
#error I2S_CHANS_ADC not defined
#define I2S_CHANS_ADC 2 /* Define anyway for doxygen */
#else
#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME)
#endif
/*
* Defines relating to the interface to external audio hardware i.e. DAC/ADC
*/
#define XUA_PCM_FORMAT_I2S (0)
#define XUA_PCM_FORMAT_TDM (1)
/**
* @brief Format of PCM audio interface. Should be set to XUA_PCM_FORMAT_I2S or XUA_PCM_FORMAT_TDM
*
* Default: XUA_PCM_FORMAT_I2S
*/
#ifdef XUA_PCM_FORMAT
#if (XUA_PCM_FORMAT != XUA_PCM_FORMAT_I2S) && (XUA_PCM_FORMAT != XUA_PCM_FORMAT_TDM)
#error Bad value for XUA_PCM_FORMAT
@@ -116,30 +158,17 @@
#endif
#endif
/**
* @brief Number of IS2 channesl to DAC/CODEC. Must be a multiple of 2.
* @brief Number of bits per channel for I2S/TDM. Supported values: 16/32-bit.
*
* Default: NONE (Must be defined by app)
* Default: 32 bits
*/
#ifndef I2S_CHANS_DAC
#error I2S_CHANS_DAC not defined
#define I2S_CHANS_DAC 2 /* Define anyway for doxygen */
#else
#define I2S_WIRES_DAC (I2S_CHANS_DAC / I2S_CHANS_PER_FRAME)
#ifndef XUA_I2S_N_BITS
#define XUA_I2S_N_BITS (32)
#endif
/**
* @brief Number of I2S channels from ADC/CODEC. Must be a multiple of 2.
*
* Default: NONE (Must be defined by app)
*/
#ifndef I2S_CHANS_ADC
#error I2S_CHANS_ADC not defined
#define I2S_CHANS_ADC 2 /* Define anyway for doxygen */
#else
#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME)
#if (XUA_I2S_N_BITS != 16) && (XUA_I2S_N_BITS != 32)
#error Unsupported value for XUA_I2S_N_BITS (only values 16/32 supported)
#endif
/**
@@ -193,22 +222,32 @@
#define I2S_DOWNSAMPLE_CHANS_IN I2S_CHANS_ADC
#endif
/*
* Clocking related defines
*/
/**
* @brief Max supported sample frequency for device (Hz). Default: 192000
* @brief Max supported sample frequency for device (Hz).
*
* Default: 192000Hz
*/
#ifndef MAX_FREQ
#define MAX_FREQ (192000)
#endif
/**
* @brief Min supported sample frequency for device (Hz). Default 44100
* @brief Min supported sample frequency for device (Hz).
*
* Default: 44100Hz
*/
#ifndef MIN_FREQ
#define MIN_FREQ (44100)
#endif
/**
* @brief Master clock defines for 44100 rates (in Hz). Default: NONE (Must be defined by app)
* @brief Master clock defines for 44100 rates (in Hz).
*
* Default: NONE (Must be defined by app)
*/
#ifndef MCLK_441
#error MCLK_441 not defined
@@ -216,7 +255,9 @@
#endif
/**
* @brief Master clock defines for 48000 rates (in Hz). Default: NONE (Must be defined by app)
* @brief Master clock defines for 48000 rates (in Hz).
*
* Default: NONE (Must be defined by app)
*/
#ifndef MCLK_48
#error MCLK_48 not defined
@@ -224,26 +265,66 @@
#endif
/**
* @brief Default device sample frequency. A safe default should be used. Default: MIN_FREQ
* @brief Enable/disable the use of the secondary/application PLL for generating master-clocks.
* Only available on xcore.ai devices.
*
* Default: Enabled (for xcore.ai devices)
*/
#ifndef XUA_USE_APP_PLL
#if defined(__XS3A__)
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
/* Currently must use an external CS2100 device for syncing to external digital streams */
#define XUA_USE_APP_PLL (0)
#else
#define XUA_USE_APP_PLL (1)
#endif
#else
#define XUA_USE_APP_PLL (0)
#endif
#endif
/**
* @brief Default device sample frequency. A safe default should be used.
*
* Default: MIN_FREQ
*/
#ifndef DEFAULT_FREQ
#define DEFAULT_FREQ (MIN_FREQ)
#endif
/* Audio Class Defines */
#define DEFAULT_MCLK (((DEFAULT_FREQ % 7350) == 0) ? MCLK_441 : MCLK_48)
/**
* @brief USB Audio Class Version. Default: 2 (Audio Class version 2.0)
* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks)
*
* 0: XMOS is I2S master. 1: CODEC is I2s master.
*
* Default: 0 (XMOS is master)
*/
#ifndef CODEC_MASTER
#define CODEC_MASTER (0)
#endif
/*
* Audio Class defines
*/
/**
* @brief USB Audio Class Version
*
* Default: 2 (Audio Class version 2.0)
*/
#ifndef AUDIO_CLASS
#define AUDIO_CLASS 2
#define AUDIO_CLASS (2)
#endif
/**
* @brief Whether or not to fall back to Audio Class 1.0 in USB Full-speed. Default: 0 (Disabled)
* @brief Enable/disable fall back to Audio Class 1.0 in USB Full-speed.
*
* Default: Disabled
*/
#ifndef AUDIO_CLASS_FALLBACK
#define AUDIO_CLASS_FALLBACK 0 /* Default to not falling back to UAC 1 */
#define AUDIO_CLASS_FALLBACK (0)
#endif
/**
@@ -272,14 +353,17 @@
#error AUDIO_CLASS set to 1 and FULL_SPEED_AUDIO_2 enabled!
#endif
/* Feature defines */
/*
* Feature defines
*/
/**
* @brief Number of PDM microphones in the design. Default: None
* @brief Disable USB functionalty just leaving AudioHub
*
* Default: Enabled
*/
#ifndef XUA_NUM_PDM_MICS
#define XUA_NUM_PDM_MICS (0)
#ifndef XUA_USB_EN
#define XUA_USB_EN (1)
#endif
/**
@@ -432,14 +516,36 @@
#endif
/**
* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks)
* HID may be required in two forms: the built-in XUA-HID reports, or a
* user-provided static HID. Some sections of code are always needed, they
* are enclosed in XUA_OR_STATIC_HID_ENABLED; code specific to XUA-HID
* reports are enclosed in XUA_HID_ENABLED.
*
* 0: XMOS is I2S master. 1: CODEC is I2s master.
* HID_CONTROLS implies that the XUA_HID is used, and hence defines both.
* In order to roll your own, do not enable HID_CONTROLS, but instead
* create a file static_hid_report.h that contains the static descriptor.
*
* Default: 0 (XMOS is master)
* You must also supply your own function to deal with the HID endpoint(s)
* in this case.
*/
#ifndef CODEC_MASTER
#define CODEC_MASTER (0)
#if (HID_CONTROLS) || defined (__DOXYGEN__)
#define XUA_HID_ENABLED (1)
#define XUA_OR_STATIC_HID_ENABLED (1)
#endif
#if defined(__static_hid_report_h_exists__)
#define XUA_OR_STATIC_HID_ENABLED (1)
#endif
/**
* @brief Enable a HID OUT endpoint. Only use this if you supply your own HID control.
*
* 1 for enabled, 0 for disabled.
*
* Default 0 (Disabled)
*/
#ifndef HID_OUT_REQUIRED
#define HID_OUT_REQUIRED (0)
#endif
/**
@@ -997,17 +1103,12 @@
#define MIXER (0)
#endif
/* Tidy up old ifndef usage */
#if defined(MIXER) && (MIXER == 0)
#undef MIXER
#endif
/**
* @brief Number of seperate mixes to perform
*
* Default: 8 if MIXER enabled, else 0
*/
#ifdef MIXER
#if (MIXER)
#ifndef MAX_MIX_COUNT
#define MAX_MIX_COUNT (8)
#endif
@@ -1087,44 +1188,24 @@
#define VOLUME_RES_MIXER (0x100)
#endif
/* Handle out volume control in the mixer */
#if defined(OUT_VOLUME_IN_MIXER) && (OUT_VOLUME_IN_MIXER==0)
#undef OUT_VOLUME_IN_MIXER
#else
#if defined(MIXER)
// Disabled by default
//#define OUT_VOLUME_IN_MIXER
#endif
/* Handle out volume control in the mixer - enabled by default */
#ifndef OUT_VOLUME_IN_MIXER
#define OUT_VOLUME_IN_MIXER (1)
#endif
/* Apply out volume controls after the mix */
#if defined(OUT_VOLUME_AFTER_MIX) && (OUT_VOLUME_AFTER_MIX==0)
#undef OUT_VOLUME_AFTER_MIX
#else
#if defined(MIXER) && defined(OUT_VOLUME_IN_MIXER)
// Enabled by default
#define OUT_VOLUME_AFTER_MIX
#endif
/* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */
#ifndef OUT_VOLUME_AFTER_MIX
#define OUT_VOLUME_AFTER_MIX (1)
#endif
/* Handle in volume control in the mixer */
#if defined(IN_VOLUME_IN_MIXER) && (IN_VOLUME_IN_MIXER==0)
#undef IN_VOLUME_IN_MIXER
#else
#if defined(MIXER)
/* Disabled by default */
//#define IN_VOLUME_IN_MIXER
#endif
/* Handle in volume control in the mixer - disabled by default */
#ifndef IN_VOLUME_IN_MIXER
#define IN_VOLUME_IN_MIXER (0)
#endif
/* Apply in volume controls after the mix */
#if defined(IN_VOLUME_AFTER_MIX) && (IN_VOLUME_AFTER_MIX==0)
#undef IN_VOLUME_AFTER_MIX
#else
#if defined(MIXER) && defined(IN_VOLUME_IN_MIXER)
// Enabled by default
#define IN_VOLUME_AFTER_MIX
#endif
/* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
#ifndef IN_VOLUME_AFTER_MIX
#define IN_VOLUME_AFTER_MIX (1)
#endif
/* Always enable explicit feedback EP, even when input stream is present */
@@ -1171,7 +1252,7 @@ enum USBEndpointNumber_In
#ifdef MIDI
ENDPOINT_NUMBER_IN_MIDI,
#endif
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
ENDPOINT_NUMBER_IN_HID,
#endif
#ifdef IAP
@@ -1198,6 +1279,9 @@ enum USBEndpointNumber_Out
#ifdef IAP_EA_NATIVE_TRANS
ENDPOINT_NUMBER_OUT_IAP_EA_NATIVE_TRANS,
#endif
#endif
#if XUA_OR_STATIC_HID_ENABLED && HID_OUT_REQUIRED
ENDPOINT_NUMBER_OUT_HID,
#endif
XUA_ENDPOINT_COUNT_OUT /* End marker */
};
@@ -1219,7 +1303,8 @@ enum USBEndpointNumber_Out
#define AUDIO_START_FROM_DFU (0x87654321)
#define AUDIO_REBOOT_FROM_DFU (0xa5a5a5a5)
#define MAX_VOL (0x20000000)
/* Result of db_to_mult(MAX_VOLUME, 8, 29) */
#define MAX_VOLUME_MULT (0x20000000)
#if defined(LEVEL_METER_LEDS) && !defined(LEVEL_UPDATE_RATE)
#define LEVEL_UPDATE_RATE (400000)
@@ -1319,9 +1404,9 @@ 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) || (FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
(FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || \
(HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
(((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \
(((FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 2))
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1
#else
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 0

View File

@@ -1,7 +1,7 @@
// Copyright 2017-2022 XMOS LIMITED.
// Copyright 2017-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __XUA_CONF_FULL_H__
#define __XUA_CONF_FULL_H__
#ifndef _XUA_CONF_FULL_H_
#define _XUA_CONF_FULL_H_
#ifdef __xua_conf_h_exists__
#include "xua_conf.h"

View File

@@ -1,8 +1,10 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUA_MIXER_H_
#define _XUA_MIXER_H_
#include "xua.h"
enum mix_ctl_cmd {
SET_SAMPLES_TO_HOST_MAP,
SET_SAMPLES_TO_DEVICE_MAP,
@@ -31,4 +33,14 @@ enum mix_ctl_cmd {
*/
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
#define XUA_MIXER_OFFSET_OUT (0)
#define XUA_MIXER_OFFSET_IN (NUM_USB_CHAN_OUT)
#define XUA_MIXER_OFFSET_MIX (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN)
#define XUA_MIXER_OFFSET_OFF (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT)
/* Defines uses for DB to actual muliplier conversion */
#define XUA_MIXER_MULT_FRAC_BITS (25)
#define XUA_MIXER_DB_FRAC_BITS (8)
#define XUA_MIXER_MAX_MULT (1<<XUA_MIXER_MULT_FRAC_BITS) /* i.e. multiply by 0 */
#endif

View File

@@ -1,9 +1,8 @@
.. _sec_api:
API Reference
-------------
*************
.. toctree::

View File

@@ -1,7 +1,7 @@
.. _sec_api_component:
Component API
-------------
=============
The following functions can be called from the top level main of an
application and implement the various components described in

View File

@@ -2,18 +2,18 @@
.. _sec_api_defines:
Configuration Defines
---------------------
=====================
An application using the USB audio framework needs to have defines set for configuration.
Defaults for these defines are found in ``xua_conf_default.h``.
These defines should be over-ridden in an optional header file ``xua_conf.h`` file or in the ``Makefile``
for a relevant build configuration.
for a relevant build configuration.
This section fully documents all of the settable defines and their default values (where appropriate).
This section fully documents all of the settable defines and their default values (where appropriate).
Code Location (tile)
~~~~~~~~~~~~~~~~~~~~
--------------------
.. doxygendefine:: AUDIO_IO_TILE
.. doxygendefine:: XUD_TILE
@@ -23,41 +23,51 @@ Code Location (tile)
.. doxygendefine:: PLL_REF_TILE
Channel Counts
~~~~~~~~~~~~~~
--------------
.. doxygendefine:: NUM_USB_CHAN_OUT
.. doxygendefine:: NUM_USB_CHAN_IN
.. doxygendefine:: I2S_CHANS_DAC
.. doxygendefine:: I2S_CHANS_ADC
.. doxygendefine:: NUM_USB_CHAN_OUT
.. doxygendefine:: NUM_USB_CHAN_IN
.. doxygendefine:: I2S_CHANS_DAC
.. doxygendefine:: I2S_CHANS_ADC
Frequencies and Clocks
~~~~~~~~~~~~~~~~~~~~~~
Frequencies and Clocks
----------------------
.. doxygendefine:: MAX_FREQ
.. doxygendefine:: MIN_FREQ
.. doxygendefine:: DEFAULT_FREQ
.. doxygendefine:: MCLK_441
.. doxygendefine:: MCLK_48
.. doxygendefine:: XUA_USE_APP_PLL
Audio Class
~~~~~~~~~~~
-----------
.. doxygendefine:: AUDIO_CLASS
.. doxygendefine:: AUDIO_CLASS_FALLBACK
.. doxygendefine:: FULL_SPEED_AUDIO_2
System Feature Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Feature Configuration
---------------------
I2S/TDM
^^^^^^^
.. doxygendefine:: I2S_CHANS_DAC
.. doxygendefine:: I2S_CHANS_ADC
.. doxygendefine:: CODEC_MASTER
.. doxygendefine:: XUA_I2S_N_BITS
.. doxygendefine:: XUA_PCM_FORMAT
MIDI
....
^^^^
.. doxygendefine:: MIDI
.. doxygendefine:: MIDI_RX_PORT_WIDTH
S/PDIF
......
^^^^^^
.. doxygendefine:: XUA_SPDIF_TX_EN
.. doxygendefine:: SPDIF_TX_INDEX
@@ -65,37 +75,37 @@ S/PDIF
.. doxygendefine:: SPDIF_RX_INDEX
ADAT
....
^^^^
.. doxygendefine:: XUA_ADAT_RX_EN
.. doxygendefine:: ADAT_RX_INDEX
PDM Microphones
...............
^^^^^^^^^^^^^^^
.. doxygendefine:: XUA_NUM_PDM_MICS
DFU
...
^^^
.. doxygendefine:: XUA_DFU_EN
.. .. doxygendefine:: DFU_FLASH_DEVICE
HID
...
^^^
.. doxygendefine:: HID_CONTROLS
CODEC Interface
...............
^^^^^^^^^^^^^^^
.. doxygendefine:: CODEC_MASTER
USB Device Configuration
~~~~~~~~~~~~~~~~~~~~~~~~
------------------------
.. doxygendefine:: VENDOR_STR
.. doxygendefine:: VENDOR_ID
@@ -108,10 +118,10 @@ USB Device Configuration
Stream Formats
~~~~~~~~~~~~~~
--------------
Output/Playback
...............
^^^^^^^^^^^^^^^
.. doxygendefine:: OUTPUT_FORMAT_COUNT
@@ -132,7 +142,8 @@ Output/Playback
.. doxygendefine:: STREAM_FORMAT_OUTPUT_3_DATAFORMAT
Input/Recording
...............
^^^^^^^^^^^^^^^
.. doxygendefine:: INPUT_FORMAT_COUNT
.. doxygendefine:: STREAM_FORMAT_INPUT_1_RESOLUTION_BITS
@@ -144,7 +155,7 @@ Input/Recording
.. doxygendefine:: STREAM_FORMAT_INPUT_1_DATAFORMAT
Volume Control
~~~~~~~~~~~~~~
--------------
.. doxygendefine:: OUTPUT_VOLUME_CONTROL
.. doxygendefine:: INPUT_VOLUME_CONTROL
@@ -152,8 +163,8 @@ Volume Control
.. doxygendefine:: MAX_VOLUME
.. doxygendefine:: VOLUME_RES
Mixing Parameters
~~~~~~~~~~~~~~~~~
Mixing
------
.. doxygendefine:: MIXER
.. doxygendefine:: MAX_MIX_COUNT
@@ -163,8 +174,7 @@ Mixing Parameters
.. doxygendefine:: VOLUME_RES_MIXER
Power
~~~~~
-----
.. doxygendefine:: SELF_POWERED
.. doxygendefine:: BMAX_POWER
.. doxygendefine:: XUA_POWERMODE

View File

@@ -1,73 +1,49 @@
Required User Function Definitions
----------------------------------
|newpage|
The following functions need to be defined by an application using the XMOS USB Audio framework.
User Function Definitions
=========================
The following functions can be defined by an application using `lib_xua`.
.. note:: Default, empty, implementations of these functions are provided in `lib_xua`. These are marked
as weak symbols so the application can simply define its own version of them.
External Audio Hardware Configuration Functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------
.. c:function:: void AudioHwInit(chanend ?c_codec)
The following functions can be optionally used by the design to configure external audio hardware.
As a minimum, in most applications, it is expected that a implementation of `AudioHwConfig()` will need
to be provided.
This function is called when the audio core starts after the
device boots up and should initialize the external audio harware e.g. clocking, DAC, ADC etc
.. doxygenfunction:: AudioHwInit
.. doxygenfunction:: AudioHwConfig
.. doxygenfunction:: AudioHwConfig_Mute
.. doxygenfunction:: AudioHwConfig_UnMute
:param c_codec: An optional chanend that was original passed into
:c:func:`audio` that can be used to communicate
with other cores.
.. c:function:: void AudioHwConfig(unsigned samFreq, unsigned mclk, chanend ?c_codec, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
This function is called when the audio core starts or changes
sample rate. It should configure the extenal audio hardware to run at the specified
sample rate given the supplied master clock frequency.
:param samFreq: The sample frequency in Hz that the hardware should be configured to (in Hz).
:param mclk: The master clock frequency that is required in Hz.
:param c_codec: An optional chanend that was original passed into
:c:func:`audio` that can be used to communicate
with other cores.
:param dsdMode: Signifies if the audio hardware should be configured for DSD operation
:param sampRes_DAC: The sample resolution of the DAC stream
:param sampRes_ADC: The sample resolution of the ADC stream
Audio Streaming Functions
~~~~~~~~~~~~~~~~~~~~~~~~~
Audio Stream Start/Stop Functions
---------------------------------
The following functions can be optionally used by the design. They can be useful for mute lines etc.
.. c:function:: void AudioStreamStart(void)
.. doxygenfunction:: UserAudioStreamStart
.. doxygenfunction:: UserAudioStreamStop
.. doxygenfunction:: UserAudioInputStreamStart
.. doxygenfunction:: UserAudioInputStreamStop
.. doxygenfunction:: UserAudioOutputStreamStart
.. doxygenfunction:: UserAudioOutputStreamStop
This function is called when the audio stream from device to host
starts.
.. c:function:: void AudioStreamStop(void)
This function is called when the audio stream from device to host stops.
Host Active
~~~~~~~~~~~
Host Active Functions
---------------------
The following function can be used to signal that the device is connected to a valid host.
This is called on a change in state.
.. c:function:: void AudioStreamStart(int active)
:param active: Indicates if the host is active or not. 1 for active else 0.
.. doxygenfunction:: UserHostActive
HID Controls
~~~~~~~~~~~~
------------
The following function is called when the device wishes to read physical user input (buttons etc).
The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used.
.. c:function:: void UserReadHIDButtons(unsigned char hidData[])
:param hidData: The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used.
.. doxygenfunction:: UserHIDGetData

View File

@@ -2,7 +2,7 @@
.. _usb_audio_sec_architecture:
Software Architecture
---------------------
*********************
This section describes the required software architecture of a USB Audio device implemented using `lib_xua`, its dependencies and other supporting libraries.

View File

@@ -1,8 +1,8 @@
Features & Options
------------------
Additional Features
*******************
The previous section describes the use of core functionality contained within ``lib_xua``
The previous chapter describes the use of core functionality contained within ``lib_xua``
This seciton details enabling additional features with supported external dependencies, for example,
``lib_xua`` can provide S/PDIF output though the used of ``lib_spdif``

View File

@@ -1,6 +1,6 @@
S/PDIF Receive
~~~~~~~~~~~~~~
==============
``lib_xua`` supports the development of devices with S/PDIF receive functionality through the use of
``lib_spdif``. The XMOS S/PDIF receiver runs in a single core and supports rates up to 192kHz.
@@ -20,11 +20,11 @@ Finally, a channel for the output samples must be declared, note, this should be
The S/PDIF receiver should be called on the appropriate tile::
SpdifReceive(p_spdif_rx, c_spdif_rx, 1, clk_spd_rx);
spdif_rx(c_spdif_rx,p_spdif_rx,clk_spd_rx,192000);
.. note::
It is recomended to use the value 1 for the ``initial_divider`` parameter
It is recomended to use the value 192000 for the ``sample_freq_estimate`` parameter
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

View File

@@ -1,6 +1,6 @@
S/PDIF Transmit
~~~~~~~~~~~~~~~
===============
``lib_xua`` supports the development of devices with S/PDIF transmit functionality through the use of
``lib_spdif``. The XMOS S/PDIF transmitter runs in a single core and supports rates up to 192kHz.

View File

@@ -2,7 +2,7 @@
|appendix|
Known Issues
------------
************
- Quad-SPI DFU will corrupt the factory image with tools version < 14.0.4 due to an issue with libquadflash

View File

@@ -2,8 +2,7 @@
.. include:: ../../../README.rst
About This Document
~~~~~~~~~~~~~~~~~~~
===================
This document describes the structure of ``lib_xua``, its use and resources required. It also covers some implementation detail.
@@ -18,7 +17,7 @@ the XMOS tool chain and XC language.
Options <opt>
Advanced Usage <using_adv>
Additional Features <feat>
Software Detail <sw>
Implementation Detail <sw>
API <api>
Known Issues <issues>

View File

@@ -2,7 +2,7 @@
.. _sec_options:
Options
-------
*******
This section describes key options of ``lib_xua``. These are typically controlled using build time defines.
Where something must be defined, it is recommended this is done in `xua_conf.h` but could also be done in the application Makefile.

View File

@@ -1,7 +1,7 @@
|newpage|
USB Audio Class Version
~~~~~~~~~~~~~~~~~~~~~~~
=======================
The codebase supports USB Audio Class versions 1.0 and 2.0.
@@ -15,22 +15,22 @@ Additional improvements, amongst others, include:
- Extensive support for interrupts to inform the host about dynamic changes that occur to different entities such as Clocks etc
Driver Support
..............
--------------
Audio Class 1.0
+++++++++++++++
^^^^^^^^^^^^^^^
Audio Class 1.0 is fully supported in Apple OSX. Audio Class 1.0 is fully supported in all modern Microsoft Windows operating systems (i.e. Windows XP and later).
Audio Class 2.0
+++++++++++++++
^^^^^^^^^^^^^^^
Audio Class 2.0 is fully supported in Apple OSX since version 10.6.4. Starting with Windows 10, release 1703, a USB Audio 2.0 driver is shipped with Windows.
Third party Windows drivers are also available, however, documentation of these is beyond the scope of this document, please contact XMOS for further details.
Audio Class 1.0 Mode and Fall-back
..................................
----------------------------------
The default for XMOS USB Audio applications is to run as a high-speed Audio Class 2.0
device. However, some products may prefer to run in Audio Class 1.0 mode, this is normally to
@@ -64,7 +64,7 @@ Due to bandwidth limitations of full-speed USB the following sample-frequency re
Related Defines
................
---------------
:ref:`opt_audio_class_defines` descibes the defines that effect audio class selection.

View File

@@ -3,7 +3,7 @@
.. _sec_opt_audio_formats:
Audio Stream Formats
~~~~~~~~~~~~~~~~~~~~
====================
The design currently supports up to three different stream formats for playback, selectable at
run time. This is implemented using standard Alternative Settings to the Audio Streaming interfaces.
@@ -32,7 +32,7 @@ By default the design exposes two sets of Alternative Settings for the playback
24-bit playback. When DSD is enabled an additional (32-bit) alternative is exposed.
Audio Subslot
.............
-------------
An audio subslot holds a single audio sample. See `USB Device Class Definition for Audio Data Formats
<http://www.usb.org/developers/devclass_docs/Audio2.0_final.zip>`_ for full details.
@@ -73,7 +73,7 @@ Values other than 4 may be used for the following reasons:
Audio Sample Resolution
.......................
-----------------------
An audio sample is represented using a number of bits (`bBitResolution`) less than or equal to the number
of total bits available in the audio subslot i.e. `bBitResolution` <= `bSubslotSize` * 8). The design
@@ -99,7 +99,7 @@ supports values 16, 24 and 32.
Audio Format
............
------------
The design supports two audio formats, PCM and, when "Native" DSD is enabled, Direct Stream Digital (DSD).
A DSD capable DAC is required for the latter.
@@ -122,7 +122,6 @@ The following options are supported:
* UAC_FORMAT_TYPEI_PCM
.. note::
Currently DSD is only supported on the output/playback stream

View File

@@ -1,7 +1,7 @@
|newpage|
Channel Counts and Sample Rates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
===============================
The codebase is fully configurable in relation to channel counts and sample rates.
Practical limitations of these are normally based on USB packet size restrictions and I/O

View File

@@ -1,7 +1,7 @@
|newpage|
Direct Stream Digital (DSD)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
===========================
Direct Stream Digital (DSD) is used for digitally encoding audio signals on Super Audio CDs (SACD).
It uses pulse-density modulation (PDM) encoding.
@@ -48,7 +48,7 @@ If only DoP functionality is desired the Native implementation can be disabled w
DSD over PCM (DoP)
..................
------------------
DoP support follows the method described in the `DoP Open Standard 1.1
<http://dsd-guide.com/sites/default/files/white-papers/DoP_openStandard_1v1.pdf>`_.
@@ -81,14 +81,14 @@ of rate.
DoP requires bit-perfect transmission - therefore any audio/volume processing will break the stream.
"Native" vs DoP
~~~~~~~~~~~~~~~
---------------
Since the DoP specification requires header bytes this eats into the data bandwidth. The "Native" implementation
has no such overhead and can therefore transfer the same DSD rate and half the effective PCM rate of DoP.
Such a property may be desired when upporting DSD128 without exposing a 352.8kHz PCM rate, for example.
Ports
.....
-----
The codebase expects 1-bit ports to be defined in the application XN file for the DSD data and
clock lines for example::

View File

@@ -1,7 +1,7 @@
|newpage|
I2S/TDM
~~~~~~~
=======
I2S/TDM is typically fundamental to most products and is built into the ``XUA_AudioHub()`` core.
@@ -23,11 +23,14 @@ The defines in :ref:`opt_i2s_defines` effect the I2S implementation.
- The desired number of input channels via I2S (0 for disabled)
- N/A (Must be defined)
* - ``XUA_PCM_FORMAT``
- Enabled either TDM or I2S mode
- Enables either TDM or I2S mode
- ``XUA_PCM_FORMAT_I2S``
* - ``CODEC_MASTER``
- Sets is xCORE is I2S master or slave
- Sets if xCORE is I2S master or slave
- ``0`` (xCORE is master)
* - ``XUA_I2S_N_BITS``
- I2S/TDM word length (16, 32-bit supported)
- ``32``
The I2S code expects that the ports required for I2S (master clock, LR-clock, bit-clock and data lines) are be defined in the application XN file in the relevant `Tile``.
For example::
@@ -42,8 +45,16 @@ For example::
<Port Location="XS1_PORT_1G" Name="PORT_I2S_ADC1"/>
</Tile>
All of the I2S related ports must be 1-bit ports.
All of the I2S/TDM related ports must be 1-bit ports.
.. note::
TDM mode allows 8 channels (rather than 2) to be supplied on each dataline.
TDM mode allows 8 channels (rather than 2) to be supplied on each data-line.
.. note::
Data output/input is in "I2S" format, rather than, say "left-justified" or "right-justified" formats.
I2S format specifies a single bit-clock delay after the LR-clock transition before sample-data is driven/received.
This also applies to TDM mode. TDM support in ADC/DAC hardware is quite varied, an "offset" value may need to be programmed into
the external device for compatible operation.

View File

@@ -1,7 +1,7 @@
|newpage|
Code Location
~~~~~~~~~~~~~
=============
When designing a system there is a choice as to which hardware resources to use for each interface.
In a multi-tile system the codebase needs to be informed as to which tiles to use for these hardware
@@ -21,7 +21,7 @@ full listing of these ``TILE`` defines.
- Description
- Default
* - ``AUDIO_IO_TILE``
- Tile on which I2S, ADAT Rx, S/PDIF Rx & mixer resides
- Tile on which I2S/TDM, ADAT Rx, S/PDIF Rx & mixer resides
- ``0``
* - ``XUD_TILE``
- Tile on which USB resides, including buffering for all USB interfaces/endppoints

View File

@@ -2,7 +2,7 @@
|newpage|
MIDI
~~~~
====
The codebase supports MIDI input/output over USB as per `Universal Serial Bus Device Class Definition for MIDI Devices <https://www.usb.org/sites/default/files/midi10.pdf>`_.

View File

@@ -1,7 +1,7 @@
|newpage|
Mixer
~~~~~
=====
The codebase supports audio mixing functionality with highly flexible routing options.

View File

@@ -1,11 +1,10 @@
|newpage|
Other Options
~~~~~~~~~~~~~
=============
There are a few other, lesser used, options available.
.. _opt_other_defines:
.. list-table:: Other defines

View File

@@ -1,7 +1,7 @@
|newpage|
PDM Microphones
~~~~~~~~~~~~~~~
===============
The codebase supports input from up to 8 PDM microphones.

View File

@@ -1,7 +1,7 @@
|newpage|
S/PDIF Receive
~~~~~~~~~~~~~~
==============
The codebase supports a single, stereo, S/PDIF receiver. This can be input via 75 Ω coaxial or optical fibre.
In order to provide S/PDIF functionality ``lib_xua`` uses ``lib_spdif`` (https://www.github.com/xmos/lib_spdif).

View File

@@ -1,7 +1,7 @@
|newpage|
S/PDIF Transmit
~~~~~~~~~~~~~~~
===============
The codebase supports a single, stereo, S/PDIF transmitter. This can be output over 75 Ω coaxial or optical fibre.
In order to provide S/PDIF transmit functionality ``lib_xua`` uses ``lib_spdif`` (https://www.github.com/xmos/lib_spdif).

View File

@@ -1,6 +1,6 @@
Strings and ID's
~~~~~~~~~~~~~~~~
================
The codebase includes various strings and ID's that should be customised to match the product requirements.
These are listed in ::ref:`opt_strings_defines`.

View File

@@ -1,27 +1,27 @@
|newpage|
Synchronisation
~~~~~~~~~~~~~~~
Synchronisation & Clocking
==========================
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 and 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 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,10 +39,17 @@ Setting the synchronisation mode of the device is done using the define in :ref:
- USB synchronisation mode
- ``XUA_SYNCMODE_ASYNC``
When operating in synchronous mode an external Cirrus Logic CS2100 device is required for master clock
generation. The codebase expects to drive a synchronisation signal to this external device
When operating in 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.
The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set appropriately.
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.
.. _opt_sync_ref_defines:
@@ -57,10 +64,33 @@ The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set ap
- Tile location of reference to CS2100 device
- ``AUDIO_IO_TILE``
The codebase expects this reference signal port to be defined in the application XN file as ``PORT_PLL_REF``.
The codebase expects this 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.

View File

@@ -1,6 +1,5 @@
Overview
--------
********
.. table::
:class: vertical-borders
@@ -26,7 +25,7 @@ Overview
| +---------------------------------------------------------------------------------------------+
| | `USB Midi Device Class 1.0 <http://www.usb.org/developers/devclass_docs/midi10.pdf>`_ |
+---------------------------------+---------------------------------------------------------------------------------------------+
| Audio | I2S/TDM |
| Audio | I2S/TDM (16/32-bit) |
| +---------------------------------------------------------------------------------------------+
| | S/PDIF |
| +---------------------------------------------------------------------------------------------+
@@ -75,5 +74,3 @@ Overview
| Reference code is maintained by XMOS Limited. |
+-------------------------------------------------------------------------------------------------------------------------------+

View File

@@ -1,8 +1,8 @@
Implementation Detail
---------------------
*********************
This section examines the implementation of the various components that make up ``lib_xua``. It also examines the integration of dependencies and supporting libraries.
This chapter examines the implementation of the various components that make up ``lib_xua``. It also examines the integration of dependencies and supporting libraries.
.. toctree::
@@ -10,8 +10,8 @@ This section examines the implementation of the various components that make up
sw_ep0
sw_xud
sw_clocking
sw_spdif
sw_mixer
sw_spdif
sw_spdif_rx
sw_adat_rx
sw_midi

View File

@@ -1,7 +1,7 @@
|newpage|
ADAT Receive
------------
============
The ADAT receive component receives up to eight channels of audio at a sample rate
of 44.1kHz or 48kHz. The API for calling the receiver functions is

View File

@@ -3,7 +3,7 @@
.. _usb_audio_sec_audio:
Audio Hub
.........
=========
The Audio Hub task performs many functions. It receives and transmits samples from/to the Decoupler
or Mixer core over a channel.
@@ -96,9 +96,8 @@ Two master clock frequencies to support 44.1kHz and 48kHz audio frequencies (e.g
and 12.288/24.576MHz respectively). This master clock input is then provided to the external audio
hardware and the xCORE device.
Port Configuration (xCORE Master)
+++++++++++++++++++++++++++++++++
---------------------------------
The default software configuration is xCORE is I2S master. That is, the XMOS device provides the BCLK and LRCLK signals to the external audio hardware
@@ -143,7 +142,7 @@ before the data (as required by the I2S standard) and alternates between high an
and right channels of audio.
Changing Audio Sample Frequency
+++++++++++++++++++++++++++++++
-------------------------------
.. _usb_audio_sec_chang-audio-sample:
@@ -159,5 +158,3 @@ functions.
Once this is complete, the I2S/TDM interface (i.e. the main loop in AudioHub) is restarted at the new frequency.

View File

@@ -4,7 +4,7 @@
.. _usb_audio_sec_clock_recovery:
External Clock Recovery (Clock Gen)
-----------------------------------
===================================
To provide an audio master clock an application may use selectable oscillators, clock
generation IC or, in the case of xCORE.ai devices, integrated secondary PLL, to generate fixed
@@ -14,7 +14,7 @@ It may also use an external PLL/Clock Multiplier to generate a master clock base
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 code-base supports the Cirrus
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.
.. note::

View File

@@ -3,14 +3,14 @@
.. _usb_audio_sec_usb:
Endpoint 0: Management and Control
..................................
==================================
All USB devices must support a mandatory control endpoint, Endpoint 0. This controls the management tasks of the USB device.
These tasks can be generally split into enumeration, audio configuration and firmware upgrade requests.
Enumeration
~~~~~~~~~~~
-----------
When the device is first attached to a host, enumeration occurs. This process involves the host interrogating the device as to its functionality. The device does this by presenting several interfaces to the host via a set of descriptors.
@@ -41,12 +41,13 @@ The function may also return ``XUD_RES_RST`` if a bus-reset has been issued onto
Since the ``USB_StandardRequests()`` function STALLs an unknown request, the endpoint 0 code must first parse the ``USB_SetupPacket_t`` structure to handle device specific requests and then call ``USB_StandardRequests()`` as required.
Over-riding Standard Requests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------
The USB Audio design "over-rides" some of the requests handled by ``USB_StandardRequests()``, for example it uses the SET_INTERFACE request to indicate if the host is streaming audio to the device. In this case the setup packet is parsed, the relevant action taken, the ``USB_StandardRequests()`` is still called to handle the response to the host.
Class Requests
~~~~~~~~~~~~~~
--------------
Before making the call to ``USB_StandardRequests()`` the setup packet is parsed for Class requests. These are handled in functions such as ``AudioClassRequests_1()``, ``AudioClassRequests_2``, ``DFUDeviceRequests()`` etc depending on the type of request.
Any device specific requests are handled - in this case Audio Class, MIDI class, DFU requests etc.
@@ -54,7 +55,7 @@ Any device specific requests are handled - in this case Audio Class, MIDI class,
Some of the common Audio Class requests and their associated behaviour will now be examined.
Audio Requests
++++++++++++++
^^^^^^^^^^^^^^
When the host issues an audio request (e.g. sample rate or volume change), it sends a command to Endpoint 0. Like all requests this is returned from ``USB_GetSetupPacket()``. After some parsing (namely as Class Request to an Audio Interface) the request is handled by either the ``AudioClassRequests_1()`` or ``AudioClassRequests_2()`` function (based on whether the device is running in Audio Class 1.0 or 2.0 mode).
@@ -63,7 +64,7 @@ Note, Audio Class 1.0 Sample rate changes are send to the relevant endpoint, rat
The ``AudioClassRequests_X()`` functions further parses the request in order to ascertain the correct audio operation to execute.
Audio Request: Set Sample Rate
++++++++++++++++++++++++++++++
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``AudioClassRequests_2()`` function parses the passed ``USB_SetupPacket_t`` structure for a ``CUR`` request of type ``SAM_FREQ_CONTROL`` to a Clock Unit in the devices topology (as described in the devices descriptors).
@@ -72,7 +73,7 @@ The new sample frequency is extracted and passed via channel to the rest of the
.. _usb_audio_sec_audio-requ-volume:
Audio Request: Volume Control
+++++++++++++++++++++++++++++
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When the host requests a volume change, it
sends an audio interface request to Endpoint 0. An array is
@@ -102,10 +103,10 @@ to the mixer to change the volume. Mixer commands
are described in :ref:`usb_audio_sec_mixer`.
Audio Endpoints (Endpoint Buffer and Decoupler)
...............................................
===============================================
Endpoint Buffer
~~~~~~~~~~~~~~~
---------------
All endpoints other that Endpoint 0 are handled in one core. This
core is implemented in the file ``ep_buffer.xc``. This core communicates directly with the XUD library.
@@ -114,7 +115,7 @@ The USB buffer core is also responsible for feedback calculation based on USB St
(SOF) notification and reads from the port counter of a port connected to the master clock.
Decouple
~~~~~~~~
--------
The decoupler supplies the USB buffering core with buffers to
transmit/receive audio data to/from the host. It marshals these buffers into
@@ -125,7 +126,7 @@ matching the audio rate to the USB packet rate). The decoupler is
implemented in the file ``decouple.xc``.
Audio Buffering Scheme
~~~~~~~~~~~~~~~~~~~~~~~
----------------------
This scheme is executed by co-operation between the buffering
core, the decouple core and the XUD library.
@@ -133,7 +134,6 @@ core, the decouple core and the XUD library.
For data going from the device to the host the following scheme is
used:
#. The Decouple core receives samples from the Audio Hub core and
puts them into a FIFO. This FIFO is split into packets when data is
entered into it. Packets are stored in a format consisting of their
@@ -152,11 +152,9 @@ used:
Decouple core that the buffer has been sent and the Decouple core
moves the read pointer of the FIFO.
For data going from the host to the device the following scheme is
used:
#. The Decouple core passes a pointer to the Endpoint Buffer core
pointing into a FIFO of data and signals to the XUD library that
the Endpoint Buffer core is ready to receive.
@@ -171,9 +169,8 @@ used:
#. Upon request from the Audio Hub core, the Decouple core sends
samples to the Audio Hub core by reading samples out of the FIFO.
Decoupler/Audio Core interaction
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--------------------------------
To meet timing requirements of the audio system (i.e Audio Hub/Mixer), the Decoupler
core must respond to requests from the audio system to
@@ -200,7 +197,6 @@ in channel count sized chunks (i.e. ``NUM_USB_CHAN_OUT`` and
The complete communication scheme is shown in the table below (for non sample
frequency change case):
.. table:: Decouple/Audio System Channel Communication
+-----------------+-----------------+-----------------------------------------+
@@ -242,7 +238,7 @@ frequency change case):
(this is especially advantageous in the DSD over PCM (DoP) case)
Asynchronous Feedback
+++++++++++++++++++++
---------------------
When built to operate in Asynchronous mode the device uses a feedback endpoint to report the rate at which
audio is output/input to/from external audio interfaces/devices. This feedback is in accordance with
@@ -265,7 +261,7 @@ sent to the host. In practice this an explicit feedback endpoint is normally use
in Microsoft Windows operating systems (see ``UAC_FORCE_FEEDBACK_EP``).
USB Rate Control
++++++++++++++++
----------------
.. _usb_audio_sec_usb-rate-control:

View File

@@ -1,5 +1,5 @@
Audio Controls via Human Interface Device (HID)
------------------------------------------------
===============================================
The design supports simple audio controls such as play/pause, volume up/down etc via the USB Human
Interface Device Class Specification.

View File

@@ -1,11 +1,11 @@
|newpage|
MIDI
----
====
The MIDI core implements a 31250 baud UART for both input and output. On receiving 32-bit USB MIDI events
The MIDI core implements a 31250 baud UART for both input and output. On receiving 32=bit USB MIDI events
from the Endpoint Buffer core, it parses these and translates them to 8-bit MIDI messages which are sent
over UART. Similarly, incoming 8-bit MIDI messages are aggregated into 32-bit USB-MIDI events and
over UART. Similarly, incoming 8-bit MIDI messages are aggregated into 32-bit USB MIDI events and
passed on to the Endpoint Buffer core. The MIDI core is implemented in the file ``usb_midi.xc``.
The Endpoint Buffer core implements the two Bulk endpoints (one In and one Out) as well as interacting

View File

@@ -87,6 +87,9 @@ intended as an example of how you might add mixer control to your own control ap
intended to be exposed to end users.
For details, consult the README file in the host_usb_mixer_control directory.
A list of arguments can also be seen with::
$ ./xmos_mixer --help
The main requirements of this control utility are to
@@ -102,78 +105,147 @@ The main requirements of this control utility are to
functionality to their end users.
Whilst using the XMOS Host control example application, consider the example of setting the
mixer to perform a loop-back from analogue inputs 1 and 2 to analogue outputs 1 and 2.
mixer to perform a loop-back from analogue inputs 1 & 2 to analogue outputs 1 & 2.
Firstly consider the inputs to the mixer. The following will displays which channels are mapped
to which mixer inputs::
.. note::
./xmos_mixer --display-aud-channel-map 0
The command outputs shown are examples; the actual output will depend on the mixer configuration.
The following command will displays which channels could possibly be mapped to mixer inputs. Notice
that analogue inputs 1 and 2 are on mixer inputs 10 and 11::
The following will show the index for each device output along with which channel is currently mapped to it.
In this example the analogue outputs 1 & 2 are 0 & 1 respectively::
./xmos_mixer --display-aud-channel-map-sources 0
$ ./xmos_mixer --display-aud-channel-map
Now examine the audio output mapping using the following command::
Audio Output Channel Map
------------------------
0 (DEVICE OUT - Analogue 1) source is 0 (DAW OUT - Analogue 1)
1 (DEVICE OUT - Analogue 2) source is 1 (DAW OUT - Analogue 2)
2 (DEVICE OUT - SPDIF 1) source is 2 (DAW OUT - SPDIF 1)
3 (DEVICE OUT - SPDIF 2) source is 3 (DAW OUT - SPDIF 2)
$ _
./xmos_mixer --display-aud-channel-map 0
The DAW Output Map can be seen with::
This displays which channels are mapped to which outputs. By default all
of these bypass the mixer. We can also see what all the possible
mappings are with the following command::
$ ./xmos_mixer --display-daw-channel-map
./xmos_mixer --display-aud-channel-map-sources 0
DAW Output To Host Channel Map
------------------------
0 (DEVICE IN - Analogue 1) source is 4 (DEVICE IN - Analogue 1)
1 (DEVICE IN - Analogue 2) source is 5 (DEVICE IN - Analogue 2)
$ _
We will now map the first two mixer outputs to physical outputs 1 and 2::
.. note::
./xmos_mixer --set-aud-channel-map 0 26
./xmos_mixer --set-aud-channel-map 1 27
In both cases, by default, these bypass the mixer.
The following command will list the channels which can be mapped to the device outputs from the
Audio Output Channel Map. Note that, in this example, analogue inputs 1 & 2 are source 4 & 5 and
Mix 1 & 2 are source 6 & 7::
$ ./xmos_mixer --display-aud-channel-map-sources
Audio Output Channel Map Source List
------------------------------------
0 (DAW OUT - Analogue 1)
1 (DAW OUT - Analogue 2)
2 (DAW OUT - SPDIF 1)
3 (DAW OUT - SPDIF 2)
4 (DEVICE IN - Analogue 1)
5 (DEVICE IN - Analogue 2)
6 (MIX - Mix 1)
7 (MIX - Mix 2)
$ _
Using the indices from the previous commands, we will now re-map the first two mixer channels (Mix 1 & Mix 2) to device outputs 1 & 2::
$ ./xmos_mixer --set-aud-channel-map 0 6
$ ./xmos_mixer --set-aud-channel-map 1 7
$ _
You can confirm the effect of this by re-checking the map::
./xmos_mixer --display-aud-channel-map 0
$ ./xmos_mixer --display-aud-channel-map
This now derives analogue outputs 1 and 2 from the mixer, rather than directly from USB. However,
since the mixer is still mapped to pass the USB channels through to the outputs there will be no
Audio Output Channel Map
------------------------
0 (DEVICE OUT - Analogue 1) source is 6 (MIX - Mix 1)
1 (DEVICE OUT - Analogue 2) source is 7 (MIX - Mix 2)
2 (DEVICE OUT - SPDIF 1) source is 2 (DAW OUT - SPDIF 1)
3 (DEVICE OUT - SPDIF 2) source is 3 (DAW OUT - SPDIF 2)
$ _
This now derives analogue outputs 1 & 2 from the mixer, rather than directly from USB. However,
since the mixer is mapped, by default, to just pass the USB channels through to the outputs there will be no
functional change.
The mixer nodes need to be individually set. They can be displayed
.. note::
The USB audio reference design has only one unit so the mixer_id argument should always be 0.
The mixer nodes need to be individually set. The nodes in mixer_id 0 can be displayed
with the following command::
./xmos_mixer --display-mixer-nodes 0
$ ./xmos_mixer --display-mixer-nodes 0
To get the audio from the analogue inputs to outputs 1 and 2, nodes 80
and 89 need to be set::
Mixer Values (0)
----------------
./xmos_mixer --set-value 0 80 0
./xmos_mixer --set-value 0 89 0
Mixer outputs
1 2
DAW - Analogue 1 0:[0000.000] 1:[ -inf ]
DAW - Analogue 2 2:[ -inf ] 3:[0000.000]
DAW - SPDIF 1 4:[ -inf ] 5:[ -inf ]
DAW - SPDIF 2 6:[ -inf ] 7:[ -inf ]
AUD - Analogue 1 8:[ -inf ] 9:[ -inf ]
AUD - Analogue 2 10:[ -inf ] 11:[ -inf ]
$ _
With mixer outputs 1 & 2 mapped to device outputs analogue 1 & 2; to get the audio from the analogue inputs to device
outputs mixer_id 0 node 8 and node 11 need to be set to 0db::
$ ./xmos_mixer --set-value 0 8 0
$ ./xmos_mixer --set-value 0 11 0
$ _
At the same time, the original mixer outputs can be muted::
./xmos_mixer --set-value 0 0 -inf
./xmos_mixer --set-value 0 9 -inf
$ ./xmos_mixer --set-value 0 0 -inf
$ ./xmos_mixer --set-value 0 3 -inf
$ _
Now audio inputs on analogue 1/2 should be heard on outputs 1/2.
Now audio inputs on analogue 1 and 2 should be heard on outputs 1 and 2 respectively.
As mentioned above, the flexibility of the mixer is such that there will be multiple ways to create
a particular mix. Another option to create the same routing would be to change the mixer sources
such that mixer 1/2 outputs come from the analogue inputs.
such that mixer outputs 1 and 2 come from the analogue inputs 1 and 2.
To demonstrate this, firstly undo the changes above (or simply reset the device)::
./xmos_mixer --set-value 0 80 -inf
./xmos_mixer --set-value 0 89 -inf
./xmos_mixer --set-value 0 0 0
./xmos_mixer --set-value 0 9 0
$ ./xmos_mixer --set-value 0 8 -inf
$ ./xmos_mixer --set-value 0 11 -inf
$ ./xmos_mixer --set-value 0 0 0
$ ./xmos_mixer --set-value 0 3 0
$ _
The mixer should now have the default values. The sources for mixer 1/2 can now be changed::
The mixer should now have the default values. The sources for mixer 0 output 1 and 2 can now be changed
using indices from the Audio Output Channel Map Source List::
./xmos_mixer --set-mixer-source 0 0 10
./xmos_mixer --set-mixer-source 0 1 11
$ ./xmos_mixer --set-mixer-source 0 0 4
Set mixer(0) input 0 to device input 4 (AUD - Analogue 1)
$ ./xmos_mixer --set-mixer-source 0 1 5
Set mixer(0) input 1 to device input 5 (AUD - Analogue 2)
$ _
If you re-run the following command then the first column now has "AUD - Analogue 1 and 2" rather
than "DAW (Digital Audio Workstation i.e. the host) - Analogue 1 and 2" confirming the new mapping.
Again, by playing audio into analogue inputs 1/2 this can be heard looped through to analogue outputs 1/2::
./xmos_mixer --display-mixer-nodes 0
$ ./xmos_mixer --display-mixer-nodes 0

View File

@@ -1,7 +1,7 @@
|newpage|
PDM Microphones
---------------
===============
The XMOS USB Audio Reference Design firmware is capable of integrating with PDM microphones.
The PDM stream from the microphones is converted to PCM and output to the host via USB.
@@ -46,9 +46,8 @@ After the decimation to the output sample-rate various other steps take place e.
and compensation etc. Please refer to the documentation provided with ``lib_mic_array`` for further
implementation detail and complete feature set.
PDM Microphone Hardware Characteristics
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---------------------------------------
The PDM microphones require a *clock input* and provide the PDM signal on a *data output*. All of
the PDM microphones must share the same clock signal (buffered on the PCB as appropriate), and
@@ -78,7 +77,7 @@ divide down 12.288 MHz master clock. Or, if clock accuracy is not important, the
reference can be divided down to provide an approximate clock.
Usage & Integration
~~~~~~~~~~~~~~~~~~~
-------------------
A PDM microphone wrapper is called from ``main()`` and takes one channel argument connecting it to the rest of the system:
@@ -113,3 +112,4 @@ sends the frame of audio back over this channel.
Note, it is assumed that the system shares a global master-clock, therefore no additional buffering or rate-matching/conversion
is required.

View File

@@ -3,7 +3,7 @@
.. _usb_audio_sec_resource_usage:
Resource Usage
--------------
==============
The following table details the resource usage of each component of the reference design software.
Note, memory usage is approximate and varies based on device used, compiler settings etc.
@@ -50,3 +50,4 @@ Note, memory usage is approximate and varies based on device used, compiler sett
Unlike other interfaces, since the USB PHY is internal the USB ports are a fixed set of ports
and cannot be modified. See ``lib_xud`` documentation for full details.

View File

@@ -2,7 +2,7 @@
|newpage|
S/PDIF Transmit
...............
===============
``lib_xua`` supports the development of devices with S/PDIF transmit throught the use of ``lib_spdif``.
The XMOS S/SPDIF transmitter component runs in a single core and supports sample-rates upto 192kHz.
@@ -21,7 +21,7 @@ bits) and transmitted in biphase-mark encoding (BMC) with respect to an *externa
Note that a minor change to the ``SpdifTransmitPortConfig`` function would enable *internal* master
clock generation (e.g. when clock source is already locked to desired audio clock).
.. list-table:: S/PDIF Capabilities
.. list-table:: S/PDIF Capabilities
* - **Sample frequencies**
- 44.1, 48, 88.2, 96, 176.4, 192 kHz
@@ -31,7 +31,7 @@ clock generation (e.g. when clock source is already locked to desired audio cloc
- ``lib_spdif``
Clocking
++++++++
--------
.. only:: latex
@@ -54,7 +54,7 @@ This resamples the master clock to its clock domain (oscillator), which introduc
A typical jitter-reduction scheme is an external D-type flip-flop clocked from the master clock (as shown in the preceding diagram).
Usage
+++++
-----
The interface to the S/PDIF transmitter core is via a normal channel with streaming built-ins
(``outuint``, ``inuint``). Data format should be 24-bit left-aligned in a 32-bit word: ``0x12345600``
@@ -84,9 +84,8 @@ The following protocol is used on the channel:
This communication is wrapped up in the API functions provided by ``lib_spdif``.
Output stream structure
+++++++++++++++++++++++
Output Stream Structure
-----------------------
The stream is composed of words with the following structure shown in
:ref:`usb_audio_spdif_stream_structure`. The channel status bits are

View File

@@ -1,7 +1,7 @@
|newpage|
S/PDIF Receive
---------------
==============
XMOS devices can support S/PDIF receive up to 192kHz - see ``lib_spdif`` for full specifications.
@@ -45,7 +45,7 @@ The tag has one of three values:
See S/PDIF, IEC 60958-3:2006, specification for further details on format, user bits etc.
Usage and Integration
+++++++++++++++++++++
---------------------
Since S/PDIF is a digital steam the devices master clock must be synchronised to it. This is typically
done with an external device. See `Clock Recovery` (:ref:`usb_audio_sec_clock_recovery`).

View File

@@ -2,7 +2,7 @@
|newpage|
XMOS USB Device (XUD) Library
.............................
=============================
All low level communication with the USB host is handled by the XMOS USB Device (XUD) library - `lib_xud`

View File

@@ -1,12 +1,12 @@
Basic Usage
-----------
***********
This sections describes the basic usage of `lib_xua` and provides a guide on how to program USB Audio Devices.
Library Structure
~~~~~~~~~~~~~~~~~
=================
The code is split into several directories.
@@ -26,7 +26,7 @@ Note, the midi and dfu directories are potential candidates for separate libs in
Using in a Project
~~~~~~~~~~~~~~~~~~
==================
All `lib_xua` functions can be accessed via the ``xua.h`` header file::
@@ -39,7 +39,7 @@ It is also required to add ``lib_xua`` to the ``USED_MODULES`` field of your app
.. _sec_basic_usage_codeless:
"Codeless" Programming Model
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
============================
Whilst it is possible to code a USB Audio device using the building blocks provided by `lib_xua`
it is realised that this might not be desirable for many classes of customers or products.
@@ -71,7 +71,7 @@ set ``EXCLUDE_USB_AUDIO_MAIN`` to 1 in the application makefile or ``xua_conf.h`
::ref:`sec_advanced_usage`.
Configuring lib_xua
~~~~~~~~~~~~~~~~~~~
===================
Configuration of the various build time options of ``lib_xua`` is done via the optional header `xua_conf.h`.
To allow the build scripts to locate this file it should reside somewhere in the application `src` directory.
@@ -93,9 +93,8 @@ should continue to include `xua.h` as previously directed. A simple example is s
#endif
User Functions
~~~~~~~~~~~~~~
==============
To enable custom functionality, such as configuring external audio hardware, bespoke behaviour on
stream start/stop etc, various functions can be overridden by the user. (see ::ref:`sec_api` for

View File

@@ -1,7 +1,7 @@
.. _sec_advanced_usage:
Advanced Usage
--------------
**************
Whilst it is possible to program USB Audio devices using ``lib_xua`` by only setting defines
(see :ref:`sec_basic_usage_codeless`) some developers may want to code a USB Audio device from

View File

@@ -1,5 +1,5 @@
Running the Core Components
~~~~~~~~~~~~~~~~~~~~~~~~~~~
===========================
In their most basic form the core components can be run as follows::

View File

@@ -1,5 +1,5 @@
Core Hardware Resources
~~~~~~~~~~~~~~~~~~~~~~~
=======================
The user must declare and initialise relevant hardware resources (globally) and pass them to the
relevant function of `lib_xua`.

View File

@@ -1,11 +1,11 @@
|newpage|
I2S/TDM
~~~~~~~
=======
I2S/TDM is typically fundamental to most products and is built into the ``XUA_AudioHub()`` core.
In order to enable I2S on must declare an array of ports for the data-lines (one for each direction)::
In order to enable I2S/TDM on must declare an array of ports for the data-lines (one for each direction)::
/* Port declarations. Note, the defines come from the XN file */
buffered out port:32 p_i2s_dac[] = {PORT_I2S_DAC0}; /* I2S Data-line(s) */
@@ -22,7 +22,7 @@ Ports for the sample and bit clocks are also required::
These ports must then be passed to the ``XUA_AudioHub()`` task appropriately.
I2S functionality also requires two clock-blocks, one for bit and sample clock e.g.::
I2S/TDM functionality also requires two clock-blocks, one for bit-clock and another for the master clock e.g.::
/* Clock-block declarations */
clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_4; /* Bit clock */

View File

@@ -1,7 +1,7 @@
|newpage|
Mixer
~~~~~
=====
Since the mixer has no I/O the instantiation is straight forward. Communication wises, the mixer cores are inserted
between the `AudioHub` and Buffering core(s)

View File

@@ -1,5 +1,5 @@
XMOSNEWSTYLE = 2
DOXYGEN_DIRS=../../api
DOXYGEN_DIRS=../../api ../../src/core/user/audiostream ../../src/core/user/hostactive ../../src/core/user/hid ../../src/core/user/audiohw
SOURCE_INCLUDE_DIRS=../../../lib_xua
SPHINX_MASTER_DOC=lib_xua

View File

@@ -1,19 +1,19 @@
VERSION = 3.3.0
VERSION = 3.5.1
DEBUG ?= 0
ifeq ($(DEBUG),1)
DEBUG_FLAGS = -g -DXASSERT_ENABLE_ASSERTIONS_DECOUPLE=1
DEBUG_FLAGS = -g -DXASSERT_ENABLE_ASSERTIONS=1 -DXASSERT_ENABLE_DEBUG=1 -DXASSERT_ENABLE_LINE_NUMBERS=1
else
DEBUG_FLAGS = -DXASSERT_DISABLE_ASSERTIONS_DECOUPLE=1
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(>=4.1.0) \
lib_spdif(>=5.0.0) \
lib_xassert(>=4.1.0) \
lib_xud(>=2.2.1) \
lib_xud(>=2.2.3) \
lib_adat(>=1.0.0)
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
@@ -35,7 +35,7 @@ XCC_FLAGS_dfu.xc = $(MODULE_XCC_FLAGS) -Os -mno-dual-issue
XCC_FLAGS_flash_interface.c = $(MODULE_XCC_FLAGS) -Os -mno-dual-issue
XCC_FLAGS_flashlib_user.c = $(MODULE_XCC_FLAGS) -Os -mno-dual-issue
OPTIONAL_HEADERS += xua_conf.h
OPTIONAL_HEADERS += xua_conf.h static_hid_report.h
EXPORT_INCLUDE_DIRS = api \
src/core \
@@ -55,6 +55,7 @@ INCLUDE_DIRS = $(EXPORT_INCLUDE_DIRS) \
src/core/user/audiostream \
src/core/user/hid \
src/core/user/hostactive \
src/core/user/audiohw \
src/hid \
src/midi
@@ -70,6 +71,7 @@ SOURCE_DIRS = src/core \
src/core/support \
src/core/user/audiostream \
src/core/user/hostactive \
src/core/user/audiohw \
src/core/xuduser \
src/dfu \
src/hid \

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2022 XMOS LIMITED.
// Copyright 2018-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#if (DSD_CHANS_DAC != 0)
@@ -52,7 +52,7 @@ static inline void DoDsdDop(int &everyOther, unsigned samplesOut[], unsigned &ds
/* When DSD is enabled and streaming is standard PCM, this function checks for a series of DoP markers in the upper byte.
If found it will exit deliver() with the command to restart in DoP mode.
When in DoP mode, this function will check for a single absence of the DoP marker and exit deliver() with the command
to restart in I2S mode. */
to restart in I2S/PCM mode. */
static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSamFreq, unsigned samplesOut[], unsigned &dsdMarker)
{
/* Check for DSD - note we only move into DoP mode if valid DoP Freq */

View File

@@ -1,7 +1,6 @@
// Copyright 2018-2022 XMOS LIMITED.
// Copyright 2018-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xua.h"
#include "dsd_support.h"
#if (DSD_CHANS_DAC != 0)
@@ -12,7 +11,7 @@ extern buffered out port:32 p_dsd_clk;
extern unsigned dsdMode;
#if !CODEC_MASTER
void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
void InitPorts_master(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
{
#if (DSD_CHANS_DAC > 0)
if(dsdMode == DSD_MODE_OFF)
@@ -38,9 +37,13 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
}
#endif
#pragma xta endpoint "divide_1"
unsigned tmp;
p_lrclk <: 0 @ 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 */
@@ -48,19 +51,30 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] @ tmp <: 0;
if(XUA_I2S_N_BITS == 32)
p_i2s_dac[i] @ tmp <: 0;
else
partout_timed(p_i2s_dac[i], XUA_I2S_N_BITS, 0, tmp);
}
#endif
unsigned lrClkVal = 0x7FFFFFFF;
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
p_lrclk @ tmp <: 0x80000000;
{
lrClkVal = 0x80000000;
}
if(XUA_I2S_N_BITS == 32)
p_lrclk @ tmp <: lrClkVal;
else
p_lrclk @ tmp <: 0x7FFFFFFF;
partout_timed(p_lrclk, XUA_I2S_N_BITS, lrClkVal, tmp);
#if (I2S_CHANS_ADC != 0)
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);
}
#endif
#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */
@@ -76,7 +90,7 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
#endif
}
#else
void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
void InitPorts_slave(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
{
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
unsigned tmp;
@@ -93,7 +107,7 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
p_lrclk when pinseq(0) :> void @ tmp;
#endif
tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ;
tmp += ((I2S_CHANS_PER_FRAME * XUA_I2S_N_BITS) - XUA_I2S_N_BITS + 1) ;
/* E.g. 2 * 32 - 32 + 1 = 33 for stereo */
/* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */
@@ -101,7 +115,10 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] @ tmp <: 0;
if(XUA_I2S_N_BITS == 32)
p_i2s_dac[i] @ tmp <: 0;
else
partout_timed(p_i2s_dac[i], XUA_I2S_N_BITS, 0, tmp);
}
#endif
@@ -109,11 +126,15 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
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);
}
#endif
asm("setpt res[%0], %1"::"r"(p_lrclk),"r"(tmp-1));
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) */
}
#endif

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @file xua_audiohub.xc
@@ -15,9 +15,12 @@
#include <xclib.h>
#include <xs1_su.h>
#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)
@@ -43,25 +46,12 @@
#define MAX(x,y) ((x)>(y) ? (x) : (y))
static unsigned samplesOut[MAX(NUM_USB_CHAN_OUT, I2S_CHANS_DAC)];
unsigned samplesOut[MAX(NUM_USB_CHAN_OUT, I2S_CHANS_DAC)];
/* Two buffers for ADC data to allow for DAC and ADC I2S ports being offset */
#define IN_CHAN_COUNT (I2S_CHANS_ADC + XUA_NUM_PDM_MICS + (8*XUA_ADAT_RX_EN) + (2*XUA_SPDIF_RX_EN))
static unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)];
#ifdef XTA_TIMING_AUDIO
#pragma xta command "add exclusion received_command"
#pragma xta command "analyse path i2s_output_l i2s_output_r"
#pragma xta command "set required - 2000 ns"
#pragma xta command "add exclusion received_command"
#pragma xta command "add exclusion received_underflow"
#pragma xta command "add exclusion divide_1"
#pragma xta command "add exclusion deliver_return"
#pragma xta command "analyse path i2s_output_r i2s_output_l"
#pragma xta command "set required - 2000 ns"
#endif
unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)];
#if (XUA_ADAT_TX_EN)
extern buffered out port:32 p_adat_tx;
@@ -76,7 +66,7 @@ void InitPorts_slave
#else
void InitPorts_master
#endif
(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]);
@@ -89,76 +79,24 @@ unsigned dsdMode = DSD_MODE_OFF;
#if (XUA_ADAT_TX_EN)
#include "audiohub_adat.h"
#endif
#pragma unsafe arrays
static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, const unsigned underflowWord)
{
if(XUA_USB_EN)
{
outuint(c_out, underflowWord);
/* Check for sample freq change (or other command) or new samples from mixer*/
if(testct(c_out))
{
unsigned command = inct(c_out);
#ifndef CODEC_MASTER
if(dsdMode == DSD_MODE_OFF)
{
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
/* Set clocks low */
p_lrclk <: 0;
p_bclk <: 0;
#endif
}
else
{
#if(DSD_CHANS_DAC != 0)
/* DSD Clock might not be shared with lrclk or bclk... */
p_dsd_clk <: 0;
#endif
}
#endif
#if (DSD_CHANS_DAC > 0)
if(dsdMode == DSD_MODE_DOP)
dsdMode = DSD_MODE_OFF;
#endif
return command;
}
else
{
#if NUM_USB_CHAN_OUT > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
int tmp = inuint(c_out);
samplesOut[i] = tmp;
}
#else
inuint(c_out);
#endif
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
#if NUM_USB_CHAN_IN > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, samplesIn[readBuffNo][i]);
}
#endif
}
}
else
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
return 0;
}
#include "xua_audiohub_st.h"
static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:32 p_lrclk)
{
#if CODEC_MASTER
unsigned syncError = 0;
unsigned lrval = 0;
p_lrclk :> lrval;
const unsigned lrval_mask = (0xffffffff << (32 - XUA_I2S_N_BITS));
if(XUA_I2S_N_BITS != 32)
{
asm volatile("in %0, res[%1]":"=r"(lrval):"r"(p_lrclk):"memory");
set_port_shift_count(p_lrclk, XUA_I2S_N_BITS);
}
else
{
p_lrclk :> lrval;
}
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
{
@@ -176,30 +114,46 @@ static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:3
}
else
{
if(frameCount == 0)
syncError += (lrval != 0x80000000);
if(XUA_I2S_N_BITS == 32)
{
if(frameCount == 0)
syncError = (lrval != 0x80000000);
else
syncError = (lrval != 0x7FFFFFFF);
}
else
syncError += (lrval != 0x7FFFFFFF);
{
if(frameCount == 0)
syncError = ((lrval & lrval_mask) != 0x80000000);
else
syncError = ((lrval | (~lrval_mask)) != 0x7FFFFFFF);
}
}
return syncError;
#else
unsigned clkVal;
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
{
if(frameCount == (I2S_CHANS_PER_FRAME-1))
p_lrclk <: 0x80000000;
clkVal = 0x80000000;
else
p_lrclk <: 0x00000000;
clkVal = 0x00000000;
}
else
{
if(frameCount == 0)
p_lrclk <: 0x80000000;
clkVal = 0x80000000;
else
p_lrclk <: 0x7fffffff;
clkVal = 0x7fffffff;
}
if(XUA_I2S_N_BITS == 32)
p_lrclk <: clkVal;
else
partout(p_lrclk, XUA_I2S_N_BITS, clkVal >> (32 - XUA_I2S_N_BITS));
return 0;
#endif
@@ -316,9 +270,9 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
if ((I2S_CHANS_DAC > 0 || I2S_CHANS_ADC > 0))
{
#if CODEC_MASTER
InitPorts_slave(divide, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
InitPorts_slave(p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
#else
InitPorts_master(divide, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
InitPorts_master(p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
#endif
}
@@ -352,9 +306,17 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
// p_i2s_adc[index++] :> sample;
// Manual IN instruction since compiler generates an extra setc per IN (bug #15256)
unsigned sample;
asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++]));
asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index]));
sample = bitrev(sample);
int chanIndex = ((frameCount-2)&(I2S_CHANS_PER_FRAME-1))+i; // channels 0, 2, 4.. on each line.
if(XUA_I2S_N_BITS != 32)
{
set_port_shift_count(p_i2s_adc[index], XUA_I2S_N_BITS);
sample <<= (32 - XUA_I2S_N_BITS);
}
index++;
int chanIndex = ((frameCount-2) & (I2S_CHANS_PER_FRAME-1)) + i; // channels 0, 2, 4.. on each line.
#if (AUD_TO_USB_RATIO > 1)
if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter)
@@ -406,7 +368,10 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
src_ff3v_fir_coefs[2-audioToUsbRatioCounter]);
}
#endif /* (AUD_TO_USB_RATIO > 1) */
p_i2s_dac[index++] <: bitrev(samplesOut[frameCount +i]);
if(XUA_I2S_N_BITS == 32)
p_i2s_dac[index++] <: bitrev(samplesOut[frameCount +i]);
else
partout(p_i2s_dac[index++], XUA_I2S_N_BITS, bitrev(samplesOut[frameCount +i]));
}
#endif // (I2S_CHANS_DAC != 0)
@@ -443,9 +408,8 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
outuint(c_dig_rx, 0);
#endif
#if (XUA_SPDIF_TX_EN) && (NUM_USB_CHAN_OUT > 0)
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward sample to S/PDIF Tx thread */
unsigned sample = samplesOut[SPDIF_TX_INDEX + 1];
outuint(c_spd_out, sample); /* Forward sample to S/PDIF Tx thread */
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward samples to S/PDIF Tx thread */
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX + 1]);
#endif
#if (XUA_NUM_PDM_MICS > 0)
@@ -480,8 +444,15 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
{
/* Manual IN instruction since compiler generates an extra setc per IN (bug #15256) */
unsigned sample;
asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++]));
asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index]));
sample = bitrev(sample);
if(XUA_I2S_N_BITS != 32)
{
set_port_shift_count(p_i2s_adc[index], XUA_I2S_N_BITS);
sample <<= (32 - XUA_I2S_N_BITS);
}
index++;
int chanIndex = ((frameCount-2)&(I2S_CHANS_PER_FRAME-1))+i; // channels 1, 3, 5.. on each line.
#if (AUD_TO_USB_RATIO > 1 && !I2S_DOWNSAMPLE_MONO_IN)
if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter)
@@ -513,7 +484,6 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
#endif
index = 0;
#pragma xta endpoint "i2s_output_r"
#if (I2S_CHANS_DAC != 0)
/* Output "odd" channel to DAC (i.e. right) */
#pragma loop unroll
@@ -532,7 +502,10 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
src_ff3v_fir_coefs[2-audioToUsbRatioCounter]);
}
#endif /* (AUD_TO_USB_RATIO > 1) */
p_i2s_dac[index++] <: bitrev(samplesOut[frameCount + i]);
if(XUA_I2S_N_BITS == 32)
p_i2s_dac[index++] <: bitrev(samplesOut[frameCount + i]);
else
partout(p_i2s_dac[index++], XUA_I2S_N_BITS, bitrev(samplesOut[frameCount + i]));
}
#endif // (I2S_CHANS_DAC != 0)
@@ -586,7 +559,6 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
}
}
}
#pragma xta endpoint "deliver_return"
return 0;
}
@@ -664,6 +636,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
buffered _XUA_CLK_DIR port:32 ?p_bclk,
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]
#if (XUA_USE_APP_PLL)
, client interface SoftPll_if i_softPll
#endif
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
, chanend c_spdif_out
#endif
@@ -691,6 +666,12 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
unsigned divide;
unsigned firstRun = 1;
#if (XUA_USE_APP_PLL)
/* Use xCORE.ai Secondary PLL to generate master clock
* This could be "fixed" for async mode or adjusted if in sync mode */
i_softPll.init(DEFAULT_MCLK);
#endif
/* Clock master clock-block from master-clock port */
/* Note, marked unsafe since other cores may be using this mclk port */
configure_clock_src(clk_audio_mclk, p_mclk_in);
@@ -716,6 +697,8 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
#endif
#endif
/* Perform required CODEC/ADC/DAC initialisation */
AudioHwInit();
@@ -744,13 +727,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
/* Calculate master clock to bit clock (or DSD clock) divide for current sample freq
* e.g. 11.289600 / (176400 * 64) = 1 */
{
#if (XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
/* I2S has 32 bits per sample. *8 as 8 channels */
unsigned numBits = 256;
#else
/* I2S has 32 bits per sample. *2 as 2 channels */
unsigned numBits = 64;
#endif
unsigned numBits = XUA_I2S_N_BITS * I2S_CHANS_PER_FRAME;
#if (DSD_CHANS_DAC > 0)
if(dsdMode == DSD_MODE_DOP)
@@ -764,17 +741,24 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
numBits = 32;
}
#endif
divide = mClk / ( curSamFreq * numBits);
divide = mClk / (curSamFreq * numBits);
//Do some checks
xassert((divide > 0) && "Error: divider is 0, BCLK rate unachievable");
unsigned remainder = mClk % ( curSamFreq * numBits);
xassert((!remainder) && "Error: MCLK not divisible into BCLK by an integer number");
unsigned divider_is_odd = divide & 0x1;
xassert((!divider_is_odd) && "Error: divider is odd, clockblock cannot produce desired BCLK");
/* TODO; we should catch and handle the case when divide is 0. Currently design will lock up */
}
#if (DSD_CHANS_DAC > 0)
if(dsdMode)
{
/* Configure audio ports */
ConfigAudioPortsWrapper(
/* Configure audio ports */
ConfigAudioPortsWrapper(
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
p_dsd_dac,
DSD_CHANS_DAC,
@@ -787,7 +771,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
null,
p_dsd_clk,
#endif
p_mclk_in, clk_audio_bclk, divide, curSamFreq, dsdMode);
p_mclk_in, clk_audio_bclk, divide, curSamFreq);
}
else
#endif
@@ -810,9 +794,8 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
p_bclk,
#endif
#endif
p_mclk_in, clk_audio_bclk, divide, curSamFreq, dsdMode);
}
p_mclk_in, clk_audio_bclk, divide, curSamFreq);
}
{
unsigned curFreq = curSamFreq;
@@ -827,8 +810,19 @@ 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);
/* User should unmute audio hardware */
AudioHwConfig_UnMute();
}
if(!firstRun)

View File

@@ -0,0 +1,66 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#pragma unsafe arrays
static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, const unsigned underflowWord)
{
if(XUA_USB_EN)
{
outuint(c_out, underflowWord);
/* Check for sample freq change (or other command) or new samples from mixer*/
if(testct(c_out))
{
unsigned command = inct(c_out);
#ifndef CODEC_MASTER
if(dsdMode == DSD_MODE_OFF)
{
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
/* Set clocks low */
p_lrclk <: 0;
p_bclk <: 0;
#endif
}
else
{
#if(DSD_CHANS_DAC != 0)
/* DSD Clock might not be shared with lrclk or bclk... */
p_dsd_clk <: 0;
#endif
}
#endif
#if (DSD_CHANS_DAC > 0)
if(dsdMode == DSD_MODE_DOP)
dsdMode = DSD_MODE_OFF;
#endif
return command;
}
else
{
#if NUM_USB_CHAN_OUT > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
int tmp = inuint(c_out);
samplesOut[i] = tmp;
}
#else
inuint(c_out);
#endif
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
#if NUM_USB_CHAN_IN > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, samplesIn[readBuffNo][i]);
}
#endif
}
}
else
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
return 0;
}

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xua.h"
@@ -43,7 +43,7 @@
/*** BUFFER SIZES ***/
#define BUFFER_PACKET_COUNT 4 /* How many packets too allow for in buffer - minimum is 4 */
#define BUFFER_PACKET_COUNT (4) /* How many packets too allow for in buffer - minimum is 4 */
#define BUFF_SIZE_OUT_HS MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS * BUFFER_PACKET_COUNT
#define BUFF_SIZE_OUT_FS MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS * BUFFER_PACKET_COUNT
@@ -55,18 +55,25 @@
#define BUFF_SIZE_IN MAX(BUFF_SIZE_IN_HS, BUFF_SIZE_IN_FS)
#define OUT_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS, MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS))
#define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2)
#define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2)
/* Volume and mute tables */
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
unsigned int multOut[NUM_USB_CHAN_OUT + 1];
static xc_ptr p_multOut;
unsafe
{
unsigned int volatile * unsafe multOutPtr = multOut;
}
#endif
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
unsigned int multIn[NUM_USB_CHAN_IN + 1];
static xc_ptr p_multIn;
unsafe
{
unsigned int volatile * unsafe multInPtr = multIn;
}
#endif
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
#if (AUDIO_CLASS == 2)
int g_numUsbChan_In = NUM_USB_CHAN_IN; /* Number of channels to/from the USB bus - initialised to HS for UAC2.0 */
int g_numUsbChan_Out = NUM_USB_CHAN_OUT;
@@ -143,7 +150,72 @@ unsigned unpackData = 0;
unsigned packState = 0;
unsigned packData = 0;
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
static inline void SendSamples4(chanend c_mix_out)
{
/* Doing this checking allows us to unroll */
if(g_numUsbChan_Out == NUM_USB_CHAN_OUT)
{
/* Buffering not underflow condition send out some samples...*/
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
int sample;
int mult;
int h;
unsigned l;
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
g_aud_from_host_rdptr+=4;
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
unsafe
{
mult = multOutPtr[i];
}
{h, l} = macs(mult, sample, 0, 0);
h <<= 3;
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
h |= (l >>29) & 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
// Note: We need all 32bits for Native DSD
#endif
outuint(c_mix_out, h);
#else
outuint(c_mix_out, sample);
#endif
}
}
else
{
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT_FS; i++)
{
int sample;
int mult;
int h;
unsigned l;
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
g_aud_from_host_rdptr+=4;
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
unsafe
{
mult = multOutPtr[i];
}
{h, l} = macs(mult, sample, 0, 0);
h <<= 3;
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
h |= (l >>29) & 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
// Note: We need all 32bits for Native DSD
#endif
outuint(c_mix_out, h);
#else
outuint(c_mix_out, sample);
#endif
}
}
}
#pragma select handler
#pragma unsafe arrays
@@ -206,8 +278,11 @@ __builtin_unreachable();
g_aud_from_host_rdptr+=2;
sample <<= 16;
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
unsafe
{
mult = multOutPtr[i];
}
{h, l} = macs(mult, sample, 0, 0);
/* Note, in 2 byte subslot mode - ignore lower result of macs */
h <<= 3;
@@ -223,41 +298,17 @@ __builtin_unreachable();
__builtin_unreachable();
#endif
/* Buffering not underflow condition send out some samples...*/
for(int i = 0; i < g_numUsbChan_Out; i++)
{
#pragma xta endpoint "mixer_request"
int sample;
int mult;
int h;
unsigned l;
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
g_aud_from_host_rdptr+=4;
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
{h, l} = macs(mult, sample, 0, 0);
h <<= 3;
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
// Note: We need all 32bits for Native DSD
#endif
outuint(c_mix_out, h);
#else
outuint(c_mix_out, sample);
#endif
}
SendSamples4(c_mix_out);
break;
case 3:
#if (STREAM_FORMAT_OUTPUT_SUBSLOT_3_USED == 0)
__builtin_unreachable();
#endif
/* Buffering not underflow condition send out some samples...*/
/* Note, in this case the unpacking of data is more of an overhead than the loop overhead
* so we do not currently make attempts to unroll */
for(int i = 0; i < g_numUsbChan_Out; i++)
{
#pragma xta endpoint "mixer_request"
int sample;
int mult;
int h;
@@ -289,19 +340,20 @@ __builtin_unreachable();
}
unpackState++;
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
unsafe
{
mult = multOutPtr[i];
}
{h, l} = macs(mult, sample, 0, 0);
h <<= 3;
outuint(c_mix_out, h);
#else
outuint(c_mix_out, sample);
#endif
}
break;
default:
__builtin_unreachable();
break;
@@ -335,17 +387,20 @@ __builtin_unreachable();
/* Receive sample */
int sample = inuint(c_mix_out);
#if (INPUT_VOLUME_CONTROL == 1)
#if !defined(IN_VOLUME_IN_MIXER)
#if (!IN_VOLUME_IN_MIXER)
/* Apply volume */
int mult;
int h;
unsigned l;
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
unsafe
{
mult = multInPtr[i];
}
{h, l} = macs(mult, sample, 0, 0);
sample = h << 3;
/* Note, in 2 byte sub slot - ignore lower bits of macs */
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
#elif (IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
sample = sample << 3;
#endif
#endif
@@ -365,18 +420,21 @@ __builtin_unreachable();
/* Receive sample */
int sample = inuint(c_mix_out);
#if(INPUT_VOLUME_CONTROL == 1)
#if !defined(IN_VOLUME_IN_MIXER)
#if (!IN_VOLUME_IN_MIXER)
/* Apply volume */
int mult;
int h;
unsigned l;
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
unsafe
{
mult = multInPtr[i];
}
{h, l} = macs(mult, sample, 0, 0);
sample = h << 3;
#if (STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED == 1)
sample |= (l >> 29) & 0x7; // Note, this step is not required if we assume sample depth is 24 (rather than 32)
#endif
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
#elif (IN_VOLUME_IN_MIXER) && (IN_VOLUME_AFTER_MIX)
sample = sample << 3;
#endif
#endif
@@ -396,12 +454,15 @@ __builtin_unreachable();
{
/* Receive sample */
int sample = inuint(c_mix_out);
#if (INPUT_VOLUME_CONTROL) && !defined(IN_VOLUME_IN_MIXER)
#if (INPUT_VOLUME_CONTROL) && (!IN_VOLUME_IN_MIXER)
/* Apply volume */
int mult;
int h;
unsigned l;
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
unsafe
{
mult = multInPtr[i];
}
{h, l} = macs(mult, sample, 0, 0);
sample = h << 3;
#endif
@@ -588,6 +649,7 @@ __builtin_unreachable();
}
}
#if (NUM_USB_CHAN_IN > 0)
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
xc_ptr aud_to_host_zeros)
@@ -619,6 +681,7 @@ static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned samp
XUD_SetReady_InPtr(aud_to_host_usb_ep, aud_to_host_zeros+4, mid);
}
#endif
#pragma unsafe arrays
void XUA_Buffer_Decouple(chanend c_mix_out
@@ -638,13 +701,6 @@ void XUA_Buffer_Decouple(chanend c_mix_out
int t = array_to_xc_ptr(outAudioBuff);
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
p_multOut = array_to_xc_ptr(multOut);
#endif
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
p_multIn = array_to_xc_ptr(multIn);
#endif
aud_from_host_fifo_start = t;
aud_from_host_fifo_end = aud_from_host_fifo_start + BUFF_SIZE_OUT;
g_aud_from_host_wrptr = aud_from_host_fifo_start;
@@ -668,17 +724,17 @@ void XUA_Buffer_Decouple(chanend c_mix_out
xc_ptr aud_to_host_zeros = t;
/* Init vol mult tables */
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
for (int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
{
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multOut),"r"(i));
unsafe{
multOutPtr[i] = MAX_VOLUME_MULT;
}
#endif
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
for (int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
{
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multIn),"r"(i));
unsafe{
multInPtr[i] = MAX_VOLUME_MULT;
}
#endif
@@ -760,8 +816,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
/* Set buffer to send back to zeros buffer */
aud_to_host_buffer = aud_to_host_zeros;
#if (NUM_USB_CHAN_IN > 0)
/* Update size of zeros buffer (and sampsToWrite) */
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
#endif
/* Reset OUT buffer state */
outUnderflow = 1;
@@ -815,8 +873,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
/* Set buffer back to zeros buffer */
aud_to_host_buffer = aud_to_host_zeros;
#if (NUM_USB_CHAN_IN > 0)
/* Update size of zeros buffer (and sampsToWrite) */
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
#endif
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
if (usbSpeed == XUD_SPEED_HS)

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xua.h"
#if XUA_USB_EN
@@ -10,7 +10,7 @@
#include "xud.h"
#include "testct_byref.h"
#if( 0 < HID_CONTROLS )
#if XUA_HID_ENABLED
#include "xua_hid_report.h"
#include "user_hid.h"
#include "xua_hid.h"
@@ -105,7 +105,11 @@ void XUA_Buffer(
#endif
, chanend c_aud
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
#if(XUA_USE_APP_PLL)
, chanend c_swpll_update
#else
, client interface pll_ref_if i_pll_ref
#endif
#endif
)
{
@@ -134,14 +138,18 @@ void XUA_Buffer(
c_clk_int,
#endif
c_sof, c_aud_ctl, p_off_mclk
#if( 0 < HID_CONTROLS )
#if XUA_HID_ENABLED
, c_hid
#endif
#ifdef CHAN_BUFF_CTRL
, c_buff_ctrl
#endif
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
, i_pll_ref
#if(XUA_USE_APP_PLL)
, c_swpll_update
#else
, i_pll_ref
#endif
#endif
);
@@ -190,8 +198,12 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#ifdef CHAN_BUFF_CTRL
, chanend c_buff_ctrl
#endif
#if XUA_SYNCMODE == XUA_SYNCMODE_SYNC
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
#if (XUA_USE_APP_PLL)
, chanend c_swpll_update
#else
, client interface pll_ref_if i_pll_ref
#endif
#endif
)
{
@@ -224,7 +236,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
XUD_ep ep_int = XUD_InitEp(c_ep_int);
#endif
#if( 0 < HID_CONTROLS )
#if XUA_HID_ENABLED
XUD_ep ep_hid = XUD_InitEp(c_hid);
#endif
unsigned u_tmp;
@@ -247,7 +259,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#if (NUM_USB_CHAN_IN > 0)
unsigned bufferIn = 1;
#endif
unsigned sofCount = 0;
int sofCount = 0;
int pllUpdate = 0;
unsigned mod_from_last_time = 0;
#ifdef FB_TOLERANCE_TEST
@@ -294,7 +307,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
unsigned iap_ea_native_interface_alt_setting = 0;
unsigned iap_ea_native_control_to_send = 0;
unsigned iap_ea_native_incoming = 0;
#endif
#endif
@@ -332,7 +344,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#endif
#endif
#if( 0 < HID_CONTROLS )
#if XUA_HID_ENABLED
while (!hidIsReportDescriptorPrepared())
;
@@ -357,12 +369,16 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#ifndef LOCAL_CLOCK_MARGIN
#define LOCAL_CLOCK_MARGIN (1000)
#endif
#if (!XUA_USE_APP_PLL)
timer t_sofCheck;
unsigned timeLastEdge;
unsigned timeNextEdge;
t_sofCheck :> timeLastEdge;
timeNextEdge + LOCAL_CLOCK_INCREMENT;
i_pll_ref.toggle();
#endif
#endif
while(1)
@@ -427,7 +443,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
/* Reset FB */
/* Note, Endpoint 0 will hold off host for a sufficient period to allow our feedback
* to stabilise (i.e. sofCount == 128 to fire) */
sofCount = 1;
sofCount = 0;
pllUpdate = 0;
clocks = 0;
clockcounter = 0;
mod_from_last_time = 0;
@@ -502,13 +519,13 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
}
#endif
/* Pass on sample freq change to decouple() via global flag (saves a chanend) */
/* Note: freqChange flags now used to communicate other commands also */
/* Note: freqChange_flag now used to communicate other commands also */
SET_SHARED_GLOBAL0(g_freqChange, cmd); /* Set command */
SET_SHARED_GLOBAL(g_freqChange_flag, cmd); /* Set Flag */
}
break;
}
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL)
case t_sofCheck when timerafter(timeNextEdge) :> void:
i_pll_ref.toggle();
timeLastEdge = timeNextEdge;
@@ -528,7 +545,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
unsigned usbSpeed;
int framesPerSec;
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
static int sofCount = 0;
framesPerSec = (usbSpeed == XUD_SPEED_HS) ? 8000 : 1000;
@@ -539,12 +555,27 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
sofCount += 1000;
if (sofCount == framesPerSec)
{
sofCount = 0;
pllUpdate++;
#if (!XUA_USE_APP_PLL)
/* Port is accessed via interface to allow flexibilty with location */
i_pll_ref.toggle();
t_sofCheck :> timeLastEdge;
sofCount = 0;
timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
#endif
}
#if (XUA_USE_APP_PLL)
// Update PLL @ 100Hz
if(pllUpdate == 10)
{
pllUpdate = 0;
unsigned short mclk_pt;
asm volatile("getts %0, res[%1]" : "=r" (mclk_pt) : "r" (p_off_mclk));
outuint(c_swpll_update, mclk_pt);
outct(c_swpll_update, XS1_CT_END);
}
#endif
#elif (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
/* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to
@@ -646,7 +677,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
clockcounter = 0;
}
#else
/* Assuming 48kHz from a 24.576 master clock (0.0407uS period)
* MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF.
* expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format.
@@ -897,8 +927,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#endif
#endif
#if( 0 < HID_CONTROLS )
/* HID Report Data */
#if (XUA_HID_ENABLED)
/* HID Report Data */
case XUD_SetData_Select(c_hid, ep_hid, result):
hid_ready_flag = 0U;
unsigned reportTime;
@@ -911,7 +941,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#endif
#ifdef MIDI
/* Received word from MIDI thread - Check for ACK or Data */
/* Received word from MIDI thread - Check for ACK or Data */
case midi_get_ack_or_data(c_midi, is_ack, datum):
if (is_ack)
{

View File

@@ -0,0 +1,457 @@
// 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

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
@@ -13,14 +13,14 @@
#include "spdif.h"
#endif
#define LOCAL_CLOCK_INCREMENT 166667
#define LOCAL_CLOCK_MARGIN 1666
#define LOCAL_CLOCK_INCREMENT (166667)
#define LOCAL_CLOCK_MARGIN (1666)
#define MAX_SAMPLES 64 /* Must be power of 2 */
#define MAX_SAMPLES (64) /* Must be power of 2 */
#define MAX_SPDIF_SAMPLES (2 * MAX_SAMPLES) /* Must be power of 2 */
#define MAX_ADAT_SAMPLES (8 * MAX_SAMPLES) /* Must be power of 2 */
#define SPDIF_FRAME_ERRORS_THRESH 40
#define SPDIF_FRAME_ERRORS_THRESH (40)
unsigned g_digData[10];
@@ -241,12 +241,7 @@ extern int samples_to_host_inputs_buff[NUM_USB_CHAN_IN];
int VendorAudCoreReqs(unsigned cmd, chanend c);
#pragma unsafe arrays
//#if (AUDIO_IO_TILE == PLL_REF_TILE)
#if 0
void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, out port p, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
#else
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)
#endif
{
timer t_local;
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
@@ -723,7 +718,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
/* Mixer requests data */
/* AudioHub requests data */
case inuint_byref(c_dig_rx, tmp):
#if (XUA_SPDIF_RX_EN)
if(spdifUnderflow)

View File

@@ -0,0 +1,398 @@
// 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
};

View File

@@ -1,4 +1,4 @@
// Copyright 2015-2021 XMOS LIMITED.
// Copyright 2015-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __DESCRIPTOR_DEFS_H__
@@ -33,6 +33,7 @@
#define ENDPOINT_ADDRESS_OUT_MIDI (ENDPOINT_NUMBER_OUT_MIDI)
#define ENDPOINT_ADDRESS_OUT_IAP (ENDPOINT_NUMBER_OUT_IAP)
#define ENDPOINT_ADDRESS_OUT_IAP_EA_NATIVE_TRANS (ENDPOINT_NUMBER_OUT_IAP_EA_NATIVE_TRANS)
#define ENDPOINT_ADDRESS_OUT_HID (ENDPOINT_NUMBER_OUT_HID)
/* Interface numbers enum */
enum USBInterfaceNumber
@@ -60,7 +61,7 @@ enum USBInterfaceNumber
INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS,
#endif
#endif
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
INTERFACE_NUMBER_HID,
#endif
INTERFACE_COUNT /* End marker */
@@ -70,4 +71,8 @@ enum USBInterfaceNumber
#define ENDPOINT_INT_INTERVAL_IN_HID 0x08
#endif
#ifndef ENDPOINT_INT_INTERVAL_OUT_HID
#define ENDPOINT_INT_INTERVAL_OUT_HID 0x08
#endif
#endif

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
@@ -26,7 +26,7 @@
#include "xc_ptr.h"
#include "xua_ep0_uacreqs.h"
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
#include "hid.h"
#include "xua_hid.h"
#include "xua_hid_report.h"
@@ -106,13 +106,17 @@ unsigned int mutesOut[NUM_USB_CHAN_OUT + 1];
int volsIn[NUM_USB_CHAN_IN + 1];
unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
#ifdef MIXER
unsigned char mixer1Crossbar[18];
short mixer1Weights[18*8];
#if (MIXER)
short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
//unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
/* Mapping of channels to output audio interfaces */
unsigned char channelMapAud[NUM_USB_CHAN_OUT];
/* Mapping of channels to USB host */
unsigned char channelMapUsb[NUM_USB_CHAN_IN];
/* Mapping of channels to Mixer(s) */
unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
#endif
@@ -262,6 +266,44 @@ void XUA_Endpoint0_setVendorId(unsigned short vid) {
#endif // AUDIO_CLASS == 1}
}
#if (MIXER)
void InitLocalMixerState()
{
for (int i = 0; i < MIX_INPUTS * MAX_MIX_COUNT; i++)
{
mixer1Weights[i] = 0x8001; //-inf
}
/* Configure default connections */
for (int i = 0; i < MAX_MIX_COUNT; i++)
{
mixer1Weights[(i * MAX_MIX_COUNT) + i] = 0;
}
#if NUM_USB_CHAN_OUT > 0
/* Setup up audio output channel mapping */
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
channelMapAud[i] = i;
}
#endif
#if NUM_USB_CHAN_IN > 0
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
}
#endif
/* Init mixer inputs */
for(int j = 0; j < MAX_MIX_COUNT; j++)
for(int i = 0; i < MIX_INPUTS; i++)
{
mixSel[j][i] = i;
}
}
#endif
void concatenateAndCopyStrings(char* string1, char* string2, char* string_buffer) {
debug_printf("concatenateAndCopyStrings() for \"%s\" and \"%s\"\n", string1, string2);
@@ -400,6 +442,15 @@ void XUA_Endpoint0_setBcdDevice(unsigned short bcd) {
#endif // AUDIO_CLASS == 1}
}
#if defined(__static_hid_report_h_exists__)
#define hidReportDescriptorLength (sizeof(hidReportDescriptorPtr))
static unsigned char hidReportDescriptorPtr[] = {
#include "static_hid_report.h"
};
#endif
void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(chanend, c_audioControl),
chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_)
{
@@ -408,75 +459,11 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
XUA_Endpoint0_setStrTable();
#if 0
/* Dont need to init globals.. */
/* Init tables for volumes (+ 1 for master) */
for(int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
{
volsOut[i] = 0;
mutesOut[i] = 0;
}
for(int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
{
volsIn[i] = 0;
mutesIn[i] = 0;
}
#endif
VendorRequests_Init(VENDOR_REQUESTS_PARAMS);
#ifdef MIXER
#if (MIXER)
/* Set up mixer default state */
for (int i = 0; i < 18*8; i++)
{
mixer1Weights[i] = 0x8001; //-inf
}
/* Configure default connections */
mixer1Weights[0] = 0;
mixer1Weights[9] = 0;
mixer1Weights[18] = 0;
mixer1Weights[27] = 0;
mixer1Weights[36] = 0;
mixer1Weights[45] = 0;
mixer1Weights[54] = 0;
mixer1Weights[63] = 0;
#if NUM_USB_CHAN_OUT > 0
/* Setup up audio output channel mapping */
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
channelMapAud[i] = i;
}
#endif
#if NUM_USB_CHAN_IN > 0
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
}
#endif
/* Set up channel mapping default */
for (int i = 0; i < NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN; i++)
{
channelMap[i] = i;
}
#if MAX_MIX_COUNT > 0
/* Mixer outputs mapping defaults */
for (int i = 0; i < MAX_MIX_COUNT; i++)
{
channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = i;
}
#endif
/* Init mixer inputs */
for(int j = 0; j < MAX_MIX_COUNT; j++)
for(int i = 0; i < MIX_INPUTS; i++)
{
mixSel[j][i] = i;
}
InitLocalMixerState();
#endif
#ifdef VENDOR_AUDIO_REQS
@@ -529,18 +516,19 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
cfgDesc_Audio1[USB_AS_OUT_INTERFACE_DESCRIPTOR_OFFSET_FREQ + 3*i + 2] = (get_usb_to_device_rate() & 0xff0000)>> 16;
}
cfgDesc_Audio1[USB_AS_OUT_EP_DESCRIPTOR_OFFSET_MAXPACKETSIZE] = ((get_usb_to_device_bit_res() >> 3) * MAX_PACKET_SIZE_MULT_OUT_FS) & 0xff; //max packet size
cfgDesc_Audio1[USB_AS_OUT_EP_DESCRIPTOR_OFFSET_MAXPACKETSIZE + 1] = (((get_usb_to_device_bit_res() >> 3) * MAX_PACKET_SIZE_MULT_OUT_FS) & 0xff00) >> 8; //max packet size
#endif // NUM_USB_CHAN_OUT
#endif // XUA_USB_DESCRIPTOR_OVERWRITE_RATE_RES
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
#if XUA_HID_ENABLED
hidReportInit();
hidPrepareReportDescriptor();
size_t hidReportDescriptorLength = hidGetReportDescriptorLength();
#endif
unsigned char hidReportDescriptorLengthLo = hidReportDescriptorLength & 0xFF;
unsigned char hidReportDescriptorLengthHi = (hidReportDescriptorLength & 0xFF00) >> 8;
@@ -551,6 +539,7 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
hidDescriptor[HID_DESCRIPTOR_LENGTH_FIELD_OFFSET ] = hidReportDescriptorLengthLo;
hidDescriptor[HID_DESCRIPTOR_LENGTH_FIELD_OFFSET + 1] = hidReportDescriptorLengthHi;
#endif // 0 < HID_CONTROLS
}
@@ -754,7 +743,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
switch(sp.bRequest)
{
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
case USB_GET_DESCRIPTOR:
/* Check what inteface request is for */
@@ -769,15 +758,17 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
{
/* Return HID Descriptor */
result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor,
sizeof(hidDescriptor), sp.wLength);
hidDescriptor[0], sp.wLength);
}
break;
case HID_REPORT:
{
/* Return HID report descriptor */
#if XUA_HID_ENABLED
unsigned char* hidReportDescriptorPtr;
hidReportDescriptorPtr = hidGetReportDescriptor();
size_t hidReportDescriptorLength = hidGetReportDescriptorLength();
#endif
result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptorPtr,
hidReportDescriptorLength, sp.wLength);
}
@@ -881,7 +872,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
}
}
#endif
#if( 0 < HID_CONTROLS )
#if XUA_HID_ENABLED
if (interfaceNum == INTERFACE_NUMBER_HID)
{
result = HidInterfaceClassRequests(ep0_out, ep0_in, &sp);

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @file xua_ep0_descriptors.h
@@ -308,28 +308,28 @@ typedef struct
#error NUM_USB_CHAN > 32
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
#if (MIXER) && (MAX_MIX_COUNT > 0)
STR_TABLE_ENTRY(mixOutStr_1);
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
#if (MIXER) && (MAX_MIX_COUNT > 1)
STR_TABLE_ENTRY(mixOutStr_2);
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
#if (MIXER) && (MAX_MIX_COUNT > 2)
STR_TABLE_ENTRY(mixOutStr_3);
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
#if (MIXER) && (MAX_MIX_COUNT > 3)
STR_TABLE_ENTRY(mixOutStr_4);
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
#if (MIXER) && (MAX_MIX_COUNT > 4)
STR_TABLE_ENTRY(mixOutStr_5);
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
#if (MIXER) && (MAX_MIX_COUNT > 5)
STR_TABLE_ENTRY(mixOutStr_6);
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
#if (MIXER) && (MAX_MIX_COUNT > 6)
STR_TABLE_ENTRY(mixOutStr_7);
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
#if (MIXER) && (MAX_MIX_COUNT > 7)
STR_TABLE_ENTRY(mixOutStr_8);
#endif
#ifdef IAP
@@ -391,31 +391,31 @@ StringDescTable_t g_strTable =
#error NUM_USB_CHAN_IN > 32
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
#if (MIXER) && (MAX_MIX_COUNT > 0)
.mixOutStr_1 = "Mix 1",
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
#if (MIXER) && (MAX_MIX_COUNT > 1)
.mixOutStr_2 = "Mix 2",
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
#if (MIXER) && (MAX_MIX_COUNT > 2)
.mixOutStr_3 = "Mix 3",
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
#if (MIXER) && (MAX_MIX_COUNT > 3)
.mixOutStr_4 = "Mix 4",
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
#if (MIXER) && (MAX_MIX_COUNT > 4)
.mixOutStr_5 = "Mix 5",
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
#if (MIXER) && (MAX_MIX_COUNT > 5)
.mixOutStr_6 = "Mix 6",
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
#if (MIXER) && (MAX_MIX_COUNT > 6)
.mixOutStr_7 = "Mix 7",
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
#if (MIXER) && (MAX_MIX_COUNT > 7)
.mixOutStr_8 = "Mix 8",
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 8)
#if (MIXER) && (MAX_MIX_COUNT > 8)
#error
#endif
#ifdef IAP
@@ -481,7 +481,7 @@ USB_Descriptor_Device_t devDesc_Audio2 =
.iManufacturer = offsetof(StringDescTable_t, vendorStr)/sizeof(char *),
.iProduct = offsetof(StringDescTable_t, productStr_Audio2)/sizeof(char *),
.iSerialNumber = offsetof(StringDescTable_t, serialStr)/sizeof(char *),
.bNumConfigurations = 0x02 /* Set to 2 such that windows does not load composite driver */
.bNumConfigurations = 0x01
};
/* Device Descriptor for Null Device */
@@ -558,7 +558,7 @@ unsigned char devQualDesc_Null[] =
};
#if defined(MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
#if (MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
//#warning Extension units on the audio path are required for mixer. Enabling them now.
#define AUDIO_PATH_XUS
#endif
@@ -575,7 +575,7 @@ unsigned char devQualDesc_Null[] =
#define DFU_LENGTH (0)
#endif
#ifdef MIXER
#if (MIXER)
#define MIX_BMCONTROLS_LEN_TMP ((MAX_MIX_COUNT * MIX_INPUTS) / 8)
#if ((MAX_MIX_COUNT * MIX_INPUTS)%8)==0
@@ -666,7 +666,7 @@ typedef struct
#if (NUM_USB_CHAN_OUT > 0)
/* Output path */
USB_Descriptor_Audio_InputTerminal_t Audio_Out_InputTerminal;
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
#if (MIXER) && (MAX_MIX_COUNT > 0)
USB_Descriptor_Audio_ExtensionUnit_t Audio_Out_ExtensionUnit;
#endif
#if(OUTPUT_VOLUME_CONTROL == 1)
@@ -677,7 +677,7 @@ typedef struct
#if (NUM_USB_CHAN_IN > 0)
/* Input path */
USB_Descriptor_Audio_InputTerminal_t Audio_In_InputTerminal;
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
#if (MIXER) && (MAX_MIX_COUNT > 0)
USB_Descriptor_Audio_ExtensionUnit_t Audio_In_ExtensionUnit;
#endif
#if(INPUT_VOLUME_CONTROL == 1)
@@ -685,7 +685,7 @@ typedef struct
#endif
USB_Descriptor_Audio_OutputTerminal_t Audio_In_OutputTerminal;
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
#if (MIXER) && (MAX_MIX_COUNT > 0)
USB_Descriptor_Audio_ExtensionUnit2_t Audio_Mix_ExtensionUnit;
// Currently no struct for mixer unit
// USB_Descriptor_Audio_MixerUnit_t Audio_MixerUnit;
@@ -787,10 +787,13 @@ typedef struct
#endif
#endif // IAP
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
USB_Descriptor_Interface_t HID_Interface;
USB_HID_Descriptor_t HID_Descriptor;
USB_Descriptor_Endpoint_t HID_In_Endpoint;
#if HID_OUT_REQUIRED
USB_Descriptor_Endpoint_t HID_Out_Endpoint;
#endif
#endif
}__attribute__((packed)) USB_Config_Descriptor_Audio2_t;
@@ -1168,7 +1171,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
UAC_CS_DESCTYPE_INTERFACE, /* 1 bDescriptorType: CS_INTERFACE */
UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT, /* 2 bDescriptorSubType: FEATURE_UNIT */
FU_USBIN, /* 3 bUnitID */
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
#if (MIXER) && (MAX_MIX_COUNT > 0)
ID_XU_IN, /* 4 bSourceID */
#else
ID_IT_AUD, /* 4 bSourceID */
@@ -1300,7 +1303,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
},
#endif /* (NUM_USB_CHAN_IN > 0) */
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
#if (MIXER) && (MAX_MIX_COUNT > 0)
/* Extension Unit Descriptor (4.7.2.12) */
.Audio_Mix_ExtensionUnit =
{
@@ -1392,7 +1395,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
0x00, /* bmControls */
0 /* Mixer unit string descriptor index */
},
#endif /* defined(MIXER) && (MAX_MIX_COUNT > 0) */
#endif /* (MIXER) && (MAX_MIX_COUNT > 0) */
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN)
/* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */
@@ -2208,14 +2211,14 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
#endif
#endif /* IAP */
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
#include "xua_hid_descriptors.h"
#endif
};
#endif /* (AUDIO_CLASS == 2) */
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
#if (AUDIO_CLASS ==1 )
unsigned char hidDescriptor[] =
{
@@ -2330,14 +2333,14 @@ const unsigned num_freqs_a1 = MAX(3, (0
#define DFU_INTERFACES_A1 0
#endif
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
/*
* The value of HID_INTERFACE_BYTES must match the length of the descriptors defined in
* - xua_hid_descriptor_contents.h
* - xua_hid_endpoint_descriptor_contents.h and
* - xua_hid_interface_descriptor_contents.h
*/
#define HID_INTERFACE_BYTES ( 9 + 9 + 7 )
#define HID_INTERFACE_BYTES ( 9 + 9 + (7 * (1 + HID_OUT_REQUIRED))) // always IN
#define HID_INTERFACES_A1 1
#else
#define HID_INTERFACE_BYTES 0
@@ -2379,7 +2382,7 @@ const unsigned num_freqs_a1 = MAX(3, (0
#endif
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
#define USB_HID_DESCRIPTOR_OFFSET (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + INTERFACE_DESCRIPTOR_BYTES)
#endif
@@ -2893,7 +2896,7 @@ unsigned char cfgDesc_Audio1[] =
offsetof(StringDescTable_t, ctrlStr)/sizeof(char *), /* 8 iInterface */
#endif
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
#include "xua_hid_descriptors.h"
#endif

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @brief Implements relevant requests from the USB Audio 2.0 Specification
@@ -14,26 +14,29 @@
#include "usbaudio10.h"
#include "dbcalc.h"
#include "xua_commands.h"
#include "xc_ptr.h"
#define CS_XU_MIXSEL (0x06)
/* From decouple.xc */
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
extern unsigned int multOut[NUM_USB_CHAN_OUT + 1];
#endif
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
extern unsigned int multIn[NUM_USB_CHAN_IN + 1];
#endif
extern int interfaceAlt[];
/* Global volume and mute tables */
/* Global volume and mute tables - from xua_endpoint0.c */
extern int volsOut[];
extern unsigned int mutesOut[];
extern int volsIn[];
extern unsigned int mutesIn[];
/* Mixer settings */
#ifdef MIXER
extern unsigned char mixer1Crossbar[];
extern short mixer1Weights[];
#if (MIXER)
/* Mixer weights */
extern short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
/* Device channel mapping */
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
@@ -102,20 +105,6 @@ void FeedbackStabilityDelay()
t when timerafter(time + delay):> void;
}
#if 0
/* Original feedback implementation */
unsafe
{
unsigned * unsafe curSamFreqMultiplier = &g_curSamFreqMultiplier;
static void setG_curSamFreqMultiplier(unsigned x)
{
// asm(" stw %0, dp[g_curSamFreqMultiplier]" :: "r"(x));
*curSamFreqMultiplier = x;
}
}
#endif
#if (OUTPUT_VOLUME_CONTROL == 1) || (INPUT_VOLUME_CONTROL == 1)
static unsigned longMul(unsigned a, unsigned b, int prec)
{
@@ -130,16 +119,9 @@ static unsigned longMul(unsigned a, unsigned b, int prec)
}
/* Update master volume i.e. i.e update weights for all channels */
static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
static void updateMasterVol(int unitID, chanend ?c_mix_ctl)
{
int x;
#ifndef OUT_VOLUME_IN_MIXER
xc_ptr p_multOut = array_to_xc_ptr(multOut);
#endif
#ifndef IN_VOLUME_IN_MIXER
xc_ptr p_multIn = array_to_xc_ptr(multIn);
#endif
switch( unitID)
switch(unitID)
{
case FU_USBOUT:
{
@@ -151,18 +133,24 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
/* 0x8000 is a special value representing -inf (i.e. mute) */
unsigned vol = volsOut[i] == 0x8000 ? 0 : db_to_mult(volsOut[i], 8, 29);
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[i];
int x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[i];
#ifdef OUT_VOLUME_IN_MIXER
#if (OUT_VOLUME_IN_MIXER)
if (!isnull(c_mix_ctl))
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
outuint(c_mix_ctl, i-1);
outuint(c_mix_ctl, x);
outct(c_mix_ctl, XS1_CT_END);
}
#else
asm("stw %0, %1[%2]"::"r"(x),"r"(p_multOut),"r"(i-1));
#else
unsafe
{
unsigned int * unsafe multOutPtr = multOut;
multOutPtr[i-1] = x;
}
#endif
}
}
@@ -177,18 +165,24 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
/* 0x8000 is a special value representing -inf (i.e. mute) */
unsigned vol = volsIn[i] == 0x8000 ? 0 : db_to_mult(volsIn[i], 8, 29);
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i];
int x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i];
#ifdef IN_VOLUME_IN_MIXER
#if (IN_VOLUME_IN_MIXER)
if (!isnull(c_mix_ctl))
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, SET_MIX_IN_VOL);
outuint(c_mix_ctl, i-1);
outuint(c_mix_ctl, x);
outct(c_mix_ctl, XS1_CT_END);
}
#else
asm("stw %0, %1[%2]"::"r"(x),"r"(p_multIn),"r"(i-1));
unsafe
{
unsigned int * unsafe multInPtr = multIn;
multInPtr[i-1] = x;
}
#endif
}
}
@@ -202,12 +196,6 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
{
int x;
#ifndef OUT_VOLUME_IN_MIXER
xc_ptr p_multOut = array_to_xc_ptr(multOut);
#endif
#ifndef IN_VOLUME_IN_MIXER
xc_ptr p_multIn = array_to_xc_ptr(multIn);
#endif
/* Check for master volume update */
if (channel == 0)
{
@@ -226,16 +214,22 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[channel];
#ifdef OUT_VOLUME_IN_MIXER
#if (OUT_VOLUME_IN_MIXER)
if (!isnull(c_mix_ctl))
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
outuint(c_mix_ctl, channel-1);
outuint(c_mix_ctl, x);
outct(c_mix_ctl, XS1_CT_END);
}
#else
asm("stw %0, %1[%2]"::"r"(x),"r"(p_multOut),"r"(channel-1));
unsafe
{
unsigned int * unsafe multOutPtr = multOut;
multOutPtr[channel-1] = x;
}
#endif
break;
}
@@ -244,20 +238,26 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
/* Calc multipliers with 29 fractional bits from a db value with 8 fractional bits */
/* 0x8000 is a special value representing -inf (i.e. mute) */
unsigned master_vol = volsIn[0] == 0x8000 ? 0 : db_to_mult(volsIn[0], 8, 29);
unsigned vol = volsIn[channel] == 0x8000 ? 0 : db_to_mult(volsIn[channel], 8, 29);
unsigned vol = volsIn[channel] == 0x8000 ? 0 : db_to_mult(volsIn[channel], 8, 29);
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[channel];
#ifdef IN_VOLUME_IN_MIXER
#if (IN_VOLUME_IN_MIXER)
if (!isnull(c_mix_ctl))
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, SET_MIX_IN_VOL);
outuint(c_mix_ctl, channel-1);
outuint(c_mix_ctl, x);
outct(c_mix_ctl, XS1_CT_END);
}
#else
asm("stw %0, %1[%2]"::"r"(x),"r"(p_multIn),"r"(channel-1));
unsafe
{
unsigned int * unsafe multInPtr = multIn;
multInPtr[channel-1] = x;
}
#endif
break;
}
@@ -266,6 +266,38 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
}
#endif
void UpdateMixerOutputRouting(chanend c_mix_ctl, unsigned map, unsigned dst, unsigned src)
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, map);
outuint(c_mix_ctl, dst);
outuint(c_mix_ctl, src);
outct(c_mix_ctl, XS1_CT_END);
}
void UpdateMixMap(chanend c_mix_ctl, int mix, int input, int src)
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, SET_MIX_MAP);
outuint(c_mix_ctl, mix); /* Mix bus */
outuint(c_mix_ctl, input); /* Mixer input (cn) */
outuint(c_mix_ctl, src); /* Source (mixSel[cn]) */
outct(c_mix_ctl, XS1_CT_END);
}
void UpdateMixerWeight(chanend c_mix_ctl, int mix, int index, unsigned mult)
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, SET_MIX_MULT);
outuint(c_mix_ctl, mix);
outuint(c_mix_ctl, index);
outuint(c_mix_ctl, mult);
outct(c_mix_ctl, XS1_CT_END);
}
/* Handles the audio class specific requests
* returns: XUD_RES_OKAY if request dealt with successfully without error,
* XUD_RES_RST for device reset
@@ -282,7 +314,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
/* Inspect request, NOTE: these are class specific requests */
switch( sp.bRequest )
{
/* CUR Request*/
case CUR:
{
@@ -318,7 +349,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
int newSampleRate = buffer[0];
/* Instruct audio thread to change sample freq (if change required) */
//if(newSampleRate != g_curSamFreq)
if(newSampleRate != g_curSamFreq)
{
int newMasterClock;
@@ -371,7 +402,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
}
#endif /* MAX_FREQ != MIN_FREQ */
/* Send 0 Length as status stage */
int x = XUD_DoSetRequestStatus(ep0_in);
return XUD_DoSetRequestStatus(ep0_in);
}
/* Direction: Device-to-host: Send Current Sample Freq */
else
@@ -537,7 +568,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
if ((sp.wValue & 0xff) <= NUM_USB_CHAN_OUT)
{
volsOut[ sp.wValue&0xff ] = (buffer, unsigned char[])[0] | (((int) (signed char) (buffer, unsigned char[])[1]) << 8);
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
return XUD_DoSetRequestStatus(ep0_in);
}
}
@@ -546,7 +577,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
if ((sp.wValue & 0xff) <= NUM_USB_CHAN_IN)
{
volsIn[ sp.wValue&0xff ] = (buffer, unsigned char[])[0] | (((int) (signed char) (buffer, unsigned char[])[1]) << 8);
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
return XUD_DoSetRequestStatus(ep0_in);
}
}
@@ -632,85 +663,76 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
break; /* FU_USBIN */
#endif
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
#if ((MIXER) && (MAX_MIX_COUNT > 0))
case ID_XU_OUT:
{
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
{
unsigned volume = 0;
int c = sp.wValue & 0xff;
int dst = sp.wValue & 0xff;
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
{
return result;
}
channelMapAud[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
if (!isnull(c_mix_ctl))
{
if (c < NUM_USB_CHAN_OUT)
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
{
outuint(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP);
outuint(c_mix_ctl, c);
outuint(c_mix_ctl, channelMapAud[c]);
outct(c_mix_ctl, XS1_CT_END);
/* Send 0 Length as status stage */
return XUD_DoSetRequestStatus(ep0_in);
return result;
}
if (dst < NUM_USB_CHAN_OUT)
{
channelMapAud[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
if (!isnull(c_mix_ctl))
{
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP, dst, channelMapAud[dst]);
}
}
/* Send 0 Length as status stage */
return XUD_DoSetRequestStatus(ep0_in);
}
else
{
(buffer, unsigned char[])[0] = channelMapAud[dst];
(buffer, unsigned char[])[1] = 0;
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
}
}
else
{
(buffer, unsigned char[])[0] = channelMapAud[sp.wValue & 0xff];
(buffer, unsigned char[])[1] = 0;
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
}
}
break;
case ID_XU_IN:
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
{
unsigned volume = 0;
int c = sp.wValue & 0xff;
int dst = sp.wValue & 0xff;
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
{
return result;
}
channelMapUsb[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
if (c < NUM_USB_CHAN_IN)
{
if (!isnull(c_mix_ctl))
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
{
outuint(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP);
outuint(c_mix_ctl, c);
outuint(c_mix_ctl, channelMapUsb[c]);
outct(c_mix_ctl, XS1_CT_END);
return XUD_DoSetRequestStatus(ep0_in);
return result;
}
if (dst < NUM_USB_CHAN_IN)
{
channelMapUsb[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
if (!isnull(c_mix_ctl))
{
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP, dst, channelMapUsb[dst]);
}
}
return XUD_DoSetRequestStatus(ep0_in);
}
else
{
/* Direction: Device-to-host */
(buffer, unsigned char[])[0] = channelMapUsb[dst];
(buffer, unsigned char[])[1] = 0;
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
}
}
else
{
/* Direction: Device-to-host */
(buffer, unsigned char[])[0] = channelMapUsb[sp.wValue & 0xff];
(buffer, unsigned char[])[1] = 0;
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
}
break;
case ID_XU_MIXSEL:
{
int cs = sp.wValue >> 8; /* Control Selector */
int cn = sp.wValue & 0xff; /* Channel number */
int cn = sp.wValue & 0xff; /* Channel Number */
/* Check for Get or Set */
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D)
@@ -723,21 +745,19 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
if(datalength > 0)
{
/* cn bounds check for safety..*/
/* CN bounds check for safety..*/
if(cn < MIX_INPUTS)
{
//if(cs == CS_XU_MIXSEL)
/* cs now contains mix number */
if(cs < (MAX_MIX_COUNT + 1))
{
int source = (buffer, unsigned char[])[0];
/* Check for "off" - update local state */
if((buffer, unsigned char[])[0] == 0xFF)
if(source == 0xFF)
{
mixSel[cs][cn] = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
}
else
{
mixSel[cs][cn] = (buffer, unsigned char[])[0];
source = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
}
if(cs == 0)
@@ -745,21 +765,17 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
/* Update all mix maps */
for (int i = 0; i < MAX_MIX_COUNT; i++)
{
outuint(c_mix_ctl, SET_MIX_MAP);
outuint(c_mix_ctl, i); /* Mix bus */
outuint(c_mix_ctl, cn); /* Mixer input */
outuint(c_mix_ctl, (int) mixSel[cn]); /* Source */
outct(c_mix_ctl, XS1_CT_END);
/* i : Mix bus */
/* cn: Mixer input */
mixSel[i][cn] = source;
UpdateMixMap(c_mix_ctl, i, cn, mixSel[i][cn]);
}
}
else
{
/* Update relevant mix map */
outuint(c_mix_ctl, SET_MIX_MAP); /* Command */
outuint(c_mix_ctl, (cs-1)); /* Mix bus */
outuint(c_mix_ctl, cn); /* Mixer input */
outuint(c_mix_ctl, (int) mixSel[cs][cn]); /* Source */
outct(c_mix_ctl, XS1_CT_END); /* Wait for handshake back */
mixSel[cs-1][cn] = source;
UpdateMixMap(c_mix_ctl, cs-1, cn, mixSel[cs-1][cn]);
}
return XUD_DoSetRequestStatus(ep0_in);
@@ -780,7 +796,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
if((cs > 0) && (cs < (MAX_MIX_COUNT+1)))
{
(buffer, unsigned char[])[0] = mixSel[cs-1][cn];
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, 1 );
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, 1);
}
}
}
@@ -788,49 +804,53 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
}
case ID_MIXER_1:
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
{
unsigned volume = 0;
int cs = sp.wValue >> 8; /* Control Selector - currently unused */
int cn = sp.wValue & 0xff; /* Channel number - used for mixer node index */
/* Expect OUT here with mute */
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
{
return result;
}
unsigned weightMult = 0;
mixer1Weights[sp.wValue & 0xff] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
/* Expect OUT here with weight */
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
{
return result;
}
if (mixer1Weights[sp.wValue & 0xff] == 0x8000)
{
volume = 0;
if(cn < sizeof(mixer1Weights)/sizeof(mixer1Weights[0]))
{
mixer1Weights[cn] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
if (mixer1Weights[cn] != 0x8000)
{
weightMult = db_to_mult(mixer1Weights[cn], XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS);
}
if (!isnull(c_mix_ctl))
{
UpdateMixerWeight(c_mix_ctl, (cn) % 8, (cn) / 8, weightMult);
}
}
/* Send 0 Length as status stage */
return XUD_DoSetRequestStatus(ep0_in);
}
else
{
volume = db_to_mult(mixer1Weights[sp.wValue & 0xff], 8, 25);
}
if (!isnull(c_mix_ctl))
{
outuint(c_mix_ctl, SET_MIX_MULT);
outuint(c_mix_ctl, (sp.wValue & 0xff) % 8);
outuint(c_mix_ctl, (sp.wValue & 0xff) / 8);
outuint(c_mix_ctl, volume);
outct(c_mix_ctl, XS1_CT_END);
}
short weight = 0x8000;
/* Send 0 Length as status stage */
return XUD_DoSetRequestStatus(ep0_in);
}
else
{
short weight = mixer1Weights[sp.wValue & 0xff];
(buffer, unsigned char[])[0] = weight & 0xff;
(buffer, unsigned char[])[1] = (weight >> 8) & 0xff;
if(cn < sizeof(mixer1Weights)/sizeof(mixer1Weights[0]))
{
weight = mixer1Weights[cn];
}
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
storeShort((buffer, unsigned char[]), 0, weight);
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
}
}
break;
#endif
default:
/* We dont have a unit with this ID! */
@@ -919,7 +939,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
num_freqs++;
}
#endif
storeShort((buffer, unsigned char[]), 0, num_freqs);
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), i, sp.wLength);
@@ -957,7 +976,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
}
break;
#ifdef MIXER
#if (MIXER)
/* Mixer Unit */
case ID_MIXER_1:
storeShort((buffer, unsigned char[]), 0, 1);
@@ -967,7 +986,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
break;
#endif
default:
/* Unknown Unit ID in Range Request selector for FU */
break;
@@ -977,7 +995,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
break; /* case: RANGE */
}
#if defined (MIXER) && (MAX_MIX_COUNT > 0)
#if ((MIXER) && (MAX_MIX_COUNT > 0))
case MEM: /* Memory Requests (5.2.7.1) */
unitID = sp.wIndex >> 8;
@@ -1003,6 +1021,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
{
if (!isnull(c_mix_ctl))
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, GET_STREAM_LEVELS);
outuint(c_mix_ctl, i);
outct(c_mix_ctl, XS1_CT_END);
@@ -1018,6 +1038,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
{
if (!isnull(c_mix_ctl))
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, GET_INPUT_LEVELS);
outuint(c_mix_ctl, (i - NUM_USB_CHAN_OUT));
outct(c_mix_ctl, XS1_CT_END);
@@ -1040,6 +1062,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
{
if (!isnull(c_mix_ctl))
{
outct(c_mix_ctl, XS1_CT_END);
inct(c_mix_ctl);
outuint(c_mix_ctl, GET_OUTPUT_LEVELS);
outuint(c_mix_ctl, i);
outct(c_mix_ctl, XS1_CT_END);
@@ -1107,13 +1131,10 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
if(newSampleRate != g_curSamFreq)
{
int curSamFreq44100Family;
int curSamFreq48000Family;
/* Windows Audio Class driver has a nice habbit of sending invalid SF's (e.g. 48001Hz)
* when under stress. Lets double check it here and ignore if not valid. */
curSamFreq48000Family = MCLK_48 % newSampleRate == 0;
curSamFreq44100Family = MCLK_441 % newSampleRate == 0;
int curSamFreq48000Family = MCLK_48 % newSampleRate == 0;
int curSamFreq44100Family = MCLK_441 % newSampleRate == 0;
if(curSamFreq48000Family || curSamFreq44100Family)
{
@@ -1128,7 +1149,7 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
/* Allow time for the change - feedback to stabilise */
FeedbackStabilityDelay();
}
}
}
return XUD_SetBuffer(ep0_in, (buffer, unsigned char[]), 0);
}
@@ -1190,12 +1211,12 @@ XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket
{
case FU_USBOUT:
volsOut[ sp.wValue & 0xff ] = buffer[0] | (((int) (signed char) buffer[1]) << 8);
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
return XUD_DoSetRequestStatus(ep0_in);
case FU_USBIN:
volsIn[ sp.wValue & 0xff ] = buffer[0] | (((int) (signed char) buffer[1]) << 8);
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
return XUD_DoSetRequestStatus(ep0_in);
}
}
@@ -1209,12 +1230,12 @@ XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket
{
case FU_USBOUT:
mutesOut[ sp.wValue & 0xff ] = buffer[0];
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
return XUD_DoSetRequestStatus(ep0_in);
case FU_USBIN:
mutesIn[ sp.wValue & 0xff ] = buffer[0];
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
return XUD_DoSetRequestStatus(ep0_in);
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2012-2022 XMOS LIMITED.
// Copyright 2012-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xua.h" /* Device specific defines */
@@ -31,7 +31,7 @@
#endif
#if (XUA_SPDIF_RX_EN)
#include "SpdifReceive.h"
#include "spdif.h"
#endif
#if (XUA_ADAT_RX_EN)
@@ -142,10 +142,10 @@ on stdcore[XUD_TILE] : buffered in port:32 p_adat_rx = PORT_ADAT_IN;
#endif
#if (XUA_SPDIF_RX_EN)
on tile[XUD_TILE] : buffered in port:4 p_spdif_rx = PORT_SPDIF_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)
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) || ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL))
/* Reference to external clock multiplier */
on tile[PLL_REF_TILE] : out port p_pll_ref = PORT_PLL_REF;
#endif
@@ -213,6 +213,9 @@ XUD_EpType epTypeTableOut[ENDPOINT_COUNT_OUT] = { XUD_EPTYPE_CTL | XUD_STATUS_EN
#ifdef MIDI
XUD_EPTYPE_BUL, /* MIDI */
#endif
#if HID_OUT_REQUIRED
XUD_EPTYPE_INT,
#endif
#ifdef IAP
XUD_EPTYPE_BUL, /* iAP */
#ifdef IAP_EA_NATIVE_TRANS
@@ -228,12 +231,12 @@ XUD_EpType epTypeTableIn[ENDPOINT_COUNT_IN] = { XUD_EPTYPE_CTL | XUD_STATUS_ENAB
XUD_EPTYPE_ISO, /* Async feedback endpoint */
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
XUD_EPTYPE_BUL,
XUD_EPTYPE_INT,
#endif
#ifdef MIDI
XUD_EPTYPE_BUL,
#endif
#if( 0 < HID_CONTROLS )
#if XUA_OR_STATIC_HID_ENABLED
XUD_EPTYPE_INT,
#endif
#ifdef IAP
@@ -267,115 +270,6 @@ void xscope_user_init()
}
#endif
#if XUA_USB_EN
/* Core USB Audio functions - must be called on the Tile connected to the USB Phy */
void usb_audio_core(chanend c_mix_out
#ifdef MIDI
, chanend c_midi
#endif
#ifdef MIXER
, chanend c_mix_ctl
#endif
, chanend ?c_clk_int
, chanend ?c_clk_ctl
, client interface i_dfu ?dfuInterface
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
, client interface pll_ref_if i_pll_ref
#endif
VENDOR_REQUESTS_PARAMS_DEC_
)
{
chan c_sof;
chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */
chan c_xud_in[ENDPOINT_COUNT_IN];
chan c_aud_ctl;
#ifndef MIXER
#define c_mix_ctl null
#endif
#ifdef IAP_EA_NATIVE_TRANS
chan c_EANativeTransport_ctrl;
#else
#define c_EANativeTransport_ctrl null
#endif
par
{
{
#ifdef XUD_PRIORITY_HIGH
set_core_high_priority_on();
#endif
/* Run UAC2.0 at high-speed, UAC1.0 at full-speed */
unsigned usbSpeed = (AUDIO_CLASS == 2) ? XUD_SPEED_HS : XUD_SPEED_FS;
unsigned xudPwrCfg = (XUA_POWERMODE == XUA_POWERMODE_SELF) ? XUD_PWR_SELF : XUD_PWR_BUS;
/* USB interface core */
XUD_Main(c_xud_out, ENDPOINT_COUNT_OUT, c_xud_in, ENDPOINT_COUNT_IN,
c_sof, epTypeTableOut, epTypeTableIn, usbSpeed, xudPwrCfg);
}
{
unsigned x;
thread_speed();
/* Attach mclk count port to mclk clock-block (for feedback) */
//set_port_clock(p_for_mclk_count, clk_audio_mclk);
#if(AUDIO_IO_TILE != XUD_TILE)
set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb);
set_port_clock(p_for_mclk_count, clk_audio_mclk_usb);
start_clock(clk_audio_mclk_usb);
#else
/* Clock port from same clock-block as I2S */
/* TODO remove asm() */
asm("ldw %0, dp[clk_audio_mclk]":"=r"(x));
asm("setclk res[%0], %1"::"r"(p_for_mclk_count), "r"(x));
#endif
/* Endpoint & audio buffering cores */
XUA_Buffer(c_xud_out[ENDPOINT_NUMBER_OUT_AUDIO],/* Audio Out*/
#if (NUM_USB_CHAN_IN > 0)
c_xud_in[ENDPOINT_NUMBER_IN_AUDIO], /* Audio In */
#endif
#if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP)
c_xud_in[ENDPOINT_NUMBER_IN_FEEDBACK], /* Audio FB */
#endif
#ifdef MIDI
c_xud_out[ENDPOINT_NUMBER_OUT_MIDI], /* MIDI Out */ // 2
c_xud_in[ENDPOINT_NUMBER_IN_MIDI], /* MIDI In */ // 4
c_midi,
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
/* Audio Interrupt - only used for interrupts on external clock change */
c_xud_in[ENDPOINT_NUMBER_IN_INTERRUPT],
c_clk_int,
#endif
c_sof, c_aud_ctl, p_for_mclk_count
#if (HID_CONTROLS)
, c_xud_in[ENDPOINT_NUMBER_IN_HID]
#endif
, c_mix_out
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
, i_pll_ref
#endif
);
//:
}
/* Endpoint 0 Core */
{
thread_speed();
XUA_Endpoint0( c_xud_out[0], c_xud_in[0], c_aud_ctl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_);
}
//:
}
}
#endif /* XUA_USB_EN */
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
void SpdifTxWrapper(chanend c_spdif_tx)
{
@@ -401,7 +295,7 @@ void usb_audio_io(chanend ?c_aud_in,
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
chanend c_spdif_tx,
#endif
#ifdef MIXER
#if (MIXER)
chanend c_mix_ctl,
#endif
streaming chanend ?c_spdif_rx,
@@ -420,9 +314,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
#endif
)
{
#ifdef MIXER
#if (MIXER)
chan c_mix_out;
#endif
@@ -446,7 +343,7 @@ void usb_audio_io(chanend ?c_aud_in,
par
{
#ifdef MIXER
#if (MIXER)
/* Mixer cores(s) */
{
thread_speed();
@@ -464,12 +361,15 @@ void usb_audio_io(chanend ?c_aud_in,
/* Audio I/O core (pars additional S/PDIF TX Core) */
{
thread_speed();
#ifdef MIXER
#if (MIXER)
#define AUDIO_CHANNEL c_mix_out
#else
#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
@@ -531,7 +431,7 @@ int main()
#endif
#endif
#ifdef MIXER
#if (MIXER)
chan c_mix_ctl;
#endif
@@ -573,17 +473,36 @@ int main()
#endif
#endif
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
interface pll_ref_if i_pll_ref;
#endif
#if (XUA_USE_APP_PLL)
interface SoftPll_if i_softPll;
chan c_swpll_update;
#endif
chan c_sof;
chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */
chan c_xud_in[ENDPOINT_COUNT_IN];
chan c_aud_ctl;
#if (!MIXER)
#define c_mix_ctl null
#endif
#ifdef IAP_EA_NATIVE_TRANS
chan c_EANativeTransport_ctrl;
#else
#define c_EANativeTransport_ctrl null
#endif
USER_MAIN_DECLARATIONS
par
{
USER_MAIN_CORES
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XYA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref);
#endif
on tile[XUD_TILE]:
@@ -597,30 +516,91 @@ int main()
#endif
#endif
#if XUA_USB_EN
/* Core USB audio task, buffering, USB etc */
usb_audio_core(c_mix_out
#ifdef MIDI
, c_midi
#endif
#ifdef IAP
, c_iap
#ifdef IAP_EA_NATIVE_TRANS
, c_ea_data
#endif
#endif
#ifdef MIXER
, c_mix_ctl
#endif
, c_clk_int, c_clk_ctl, dfuInterface
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
, i_pll_ref
#endif
VENDOR_REQUESTS_PARAMS_
);
/* Core USB task, buffering, USB etc */
{
#ifdef XUD_PRIORITY_HIGH
set_core_high_priority_on();
#endif
/* Run UAC2.0 at high-speed, UAC1.0 at full-speed */
unsigned usbSpeed = (AUDIO_CLASS == 2) ? XUD_SPEED_HS : XUD_SPEED_FS;
unsigned xudPwrCfg = (XUA_POWERMODE == XUA_POWERMODE_SELF) ? XUD_PWR_SELF : XUD_PWR_BUS;
/* USB interface core */
XUD_Main(c_xud_out, ENDPOINT_COUNT_OUT, c_xud_in, ENDPOINT_COUNT_IN,
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;
thread_speed();
/* Attach mclk count port to mclk clock-block (for feedback) */
//set_port_clock(p_for_mclk_count, clk_audio_mclk);
#if(AUDIO_IO_TILE != XUD_TILE)
set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb);
set_port_clock(p_for_mclk_count, clk_audio_mclk_usb);
start_clock(clk_audio_mclk_usb);
#else
/* Clock port from same clock-block as I2S */
/* TODO remove asm() */
asm("ldw %0, dp[clk_audio_mclk]":"=r"(x));
asm("setclk res[%0], %1"::"r"(p_for_mclk_count), "r"(x));
#endif
/* Endpoint & audio buffering cores */
XUA_Buffer(c_xud_out[ENDPOINT_NUMBER_OUT_AUDIO],/* Audio Out*/
#if (NUM_USB_CHAN_IN > 0)
c_xud_in[ENDPOINT_NUMBER_IN_AUDIO], /* Audio In */
#endif
#if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP)
c_xud_in[ENDPOINT_NUMBER_IN_FEEDBACK], /* Audio FB */
#endif
#ifdef MIDI
c_xud_out[ENDPOINT_NUMBER_OUT_MIDI], /* MIDI Out */ // 2
c_xud_in[ENDPOINT_NUMBER_IN_MIDI], /* MIDI In */ // 4
c_midi,
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
/* Audio Interrupt - only used for interrupts on external clock change */
c_xud_in[ENDPOINT_NUMBER_IN_INTERRUPT],
c_clk_int,
#endif
c_sof, c_aud_ctl, p_for_mclk_count
#if (XUA_HID_ENABLED)
, c_xud_in[ENDPOINT_NUMBER_IN_HID]
#endif
, c_mix_out
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
#if (!XUA_USE_APP_PLL)
, i_pll_ref
#else
, c_swpll_update
#endif
#endif
);
//:
}
/* Endpoint 0 Core */
{
thread_speed();
XUA_Endpoint0( c_xud_out[0], c_xud_in[0], c_aud_ctl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_);
}
#endif /* XUA_USB_EN */
}
#if(XUA_USE_APP_PLL)
on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update);
#endif
on tile[AUDIO_IO_TILE]:
{
/* Audio I/O task, includes mixing etc */
@@ -628,7 +608,7 @@ int main()
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
, c_spdif_tx
#endif
#ifdef MIXER
#if (MIXER)
, c_mix_ctl
#endif
, c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int
@@ -643,6 +623,9 @@ int main()
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
, i_pll_ref
#endif
#if (XUA_USE_APP_PLL)
, i_softPll
#endif
);
}
@@ -685,7 +668,7 @@ int main()
on tile[XUD_TILE]:
{
thread_speed();
SpdifReceive(p_spdif_rx, c_spdif_rx, 1, clk_spd_rx);
spdif_rx(c_spdif_rx,p_spdif_rx,clk_spd_rx,192000);
}
#endif

View File

@@ -1,12 +1,21 @@
// Copyright 2018-2021 XMOS LIMITED.
// Copyright 2018-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#define MAX_MIX_COUNT 8
#define MIX_INPUTS 18
#include "xua.h"
#ifndef MAX_MIX_COUNT
#error
#endif
#ifndef MIX_INPUTS
#error
#endif
#if (MAX_MIX_COUNT > 0)
#define DOMIX_TOP(i) \
.cc_top doMix##i.function,doMix##i; \
.align 4 ;\
.align 16 ;\
.globl doMix##i ;\
.type doMix##i, @function ;\
.globl doMix##i##.nstackwords ;\
@@ -124,7 +133,7 @@ DOMIX_BOT(7)
#undef BODY
#define N MAX_MIX_COUNT
.cc_top setPtr.function,setPtr;
.align 4 ;
.align 16 ;
.globl setPtr;
.type setPtr, @function
.globl setPtr.nstackwords;
@@ -173,5 +182,5 @@ setPtr_go:
#undef N
#undef BODY
#endif

View File

@@ -1,25 +1,39 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#define XASSERT_UNIT MIXER
#include "xassert.h"
#include <xs1.h>
#include <print.h>
#include "xua.h"
#include "xc_ptr.h"
#include "xua_commands.h"
#include "dbcalc.h"
#ifdef MIXER
/* FAST_MIXER has a bit of a nasty implentation but is more efficient */
#ifndef FAST_MIXER
#define FAST_MIXER (1)
#endif
/* FAST_MIXER has a bit of a nasty implentation but is more effcient */
#define FAST_MIXER 1
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) || !FAST_MIXER
#include "xc_ptr.h"
#endif
//#ifdef OUT_VOLUME_IN_MIXER
#if (MIXER)
#if (OUT_VOLUME_IN_MIXER)
static unsigned int multOut_array[NUM_USB_CHAN_OUT + 1];
static xc_ptr multOut;
//#endif
//#ifdef IN_VOLUME_IN_MIXER
unsafe
{
unsigned int volatile * unsafe multOut = multOut_array;
}
#endif
#if (IN_VOLUME_IN_MIXER)
static unsigned int multIn_array[NUM_USB_CHAN_IN + 1];
static xc_ptr multIn;
//#endif
unsafe
{
unsigned int volatile * unsafe multIn = multIn_array;
}
#endif
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
static unsigned abs(int x)
@@ -35,35 +49,38 @@ static unsigned abs(int x)
}
#endif
static const int SOURCE_COUNT = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1;
static int samples_array[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */
xc_ptr samples;
static int samples_to_host_map_array[NUM_USB_CHAN_IN];
static int samples_to_device_map_array[NUM_USB_CHAN_OUT];
unsafe
{
static int volatile * const unsafe ptr_samples = samples_array;
int volatile * const unsafe ptr_samples = samples_array;
int volatile * const unsafe samples_to_host_map = samples_to_host_map_array;
int volatile * const unsafe samples_to_device_map = samples_to_device_map_array;
}
int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
int samples_to_host_map_array[NUM_USB_CHAN_IN];
xc_ptr samples_to_host_map;
int samples_to_device_map_array[NUM_USB_CHAN_OUT];
xc_ptr samples_to_device_map;
#if MAX_MIX_COUNT > 0
int mix_mult_array[MAX_MIX_COUNT][MIX_INPUTS];
xc_ptr mix_mult;
#define write_word_to_mix_mult(x,y,val) write_via_xc_ptr_indexed(mix_mult,((x)*MIX_INPUTS)+(y), val)
#define mix_mult_slice(x) (mix_mult + x * MIX_INPUTS * sizeof(int))
#ifndef FAST_MIXER
int mix_map_array[MAX_MIX_COUNT][MIX_INPUTS];
xc_ptr mix_map;
#define write_word_to_mix_map(x,y,val) write_via_xc_ptr_indexed(mix_map,((x)*MIX_INPUTS)+(y), val)
#define mix_map_slice(x) (mix_map + x * MIX_INPUTS * sizeof(int))
#endif
#if (MAX_MIX_COUNT > 0)
int mix_mult_array[MAX_MIX_COUNT * MIX_INPUTS];
#if (FAST_MIXER == 0)
int mix_map_array[MAX_MIX_COUNT * MIX_INPUTS];
#endif
unsafe
{
int volatile * const unsafe mix_mult = mix_mult_array;
#if (FAST_MIXER == 0)
int volatile * const unsafe mix_map = mix_map_array;
#endif
}
#define slice(a, i) (a + i * MIX_INPUTS)
#endif
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
/* Arrays for level data */
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. device inputs */
xc_ptr samples_to_host_inputs_ptr;
@@ -77,19 +94,6 @@ static int samples_from_host_streams[NUM_USB_CHAN_OUT]; /* Peak samples for audi
static int samples_mixer_outputs[MAX_MIX_COUNT]; /* Peak samples out of the mixer */
xc_ptr samples_mixer_outputs_ptr;
#if 0
#pragma xta command "add exclusion mixer1_rate_change"
#pragma xta command "analyse path mixer1_req mixer1_req"
#pragma xta command "set required - 10400 ns" /* 96kHz */
#endif
#if 0
#pragma xta command "add exclusion mixer2_rate_change"
#pragma xta command "analyse path mixer2_req mixer2_req"
#pragma xta command "set required - 10400 ns" /* 96kHz */
#endif
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
static inline void ComputeMixerLevel(int sample, int i)
{
int x;
@@ -108,42 +112,40 @@ static inline void ComputeMixerLevel(int sample, int i)
}
}
#endif
#ifdef FAST_MIXER
#if (FAST_MIXER)
void setPtr(int src, int dst, int mix);
int doMix0(xc_ptr samples, xc_ptr mult);
int doMix1(xc_ptr samples, xc_ptr mult);
int doMix2(xc_ptr samples, xc_ptr mult);
int doMix3(xc_ptr samples, xc_ptr mult);
int doMix4(xc_ptr samples, xc_ptr mult);
int doMix5(xc_ptr samples, xc_ptr mult);
int doMix6(xc_ptr samples, xc_ptr mult);
int doMix7(xc_ptr samples, xc_ptr mult);
int doMix8(xc_ptr samples, xc_ptr mult);
int doMix0(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix1(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix2(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix3(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix4(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix5(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix6(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix7(volatile int * const unsafe samples, volatile int * const unsafe mult);
#else
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
/* At 18 x 12dB we could get 64 x bigger */
#pragma unsafe arrays
static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
static inline int doMix(volatile int * unsafe samples, volatile int * unsafe const mixMap, volatile int * const unsafe mult)
{
int h=0;
int l=0;
/* By breaking up the loop we keep things in the encoding for ldw (0-11) */
#pragma loop unroll
for (int i=0; i<MIX_INPUTS; i++)
{
int sample;
int index;
int m;
read_via_xc_ptr_indexed(index, ptr, i);
read_via_xc_ptr_indexed(sample,samples,index);
read_via_xc_ptr_indexed(m, mult, i);
{h,l} = macs(sample, m, h, l);
unsafe{
int sample;
int source;
int weight;
read_via_xc_ptr_indexed(source, mixMap, i);
sample = samples[source];
read_via_xc_ptr_indexed(weight, mult, i);
{h,l} = macs(sample, weight, h, l);
}
#if 1
/* Perform saturation */
l = sext(h, 25);
l = sext(h, XUA_MIXER_MULT_FRAC_BITS);
if(l != h)
{
@@ -152,15 +154,14 @@ static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
else
h = (0x7fffff00>>7);
}
#endif
return h<<7;
}
#endif
#pragma unsafe arrays
static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
static inline void GiveSamplesToHost(chanend c, volatile int * unsafe hostMap)
{
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
int mult;
int h;
unsigned l;
@@ -170,23 +171,26 @@ static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
for (int i=0; i<NUM_USB_CHAN_IN; i++)
{
int sample;
int index;
#if MAX_MIX_COUNT > 0
read_via_xc_ptr_indexed(index,ptr,i);
#else
index = i + NUM_USB_CHAN_OUT;
#endif
#if (MAX_MIX_COUNT > 0)
unsafe
{
//read_via_xc_ptr_indexed(sample,samples,index);
sample = ptr_samples[index];
sample = ptr_samples[hostMap[i]];
}
#else
unsafe
{
sample = ptr_samples[i + NUM_USB_CHAN_OUT];
}
#endif
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
#warning IN Vols in mixer, AFTER mix & map
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
read_via_xc_ptr_indexed(mult, multIn, i);
unsafe
{
mult = multIn[i];
}
{h, l} = macs(mult, sample, 0, 0);
//h <<= 3 done on other side */
@@ -209,7 +213,7 @@ static inline void GetSamplesFromHost(chanend c)
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
unsafe {
int sample, x;
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
#if (OUT_VOLUME_IN_MIXER && !OUT_VOLUME_AFTER_MIX)
int mult;
int h;
unsigned l;
@@ -226,50 +230,47 @@ static inline void GetSamplesFromHost(chanend c)
}
#endif
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
#if (OUT_VOLUME_IN_MIXER && !OUT_VOLUME_AFTER_MIX)
#warning OUT Vols in mixer, BEFORE mix & map
read_via_xc_ptr_indexed(mult, multOut, i);
mult = multOut[i];
{h, l} = macs(mult, sample, 0, 0);
h<<=3;
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
// Note: We need all 32bits for Native DSD
// Note: We need all 32bits for Native DSD
#endif
sample = h;
#endif
write_via_xc_ptr_indexed(multOut, index, val);
write_via_xc_ptr_indexed(samples_array, i, h);
#else
ptr_samples[i] = sample;
#endif
}
}
#endif
}
#pragma unsafe arrays
static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
static inline void GiveSamplesToDevice(chanend c, volatile int * unsafe deviceMap)
{
#if(NUM_USB_CHAN_OUT == 0)
#if (NUM_USB_CHAN_OUT == 0)
outuint(c, 0);
#else
#pragma loop unroll
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
{
int sample, x;
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
#if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
int mult;
int h;
unsigned l;
#endif
int index;
#if MAX_MIX_COUNT > 0
#if (MAX_MIX_COUNT > 0)
/* If mixer turned on sort out the channel mapping */
/* Read pointer to sample from the map */
read_via_xc_ptr_indexed(index, ptr, i);
/* Read the actual sample value */
read_via_xc_ptr_indexed(sample, samples, index);
unsafe
{
/* Read index to sample from the map then Read the actual sample value */
sample = ptr_samples[deviceMap[i]];
}
#else
unsafe
{
@@ -278,16 +279,19 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
}
#endif
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
#if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
/* Do volume control processing */
#warning OUT Vols in mixer, AFTER mix & map
read_via_xc_ptr_indexed(mult, multOut, i);
unsafe
{
mult = multOut[i];
}
{h, l} = macs(mult, sample, 0, 0);
h<<=3; // Shift used to be done in audio thread but now done here incase of 32bit support
#error
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
// Note: We need all 32bits for Native DSD
// Note: We need all 32bits for Native DSD
#endif
outuint(c, h);
#else
@@ -300,14 +304,14 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
#pragma unsafe arrays
static inline void GetSamplesFromDevice(chanend c)
{
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
int mult;
int h;
unsigned l;
#endif
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_IN;i++)
for (int i=0; i<NUM_USB_CHAN_IN; i++)
{
int sample;
int x;
@@ -327,22 +331,24 @@ static inline void GetSamplesFromDevice(chanend c)
}
#endif
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
/* Read relevant multiplier */
read_via_xc_ptr_indexed(mult, multIn, i);
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
/* Volume processing - read relevant multiplier */
unsafe
{
mult = multIn[i];
}
/* Do the multiply */
{h, l} = macs(mult, sample, 0, 0);
h <<=3;
write_via_xc_ptr_indexed(samples_array, NUM_USB_CHAN_OUT+i, h);
#else
/* No volume processing */
h <<= 3;
sample = h;
#endif
unsafe
{
ptr_samples[NUM_USB_CHAN_OUT + i] = sample;
assert((XUA_MIXER_OFFSET_IN + i) < (NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT));
ptr_samples[XUA_MIXER_OFFSET_IN + i] = sample;
}
#endif
}
}
}
static int mixer1_mix2_flag = (DEFAULT_FREQ > 96000);
@@ -353,12 +359,14 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
#if (MAX_MIX_COUNT > 0)
int mixed;
#endif
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
unsigned cmd;
unsigned char ct;
#endif
unsigned request = 0;
while (1)
{
#pragma xta endpoint "mixer1_req"
/* Request from audio()/mixer2() */
request = inuint(c_mixer2);
@@ -369,28 +377,62 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
/* Sync */
outuint(c_mixer2, 0);
#endif
/* Between request to decouple and response ~ 400nS latency for interrupt to fire */
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
select
{
case inuint_byref(c_mix_ctl, cmd):
/* Check if EP0 intends to send us a control command */
case inct_byref(c_mix_ctl, ct):
{
int mix, index, val;
/* Handshake back to tell EP0 we are ready for an update */
outct(c_mix_ctl, XS1_CT_END);
/* Receive command from EP0 */
cmd = inuint(c_mix_ctl);
/* Interpret control command */
switch (cmd)
{
#if MAX_MIX_COUNT > 0
#if (MAX_MIX_COUNT > 0)
case SET_SAMPLES_TO_HOST_MAP:
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
write_via_xc_ptr_indexed(samples_to_host_map, index, val);
{
int dst = inuint(c_mix_ctl);
int src = inuint(c_mix_ctl);
inct(c_mix_ctl);
assert((dst < NUM_USB_CHAN_IN) && msg("Host map destination out of range"));
assert((src < SOURCE_COUNT) && msg("Host map source out of range"));
if((dst < NUM_USB_CHAN_IN) && (src < SOURCE_COUNT))
{
unsafe
{
samples_to_host_map[dst] = src;
}
}
}
break;
case SET_SAMPLES_TO_DEVICE_MAP:
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
write_via_xc_ptr_indexed(samples_to_device_map,index,val);
{
int dst = inuint(c_mix_ctl);
int src = inuint(c_mix_ctl);
inct(c_mix_ctl);
assert((dst < NUM_USB_CHAN_OUT) && msg("Device map destination out of range"));
assert((src < SOURCE_COUNT) && msg("Device map source out of range"));
if((dst < NUM_USB_CHAN_OUT) && (src < SOURCE_COUNT))
{
unsafe
{
samples_to_device_map[dst] = src;
}
}
}
break;
case SET_MIX_MULT:
@@ -399,40 +441,80 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
write_word_to_mix_mult(mix, index, val);
assert((mix < MAX_MIX_COUNT) && msg("Mix mult mix out of range"));
assert((index < MIX_INPUTS) && msg("Mix mult index out of range"));
if((index < MIX_INPUTS) && (mix < MAX_MIX_COUNT))
{
unsafe
{
mix_mult[(mix * MIX_INPUTS) + index] = val;
}
}
break;
case SET_MIX_MAP:
mix = inuint(c_mix_ctl);
index = inuint(c_mix_ctl); /* mixer input */
val = inuint(c_mix_ctl); /* source */
inct(c_mix_ctl);
#ifdef FAST_MIXER
setPtr(index, val, mix);
{
unsigned mix = inuint(c_mix_ctl);
unsigned input = inuint(c_mix_ctl); /* mixer input */
unsigned source = inuint(c_mix_ctl); /* source */
inct(c_mix_ctl);
assert((mix < MAX_MIX_COUNT) && msg("Mix map mix out of range"));
assert((input < MIX_INPUTS) && msg("Mix map index out of range"));
assert((source < SOURCE_COUNT) && msg("Mix map source out of range"));
if((input < MIX_INPUTS) && (mix < MAX_MIX_COUNT) && (source < SOURCE_COUNT))
{
#if (FAST_MIXER)
setPtr(input, source, mix);
#else
write_word_to_mix_map(mix, index, val);
unsafe
{
mix_map[(mix * MIX_INPUTS) + input] = source;
}
#endif
}
}
break;
#endif /* if MAX_MIX_COUNT > 0 */
#ifdef IN_VOLUME_IN_MIXER
#if (IN_VOLUME_IN_MIXER)
case SET_MIX_IN_VOL:
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
write_via_xc_ptr_indexed(multIn, index, val);
assert((index < (NUM_USB_CHAN_IN + 1)) && msg("In volume index out of range"));
if(index < NUM_USB_CHAN_IN + 1)
{
unsafe
{
multIn[index] = val;
}
}
break;
#endif
#ifdef OUT_VOLUME_IN_MIXER
#if (OUT_VOLUME_IN_MIXER)
case SET_MIX_OUT_VOL:
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
write_via_xc_ptr_indexed(multOut, index, val);
assert((index < (NUM_USB_CHAN_OUT + 1)) && msg("Out volume index out of range"));
if(index < NUM_USB_CHAN_OUT + 1)
{
unsafe
{
multOut[index] = val;
}
}
break;
#endif
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
/* Peak samples of stream from host to device (via USB) */
case GET_STREAM_LEVELS:
index = inuint(c_mix_ctl);
@@ -441,42 +523,6 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
outct(c_mix_ctl, XS1_CT_END);
samples_from_host_streams[index] = 0;
break;
case GET_INPUT_LEVELS:
index = inuint(c_mix_ctl);
chkct(c_mix_ctl, XS1_CT_END);
#ifdef LEVEL_METER_LEDS
/* Level LEDS process reseting samples_to_host_inputs
* Other side makes sure we don't miss a peak */
//val = samples_to_host_inputs_buff[index];
//samples_to_host_inputs_buff[index] = 0;
/* Access funcs used to avoid disjointness check */
read_via_xc_ptr_indexed(val, samples_to_host_inputs_buff_ptr, index);
write_via_xc_ptr_indexed(samples_to_host_inputs_buff_ptr, index, 0);
#else
/* We dont have a level LEDs process, so reset ourselves */
//val = samples_to_host_inputs[index];
//samples_to_host_inputs[index] = 0;
/* Access funcs used to avoid disjointness check */
read_via_xc_ptr_indexed(val, samples_to_host_inputs_ptr, index);
write_via_xc_ptr_indexed(samples_to_host_inputs_ptr, index, 0);
#endif
outuint(c_mix_ctl, val);
outct(c_mix_ctl, XS1_CT_END);
break;
#if (MAX_MIX_COUNT > 0)
/* Peak samples of the mixer outputs */
case GET_OUTPUT_LEVELS:
index = inuint(c_mix_ctl);
chkct(c_mix_ctl, XS1_CT_END);
read_via_xc_ptr_indexed(val, samples_mixer_outputs, index);
write_via_xc_ptr_indexed(samples_mixer_outputs, index, 0);
//val = samples_mixer_outputs[index];
//samples_mixer_outputs[index] = 0;
outuint(c_mix_ctl, val);
outct(c_mix_ctl, XS1_CT_END);
break;
#endif
}
break;
@@ -484,14 +530,13 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
default:
/* Select default */
break;
}
} // select
#endif
/* Get response from decouple */
if(testct(c_host))
{
int sampFreq;
#pragma xta endpoint "mixer1_rate_change"
unsigned command = inct(c_host);
switch(command)
@@ -520,9 +565,8 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
#pragma loop unroll
/* Reset the mix values back to 0 */
for (int i=0;i<MAX_MIX_COUNT;i++)
for (int i=0; i<MAX_MIX_COUNT; i++)
{
//write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
unsafe
{
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
@@ -535,21 +579,24 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
}
else
{
#if MAX_MIX_COUNT > 0
#if (MAX_MIX_COUNT > 0)
GetSamplesFromHost(c_host);
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
GiveSamplesToHost(c_host, samples_to_host_map);
/* Sync with mixer 2 (once it has swapped samples with audiohub) */
outuint(c_mixer2, 0);
inuint(c_mixer2);
/* Do the mixing */
#ifdef FAST_MIXER
mixed = doMix0(samples, mix_mult_slice(0));
unsafe
{
#if (FAST_MIXER)
mixed = doMix0(ptr_samples, slice(mix_mult, 0));
#else
mixed = doMix(samples, mix_map_slice(0),mix_mult_slice(0));
mixed = doMix(ptr_samples, slice(mix_map, 0), slice(mix_mult, 0));
#endif
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0), mixed);
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0] = mixed;
}
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 0);
@@ -560,40 +607,46 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
#endif
{
#if MAX_MIX_COUNT > 2
#ifdef FAST_MIXER
mixed = doMix2(samples, mix_mult_slice(2));
#if (MAX_MIX_COUNT > 2)
unsafe
{
#if (FAST_MIXER)
mixed = doMix2(ptr_samples, slice(mix_mult, 2));
#else
mixed = doMix(samples, mix_map_slice(2),mix_mult_slice(2));
mixed = doMix(ptr_samples, slice(mix_map, 2), slice(mix_mult, 2));
#endif
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2), mixed);
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2] = mixed;
}
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 2);
#endif
#endif
#if MAX_MIX_COUNT > 4
#ifdef FAST_MIXER
mixed = doMix4(samples, mix_mult_slice(4));
#if (MAX_MIX_COUNT > 4)
unsafe
{
#if (FAST_MIXER)
mixed = doMix4(ptr_samples, slice(mix_mult, 4));
#else
mixed = doMix(samples, mix_map_slice(4),mix_mult_slice(4));
mixed = doMix(ptr_samples, slice(mix_map, 4), slice(mix_mult, 4));
#endif
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 4), mixed);
ptr_samples[XUA_MIXER_OFFSET_MIX + 4] = mixed;
}
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 4);
#endif
#endif
#if MAX_MIX_COUNT > 6
#ifdef FAST_MIXER
mixed = doMix6(samples, mix_mult_slice(6));
#if (MAX_MIX_COUNT > 6)
unsafe
{
#if (FAST_MIXER)
mixed = doMix6(ptr_samples, slice(mix_mult, 6));
#else
mixed = doMix(samples, mix_map_slice(6),mix_mult_slice(6));
mixed = doMix(ptr_samples, slice(mix_map, 6), slice(mix_mult, 6));
#endif
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 6), mixed);
ptr_samples[XUA_MIXER_OFFSET_MIX + 6] = mixed;
}
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 6);
#endif
@@ -601,10 +654,10 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
}
#else /* IF MAX_MIX_COUNT > 0 */
/* No mixes, this thread runs on its own doing just volume */
GiveSamplesToDevice(c_mixer2, samples_to_device_map, multOut);
GiveSamplesToDevice(c_mixer2, samples_to_device_map);
GetSamplesFromDevice(c_mixer2);
GetSamplesFromHost(c_host);
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
GiveSamplesToHost(c_host, samples_to_host_map);
#endif
}
}
@@ -621,7 +674,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
while (1)
{
#pragma xta endpoint "mixer2_req"
request = inuint(c_audio);
/* Forward the request on */
@@ -633,7 +685,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
if(testct(c_mixer1))
{
int sampFreq;
#pragma xta endpoint "mixer2_rate_change"
unsigned command = inct(c_mixer1);
switch(command)
@@ -660,8 +711,8 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
}
for (int i=0;i<MAX_MIX_COUNT;i++)
{
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
unsafe{
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
}
/* Wait for handshake and pass on */
@@ -670,7 +721,7 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
}
else
{
GiveSamplesToDevice(c_audio, samples_to_device_map, multOut);
GiveSamplesToDevice(c_audio, samples_to_device_map);
GetSamplesFromDevice(c_audio);
/* Sync with mixer 1 (once it has swapped samples with the buffering sub-system) */
@@ -678,61 +729,67 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
outuint(c_mixer1, 0);
/* Do the mixing */
#if MAX_MIX_COUNT > 1
#ifdef FAST_MIXER
mixed = doMix1(samples, mix_mult_slice(1));
#if (MAX_MIX_COUNT > 1)
unsafe
{
#if (FAST_MIXER)
mixed = doMix1(ptr_samples, slice(mix_mult, 1));
#else
mixed = doMix(samples, mix_map_slice(1),mix_mult_slice(1));
mixed = doMix(ptr_samples, slice(mix_map, 1), slice(mix_mult, 1));
#endif
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1), mixed);
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1] = mixed;
}
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 1);
#endif
#endif
#if (MAX_FREQ > 96000)
/* Fewer mixes when running higher than 96kHz */
if (!mixer2_mix2_flag)
#endif
{
#if MAX_MIX_COUNT > 3
#ifdef FAST_MIXER
mixed = doMix3(samples, mix_mult_slice(3));
#if (MAX_MIX_COUNT > 3)
unsafe
{
#if (FAST_MIXER)
mixed = doMix3(ptr_samples, slice(mix_mult, 3));
#else
mixed = doMix(samples, mix_map_slice(3),mix_mult_slice(3));
mixed = doMix(ptr_samples, slice(mix_map, 3), slice(mix_mult, 3));
#endif
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3), mixed);
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3] = mixed;
}
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 3);
#endif
#endif
#if MAX_MIX_COUNT > 5
#ifdef FAST_MIXER
mixed = doMix5(samples, mix_mult_slice(5));
#if (MAX_MIX_COUNT > 5)
unsafe
{
#if (FAST_MIXER)
mixed = doMix5(ptr_samples, slice(mix_mult, 5));
#else
mixed = doMix(samples, mix_map_slice(5),mix_mult_slice(5));
mixed = doMix(ptr_samples, slice(mix_map, 5), slice(mix_mult, 5));
#endif
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5, mixed);
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5] = mixed;
}
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 5);
#endif
#endif
#if MAX_MIX_COUNT > 7
#ifdef FAST_MIXER
mixed = doMix7(samples, mix_mult_slice(7));
#if (MAX_MIX_COUNT > 7)
unsafe
{
#if (FAST_MIXER)
mixed = doMix7(ptr_samples, slice(mix_mult, 7));
#else
mixed = doMix(samples, mix_map_slice(7),mix_mult_slice(7));
mixed = doMix(ptr_samples, slice(mix_map, 7), slice(mix_mult, 7));
#endif
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7, mixed);
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7] = mixed;
}
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 7);
#endif
@@ -748,68 +805,52 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
#if (MAX_MIX_COUNT > 0)
chan c;
#endif
multOut = array_to_xc_ptr((multOut_array,unsigned[]));
multIn = array_to_xc_ptr((multIn_array,unsigned[]));
samples = array_to_xc_ptr((samples_array,unsigned[]));
samples_to_host_map = array_to_xc_ptr((samples_to_host_map_array,unsigned[]));
samples_to_device_map = array_to_xc_ptr((samples_to_device_map_array,unsigned[]));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
samples_to_host_inputs_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
#ifdef LEVEL_METER_LEDS
samples_to_host_inputs_buff_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
#endif
samples_mixer_outputs_ptr = array_to_xc_ptr((samples_mixer_outputs, unsigned[]));
#if MAX_MIX_COUNT >0
mix_mult = array_to_xc_ptr((mix_mult_array,unsigned[]));
#ifndef FAST_MIXER
mix_map = array_to_xc_ptr((mix_map_array,unsigned[]));
#endif
#endif
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
unsafe {
//write_via_xc_ptr_indexed(samples,i,0);
ptr_samples[i] = 0;
}
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
{
int num_mixes = DEFAULT_FREQ > 96000 ? 2 : MAX_MIX_COUNT;
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
//samples_to_device_map_array[i] = i;
asm("stw %0, %1[%2]":: "r"(i), "r"(samples_to_device_map), "r"(i));
}
samples_to_device_map_array[i] = i;
}
#ifdef OUT_VOLUME_IN_MIXER
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
write_via_xc_ptr_indexed(multOut, i, MAX_VOL);
#if (OUT_VOLUME_IN_MIXER)
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
unsafe{
multOut[i] = MAX_VOLUME_MULT;
}
#endif
#ifdef IN_VOLUME_IN_MIXER
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
write_via_xc_ptr_indexed(multIn, i, MAX_VOL);
#if (IN_VOLUME_IN_MIXER)
for (int i=0; i<NUM_USB_CHAN_IN; i++)
unsafe{
multIn[i] = MAX_VOLUME_MULT;
}
#endif
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
write_via_xc_ptr_indexed(samples_to_host_map, i, NUM_USB_CHAN_OUT + i);
for (int i=0; i<NUM_USB_CHAN_IN; i++)
unsafe{
samples_to_host_map[i] = XUA_MIXER_OFFSET_IN + i;
}
#if MAX_MIX_COUNT> 0
#if (MAX_MIX_COUNT> 0)
for (int i=0;i<MAX_MIX_COUNT;i++)
for (int j=0;j<MIX_INPUTS;j++)
{
#ifndef FAST_MIXER
write_word_to_mix_map(i,j, j < 16 ? j : j + 2);
unsafe{
#if (FAST_MIXER == 0)
mix_map[i * MIX_INPUTS + j] = (j < 16 ? j : j + 2);
#endif
write_word_to_mix_mult(i,j, i==j ? db_to_mult(0, 8, 25) : 0);
mix_mult[i * MIX_INPUTS + j] = (i==j ? db_to_mult(0, XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS) : 0);
}
#endif

View File

@@ -1,4 +1,4 @@
// Copyright 2013-2022 XMOS LIMITED.
// Copyright 2013-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
@@ -9,17 +9,17 @@
#include "xua.h"
/* Note since DSD ports could be reused for I2S ports we do all the setup manually in C */
#if DSD_CHANS_DAC > 0
#if (DSD_CHANS_DAC > 0)
port p_dsd_dac[DSD_CHANS_DAC] = {
PORT_DSD_DAC0,
#endif
#if DSD_CHANS_DAC > 1
#if (DSD_CHANS_DAC > 1)
PORT_DSD_DAC1,
#endif
#if DSD_CHANS_DAC > 2
#if (DSD_CHANS_DAC > 2)
#error > 2 DSD chans currently not supported
#endif
#if DSD_CHANS_DAC > 0
#if (DSD_CHANS_DAC > 0)
};
port p_dsd_clk = PORT_DSD_CLK;
#endif
@@ -45,7 +45,7 @@ void ConfigAudioPortsWrapper(
port p_lrclk,
port p_bclk,
#endif
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode)
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq)
{
ConfigAudioPorts(
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _AUDIOPORTS_H_
#define _AUDIOPORTS_H_
@@ -79,7 +79,7 @@ void ConfigAudioPortsWrapper(
buffered in port:32 p_bclk,
#endif
#endif
in port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode);
in port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq);
#else
void ConfigAudioPortsWrapper(
@@ -95,7 +95,7 @@ void ConfigAudioPortsWrapper(
port p_lrclk,
port p_bclk,
#endif
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode);
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq);
#endif /* __XC__*/

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 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 <platform.h>
@@ -6,9 +6,7 @@
#include "xua.h"
#include "audioports.h"
//extern in port p_mclk_in;
extern clock clk_audio_mclk;
//extern clock clk_audio_bclk;
void ConfigAudioPorts(
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
@@ -58,7 +56,7 @@ void ConfigAudioPorts(
}
#endif
#if (I2S_CHANS_DAC != 0)
#if (I2S_CHANS_DAC != 0)|| (DSD_CHANS_DAC != 0)
for(int i = 0; i < numPortsDac; i++)
{
clearbuf(p_i2s_dac[i]);
@@ -82,7 +80,7 @@ void ConfigAudioPorts(
/* Some adustments for timing. Sample ADC lines on negative edge and add some delay */
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
{
for(int i = 0; i < I2S_WIRES_ADC; i++)
for(int i = 0; i < numPortsAdc; i++)
{
set_port_sample_delay(p_i2s_adc[i]);
set_pad_delay(p_i2s_adc[i], 4);
@@ -91,7 +89,6 @@ void ConfigAudioPorts(
#endif
#elif (CODEC_MASTER)
/* Stop bit and master clock blocks */
stop_clock(clk_audio_bclk);
@@ -103,20 +100,18 @@ void ConfigAudioPorts(
/* Do some clocking shifting to get data in the valid window */
/* E.g. Only shift when running at 88.2+ kHz TDM slave */
int bClkDelay_fall = 0;
if(curSamFreq * I2S_CHANS_PER_FRAME * 32 >= 20000000)
if(curSamFreq * I2S_CHANS_PER_FRAME * XUA_I2S_N_BITS >= 20000000)
{
/* 18 * 2ns = 36ns. This results in a -4ns (36 - 40) shift at 96KHz and -8ns (36 - 44) at 88.4KHz */
bClkDelay_fall = 18;
}
set_clock_fall_delay(clk_audio_bclk, bClkDelay_fall);
#endif
#if (I2S_CHANS_DAC != 0)
/* Clock I2S output data ports from b-clock clock block */
for(int i = 0; i < I2S_WIRES_DAC; i++)
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
/* Clock I2S/DSD output data ports from b-clock clock block */
for(int i = 0; i < numPortsDac; i++)
{
configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0);
}
@@ -124,7 +119,7 @@ void ConfigAudioPorts(
#if (I2S_CHANS_ADC != 0)
/* Clock I2S input data ports from clock block */
for(int i = 0; i < I2S_WIRES_ADC; i++)
for(int i = 0; i < numPortsAdc; i++)
{
configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk);
}

View File

@@ -0,0 +1,29 @@
// Copyright 2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* Default implementations of AudioHwInit(), AudioHwConfig(), AudioHwConfig_Mute() and AudioHwConfig_UnMute() */
void AudioHwInit() __attribute__ ((weak));
void AudioHwInit()
{
return;
}
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) __attribute__ ((weak));
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
{
return;
}
void AudioHwConfig_Mute() __attribute__ ((weak));
void AudioHwConfig_Mute()
{
return;
}
void AudioHwConfig_UnMute() __attribute__ ((weak));
void AudioHwConfig_UnMute()
{
return;
}

View File

@@ -0,0 +1,54 @@
// Copyright 2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _AUDIO_HW_H_
#define _AUDIO_HW_H_
/* The functions below should be implemented for the external audio hardware arrangement of a specific design.
* Note, default (empty) implementations of these are provided in audiohub_user.c
*/
/**
* @brief User audio hardware initialisation code
*
* This function is called when the device starts up and should contain user code to perform any required audio hardware initialisation
*/
void AudioHwInit(void);
/**
* @brief User audio hardware configuration code
*
* This function is called when on sample rate change and should contain user code to configure audio hardware
* (clocking, CODECs etc) for a specific mClk/Sample frequency
*
* \param samFreq The new sample frequency (in Hz)
*
* \param mClk The new master clock frequency (in Hz)
*
* \param dsdMode DSD mode, DSD_MODE_NATIVE, DSD_MODE_DOP or DSD_MODE_OFF
*
* \param sampRes_DAC Playback sample resolution (in bits)
*
* \param sampRes_ADC Record sample resolution (in bits)
*/
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC);
/**
* @brief User code mute audio hardware
*
* This function is called before AudioHwConfig() and should contain user code to mute audio hardware before a
* sample rate change in order to reduced audible pops/clicks
*
* Note, if using the application PLL of a xcore.ai device this function will be called before the master-clock is
* changed
*/
void AudioHwConfig_Mute(void);
/**
* @brief User code to un-mute audio hardware
*
* This function is called after AudioHwConfig() and should contain user code to un-mute audio hardware after a
* sample rate change
*/
void AudioHwConfig_UnMute(void);
#endif

Some files were not shown because too many files have changed in this diff Show More