#########################################
AN00248: Using lib_xua with lib_mic_array
#########################################

************
Introduction
************

The XMOS USB Audio library `lib_xua <https://github.com/xmos/lib_xua/>`_ provides an implementation of USB Audio Class versions 1.0 and 2.0.

This application note demonstrates the implementation of a basic USB Audio device with
record functionality from PDM microphones on the `XK-EVK-XU316 <https://www.xmos.com/xk-evk-xu316>`_ board.

Core PDM microphone functionality is contained in `lib_mic_array <https://github.com/xmos/lib_mic_array/>`_.
This library handles both the physical interfacing to the PDM microphones and efficient decimation to
user-configurable output sample rates, effectively performing PDM-to-PCM conversion.

I2S is also enabled as an output and the on board DAC is configured to play back the microphone signals.

*******************
Example application
*******************

The CMakeLists.txt file
=======================

Add ``lib_xua`` to the dependent module list in the CMakeLists.txt
file. Also add ``lib_board_support`` which contains code to setup the audio hardware:

.. literalinclude:: ../../app_an00248/CMakeLists.txt
   :start-at: set(APP_DEPENDENT_MODULES
   :end-at: ")


Compiler flags need to be set to tell ``lib_board_support`` which
board is being used. For example::

  set(APP_COMPILER_FLAGS      -DBOARD_SUPPORT_BOARD=XK_EVK_XU316
                              ..)


Declarations
============

Allocating hardware resources for lib_xua
-----------------------------------------

This implementation of a USB Audio device using ``lib_xua`` requires the following I/O pins:

- Audio Master clock (generated by the XCORE)
- Bit clock (generated by the XCORE)
- Word clock (generated by the XCORE)
- I2S data output pin (generated by the XCORE)


On an XCORE the pins are controlled by ``ports``. The main application therefore declares a
port for the master clock input signal.
The ``main()`` function that is provided within ``lib_xua/src/core/main.xc`` itself
has these ports defined. Look for ``p_i2s_dac``, ``p_lrclk``, ``p_bclk`` and ``p_mclk_in`` in
``lib_xua/src/core/main.xc``.


``lib_xua`` also requires two ports for internally calculating USB feedback. Please refer to
the ``lib_xua`` library documentation for further details.  In this example ``XUA_Buffer()`` and ``XUA_AudioHub()``
reside on the same tile and can therefore make use of the same master-clock port.
These are defined as ``p_for_mclk_count`` and ``p_mclk_in_usb`` in the ``main()`` function in ``lib_xua``.

In addition to ``port`` resources, some clock-block resources (``clk_audio_bclk``, ``clk_audio_mclk`` and ``clk_audio_mclk_usb``),
also defined in the ``main()`` function in `lib_xua`, are required.


Allocating hardware resources for lib_mic_array
-----------------------------------------------

In this example ``lib_mic_array`` requires a single 1-bit port for PDM data from two microphones. Each microphone is configured
to produce a PDM sample on an opposite clock edge from the other. This means the the data is effectively double
data rate (DDR) with respect to the PDM clock.

The microphones must be clocked by a clock synchronous to the audio application clock - typically 3.072MHz for 16, 32 or 48 kHz output
PCM sampling rate.

These ports, along with other ``mic_array`` required resources are populated within ``lib_xua`` and passed
to ``lib_mic_array``. In ``lib_xua``, the microphone resources are populated and then provided
to ``mic_array_init()``:

.. code-block:: c

   pdm_rx_resources_t pdm_res = PDM_RX_RESOURCES_DDR(
                                 PORT_MCLK_IN,
                                 PORT_PDM_CLK,
                                 PORT_PDM_DATA,
                                 mClk,
                                 pdmClk,
                                 XS1_CLKBLK_1,
                                 XS1_CLKBLK_2);

   mic_array_init(&pdm_res, channel_map, mic_samp_rate);

The port names are derived from the board XN file (for example ``XK-EVK-XU316.xn``).
The ports required for the mic array operation are expected to be defined in the application XN file on the
relevant ``Tile``. For example::

   <Tile Number="1" Reference="tile[1]">
      <Port Location="XS1_PORT_1G" Name="PORT_PDM_CLK"/>
      <Port Location="XS1_PORT_1F" Name="PORT_PDM_DATA"/>
      <Port Location="XS1_PORT_1D" Name="PORT_MCLK_IN"/>
   </Tile>

The clock blocks used for the microphone task are fixed to ``XS1_CLKBLK_1`` and ``XS1_CLKBLK_2`` and cannot
be changed from the application.


The ``XK-EVK-XU316`` Board expects the XCORE to divide down the audio master clock (24.576 MHz)
and output the result to the microphones. This is done internally by ``lib_mic_array``. The master clock
and the pdm clock frequencies are passed to ``mic_array_init()`` via the ``pdm_rx_resources_t`` in ``lib_xua``
and are fixed to 24.576 MHz and 3.072 MHz for the 48 kHz family of output sampling rates and to
22.5792 MHz and 28.224 MHz for 44.1 kHz family of output sampling rates:

.. code-block:: c

   unsigned mClk = MCLK_48, pdmClk = 3072000;
   if (((MCLK_441) % mic_samp_rate) == 0)
   {
      // Note: Ensure the selected microphone supports this PDM clock frequency.
      // Refer to the microphone datasheet for the allowed fClk range.
      mClk = MCLK_441;
      pdmClk = 2822400;
   }

Please see the ``lib_mic_array`` library documentation for full details.


Configuring lib_xua
===================

``lib_xua`` must be configured to enable support for PDM microphones.

``lib_xua`` has many parameters than can be configured at build time, some examples include:

- Supported sample-rates
- Channel counts
- Audio Class version
- Product/Vendor IDs
- Various product strings
- Master clock frequency

To enable PDM microphone support  ``XUA_NUM_PDM_MICS`` must be set to a non-zero value.  Setting this will cause the ``XUA_AudioHub``
task to forward sample rate information and receive samples from the relevant microphone related tasks.

These parameters are set via defines in the ``xua_conf.h`` header file. For this simple application the
complete contents of this file are as follows:

.. literalinclude:: ../../app_an00248/src/xua_conf.h
   :start-at: // Copyright
   :end-at: #endif

``XUA_PDM_MIC_FREQ`` can be changed to 32000 or 16000 to reconfigure the system to lower sample rates than the default 48 kHz.


The application ``main()`` function
===================================

The ``main()`` function is provided within the ``lib_xua/src/core/main.xc`` file.
It starts all of the tasks in parallel using the xC ``par`` construct.

Firstly the standard ``lib_xua`` USB side tasks are run on tile 0. This code starts the low-level USB task and an Endpoint 0 task. The Audio buffering task and a task to handle
the audio I/O (``XUA_AudioHub``) is started on tile 1 where the I2S bus exists.

The microphone task ``mic_array_task`` spawns a single thread which handles PDM receive on the ports and the decimation filters to produce PCM.
This is placed on tile 1 where the microphone hardware is connected.
It connects directly to ``XUA_AudioHub`` and provides samples which are at the same rate as the audio I/O.

User callbacks
--------------

While the ``main()`` function is provided within ``lib_xua`` itself, there are a number of callbacks which allow
for customisation of the application.

The DAC is configured by ``AudioHwInit()`` function in `hwsupport.xc`, which calls Audio hardware initialisation
functions for the relevant hardware from ``lib_board_support``

.. literalinclude:: ../../app_an00248/src/hwsupport.xc
   :start-at: #include "xua.h"
   :end-before: /* Configures the external

Callback functions ``UserBufferManagement()`` and ``xua_user_pdm_process()`` are defined in `user_callbacks.xc`.
Both these functions are called from the main loop in ``XUA_AudioHub()``.
``xua_user_pdm_process()`` implements the PCM sample post processing, which for this example is a simple scaling by a factor of 64
to allow the mic captured audio to be heard easily. ``UserBufferManagement()`` routes the mic samples to the DAC.

.. literalinclude:: ../../app_an00248/src/user_callbacks.xc


|newpage|

Hardware setup
==============

Required hardware
-----------------

- 1x ``XK-EVK-XU316`` board
- 2x Micro USB cable (For USB and XTAG)
- 3.5mm audio cable to connect to the line out connector on the ``XK-EVK-XU316`` board
- Host computer

Setup procedure
---------------

#. Connect a pair of PDM microphones to the microphone connector on the ``XK-EVK-XU316`` via a ribbon cable.
   Refer to the `xcore.ai Explorer hardware manual <https://www.xmos.com/file/xcore_ai-evaluation-kit-v2_0-hardware-manual?version=latest>`_
   for more details.

#. Connect one Micro USB cable between the host computer and the ``XK-EVK-XU316`` **DEBUG** port.

#. Connect the other Micro USB cable between the host computer and the ``XK-EVK-XU316`` **USB** port.

:numref:`an00248_hw_setup` shows the ``XK-EVK-XU316`` board with all the cables connected.

.. _an00248_hw_setup:
.. figure:: images/hw_setup.*
   :width: 80%

   Hardware setup

|newpage|

Building the example
====================

This section assumes that the `XMOS XTC Tools <https://www.xmos.com/software-tools/>`_ have been
downloaded and installed. The required version is specified in the accompanying ``README``.

Installation instructions can be found `here <https://xmos.com/xtc-install-guide>`_.

Special attention should be paid to the section on
`Installation of Required Third-Party Tools <https://www.xmos.com/documentation/XM-014363-PC/html/installation/install-configure/install-tools/install_prerequisites.html>`_.

The application is built using the `xcommon-cmake <https://www.xmos.com/file/xcommon-cmake-documentation/?version=latest>`_
build system, which is provided with the XTC tools and is based on `CMake <https://cmake.org/>`_.

The ``an00248`` software ZIP package should be downloaded and extracted to a chosen working
directory.

To configure the build, the following commands should be run from an XTC command prompt::

    cd an00248
    cd app_an00248
    cmake -G "Unix Makefiles" -B build

All required dependencies are included in the software package. If any dependencies are missing,
they will be retrieved automatically during this step.

The application binaries should then be built using ``xmake``::

    xmake -j -C build

Binary artifacts (.xe files) will be generated under the appropriate subdirectories of the
``app_an00248/bin`` directory — one for each supported build configuration.

For subsequent builds, the ``cmake`` step may be omitted.
If ``CMakeLists.txt`` or other build files are modified, ``cmake`` will be re-run automatically
by ``xmake`` as needed.

The application uses approximately 49 kB on tile 0 and 17 kB on tile 1 (of 512 kB on each).

Running the example
===================

From an XTC command prompt, the following command should be run from the ``an00248/app_an00248``
directory::

    xrun ./bin/app_an00248.xe

Alternatively, the application can be programmed into flash memory for standalone execution::

    xflash ./bin/app_an00248.xe

A USB audio device called ``XUA PDM Example`` should now be seen enumerated and the stereo microphone audio input stream
can be recorded on the USB host or listened to by connecting to the analog output jacks.

